@tanstack/ai-sandbox-cloudflare 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/provider.js +1 -1
- package/dist/esm/provider.js.map +1 -1
- package/package.json +5 -5
- package/src/provider.ts +5 -1
package/dist/esm/provider.js
CHANGED
|
@@ -19,7 +19,7 @@ class CloudflareProvider {
|
|
|
19
19
|
return { transport: this.config.transport ?? "rpc" };
|
|
20
20
|
}
|
|
21
21
|
async create(input) {
|
|
22
|
-
const id = crypto.randomUUID();
|
|
22
|
+
const id = input.id ?? crypto.randomUUID();
|
|
23
23
|
const sandbox = getSandbox(this.config.binding, id, this.sandboxOptions);
|
|
24
24
|
if (input.env && Object.keys(input.env).length > 0) {
|
|
25
25
|
await sandbox.setEnvVars(input.env);
|
package/dist/esm/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sources":["../../src/provider.ts"],"sourcesContent":["import { getSandbox } from '@cloudflare/sandbox'\nimport { CLOUDFLARE_CAPS, CloudflareHandle } from './handle'\nimport type { Sandbox, SandboxTransport } from '@cloudflare/sandbox'\nimport type {\n SandboxCapabilities,\n SandboxCreateInput,\n SandboxDestroyInput,\n SandboxHandle,\n SandboxProvider,\n SandboxResumeInput,\n} from '@tanstack/ai-sandbox'\n\nconst DEFAULT_WORKDIR = '/workspace'\n\nexport interface CloudflareSandboxConfig {\n /**\n * The Sandbox Durable Object namespace binding (e.g. `env.Sandbox`).\n * Available inside a Worker `fetch` handler.\n */\n binding: DurableObjectNamespace<Sandbox>\n /** Working directory inside the container. Defaults to `/workspace`. */\n workdir?: string\n /**\n * Your Worker's request hostname, required by `ports.connect` to expose a\n * preview URL (Cloudflare routes exposed ports by hostname).\n */\n previewHostname?: string\n /**\n * Container-control transport. Defaults to `'rpc'` (the SDK's primary path)\n * because `sandbox.tunnels` — used by `exposePreviewTool` to mint quick-tunnel\n * preview URLs — ONLY exists on the RPC transport; on `'http'`/`'websocket'` it\n * throws \"requires the RPC transport\". The transport must be the same for every\n * `getSandbox()` of a given id, so this provider applies it to create/resume/\n * destroy alike. Override to `'http'` only if you don't use preview tunnels.\n */\n transport?: SandboxTransport\n}\n\nclass CloudflareProvider implements SandboxProvider {\n readonly name = 'cloudflare'\n\n constructor(private readonly config: CloudflareSandboxConfig) {}\n\n capabilities(): SandboxCapabilities {\n return CLOUDFLARE_CAPS\n }\n\n private get workdir(): string {\n return this.config.workdir ?? DEFAULT_WORKDIR\n }\n\n // `transport: 'rpc'` by default so `sandbox.tunnels` (preview URLs) works; must be\n // identical across every `getSandbox()` for an id, so all three paths share this.\n private get sandboxOptions(): { transport: SandboxTransport } {\n return { transport: this.config.transport ?? 'rpc' }\n }\n\n async create(input: SandboxCreateInput): Promise<SandboxHandle> {\n const id = crypto.randomUUID()\n const sandbox = getSandbox(this.config.binding, id, this.sandboxOptions)\n if (input.env && Object.keys(input.env).length > 0) {\n await sandbox.setEnvVars(input.env)\n }\n await sandbox.mkdir(this.workdir, { recursive: true })\n return new CloudflareHandle(\n id,\n sandbox,\n this.workdir,\n this.config.previewHostname,\n )\n }\n\n resume(input: SandboxResumeInput): Promise<SandboxHandle | null> {\n // The Durable Object is durable, so the sandbox is always addressable by\n // id. (The container disk may have been wiped on cold start — withSandbox\n // re-bootstraps under the same identity when durableFilesystem is false.)\n const sandbox = getSandbox(\n this.config.binding,\n input.id,\n this.sandboxOptions,\n )\n return Promise.resolve(\n new CloudflareHandle(\n input.id,\n sandbox,\n this.workdir,\n this.config.previewHostname,\n ),\n )\n }\n\n async destroy(input: SandboxDestroyInput): Promise<void> {\n const sandbox = getSandbox(\n this.config.binding,\n input.id,\n this.sandboxOptions,\n )\n await sandbox.destroy()\n }\n}\n\n/**\n * Cloudflare sandbox provider — runs harness adapters inside Cloudflare\n * Containers at the edge. Construct it inside a Worker with the Sandbox Durable\n * Object namespace binding. See the stdin/snapshot limitations in `handle.ts`.\n */\nexport function cloudflareSandbox(\n config: CloudflareSandboxConfig,\n): SandboxProvider {\n return new CloudflareProvider(config)\n}\n"],"names":[],"mappings":";;AAYA,MAAM,kBAAkB;AA0BxB,MAAM,mBAA8C;AAAA,EAGlD,YAA6B,QAAiC;AAAjC,SAAA,SAAA;AAAA,EAAkC;AAAA,EAAlC;AAAA,EAFpB,OAAO;AAAA,EAIhB,eAAoC;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,IAAY,UAAkB;AAC5B,WAAO,KAAK,OAAO,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA,EAIA,IAAY,iBAAkD;AAC5D,WAAO,EAAE,WAAW,KAAK,OAAO,aAAa,MAAA;AAAA,EAC/C;AAAA,EAEA,MAAM,OAAO,OAAmD;
|
|
1
|
+
{"version":3,"file":"provider.js","sources":["../../src/provider.ts"],"sourcesContent":["import { getSandbox } from '@cloudflare/sandbox'\nimport { CLOUDFLARE_CAPS, CloudflareHandle } from './handle'\nimport type { Sandbox, SandboxTransport } from '@cloudflare/sandbox'\nimport type {\n SandboxCapabilities,\n SandboxCreateInput,\n SandboxDestroyInput,\n SandboxHandle,\n SandboxProvider,\n SandboxResumeInput,\n} from '@tanstack/ai-sandbox'\n\nconst DEFAULT_WORKDIR = '/workspace'\n\nexport interface CloudflareSandboxConfig {\n /**\n * The Sandbox Durable Object namespace binding (e.g. `env.Sandbox`).\n * Available inside a Worker `fetch` handler.\n */\n binding: DurableObjectNamespace<Sandbox>\n /** Working directory inside the container. Defaults to `/workspace`. */\n workdir?: string\n /**\n * Your Worker's request hostname, required by `ports.connect` to expose a\n * preview URL (Cloudflare routes exposed ports by hostname).\n */\n previewHostname?: string\n /**\n * Container-control transport. Defaults to `'rpc'` (the SDK's primary path)\n * because `sandbox.tunnels` — used by `exposePreviewTool` to mint quick-tunnel\n * preview URLs — ONLY exists on the RPC transport; on `'http'`/`'websocket'` it\n * throws \"requires the RPC transport\". The transport must be the same for every\n * `getSandbox()` of a given id, so this provider applies it to create/resume/\n * destroy alike. Override to `'http'` only if you don't use preview tunnels.\n */\n transport?: SandboxTransport\n}\n\nclass CloudflareProvider implements SandboxProvider {\n readonly name = 'cloudflare'\n\n constructor(private readonly config: CloudflareSandboxConfig) {}\n\n capabilities(): SandboxCapabilities {\n return CLOUDFLARE_CAPS\n }\n\n private get workdir(): string {\n return this.config.workdir ?? DEFAULT_WORKDIR\n }\n\n // `transport: 'rpc'` by default so `sandbox.tunnels` (preview URLs) works; must be\n // identical across every `getSandbox()` for an id, so all three paths share this.\n private get sandboxOptions(): { transport: SandboxTransport } {\n return { transport: this.config.transport ?? 'rpc' }\n }\n\n async create(input: SandboxCreateInput): Promise<SandboxHandle> {\n // Honor the deterministic id `ensure()` supplies so reconnecting consumers\n // (e.g. a preview iframe) address the same DO the agent edits. The DO id is\n // `idFromName(id)`, so any stable string works; fall back to a random id\n // when created outside `defineSandbox` (advanced direct use).\n const id = input.id ?? crypto.randomUUID()\n const sandbox = getSandbox(this.config.binding, id, this.sandboxOptions)\n if (input.env && Object.keys(input.env).length > 0) {\n await sandbox.setEnvVars(input.env)\n }\n await sandbox.mkdir(this.workdir, { recursive: true })\n return new CloudflareHandle(\n id,\n sandbox,\n this.workdir,\n this.config.previewHostname,\n )\n }\n\n resume(input: SandboxResumeInput): Promise<SandboxHandle | null> {\n // The Durable Object is durable, so the sandbox is always addressable by\n // id. (The container disk may have been wiped on cold start — withSandbox\n // re-bootstraps under the same identity when durableFilesystem is false.)\n const sandbox = getSandbox(\n this.config.binding,\n input.id,\n this.sandboxOptions,\n )\n return Promise.resolve(\n new CloudflareHandle(\n input.id,\n sandbox,\n this.workdir,\n this.config.previewHostname,\n ),\n )\n }\n\n async destroy(input: SandboxDestroyInput): Promise<void> {\n const sandbox = getSandbox(\n this.config.binding,\n input.id,\n this.sandboxOptions,\n )\n await sandbox.destroy()\n }\n}\n\n/**\n * Cloudflare sandbox provider — runs harness adapters inside Cloudflare\n * Containers at the edge. Construct it inside a Worker with the Sandbox Durable\n * Object namespace binding. See the stdin/snapshot limitations in `handle.ts`.\n */\nexport function cloudflareSandbox(\n config: CloudflareSandboxConfig,\n): SandboxProvider {\n return new CloudflareProvider(config)\n}\n"],"names":[],"mappings":";;AAYA,MAAM,kBAAkB;AA0BxB,MAAM,mBAA8C;AAAA,EAGlD,YAA6B,QAAiC;AAAjC,SAAA,SAAA;AAAA,EAAkC;AAAA,EAAlC;AAAA,EAFpB,OAAO;AAAA,EAIhB,eAAoC;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,IAAY,UAAkB;AAC5B,WAAO,KAAK,OAAO,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA,EAIA,IAAY,iBAAkD;AAC5D,WAAO,EAAE,WAAW,KAAK,OAAO,aAAa,MAAA;AAAA,EAC/C;AAAA,EAEA,MAAM,OAAO,OAAmD;AAK9D,UAAM,KAAK,MAAM,MAAM,OAAO,WAAA;AAC9B,UAAM,UAAU,WAAW,KAAK,OAAO,SAAS,IAAI,KAAK,cAAc;AACvE,QAAI,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG,EAAE,SAAS,GAAG;AAClD,YAAM,QAAQ,WAAW,MAAM,GAAG;AAAA,IACpC;AACA,UAAM,QAAQ,MAAM,KAAK,SAAS,EAAE,WAAW,MAAM;AACrD,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL,KAAK,OAAO;AAAA,IAAA;AAAA,EAEhB;AAAA,EAEA,OAAO,OAA0D;AAI/D,UAAM,UAAU;AAAA,MACd,KAAK,OAAO;AAAA,MACZ,MAAM;AAAA,MACN,KAAK;AAAA,IAAA;AAEP,WAAO,QAAQ;AAAA,MACb,IAAI;AAAA,QACF,MAAM;AAAA,QACN;AAAA,QACA,KAAK;AAAA,QACL,KAAK,OAAO;AAAA,MAAA;AAAA,IACd;AAAA,EAEJ;AAAA,EAEA,MAAM,QAAQ,OAA2C;AACvD,UAAM,UAAU;AAAA,MACd,KAAK,OAAO;AAAA,MACZ,MAAM;AAAA,MACN,KAAK;AAAA,IAAA;AAEP,UAAM,QAAQ,QAAA;AAAA,EAChB;AACF;AAOO,SAAS,kBACd,QACiB;AACjB,SAAO,IAAI,mBAAmB,MAAM;AACtC;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-sandbox-cloudflare",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Cloudflare sandbox provider for TanStack AI — run harness adapters inside Cloudflare Containers (edge) through the uniform SandboxHandle.",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"zod": "^4.0.0",
|
|
48
|
-
"@tanstack/ai": "^0.
|
|
49
|
-
"@tanstack/ai
|
|
48
|
+
"@tanstack/ai-sandbox": "^0.2.2",
|
|
49
|
+
"@tanstack/ai": "^0.40.0",
|
|
50
50
|
"@tanstack/ai-sandbox-local-process": "^0.2.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"@types/node": "^24.10.1",
|
|
55
55
|
"@vitest/coverage-v8": "4.0.14",
|
|
56
56
|
"zod": "^4.2.0",
|
|
57
|
-
"@tanstack/ai": "0.
|
|
58
|
-
"@tanstack/ai-sandbox": "0.2.
|
|
57
|
+
"@tanstack/ai": "0.40.0",
|
|
58
|
+
"@tanstack/ai-sandbox": "0.2.2",
|
|
59
59
|
"@tanstack/ai-sandbox-local-process": "0.2.0"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
package/src/provider.ts
CHANGED
|
@@ -56,7 +56,11 @@ class CloudflareProvider implements SandboxProvider {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
async create(input: SandboxCreateInput): Promise<SandboxHandle> {
|
|
59
|
-
|
|
59
|
+
// Honor the deterministic id `ensure()` supplies so reconnecting consumers
|
|
60
|
+
// (e.g. a preview iframe) address the same DO the agent edits. The DO id is
|
|
61
|
+
// `idFromName(id)`, so any stable string works; fall back to a random id
|
|
62
|
+
// when created outside `defineSandbox` (advanced direct use).
|
|
63
|
+
const id = input.id ?? crypto.randomUUID()
|
|
60
64
|
const sandbox = getSandbox(this.config.binding, id, this.sandboxOptions)
|
|
61
65
|
if (input.env && Object.keys(input.env).length > 0) {
|
|
62
66
|
await sandbox.setEnvVars(input.env)
|