the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add files, sandbox_files, and creation APIs

+2119 -62
+3
apps/api/bun.lock
··· 44 44 "redis": "^5.10.0", 45 45 "redlock": "^5.0.0-beta.2", 46 46 "ssh2": "^1.16.0", 47 + "unique-username-generator": "^1.5.1", 47 48 "unstorage": "^1.17.4", 48 49 "zod": "^4.3.6", 49 50 "zx": "^8.8.5", ··· 928 929 "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], 929 930 930 931 "unicode-segmenter": ["unicode-segmenter@0.14.5", "", {}, "sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g=="], 932 + 933 + "unique-username-generator": ["unique-username-generator@1.5.1", "", { "bin": { "usernamegen": "dist/cli.js", "usergen": "dist/cli.js", "unique-username": "dist/cli.js", "uuname": "dist/cli.js" } }, "sha512-Q0pSKPyij4L7Tm6Bo3XsWeFG9qbyWTtwb3jTN+XgGhCFdlvQn6Fj0DCfYElw0kp/Xp7Jv1Q+CL+aA8S07RMChA=="], 931 934 932 935 "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], 933 936
+1
apps/api/package.json
··· 55 55 "redis": "^5.10.0", 56 56 "redlock": "^5.0.0-beta.2", 57 57 "ssh2": "^1.16.0", 58 + "unique-username-generator": "^1.5.1", 58 59 "unstorage": "^1.17.4", 59 60 "zod": "^4.3.6", 60 61 "zx": "^8.8.5"
+5 -3
apps/api/src/schema/authorized-keys.ts
··· 3 3 import sandboxes from "./sandboxes"; 4 4 5 5 const authorizedKeys = pgTable("authorized_keys", { 6 - id: text("id").primaryKey().default(sql`xata_id()`), 6 + id: text("id") 7 + .primaryKey() 8 + .default(sql`xata_id()`), 7 9 sandboxId: text("sandbox_id").references(() => sandboxes.id), 8 10 publicKey: text("public_key").notNull(), 9 11 createdAt: timestamp("created_at").defaultNow().notNull(), 10 12 }); 11 13 12 - export type SelectAuthorizedKeys = InferSelectModel<typeof authorizedKeys>; 13 - export type InsertAuthorizedKeys = InferInsertModel<typeof authorizedKeys>; 14 + export type SelectAuthorizedKey = InferSelectModel<typeof authorizedKeys>; 15 + export type InsertAuthorizedKey = InferInsertModel<typeof authorizedKeys>; 14 16 15 17 export default authorizedKeys;
+16
apps/api/src/schema/files.ts
··· 1 + import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; 2 + import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; 3 + 4 + const files = pgTable("files", { 5 + id: text("id") 6 + .primaryKey() 7 + .default(sql`variable_id()`), 8 + content: text("content").notNull(), 9 + createdAt: timestamp("created_at").defaultNow().notNull(), 10 + updatedAt: timestamp("updated_at").defaultNow().notNull(), 11 + }); 12 + 13 + export type SelectFile = InferSelectModel<typeof files>; 14 + export type InsertFile = InferInsertModel<typeof files>; 15 + 16 + export default files;
+4
apps/api/src/schema/index.ts
··· 7 7 import sandboxSecrets from "./sandbox-secrets"; 8 8 import sandboxVariables from "./sandbox-variables"; 9 9 import sandboxVolumes from "./sandbox-volumes"; 10 + import files from "./files"; 11 + import sandboxFiles from "./sandbox-files"; 10 12 11 13 export default { 12 14 sandboxes, ··· 18 20 sandboxSecrets, 19 21 sandboxVariables, 20 22 sandboxVolumes, 23 + files, 24 + sandboxFiles, 21 25 };
+22
apps/api/src/schema/sandbox-files.ts
··· 1 + import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; 2 + import { pgTable, text } from "drizzle-orm/pg-core"; 3 + import sandboxes from "./sandboxes"; 4 + import files from "./files"; 5 + 6 + const sandboxFiles = pgTable("sandbox_files", { 7 + id: text("id") 8 + .primaryKey() 9 + .default(sql`xata_id()`), 10 + sandboxId: text("sandbox_id") 11 + .notNull() 12 + .references(() => sandboxes.id), 13 + fileId: text("file_id") 14 + .notNull() 15 + .references(() => files.id), 16 + path: text("path").notNull(), 17 + }); 18 + 19 + export type SelectSandboxFile = InferSelectModel<typeof sandboxFiles>; 20 + export type InsertSandboxFile = InferInsertModel<typeof sandboxFiles>; 21 + 22 + export default sandboxFiles;
+5 -3
apps/api/src/schema/sandbox-secrets.ts
··· 6 6 const sandboxSecrets = pgTable( 7 7 "sandbox_secrets", 8 8 { 9 - id: text("id").primaryKey().default(sql`xata_id()`), 9 + id: text("id") 10 + .primaryKey() 11 + .default(sql`xata_id()`), 10 12 sandboxId: text("sandbox_id") 11 13 .notNull() 12 14 .references(() => sandboxes.id), ··· 17 19 (t) => [uniqueIndex("unique_sandbox_secret").on(t.sandboxId, t.secretId)], 18 20 ); 19 21 20 - export type SelectSandboxSecrets = InferSelectModel<typeof sandboxSecrets>; 21 - export type InsertSandboxSecrets = InferInsertModel<typeof sandboxSecrets>; 22 + export type SelectSandboxSecret = InferSelectModel<typeof sandboxSecrets>; 23 + export type InsertSandboxSecret = InferInsertModel<typeof sandboxSecrets>; 22 24 23 25 export default sandboxSecrets;
+5 -3
apps/api/src/schema/sandbox-variables.ts
··· 6 6 const sandboxVariables = pgTable( 7 7 "sandbox_variables", 8 8 { 9 - id: text("id").primaryKey().default(sql`xata_id()`), 9 + id: text("id") 10 + .primaryKey() 11 + .default(sql`xata_id()`), 10 12 sandboxId: text("sandbox_id") 11 13 .notNull() 12 14 .references(() => sandboxes.id), ··· 19 21 ], 20 22 ); 21 23 22 - export type SelectSandboxVariables = InferSelectModel<typeof sandboxVariables>; 23 - export type InsertSandboxVariables = InferInsertModel<typeof sandboxVariables>; 24 + export type SelectSandboxVariable = InferSelectModel<typeof sandboxVariables>; 25 + export type InsertSandboxVariable = InferInsertModel<typeof sandboxVariables>; 24 26 export default sandboxVariables;
+6 -3
apps/api/src/schema/sandbox-volumes.ts
··· 4 4 import volumes from "./volumes"; 5 5 6 6 const sandboxVolumes = pgTable("sandbox_volumes", { 7 - id: text("id").primaryKey().default(sql`xata_id()`), 7 + id: text("id") 8 + .primaryKey() 9 + .default(sql`xata_id()`), 8 10 sandboxId: text("sandbox_id") 9 11 .notNull() 10 12 .references(() => sandboxes.id), 11 13 volumeId: text("volume_id") 12 14 .notNull() 13 15 .references(() => volumes.id), 16 + path: text("path").notNull(), 14 17 }); 15 18 16 - export type SelectSandboxVolumes = InferSelectModel<typeof sandboxVolumes>; 17 - export type InsertSandboxVolumes = InferInsertModel<typeof sandboxVolumes>; 19 + export type SelectSandboxVolume = InferSelectModel<typeof sandboxVolumes>; 20 + export type InsertSandboxVolume = InferInsertModel<typeof sandboxVolumes>; 18 21 19 22 export default sandboxVolumes;
+2
apps/api/src/xrpc/index.ts
··· 21 21 import getVolumes from "./io/pocketenv/volume/getVolumes"; 22 22 import putPreferences from "./io/pocketenv/sandbox/putPreferences"; 23 23 import getPreferences from "./io/pocketenv/sandbox/getPreferences"; 24 + import addVariable from "./io/pocketenv/variable/addVariable"; 24 25 25 26 export default function (server: Server, ctx: Context) { 26 27 // io.pocketenv ··· 40 41 deleteFile(server, ctx); 41 42 getFiles(server, ctx); 42 43 addSecret(server, ctx); 44 + addVariable(server, ctx); 43 45 deleteSecret(server, ctx); 44 46 getSecrets(server, ctx); 45 47 addVolume(server, ctx);
+30
apps/api/src/xrpc/io/pocketenv/file/addFile.ts
··· 2 2 import type { Context } from "context"; 3 3 import type { Server } from "lexicon"; 4 4 import type { HandlerInput } from "lexicon/types/io/pocketenv/file/addFile"; 5 + import files from "schema/files"; 6 + import sandboxFiles from "schema/sandbox-files"; 5 7 6 8 export default function (server: Server, ctx: Context) { 7 9 const addFile = async (input: HandlerInput, auth: HandlerAuth) => { 10 + if (!auth.credentials) { 11 + throw new XRPCError(401, "Unauthorized"); 12 + } 13 + 14 + await ctx.db.transaction(async (tx) => { 15 + const [file] = await tx 16 + .insert(files) 17 + .values({ 18 + content: input.body.file.content, 19 + }) 20 + .returning() 21 + .execute(); 22 + 23 + if (!file?.id) throw new XRPCError(500, "Failed to insert file"); 24 + 25 + if (!input.body.file.sandboxId) { 26 + return; 27 + } 28 + 29 + await tx 30 + .insert(sandboxFiles) 31 + .values({ 32 + fileId: file.id, 33 + sandboxId: input.body.file.sandboxId, 34 + path: input.body.file.path, 35 + }) 36 + .execute(); 37 + }); 8 38 return {}; 9 39 }; 10 40 server.io.pocketenv.file.addFile({
+33
apps/api/src/xrpc/io/pocketenv/secret/addSecret.ts
··· 2 2 import type { Context } from "context"; 3 3 import type { Server } from "lexicon"; 4 4 import type { HandlerInput } from "lexicon/types/io/pocketenv/secret/addSecret"; 5 + import sandboxSecrets from "schema/sandbox-secrets"; 6 + import secrets from "schema/secrets"; 5 7 6 8 export default function (server: Server, ctx: Context) { 7 9 const addSecret = async (input: HandlerInput, auth: HandlerAuth) => { 10 + if (!auth.credentials) { 11 + throw new XRPCError(401, "Unauthorized"); 12 + } 13 + 14 + await ctx.db.transaction(async (tx) => { 15 + const [secret] = await tx 16 + .insert(secrets) 17 + .values({ 18 + name: input.body.secret.name, 19 + value: input.body.secret.value, 20 + }) 21 + .returning() 22 + .execute(); 23 + 24 + if (!secret) { 25 + throw new XRPCError(500, "Failed to add secret"); 26 + } 27 + 28 + if (!input.body.secret.sandboxId) { 29 + return; 30 + } 31 + 32 + await tx 33 + .insert(sandboxSecrets) 34 + .values({ 35 + secretId: secret.id, 36 + sandboxId: input.body.secret.sandboxId, 37 + }) 38 + .returning() 39 + .execute(); 40 + }); 8 41 return {}; 9 42 }; 10 43 server.io.pocketenv.secret.addSecret({
+32 -1
apps/api/src/xrpc/io/pocketenv/variable/addVariable.ts
··· 2 2 import type { Context } from "context"; 3 3 import type { Server } from "lexicon"; 4 4 import type { HandlerInput } from "lexicon/types/io/pocketenv/variable/addVariable"; 5 + import sandboxVariables from "schema/sandbox-variables"; 6 + import variables from "schema/variables"; 5 7 6 8 export default function (server: Server, ctx: Context) { 7 9 const addVariable = async (input: HandlerInput, auth: HandlerAuth) => { 8 - return {}; 10 + if (!auth.credentials) { 11 + throw new XRPCError(401, "Unauthorized"); 12 + } 13 + 14 + await ctx.db.transaction(async (tx) => { 15 + const [variable] = await tx 16 + .insert(variables) 17 + .values({ 18 + name: input.body.variable.name, 19 + value: input.body.variable.value, 20 + }) 21 + .returning() 22 + .execute(); 23 + 24 + if (!variable) { 25 + throw new XRPCError(500, "Failed to add variable"); 26 + } 27 + 28 + if (!input.body.variable.sandboxId) { 29 + return; 30 + } 31 + 32 + await tx 33 + .insert(sandboxVariables) 34 + .values({ 35 + sandboxId: input.body.variable.sandboxId, 36 + variableId: variable.id, 37 + }) 38 + .execute(); 39 + }); 9 40 }; 10 41 server.io.pocketenv.variable.addVariable({ 11 42 auth: ctx.authVerifier,
+61
apps/api/src/xrpc/io/pocketenv/volume/addVolume.ts
··· 1 1 import { XRPCError, type HandlerAuth } from "@atproto/xrpc-server"; 2 2 import type { Context } from "context"; 3 + import { eq } from "drizzle-orm"; 3 4 import type { Server } from "lexicon"; 4 5 import type { HandlerInput } from "lexicon/types/io/pocketenv/volume/addVolume"; 6 + import sandboxVolumes from "schema/sandbox-volumes"; 7 + import volumes from "schema/volumes"; 8 + import { 9 + adjectives, 10 + generateUniqueAsync, 11 + nouns, 12 + } from "unique-username-generator"; 5 13 6 14 export default function (server: Server, ctx: Context) { 7 15 const addVolume = async (input: HandlerInput, auth: HandlerAuth) => { 16 + if (!auth.credentials) { 17 + throw new XRPCError(401, "Unauthorized"); 18 + } 19 + 20 + let slug, suffix, existing; 21 + do { 22 + slug = await generateUniqueAsync( 23 + { dictionaries: [adjectives, nouns], separator: "-" }, 24 + () => false, 25 + ); 26 + 27 + suffix = Math.random().toString(36).substring(2, 6); 28 + slug = `${slug}-${suffix}`; 29 + 30 + existing = await ctx.db 31 + .select() 32 + .from(volumes) 33 + .where(eq(volumes.slug, slug)) 34 + .execute(); 35 + if (existing.length === 0) { 36 + break; 37 + } 38 + } while (true); 39 + 40 + await ctx.db.transaction(async (tx) => { 41 + const [volume] = await tx 42 + .insert(volumes) 43 + .values({ 44 + slug, 45 + size: 20, 46 + sizeUnit: "GB", 47 + }) 48 + .returning() 49 + .execute(); 50 + 51 + if (!volume?.id) { 52 + throw new XRPCError(500, "Failed to create volume"); 53 + } 54 + 55 + if (!input.body.volume.sandboxId || !input.body.volume.path) { 56 + return; 57 + } 58 + 59 + await tx 60 + .insert(sandboxVolumes) 61 + .values({ 62 + volumeId: volume.id, 63 + sandboxId: input.body.volume.sandboxId, 64 + path: input.body.volume.path, 65 + }) 66 + .execute(); 67 + }); 68 + 8 69 return {}; 9 70 }; 10 71 server.io.pocketenv.volume.addVolume({
+2
apps/cf-sandbox/Dockerfile
··· 75 75 76 76 RUN echo 'PATH="$HOME/.deno/bin:$HOME/.local/bin:$PATH"' >> ~/.bashrc 77 77 78 + COPY banner.sh /root/.local/bin 79 + 78 80 WORKDIR /workspace 79 81 80 82 ENV COMMAND_TIMEOUT_MS=300000
+32
apps/cf-sandbox/banner.sh
··· 1 + #!/usr/bin/env bash 2 + 3 + readonly MAGENTA="$(tput setaf 5 2>/dev/null || echo '')" 4 + readonly GREEN="$(tput setaf 2 2>/dev/null || echo '')" 5 + readonly CYAN="$(tput setaf 6 2>/dev/null || echo '')" 6 + readonly NEON="$(tput setaf 50 2>/dev/null || echo '')" 7 + readonly NO_COLOR="$(tput sgr0 2>/dev/null || echo '')" 8 + 9 + cat << EOF 10 + ${NEON} 11 + ██████╗ ██████╗ ██████╗██╗ ██╗███████╗████████╗███████╗███╗ ██╗██╗ ██╗ 12 + ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝╚══██╔══╝██╔════╝████╗ ██║██║ ██║ 13 + ██████╔╝██║ ██║██║ █████╔╝ █████╗ ██║ █████╗ ██╔██╗ ██║██║ ██║ 14 + ██╔═══╝ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║ ██╔══╝ ██║╚██╗██║╚██╗ ██╔╝ 15 + ██║ ╚██████╔╝╚██████╗██║ ██╗███████╗ ██║ ███████╗██║ ╚████║ ╚████╔╝ 16 + ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═══╝ 17 + ${NO_COLOR} 18 + 19 + ╭─────────────────────────────────────────────────────────────╮ 20 + │ This environment is ephemeral. │ 21 + │ What you build here lives fast and dies clean. │ 22 + │ │ 23 + │ Break systems. │ 24 + │ Spawn agents. │ 25 + │ Ship experiments. │ 26 + ╰─────────────────────────────────────────────────────────────╯ 27 + 28 + Type ${NEON}openclaw${NO_COLOR} to get started. 29 + 30 + Happy hacking! 🎉 31 + 32 + EOF
+1
apps/cf-sandbox/drizzle/0013_faulty_captain_stacy.sql
··· 1 + ALTER TABLE "sandbox_volumes" ADD COLUMN "path" text NOT NULL;
+16
apps/cf-sandbox/drizzle/0014_wakeful_kingpin.sql
··· 1 + CREATE TABLE "files" ( 2 + "id" text PRIMARY KEY DEFAULT variable_id() NOT NULL, 3 + "content" text NOT NULL, 4 + "created_at" timestamp DEFAULT now() NOT NULL, 5 + "updated_at" timestamp DEFAULT now() NOT NULL 6 + ); 7 + --> statement-breakpoint 8 + CREATE TABLE "sandbox_files" ( 9 + "id" text PRIMARY KEY DEFAULT xata_id() NOT NULL, 10 + "sandbox_id" text NOT NULL, 11 + "file_id" text NOT NULL, 12 + "path" text NOT NULL 13 + ); 14 + --> statement-breakpoint 15 + ALTER TABLE "sandbox_files" ADD CONSTRAINT "sandbox_files_sandbox_id_sandboxes_id_fk" FOREIGN KEY ("sandbox_id") REFERENCES "public"."sandboxes"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint 16 + ALTER TABLE "sandbox_files" ADD CONSTRAINT "sandbox_files_file_id_files_id_fk" FOREIGN KEY ("file_id") REFERENCES "public"."files"("id") ON DELETE no action ON UPDATE no action;
+763
apps/cf-sandbox/drizzle/meta/0013_snapshot.json
··· 1 + { 2 + "id": "b1ee5071-9348-4241-931a-2553366d2ade", 3 + "prevId": "bbc292d8-d78f-4887-934c-7de4b2f52f6b", 4 + "version": "7", 5 + "dialect": "postgresql", 6 + "tables": { 7 + "public.authorized_keys": { 8 + "name": "authorized_keys", 9 + "schema": "", 10 + "columns": { 11 + "id": { 12 + "name": "id", 13 + "type": "text", 14 + "primaryKey": true, 15 + "notNull": true, 16 + "default": "xata_id()" 17 + }, 18 + "sandbox_id": { 19 + "name": "sandbox_id", 20 + "type": "text", 21 + "primaryKey": false, 22 + "notNull": false 23 + }, 24 + "public_key": { 25 + "name": "public_key", 26 + "type": "text", 27 + "primaryKey": false, 28 + "notNull": true 29 + }, 30 + "created_at": { 31 + "name": "created_at", 32 + "type": "timestamp", 33 + "primaryKey": false, 34 + "notNull": true, 35 + "default": "now()" 36 + } 37 + }, 38 + "indexes": {}, 39 + "foreignKeys": { 40 + "authorized_keys_sandbox_id_sandboxes_id_fk": { 41 + "name": "authorized_keys_sandbox_id_sandboxes_id_fk", 42 + "tableFrom": "authorized_keys", 43 + "tableTo": "sandboxes", 44 + "columnsFrom": [ 45 + "sandbox_id" 46 + ], 47 + "columnsTo": [ 48 + "id" 49 + ], 50 + "onDelete": "no action", 51 + "onUpdate": "no action" 52 + } 53 + }, 54 + "compositePrimaryKeys": {}, 55 + "uniqueConstraints": {}, 56 + "policies": {}, 57 + "checkConstraints": {}, 58 + "isRLSEnabled": false 59 + }, 60 + "public.sandbox_secrets": { 61 + "name": "sandbox_secrets", 62 + "schema": "", 63 + "columns": { 64 + "id": { 65 + "name": "id", 66 + "type": "text", 67 + "primaryKey": true, 68 + "notNull": true, 69 + "default": "xata_id()" 70 + }, 71 + "sandbox_id": { 72 + "name": "sandbox_id", 73 + "type": "text", 74 + "primaryKey": false, 75 + "notNull": true 76 + }, 77 + "secret_id": { 78 + "name": "secret_id", 79 + "type": "text", 80 + "primaryKey": false, 81 + "notNull": true 82 + } 83 + }, 84 + "indexes": { 85 + "unique_sandbox_secret": { 86 + "name": "unique_sandbox_secret", 87 + "columns": [ 88 + { 89 + "expression": "sandbox_id", 90 + "isExpression": false, 91 + "asc": true, 92 + "nulls": "last" 93 + }, 94 + { 95 + "expression": "secret_id", 96 + "isExpression": false, 97 + "asc": true, 98 + "nulls": "last" 99 + } 100 + ], 101 + "isUnique": true, 102 + "concurrently": false, 103 + "method": "btree", 104 + "with": {} 105 + } 106 + }, 107 + "foreignKeys": { 108 + "sandbox_secrets_sandbox_id_sandboxes_id_fk": { 109 + "name": "sandbox_secrets_sandbox_id_sandboxes_id_fk", 110 + "tableFrom": "sandbox_secrets", 111 + "tableTo": "sandboxes", 112 + "columnsFrom": [ 113 + "sandbox_id" 114 + ], 115 + "columnsTo": [ 116 + "id" 117 + ], 118 + "onDelete": "no action", 119 + "onUpdate": "no action" 120 + }, 121 + "sandbox_secrets_secret_id_secrets_id_fk": { 122 + "name": "sandbox_secrets_secret_id_secrets_id_fk", 123 + "tableFrom": "sandbox_secrets", 124 + "tableTo": "secrets", 125 + "columnsFrom": [ 126 + "secret_id" 127 + ], 128 + "columnsTo": [ 129 + "id" 130 + ], 131 + "onDelete": "no action", 132 + "onUpdate": "no action" 133 + } 134 + }, 135 + "compositePrimaryKeys": {}, 136 + "uniqueConstraints": {}, 137 + "policies": {}, 138 + "checkConstraints": {}, 139 + "isRLSEnabled": false 140 + }, 141 + "public.sandbox_variables": { 142 + "name": "sandbox_variables", 143 + "schema": "", 144 + "columns": { 145 + "id": { 146 + "name": "id", 147 + "type": "text", 148 + "primaryKey": true, 149 + "notNull": true, 150 + "default": "xata_id()" 151 + }, 152 + "sandbox_id": { 153 + "name": "sandbox_id", 154 + "type": "text", 155 + "primaryKey": false, 156 + "notNull": true 157 + }, 158 + "variable_id": { 159 + "name": "variable_id", 160 + "type": "text", 161 + "primaryKey": false, 162 + "notNull": true 163 + } 164 + }, 165 + "indexes": { 166 + "unique_sandbox_variables": { 167 + "name": "unique_sandbox_variables", 168 + "columns": [ 169 + { 170 + "expression": "sandbox_id", 171 + "isExpression": false, 172 + "asc": true, 173 + "nulls": "last" 174 + }, 175 + { 176 + "expression": "variable_id", 177 + "isExpression": false, 178 + "asc": true, 179 + "nulls": "last" 180 + } 181 + ], 182 + "isUnique": true, 183 + "concurrently": false, 184 + "method": "btree", 185 + "with": {} 186 + } 187 + }, 188 + "foreignKeys": { 189 + "sandbox_variables_sandbox_id_sandboxes_id_fk": { 190 + "name": "sandbox_variables_sandbox_id_sandboxes_id_fk", 191 + "tableFrom": "sandbox_variables", 192 + "tableTo": "sandboxes", 193 + "columnsFrom": [ 194 + "sandbox_id" 195 + ], 196 + "columnsTo": [ 197 + "id" 198 + ], 199 + "onDelete": "no action", 200 + "onUpdate": "no action" 201 + }, 202 + "sandbox_variables_variable_id_variables_id_fk": { 203 + "name": "sandbox_variables_variable_id_variables_id_fk", 204 + "tableFrom": "sandbox_variables", 205 + "tableTo": "variables", 206 + "columnsFrom": [ 207 + "variable_id" 208 + ], 209 + "columnsTo": [ 210 + "id" 211 + ], 212 + "onDelete": "no action", 213 + "onUpdate": "no action" 214 + } 215 + }, 216 + "compositePrimaryKeys": {}, 217 + "uniqueConstraints": {}, 218 + "policies": {}, 219 + "checkConstraints": {}, 220 + "isRLSEnabled": false 221 + }, 222 + "public.sandbox_volumes": { 223 + "name": "sandbox_volumes", 224 + "schema": "", 225 + "columns": { 226 + "id": { 227 + "name": "id", 228 + "type": "text", 229 + "primaryKey": true, 230 + "notNull": true, 231 + "default": "xata_id()" 232 + }, 233 + "sandbox_id": { 234 + "name": "sandbox_id", 235 + "type": "text", 236 + "primaryKey": false, 237 + "notNull": true 238 + }, 239 + "volume_id": { 240 + "name": "volume_id", 241 + "type": "text", 242 + "primaryKey": false, 243 + "notNull": true 244 + }, 245 + "path": { 246 + "name": "path", 247 + "type": "text", 248 + "primaryKey": false, 249 + "notNull": true 250 + } 251 + }, 252 + "indexes": {}, 253 + "foreignKeys": { 254 + "sandbox_volumes_sandbox_id_sandboxes_id_fk": { 255 + "name": "sandbox_volumes_sandbox_id_sandboxes_id_fk", 256 + "tableFrom": "sandbox_volumes", 257 + "tableTo": "sandboxes", 258 + "columnsFrom": [ 259 + "sandbox_id" 260 + ], 261 + "columnsTo": [ 262 + "id" 263 + ], 264 + "onDelete": "no action", 265 + "onUpdate": "no action" 266 + }, 267 + "sandbox_volumes_volume_id_volumes_id_fk": { 268 + "name": "sandbox_volumes_volume_id_volumes_id_fk", 269 + "tableFrom": "sandbox_volumes", 270 + "tableTo": "volumes", 271 + "columnsFrom": [ 272 + "volume_id" 273 + ], 274 + "columnsTo": [ 275 + "id" 276 + ], 277 + "onDelete": "no action", 278 + "onUpdate": "no action" 279 + } 280 + }, 281 + "compositePrimaryKeys": {}, 282 + "uniqueConstraints": {}, 283 + "policies": {}, 284 + "checkConstraints": {}, 285 + "isRLSEnabled": false 286 + }, 287 + "public.sandboxes": { 288 + "name": "sandboxes", 289 + "schema": "", 290 + "columns": { 291 + "id": { 292 + "name": "id", 293 + "type": "text", 294 + "primaryKey": true, 295 + "notNull": true, 296 + "default": "sandbox_id()" 297 + }, 298 + "base": { 299 + "name": "base", 300 + "type": "text", 301 + "primaryKey": false, 302 + "notNull": false 303 + }, 304 + "name": { 305 + "name": "name", 306 + "type": "text", 307 + "primaryKey": false, 308 + "notNull": true 309 + }, 310 + "display_name": { 311 + "name": "display_name", 312 + "type": "text", 313 + "primaryKey": false, 314 + "notNull": false 315 + }, 316 + "uri": { 317 + "name": "uri", 318 + "type": "text", 319 + "primaryKey": false, 320 + "notNull": false 321 + }, 322 + "cid": { 323 + "name": "cid", 324 + "type": "text", 325 + "primaryKey": false, 326 + "notNull": false 327 + }, 328 + "repo": { 329 + "name": "repo", 330 + "type": "text", 331 + "primaryKey": false, 332 + "notNull": false 333 + }, 334 + "provider": { 335 + "name": "provider", 336 + "type": "text", 337 + "primaryKey": false, 338 + "notNull": true, 339 + "default": "'cloudflare'" 340 + }, 341 + "description": { 342 + "name": "description", 343 + "type": "text", 344 + "primaryKey": false, 345 + "notNull": false 346 + }, 347 + "logo": { 348 + "name": "logo", 349 + "type": "text", 350 + "primaryKey": false, 351 + "notNull": false 352 + }, 353 + "readme": { 354 + "name": "readme", 355 + "type": "text", 356 + "primaryKey": false, 357 + "notNull": false 358 + }, 359 + "public_key": { 360 + "name": "public_key", 361 + "type": "text", 362 + "primaryKey": false, 363 + "notNull": true 364 + }, 365 + "user_id": { 366 + "name": "user_id", 367 + "type": "text", 368 + "primaryKey": false, 369 + "notNull": false 370 + }, 371 + "instance_type": { 372 + "name": "instance_type", 373 + "type": "text", 374 + "primaryKey": false, 375 + "notNull": false 376 + }, 377 + "vcpus": { 378 + "name": "vcpus", 379 + "type": "integer", 380 + "primaryKey": false, 381 + "notNull": false 382 + }, 383 + "memory": { 384 + "name": "memory", 385 + "type": "integer", 386 + "primaryKey": false, 387 + "notNull": false 388 + }, 389 + "disk": { 390 + "name": "disk", 391 + "type": "integer", 392 + "primaryKey": false, 393 + "notNull": false 394 + }, 395 + "status": { 396 + "name": "status", 397 + "type": "text", 398 + "primaryKey": false, 399 + "notNull": true 400 + }, 401 + "keep_alive": { 402 + "name": "keep_alive", 403 + "type": "boolean", 404 + "primaryKey": false, 405 + "notNull": true, 406 + "default": false 407 + }, 408 + "sleep_after": { 409 + "name": "sleep_after", 410 + "type": "text", 411 + "primaryKey": false, 412 + "notNull": false 413 + }, 414 + "sandbox_id": { 415 + "name": "sandbox_id", 416 + "type": "text", 417 + "primaryKey": false, 418 + "notNull": false 419 + }, 420 + "installs": { 421 + "name": "installs", 422 + "type": "integer", 423 + "primaryKey": false, 424 + "notNull": true, 425 + "default": 0 426 + }, 427 + "started_at": { 428 + "name": "started_at", 429 + "type": "timestamp", 430 + "primaryKey": false, 431 + "notNull": false 432 + }, 433 + "created_at": { 434 + "name": "created_at", 435 + "type": "timestamp", 436 + "primaryKey": false, 437 + "notNull": true, 438 + "default": "now()" 439 + }, 440 + "updated_at": { 441 + "name": "updated_at", 442 + "type": "timestamp", 443 + "primaryKey": false, 444 + "notNull": true, 445 + "default": "now()" 446 + } 447 + }, 448 + "indexes": {}, 449 + "foreignKeys": { 450 + "sandboxes_user_id_users_id_fk": { 451 + "name": "sandboxes_user_id_users_id_fk", 452 + "tableFrom": "sandboxes", 453 + "tableTo": "users", 454 + "columnsFrom": [ 455 + "user_id" 456 + ], 457 + "columnsTo": [ 458 + "id" 459 + ], 460 + "onDelete": "no action", 461 + "onUpdate": "no action" 462 + } 463 + }, 464 + "compositePrimaryKeys": {}, 465 + "uniqueConstraints": { 466 + "sandboxes_name_unique": { 467 + "name": "sandboxes_name_unique", 468 + "nullsNotDistinct": false, 469 + "columns": [ 470 + "name" 471 + ] 472 + }, 473 + "sandboxes_uri_unique": { 474 + "name": "sandboxes_uri_unique", 475 + "nullsNotDistinct": false, 476 + "columns": [ 477 + "uri" 478 + ] 479 + }, 480 + "sandboxes_cid_unique": { 481 + "name": "sandboxes_cid_unique", 482 + "nullsNotDistinct": false, 483 + "columns": [ 484 + "cid" 485 + ] 486 + } 487 + }, 488 + "policies": {}, 489 + "checkConstraints": {}, 490 + "isRLSEnabled": false 491 + }, 492 + "public.secrets": { 493 + "name": "secrets", 494 + "schema": "", 495 + "columns": { 496 + "id": { 497 + "name": "id", 498 + "type": "text", 499 + "primaryKey": true, 500 + "notNull": true, 501 + "default": "secret_id()" 502 + }, 503 + "name": { 504 + "name": "name", 505 + "type": "text", 506 + "primaryKey": false, 507 + "notNull": true 508 + }, 509 + "value": { 510 + "name": "value", 511 + "type": "text", 512 + "primaryKey": false, 513 + "notNull": true 514 + }, 515 + "created_at": { 516 + "name": "created_at", 517 + "type": "timestamp", 518 + "primaryKey": false, 519 + "notNull": true, 520 + "default": "now()" 521 + } 522 + }, 523 + "indexes": {}, 524 + "foreignKeys": {}, 525 + "compositePrimaryKeys": {}, 526 + "uniqueConstraints": {}, 527 + "policies": {}, 528 + "checkConstraints": {}, 529 + "isRLSEnabled": false 530 + }, 531 + "public.snapshots": { 532 + "name": "snapshots", 533 + "schema": "", 534 + "columns": { 535 + "id": { 536 + "name": "id", 537 + "type": "text", 538 + "primaryKey": true, 539 + "notNull": true, 540 + "default": "snapshot_id()" 541 + }, 542 + "slug": { 543 + "name": "slug", 544 + "type": "text", 545 + "primaryKey": false, 546 + "notNull": true 547 + }, 548 + "created_at": { 549 + "name": "created_at", 550 + "type": "timestamp", 551 + "primaryKey": false, 552 + "notNull": true, 553 + "default": "now()" 554 + } 555 + }, 556 + "indexes": {}, 557 + "foreignKeys": {}, 558 + "compositePrimaryKeys": {}, 559 + "uniqueConstraints": { 560 + "snapshots_slug_unique": { 561 + "name": "snapshots_slug_unique", 562 + "nullsNotDistinct": false, 563 + "columns": [ 564 + "slug" 565 + ] 566 + } 567 + }, 568 + "policies": {}, 569 + "checkConstraints": {}, 570 + "isRLSEnabled": false 571 + }, 572 + "public.users": { 573 + "name": "users", 574 + "schema": "", 575 + "columns": { 576 + "id": { 577 + "name": "id", 578 + "type": "text", 579 + "primaryKey": true, 580 + "notNull": true, 581 + "default": "xata_id()" 582 + }, 583 + "did": { 584 + "name": "did", 585 + "type": "text", 586 + "primaryKey": false, 587 + "notNull": true 588 + }, 589 + "display_name": { 590 + "name": "display_name", 591 + "type": "text", 592 + "primaryKey": false, 593 + "notNull": false 594 + }, 595 + "handle": { 596 + "name": "handle", 597 + "type": "text", 598 + "primaryKey": false, 599 + "notNull": true 600 + }, 601 + "avatar": { 602 + "name": "avatar", 603 + "type": "text", 604 + "primaryKey": false, 605 + "notNull": false 606 + }, 607 + "created_at": { 608 + "name": "created_at", 609 + "type": "timestamp", 610 + "primaryKey": false, 611 + "notNull": true, 612 + "default": "now()" 613 + }, 614 + "updated_at": { 615 + "name": "updated_at", 616 + "type": "timestamp", 617 + "primaryKey": false, 618 + "notNull": true, 619 + "default": "now()" 620 + } 621 + }, 622 + "indexes": {}, 623 + "foreignKeys": {}, 624 + "compositePrimaryKeys": {}, 625 + "uniqueConstraints": { 626 + "users_did_unique": { 627 + "name": "users_did_unique", 628 + "nullsNotDistinct": false, 629 + "columns": [ 630 + "did" 631 + ] 632 + }, 633 + "users_handle_unique": { 634 + "name": "users_handle_unique", 635 + "nullsNotDistinct": false, 636 + "columns": [ 637 + "handle" 638 + ] 639 + } 640 + }, 641 + "policies": {}, 642 + "checkConstraints": {}, 643 + "isRLSEnabled": false 644 + }, 645 + "public.variables": { 646 + "name": "variables", 647 + "schema": "", 648 + "columns": { 649 + "id": { 650 + "name": "id", 651 + "type": "text", 652 + "primaryKey": true, 653 + "notNull": true, 654 + "default": "variable_id()" 655 + }, 656 + "name": { 657 + "name": "name", 658 + "type": "text", 659 + "primaryKey": false, 660 + "notNull": true 661 + }, 662 + "value": { 663 + "name": "value", 664 + "type": "text", 665 + "primaryKey": false, 666 + "notNull": true 667 + }, 668 + "created_at": { 669 + "name": "created_at", 670 + "type": "timestamp", 671 + "primaryKey": false, 672 + "notNull": true, 673 + "default": "now()" 674 + }, 675 + "updated_at": { 676 + "name": "updated_at", 677 + "type": "timestamp", 678 + "primaryKey": false, 679 + "notNull": true, 680 + "default": "now()" 681 + } 682 + }, 683 + "indexes": {}, 684 + "foreignKeys": {}, 685 + "compositePrimaryKeys": {}, 686 + "uniqueConstraints": {}, 687 + "policies": {}, 688 + "checkConstraints": {}, 689 + "isRLSEnabled": false 690 + }, 691 + "public.volumes": { 692 + "name": "volumes", 693 + "schema": "", 694 + "columns": { 695 + "id": { 696 + "name": "id", 697 + "type": "text", 698 + "primaryKey": true, 699 + "notNull": true, 700 + "default": "volume_id()" 701 + }, 702 + "slug": { 703 + "name": "slug", 704 + "type": "text", 705 + "primaryKey": false, 706 + "notNull": true 707 + }, 708 + "size": { 709 + "name": "size", 710 + "type": "integer", 711 + "primaryKey": false, 712 + "notNull": true 713 + }, 714 + "size_unit": { 715 + "name": "size_unit", 716 + "type": "text", 717 + "primaryKey": false, 718 + "notNull": true 719 + }, 720 + "created_at": { 721 + "name": "created_at", 722 + "type": "timestamp", 723 + "primaryKey": false, 724 + "notNull": true, 725 + "default": "now()" 726 + }, 727 + "updated_at": { 728 + "name": "updated_at", 729 + "type": "timestamp", 730 + "primaryKey": false, 731 + "notNull": true, 732 + "default": "now()" 733 + } 734 + }, 735 + "indexes": {}, 736 + "foreignKeys": {}, 737 + "compositePrimaryKeys": {}, 738 + "uniqueConstraints": { 739 + "volumes_slug_unique": { 740 + "name": "volumes_slug_unique", 741 + "nullsNotDistinct": false, 742 + "columns": [ 743 + "slug" 744 + ] 745 + } 746 + }, 747 + "policies": {}, 748 + "checkConstraints": {}, 749 + "isRLSEnabled": false 750 + } 751 + }, 752 + "enums": {}, 753 + "schemas": {}, 754 + "sequences": {}, 755 + "roles": {}, 756 + "policies": {}, 757 + "views": {}, 758 + "_meta": { 759 + "columns": {}, 760 + "schemas": {}, 761 + "tables": {} 762 + } 763 + }
+868
apps/cf-sandbox/drizzle/meta/0014_snapshot.json
··· 1 + { 2 + "id": "e3be2b18-e17a-43de-b948-e7bfc91860ba", 3 + "prevId": "b1ee5071-9348-4241-931a-2553366d2ade", 4 + "version": "7", 5 + "dialect": "postgresql", 6 + "tables": { 7 + "public.authorized_keys": { 8 + "name": "authorized_keys", 9 + "schema": "", 10 + "columns": { 11 + "id": { 12 + "name": "id", 13 + "type": "text", 14 + "primaryKey": true, 15 + "notNull": true, 16 + "default": "xata_id()" 17 + }, 18 + "sandbox_id": { 19 + "name": "sandbox_id", 20 + "type": "text", 21 + "primaryKey": false, 22 + "notNull": false 23 + }, 24 + "public_key": { 25 + "name": "public_key", 26 + "type": "text", 27 + "primaryKey": false, 28 + "notNull": true 29 + }, 30 + "created_at": { 31 + "name": "created_at", 32 + "type": "timestamp", 33 + "primaryKey": false, 34 + "notNull": true, 35 + "default": "now()" 36 + } 37 + }, 38 + "indexes": {}, 39 + "foreignKeys": { 40 + "authorized_keys_sandbox_id_sandboxes_id_fk": { 41 + "name": "authorized_keys_sandbox_id_sandboxes_id_fk", 42 + "tableFrom": "authorized_keys", 43 + "tableTo": "sandboxes", 44 + "columnsFrom": [ 45 + "sandbox_id" 46 + ], 47 + "columnsTo": [ 48 + "id" 49 + ], 50 + "onDelete": "no action", 51 + "onUpdate": "no action" 52 + } 53 + }, 54 + "compositePrimaryKeys": {}, 55 + "uniqueConstraints": {}, 56 + "policies": {}, 57 + "checkConstraints": {}, 58 + "isRLSEnabled": false 59 + }, 60 + "public.files": { 61 + "name": "files", 62 + "schema": "", 63 + "columns": { 64 + "id": { 65 + "name": "id", 66 + "type": "text", 67 + "primaryKey": true, 68 + "notNull": true, 69 + "default": "variable_id()" 70 + }, 71 + "content": { 72 + "name": "content", 73 + "type": "text", 74 + "primaryKey": false, 75 + "notNull": true 76 + }, 77 + "created_at": { 78 + "name": "created_at", 79 + "type": "timestamp", 80 + "primaryKey": false, 81 + "notNull": true, 82 + "default": "now()" 83 + }, 84 + "updated_at": { 85 + "name": "updated_at", 86 + "type": "timestamp", 87 + "primaryKey": false, 88 + "notNull": true, 89 + "default": "now()" 90 + } 91 + }, 92 + "indexes": {}, 93 + "foreignKeys": {}, 94 + "compositePrimaryKeys": {}, 95 + "uniqueConstraints": {}, 96 + "policies": {}, 97 + "checkConstraints": {}, 98 + "isRLSEnabled": false 99 + }, 100 + "public.sandbox_files": { 101 + "name": "sandbox_files", 102 + "schema": "", 103 + "columns": { 104 + "id": { 105 + "name": "id", 106 + "type": "text", 107 + "primaryKey": true, 108 + "notNull": true, 109 + "default": "xata_id()" 110 + }, 111 + "sandbox_id": { 112 + "name": "sandbox_id", 113 + "type": "text", 114 + "primaryKey": false, 115 + "notNull": true 116 + }, 117 + "file_id": { 118 + "name": "file_id", 119 + "type": "text", 120 + "primaryKey": false, 121 + "notNull": true 122 + }, 123 + "path": { 124 + "name": "path", 125 + "type": "text", 126 + "primaryKey": false, 127 + "notNull": true 128 + } 129 + }, 130 + "indexes": {}, 131 + "foreignKeys": { 132 + "sandbox_files_sandbox_id_sandboxes_id_fk": { 133 + "name": "sandbox_files_sandbox_id_sandboxes_id_fk", 134 + "tableFrom": "sandbox_files", 135 + "tableTo": "sandboxes", 136 + "columnsFrom": [ 137 + "sandbox_id" 138 + ], 139 + "columnsTo": [ 140 + "id" 141 + ], 142 + "onDelete": "no action", 143 + "onUpdate": "no action" 144 + }, 145 + "sandbox_files_file_id_files_id_fk": { 146 + "name": "sandbox_files_file_id_files_id_fk", 147 + "tableFrom": "sandbox_files", 148 + "tableTo": "files", 149 + "columnsFrom": [ 150 + "file_id" 151 + ], 152 + "columnsTo": [ 153 + "id" 154 + ], 155 + "onDelete": "no action", 156 + "onUpdate": "no action" 157 + } 158 + }, 159 + "compositePrimaryKeys": {}, 160 + "uniqueConstraints": {}, 161 + "policies": {}, 162 + "checkConstraints": {}, 163 + "isRLSEnabled": false 164 + }, 165 + "public.sandbox_secrets": { 166 + "name": "sandbox_secrets", 167 + "schema": "", 168 + "columns": { 169 + "id": { 170 + "name": "id", 171 + "type": "text", 172 + "primaryKey": true, 173 + "notNull": true, 174 + "default": "xata_id()" 175 + }, 176 + "sandbox_id": { 177 + "name": "sandbox_id", 178 + "type": "text", 179 + "primaryKey": false, 180 + "notNull": true 181 + }, 182 + "secret_id": { 183 + "name": "secret_id", 184 + "type": "text", 185 + "primaryKey": false, 186 + "notNull": true 187 + } 188 + }, 189 + "indexes": { 190 + "unique_sandbox_secret": { 191 + "name": "unique_sandbox_secret", 192 + "columns": [ 193 + { 194 + "expression": "sandbox_id", 195 + "isExpression": false, 196 + "asc": true, 197 + "nulls": "last" 198 + }, 199 + { 200 + "expression": "secret_id", 201 + "isExpression": false, 202 + "asc": true, 203 + "nulls": "last" 204 + } 205 + ], 206 + "isUnique": true, 207 + "concurrently": false, 208 + "method": "btree", 209 + "with": {} 210 + } 211 + }, 212 + "foreignKeys": { 213 + "sandbox_secrets_sandbox_id_sandboxes_id_fk": { 214 + "name": "sandbox_secrets_sandbox_id_sandboxes_id_fk", 215 + "tableFrom": "sandbox_secrets", 216 + "tableTo": "sandboxes", 217 + "columnsFrom": [ 218 + "sandbox_id" 219 + ], 220 + "columnsTo": [ 221 + "id" 222 + ], 223 + "onDelete": "no action", 224 + "onUpdate": "no action" 225 + }, 226 + "sandbox_secrets_secret_id_secrets_id_fk": { 227 + "name": "sandbox_secrets_secret_id_secrets_id_fk", 228 + "tableFrom": "sandbox_secrets", 229 + "tableTo": "secrets", 230 + "columnsFrom": [ 231 + "secret_id" 232 + ], 233 + "columnsTo": [ 234 + "id" 235 + ], 236 + "onDelete": "no action", 237 + "onUpdate": "no action" 238 + } 239 + }, 240 + "compositePrimaryKeys": {}, 241 + "uniqueConstraints": {}, 242 + "policies": {}, 243 + "checkConstraints": {}, 244 + "isRLSEnabled": false 245 + }, 246 + "public.sandbox_variables": { 247 + "name": "sandbox_variables", 248 + "schema": "", 249 + "columns": { 250 + "id": { 251 + "name": "id", 252 + "type": "text", 253 + "primaryKey": true, 254 + "notNull": true, 255 + "default": "xata_id()" 256 + }, 257 + "sandbox_id": { 258 + "name": "sandbox_id", 259 + "type": "text", 260 + "primaryKey": false, 261 + "notNull": true 262 + }, 263 + "variable_id": { 264 + "name": "variable_id", 265 + "type": "text", 266 + "primaryKey": false, 267 + "notNull": true 268 + } 269 + }, 270 + "indexes": { 271 + "unique_sandbox_variables": { 272 + "name": "unique_sandbox_variables", 273 + "columns": [ 274 + { 275 + "expression": "sandbox_id", 276 + "isExpression": false, 277 + "asc": true, 278 + "nulls": "last" 279 + }, 280 + { 281 + "expression": "variable_id", 282 + "isExpression": false, 283 + "asc": true, 284 + "nulls": "last" 285 + } 286 + ], 287 + "isUnique": true, 288 + "concurrently": false, 289 + "method": "btree", 290 + "with": {} 291 + } 292 + }, 293 + "foreignKeys": { 294 + "sandbox_variables_sandbox_id_sandboxes_id_fk": { 295 + "name": "sandbox_variables_sandbox_id_sandboxes_id_fk", 296 + "tableFrom": "sandbox_variables", 297 + "tableTo": "sandboxes", 298 + "columnsFrom": [ 299 + "sandbox_id" 300 + ], 301 + "columnsTo": [ 302 + "id" 303 + ], 304 + "onDelete": "no action", 305 + "onUpdate": "no action" 306 + }, 307 + "sandbox_variables_variable_id_variables_id_fk": { 308 + "name": "sandbox_variables_variable_id_variables_id_fk", 309 + "tableFrom": "sandbox_variables", 310 + "tableTo": "variables", 311 + "columnsFrom": [ 312 + "variable_id" 313 + ], 314 + "columnsTo": [ 315 + "id" 316 + ], 317 + "onDelete": "no action", 318 + "onUpdate": "no action" 319 + } 320 + }, 321 + "compositePrimaryKeys": {}, 322 + "uniqueConstraints": {}, 323 + "policies": {}, 324 + "checkConstraints": {}, 325 + "isRLSEnabled": false 326 + }, 327 + "public.sandbox_volumes": { 328 + "name": "sandbox_volumes", 329 + "schema": "", 330 + "columns": { 331 + "id": { 332 + "name": "id", 333 + "type": "text", 334 + "primaryKey": true, 335 + "notNull": true, 336 + "default": "xata_id()" 337 + }, 338 + "sandbox_id": { 339 + "name": "sandbox_id", 340 + "type": "text", 341 + "primaryKey": false, 342 + "notNull": true 343 + }, 344 + "volume_id": { 345 + "name": "volume_id", 346 + "type": "text", 347 + "primaryKey": false, 348 + "notNull": true 349 + }, 350 + "path": { 351 + "name": "path", 352 + "type": "text", 353 + "primaryKey": false, 354 + "notNull": true 355 + } 356 + }, 357 + "indexes": {}, 358 + "foreignKeys": { 359 + "sandbox_volumes_sandbox_id_sandboxes_id_fk": { 360 + "name": "sandbox_volumes_sandbox_id_sandboxes_id_fk", 361 + "tableFrom": "sandbox_volumes", 362 + "tableTo": "sandboxes", 363 + "columnsFrom": [ 364 + "sandbox_id" 365 + ], 366 + "columnsTo": [ 367 + "id" 368 + ], 369 + "onDelete": "no action", 370 + "onUpdate": "no action" 371 + }, 372 + "sandbox_volumes_volume_id_volumes_id_fk": { 373 + "name": "sandbox_volumes_volume_id_volumes_id_fk", 374 + "tableFrom": "sandbox_volumes", 375 + "tableTo": "volumes", 376 + "columnsFrom": [ 377 + "volume_id" 378 + ], 379 + "columnsTo": [ 380 + "id" 381 + ], 382 + "onDelete": "no action", 383 + "onUpdate": "no action" 384 + } 385 + }, 386 + "compositePrimaryKeys": {}, 387 + "uniqueConstraints": {}, 388 + "policies": {}, 389 + "checkConstraints": {}, 390 + "isRLSEnabled": false 391 + }, 392 + "public.sandboxes": { 393 + "name": "sandboxes", 394 + "schema": "", 395 + "columns": { 396 + "id": { 397 + "name": "id", 398 + "type": "text", 399 + "primaryKey": true, 400 + "notNull": true, 401 + "default": "sandbox_id()" 402 + }, 403 + "base": { 404 + "name": "base", 405 + "type": "text", 406 + "primaryKey": false, 407 + "notNull": false 408 + }, 409 + "name": { 410 + "name": "name", 411 + "type": "text", 412 + "primaryKey": false, 413 + "notNull": true 414 + }, 415 + "display_name": { 416 + "name": "display_name", 417 + "type": "text", 418 + "primaryKey": false, 419 + "notNull": false 420 + }, 421 + "uri": { 422 + "name": "uri", 423 + "type": "text", 424 + "primaryKey": false, 425 + "notNull": false 426 + }, 427 + "cid": { 428 + "name": "cid", 429 + "type": "text", 430 + "primaryKey": false, 431 + "notNull": false 432 + }, 433 + "repo": { 434 + "name": "repo", 435 + "type": "text", 436 + "primaryKey": false, 437 + "notNull": false 438 + }, 439 + "provider": { 440 + "name": "provider", 441 + "type": "text", 442 + "primaryKey": false, 443 + "notNull": true, 444 + "default": "'cloudflare'" 445 + }, 446 + "description": { 447 + "name": "description", 448 + "type": "text", 449 + "primaryKey": false, 450 + "notNull": false 451 + }, 452 + "logo": { 453 + "name": "logo", 454 + "type": "text", 455 + "primaryKey": false, 456 + "notNull": false 457 + }, 458 + "readme": { 459 + "name": "readme", 460 + "type": "text", 461 + "primaryKey": false, 462 + "notNull": false 463 + }, 464 + "public_key": { 465 + "name": "public_key", 466 + "type": "text", 467 + "primaryKey": false, 468 + "notNull": true 469 + }, 470 + "user_id": { 471 + "name": "user_id", 472 + "type": "text", 473 + "primaryKey": false, 474 + "notNull": false 475 + }, 476 + "instance_type": { 477 + "name": "instance_type", 478 + "type": "text", 479 + "primaryKey": false, 480 + "notNull": false 481 + }, 482 + "vcpus": { 483 + "name": "vcpus", 484 + "type": "integer", 485 + "primaryKey": false, 486 + "notNull": false 487 + }, 488 + "memory": { 489 + "name": "memory", 490 + "type": "integer", 491 + "primaryKey": false, 492 + "notNull": false 493 + }, 494 + "disk": { 495 + "name": "disk", 496 + "type": "integer", 497 + "primaryKey": false, 498 + "notNull": false 499 + }, 500 + "status": { 501 + "name": "status", 502 + "type": "text", 503 + "primaryKey": false, 504 + "notNull": true 505 + }, 506 + "keep_alive": { 507 + "name": "keep_alive", 508 + "type": "boolean", 509 + "primaryKey": false, 510 + "notNull": true, 511 + "default": false 512 + }, 513 + "sleep_after": { 514 + "name": "sleep_after", 515 + "type": "text", 516 + "primaryKey": false, 517 + "notNull": false 518 + }, 519 + "sandbox_id": { 520 + "name": "sandbox_id", 521 + "type": "text", 522 + "primaryKey": false, 523 + "notNull": false 524 + }, 525 + "installs": { 526 + "name": "installs", 527 + "type": "integer", 528 + "primaryKey": false, 529 + "notNull": true, 530 + "default": 0 531 + }, 532 + "started_at": { 533 + "name": "started_at", 534 + "type": "timestamp", 535 + "primaryKey": false, 536 + "notNull": false 537 + }, 538 + "created_at": { 539 + "name": "created_at", 540 + "type": "timestamp", 541 + "primaryKey": false, 542 + "notNull": true, 543 + "default": "now()" 544 + }, 545 + "updated_at": { 546 + "name": "updated_at", 547 + "type": "timestamp", 548 + "primaryKey": false, 549 + "notNull": true, 550 + "default": "now()" 551 + } 552 + }, 553 + "indexes": {}, 554 + "foreignKeys": { 555 + "sandboxes_user_id_users_id_fk": { 556 + "name": "sandboxes_user_id_users_id_fk", 557 + "tableFrom": "sandboxes", 558 + "tableTo": "users", 559 + "columnsFrom": [ 560 + "user_id" 561 + ], 562 + "columnsTo": [ 563 + "id" 564 + ], 565 + "onDelete": "no action", 566 + "onUpdate": "no action" 567 + } 568 + }, 569 + "compositePrimaryKeys": {}, 570 + "uniqueConstraints": { 571 + "sandboxes_name_unique": { 572 + "name": "sandboxes_name_unique", 573 + "nullsNotDistinct": false, 574 + "columns": [ 575 + "name" 576 + ] 577 + }, 578 + "sandboxes_uri_unique": { 579 + "name": "sandboxes_uri_unique", 580 + "nullsNotDistinct": false, 581 + "columns": [ 582 + "uri" 583 + ] 584 + }, 585 + "sandboxes_cid_unique": { 586 + "name": "sandboxes_cid_unique", 587 + "nullsNotDistinct": false, 588 + "columns": [ 589 + "cid" 590 + ] 591 + } 592 + }, 593 + "policies": {}, 594 + "checkConstraints": {}, 595 + "isRLSEnabled": false 596 + }, 597 + "public.secrets": { 598 + "name": "secrets", 599 + "schema": "", 600 + "columns": { 601 + "id": { 602 + "name": "id", 603 + "type": "text", 604 + "primaryKey": true, 605 + "notNull": true, 606 + "default": "secret_id()" 607 + }, 608 + "name": { 609 + "name": "name", 610 + "type": "text", 611 + "primaryKey": false, 612 + "notNull": true 613 + }, 614 + "value": { 615 + "name": "value", 616 + "type": "text", 617 + "primaryKey": false, 618 + "notNull": true 619 + }, 620 + "created_at": { 621 + "name": "created_at", 622 + "type": "timestamp", 623 + "primaryKey": false, 624 + "notNull": true, 625 + "default": "now()" 626 + } 627 + }, 628 + "indexes": {}, 629 + "foreignKeys": {}, 630 + "compositePrimaryKeys": {}, 631 + "uniqueConstraints": {}, 632 + "policies": {}, 633 + "checkConstraints": {}, 634 + "isRLSEnabled": false 635 + }, 636 + "public.snapshots": { 637 + "name": "snapshots", 638 + "schema": "", 639 + "columns": { 640 + "id": { 641 + "name": "id", 642 + "type": "text", 643 + "primaryKey": true, 644 + "notNull": true, 645 + "default": "snapshot_id()" 646 + }, 647 + "slug": { 648 + "name": "slug", 649 + "type": "text", 650 + "primaryKey": false, 651 + "notNull": true 652 + }, 653 + "created_at": { 654 + "name": "created_at", 655 + "type": "timestamp", 656 + "primaryKey": false, 657 + "notNull": true, 658 + "default": "now()" 659 + } 660 + }, 661 + "indexes": {}, 662 + "foreignKeys": {}, 663 + "compositePrimaryKeys": {}, 664 + "uniqueConstraints": { 665 + "snapshots_slug_unique": { 666 + "name": "snapshots_slug_unique", 667 + "nullsNotDistinct": false, 668 + "columns": [ 669 + "slug" 670 + ] 671 + } 672 + }, 673 + "policies": {}, 674 + "checkConstraints": {}, 675 + "isRLSEnabled": false 676 + }, 677 + "public.users": { 678 + "name": "users", 679 + "schema": "", 680 + "columns": { 681 + "id": { 682 + "name": "id", 683 + "type": "text", 684 + "primaryKey": true, 685 + "notNull": true, 686 + "default": "xata_id()" 687 + }, 688 + "did": { 689 + "name": "did", 690 + "type": "text", 691 + "primaryKey": false, 692 + "notNull": true 693 + }, 694 + "display_name": { 695 + "name": "display_name", 696 + "type": "text", 697 + "primaryKey": false, 698 + "notNull": false 699 + }, 700 + "handle": { 701 + "name": "handle", 702 + "type": "text", 703 + "primaryKey": false, 704 + "notNull": true 705 + }, 706 + "avatar": { 707 + "name": "avatar", 708 + "type": "text", 709 + "primaryKey": false, 710 + "notNull": false 711 + }, 712 + "created_at": { 713 + "name": "created_at", 714 + "type": "timestamp", 715 + "primaryKey": false, 716 + "notNull": true, 717 + "default": "now()" 718 + }, 719 + "updated_at": { 720 + "name": "updated_at", 721 + "type": "timestamp", 722 + "primaryKey": false, 723 + "notNull": true, 724 + "default": "now()" 725 + } 726 + }, 727 + "indexes": {}, 728 + "foreignKeys": {}, 729 + "compositePrimaryKeys": {}, 730 + "uniqueConstraints": { 731 + "users_did_unique": { 732 + "name": "users_did_unique", 733 + "nullsNotDistinct": false, 734 + "columns": [ 735 + "did" 736 + ] 737 + }, 738 + "users_handle_unique": { 739 + "name": "users_handle_unique", 740 + "nullsNotDistinct": false, 741 + "columns": [ 742 + "handle" 743 + ] 744 + } 745 + }, 746 + "policies": {}, 747 + "checkConstraints": {}, 748 + "isRLSEnabled": false 749 + }, 750 + "public.variables": { 751 + "name": "variables", 752 + "schema": "", 753 + "columns": { 754 + "id": { 755 + "name": "id", 756 + "type": "text", 757 + "primaryKey": true, 758 + "notNull": true, 759 + "default": "variable_id()" 760 + }, 761 + "name": { 762 + "name": "name", 763 + "type": "text", 764 + "primaryKey": false, 765 + "notNull": true 766 + }, 767 + "value": { 768 + "name": "value", 769 + "type": "text", 770 + "primaryKey": false, 771 + "notNull": true 772 + }, 773 + "created_at": { 774 + "name": "created_at", 775 + "type": "timestamp", 776 + "primaryKey": false, 777 + "notNull": true, 778 + "default": "now()" 779 + }, 780 + "updated_at": { 781 + "name": "updated_at", 782 + "type": "timestamp", 783 + "primaryKey": false, 784 + "notNull": true, 785 + "default": "now()" 786 + } 787 + }, 788 + "indexes": {}, 789 + "foreignKeys": {}, 790 + "compositePrimaryKeys": {}, 791 + "uniqueConstraints": {}, 792 + "policies": {}, 793 + "checkConstraints": {}, 794 + "isRLSEnabled": false 795 + }, 796 + "public.volumes": { 797 + "name": "volumes", 798 + "schema": "", 799 + "columns": { 800 + "id": { 801 + "name": "id", 802 + "type": "text", 803 + "primaryKey": true, 804 + "notNull": true, 805 + "default": "volume_id()" 806 + }, 807 + "slug": { 808 + "name": "slug", 809 + "type": "text", 810 + "primaryKey": false, 811 + "notNull": true 812 + }, 813 + "size": { 814 + "name": "size", 815 + "type": "integer", 816 + "primaryKey": false, 817 + "notNull": true 818 + }, 819 + "size_unit": { 820 + "name": "size_unit", 821 + "type": "text", 822 + "primaryKey": false, 823 + "notNull": true 824 + }, 825 + "created_at": { 826 + "name": "created_at", 827 + "type": "timestamp", 828 + "primaryKey": false, 829 + "notNull": true, 830 + "default": "now()" 831 + }, 832 + "updated_at": { 833 + "name": "updated_at", 834 + "type": "timestamp", 835 + "primaryKey": false, 836 + "notNull": true, 837 + "default": "now()" 838 + } 839 + }, 840 + "indexes": {}, 841 + "foreignKeys": {}, 842 + "compositePrimaryKeys": {}, 843 + "uniqueConstraints": { 844 + "volumes_slug_unique": { 845 + "name": "volumes_slug_unique", 846 + "nullsNotDistinct": false, 847 + "columns": [ 848 + "slug" 849 + ] 850 + } 851 + }, 852 + "policies": {}, 853 + "checkConstraints": {}, 854 + "isRLSEnabled": false 855 + } 856 + }, 857 + "enums": {}, 858 + "schemas": {}, 859 + "sequences": {}, 860 + "roles": {}, 861 + "policies": {}, 862 + "views": {}, 863 + "_meta": { 864 + "columns": {}, 865 + "schemas": {}, 866 + "tables": {} 867 + } 868 + }
+14
apps/cf-sandbox/drizzle/meta/_journal.json
··· 92 92 "when": 1771532126862, 93 93 "tag": "0012_happy_mysterio", 94 94 "breakpoints": true 95 + }, 96 + { 97 + "idx": 13, 98 + "version": "7", 99 + "when": 1772769743170, 100 + "tag": "0013_faulty_captain_stacy", 101 + "breakpoints": true 102 + }, 103 + { 104 + "idx": 14, 105 + "version": "7", 106 + "when": 1772772046957, 107 + "tag": "0014_wakeful_kingpin", 108 + "breakpoints": true 95 109 } 96 110 ] 97 111 }
+2 -2
apps/cf-sandbox/src/schema/authorized-keys.ts
··· 11 11 createdAt: timestamp("created_at").defaultNow().notNull(), 12 12 }); 13 13 14 - export type SelectAuthorizedKeys = InferSelectModel<typeof authorizedKeys>; 15 - export type InsertAuthorizedKeys = InferInsertModel<typeof authorizedKeys>; 14 + export type SelectAuthorizedKey = InferSelectModel<typeof authorizedKeys>; 15 + export type InsertAuthorizedKey = InferInsertModel<typeof authorizedKeys>; 16 16 17 17 export default authorizedKeys;
+16
apps/cf-sandbox/src/schema/files.ts
··· 1 + import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; 2 + import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; 3 + 4 + const files = pgTable("files", { 5 + id: text("id") 6 + .primaryKey() 7 + .default(sql`variable_id()`), 8 + content: text("content").notNull(), 9 + createdAt: timestamp("created_at").defaultNow().notNull(), 10 + updatedAt: timestamp("updated_at").defaultNow().notNull(), 11 + }); 12 + 13 + export type SelectFile = InferSelectModel<typeof files>; 14 + export type InsertFile = InferInsertModel<typeof files>; 15 + 16 + export default files;
+4
apps/cf-sandbox/src/schema/index.ts
··· 7 7 import sandboxSecrets from "./sandbox-secrets"; 8 8 import sandboxVariables from "./sandbox-variables"; 9 9 import sandboxVolumes from "./sandbox-volumes"; 10 + import files from "./files"; 11 + import sandboxFiles from "./sandbox-files"; 10 12 11 13 export { 12 14 sandboxes, ··· 18 20 sandboxSecrets, 19 21 sandboxVariables, 20 22 sandboxVolumes, 23 + files, 24 + sandboxFiles, 21 25 };
+22
apps/cf-sandbox/src/schema/sandbox-files.ts
··· 1 + import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; 2 + import { pgTable, text } from "drizzle-orm/pg-core"; 3 + import sandboxes from "./sandboxes"; 4 + import files from "./files"; 5 + 6 + const sandboxFiles = pgTable("sandbox_files", { 7 + id: text("id") 8 + .primaryKey() 9 + .default(sql`xata_id()`), 10 + sandboxId: text("sandbox_id") 11 + .notNull() 12 + .references(() => sandboxes.id), 13 + fileId: text("file_id") 14 + .notNull() 15 + .references(() => files.id), 16 + path: text("path").notNull(), 17 + }); 18 + 19 + export type SelectSandboxFile = InferSelectModel<typeof sandboxFiles>; 20 + export type InsertSandboxFile = InferInsertModel<typeof sandboxFiles>; 21 + 22 + export default sandboxFiles;
+2 -2
apps/cf-sandbox/src/schema/sandbox-secrets.ts
··· 19 19 (t) => [uniqueIndex("unique_sandbox_secret").on(t.sandboxId, t.secretId)], 20 20 ); 21 21 22 - export type SelectSandboxSecrets = InferSelectModel<typeof sandboxSecrets>; 23 - export type InsertSandboxSecrets = InferInsertModel<typeof sandboxSecrets>; 22 + export type SelectSandboxSecret = InferSelectModel<typeof sandboxSecrets>; 23 + export type InsertSandboxSecret = InferInsertModel<typeof sandboxSecrets>; 24 24 25 25 export default sandboxSecrets;
+2 -2
apps/cf-sandbox/src/schema/sandbox-variables.ts
··· 21 21 ], 22 22 ); 23 23 24 - export type SelectSandboxVariables = InferSelectModel<typeof sandboxVariables>; 25 - export type InsertSandboxVariables = InferInsertModel<typeof sandboxVariables>; 24 + export type SelectSandboxVariable = InferSelectModel<typeof sandboxVariables>; 25 + export type InsertSandboxVariable = InferInsertModel<typeof sandboxVariables>; 26 26 export default sandboxVariables;
+3 -2
apps/cf-sandbox/src/schema/sandbox-volumes.ts
··· 13 13 volumeId: text("volume_id") 14 14 .notNull() 15 15 .references(() => volumes.id), 16 + path: text("path").notNull(), 16 17 }); 17 18 18 - export type SelectSandboxVolumes = InferSelectModel<typeof sandboxVolumes>; 19 - export type InsertSandboxVolumes = InferInsertModel<typeof sandboxVolumes>; 19 + export type SelectSandboxVolume = InferSelectModel<typeof sandboxVolumes>; 20 + export type InsertSandboxVolume = InferInsertModel<typeof sandboxVolumes>; 20 21 21 22 export default sandboxVolumes;
+2 -2
apps/sandbox/src/schema/authorized-keys.ts
··· 11 11 createdAt: timestamp("created_at").defaultNow().notNull(), 12 12 }); 13 13 14 - export type SelectAuthorizedKeys = InferSelectModel<typeof authorizedKeys>; 15 - export type InsertAuthorizedKeys = InferInsertModel<typeof authorizedKeys>; 14 + export type SelectAuthorizedKey = InferSelectModel<typeof authorizedKeys>; 15 + export type InsertAuthorizedKey = InferInsertModel<typeof authorizedKeys>; 16 16 17 17 export default authorizedKeys;
+16
apps/sandbox/src/schema/files.ts
··· 1 + import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; 2 + import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; 3 + 4 + const files = pgTable("files", { 5 + id: text("id") 6 + .primaryKey() 7 + .default(sql`variable_id()`), 8 + content: text("content").notNull(), 9 + createdAt: timestamp("created_at").defaultNow().notNull(), 10 + updatedAt: timestamp("updated_at").defaultNow().notNull(), 11 + }); 12 + 13 + export type SelectFile = InferSelectModel<typeof files>; 14 + export type InsertFile = InferInsertModel<typeof files>; 15 + 16 + export default files;
+4
apps/sandbox/src/schema/mod.ts
··· 7 7 import sandboxSecrets from "./sandbox-secrets.ts"; 8 8 import sandboxVariables from "./sandbox-variables.ts"; 9 9 import sandboxVolumes from "./sandbox-volumes.ts"; 10 + import files from "./files.ts"; 11 + import sandboxFiles from "./sandbox-files.ts"; 10 12 11 13 export { 12 14 sandboxes, ··· 18 20 sandboxSecrets, 19 21 sandboxVariables, 20 22 sandboxVolumes, 23 + files, 24 + sandboxFiles, 21 25 };
+22
apps/sandbox/src/schema/sandbox-files.ts
··· 1 + import { type InferInsertModel, type InferSelectModel, sql } from "drizzle-orm"; 2 + import { pgTable, text } from "drizzle-orm/pg-core"; 3 + import sandboxes from "./sandboxes.ts"; 4 + import files from "./files.ts"; 5 + 6 + const sandboxFiles = pgTable("sandbox_files", { 7 + id: text("id") 8 + .primaryKey() 9 + .default(sql`xata_id()`), 10 + sandboxId: text("sandbox_id") 11 + .notNull() 12 + .references(() => sandboxes.id), 13 + fileId: text("file_id") 14 + .notNull() 15 + .references(() => files.id), 16 + path: text("path").notNull(), 17 + }); 18 + 19 + export type SelectSandboxFile = InferSelectModel<typeof sandboxFiles>; 20 + export type InsertSandboxFile = InferInsertModel<typeof sandboxFiles>; 21 + 22 + export default sandboxFiles;
+2 -2
apps/sandbox/src/schema/sandbox-secrets.ts
··· 19 19 (t) => [uniqueIndex("unique_sandbox_secret").on(t.sandboxId, t.secretId)], 20 20 ); 21 21 22 - export type SelectSandboxSecrets = InferSelectModel<typeof sandboxSecrets>; 23 - export type InsertSandboxSecrets = InferInsertModel<typeof sandboxSecrets>; 22 + export type SelectSandboxSecret = InferSelectModel<typeof sandboxSecrets>; 23 + export type InsertSandboxSecret = InferInsertModel<typeof sandboxSecrets>; 24 24 25 25 export default sandboxSecrets;
+2 -2
apps/sandbox/src/schema/sandbox-variables.ts
··· 21 21 ], 22 22 ); 23 23 24 - export type SelectSandboxVariables = InferSelectModel<typeof sandboxVariables>; 25 - export type InsertSandboxVariables = InferInsertModel<typeof sandboxVariables>; 24 + export type SelectSandboxVariable = InferSelectModel<typeof sandboxVariables>; 25 + export type InsertSandboxVariable = InferInsertModel<typeof sandboxVariables>; 26 26 export default sandboxVariables;
+3 -2
apps/sandbox/src/schema/sandbox-volumes.ts
··· 13 13 volumeId: text("volume_id") 14 14 .notNull() 15 15 .references(() => volumes.id), 16 + path: text("path").notNull(), 16 17 }); 17 18 18 - export type SelectSandboxVolumes = InferSelectModel<typeof sandboxVolumes>; 19 - export type InsertSandboxVolumes = InferInsertModel<typeof sandboxVolumes>; 19 + export type SelectSandboxVolume = InferSelectModel<typeof sandboxVolumes>; 20 + export type InsertSandboxVolume = InferInsertModel<typeof sandboxVolumes>; 20 21 21 22 export default sandboxVolumes;
+5
apps/web/bun.lock
··· 24 24 "effect": "^3.19.16", 25 25 "flyonui": "^2.4.1", 26 26 "jotai": "^2.17.1", 27 + "libsodium-wrappers": "^0.8.2", 27 28 "lodash": "^4.17.23", 28 29 "numeral": "^2.0.6", 29 30 "ramda": "^0.32.0", ··· 647 648 "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], 648 649 649 650 "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], 651 + 652 + "libsodium": ["libsodium@0.8.2", "", {}, "sha512-TsnGYMoZtpweT+kR+lOv5TVsnJ/9U0FZOsLFzFOMWmxqOAYXjX3fsrPAW+i1LthgDKXJnI9A8dWEanT1tnJKIw=="], 653 + 654 + "libsodium-wrappers": ["libsodium-wrappers@0.8.2", "", { "dependencies": { "libsodium": "^0.8.0" } }, "sha512-VFLmfxkxo+U9q60tjcnSomQBRx2UzlRjKWJqvB4K1pUqsMQg4cu3QXA2nrcsj9A1qRsnJBbi2Ozx1hsiDoCkhw=="], 650 655 651 656 "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], 652 657
+1
apps/web/package.json
··· 30 30 "effect": "^3.19.16", 31 31 "flyonui": "^2.4.1", 32 32 "jotai": "^2.17.1", 33 + "libsodium-wrappers": "^0.8.2", 33 34 "lodash": "^4.17.23", 34 35 "numeral": "^2.0.6", 35 36 "ramda": "^0.32.0",
+5 -3
apps/web/src/api/file.ts
··· 4 4 client.post( 5 5 "/xrpc/io.pocketenv.file.addFile", 6 6 { 7 - sandboxId, 8 - path, 9 - content, 7 + file: { 8 + sandboxId, 9 + path, 10 + content, 11 + }, 10 12 }, 11 13 { 12 14 headers: {
+5 -3
apps/web/src/api/secret.ts
··· 4 4 client.post( 5 5 "/xrpc/io.pocketenv.secret.addSecret", 6 6 { 7 - sandboxId, 8 - name, 9 - value, 7 + secret: { 8 + sandboxId, 9 + name, 10 + value, 11 + }, 10 12 }, 11 13 { 12 14 headers: {
+5 -3
apps/web/src/api/variable.ts
··· 4 4 client.post( 5 5 "/xrpc/io.pocketenv.variable.addVariable", 6 6 { 7 - sandboxId, 8 - name, 9 - value, 7 + variable: { 8 + sandboxId, 9 + name, 10 + value, 11 + }, 10 12 }, 11 13 { 12 14 headers: {
+5 -3
apps/web/src/api/volume.ts
··· 4 4 client.post( 5 5 "/xrpc/io.pocketenv.volume.addVolume", 6 6 { 7 - sandboxId, 8 - name, 9 - path, 7 + volume: { 8 + sandboxId, 9 + name, 10 + path, 11 + }, 10 12 }, 11 13 { 12 14 headers: {
+2 -2
apps/web/src/components/contextmenu/AddEnvironmentVariableModal/AddEnvironmentVariableModal.tsx
··· 24 24 sandboxId, 25 25 }: AddEnvironmentVariableModalProps) { 26 26 const [isLoading, setIsLoading] = useState(false); 27 - const { mutateAsync } = useAddVariableMutation(); 27 + const { mutateAsync: addVariable } = useAddVariableMutation(); 28 28 const { 29 29 register, 30 30 handleSubmit, ··· 67 67 68 68 const onSubmit = async (data: FormValues) => { 69 69 setIsLoading(true); 70 - await mutateAsync({ 70 + await addVariable({ 71 71 sandboxId, 72 72 name: data.name, 73 73 value: data.value,
+13 -3
apps/web/src/components/contextmenu/AddFileModal/AddFileModal.tsx
··· 4 4 import { z } from "zod"; 5 5 import { zodResolver } from "@hookform/resolvers/zod"; 6 6 import { useAddFileMutation } from "../../../hooks/useFile"; 7 + import { useSodium } from "../../../hooks/useSodium"; 8 + import { PUBLIC_KEY } from "../../../consts"; 7 9 8 10 const schema = z.object({ 9 11 path: z.string().min(1, "Path is required"), ··· 19 21 }; 20 22 21 23 function AddFileModal({ isOpen, onClose, sandboxId }: AddFileModalProps) { 24 + const sodium = useSodium(); 22 25 const [isLoading, setIsLoading] = useState(false); 23 - const { mutateAsync } = useAddFileMutation(); 26 + const { mutateAsync: addFile } = useAddFileMutation(); 24 27 const { 25 28 register, 26 29 handleSubmit, ··· 64 67 65 68 const onSubmit = async (data: FormValues) => { 66 69 setIsLoading(true); 67 - await mutateAsync({ 70 + const sealed = sodium.cryptoBoxSeal( 71 + sodium.fromString(data.content), 72 + sodium.fromHex(PUBLIC_KEY), 73 + ); 74 + await addFile({ 68 75 sandboxId, 69 76 path: data.path, 70 - content: data.content, 77 + content: sodium.toBase64( 78 + sealed, 79 + sodium.base64Variants.URLSAFE_NO_PADDING, 80 + ), 71 81 }); 72 82 setIsLoading(false); 73 83 reset();
+10 -3
apps/web/src/components/contextmenu/AddSecretModal/AddSecretModal.tsx
··· 4 4 import { z } from "zod"; 5 5 import { zodResolver } from "@hookform/resolvers/zod"; 6 6 import { useAddSecretMutation } from "../../../hooks/useSecret"; 7 + import { useSodium } from "../../../hooks/useSodium"; 8 + import { PUBLIC_KEY } from "../../../consts"; 7 9 8 10 const schema = z.object({ 9 11 name: z.string().min(1, "Name is required"), ··· 19 21 }; 20 22 21 23 function AddSecretModal({ isOpen, onClose, sandboxId }: AddSecretModalProps) { 24 + const sodium = useSodium(); 22 25 const [isLoading, setIsLoading] = useState(false); 23 - const { mutateAsync } = useAddSecretMutation(); 26 + const { mutateAsync: addSecret } = useAddSecretMutation(); 24 27 const { 25 28 register, 26 29 handleSubmit, ··· 64 67 65 68 const onSubmit = async (data: FormValues) => { 66 69 setIsLoading(true); 67 - await mutateAsync({ 70 + const sealed = sodium.cryptoBoxSeal( 71 + sodium.fromString(data.value), 72 + sodium.fromHex(PUBLIC_KEY), 73 + ); 74 + await addSecret({ 68 75 sandboxId, 69 76 name: data.name, 70 - value: data.value, 77 + value: sodium.toBase64(sealed, sodium.base64Variants.URLSAFE_NO_PADDING), 71 78 }); 72 79 setIsLoading(false); 73 80 reset();
+2 -2
apps/web/src/components/contextmenu/AddVolumeModal/AddVolumeModal.tsx
··· 20 20 21 21 function AddVolumeModal({ isOpen, onClose, sandboxId }: AddVolumeModalProps) { 22 22 const [isLoading, setIsLoading] = useState(false); 23 - const { mutateAsync } = useAddVolumeMutation(); 23 + const { mutateAsync: addVolume } = useAddVolumeMutation(); 24 24 const { 25 25 register, 26 26 handleSubmit, ··· 64 64 65 65 const onSubmit = async (data: FormValues) => { 66 66 setIsLoading(true); 67 - await mutateAsync({ 67 + await addVolume({ 68 68 sandboxId, 69 69 name: data.name, 70 70 path: data.path,
+3 -6
apps/web/src/components/contextmenu/ContextMenu.tsx
··· 73 73 setIsDeleteSandboxModalOpen(true); 74 74 }; 75 75 76 - // disable context menu temporarily 77 - return <></>; 78 - 79 76 return ( 80 77 <> 81 78 <div ··· 130 127 Delete 131 128 </div> 132 129 </li> 133 - <li> 130 + {/*<li> 134 131 <a href="/settings" className="dropdown-item cursor-pointer"> 135 132 Settings 136 - </a> 137 - </li> 133 + </a>* 134 + </li>*/} 138 135 </ul> 139 136 </div> 140 137 <AddEnvironmentVariableModal
+11 -5
apps/web/src/components/contextmenu/DeleteSandboxModal/DeleteSandboxModal.tsx
··· 1 - import { useEffect } from "react"; 1 + import { useEffect, useState } from "react"; 2 2 import { createPortal } from "react-dom"; 3 3 import { useDeleteSandboxMutation } from "../../../hooks/useSandbox"; 4 4 ··· 13 13 onClose, 14 14 sandboxId, 15 15 }: DeleteSandboxModalProps) { 16 - const { mutateAsync } = useDeleteSandboxMutation(); 16 + const [isLoading, setIsLoading] = useState(false); 17 + const { mutateAsync: deleteSandbox } = useDeleteSandboxMutation(); 17 18 useEffect(() => { 18 19 const handleEscapeKey = (event: KeyboardEvent) => { 19 20 if (event.key === "Escape" && isOpen) { ··· 28 29 }, [isOpen, onClose]); 29 30 30 31 const onDeleteSandbox = async (e: React.MouseEvent<HTMLButtonElement>) => { 31 - await mutateAsync(sandboxId); 32 + setIsLoading(true); 33 + await deleteSandbox(sandboxId); 34 + setIsLoading(false); 32 35 e.stopPropagation(); 33 36 onClose(); 34 37 }; ··· 66 69 onMouseDown={handleContentClick} 67 70 > 68 71 <div className="modal-content"> 69 - <div className="modal-header"> 72 + <div className="modal-header pb-0"> 70 73 <div className="flex-1">Delete</div> 71 74 <button 72 75 type="button" ··· 78 81 <span className="icon-[tabler--x] size-4"></span> 79 82 </button> 80 83 </div> 81 - <div className="modal-body p-0 pl-2 h-[100px]"> 84 + <div className="modal-body p-0 pl-2 h-[100px] flex flex-col justify-center"> 82 85 <p className="font-semibold text-center"> 83 86 Are you sure you want to delete this sandbox? 84 87 </p> ··· 89 92 className="btn btn-error font-semibold" 90 93 onClick={onDeleteSandbox} 91 94 > 95 + {isLoading && ( 96 + <span className="loading loading-spinner loading-xs mr-1.5"></span> 97 + )} 92 98 Delete Sandbox 93 99 </button> 94 100 </div>
+1
apps/web/src/consts.ts
··· 4 4 export const CF_URL = import.meta.env.VITE_CF_URL || "http://localhost:8787"; 5 5 export const CF_SITE_KEY = 6 6 import.meta.env.VITE_CF_SITE_KEY || "1x00000000000000000000BB"; 7 + export const PUBLIC_KEY = import.meta.env.VITE_PUBLIC_KEY || "";
+28
apps/web/src/hooks/useSodium.ts
··· 1 + import sodium from "libsodium-wrappers"; 2 + import { useEffect, useState } from "react"; 3 + 4 + export const useSodium = () => { 5 + const [isInitialized, setIsInitialized] = useState(false); 6 + 7 + useEffect(() => { 8 + sodium.ready.then(() => { 9 + setIsInitialized(true); 10 + }); 11 + }, []); 12 + 13 + const cryptoBoxSeal = sodium.crypto_box_seal; 14 + const fromString = sodium.from_string; 15 + const fromHex = sodium.from_hex; 16 + const toBase64 = sodium.to_base64; 17 + const base64Variants = sodium.base64_variants; 18 + 19 + return { 20 + isInitialized, 21 + sodium, 22 + cryptoBoxSeal, 23 + fromString, 24 + fromHex, 25 + toBase64, 26 + base64Variants, 27 + }; 28 + };