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.

Support Deno deploy tokens for sandboxes

Store and query deno auth when creating sandboxes and use the Deno
deploy token as a credential fallback alongside Sprite and Daytona
tokens. Pass the token into the Deno provider (create/get) via the
denoDeployToken option and accept it in SandboxOptions. Use consola
for provider error logging.

+139 -73
+130 -66
apps/sandbox/src/index.ts
··· 15 15 users, 16 16 variables, 17 17 spriteAuth, 18 + denoAuth, 18 19 } from "./schema/mod.ts"; 19 20 import { 20 21 adjectives, ··· 44 45 import decrypt from "./lib/decrypt.ts"; 45 46 import { InsertSpriteAuth } from "./schema/sprite-auth.ts"; 46 47 import daytonaAuth, { InsertDaytonaAuth } from "./schema/daytona-auth.ts"; 48 + import { InsertDenoAuth } from "./schema/deno-auth.ts"; 47 49 48 50 const app = new Hono<{ Variables: Context }>(); 49 51 ··· 179 181 .execute(); 180 182 } 181 183 184 + if (params.denoDeployToken && user?.id) { 185 + await tx 186 + .insert(denoAuth) 187 + .values({ 188 + sandboxId: record.id, 189 + deployToken: params.denoDeployToken, 190 + redactedDenoToken: params.redactedDenoDeployToken ?? "", 191 + userId: user.id, 192 + } satisfies InsertDenoAuth) 193 + .execute(); 194 + } 195 + 182 196 const sandbox = await createSandbox(params.provider, { 183 197 id: record.id, 184 198 keepAlive: params.keepAlive, ··· 248 262 const body = await c.req.json<StartSandboxInput>(); 249 263 const { repo } = StartSandboxInputSchema.parse(body); 250 264 251 - const [[spriteAuthParams], [daytonaAuthParams]] = await Promise.all([ 252 - c.var.db 253 - .select() 254 - .from(spriteAuth) 255 - .where(eq(spriteAuth.sandboxId, record.id)) 256 - .execute(), 257 - c.var.db 258 - .select() 259 - .from(daytonaAuth) 260 - .where(eq(daytonaAuth.sandboxId, record.id)) 261 - .execute(), 262 - ]); 265 + const [[spriteAuthParams], [daytonaAuthParams], [denoAuthParams]] = 266 + await Promise.all([ 267 + c.var.db 268 + .select() 269 + .from(spriteAuth) 270 + .where(eq(spriteAuth.sandboxId, record.id)) 271 + .execute(), 272 + c.var.db 273 + .select() 274 + .from(daytonaAuth) 275 + .where(eq(daytonaAuth.sandboxId, record.id)) 276 + .execute(), 277 + c.var.db 278 + .select() 279 + .from(denoAuth) 280 + .where(eq(denoAuth.sandboxId, record.id)) 281 + .execute(), 282 + ]); 263 283 264 284 if (!record.sandboxId) { 265 285 sandbox = await createSandbox(record.provider as Provider, { ··· 267 287 daytonaApiKey: decrypt(daytonaAuthParams?.apiKey), 268 288 organizationId: daytonaAuthParams?.organizationId, 269 289 spriteToken: decrypt(spriteAuthParams?.spriteToken), 290 + denoDeployToken: decrypt(denoAuthParams?.deployToken), 270 291 }); 271 292 const sandboxId = await sandbox.id(); 272 293 await c.var.db ··· 280 301 sandbox = await getSandboxById( 281 302 record.provider as Provider, 282 303 record.sandboxId!, 283 - decrypt(spriteAuthParams?.spriteToken || daytonaAuthParams?.apiKey), 304 + decrypt( 305 + spriteAuthParams?.spriteToken || 306 + daytonaAuthParams?.apiKey || 307 + denoAuthParams?.deployToken, 308 + ), 284 309 daytonaAuthParams?.organizationId, 285 310 ); 286 311 ··· 390 415 return c.json({ error: "Sandbox provider not supported" }, 400); 391 416 } 392 417 393 - const [[spriteAuthParams], [daytonaAuthParams]] = await Promise.all([ 394 - c.var.db 395 - .select() 396 - .from(spriteAuth) 397 - .where(eq(spriteAuth.sandboxId, record.id)) 398 - .execute(), 399 - c.var.db 400 - .select() 401 - .from(daytonaAuth) 402 - .where(eq(daytonaAuth.sandboxId, record.id)) 403 - .execute(), 404 - ]); 418 + const [[spriteAuthParams], [daytonaAuthParams], [denoAuthParams]] = 419 + await Promise.all([ 420 + c.var.db 421 + .select() 422 + .from(spriteAuth) 423 + .where(eq(spriteAuth.sandboxId, record.id)) 424 + .execute(), 425 + c.var.db 426 + .select() 427 + .from(daytonaAuth) 428 + .where(eq(daytonaAuth.sandboxId, record.id)) 429 + .execute(), 430 + c.var.db 431 + .select() 432 + .from(denoAuth) 433 + .where(eq(denoAuth.sandboxId, record.id)) 434 + .execute(), 435 + ]); 405 436 406 437 sandbox = await getSandboxById( 407 438 record.provider as Provider, 408 439 record.sandboxId!, 409 - decrypt(spriteAuthParams?.spriteToken || daytonaAuthParams?.apiKey), 440 + decrypt( 441 + spriteAuthParams?.spriteToken || 442 + daytonaAuthParams?.apiKey || 443 + denoAuthParams?.deployToken, 444 + ), 410 445 daytonaAuthParams?.organizationId, 411 446 ); 412 447 ··· 436 471 return c.json({ error: "Sandbox provider not supported" }, 400); 437 472 } 438 473 439 - const [[spriteAuthParams], [daytonaAuthParams]] = await Promise.all([ 440 - c.var.db 441 - .select() 442 - .from(spriteAuth) 443 - .where(eq(spriteAuth.sandboxId, record.id)) 444 - .execute(), 445 - c.var.db 446 - .select() 447 - .from(daytonaAuth) 448 - .where(eq(daytonaAuth.sandboxId, record.id)) 449 - .execute(), 450 - ]); 474 + const [[spriteAuthParams], [daytonaAuthParams], [denoAuthParams]] = 475 + await Promise.all([ 476 + c.var.db 477 + .select() 478 + .from(spriteAuth) 479 + .where(eq(spriteAuth.sandboxId, record.id)) 480 + .execute(), 481 + c.var.db 482 + .select() 483 + .from(daytonaAuth) 484 + .where(eq(daytonaAuth.sandboxId, record.id)) 485 + .execute(), 486 + c.var.db 487 + .select() 488 + .from(denoAuth) 489 + .where(eq(denoAuth.sandboxId, record.id)) 490 + .execute(), 491 + ]); 451 492 452 493 sandbox = await getSandboxById( 453 494 record.provider as Provider, 454 495 record.sandboxId!, 455 - decrypt(spriteAuthParams?.spriteToken || daytonaAuthParams?.apiKey), 496 + decrypt( 497 + spriteAuthParams?.spriteToken || 498 + daytonaAuthParams?.apiKey || 499 + denoAuthParams?.deployToken, 500 + ), 456 501 daytonaAuthParams?.organizationId, 457 502 ); 458 503 ··· 478 523 return c.json({ error: "Sandbox provider not supported" }, 400); 479 524 } 480 525 481 - const [[spriteAuthParams], [daytonaAuthParams]] = await Promise.all([ 482 - c.var.db 483 - .select() 484 - .from(spriteAuth) 485 - .where(eq(spriteAuth.sandboxId, record.id)) 486 - .execute(), 487 - c.var.db 488 - .select() 489 - .from(daytonaAuth) 490 - .where(eq(daytonaAuth.sandboxId, record.id)) 491 - .execute(), 492 - ]); 493 - 526 + const [[spriteAuthParams], [daytonaAuthParams], [denoAuthParams]] = 527 + await Promise.all([ 528 + c.var.db 529 + .select() 530 + .from(spriteAuth) 531 + .where(eq(spriteAuth.sandboxId, record.id)) 532 + .execute(), 533 + c.var.db 534 + .select() 535 + .from(daytonaAuth) 536 + .where(eq(daytonaAuth.sandboxId, record.id)) 537 + .execute(), 538 + c.var.db 539 + .select() 540 + .from(denoAuth) 541 + .where(eq(denoAuth.sandboxId, record.id)) 542 + .execute(), 543 + ]); 494 544 sandbox = await getSandboxById( 495 545 record.provider as Provider, 496 546 record.sandboxId!, 497 - decrypt(spriteAuthParams?.spriteToken || daytonaAuthParams?.apiKey), 547 + decrypt( 548 + spriteAuthParams?.spriteToken || 549 + daytonaAuthParams?.apiKey || 550 + denoAuthParams?.deployToken, 551 + ), 498 552 daytonaAuthParams?.organizationId, 499 553 ); 500 554 ··· 525 579 return c.json({ error: "Sandbox provider not supported" }, 400); 526 580 } 527 581 528 - const [[spriteAuthParams], [daytonaAuthParams]] = await Promise.all([ 529 - c.var.db 530 - .select() 531 - .from(spriteAuth) 532 - .where(eq(spriteAuth.sandboxId, record.id)) 533 - .execute(), 534 - c.var.db 535 - .select() 536 - .from(daytonaAuth) 537 - .where(eq(daytonaAuth.sandboxId, record.id)) 538 - .execute(), 539 - ]); 582 + const [[spriteAuthParams], [daytonaAuthParams], [denoAuthParams]] = 583 + await Promise.all([ 584 + c.var.db 585 + .select() 586 + .from(spriteAuth) 587 + .where(eq(spriteAuth.sandboxId, record.id)) 588 + .execute(), 589 + c.var.db 590 + .select() 591 + .from(daytonaAuth) 592 + .where(eq(daytonaAuth.sandboxId, record.id)) 593 + .execute(), 594 + c.var.db 595 + .select() 596 + .from(denoAuth) 597 + .where(eq(denoAuth.sandboxId, record.id)) 598 + .execute(), 599 + ]); 540 600 541 601 sandbox = await getSandboxById( 542 602 record.provider as Provider, 543 603 record.sandboxId!, 544 - decrypt(spriteAuthParams?.spriteToken || daytonaAuthParams?.apiKey), 604 + decrypt( 605 + spriteAuthParams?.spriteToken || 606 + daytonaAuthParams?.apiKey || 607 + denoAuthParams?.deployToken, 608 + ), 545 609 daytonaAuthParams?.organizationId, 546 610 ); 547 611
+3 -3
apps/sandbox/src/providers/deno/mod.ts
··· 146 146 port: options.port, 147 147 memory: options.memory, 148 148 env: options.envVars, 149 - token: process.env.DENO_DEPLOY_TOKEN, 149 + token: options.denoDeployToken, 150 150 }); 151 151 152 152 return new DenoSandbox(sandbox); 153 153 } 154 154 155 - async get(id: string): Promise<BaseSandbox> { 156 - const sandbox = await Sandbox.connect(id); 155 + async get(id: string, token?: string): Promise<BaseSandbox> { 156 + const sandbox = await Sandbox.connect(id, { token }); 157 157 return new DenoSandbox(sandbox); 158 158 } 159 159 }
+6 -4
apps/sandbox/src/providers/mod.ts
··· 1 1 import { Memory } from "@deno/sandbox"; 2 2 import { Buffer } from "node:buffer"; 3 - import process from "node:process"; 3 + import { consola } from "consola"; 4 4 5 5 export abstract class BaseSandbox { 6 6 abstract start(): Promise<void>; ··· 47 47 spriteName?: string; 48 48 daytonaApiKey?: string; 49 49 organizationId?: string; 50 + denoDeployToken?: string; 50 51 [key: string]: any; 51 52 } 52 53 ··· 100 101 case "deno": { 101 102 const module = await import("./deno/mod.ts"); 102 103 try { 103 - return await new module.default().get(id); 104 + return await new module.default().get(id, token); 104 105 } catch (err) { 105 106 console.error(`Error getting Deno sandbox with ID ${id}:`, err); 106 107 return createSandbox("deno", { 107 108 id, 108 - snapshotRoot: process.env.DENO_SNAPSHOT_ROOT, 109 + denoDeployToken: token, 110 + // snapshotRoot: process.env.DENO_SNAPSHOT_ROOT, 109 111 }); 110 112 } 111 113 } ··· 118 120 new module.default().get(id, token), 119 121 ); 120 122 default: 121 - console.log(`Provider ${provider} is not supported yet.`); 123 + consola.error(`Provider ${provider} is not supported yet.`); 122 124 throw new Error(`Unsupported provider: ${provider}`); 123 125 } 124 126 }