@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.
- package/.turbo/turbo-build.log +44 -0
- package/CHANGELOG.md +6 -8
- package/Dockerfile +88 -18
- package/README.md +89 -824
- package/dist/{chunk-JTKON2SH.js → chunk-BCJ7SF3Q.js} +9 -5
- package/dist/chunk-BCJ7SF3Q.js.map +1 -0
- package/dist/chunk-BFVUNTP4.js +104 -0
- package/dist/chunk-BFVUNTP4.js.map +1 -0
- package/dist/{chunk-NNGBXDMY.js → chunk-EKSWCBCA.js} +3 -6
- package/dist/chunk-EKSWCBCA.js.map +1 -0
- package/dist/chunk-HGF554LH.js +2236 -0
- package/dist/chunk-HGF554LH.js.map +1 -0
- package/dist/{chunk-6UAWTJ5S.js → chunk-Z532A7QC.js} +13 -20
- package/dist/{chunk-6UAWTJ5S.js.map → chunk-Z532A7QC.js.map} +1 -1
- package/dist/file-stream.d.ts +16 -38
- package/dist/file-stream.js +1 -2
- package/dist/index.d.ts +6 -5
- package/dist/index.js +35 -39
- package/dist/index.js.map +1 -1
- package/dist/interpreter.d.ts +3 -3
- package/dist/interpreter.js +2 -2
- package/dist/request-handler.d.ts +4 -3
- package/dist/request-handler.js +4 -7
- package/dist/sandbox-D9K2ypln.d.ts +583 -0
- package/dist/sandbox.d.ts +3 -3
- package/dist/sandbox.js +4 -7
- package/dist/security.d.ts +4 -3
- package/dist/security.js +3 -3
- package/dist/sse-parser.js +1 -1
- package/package.json +11 -5
- package/src/clients/base-client.ts +280 -0
- package/src/clients/command-client.ts +115 -0
- package/src/clients/file-client.ts +269 -0
- package/src/clients/git-client.ts +92 -0
- package/src/clients/index.ts +63 -0
- package/src/{interpreter-client.ts → clients/interpreter-client.ts} +148 -171
- package/src/clients/port-client.ts +105 -0
- package/src/clients/process-client.ts +177 -0
- package/src/clients/sandbox-client.ts +41 -0
- package/src/clients/types.ts +84 -0
- package/src/clients/utility-client.ts +94 -0
- package/src/errors/adapter.ts +180 -0
- package/src/errors/classes.ts +469 -0
- package/src/errors/index.ts +105 -0
- package/src/file-stream.ts +119 -117
- package/src/index.ts +81 -69
- package/src/interpreter.ts +17 -8
- package/src/request-handler.ts +69 -43
- package/src/sandbox.ts +694 -533
- package/src/security.ts +14 -23
- package/src/sse-parser.ts +4 -8
- package/startup.sh +3 -0
- package/tests/base-client.test.ts +328 -0
- package/tests/command-client.test.ts +407 -0
- package/tests/file-client.test.ts +643 -0
- package/tests/file-stream.test.ts +306 -0
- package/tests/git-client.test.ts +328 -0
- package/tests/port-client.test.ts +301 -0
- package/tests/process-client.test.ts +658 -0
- package/tests/sandbox.test.ts +465 -0
- package/tests/sse-parser.test.ts +290 -0
- package/tests/utility-client.test.ts +266 -0
- package/tests/wrangler.jsonc +35 -0
- package/tsconfig.json +9 -1
- package/vitest.config.ts +31 -0
- package/container_src/bun.lock +0 -76
- package/container_src/circuit-breaker.ts +0 -121
- package/container_src/control-process.ts +0 -784
- package/container_src/handler/exec.ts +0 -185
- package/container_src/handler/file.ts +0 -457
- package/container_src/handler/git.ts +0 -130
- package/container_src/handler/ports.ts +0 -314
- package/container_src/handler/process.ts +0 -568
- package/container_src/handler/session.ts +0 -92
- package/container_src/index.ts +0 -601
- package/container_src/interpreter-service.ts +0 -276
- package/container_src/isolation.ts +0 -1213
- package/container_src/mime-processor.ts +0 -255
- package/container_src/package.json +0 -18
- package/container_src/runtime/executors/javascript/node_executor.ts +0 -123
- package/container_src/runtime/executors/python/ipython_executor.py +0 -338
- package/container_src/runtime/executors/typescript/ts_executor.ts +0 -138
- package/container_src/runtime/process-pool.ts +0 -464
- package/container_src/shell-escape.ts +0 -42
- package/container_src/startup.sh +0 -11
- package/container_src/types.ts +0 -131
- package/dist/chunk-32UDXUPC.js +0 -671
- package/dist/chunk-32UDXUPC.js.map +0 -1
- package/dist/chunk-5DILEXGY.js +0 -85
- package/dist/chunk-5DILEXGY.js.map +0 -1
- package/dist/chunk-D3U63BZP.js +0 -240
- package/dist/chunk-D3U63BZP.js.map +0 -1
- package/dist/chunk-FXYPFGOZ.js +0 -129
- package/dist/chunk-FXYPFGOZ.js.map +0 -1
- package/dist/chunk-JTKON2SH.js.map +0 -1
- package/dist/chunk-NNGBXDMY.js.map +0 -1
- package/dist/chunk-SQLJNZ3K.js +0 -674
- package/dist/chunk-SQLJNZ3K.js.map +0 -1
- package/dist/chunk-W7TVRPBG.js +0 -108
- package/dist/chunk-W7TVRPBG.js.map +0 -1
- package/dist/client-B3RUab0s.d.ts +0 -225
- package/dist/client.d.ts +0 -4
- package/dist/client.js +0 -7
- package/dist/client.js.map +0 -1
- package/dist/errors.d.ts +0 -95
- package/dist/errors.js +0 -27
- package/dist/errors.js.map +0 -1
- package/dist/interpreter-client.d.ts +0 -4
- package/dist/interpreter-client.js +0 -9
- package/dist/interpreter-client.js.map +0 -1
- package/dist/interpreter-types.d.ts +0 -259
- package/dist/interpreter-types.js +0 -9
- package/dist/interpreter-types.js.map +0 -1
- package/dist/types.d.ts +0 -453
- package/dist/types.js +0 -45
- package/dist/types.js.map +0 -1
- package/src/client.ts +0 -1048
- package/src/errors.ts +0 -219
- package/src/interpreter-types.ts +0 -390
- package/src/types.ts +0 -571
package/README.md
CHANGED
|
@@ -1,859 +1,126 @@
|
|
|
1
|
-
<
|
|
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
|
-
|
|
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
|
-
|
|
119
|
-
export { Sandbox } from "@cloudflare/sandbox";
|
|
5
|
+
[](https://www.npmjs.com/package/@cloudflare/sandbox)
|
|
120
6
|
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15
|
+
## Getting Started
|
|
137
16
|
|
|
138
|
-
|
|
17
|
+
### Prerequisites
|
|
139
18
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
23
|
+
### 1. Create a new project
|
|
153
24
|
|
|
154
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
258
|
-
|
|
259
|
-
Set environment variables dynamically in the sandbox.
|
|
32
|
+
### 2. Test locally
|
|
260
33
|
|
|
261
|
-
|
|
262
|
-
for that instance.
|
|
34
|
+
Start the development server:
|
|
263
35
|
|
|
264
|
-
```
|
|
265
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
+
Test the endpoints:
|
|
316
43
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
328
|
-
|
|
48
|
+
# File operations
|
|
49
|
+
curl http://localhost:8787/file
|
|
329
50
|
```
|
|
330
51
|
|
|
331
|
-
|
|
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
|
-
|
|
54
|
+
Deploy your Worker and container:
|
|
339
55
|
|
|
340
|
-
```
|
|
341
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
62
|
+
**📖 [View the complete getting started guide](https://developers.cloudflare.com/sandbox/get-started/)** for detailed instructions and explanations.
|
|
376
63
|
|
|
377
|
-
|
|
64
|
+
## Quick API Example
|
|
378
65
|
|
|
379
66
|
```typescript
|
|
380
|
-
|
|
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
|
-
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
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
|
-
|
|
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
|
-
|
|
831
|
-
|
|
832
|
-
<h2 id="debugging">🔍 Debugging</h2>
|
|
102
|
+
## Documentation
|
|
833
103
|
|
|
834
|
-
|
|
104
|
+
**📖 [Full Documentation](https://developers.cloudflare.com/sandbox/)**
|
|
835
105
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
-
|
|
111
|
+
## Key Features
|
|
846
112
|
|
|
847
|
-
-
|
|
848
|
-
-
|
|
849
|
-
-
|
|
850
|
-
-
|
|
851
|
-
-
|
|
852
|
-
-
|
|
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
|
-
|
|
121
|
+
## Development
|
|
855
122
|
|
|
856
|
-
|
|
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
|
-
#
|
|
139
|
+
# Type checking and linting
|
|
880
140
|
npm run check
|
|
881
141
|
```
|
|
882
142
|
|
|
883
|
-
|
|
143
|
+
## Examples
|
|
884
144
|
|
|
885
|
-
[
|
|
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
|
-
|
|
153
|
+
**Beta** - The SDK is in active development. APIs may change before v1.0.
|
|
888
154
|
|
|
889
|
-
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
[MIT License](LICENSE)
|
|
890
158
|
|
|
891
|
-
|
|
159
|
+
## Links
|
|
892
160
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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)
|