@cloudflare/sandbox 0.13.0-next.769.1 → 1.0.0-rc.0

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.
Files changed (63) hide show
  1. package/README.md +62 -219
  2. package/dist/index.d.mts +548 -0
  3. package/dist/index.mjs +2452 -0
  4. package/package.json +17 -118
  5. package/Dockerfile +0 -327
  6. package/dist/bridge/index.d.ts +0 -181
  7. package/dist/bridge/index.d.ts.map +0 -1
  8. package/dist/bridge/index.js +0 -3053
  9. package/dist/bridge/index.js.map +0 -1
  10. package/dist/contexts-1EsLHByO.d.ts +0 -463
  11. package/dist/contexts-1EsLHByO.d.ts.map +0 -1
  12. package/dist/dist-Duor5GbS.js +0 -752
  13. package/dist/dist-Duor5GbS.js.map +0 -1
  14. package/dist/errors/index.d.ts +0 -4
  15. package/dist/errors/index.js +0 -4
  16. package/dist/errors-CXR0xBpw.js +0 -285
  17. package/dist/errors-CXR0xBpw.js.map +0 -1
  18. package/dist/errors-QYlSkVGz.js +0 -893
  19. package/dist/errors-QYlSkVGz.js.map +0 -1
  20. package/dist/extensions/index.d.ts +0 -4
  21. package/dist/extensions/index.js +0 -6
  22. package/dist/extensions-CFB2xHqY.js +0 -1023
  23. package/dist/extensions-CFB2xHqY.js.map +0 -1
  24. package/dist/filesystem-BWAZCZER.d.ts +0 -732
  25. package/dist/filesystem-BWAZCZER.d.ts.map +0 -1
  26. package/dist/git/index.d.ts +0 -63
  27. package/dist/git/index.d.ts.map +0 -1
  28. package/dist/git/index.js +0 -338
  29. package/dist/git/index.js.map +0 -1
  30. package/dist/index-Bs4bqXDR.d.ts +0 -438
  31. package/dist/index-Bs4bqXDR.d.ts.map +0 -1
  32. package/dist/index-HNYBk-az.d.ts +0 -444
  33. package/dist/index-HNYBk-az.d.ts.map +0 -1
  34. package/dist/index.d.ts +0 -576
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/index.js +0 -33
  37. package/dist/index.js.map +0 -1
  38. package/dist/interpreter/index.d.ts +0 -311
  39. package/dist/interpreter/index.d.ts.map +0 -1
  40. package/dist/interpreter/index.js +0 -292
  41. package/dist/interpreter/index.js.map +0 -1
  42. package/dist/openai/index.d.ts +0 -68
  43. package/dist/openai/index.d.ts.map +0 -1
  44. package/dist/openai/index.js +0 -367
  45. package/dist/openai/index.js.map +0 -1
  46. package/dist/opencode/index.d.ts +0 -182
  47. package/dist/opencode/index.d.ts.map +0 -1
  48. package/dist/opencode/index.js +0 -454
  49. package/dist/opencode/index.js.map +0 -1
  50. package/dist/process-types-GStiZ8f8.d.ts +0 -73
  51. package/dist/process-types-GStiZ8f8.d.ts.map +0 -1
  52. package/dist/sandbox-BbAabq93.d.ts +0 -42
  53. package/dist/sandbox-BbAabq93.d.ts.map +0 -1
  54. package/dist/sandbox-cmlgGVYX.js +0 -10056
  55. package/dist/sandbox-cmlgGVYX.js.map +0 -1
  56. package/dist/sidecar/index.d.ts +0 -77
  57. package/dist/sidecar/index.d.ts.map +0 -1
  58. package/dist/sidecar/index.js +0 -201
  59. package/dist/sidecar/index.js.map +0 -1
  60. package/dist/xterm/index.d.ts +0 -93
  61. package/dist/xterm/index.d.ts.map +0 -1
  62. package/dist/xterm/index.js +0 -220
  63. package/dist/xterm/index.js.map +0 -1
