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 volume mount support for Cloudflare sandboxes

Implement mount/unmount on Cloudflare sandbox provider backed by R2.
Start endpoint now queries sandboxVolumes and mounts volumes using
VOLUME_BUCKET, ACCOUNT_ID, R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY.

+39 -2
+4
apps/cf-sandbox/.dev.vars.example
··· 3 3 PRIVATE_KEY=<YOUR-KEY-HERE> 4 4 PUBLIC_KEY=<YOUR-KEY-HERE> 5 5 JWT_SECRET=<YOUR-KEY-HERE> 6 + VOLUME_BUCKET=pocketenv-volumes 7 + ACCOUNT_ID=<YOUR-ACCOUNT-ID> 8 + R2_ACCESS_KEY_ID=<YOUR-R2-ACCESS-KEY-ID> 9 + R2_SECRET_ACCESS_KEY=<YOUR-R2-SECRET-ACCESS-KEY>
+13
apps/cf-sandbox/src/index.ts
··· 8 8 sandboxFiles, 9 9 sandboxSecrets, 10 10 sandboxVariables, 11 + sandboxVolumes, 11 12 secrets, 12 13 sshKeys, 13 14 tailscaleAuthKeys, ··· 285 286 .from(tailscaleAuthKeys) 286 287 .where(eq(tailscaleAuthKeys.sandboxId, c.req.param("sandboxId"))) 287 288 .execute(), 289 + c.var.db 290 + .select() 291 + .from(sandboxVolumes) 292 + .leftJoin(sandboxes, eq(sandboxVolumes.sandboxId, sandboxes.id)) 293 + .leftJoin(users, eq(sandboxes.userId, users.id)) 294 + .where(eq(sandboxVolumes.sandboxId, c.req.param("sandboxId"))) 295 + .execute(), 288 296 ]); 289 297 290 298 await sandbox.setEnvs({ ··· 327 335 ), 328 336 params[4].length > 0 && 329 337 sandbox?.setupTailscale(await decrypt(params[4][0].authKey)), 338 + ...params[5].map((volume) => 339 + sandbox?.mount( 340 + `/${volume.users?.did || ""}${volume.users?.did ? "/" : ""}${volume.sandbox_volumes.id}`, 341 + ), 342 + ), 330 343 ]); 331 344 332 345 if (record.repo) {
+14
apps/cf-sandbox/src/providers/cloudflare/index.ts
··· 92 92 clone(repoUrl: string): Promise<any> { 93 93 return this.sh`git clone ${repoUrl}`; 94 94 } 95 + 96 + mount(path: string): Promise<void> { 97 + return this.sandbox.mountBucket(env.VOLUME_BUCKET, path, { 98 + endpoint: `https://${env.ACCOUNT_ID}.r2.cloudflarestorage.com`, 99 + credentials: { 100 + accessKeyId: env.R2_ACCESS_KEY_ID, 101 + secretAccessKey: env.R2_SECRET_ACCESS_KEY, 102 + }, 103 + }); 104 + } 105 + 106 + unmount(path: string): Promise<void> { 107 + return this.sandbox.unmountBucket(path); 108 + } 95 109 } 96 110 97 111 class CloudflareProvider implements BaseProvider {
+2
apps/cf-sandbox/src/providers/index.ts
··· 10 10 abstract setupSshKeys(privateKey: string, publicKey: string): Promise<void>; 11 11 abstract setupTailscale(autKey: string): Promise<void>; 12 12 abstract clone(repoUrl: string): Promise<void>; 13 + abstract mount(path: string): Promise<void>; 14 + abstract unmount(path: string): Promise<void>; 13 15 } 14 16 15 17 abstract class BaseProvider {
+6 -2
apps/cf-sandbox/worker-configuration.d.ts
··· 1 1 /* eslint-disable */ 2 - // Generated by Wrangler by running `wrangler types` (hash: 63d900118c089c42015e56aa5258de5f) 2 + // Generated by Wrangler by running `wrangler types` (hash: 209f0bba762d65df0a0eb80f96ad226b) 3 3 // Runtime types generated with workerd@1.20260205.0 2025-05-06 nodejs_compat 4 4 declare namespace Cloudflare { 5 5 interface GlobalProps { ··· 13 13 PUBLIC_KEY: string; 14 14 PRIVATE_KEY: string; 15 15 JWT_SECRET: string; 16 + VOLUME_BUCKET: string; 17 + ACCOUNT_ID: string; 18 + R2_ACCESS_KEY_ID: string; 19 + R2_SECRET_ACCESS_KEY: string; 16 20 Sandbox: DurableObjectNamespace<import("./src/index").Sandbox>; 17 21 } 18 22 } ··· 21 25 [Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string; 22 26 }; 23 27 declare namespace NodeJS { 24 - interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "SANDBOX_TRANSPORT" | "CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE" | "PUBLIC_KEY" | "PRIVATE_KEY" | "JWT_SECRET">> {} 28 + interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "SANDBOX_TRANSPORT" | "CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE" | "PUBLIC_KEY" | "PRIVATE_KEY" | "JWT_SECRET" | "VOLUME_BUCKET" | "ACCOUNT_ID" | "R2_ACCESS_KEY_ID" | "R2_SECRET_ACCESS_KEY">> {} 25 29 } 26 30 27 31 // Begin runtime types