@cloudflare/sandbox 0.0.0-215ab49 → 0.0.0-2450ebd
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/CHANGELOG.md +157 -0
- package/Dockerfile +112 -54
- package/README.md +91 -489
- package/dist/chunk-BFVUNTP4.js +104 -0
- package/dist/chunk-BFVUNTP4.js.map +1 -0
- package/dist/chunk-EKSWCBCA.js +86 -0
- package/dist/chunk-EKSWCBCA.js.map +1 -0
- package/dist/chunk-EXQOIRZI.js +2351 -0
- package/dist/chunk-EXQOIRZI.js.map +1 -0
- package/dist/chunk-JXZMAU2C.js +559 -0
- package/dist/chunk-JXZMAU2C.js.map +1 -0
- package/dist/chunk-Z532A7QC.js +78 -0
- package/dist/chunk-Z532A7QC.js.map +1 -0
- package/dist/file-stream.d.ts +43 -0
- package/dist/file-stream.js +9 -0
- package/dist/file-stream.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/interpreter.d.ts +33 -0
- package/dist/interpreter.js +8 -0
- package/dist/interpreter.js.map +1 -0
- package/dist/request-handler.d.ts +18 -0
- package/dist/request-handler.js +12 -0
- package/dist/request-handler.js.map +1 -0
- package/dist/sandbox-D9K2ypln.d.ts +583 -0
- package/dist/sandbox.d.ts +4 -0
- package/dist/sandbox.js +12 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/security.d.ts +31 -0
- package/dist/security.js +13 -0
- package/dist/security.js.map +1 -0
- package/dist/sse-parser.d.ts +28 -0
- package/dist/sse-parser.js +11 -0
- package/dist/sse-parser.js.map +1 -0
- package/package.json +13 -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/clients/interpreter-client.ts +329 -0
- 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 +164 -0
- package/src/index.ts +85 -12
- package/src/interpreter.ts +159 -0
- package/src/request-handler.ts +69 -43
- package/src/sandbox.ts +558 -292
- 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/handler/exec.ts +0 -338
- package/container_src/handler/file.ts +0 -844
- package/container_src/handler/git.ts +0 -182
- package/container_src/handler/ports.ts +0 -314
- package/container_src/handler/process.ts +0 -640
- package/container_src/index.ts +0 -361
- package/container_src/package.json +0 -9
- package/container_src/types.ts +0 -108
- package/src/client.ts +0 -1038
- package/src/types.ts +0 -386
package/README.md
CHANGED
|
@@ -1,532 +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
|
-
- [🌐 Port Forwarding](#port-forwarding)
|
|
21
|
-
- [Utility Methods](#utility-methods)
|
|
22
|
-
- [💡 Examples](#examples)
|
|
23
|
-
- [Run a Node.js App](#run-a-nodejs-app)
|
|
24
|
-
- [Build and Test Code](#build-and-test-code)
|
|
25
|
-
- [Interactive Development Environment](#interactive-development-environment)
|
|
26
|
-
- [Expose Services with Preview URLs](#expose-services-with-preview-urls)
|
|
27
|
-
- [🏗️ Architecture](#architecture)
|
|
28
|
-
- [🛠️ Advanced Usage](#advanced-usage)
|
|
29
|
-
- [AsyncIterable Streaming Support](#asynciterable-streaming-support)
|
|
30
|
-
- [Session Management](#session-management)
|
|
31
|
-
- [🔍 Debugging](#debugging)
|
|
32
|
-
- [🚧 Known Limitations](#known-limitations)
|
|
33
|
-
- [🤝 Contributing](#contributing)
|
|
34
|
-
- [📄 License](#license)
|
|
35
|
-
- [🙌 Acknowledgments](#acknowledgments)
|
|
36
|
-
|
|
37
|
-
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
38
|
-
|
|
39
|
-
<h2 id="overview">✨ Overview</h2>
|
|
40
|
-
|
|
41
|
-
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.
|
|
42
|
-
|
|
43
|
-
<h2 id="features">🎯 Features</h2>
|
|
44
|
-
|
|
45
|
-
- **🔒 Secure Isolation**: Each sandbox runs in its own container with full process isolation
|
|
46
|
-
- **⚡ Edge-Native**: Runs on Cloudflare's global network for low latency worldwide
|
|
47
|
-
- **📁 File System Access**: Read, write, and manage files within the sandbox
|
|
48
|
-
- **🔧 Command Execution**: Run any command or process inside the container
|
|
49
|
-
- **🌐 Preview URLs**: Expose services running in your sandbox via public URLs
|
|
50
|
-
- **🔄 Git Integration**: Clone repositories directly into sandboxes
|
|
51
|
-
- **🚀 Streaming Support**: Real-time output streaming for long-running commands
|
|
52
|
-
- **🎮 Session Management**: Maintain state across multiple operations
|
|
53
|
-
|
|
54
|
-
<h2 id="quick-start">🚀 Quick Start</h2>
|
|
55
|
-
|
|
56
|
-
### Installation
|
|
1
|
+
<img width="1362" height="450" alt="Image" src="https://github.com/user-attachments/assets/6f770ae3-0a14-4d2b-9aed-a304ee5446c5" />
|
|
57
2
|
|
|
58
|
-
|
|
59
|
-
npm install @cloudflare/sandbox
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Basic Setup
|
|
63
|
-
|
|
64
|
-
1. **Create a Dockerfile** (temporary requirement, will be removed in future releases):
|
|
65
|
-
|
|
66
|
-
```dockerfile
|
|
67
|
-
FROM docker.io/cloudflare/sandbox:0.1.3
|
|
68
|
-
|
|
69
|
-
EXPOSE 3000
|
|
70
|
-
|
|
71
|
-
# Run the same command as the original image
|
|
72
|
-
CMD ["bun", "index.ts"]
|
|
73
|
-
```
|
|
3
|
+
# Cloudflare Sandbox SDK
|
|
74
4
|
|
|
75
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@cloudflare/sandbox)
|
|
76
6
|
|
|
77
|
-
|
|
7
|
+
**Build secure, isolated code execution environments on Cloudflare.**
|
|
78
8
|
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
// ...
|
|
82
|
-
"containers": [
|
|
83
|
-
{
|
|
84
|
-
"class_name": "Sandbox",
|
|
85
|
-
"image": "./Dockerfile",
|
|
86
|
-
"max_instances": 1
|
|
87
|
-
}
|
|
88
|
-
],
|
|
89
|
-
"durable_objects": {
|
|
90
|
-
"bindings": [
|
|
91
|
-
{
|
|
92
|
-
"class_name": "Sandbox",
|
|
93
|
-
"name": "Sandbox"
|
|
94
|
-
}
|
|
95
|
-
]
|
|
96
|
-
},
|
|
97
|
-
"migrations": [
|
|
98
|
-
{
|
|
99
|
-
"new_sqlite_classes": ["Sandbox"],
|
|
100
|
-
"tag": "v1"
|
|
101
|
-
}
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
3. **Create your Worker**:
|
|
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.
|
|
107
10
|
|
|
108
|
-
|
|
109
|
-
import { getSandbox } from "@cloudflare/sandbox";
|
|
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.
|
|
110
12
|
|
|
111
|
-
|
|
112
|
-
export { Sandbox } from "@cloudflare/sandbox";
|
|
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.
|
|
113
14
|
|
|
114
|
-
|
|
115
|
-
async fetch(request: Request, env: Env) {
|
|
116
|
-
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
|
|
15
|
+
## Getting Started
|
|
117
16
|
|
|
118
|
-
|
|
119
|
-
const result = await sandbox.exec("echo 'Hello from the edge!'");
|
|
120
|
-
return new Response(result.stdout);
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
```
|
|
17
|
+
### Prerequisites
|
|
124
18
|
|
|
125
|
-
|
|
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)
|
|
126
22
|
|
|
127
|
-
###
|
|
23
|
+
### 1. Create a new project
|
|
128
24
|
|
|
129
|
-
|
|
25
|
+
Create a new Sandbox SDK project using the minimal template:
|
|
130
26
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// Simple execution
|
|
135
|
-
const result = await sandbox.exec("npm install express");
|
|
136
|
-
console.log(result.stdout, result.exitCode);
|
|
137
|
-
|
|
138
|
-
// With streaming callbacks
|
|
139
|
-
const result = await sandbox.exec("npm run build", {
|
|
140
|
-
stream: true,
|
|
141
|
-
onOutput: (stream, data) => console.log(`[${stream}] ${data}`)
|
|
142
|
-
});
|
|
27
|
+
```bash
|
|
28
|
+
npm create cloudflare@latest -- my-sandbox --template=cloudflare/sandbox-sdk/examples/minimal
|
|
29
|
+
cd my-sandbox
|
|
143
30
|
```
|
|
144
31
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { parseSSEStream, type ExecEvent } from '@cloudflare/sandbox';
|
|
149
|
-
|
|
150
|
-
const stream = await sandbox.execStream("npm run test");
|
|
151
|
-
for await (const event of parseSSEStream<ExecEvent>(stream)) {
|
|
152
|
-
switch (event.type) {
|
|
153
|
-
case 'stdout':
|
|
154
|
-
console.log(`Test output: ${event.data}`);
|
|
155
|
-
break;
|
|
156
|
-
case 'complete':
|
|
157
|
-
console.log(`Tests ${event.exitCode === 0 ? 'passed' : 'failed'}`);
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
```
|
|
32
|
+
### 2. Test locally
|
|
162
33
|
|
|
163
|
-
|
|
34
|
+
Start the development server:
|
|
164
35
|
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
console.log(`Started process ${process.id} with PID ${process.pid}`);
|
|
168
|
-
|
|
169
|
-
// Monitor the process
|
|
170
|
-
const logStream = await sandbox.streamProcessLogs(process.id);
|
|
171
|
-
for await (const log of parseSSEStream<LogEvent>(logStream)) {
|
|
172
|
-
console.log(`Server: ${log.data}`);
|
|
173
|
-
}
|
|
36
|
+
```bash
|
|
37
|
+
npm run dev
|
|
174
38
|
```
|
|
175
39
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Write content to a file.
|
|
40
|
+
> **Note:** First run builds the Docker container (2-3 minutes). Subsequent runs are much faster.
|
|
179
41
|
|
|
180
|
-
|
|
181
|
-
await sandbox.writeFile("/app.js", "console.log('Hello!');");
|
|
182
|
-
```
|
|
42
|
+
Test the endpoints:
|
|
183
43
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
44
|
+
```bash
|
|
45
|
+
# Execute Python code
|
|
46
|
+
curl http://localhost:8787/run
|
|
187
47
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
console.log(file.content);
|
|
48
|
+
# File operations
|
|
49
|
+
curl http://localhost:8787/file
|
|
191
50
|
```
|
|
192
51
|
|
|
193
|
-
|
|
52
|
+
### 3. Deploy to production
|
|
194
53
|
|
|
195
|
-
|
|
54
|
+
Deploy your Worker and container:
|
|
196
55
|
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
branch: "main",
|
|
200
|
-
targetDir: "my-project",
|
|
201
|
-
});
|
|
56
|
+
```bash
|
|
57
|
+
npx wrangler deploy
|
|
202
58
|
```
|
|
203
59
|
|
|
204
|
-
|
|
60
|
+
> **Wait for provisioning:** After first deployment, wait 2-3 minutes before making requests.
|
|
205
61
|
|
|
206
|
-
|
|
62
|
+
**📖 [View the complete getting started guide](https://developers.cloudflare.com/sandbox/get-started/)** for detailed instructions and explanations.
|
|
207
63
|
|
|
208
|
-
|
|
209
|
-
for that instance.
|
|
64
|
+
## Quick API Example
|
|
210
65
|
|
|
211
66
|
```typescript
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
// Set environment variables FIRST, before any other operations
|
|
215
|
-
await sandbox.setEnvVars({
|
|
216
|
-
NODE_ENV: "production",
|
|
217
|
-
API_KEY: "your-api-key",
|
|
218
|
-
DATABASE_URL: "postgresql://localhost:5432/mydb"
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// Now you can run commands - environment variables are available
|
|
222
|
-
const result = await sandbox.exec("echo $NODE_ENV");
|
|
223
|
-
console.log(result.stdout); // "production"
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
#### Process Management
|
|
227
|
-
|
|
228
|
-
- `listProcesses()` - List all running processes
|
|
229
|
-
- `getProcess(id)` - Get detailed process status
|
|
230
|
-
- `killProcess(id, signal?)` - Terminate specific processes
|
|
231
|
-
- `killAllProcesses()` - Kill all processes
|
|
232
|
-
- `streamProcessLogs(id, options?)` - Stream logs from running processes
|
|
233
|
-
- `getProcessLogs(id)` - Get accumulated process output
|
|
234
|
-
|
|
235
|
-
#### File System Methods
|
|
236
|
-
|
|
237
|
-
- `writeFile(path, content, options?)` - Write content to a file
|
|
238
|
-
- `readFile(path, options?)` - Read a file from the sandbox
|
|
239
|
-
- `mkdir(path, options?)` - Create a directory
|
|
240
|
-
- `deleteFile(path)` - Delete a file
|
|
241
|
-
- `renameFile(oldPath, newPath)` - Rename a file
|
|
242
|
-
- `moveFile(sourcePath, destinationPath)` - Move a file
|
|
243
|
-
- `gitCheckout(repoUrl, options?)` - Clone git repositories
|
|
244
|
-
|
|
245
|
-
#### Network Methods
|
|
67
|
+
import { getSandbox, proxyToSandbox, type Sandbox } from '@cloudflare/sandbox';
|
|
246
68
|
|
|
247
|
-
|
|
248
|
-
- `unexposePort(port)` - Remove port exposure
|
|
249
|
-
- `getExposedPorts()` - List all exposed ports with their URLs
|
|
69
|
+
export { Sandbox } from '@cloudflare/sandbox';
|
|
250
70
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
import { proxyToSandbox, getSandbox } from "@cloudflare/sandbox";
|
|
71
|
+
type Env = {
|
|
72
|
+
Sandbox: DurableObjectNamespace<Sandbox>;
|
|
73
|
+
};
|
|
257
74
|
|
|
258
75
|
export default {
|
|
259
|
-
async fetch(request, env) {
|
|
260
|
-
//
|
|
76
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
77
|
+
// Required for preview URLs
|
|
261
78
|
const proxyResponse = await proxyToSandbox(request, env);
|
|
262
79
|
if (proxyResponse) return proxyResponse;
|
|
263
80
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
When you expose a port, the SDK returns a preview URL that automatically routes to your service:
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
const preview = await sandbox.exposePort(3000);
|
|
274
|
-
console.log(preview.url); // https://3000-sandbox-id.your-worker.dev
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
The SDK handles:
|
|
278
|
-
|
|
279
|
-
- Subdomain routing (`3000-sandbox-id.domain.com`) for both production and local development
|
|
280
|
-
- All localhost variants (127.0.0.1, ::1, etc.)
|
|
281
|
-
- Request forwarding with proper headers
|
|
282
|
-
|
|
283
|
-
> **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.
|
|
284
|
-
|
|
285
|
-
```dockerfile
|
|
286
|
-
# In your Dockerfile (only needed for local dev)
|
|
287
|
-
FROM oven/bun:latest
|
|
288
|
-
|
|
289
|
-
# Expose the ports you'll be using
|
|
290
|
-
EXPOSE 3000 # For a web server
|
|
291
|
-
EXPOSE 8080 # For an API server
|
|
292
|
-
EXPOSE 3001 # For any additional services
|
|
293
|
-
|
|
294
|
-
# Your container setup...
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
Without the `EXPOSE` instruction in local development, you'll see this error:
|
|
298
|
-
|
|
299
|
-
```
|
|
300
|
-
connect(): Connection refused: container port not found. Make sure you exposed the port in your container definition.
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
For more details, see the [Cloudflare Containers local development guide](https://developers.cloudflare.com/containers/local-dev/#exposing-ports).
|
|
304
|
-
|
|
305
|
-
### Utility Methods
|
|
81
|
+
const url = new URL(request.url);
|
|
82
|
+
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
|
|
306
83
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
### Run a Node.js App
|
|
313
|
-
|
|
314
|
-
```typescript
|
|
315
|
-
const sandbox = getSandbox(env.Sandbox, "node-app");
|
|
316
|
-
|
|
317
|
-
// Write a simple Express server
|
|
318
|
-
await sandbox.writeFile(
|
|
319
|
-
"/app.js",
|
|
320
|
-
`
|
|
321
|
-
const express = require('express');
|
|
322
|
-
const app = express();
|
|
323
|
-
|
|
324
|
-
app.get('/', (req, res) => {
|
|
325
|
-
res.json({ message: 'Hello from Cloudflare!' });
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
app.listen(3000);
|
|
329
|
-
`
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
// Install dependencies and start the server
|
|
333
|
-
await sandbox.exec("npm init -y");
|
|
334
|
-
await sandbox.exec("npm install express");
|
|
335
|
-
const server = await sandbox.startProcess("node app.js");
|
|
336
|
-
|
|
337
|
-
// Expose it to the internet
|
|
338
|
-
const preview = await sandbox.exposePort(3000);
|
|
339
|
-
console.log(`API available at: ${preview.url}`);
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Build and Test Code
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
const sandbox = getSandbox(env.Sandbox, "test-env");
|
|
346
|
-
|
|
347
|
-
// Clone a repository
|
|
348
|
-
await sandbox.gitCheckout("https://github.com/user/project");
|
|
349
|
-
|
|
350
|
-
// Run tests
|
|
351
|
-
const testResult = await sandbox.exec("npm test");
|
|
352
|
-
|
|
353
|
-
// Build the project
|
|
354
|
-
const buildResult = await sandbox.exec("npm run build");
|
|
355
|
-
|
|
356
|
-
return new Response(
|
|
357
|
-
JSON.stringify({
|
|
358
|
-
tests: testResult.exitCode === 0 ? "passed" : "failed",
|
|
359
|
-
build: buildResult.exitCode === 0 ? "success" : "failed",
|
|
360
|
-
output: testResult.stdout,
|
|
361
|
-
})
|
|
362
|
-
);
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### Interactive Development Environment
|
|
366
|
-
|
|
367
|
-
```typescript
|
|
368
|
-
// Create a development sandbox with hot reload
|
|
369
|
-
const sandbox = getSandbox(env.Sandbox, "dev-env");
|
|
370
|
-
|
|
371
|
-
// Set up the project
|
|
372
|
-
await sandbox.gitCheckout("https://github.com/user/my-app");
|
|
373
|
-
await sandbox.exec("npm install");
|
|
374
|
-
|
|
375
|
-
// Start dev server
|
|
376
|
-
const devServer = await sandbox.startProcess("npm run dev");
|
|
377
|
-
|
|
378
|
-
// Expose the dev server
|
|
379
|
-
const preview = await sandbox.exposePort(3000, { name: "dev-server" });
|
|
380
|
-
|
|
381
|
-
// Make changes and see them live!
|
|
382
|
-
await sandbox.writeFile("/src/App.jsx", updatedCode);
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### Expose Services with Preview URLs
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
// Create and start a web server
|
|
389
|
-
await sandbox.writeFile(
|
|
390
|
-
"/server.js",
|
|
391
|
-
`Bun.serve({
|
|
392
|
-
port: 8080,
|
|
393
|
-
fetch(req) {
|
|
394
|
-
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 });
|
|
395
88
|
}
|
|
396
|
-
});`
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
const server = await sandbox.startProcess("bun run /server.js");
|
|
400
|
-
|
|
401
|
-
// Expose the port - returns a public URL
|
|
402
|
-
const preview = await sandbox.exposePort(8080);
|
|
403
|
-
console.log(`Service available at: ${preview.url}`);
|
|
404
|
-
|
|
405
|
-
// Note: Your Worker needs to handle preview URL routing.
|
|
406
|
-
// See the example in examples/basic/src/index.ts for the routing implementation.
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
<h2 id="architecture">🏗️ Architecture</h2>
|
|
410
|
-
|
|
411
|
-
The SDK leverages Cloudflare's infrastructure:
|
|
412
|
-
|
|
413
|
-
- **Durable Objects**: Manages sandbox lifecycle and state
|
|
414
|
-
- **Containers**: Provides isolated execution environments
|
|
415
|
-
- **Workers**: Handles HTTP routing and API interface
|
|
416
|
-
- **Edge Network**: Enables global distribution and low latency
|
|
417
89
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
```typescript
|
|
425
|
-
import { parseSSEStream, type ExecEvent } from '@cloudflare/sandbox';
|
|
426
|
-
|
|
427
|
-
// Stream command execution
|
|
428
|
-
const stream = await sandbox.execStream('npm run build');
|
|
429
|
-
for await (const event of parseSSEStream<ExecEvent>(stream)) {
|
|
430
|
-
switch (event.type) {
|
|
431
|
-
case 'start':
|
|
432
|
-
console.log(`Build started: ${event.command}`);
|
|
433
|
-
break;
|
|
434
|
-
case 'stdout':
|
|
435
|
-
console.log(`Build: ${event.data}`);
|
|
436
|
-
break;
|
|
437
|
-
case 'complete':
|
|
438
|
-
console.log(`Exit code: ${event.exitCode}`);
|
|
439
|
-
break;
|
|
440
|
-
case 'error':
|
|
441
|
-
console.error(`Error: ${event.error}`);
|
|
442
|
-
break;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
#### Streaming Utilities
|
|
448
|
-
|
|
449
|
-
The SDK exports utilities for working with Server-Sent Event streams:
|
|
450
|
-
|
|
451
|
-
- **`parseSSEStream<T>(stream)`** - Convert ReadableStream to typed AsyncIterable
|
|
452
|
-
- **`responseToAsyncIterable<T>(response)`** - Convert SSE Response to AsyncIterable
|
|
453
|
-
- **`asyncIterableToSSEStream<T>(iterable)`** - Convert AsyncIterable back to SSE stream
|
|
454
|
-
|
|
455
|
-
#### Advanced Streaming Examples
|
|
456
|
-
|
|
457
|
-
**CI/CD Build System:**
|
|
458
|
-
```typescript
|
|
459
|
-
export async function runBuild(env: Env, buildId: string) {
|
|
460
|
-
const sandbox = getSandbox(env.SANDBOX, buildId);
|
|
461
|
-
const stream = await sandbox.execStream('npm run build');
|
|
462
|
-
|
|
463
|
-
for await (const event of parseSSEStream<ExecEvent>(stream)) {
|
|
464
|
-
switch (event.type) {
|
|
465
|
-
case 'start':
|
|
466
|
-
await env.BUILDS.put(buildId, { status: 'running' });
|
|
467
|
-
break;
|
|
468
|
-
case 'complete':
|
|
469
|
-
await env.BUILDS.put(buildId, {
|
|
470
|
-
status: event.exitCode === 0 ? 'success' : 'failed',
|
|
471
|
-
exitCode: event.exitCode
|
|
472
|
-
});
|
|
473
|
-
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 });
|
|
474
95
|
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
```
|
|
478
96
|
|
|
479
|
-
|
|
480
|
-
```typescript
|
|
481
|
-
const monitor = await sandbox.startProcess('tail -f /var/log/system.log');
|
|
482
|
-
const logStream = await sandbox.streamProcessLogs(monitor.id);
|
|
483
|
-
|
|
484
|
-
for await (const log of parseSSEStream<LogEvent>(logStream)) {
|
|
485
|
-
if (log.type === 'stdout' && log.data.includes('ERROR')) {
|
|
486
|
-
await env.ALERTS.send({
|
|
487
|
-
severity: 'high',
|
|
488
|
-
message: log.data,
|
|
489
|
-
timestamp: log.timestamp
|
|
490
|
-
});
|
|
97
|
+
return new Response('Try /run or /file');
|
|
491
98
|
}
|
|
492
|
-
}
|
|
99
|
+
};
|
|
493
100
|
```
|
|
494
101
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
Maintain context across commands:
|
|
498
|
-
|
|
499
|
-
```typescript
|
|
500
|
-
const sessionId = crypto.randomUUID();
|
|
501
|
-
|
|
502
|
-
// Commands in the same session share working directory
|
|
503
|
-
await sandbox.exec("cd /app", { sessionId });
|
|
504
|
-
await sandbox.exec("npm install", { sessionId });
|
|
505
|
-
const app = await sandbox.startProcess("npm start", { sessionId });
|
|
506
|
-
```
|
|
102
|
+
## Documentation
|
|
507
103
|
|
|
508
|
-
|
|
104
|
+
**📖 [Full Documentation](https://developers.cloudflare.com/sandbox/)**
|
|
509
105
|
|
|
510
|
-
|
|
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
|
|
511
110
|
|
|
512
|
-
|
|
513
|
-
const sandbox = getSandbox(env.Sandbox, "debug-sandbox");
|
|
514
|
-
sandbox.client.onCommandStart = (cmd, args) =>
|
|
515
|
-
console.log(`Starting: ${cmd} ${args.join(" ")}`);
|
|
516
|
-
sandbox.client.onOutput = (stream, data) => console.log(`[${stream}] ${data}`);
|
|
517
|
-
sandbox.client.onCommandComplete = (success, code) =>
|
|
518
|
-
console.log(`Completed: ${success} (${code})`);
|
|
519
|
-
```
|
|
111
|
+
## Key Features
|
|
520
112
|
|
|
521
|
-
|
|
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
|
|
522
120
|
|
|
523
|
-
|
|
524
|
-
- WebSocket support for preview URLs coming soon
|
|
525
|
-
- Some system calls may be restricted in the container environment
|
|
121
|
+
## Development
|
|
526
122
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
123
|
+
This repository contains the SDK source code. To contribute:
|
|
530
124
|
|
|
531
125
|
```bash
|
|
532
126
|
# Clone the repo
|
|
@@ -541,22 +135,30 @@ npm test
|
|
|
541
135
|
|
|
542
136
|
# Build the project
|
|
543
137
|
npm run build
|
|
138
|
+
|
|
139
|
+
# Type checking and linting
|
|
140
|
+
npm run check
|
|
544
141
|
```
|
|
545
142
|
|
|
546
|
-
|
|
143
|
+
## Examples
|
|
547
144
|
|
|
548
|
-
[
|
|
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
|
|
549
150
|
|
|
550
|
-
|
|
151
|
+
## Status
|
|
551
152
|
|
|
552
|
-
|
|
153
|
+
**Beta** - The SDK is in active development. APIs may change before v1.0.
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
[MIT License](LICENSE)
|
|
553
158
|
|
|
554
|
-
|
|
159
|
+
## Links
|
|
555
160
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
<a href="https://twitter.com/CloudflareDev">Twitter</a>
|
|
561
|
-
</p>
|
|
562
|
-
</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)
|