@cloudflare/sandbox 0.3.6 → 0.4.1

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 (120) hide show
  1. package/.turbo/turbo-build.log +44 -0
  2. package/CHANGELOG.md +6 -8
  3. package/Dockerfile +88 -18
  4. package/README.md +89 -824
  5. package/dist/{chunk-JTKON2SH.js → chunk-BCJ7SF3Q.js} +9 -5
  6. package/dist/chunk-BCJ7SF3Q.js.map +1 -0
  7. package/dist/chunk-BFVUNTP4.js +104 -0
  8. package/dist/chunk-BFVUNTP4.js.map +1 -0
  9. package/dist/{chunk-NNGBXDMY.js → chunk-EKSWCBCA.js} +3 -6
  10. package/dist/chunk-EKSWCBCA.js.map +1 -0
  11. package/dist/chunk-HGF554LH.js +2236 -0
  12. package/dist/chunk-HGF554LH.js.map +1 -0
  13. package/dist/{chunk-6UAWTJ5S.js → chunk-Z532A7QC.js} +13 -20
  14. package/dist/{chunk-6UAWTJ5S.js.map → chunk-Z532A7QC.js.map} +1 -1
  15. package/dist/file-stream.d.ts +16 -38
  16. package/dist/file-stream.js +1 -2
  17. package/dist/index.d.ts +6 -5
  18. package/dist/index.js +35 -39
  19. package/dist/index.js.map +1 -1
  20. package/dist/interpreter.d.ts +3 -3
  21. package/dist/interpreter.js +2 -2
  22. package/dist/request-handler.d.ts +4 -3
  23. package/dist/request-handler.js +4 -7
  24. package/dist/sandbox-D9K2ypln.d.ts +583 -0
  25. package/dist/sandbox.d.ts +3 -3
  26. package/dist/sandbox.js +4 -7
  27. package/dist/security.d.ts +4 -3
  28. package/dist/security.js +3 -3
  29. package/dist/sse-parser.js +1 -1
  30. package/package.json +11 -5
  31. package/src/clients/base-client.ts +280 -0
  32. package/src/clients/command-client.ts +115 -0
  33. package/src/clients/file-client.ts +269 -0
  34. package/src/clients/git-client.ts +92 -0
  35. package/src/clients/index.ts +63 -0
  36. package/src/{interpreter-client.ts → clients/interpreter-client.ts} +148 -171
  37. package/src/clients/port-client.ts +105 -0
  38. package/src/clients/process-client.ts +177 -0
  39. package/src/clients/sandbox-client.ts +41 -0
  40. package/src/clients/types.ts +84 -0
  41. package/src/clients/utility-client.ts +94 -0
  42. package/src/errors/adapter.ts +180 -0
  43. package/src/errors/classes.ts +469 -0
  44. package/src/errors/index.ts +105 -0
  45. package/src/file-stream.ts +119 -117
  46. package/src/index.ts +81 -69
  47. package/src/interpreter.ts +17 -8
  48. package/src/request-handler.ts +69 -43
  49. package/src/sandbox.ts +694 -533
  50. package/src/security.ts +14 -23
  51. package/src/sse-parser.ts +4 -8
  52. package/startup.sh +3 -0
  53. package/tests/base-client.test.ts +328 -0
  54. package/tests/command-client.test.ts +407 -0
  55. package/tests/file-client.test.ts +643 -0
  56. package/tests/file-stream.test.ts +306 -0
  57. package/tests/git-client.test.ts +328 -0
  58. package/tests/port-client.test.ts +301 -0
  59. package/tests/process-client.test.ts +658 -0
  60. package/tests/sandbox.test.ts +465 -0
  61. package/tests/sse-parser.test.ts +290 -0
  62. package/tests/utility-client.test.ts +266 -0
  63. package/tests/wrangler.jsonc +35 -0
  64. package/tsconfig.json +9 -1
  65. package/vitest.config.ts +31 -0
  66. package/container_src/bun.lock +0 -76
  67. package/container_src/circuit-breaker.ts +0 -121
  68. package/container_src/control-process.ts +0 -784
  69. package/container_src/handler/exec.ts +0 -185
  70. package/container_src/handler/file.ts +0 -457
  71. package/container_src/handler/git.ts +0 -130
  72. package/container_src/handler/ports.ts +0 -314
  73. package/container_src/handler/process.ts +0 -568
  74. package/container_src/handler/session.ts +0 -92
  75. package/container_src/index.ts +0 -601
  76. package/container_src/interpreter-service.ts +0 -276
  77. package/container_src/isolation.ts +0 -1213
  78. package/container_src/mime-processor.ts +0 -255
  79. package/container_src/package.json +0 -18
  80. package/container_src/runtime/executors/javascript/node_executor.ts +0 -123
  81. package/container_src/runtime/executors/python/ipython_executor.py +0 -338
  82. package/container_src/runtime/executors/typescript/ts_executor.ts +0 -138
  83. package/container_src/runtime/process-pool.ts +0 -464
  84. package/container_src/shell-escape.ts +0 -42
  85. package/container_src/startup.sh +0 -11
  86. package/container_src/types.ts +0 -131
  87. package/dist/chunk-32UDXUPC.js +0 -671
  88. package/dist/chunk-32UDXUPC.js.map +0 -1
  89. package/dist/chunk-5DILEXGY.js +0 -85
  90. package/dist/chunk-5DILEXGY.js.map +0 -1
  91. package/dist/chunk-D3U63BZP.js +0 -240
  92. package/dist/chunk-D3U63BZP.js.map +0 -1
  93. package/dist/chunk-FXYPFGOZ.js +0 -129
  94. package/dist/chunk-FXYPFGOZ.js.map +0 -1
  95. package/dist/chunk-JTKON2SH.js.map +0 -1
  96. package/dist/chunk-NNGBXDMY.js.map +0 -1
  97. package/dist/chunk-SQLJNZ3K.js +0 -674
  98. package/dist/chunk-SQLJNZ3K.js.map +0 -1
  99. package/dist/chunk-W7TVRPBG.js +0 -108
  100. package/dist/chunk-W7TVRPBG.js.map +0 -1
  101. package/dist/client-B3RUab0s.d.ts +0 -225
  102. package/dist/client.d.ts +0 -4
  103. package/dist/client.js +0 -7
  104. package/dist/client.js.map +0 -1
  105. package/dist/errors.d.ts +0 -95
  106. package/dist/errors.js +0 -27
  107. package/dist/errors.js.map +0 -1
  108. package/dist/interpreter-client.d.ts +0 -4
  109. package/dist/interpreter-client.js +0 -9
  110. package/dist/interpreter-client.js.map +0 -1
  111. package/dist/interpreter-types.d.ts +0 -259
  112. package/dist/interpreter-types.js +0 -9
  113. package/dist/interpreter-types.js.map +0 -1
  114. package/dist/types.d.ts +0 -453
  115. package/dist/types.js +0 -45
  116. package/dist/types.js.map +0 -1
  117. package/src/client.ts +0 -1048
  118. package/src/errors.ts +0 -219
  119. package/src/interpreter-types.ts +0 -390
  120. package/src/types.ts +0 -571