package/README.md CHANGED
@@ -1,263 +1,106 @@
1
- <img width="1362" height="450" alt="Image" src="https://github.com/user-attachments/assets/6f770ae3-0a14-4d2b-9aed-a304ee5446c5" />
1
+ <img width="1362" height="450" alt="sandbox" src="https://github.com/user-attachments/assets/6f770ae3-0a14-4d2b-9aed-a304ee5446c5" />
2
2
 
3
3
  # Cloudflare Sandbox SDK
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@cloudflare/sandbox)](https://www.npmjs.com/package/@cloudflare/sandbox)
6
6
  [![npm downloads](https://img.shields.io/npm/dw/@cloudflare/sandbox)](https://www.npmjs.com/package/@cloudflare/sandbox)
7
7
 
8
- **Build secure, isolated code execution environments on Cloudflare.**
8
+ Run untrusted or generated code in a Linux sandbox that belongs to one user, task, or session. Your Worker decides who gets a sandbox, which hosts it can reach, and which credentials stay out of it.
9
9
 
10
- The Sandbox SDK lets you run untrusted code safely in isolated containers. Execute commands, manage files, run background processes, and expose services — all from your Workers applications.
10
+ A sandbox is a Durable Object and the [Container](https://developers.cloudflare.com/containers/) it starts. The Durable Object starts the instance and runs commands with the Container API on `this.ctx.container`. `@cloudflare/sandbox` adds three things that API does not have:
11
11
 
12
- Perfect for AI code execution, interactive development environments, data analysis platforms, CI/CD systems, and any application that needs secure code execution at the edge.
12
+ - [`Files`](https://developers.cloudflare.com/sandbox/reference/files/) streams files in and out of the running instance and reports Linux errors such as `ENOENT`.
13
+ - [`S3Mounts`](https://developers.cloudflare.com/sandbox/reference/s3-mounts/) mounts an S3-compatible bucket at a path. Your Worker signs each storage request, so the credentials never enter the sandbox.
14
+ - [`DirectoryBackups`](https://developers.cloudflare.com/sandbox/reference/directory-backups/) saves a directory to R2 and restores it into any Container, including one on a newer image. The Container reaches only the one object each operation needs.
13
15
 
14
- ## Getting Started
16
+ **[Read the documentation](https://developers.cloudflare.com/sandbox/)**
15
17
 
16
- ### Prerequisites
18
+ ## Try it
17
19
 
18
- 1. Install [Node.js](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) (version 16.17.0 or later)
19
- 2. Ensure Docker is running locally ([see setup guide](https://developers.cloudflare.com/sandbox/get-started/#ensure-docker-is-running-locally))
20
- 3. For deploying to production, sign up for a [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages)
20
+ Create a project from the minimal template, or deploy it directly:
21
21
 
22
- ### 1. Create a new project
23
-
24
- Create a new Sandbox SDK project using the minimal template:
25
-
26
- ```bash
22
+ ```sh
27
23
  npm create cloudflare@latest -- my-sandbox --template=cloudflare/sandbox-sdk/examples/minimal
28
- cd my-sandbox
29
- ```
30
-
31
- ### 2. Test locally
32
-
33
- Start the development server:
34
-
35
- ```bash
36
- npm run dev
37
- ```
38
-
39
- > **Note:** First run builds the Docker container (2-3 minutes). Subsequent runs are much faster.
40
-
41
- Test the endpoints:
42
-
43
- ```bash
44
- # Execute Python code
45
- curl http://localhost:8787/run
46
-
47
- # File operations
48
- curl http://localhost:8787/file
49
- ```
50
-
51
- ### 3. Deploy to production
52
-
53
- Deploy your Worker and container:
54
-
55
- ```bash
56
- npx wrangler deploy
57
24
  ```
58
25
 
59
- > **Wait for provisioning:** After first deployment, wait 2-3 minutes before making requests.
60
-
61
- **📖 [View the complete getting started guide](https://developers.cloudflare.com/sandbox/get-started/)** for detailed instructions and explanations.
26
+ [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/sandbox-sdk/tree/main/examples/minimal)
62
27
 
63
- ## Quick API Example
28
+ The template gives each name in the URL its own sandbox. At its core is a Durable Object like this one:
64
29
 
65
- ```typescript
66
- import { getSandbox, proxyToSandbox, type Sandbox } from '@cloudflare/sandbox';
67
-
68
- export { Sandbox } from '@cloudflare/sandbox';
69
-
70
- type Env = {
71
- Sandbox: DurableObjectNamespace<Sandbox>;
72
- };
73
-
74
- export default {
75
- async fetch(request: Request, env: Env): Promise<Response> {
76
- // Required for preview URLs
77
- const proxyResponse = await proxyToSandbox(request, env);
78
- if (proxyResponse) return proxyResponse;
30
+ ```ts
31
+ import { Files } from "@cloudflare/sandbox";
32
+ import { DurableObject } from "cloudflare:workers";
79
33
 
80
- const url = new URL(request.url);
81
- const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
34
+ export class Sandbox extends DurableObject<Env> {
35
+ async run(script: string) {
36
+ const container = this.ctx.container;
37
+ if (!container) throw new Error("The container binding is not configured");
82
38
 
83
- // Execute Python code
84
- if (url.pathname === '/run') {
85
- const process = await sandbox.exec(['python3', '-c', 'print(2 + 2)']);
86
- const output = await process.output({ encoding: 'utf8' });
87
- return Response.json({
88
- output: output.stdout,
89
- success: output.exitCode === 0
90
- });
39
+ if (!container.running) {
40
+ container.start({ image: container.images.sandbox, enableInternet: false });
91
41
  }
92
42
 
93
- // Work with files
94
- if (url.pathname === '/file') {
95
- await sandbox.writeFile('/workspace/hello.txt', 'Hello, Sandbox!');
96
- const file = await sandbox.readFile('/workspace/hello.txt');
97
- return Response.json({ content: file.content });
98
- }
43
+ const files = new Files(container);
44
+ await files.writeFile("/workspace/task.sh", script);
99
45
 
100
- return new Response('Try /run or /file');
46
+ const process = await container.exec(["sh", "task.sh"], { cwd: "/workspace" });
47
+ const { exitCode, stdout } = await process.output();
48
+ return { exitCode, stdout: new TextDecoder().decode(stdout) };
101
49
  }
102
- };
103
- ```
104
-
105
- ## Process Execution
106
-
107
- A Sandbox is the long-running computer. `exec()` launches one supervised argv process and returns after the runtime confirms launch; it does not run through a hidden persistent shell.
108
-
109
- ```ts
110
- const process = await sandbox.exec(['python3', '-c', 'print(2 + 2)']);
111
- const output = await process.output({ encoding: 'utf8' });
112
-
113
- console.log(process.id, process.pid, output.stdout, output.exitCode);
114
- ```
115
-
116
- `await sandbox.exec(argv)` waits only for launch; `process.pid` is available once it resolves. `await process.output()` and `await process.waitForExit()` wait for completion. `process.status()` observes the current state, and `process.logs()` streams replayable cursor events incrementally.
117
-
118
- `output()` is replayable but may return `truncated: true`; use `logs({ since, replay, follow })` for cursor resume and output too large to buffer. `exec(argv, { timeout })` sets a remote process lifetime deadline: the supervisor may terminate and then kill the process internally, and completion is reported with `timedOut: true`. Timeouts and `AbortSignal`s on `logs()`, `output()`, `waitForExit()`, `waitForLog()`, and `waitForPort()` cancel only that local observation—they do not stop the process. Call `process.kill(signal)` with a numeric signal (default `15`) to request termination.
119
-
120
- Use explicit shell argv when you need shell syntax:
50
+ }
121
51
 
122
- ```ts
123
- const proc = await sandbox.exec(['/bin/bash', '-lc', 'cd app && npm test'], {
124
- cwd: '/workspace',
125
- env: { CI: '1' }
126
- });
127
- ```
128
-
129
- For asynchronous work, keep `proc.id` and recover the live process from a later Worker request:
130
-
131
- ```ts
132
- const server = await sandbox.exec([
133
- '/bin/bash',
134
- '-lc',
135
- 'npm run dev -- --host 0.0.0.0'
136
- ]);
137
- await server.waitForPort(3000);
138
-
139
- const recovered = await sandbox.getProcess(server.id);
140
- const running = await sandbox.listProcesses();
141
- ```
142
-
143
- `getProcess()` and `listProcesses()` are non-waking discovery calls: with no active runtime they return `null` and `[]` instead of starting a replacement. Handles, IDs, PIDs, statuses, retained logs, and cursors belong to the runtime that launched the process. After sleep, restart, or replacement, discovery cannot recover them and operations on an old handle fail with `STALE_PROCESS_HANDLE` rather than targeting a replacement runtime.
144
-
145
- Use `createTerminal()` for a persistent interactive PTY shell with input, resize, interrupt, terminate, and reconnect semantics. Terminals remain separate from supervised processes and are also runtime-local.
146
-
147
- ## Quick tunnels
148
-
149
- `sandbox.tunnels.get(port)` exposes a service running inside the
150
- sandbox on a `*.trycloudflare.com` URL. No Cloudflare account or DNS
151
- setup required — cloudflared opens a persistent QUIC connection to
152
- Cloudflare's edge and Cloudflare hands back a hostname.
153
-
154
- ```ts
155
- // Inside a Worker with a sandbox:
156
- const tunnel = await sandbox.tunnels.get(8080);
157
- console.log(tunnel.url);
158
- // → https://random-words-here.trycloudflare.com
159
-
160
- // Repeated calls for the same port return the same record:
161
- const same = await sandbox.tunnels.get(8080);
162
- console.log(same.url === tunnel.url); // true
163
-
164
- // Tear down by port number or by the record:
165
- await sandbox.tunnels.destroy(8080);
166
- // or: await sandbox.tunnels.destroy(tunnel);
52
+ export default {
53
+ async fetch(request, env) {
54
+ // Authenticate the request, then choose the sandbox for this user or task.
55
+ const sandbox = env.SANDBOX.getByName("user-123");
56
+ return Response.json(await sandbox.run(await request.text()));
57
+ },
58
+ } satisfies ExportedHandler<Env>;
167
59
  ```
168
60
 
169
- `get()` is idempotent: it consults a per-sandbox cache in Durable
170
- Object storage, returns the cached record on a hit, and only spawns a
171
- fresh cloudflared process on a miss. `list()` returns every cached
172
- tunnel.
61
+ The image needs the helper that `Files` runs, and the Worker needs `nodejs_compat`. Refer to [Requirements](https://developers.cloudflare.com/sandbox/reference/#requirements).
173
62
 
174
- Notes:
63
+ ## What you can build
175
64
 
176
- - URLs do **not** survive a container restart. Cloudflare assigns the
177
- hostname during cloudflared's startup handshake, so every restart
178
- yields a new URL. The SDK clears its cache on container start, so
179
- the next `get(port)` after a restart returns a fresh record.
180
- - The first fetch through a brand-new URL can take a couple of
181
- seconds while DNS propagates, even after `get()` resolves.
182
- - `*.trycloudflare.com` buffers `text/event-stream` responses.
183
- WebSockets work fine.
184
- - Local builds behind a TLS-intercepting proxy (e.g. Cloudflare WARP)
185
- need the host CA bundle injected at build time — see
186
- [DOCKER_README.md](../../DOCKER_README.md).
65
+ | Goal | Guide | Example |
66
+ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
67
+ | Run a script and read its output | [Execute commands](https://developers.cloudflare.com/sandbox/commands/execute-commands/) | [`workspace`](examples/workspace) |
68
+ | Keep a server or build running | [Run background processes](https://developers.cloudflare.com/sandbox/commands/run-background-processes/) | [`process-workspace`](examples/process-workspace) |
69
+ | Open a shell in the browser | [Open a terminal in the browser](https://developers.cloudflare.com/sandbox/commands/open-a-terminal-in-the-browser/) | [`terminal-workspace`](examples/terminal-workspace) |
70
+ | Process files from a bucket | [Mount an R2 bucket](https://developers.cloudflare.com/sandbox/files/mount-an-r2-bucket/) | [`artifact-workspace`](examples/artifact-workspace) |
71
+ | Save a workspace and resume it later | [Save and restore a sandbox](https://developers.cloudflare.com/sandbox/files/save-and-restore-a-workspace/) | [`checkpoint-workspace`](examples/checkpoint-workspace), [`backup-workspace`](examples/backup-workspace) |
72
+ | Preview a web app while you edit it | [Preview a web application](https://developers.cloudflare.com/sandbox/previews/preview-a-web-application/) | [`preview-workspace`](examples/preview-workspace) |
73
+ | Share a port on its own URL | [Serve previews on their own hostnames](https://developers.cloudflare.com/sandbox/previews/serve-previews-on-their-own-hostnames/) | [`share-workspace`](examples/share-workspace) |
74
+ | Choose which hosts a sandbox can reach | [Control network access](https://developers.cloudflare.com/sandbox/network/) | [`outbound-workspace`](examples/outbound-workspace) |
75
+ | Run a coding agent on a repository | [Coding agents](https://developers.cloudflare.com/sandbox/coding-agents/) | [`coding-agents`](examples/coding-agents), [`devin`](devin), [`openai/agents-api`](openai/agents-api) |
187
76
 
188
- ## Documentation
77
+ To run JavaScript or Python without a Linux environment, use [Dynamic Workers](https://developers.cloudflare.com/sandbox/choose-an-environment/) instead.
189
78
 
190
- **📖 [Full Documentation](https://developers.cloudflare.com/sandbox/)**
79
+ ## Coming from 0.x
191
80
 
192
- - [Get Started Guide](https://developers.cloudflare.com/sandbox/get-started/) - Step-by-step tutorial
193
- - [API Reference](https://developers.cloudflare.com/sandbox/api/) - Complete API docs
194
- - [Guides](https://developers.cloudflare.com/sandbox/guides/) - Execute commands, manage files, expose services
195
- - [Examples](https://developers.cloudflare.com/sandbox/tutorials/) - AI agents, data analysis, CI/CD pipelines
81
+ Version 0.x provided a `Sandbox` class that owned the Container and ran commands for you. In 1.0, your own Durable Object starts the Container, and this package provides only file operations and bucket mounts. The [migration guide](https://developers.cloudflare.com/sandbox/sdk/migrate/) maps each 0.x API to its replacement. The 0.x source is on the [`v0`](https://github.com/cloudflare/sandbox-sdk/tree/v0) branch.
196
82
 
197
- ## Key Features
83
+ ## Repository
198
84
 
199
- - **Secure Isolation** - Each sandbox runs in its own container
200
- - **Edge-Native** - Runs on Cloudflare's global network
201
- - **Code Interpreter** - Execute Python and JavaScript with rich outputs
202
- - **File System Access** - Read, write, and manage files
203
- - **Command Execution** - Run any command with streaming support
204
- - **Preview URLs** - Expose services with public URLs
205
- - **Quick tunnels** - Zero-config `*.trycloudflare.com` URLs via `sandbox.tunnels.get(port)`
206
- - **Git Integration** - Clone repositories directly
85
+ | Path | Contents |
86
+ | ---------------------------------------------- | ------------------------------------------------------------------------------------- |
87
+ | [`packages/sandbox`](packages/sandbox) | The `@cloudflare/sandbox` package |
88
+ | [`crates/sandbox-tools`](crates/sandbox-tools) | `sandbox-shim`, the Linux helper that `Files`, `S3Mounts`, and `DirectoryBackups` run |
89
+ | [`images/sandbox-tools`](images/sandbox-tools) | The `cloudflare/sandbox` image that ships `sandbox-shim` |
90
+ | [`examples`](examples) | Deployable Workers, one per goal |
207
91
 
208
- ## Contributing
92
+ To learn how these parts fit together, read [Architecture](docs/architecture.md). The package and `sandbox-shim` exchange frames described in [Shim protocol](docs/shim-protocol.md). [S3 mounts design](docs/s3-mounts-design.md) explains `S3Mounts` and `S3Gateway`. To add an example, read [Examples](docs/examples.md).
209
93
 
210
- We welcome contributions from the community! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on:
94
+ Build and test with Node.js and Docker:
211
95
 
212
- - Setting up your development environment
213
- - Creating pull requests
214
- - Code style and testing requirements
215
-
216
- ## Development
217
-
218
- This repository contains the SDK source code. Quick start:
219
-
220
- ```bash
221
- # Clone the repo
222
- git clone https://github.com/cloudflare/sandbox-sdk
223
- cd sandbox-sdk
224
-
225
- # Install dependencies
96
+ ```sh
226
97
  npm install
227
-
228
- # Run tests
229
- npm test
230
-
231
- # Build the project
232
- npm run build
233
-
234
- # Type checking and linting
235
98
  npm run check
99
+ npm test
236
100
  ```
237
101
 
238
- ## Examples
239
-
240
- See the [examples directory](./examples) for complete working examples:
241
-
242
- - [Minimal](./examples/minimal) - Start here: exec commands, read/write files
243
- - [Code Interpreter](./examples/code-interpreter) - Give [gpt-oss](https://developers.cloudflare.com/workers-ai/models/gpt-oss-120b/) on Workers AI a Python REPL
244
- - [Claude Code](./examples/claude-code) - Run [Claude Code](https://claude.ai/code) headless on any repo
245
- - [OpenAI Agents](./examples/openai-agents) - `Shell` and `Editor` tools for [OpenAI Agents SDK](https://openai.github.io/openai-agents-js/)
246
- - [OpenCode](./examples/opencode) - [OpenCode](https://github.com/sst/opencode) web UI or [SDK](https://opencode.ai/docs/sdk/) in a sandbox
247
- - [Git Repo Per Sandbox](./examples/git-repo-per-sandbox) - One Artifacts Git repo per sandbox
248
- - [TypeScript Validator](./examples/typescript-validator) - Build with npm in sandbox, execute in [isolates](https://developers.cloudflare.com/workers/runtime-apis/bindings/worker-loader/)
249
-
250
- ## Status
251
-
252
- **Beta** - The SDK is in active development. APIs may change before v1.0.
102
+ [Testing](docs/testing.md) explains what these commands check, how to build behind a TLS-inspecting proxy, and how to test in production. [Releasing](docs/releasing.md) explains how maintainers publish the package and its image.
253
103
 
254
104
  ## License
255
105
 
256
106
  [Apache License 2.0](LICENSE)
257
-
258
- ## Links
259
-
260
- - [Documentation](https://developers.cloudflare.com/sandbox/)
261
- - [GitHub Issues](https://github.com/cloudflare/sandbox-sdk/issues)
262
- - [Developer Discord](https://discord.cloudflare.com)
263
- - [Cloudflare Developers](https://twitter.com/CloudflareDev)