@cloudflare/sandbox 0.0.0-12bbd12 → 0.0.0-153e416

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