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.

Move sandbox POST outside DB transaction

+115 -104
+115 -104
apps/api/src/xrpc/io/pocketenv/sandbox/exposeVscode.ts
··· 15 15 16 16 export default function (server: Server, ctx: Context) { 17 17 const exposeVscode = async (params: QueryParams, auth: HandlerAuth) => { 18 - return ctx.db.transaction(async (tx) => { 19 - const [record] = await tx 20 - .select() 21 - .from(schema.sandboxes) 22 - .leftJoin(schema.users, eq(schema.sandboxes.userId, schema.users.id)) 23 - .where( 24 - and( 25 - or( 26 - eq(schema.sandboxes.id, params.id), 27 - eq(schema.sandboxes.uri, params.id), 28 - eq(schema.sandboxes.name, params.id), 18 + const { sandbox, record, previewUrl } = await ctx.db.transaction( 19 + async (tx) => { 20 + const [record] = await tx 21 + .select() 22 + .from(schema.sandboxes) 23 + .leftJoin(schema.users, eq(schema.sandboxes.userId, schema.users.id)) 24 + .where( 25 + and( 26 + or( 27 + eq(schema.sandboxes.id, params.id), 28 + eq(schema.sandboxes.uri, params.id), 29 + eq(schema.sandboxes.name, params.id), 30 + ), 31 + auth.credentials 32 + ? eq(schema.users.did, auth.credentials.did) 33 + : isNull(schema.sandboxes.userId), 29 34 ), 30 - auth.credentials 31 - ? eq(schema.users.did, auth.credentials.did) 32 - : isNull(schema.sandboxes.userId), 33 - ), 34 - ) 35 - .execute(); 35 + ) 36 + .execute(); 36 37 37 - if (!record) { 38 - throw new XRPCError(404, "Sandbox not found"); 39 - } 38 + if (!record) { 39 + throw new XRPCError(404, "Sandbox not found"); 40 + } 40 41 41 - const existingPort = await tx 42 - .select() 43 - .from(schema.sandboxPorts) 44 - .where( 45 - and( 46 - eq(schema.sandboxPorts.sandboxId, record.sandboxes.id), 47 - eq(schema.sandboxPorts.exposedPort, VSCODE_PORT), 48 - ), 49 - ) 50 - .execute(); 42 + const existingPort = await tx 43 + .select() 44 + .from(schema.sandboxPorts) 45 + .where( 46 + and( 47 + eq(schema.sandboxPorts.sandboxId, record.sandboxes.id), 48 + eq(schema.sandboxPorts.exposedPort, VSCODE_PORT), 49 + ), 50 + ) 51 + .execute(); 51 52 52 - if (existingPort.length > 0) { 53 - return existingPort[0]!.previewUrl || ""; 54 - } 53 + if (existingPort.length > 0) { 54 + return { previewUrl: existingPort[0]!.previewUrl || "" }; 55 + } 55 56 56 - await tx 57 - .insert(schema.sandboxPorts) 58 - .values({ 59 - sandboxId: record.sandboxes.id, 60 - exposedPort: VSCODE_PORT, 61 - description: "VS Code Server", 62 - }) 63 - .execute(); 57 + await tx 58 + .insert(schema.sandboxPorts) 59 + .values({ 60 + sandboxId: record.sandboxes.id, 61 + exposedPort: VSCODE_PORT, 62 + description: "VS Code Server", 63 + }) 64 + .execute(); 64 65 65 - const records = await tx 66 - .select() 67 - .from(schema.sandboxPorts) 68 - .where(eq(schema.sandboxPorts.sandboxId, record.sandboxes.id)) 69 - .execute(); 66 + const records = await tx 67 + .select() 68 + .from(schema.sandboxPorts) 69 + .where(eq(schema.sandboxPorts.sandboxId, record.sandboxes.id)) 70 + .execute(); 70 71 71 - const ports = records.map((r) => r.exposedPort); 72 + const ports = records.map((r) => r.exposedPort); 72 73 73 - if (record.sandboxes.uri) { 74 - if (!auth.credentials) { 75 - throw new XRPCError(401, "Unauthorized"); 76 - } 74 + if (record.sandboxes.uri) { 75 + if (!auth.credentials) { 76 + throw new XRPCError(401, "Unauthorized"); 77 + } 77 78 78 - const agent = await createAgent(ctx.oauthClient, auth.credentials.did); 79 - if (!agent) { 80 - consola.error( 81 - "Failed to create AT Protocol agent for DID:", 79 + const agent = await createAgent( 80 + ctx.oauthClient, 82 81 auth.credentials.did, 83 82 ); 84 - throw new XRPCError( 85 - 500, 86 - "Failed to create AT Protocol agent", 87 - "AgentCreationError", 88 - ); 83 + if (!agent) { 84 + consola.error( 85 + "Failed to create AT Protocol agent for DID:", 86 + auth.credentials.did, 87 + ); 88 + throw new XRPCError( 89 + 500, 90 + "Failed to create AT Protocol agent", 91 + "AgentCreationError", 92 + ); 93 + } 94 + 95 + updateSandbox(agent, { 96 + rkey: record.sandboxes.uri.split("/").pop()!, 97 + ports, 98 + }).catch((err) => { 99 + consola.error("Failed to update sandbox with new ports:", err); 100 + }); 89 101 } 90 102 91 - updateSandbox(agent, { 92 - rkey: record.sandboxes.uri.split("/").pop()!, 93 - ports, 94 - }).catch((err) => { 95 - consola.error("Failed to update sandbox with new ports:", err); 96 - }); 97 - } 103 + const sandbox = 104 + record.sandboxes.provider === Providers.CLOUDFLARE 105 + ? ctx.cfsandbox(record.sandboxes.base!) 106 + : ctx.sandbox(); 107 + return { sandbox, record }; 108 + }, 109 + ); 98 110 99 - const sandbox = 100 - record.sandboxes.provider === Providers.CLOUDFLARE 101 - ? ctx.cfsandbox(record.sandboxes.base!) 102 - : ctx.sandbox(); 111 + if (!sandbox && !record) { 112 + return previewUrl; 113 + } 103 114 104 - const { data } = await sandbox.post<{ previewUrl: string }>( 105 - `/v1/sandboxes/${record.sandboxes.id}/vscode`, 106 - {}, 107 - { 108 - headers: { 109 - Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 110 - }, 115 + const { data } = await sandbox.post<{ previewUrl: string }>( 116 + `/v1/sandboxes/${record.sandboxes.id}/vscode`, 117 + {}, 118 + { 119 + headers: { 120 + Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 111 121 }, 112 - ); 122 + }, 123 + ); 113 124 114 - if (data.previewUrl) { 115 - const updated = await ctx.db 116 - .update(schema.sandboxPorts) 117 - .set({ previewUrl: data.previewUrl }) 118 - .where( 119 - and( 120 - eq(schema.sandboxPorts.sandboxId, record.sandboxes.id), 121 - eq(schema.sandboxPorts.exposedPort, VSCODE_PORT), 122 - ), 123 - ) 124 - .returning() 125 - .execute(); 125 + if (data.previewUrl) { 126 + const updated = await ctx.db 127 + .update(schema.sandboxPorts) 128 + .set({ previewUrl: data.previewUrl }) 129 + .where( 130 + and( 131 + eq(schema.sandboxPorts.sandboxId, record.sandboxes.id), 132 + eq(schema.sandboxPorts.exposedPort, VSCODE_PORT), 133 + ), 134 + ) 135 + .returning() 136 + .execute(); 126 137 127 - if (updated.length === 0) { 128 - await ctx.db 129 - .insert(schema.sandboxPorts) 130 - .values({ 131 - sandboxId: record.sandboxes.id, 132 - exposedPort: VSCODE_PORT, 133 - previewUrl: data.previewUrl, 134 - description: "VS Code Server", 135 - }) 136 - .execute(); 137 - } 138 + if (updated.length === 0) { 139 + await ctx.db 140 + .insert(schema.sandboxPorts) 141 + .values({ 142 + sandboxId: record.sandboxes.id, 143 + exposedPort: VSCODE_PORT, 144 + previewUrl: data.previewUrl, 145 + description: "VS Code Server", 146 + }) 147 + .execute(); 138 148 } 149 + } 139 150 140 - return data.previewUrl; 141 - }); 151 + return data.previewUrl; 142 152 }; 153 + 143 154 server.io.pocketenv.sandbox.exposeVscode({ 144 155 auth: ctx.authVerifier, 145 156 handler: async ({ params, auth }) => {