@cloudflare/sandbox 0.0.0-e1fa354 → 0.0.0-e489cbb

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