package/README.md CHANGED
@@ -1,859 +1,126 @@
1
- <div align="center">
2
- <h1>📦 Cloudflare Sandbox SDK</h1>
3
- <h3><strong>Run sandboxed code environments on Cloudflare's edge network</strong></h3>
4
- <p>
5
- <a href="https://www.npmjs.com/package/@cloudflare/sandbox"><img src="https://img.shields.io/npm/v/@cloudflare/sandbox.svg" alt="npm version"></a>
6
- <a href="https://github.com/cloudflare/sandbox-sdk"><img src="https://img.shields.io/badge/status-experimental-orange.svg" alt="status"></a>
7
- </p>
8
- </div>
9
-
10
- <!-- START doctoc generated TOC please keep comment here to allow auto update -->
11
- <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
12
-
13
- - [✨ Overview](#overview)
14
- - [🎯 Features](#features)
15
- - [🚀 Quick Start](#quick-start)
16
- - [Installation](#installation)
17
- - [Basic Setup](#basic-setup)
18
- - [📚 API Reference](#api-reference)
19
- - [Core Methods](#core-methods)
20
- - [🧪 Code Interpreter](#code-interpreter)
21
- - [Code Execution](#code-execution)
22
- - [Rich Outputs](#rich-outputs)
23
- - [Output Formats](#output-formats)
24
- - [🌐 Port Forwarding](#port-forwarding)
25
- - [Utility Methods](#utility-methods)
26
- - [💡 Examples](#examples)
27
- - [Run a Node.js App](#run-a-nodejs-app)
28
- - [Build and Test Code](#build-and-test-code)
29
- - [Interactive Development Environment](#interactive-development-environment)
30
- - [Expose Services with Preview URLs](#expose-services-with-preview-urls)
31
- - [Data Analysis with Code Interpreter](#data-analysis-with-code-interpreter)
32
- - [🏗️ Architecture](#architecture)
33
- - [🛠️ Advanced Usage](#advanced-usage)
34
- - [AsyncIterable Streaming Support](#asynciterable-streaming-support)
35
- - [Session Management](#session-management)
36
- - [🔍 Debugging](#debugging)
37
- - [🚧 Known Limitations](#known-limitations)
38
- - [🤝 Contributing](#contributing)
39
- - [📄 License](#license)
40
- - [🙌 Acknowledgments](#acknowledgments)
41
-
42
- <!-- END doctoc generated TOC please keep comment here to allow auto update -->
43
-
44
- <h2 id="overview">✨ Overview</h2>
45
-
46
- The Cloudflare Sandbox SDK enables you to run isolated code environments directly on Cloudflare's edge network using Durable Objects and the Cloudflare Containers. Execute commands, manage files, run services, and expose them via public URLs - all within secure, sandboxed containers.
47
-
48
- <h2 id="features">🎯 Features</h2>
49
-
50
- - **🔒 Secure Isolation**: Each sandbox runs in its own container with full process isolation
51
- - **⚡ Edge-Native**: Runs on Cloudflare's global network for low latency worldwide
52
- - **📁 File System Access**: Read, write, and manage files within the sandbox
53
- - **🖼️ Binary File Support**: Automatic MIME type detection and base64 encoding for images, PDFs, and other binary files
54
- - **🔧 Command Execution**: Run any command or process inside the container
55
- - **🌐 Preview URLs**: Expose services running in your sandbox via public URLs
56
- - **🔄 Git Integration**: Clone repositories directly into sandboxes
57
- - **🚀 Streaming Support**: Real-time output streaming for long-running commands and file transfers
58
- - **🎮 Session Management**: Maintain state across multiple operations
59
- - **🧪 Code Interpreter**: Execute Python and JavaScript with rich outputs (charts, tables, formatted data)
60
- - **📊 Multi-Language Support**: Persistent execution contexts for Python and JavaScript/TypeScript
61
- - **🎨 Rich MIME Types**: Automatic processing of images, HTML, charts, and structured data
62
-
63
- <h2 id="quick-start">🚀 Quick Start</h2>
64
-
65
- ### Installation
1
+ <img width="1362" height="450" alt="Image" src="https://github.com/user-attachments/assets/6f770ae3-0a14-4d2b-9aed-a304ee5446c5" />
66
2
 
67
- ```bash
68
- npm install @cloudflare/sandbox
69
- ```
70
-
71
- ### Basic Setup
72
-
73
- 1. **Create a Dockerfile** (temporary requirement, will be removed in future releases):
74
-
75
- ```dockerfile
76
- FROM docker.io/cloudflare/sandbox:0.3.6
77
-
78
- # Expose the ports you want to expose
79
- EXPOSE 3000
80
- ```
81
-
82
- 2. **Configure wrangler.json**:
83
-
84
- > **NOTE**: In an upcoming release, this step will be removed entirely and you can reference a single Docker image published by us directly in your wrangler configuration below.
85
-
86
- ```jsonc
87
- {
88
- // ...
89
- "containers": [
90
- {
91
- "class_name": "Sandbox",
92
- "image": "./Dockerfile",
93
- "max_instances": 20
94
- }
95
- ],
96
- "durable_objects": {
97
- "bindings": [
98
- {
99
- "class_name": "Sandbox",
100
- "name": "Sandbox"
101
- }
102
- ]
103
- },
104
- "migrations": [
105
- {
106
- "new_sqlite_classes": ["Sandbox"],
107
- "tag": "v1"
108
- }
109
- ]
110
- }
111
- ```
112
-
113
- 3. **Create your Worker**:
114
-
115
- ```typescript
116
- import { getSandbox } from "@cloudflare/sandbox";
3
+ # Cloudflare Sandbox SDK
117
4
 
118
- // Export the Sandbox class in your Worker
119
- export { Sandbox } from "@cloudflare/sandbox";
5
+ [![npm version](https://img.shields.io/npm/v/@cloudflare/sandbox.svg)](https://www.npmjs.com/package/@cloudflare/sandbox)
120
6
 
121
- export default {
122
- async fetch(request: Request, env: Env) {
123
- const sandbox = getSandbox(env.Sandbox, "my-sandbox");
7
+ **Build secure, isolated code execution environments on Cloudflare.**
124
8
 
125
- // Execute a command
126
- const result = await sandbox.exec("echo 'Hello from the edge!'");
127
- return new Response(result.stdout);
128
- },
129
- };
130
- ```
9
+ 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.
131
10
 
132
- <h2 id="api-reference">📚 API Reference</h2>
11
+ 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.
133
12
 
134
- ### Core Methods
13
+ > **Note:** The latest published version of the SDK is on the [v03 branch](https://github.com/cloudflare/sandbox-sdk/tree/v03). This main branch is currently the development version and is not yet published.
135
14
 
136
- #### Command Execution
15
+ ## Getting Started
137
16
 
138
- **`exec(command, options?)`** - Enhanced command execution that always returns results
17
+ ### Prerequisites
139
18
 
140
- ```typescript
141
- // Simple execution
142
- const result = await sandbox.exec("npm install express");
143
- console.log(result.stdout, result.exitCode);
144
-
145
- // With streaming callbacks
146
- const result = await sandbox.exec("npm run build", {
147
- stream: true,
148
- onOutput: (stream, data) => console.log(`[${stream}] ${data}`)
149
- });
150
- ```
19
+ 1. Install [Node.js](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) (version 16.17.0 or later)
20
+ 2. Ensure Docker is running locally
21
+ 3. For deploying to production, sign up for a [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages)
151
22
 
152
- **`execStream(command, options?)`** - Dedicated streaming method returning SSE stream
23
+ ### 1. Create a new project
153
24
 
154
- ```typescript
155
- import { parseSSEStream, type ExecEvent } from '@cloudflare/sandbox';
156
-
157
- const stream = await sandbox.execStream("npm run test");
158
- for await (const event of parseSSEStream<ExecEvent>(stream)) {
159
- switch (event.type) {
160
- case 'stdout':
161
- console.log(`Test output: ${event.data}`);
162
- break;
163
- case 'complete':
164
- console.log(`Tests ${event.exitCode === 0 ? 'passed' : 'failed'}`);
165
- break;
166
- }
167
- }
168
- ```
25
+ Create a new Sandbox SDK project using the minimal template:
169
26
 
170
- **`startProcess(command, options?)`** - Start background processes with lifecycle management
171
-
172
- ```typescript
173
- const process = await sandbox.startProcess("node server.js");
174
- console.log(`Started process ${process.id} with PID ${process.pid}`);
175
-
176
- // Monitor the process
177
- const logStream = await sandbox.streamProcessLogs(process.id);
178
- for await (const log of parseSSEStream<LogEvent>(logStream)) {
179
- console.log(`Server: ${log.data}`);
180
- }
181
- ```
182
-
183
- #### `writeFile(path, content, options?)`
184
-
185
- Write content to a file.
186
-
187
- ```typescript
188
- await sandbox.writeFile("/workspace/app.js", "console.log('Hello!');");
189
- ```
190
-
191
- #### `readFile(path, options?)`
192
-
193
- Read a file from the sandbox with automatic binary detection.
194
-
195
- ```typescript
196
- // Read text files
197
- const file = await sandbox.readFile("/package.json");
198
- console.log(file.content); // UTF-8 text content
199
-
200
- // Read binary files - automatically detected and base64 encoded
201
- const image = await sandbox.readFile("/workspace/chart.png");
202
- console.log(image.mimeType); // "image/png"
203
- console.log(image.isBinary); // true
204
- console.log(image.encoding); // "base64"
205
- console.log(image.size); // File size in bytes
206
-
207
- // Use the base64 content directly in data URLs
208
- const dataUrl = `data:${image.mimeType};base64,${image.content}`;
209
- ```
210
-
211
- #### `readFileStream(path)`
212
-
213
- Stream large files efficiently with automatic chunking and encoding.
214
-
215
- ```typescript
216
- import { streamFile, collectFile } from '@cloudflare/sandbox';
217
-
218
- // Stream a large file
219
- const stream = await sandbox.readFileStream("/large-video.mp4");
220
-
221
- // Option 1: Process chunks as they arrive
222
- for await (const chunk of streamFile(stream)) {
223
- if (chunk instanceof Uint8Array) {
224
- // Binary chunk - already decoded from base64
225
- console.log(`Received ${chunk.byteLength} bytes`);
226
- // Process binary data...
227
- } else {
228
- // Text chunk
229
- console.log('Text:', chunk);
230
- }
231
- }
232
-
233
- // Option 2: Collect entire file into memory
234
- const { content, metadata } = await collectFile(stream);
235
- console.log(`MIME: ${metadata.mimeType}, Size: ${metadata.size} bytes`);
236
-
237
- if (content instanceof Uint8Array) {
238
- // Binary file - ready to save or process
239
- await writeToStorage(content);
240
- } else {
241
- // Text file
242
- console.log('Content:', content);
243
- }
244
- ```
245
-
246
- #### `gitCheckout(repoUrl, options?)`
247
-
248
- Clone a git repository.
249
-
250
- ```typescript
251
- await sandbox.gitCheckout("https://github.com/user/repo", {
252
- branch: "main",
253
- targetDir: "my-project",
254
- });
27
+ ```bash
28
+ npm create cloudflare@latest -- my-sandbox --template=cloudflare/sandbox-sdk/examples/minimal
29
+ cd my-sandbox
255
30
  ```
256
31
 
257
- #### `setEnvVars(envVars)`
258
-
259
- Set environment variables dynamically in the sandbox.
32
+ ### 2. Test locally
260
33
 
261
- > **Important**: This method must be called immediately after `getSandbox()` and before any other operations. Once a sandbox instance starts up, environment variables cannot be changed
262
- for that instance.
34
+ Start the development server:
263
35
 
264
- ```typescript
265
- const sandbox = getSandbox(env.Sandbox, "my-sandbox");
266
-
267
- // Set environment variables FIRST, before any other operations
268
- await sandbox.setEnvVars({
269
- NODE_ENV: "production",
270
- API_KEY: "your-api-key",
271
- DATABASE_URL: "postgresql://localhost:5432/mydb"
272
- });
273
-
274
- // Now you can run commands - environment variables are available
275
- const result = await sandbox.exec("echo $NODE_ENV");
276
- console.log(result.stdout); // "production"
36
+ ```bash
37
+ npm run dev
277
38
  ```
278
39
 
279
- #### Process Management
280
-
281
- - `listProcesses()` - List all running processes
282
- - `getProcess(id)` - Get detailed process status
283
- - `killProcess(id, signal?)` - Terminate specific processes
284
- - `killAllProcesses()` - Kill all processes
285
- - `streamProcessLogs(id, options?)` - Stream logs from running processes
286
- - `getProcessLogs(id)` - Get accumulated process output
287
-
288
- #### File System Methods
289
-
290
- - `writeFile(path, content, options?)` - Write content to a file
291
- - `readFile(path, options?)` - Read a file with automatic binary detection and base64 encoding
292
- - `readFileStream(path)` - Stream large files efficiently with chunking
293
- - `mkdir(path, options?)` - Create a directory
294
- - `deleteFile(path)` - Delete a file
295
- - `renameFile(oldPath, newPath)` - Rename a file
296
- - `moveFile(sourcePath, destinationPath)` - Move a file
297
- - `gitCheckout(repoUrl, options?)` - Clone git repositories
298
-
299
- #### Network Methods
300
-
301
- - `exposePort(port, options?)` - Expose a port and get a public URL
302
- - `unexposePort(port)` - Remove port exposure
303
- - `getExposedPorts()` - List all exposed ports with their URLs
304
-
305
- #### Session Methods
306
-
307
- - `createSession(options)` - Create an isolated execution session
308
- - `name`: Session identifier
309
- - `env`: Environment variables for this session
310
- - `cwd`: Working directory
311
- - `isolation`: Enable PID namespace isolation (requires CAP_SYS_ADMIN)
312
-
313
- <h2 id="code-interpreter">🧪 Code Interpreter</h2>
40
+ > **Note:** First run builds the Docker container (2-3 minutes). Subsequent runs are much faster.
314
41
 
315
- The Sandbox SDK includes powerful code interpreter capabilities, allowing you to execute Python and JavaScript code with rich outputs including charts, tables, and formatted data.
42
+ Test the endpoints:
316
43
 
317
- ### Code Execution
318
-
319
- #### `createCodeContext(options?)`
320
-
321
- Creates a new code execution context with persistent state.
322
-
323
- ```typescript
324
- // Create a Python context
325
- const pythonCtx = await sandbox.createCodeContext({ language: 'python' });
44
+ ```bash
45
+ # Execute Python code
46
+ curl http://localhost:8787/run
326
47
 
327
- // Create a JavaScript context
328
- const jsCtx = await sandbox.createCodeContext({ language: 'javascript' });
48
+ # File operations
49
+ curl http://localhost:8787/file
329
50
  ```
330
51
 
331
- **Options:**
332
- - `language`: Programming language (`'python'` | `'javascript'` | `'typescript'`)
333
- - `cwd`: Working directory (default: `/workspace`)
334
- - `envVars`: Environment variables for the context
335
-
336
- #### `runCode(code, options?)`
52
+ ### 3. Deploy to production
337
53
 
338
- Executes code with optional streaming callbacks.
54
+ Deploy your Worker and container:
339
55
 
340
- ```typescript
341
- // Simple execution
342
- const execution = await sandbox.runCode('print("Hello World")', {
343
- context: pythonCtx
344
- });
345
-
346
- // With streaming callbacks
347
- await sandbox.runCode(`
348
- for i in range(5):
349
- print(f"Step {i}")
350
- time.sleep(1)
351
- `, {
352
- context: pythonCtx,
353
- onStdout: (output) => console.log('Real-time:', output.text),
354
- onResult: (result) => console.log('Result:', result)
355
- });
56
+ ```bash
57
+ npx wrangler deploy
356
58
  ```
357
59
 
358
- **Options:**
359
- - `context`: Context to run the code in
360
- - `language`: Language if no context provided
361
- - `onStdout`: Callback for stdout output
362
- - `onStderr`: Callback for stderr output
363
- - `onResult`: Callback for execution results
364
- - `onError`: Callback for errors
365
-
366
- #### `runCodeStream(code, options?)`
367
-
368
- Returns a streaming response for real-time processing.
369
-
370
- ```typescript
371
- const stream = await sandbox.runCodeStream('import time; [print(i) for i in range(10)]');
372
- // Process the stream as needed
373
- ```
60
+ > **Wait for provisioning:** After first deployment, wait 2-3 minutes before making requests.
374
61
 
375
- ### Rich Outputs
62
+ **📖 [View the complete getting started guide](https://developers.cloudflare.com/sandbox/get-started/)** for detailed instructions and explanations.
376
63
 
377
- The code interpreter automatically detects and processes various output types:
64
+ ## Quick API Example
378
65
 
379
66
  ```typescript
380
- // Data visualization
381
- const execution = await sandbox.runCode(`
382
- import matplotlib.pyplot as plt
383
- import numpy as np
384
-
385
- x = np.linspace(0, 10, 100)
386
- y = np.sin(x)
387
- plt.plot(x, y)
388
- plt.title('Sine Wave')
389
- plt.show()
390
- `, {
391
- context: pythonCtx,
392
- onResult: (result) => {
393
- if (result.png) {
394
- // Base64 encoded PNG image
395
- console.log('Chart generated!');
396
- }
397
- }
398
- });
399
-
400
- // HTML tables with pandas
401
- const tableExecution = await sandbox.runCode(`
402
- import pandas as pd
403
- df = pd.DataFrame({
404
- 'name': ['Alice', 'Bob', 'Charlie'],
405
- 'score': [92, 88, 95]
406
- })
407
- df
408
- `, { context: pythonCtx });
409
-
410
- // Access HTML table in execution.results[0].html
411
- ```
412
-
413
- ### Output Formats
67
+ import { getSandbox, proxyToSandbox, type Sandbox } from '@cloudflare/sandbox';
414
68
 
415
- Results can include multiple formats:
416
- - `text`: Plain text representation
417
- - `html`: HTML (often pandas DataFrames)
418
- - `png`/`jpeg`: Base64 encoded images
419
- - `svg`: Vector graphics
420
- - `json`: Structured data
421
- - `chart`: Parsed chart information
69
+ export { Sandbox } from '@cloudflare/sandbox';
422
70
 
423
- Check available formats with `result.formats()`.
424
-
425
- #### Additional Code Interpreter Methods
426
-
427
- - `listCodeContexts()` - List all active code contexts
428
- - `deleteCodeContext(contextId)` - Delete a specific context
429
-
430
- <h2 id="port-forwarding">🌐 Port Forwarding</h2>
431
-
432
- The SDK automatically handles preview URL routing for exposed ports. Just add one line to your worker:
433
-
434
- ```typescript
435
- import { proxyToSandbox, getSandbox } from "@cloudflare/sandbox";
71
+ type Env = {
72
+ Sandbox: DurableObjectNamespace<Sandbox>;
73
+ };
436
74
 
437
75
  export default {
438
- async fetch(request, env) {
439
- // Route requests to exposed container ports via their preview URLs
76
+ async fetch(request: Request, env: Env): Promise<Response> {
77
+ // Required for preview URLs
440
78
  const proxyResponse = await proxyToSandbox(request, env);
441
79
  if (proxyResponse) return proxyResponse;
442
80
 
443
- // Your custom routes here
444
- // ...
445
- },
446
- };
447
- ```
448
-
449
- When you expose a port, the SDK returns a preview URL that automatically routes to your service:
450
-
451
- ```typescript
452
- const preview = await sandbox.exposePort(3000);
453
- console.log(preview.url); // https://3000-sandbox-id.your-worker.dev
454
- ```
455
-
456
- The SDK handles:
457
-
458
- - Subdomain routing (`3000-sandbox-id.domain.com`) for both production and local development
459
- - All localhost variants (127.0.0.1, ::1, etc.)
460
- - Request forwarding with proper headers
461
-
462
- > **Important for Local Development**: When developing locally with `wrangler dev`, you must explicitly expose ports in your Dockerfile using the `EXPOSE` instruction. This is **only required for local development** - in production, all container ports are automatically accessible.
463
-
464
- ```dockerfile
465
- # In your Dockerfile (only needed for local dev)
466
- FROM docker.io/cloudflare/sandbox:0.1.3
81
+ const url = new URL(request.url);
82
+ const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
467
83
 
468
- # Expose the ports you'll be using
469
- EXPOSE 3000 # For a web server
470
- EXPOSE 8080 # For an API server
471
- EXPOSE 3001 # For any additional services
472
-
473
- # Your container setup...
474
- ```
475
-
476
- Without the `EXPOSE` instruction in local development, you'll see this error:
477
-
478
- ```
479
- connect(): Connection refused: container port not found. Make sure you exposed the port in your container definition.
480
- ```
481
-
482
- For more details, see the [Cloudflare Containers local development guide](https://developers.cloudflare.com/containers/local-dev/#exposing-ports).
483
-
484
- ### Utility Methods
485
-
486
- - `ping()` - Health check for the sandbox
487
- - `containerFetch(request)` - Direct container communication
488
-
489
- <h2 id="examples">💡 Examples</h2>
490
-
491
- ### Run a Node.js App
492
-
493
- ```typescript
494
- const sandbox = getSandbox(env.Sandbox, "node-app");
495
-
496
- // Write a simple Express server
497
- await sandbox.writeFile(
498
- "/workspace/app.js",
499
- `
500
- const express = require('express');
501
- const app = express();
502
-
503
- app.get('/', (req, res) => {
504
- res.json({ message: 'Hello from Cloudflare!' });
505
- });
506
-
507
- app.listen(3000);
508
- `
509
- );
510
-
511
- // Install dependencies and start the server
512
- await sandbox.exec("npm init -y");
513
- await sandbox.exec("npm install express");
514
- const server = await sandbox.startProcess("node app.js");
515
-
516
- // Expose it to the internet
517
- const preview = await sandbox.exposePort(3000);
518
- console.log(`API available at: ${preview.url}`);
519
- ```
520
-
521
- ### Build and Test Code
522
-
523
- ```typescript
524
- const sandbox = getSandbox(env.Sandbox, "test-env");
525
-
526
- // Clone a repository
527
- await sandbox.gitCheckout("https://github.com/user/project");
528
-
529
- // Run tests
530
- const testResult = await sandbox.exec("npm test");
531
-
532
- // Build the project
533
- const buildResult = await sandbox.exec("npm run build");
534
-
535
- return new Response(
536
- JSON.stringify({
537
- tests: testResult.exitCode === 0 ? "passed" : "failed",
538
- build: buildResult.exitCode === 0 ? "success" : "failed",
539
- output: testResult.stdout,
540
- })
541
- );
542
- ```
543
-
544
- ### Interactive Development Environment
545
-
546
- ```typescript
547
- // Create a development sandbox with hot reload
548
- const sandbox = getSandbox(env.Sandbox, "dev-env");
549
-
550
- // Set up the project
551
- await sandbox.gitCheckout("https://github.com/user/my-app");
552
- await sandbox.exec("npm install");
553
-
554
- // Start dev server
555
- const devServer = await sandbox.startProcess("npm run dev");
556
-
557
- // Expose the dev server
558
- const preview = await sandbox.exposePort(3000, { name: "dev-server" });
559
-
560
- // Make changes and see them live!
561
- await sandbox.writeFile("/src/App.jsx", updatedCode);
562
- ```
563
-
564
- ### Expose Services with Preview URLs
565
-
566
- ```typescript
567
- // Create and start a web server
568
- await sandbox.writeFile(
569
- "/server.js",
570
- `Bun.serve({
571
- port: 8080,
572
- fetch(req) {
573
- return new Response("Hello from sandbox!");
84
+ // Execute Python code
85
+ if (url.pathname === '/run') {
86
+ const result = await sandbox.exec('python3 -c "print(2 + 2)"');
87
+ return Response.json({ output: result.stdout, success: result.success });
574
88
  }
575
- });`
576
- );
577
-
578
- const server = await sandbox.startProcess("bun run /server.js");
579
-
580
- // Expose the port - returns a public URL
581
- const preview = await sandbox.exposePort(8080);
582
- console.log(`Service available at: ${preview.url}`);
583
-
584
- // Note: Your Worker needs to handle preview URL routing.
585
- // See the example in examples/basic/src/index.ts for the routing implementation.
586
- ```
587
-
588
- ### Data Analysis with Code Interpreter
589
-
590
- ```typescript
591
- const sandbox = getSandbox(env.Sandbox, "analysis");
592
-
593
- // Create a Python context for data analysis
594
- const pythonCtx = await sandbox.createCodeContext({ language: 'python' });
595
-
596
- // Load and analyze data
597
- const analysis = await sandbox.runCode(`
598
- import pandas as pd
599
- import matplotlib.pyplot as plt
600
-
601
- # Create sample data
602
- data = {
603
- 'Month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
604
- 'Sales': [10000, 12000, 15000, 14000, 18000],
605
- 'Profit': [2000, 2500, 3200, 2800, 4000]
606
- }
607
- df = pd.DataFrame(data)
608
-
609
- # Display summary statistics
610
- print("Sales Summary:")
611
- print(df.describe())
612
-
613
- # Create visualization
614
- plt.figure(figsize=(10, 6))
615
- plt.subplot(1, 2, 1)
616
- plt.bar(df['Month'], df['Sales'])
617
- plt.title('Monthly Sales')
618
- plt.xlabel('Month')
619
- plt.ylabel('Sales ($)')
620
-
621
- plt.subplot(1, 2, 2)
622
- plt.plot(df['Month'], df['Profit'], marker='o', color='green')
623
- plt.title('Monthly Profit')
624
- plt.xlabel('Month')
625
- plt.ylabel('Profit ($)')
626
-
627
- plt.tight_layout()
628
- plt.show()
629
-
630
- # Return the data as JSON
631
- df.to_dict('records')
632
- `, {
633
- context: pythonCtx,
634
- onResult: (result) => {
635
- if (result.png) {
636
- // Handle the chart image
637
- console.log('Chart generated:', result.png.substring(0, 50) + '...');
638
- }
639
- if (result.json) {
640
- // Handle the structured data
641
- console.log('Data:', result.json);
642
- }
643
- }
644
- });
645
-
646
- // Multi-language workflow: Process in Python, analyze in JavaScript
647
- await sandbox.runCode(`
648
- # Save processed data
649
- df.to_json('/tmp/sales_data.json', orient='records')
650
- `, { context: pythonCtx });
651
-
652
- const jsCtx = await sandbox.createCodeContext({ language: 'javascript' });
653
- const jsAnalysis = await sandbox.runCode(`
654
- const fs = require('fs');
655
- const data = JSON.parse(fs.readFileSync('/tmp/sales_data.json', 'utf8'));
656
-
657
- // Calculate growth rate
658
- const growth = data.map((curr, idx) => {
659
- if (idx === 0) return { ...curr, growth: 0 };
660
- const prev = data[idx - 1];
661
- return {
662
- ...curr,
663
- growth: ((curr.Sales - prev.Sales) / prev.Sales * 100).toFixed(2) + '%'
664
- };
665
- });
666
-
667
- console.log('Growth Analysis:', growth);
668
- growth;
669
- `, { context: jsCtx });
670
- ```
671
-
672
- <h2 id="architecture">🏗️ Architecture</h2>
673
-
674
- The SDK leverages Cloudflare's infrastructure:
675
89
 
676
- - **Durable Objects**: Manages sandbox lifecycle and state
677
- - **Containers**: Provides isolated execution environments with Jupyter kernels
678
- - **Workers**: Handles HTTP routing and API interface
679
- - **Edge Network**: Enables global distribution and low latency
680
- - **Jupyter Integration**: Python (IPython) and JavaScript (TSLab) kernels for code execution
681
- - **MIME Processing**: Automatic detection and handling of rich output formats
682
-
683
- <h2 id="advanced-usage">🛠️ Advanced Usage</h2>
684
-
685
- ### AsyncIterable Streaming Support
686
-
687
- The SDK provides powerful streaming capabilities with typed AsyncIterable support:
688
-
689
- ```typescript
690
- import { parseSSEStream, type ExecEvent } from '@cloudflare/sandbox';
691
-
692
- // Stream command execution
693
- const stream = await sandbox.execStream('npm run build');
694
- for await (const event of parseSSEStream<ExecEvent>(stream)) {
695
- switch (event.type) {
696
- case 'start':
697
- console.log(`Build started: ${event.command}`);
698
- break;
699
- case 'stdout':
700
- console.log(`Build: ${event.data}`);
701
- break;
702
- case 'complete':
703
- console.log(`Exit code: ${event.exitCode}`);
704
- break;
705
- case 'error':
706
- console.error(`Error: ${event.error}`);
707
- break;
708
- }
709
- }
710
- ```
711
-
712
- #### Streaming Utilities
713
-
714
- The SDK exports utilities for working with Server-Sent Event streams:
715
-
716
- **Command Execution:**
717
- - **`parseSSEStream<T>(stream)`** - Convert ReadableStream to typed AsyncIterable
718
- - **`responseToAsyncIterable<T>(response)`** - Convert SSE Response to AsyncIterable
719
- - **`asyncIterableToSSEStream<T>(iterable)`** - Convert AsyncIterable back to SSE stream
720
-
721
- **File Streaming:**
722
- - **`streamFile(stream, signal?)`** - Convert file SSE stream to AsyncIterable with automatic base64 decoding
723
- - **`collectFile(stream, signal?)`** - Collect entire file from stream into memory
724
-
725
- #### Advanced Streaming Examples
726
-
727
- **CI/CD Build System:**
728
- ```typescript
729
- export async function runBuild(env: Env, buildId: string) {
730
- const sandbox = getSandbox(env.SANDBOX, buildId);
731
- const stream = await sandbox.execStream('npm run build');
732
-
733
- for await (const event of parseSSEStream<ExecEvent>(stream)) {
734
- switch (event.type) {
735
- case 'start':
736
- await env.BUILDS.put(buildId, { status: 'running' });
737
- break;
738
- case 'complete':
739
- await env.BUILDS.put(buildId, {
740
- status: event.exitCode === 0 ? 'success' : 'failed',
741
- exitCode: event.exitCode
742
- });
743
- break;
90
+ // Work with files
91
+ if (url.pathname === '/file') {
92
+ await sandbox.writeFile('/workspace/hello.txt', 'Hello, Sandbox!');
93
+ const file = await sandbox.readFile('/workspace/hello.txt');
94
+ return Response.json({ content: file.content });
744
95
  }
745
- }
746
- }
747
- ```
748
96
 
749
- **System Monitoring:**
750
- ```typescript
751
- const monitor = await sandbox.startProcess('tail -f /var/log/system.log');
752
- const logStream = await sandbox.streamProcessLogs(monitor.id);
753
-
754
- for await (const log of parseSSEStream<LogEvent>(logStream)) {
755
- if (log.type === 'stdout' && log.data.includes('ERROR')) {
756
- await env.ALERTS.send({
757
- severity: 'high',
758
- message: log.data,
759
- timestamp: log.timestamp
760
- });
97
+ return new Response('Try /run or /file');
761
98
  }
762
- }
763
- ```
764
-
765
- ### Session Management
766
-
767
- The SDK provides two approaches for managing execution context:
768
-
769
- #### Implicit Sessions (Recommended)
770
-
771
- Each sandbox maintains its own persistent session automatically:
772
-
773
- ```typescript
774
- const sandbox = getSandbox(env.Sandbox, "my-app");
775
-
776
- // These commands share state (pwd, env vars, etc.)
777
- await sandbox.exec("cd /app");
778
- await sandbox.exec("pwd"); // Output: /app
779
- await sandbox.exec("export MY_VAR=hello");
780
- await sandbox.exec("echo $MY_VAR"); // Output: hello
781
- ```
782
-
783
- #### Explicit Sessions for Advanced Use Cases
784
-
785
- Create isolated execution contexts within the same sandbox:
786
-
787
- ```typescript
788
- const sandbox = getSandbox(env.Sandbox, "multi-env");
789
-
790
- // Create independent sessions with different environments
791
- const buildSession = await sandbox.createSession({
792
- name: "build",
793
- env: { NODE_ENV: "production" },
794
- cwd: "/build"
795
- });
796
-
797
- const testSession = await sandbox.createSession({
798
- name: "test",
799
- env: { NODE_ENV: "test" },
800
- cwd: "/test"
801
- });
802
-
803
- // Run commands in parallel with different contexts
804
- await Promise.all([
805
- buildSession.exec("npm run build"),
806
- testSession.exec("npm test")
807
- ]);
808
- ```
809
-
810
- #### Security with AI Agents
811
-
812
- When using AI coding agents, separate development from execution:
813
-
814
- ```typescript
815
- // Phase 1: AI agent writes code (with API keys)
816
- const devSession = await sandbox.createSession({
817
- name: "ai-development",
818
- env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }
819
- });
820
- await devSession.exec('opencode "build a web server"');
821
-
822
- // Phase 2: Run the generated code (without API keys)
823
- const appSession = await sandbox.createSession({
824
- name: "app-runtime",
825
- env: { PORT: "3000" } // Only app-specific vars
826
- });
827
- await appSession.exec("node server.js");
99
+ };
828
100
  ```
829
101
 
830
- > **Best Practice**: Keep AI agent credentials separate from your application runtime to prevent accidental exposure of API keys.
831
-
832
- <h2 id="debugging">🔍 Debugging</h2>
102
+ ## Documentation
833
103
 
834
- Enable verbose logging:
104
+ **📖 [Full Documentation](https://developers.cloudflare.com/sandbox/)**
835
105
 
836
- ```typescript
837
- const sandbox = getSandbox(env.Sandbox, "debug-sandbox");
838
- sandbox.client.onCommandStart = (cmd, args) =>
839
- console.log(`Starting: ${cmd} ${args.join(" ")}`);
840
- sandbox.client.onOutput = (stream, data) => console.log(`[${stream}] ${data}`);
841
- sandbox.client.onCommandComplete = (success, code) =>
842
- console.log(`Completed: ${success} (${code})`);
843
- ```
106
+ - [Get Started Guide](https://developers.cloudflare.com/sandbox/get-started/) - Step-by-step tutorial
107
+ - [API Reference](https://developers.cloudflare.com/sandbox/api/) - Complete API docs
108
+ - [Guides](https://developers.cloudflare.com/sandbox/guides/) - Execute commands, manage files, expose services
109
+ - [Examples](https://developers.cloudflare.com/sandbox/tutorials/) - AI agents, data analysis, CI/CD pipelines
844
110
 
845
- <h2 id="known-limitations">🚧 Known Limitations</h2>
111
+ ## Key Features
846
112
 
847
- - Maximum container runtime is limited by Durable Object constraints
848
- - WebSocket support for preview URLs coming soon
849
- - Some system calls may be restricted in the container environment
850
- - Code interpreter has no internet access (sandbox restriction)
851
- - Some Python/JavaScript packages may not be pre-installed
852
- - Resource limits apply to code execution (CPU, memory)
113
+ - **Secure Isolation** - Each sandbox runs in its own container
114
+ - **Edge-Native** - Runs on Cloudflare's global network
115
+ - **Code Interpreter** - Execute Python and JavaScript with rich outputs
116
+ - **File System Access** - Read, write, and manage files
117
+ - **Command Execution** - Run any command with streaming support
118
+ - **Preview URLs** - Expose services with public URLs
119
+ - **Git Integration** - Clone repositories directly
853
120
 
854
- <h2 id="contributing">🤝 Contributing</h2>
121
+ ## Development
855
122
 
856
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
123
+ This repository contains the SDK source code. To contribute:
857
124
 
858
125
  ```bash
859
126
  # Clone the repo
@@ -863,37 +130,35 @@ cd sandbox-sdk
863
130
  # Install dependencies
864
131
  npm install
865
132
 
866
- # Install Bun (if not already installed)
867
- # Visit https://bun.sh for installation instructions
868
- curl -fsSL https://bun.sh/install | bash
869
-
870
- # Install container dependencies (required for TypeScript checking)
871
- cd packages/sandbox/container_src && bun install && cd -
872
-
873
133
  # Run tests
874
134
  npm test
875
135
 
876
136
  # Build the project
877
137
  npm run build
878
138
 
879
- # Run type checking and linting
139
+ # Type checking and linting
880
140
  npm run check
881
141
  ```
882
142
 
883
- <h2 id="license">📄 License</h2>
143
+ ## Examples
884
144
 
885
- [MIT License](LICENSE)
145
+ See the [examples directory](./examples) for complete working examples:
146
+
147
+ - [Minimal](./examples/minimal) - Basic sandbox setup
148
+ - [Code Interpreter](./examples/code-interpreter) - Use sandbox as an interpreter tool with gpt-oss
149
+ - [Complete](./examples/basic) - Huge example integrated with every sandbox feature
150
+
151
+ ## Status
886
152
 
887
- <h2 id="acknowledgments">🙌 Acknowledgments</h2>
153
+ **Beta** - The SDK is in active development. APIs may change before v1.0.
888
154
 
889
- Built with ❤️ by the Cloudflare team. Special thanks to all early adopters and contributors.
155
+ ## License
156
+
157
+ [MIT License](LICENSE)
890
158
 
891
- ---
159
+ ## Links
892
160
 
893
- <div align="center">
894
- <p>
895
- <a href="https://github.com/cloudflare/sandbox-sdk/issues">Issues</a> •
896
- <a href="https://discord.gg/cloudflaredev">Discord</a> •
897
- <a href="https://twitter.com/CloudflareDev">Twitter</a>
898
- </p>
899
- </div>
161
+ - [Documentation](https://developers.cloudflare.com/sandbox/)
162
+ - [GitHub Issues](https://github.com/cloudflare/sandbox-sdk/issues)
163
+ - [Developer Discord](https://discord.cloudflare.com)
164
+ - [Cloudflare Developers](https://twitter.com/CloudflareDev)