@cloudflare/sandbox 0.0.0-fd5ec7f → 0.0.0-feafd32
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 +129 -0
- package/Dockerfile +41 -15
- package/README.md +297 -11
- package/container_src/bun.lock +76 -0
- package/container_src/circuit-breaker.ts +121 -0
- package/container_src/control-process.ts +784 -0
- package/container_src/handler/exec.ts +99 -252
- package/container_src/handler/file.ts +204 -642
- package/container_src/handler/git.ts +28 -80
- package/container_src/handler/process.ts +443 -515
- package/container_src/handler/session.ts +92 -0
- package/container_src/index.ts +354 -123
- package/container_src/interpreter-service.ts +276 -0
- package/container_src/isolation.ts +1049 -0
- package/container_src/mime-processor.ts +255 -0
- package/container_src/package.json +9 -0
- package/container_src/runtime/executors/javascript/node_executor.ts +123 -0
- package/container_src/runtime/executors/python/ipython_executor.py +338 -0
- package/container_src/runtime/executors/typescript/ts_executor.ts +138 -0
- package/container_src/runtime/process-pool.ts +464 -0
- package/container_src/shell-escape.ts +42 -0
- package/container_src/startup.sh +11 -0
- package/container_src/types.ts +35 -12
- package/package.json +2 -2
- package/src/client.ts +204 -233
- package/src/errors.ts +219 -0
- package/src/index.ts +70 -15
- package/src/interpreter-client.ts +352 -0
- package/src/interpreter-types.ts +390 -0
- package/src/interpreter.ts +150 -0
- package/src/sandbox.ts +502 -405
- package/src/types.ts +140 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,134 @@
|
|
|
1
1
|
# @cloudflare/sandbox
|
|
2
2
|
|
|
3
|
+
## 0.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#83](https://github.com/cloudflare/sandbox-sdk/pull/83) [`eec5bb6`](https://github.com/cloudflare/sandbox-sdk/commit/eec5bb6203dd5d775b4b54e91c26de25eeb767ce) Thanks [@mikenomitch](https://github.com/mikenomitch)! - Bump containers package version
|
|
8
|
+
|
|
9
|
+
## 0.3.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#76](https://github.com/cloudflare/sandbox-sdk/pull/76) [`ef9e320`](https://github.com/cloudflare/sandbox-sdk/commit/ef9e320dcef30e57797fef6ebd9a9383fa9720d9) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Replace Jupyter with lightweight interpreters for >90% faster cold starts for `.runCode` calls, while maintaining full code execution capabilities and rich output support.
|
|
14
|
+
|
|
15
|
+
## 0.3.1
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#71](https://github.com/cloudflare/sandbox-sdk/pull/71) [`fb3c9c2`](https://github.com/cloudflare/sandbox-sdk/commit/fb3c9c22242d9d4f157c26f547f1e697ef7875f9) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Bump containers package version
|
|
20
|
+
|
|
21
|
+
- [#70](https://github.com/cloudflare/sandbox-sdk/pull/70) [`e1fa354`](https://github.com/cloudflare/sandbox-sdk/commit/e1fa354ab1bc7b0e89db4901b67028ebf1a93d0a) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix escaped quotes in file write operations
|
|
22
|
+
|
|
23
|
+
- [#68](https://github.com/cloudflare/sandbox-sdk/pull/68) [`69b91d1`](https://github.com/cloudflare/sandbox-sdk/commit/69b91d1a8f6afb63262cc381ea93e94a033ed5e8) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Configurable timeouts via environment variables in isolation.ts
|
|
24
|
+
|
|
25
|
+
- [#66](https://github.com/cloudflare/sandbox-sdk/pull/66) [`eca93b9`](https://github.com/cloudflare/sandbox-sdk/commit/eca93b97e40fa0d3bd9dc27af2cc214ec355b696) Thanks [@peterp](https://github.com/peterp)! - Determine if the port is specified in the URL.
|
|
26
|
+
|
|
27
|
+
## 0.3.0
|
|
28
|
+
|
|
29
|
+
### Minor Changes
|
|
30
|
+
|
|
31
|
+
- [#59](https://github.com/cloudflare/sandbox-sdk/pull/59) [`b6757f7`](https://github.com/cloudflare/sandbox-sdk/commit/b6757f730c34381d5a70d513944bbf9840f598ab) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Add process isolation for sandbox commands
|
|
32
|
+
|
|
33
|
+
Implements PID namespace isolation to protect control plane processes (Jupyter, Bun) from sandboxed code. Commands executed via `exec()` now run in isolated namespaces that cannot see or interact with system processes.
|
|
34
|
+
|
|
35
|
+
**Key security improvements:**
|
|
36
|
+
|
|
37
|
+
- Control plane processes are hidden from sandboxed commands
|
|
38
|
+
- Platform secrets in `/proc/1/environ` are inaccessible
|
|
39
|
+
- Ports 8888 (Jupyter) and 3000 (Bun) are protected from hijacking
|
|
40
|
+
|
|
41
|
+
**Breaking changes:**
|
|
42
|
+
|
|
43
|
+
1. **Removed `sessionId` parameter**: The `sessionId` parameter has been removed from all methods (`exec()`, `execStream()`, `startProcess()`, etc.). Each sandbox now maintains its own persistent session automatically.
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// Before: manual session management
|
|
47
|
+
await sandbox.exec("cd /app", { sessionId: "my-session" });
|
|
48
|
+
|
|
49
|
+
// After: automatic session per sandbox
|
|
50
|
+
await sandbox.exec("cd /app");
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
2. **Commands now maintain state**: Commands within the same sandbox now share state (working directory, environment variables, background processes). Previously each command was stateless.
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
// Before: each exec was independent
|
|
57
|
+
await sandbox.exec("cd /app");
|
|
58
|
+
await sandbox.exec("pwd"); // Output: /workspace
|
|
59
|
+
|
|
60
|
+
// After: state persists in session
|
|
61
|
+
await sandbox.exec("cd /app");
|
|
62
|
+
await sandbox.exec("pwd"); // Output: /app
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Migration guide:**
|
|
66
|
+
|
|
67
|
+
- Remove `sessionId` from all method calls - each sandbox maintains its own session
|
|
68
|
+
- If you need isolated execution contexts within the same sandbox, use `sandbox.createSession()`:
|
|
69
|
+
```javascript
|
|
70
|
+
// Create independent sessions with different environments
|
|
71
|
+
const buildSession = await sandbox.createSession({
|
|
72
|
+
name: "build",
|
|
73
|
+
env: { NODE_ENV: "production" },
|
|
74
|
+
cwd: "/build",
|
|
75
|
+
});
|
|
76
|
+
const testSession = await sandbox.createSession({
|
|
77
|
+
name: "test",
|
|
78
|
+
env: { NODE_ENV: "test" },
|
|
79
|
+
cwd: "/test",
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
- Environment variables set in one command persist to the next
|
|
83
|
+
- Background processes remain active until explicitly killed
|
|
84
|
+
- Requires CAP_SYS_ADMIN (available in production, falls back gracefully in dev)
|
|
85
|
+
|
|
86
|
+
### Patch Changes
|
|
87
|
+
|
|
88
|
+
- [#62](https://github.com/cloudflare/sandbox-sdk/pull/62) [`4bedc3a`](https://github.com/cloudflare/sandbox-sdk/commit/4bedc3aba347f3d4090a6efe2c9778bac00ce74a) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix broken build due to bun lockfile not being used
|
|
89
|
+
|
|
90
|
+
## 0.2.4
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- [#57](https://github.com/cloudflare/sandbox-sdk/pull/57) [`12bbd12`](https://github.com/cloudflare/sandbox-sdk/commit/12bbd1229c07ef8c1c0bf58a4235a27938155b08) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Add listFiles method
|
|
95
|
+
|
|
96
|
+
## 0.2.3
|
|
97
|
+
|
|
98
|
+
### Patch Changes
|
|
99
|
+
|
|
100
|
+
- [#53](https://github.com/cloudflare/sandbox-sdk/pull/53) [`c87db11`](https://github.com/cloudflare/sandbox-sdk/commit/c87db117693a86cfb667bf09fb7720d6a6e0524d) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Improve jupyterlab config to speed up startup
|
|
101
|
+
|
|
102
|
+
## 0.2.2
|
|
103
|
+
|
|
104
|
+
### Patch Changes
|
|
105
|
+
|
|
106
|
+
- [#51](https://github.com/cloudflare/sandbox-sdk/pull/51) [`4aceb32`](https://github.com/cloudflare/sandbox-sdk/commit/4aceb3215c836f59afcb88b2b325016b3f623f46) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Handle intermittent interpreter failures and decouple jupyter startup
|
|
107
|
+
|
|
108
|
+
## 0.2.1
|
|
109
|
+
|
|
110
|
+
### Patch Changes
|
|
111
|
+
|
|
112
|
+
- [#49](https://github.com/cloudflare/sandbox-sdk/pull/49) [`d81d2a5`](https://github.com/cloudflare/sandbox-sdk/commit/d81d2a563c9af8947d5444019ed4d6156db563e3) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Implement code interpreter API
|
|
113
|
+
|
|
114
|
+
## 0.2.0
|
|
115
|
+
|
|
116
|
+
### Minor Changes
|
|
117
|
+
|
|
118
|
+
- [#47](https://github.com/cloudflare/sandbox-sdk/pull/47) [`8a93d0c`](https://github.com/cloudflare/sandbox-sdk/commit/8a93d0cae18a25bda6506b8b0a08d9e9eb3bb290) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Change default directory to a clean /workspace
|
|
119
|
+
|
|
120
|
+
## 0.1.4
|
|
121
|
+
|
|
122
|
+
### Patch Changes
|
|
123
|
+
|
|
124
|
+
- [#46](https://github.com/cloudflare/sandbox-sdk/pull/46) [`7de28be`](https://github.com/cloudflare/sandbox-sdk/commit/7de28be482d9634551572d548c7c4b5842df812d) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Update README
|
|
125
|
+
|
|
126
|
+
- [#44](https://github.com/cloudflare/sandbox-sdk/pull/44) [`215ab49`](https://github.com/cloudflare/sandbox-sdk/commit/215ab494427d7e2a92bb9a25384cb493a221c200) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Update example to use env & cwd
|
|
127
|
+
|
|
128
|
+
- [#42](https://github.com/cloudflare/sandbox-sdk/pull/42) [`bb72193`](https://github.com/cloudflare/sandbox-sdk/commit/bb72193ad75695979bd1132206f481e91fe37325) Thanks [@jonasnobile](https://github.com/jonasnobile)! - Propagate `cwd` and `env` options in `executeCommand`
|
|
129
|
+
|
|
130
|
+
- [#27](https://github.com/cloudflare/sandbox-sdk/pull/27) [`fd5ec7f`](https://github.com/cloudflare/sandbox-sdk/commit/fd5ec7f34bc12b06320a89356c4af07801f52d64) Thanks [@threepointone](https://github.com/threepointone)! - remove yarn and pnpm from the image
|
|
131
|
+
|
|
3
132
|
## 0.1.3
|
|
4
133
|
|
|
5
134
|
### Patch Changes
|
package/Dockerfile
CHANGED
|
@@ -31,23 +31,19 @@ RUN apt-get update && apt-get install -y \
|
|
|
31
31
|
python3.11 \
|
|
32
32
|
python3.11-dev \
|
|
33
33
|
python3-pip \
|
|
34
|
+
python3.11-venv \
|
|
34
35
|
# Other useful tools
|
|
35
|
-
sudo \
|
|
36
36
|
ca-certificates \
|
|
37
37
|
gnupg \
|
|
38
38
|
lsb-release \
|
|
39
|
+
strace \
|
|
39
40
|
&& rm -rf /var/lib/apt/lists/*
|
|
40
41
|
|
|
41
42
|
# Set Python 3.11 as default python3
|
|
42
43
|
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1
|
|
43
44
|
|
|
44
|
-
# Install Node.js
|
|
45
|
-
|
|
46
|
-
RUN apt-get update && apt-get install -y ca-certificates curl gnupg \
|
|
47
|
-
&& mkdir -p /etc/apt/keyrings \
|
|
48
|
-
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
|
|
49
|
-
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
|
|
50
|
-
&& apt-get update \
|
|
45
|
+
# Install Node.js 20 LTS using official NodeSource setup script
|
|
46
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
|
51
47
|
&& apt-get install -y nodejs \
|
|
52
48
|
&& rm -rf /var/lib/apt/lists/*
|
|
53
49
|
|
|
@@ -55,22 +51,52 @@ RUN apt-get update && apt-get install -y ca-certificates curl gnupg \
|
|
|
55
51
|
COPY --from=bun-source /usr/local/bin/bun /usr/local/bin/bun
|
|
56
52
|
COPY --from=bun-source /usr/local/bin/bunx /usr/local/bin/bunx
|
|
57
53
|
|
|
54
|
+
# Install essential Python packages for code execution
|
|
55
|
+
RUN pip3 install --no-cache-dir \
|
|
56
|
+
matplotlib \
|
|
57
|
+
numpy \
|
|
58
|
+
pandas \
|
|
59
|
+
ipython
|
|
58
60
|
|
|
59
|
-
# Set up
|
|
60
|
-
WORKDIR /
|
|
61
|
+
# Set up container server directory
|
|
62
|
+
WORKDIR /container-server
|
|
61
63
|
|
|
62
64
|
# Verify installations
|
|
63
65
|
RUN python3 --version && \
|
|
64
66
|
node --version && \
|
|
65
67
|
npm --version && \
|
|
66
68
|
bun --version
|
|
67
|
-
|
|
68
69
|
|
|
69
|
-
# Copy container source files
|
|
70
|
+
# Copy container source files to server directory
|
|
71
|
+
COPY container_src/package.json container_src/bun.lock ./
|
|
72
|
+
RUN bun install --frozen-lockfile
|
|
73
|
+
|
|
70
74
|
COPY container_src/ ./
|
|
71
75
|
|
|
72
|
-
#
|
|
76
|
+
# Compile TypeScript files using the locally installed TypeScript
|
|
77
|
+
RUN npx tsc control-process.ts --outDir . --module commonjs --target es2020 --esModuleInterop --skipLibCheck
|
|
78
|
+
RUN cd runtime/executors/javascript && npx tsc node_executor.ts --module commonjs --target es2020 --esModuleInterop --skipLibCheck
|
|
79
|
+
RUN cd runtime/executors/typescript && npx tsc ts_executor.ts --module commonjs --target es2020 --esModuleInterop --skipLibCheck
|
|
80
|
+
|
|
81
|
+
# Configure process pool sizes (can be overridden at runtime)
|
|
82
|
+
ENV PYTHON_POOL_MIN_SIZE=3
|
|
83
|
+
ENV PYTHON_POOL_MAX_SIZE=15
|
|
84
|
+
ENV JAVASCRIPT_POOL_MIN_SIZE=3
|
|
85
|
+
ENV JAVASCRIPT_POOL_MAX_SIZE=10
|
|
86
|
+
ENV TYPESCRIPT_POOL_MIN_SIZE=3
|
|
87
|
+
ENV TYPESCRIPT_POOL_MAX_SIZE=10
|
|
88
|
+
|
|
89
|
+
# Create clean workspace directory for user code
|
|
90
|
+
# Architecture:
|
|
91
|
+
# /container-server/ - SDK infrastructure (server, executors, dependencies)
|
|
92
|
+
# /workspace/ - User's clean workspace for their code
|
|
93
|
+
RUN mkdir -p /workspace
|
|
94
|
+
|
|
95
|
+
# Expose the application port (3000 for control)
|
|
73
96
|
EXPOSE 3000
|
|
74
97
|
|
|
75
|
-
#
|
|
76
|
-
|
|
98
|
+
# Make startup script executable
|
|
99
|
+
RUN chmod +x startup.sh
|
|
100
|
+
|
|
101
|
+
# Use startup script
|
|
102
|
+
CMD ["./startup.sh"]
|
package/README.md
CHANGED
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
- [Basic Setup](#basic-setup)
|
|
18
18
|
- [📚 API Reference](#api-reference)
|
|
19
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)
|
|
20
24
|
- [🌐 Port Forwarding](#port-forwarding)
|
|
21
25
|
- [Utility Methods](#utility-methods)
|
|
22
26
|
- [💡 Examples](#examples)
|
|
@@ -24,6 +28,7 @@
|
|
|
24
28
|
- [Build and Test Code](#build-and-test-code)
|
|
25
29
|
- [Interactive Development Environment](#interactive-development-environment)
|
|
26
30
|
- [Expose Services with Preview URLs](#expose-services-with-preview-urls)
|
|
31
|
+
- [Data Analysis with Code Interpreter](#data-analysis-with-code-interpreter)
|
|
27
32
|
- [🏗️ Architecture](#architecture)
|
|
28
33
|
- [🛠️ Advanced Usage](#advanced-usage)
|
|
29
34
|
- [AsyncIterable Streaming Support](#asynciterable-streaming-support)
|
|
@@ -50,6 +55,9 @@ The Cloudflare Sandbox SDK enables you to run isolated code environments directl
|
|
|
50
55
|
- **🔄 Git Integration**: Clone repositories directly into sandboxes
|
|
51
56
|
- **🚀 Streaming Support**: Real-time output streaming for long-running commands
|
|
52
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
|
|
53
61
|
|
|
54
62
|
<h2 id="quick-start">🚀 Quick Start</h2>
|
|
55
63
|
|
|
@@ -64,7 +72,7 @@ npm install @cloudflare/sandbox
|
|
|
64
72
|
1. **Create a Dockerfile** (temporary requirement, will be removed in future releases):
|
|
65
73
|
|
|
66
74
|
```dockerfile
|
|
67
|
-
FROM docker.io/cloudflare/sandbox:0.
|
|
75
|
+
FROM docker.io/cloudflare/sandbox:0.3.3
|
|
68
76
|
|
|
69
77
|
# Expose the ports you want to expose
|
|
70
78
|
EXPOSE 3000
|
|
@@ -81,7 +89,7 @@ EXPOSE 3000
|
|
|
81
89
|
{
|
|
82
90
|
"class_name": "Sandbox",
|
|
83
91
|
"image": "./Dockerfile",
|
|
84
|
-
"max_instances":
|
|
92
|
+
"max_instances": 20
|
|
85
93
|
}
|
|
86
94
|
],
|
|
87
95
|
"durable_objects": {
|
|
@@ -176,7 +184,7 @@ for await (const log of parseSSEStream<LogEvent>(logStream)) {
|
|
|
176
184
|
Write content to a file.
|
|
177
185
|
|
|
178
186
|
```typescript
|
|
179
|
-
await sandbox.writeFile("/app.js", "console.log('Hello!');");
|
|
187
|
+
await sandbox.writeFile("/workspace/app.js", "console.log('Hello!');");
|
|
180
188
|
```
|
|
181
189
|
|
|
182
190
|
#### `readFile(path, options?)`
|
|
@@ -246,6 +254,131 @@ console.log(result.stdout); // "production"
|
|
|
246
254
|
- `unexposePort(port)` - Remove port exposure
|
|
247
255
|
- `getExposedPorts()` - List all exposed ports with their URLs
|
|
248
256
|
|
|
257
|
+
#### Session Methods
|
|
258
|
+
|
|
259
|
+
- `createSession(options)` - Create an isolated execution session
|
|
260
|
+
- `name`: Session identifier
|
|
261
|
+
- `env`: Environment variables for this session
|
|
262
|
+
- `cwd`: Working directory
|
|
263
|
+
- `isolation`: Enable PID namespace isolation (requires CAP_SYS_ADMIN)
|
|
264
|
+
|
|
265
|
+
<h2 id="code-interpreter">🧪 Code Interpreter</h2>
|
|
266
|
+
|
|
267
|
+
The Sandbox SDK includes powerful code interpreter capabilities, allowing you to execute Python and JavaScript code with rich outputs including charts, tables, and formatted data.
|
|
268
|
+
|
|
269
|
+
### Code Execution
|
|
270
|
+
|
|
271
|
+
#### `createCodeContext(options?)`
|
|
272
|
+
|
|
273
|
+
Creates a new code execution context with persistent state.
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// Create a Python context
|
|
277
|
+
const pythonCtx = await sandbox.createCodeContext({ language: 'python' });
|
|
278
|
+
|
|
279
|
+
// Create a JavaScript context
|
|
280
|
+
const jsCtx = await sandbox.createCodeContext({ language: 'javascript' });
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Options:**
|
|
284
|
+
- `language`: Programming language (`'python'` | `'javascript'` | `'typescript'`)
|
|
285
|
+
- `cwd`: Working directory (default: `/workspace`)
|
|
286
|
+
- `envVars`: Environment variables for the context
|
|
287
|
+
|
|
288
|
+
#### `runCode(code, options?)`
|
|
289
|
+
|
|
290
|
+
Executes code with optional streaming callbacks.
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// Simple execution
|
|
294
|
+
const execution = await sandbox.runCode('print("Hello World")', {
|
|
295
|
+
context: pythonCtx
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// With streaming callbacks
|
|
299
|
+
await sandbox.runCode(`
|
|
300
|
+
for i in range(5):
|
|
301
|
+
print(f"Step {i}")
|
|
302
|
+
time.sleep(1)
|
|
303
|
+
`, {
|
|
304
|
+
context: pythonCtx,
|
|
305
|
+
onStdout: (output) => console.log('Real-time:', output.text),
|
|
306
|
+
onResult: (result) => console.log('Result:', result)
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Options:**
|
|
311
|
+
- `context`: Context to run the code in
|
|
312
|
+
- `language`: Language if no context provided
|
|
313
|
+
- `onStdout`: Callback for stdout output
|
|
314
|
+
- `onStderr`: Callback for stderr output
|
|
315
|
+
- `onResult`: Callback for execution results
|
|
316
|
+
- `onError`: Callback for errors
|
|
317
|
+
|
|
318
|
+
#### `runCodeStream(code, options?)`
|
|
319
|
+
|
|
320
|
+
Returns a streaming response for real-time processing.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
const stream = await sandbox.runCodeStream('import time; [print(i) for i in range(10)]');
|
|
324
|
+
// Process the stream as needed
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Rich Outputs
|
|
328
|
+
|
|
329
|
+
The code interpreter automatically detects and processes various output types:
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
// Data visualization
|
|
333
|
+
const execution = await sandbox.runCode(`
|
|
334
|
+
import matplotlib.pyplot as plt
|
|
335
|
+
import numpy as np
|
|
336
|
+
|
|
337
|
+
x = np.linspace(0, 10, 100)
|
|
338
|
+
y = np.sin(x)
|
|
339
|
+
plt.plot(x, y)
|
|
340
|
+
plt.title('Sine Wave')
|
|
341
|
+
plt.show()
|
|
342
|
+
`, {
|
|
343
|
+
context: pythonCtx,
|
|
344
|
+
onResult: (result) => {
|
|
345
|
+
if (result.png) {
|
|
346
|
+
// Base64 encoded PNG image
|
|
347
|
+
console.log('Chart generated!');
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// HTML tables with pandas
|
|
353
|
+
const tableExecution = await sandbox.runCode(`
|
|
354
|
+
import pandas as pd
|
|
355
|
+
df = pd.DataFrame({
|
|
356
|
+
'name': ['Alice', 'Bob', 'Charlie'],
|
|
357
|
+
'score': [92, 88, 95]
|
|
358
|
+
})
|
|
359
|
+
df
|
|
360
|
+
`, { context: pythonCtx });
|
|
361
|
+
|
|
362
|
+
// Access HTML table in execution.results[0].html
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Output Formats
|
|
366
|
+
|
|
367
|
+
Results can include multiple formats:
|
|
368
|
+
- `text`: Plain text representation
|
|
369
|
+
- `html`: HTML (often pandas DataFrames)
|
|
370
|
+
- `png`/`jpeg`: Base64 encoded images
|
|
371
|
+
- `svg`: Vector graphics
|
|
372
|
+
- `json`: Structured data
|
|
373
|
+
- `chart`: Parsed chart information
|
|
374
|
+
|
|
375
|
+
Check available formats with `result.formats()`.
|
|
376
|
+
|
|
377
|
+
#### Additional Code Interpreter Methods
|
|
378
|
+
|
|
379
|
+
- `listCodeContexts()` - List all active code contexts
|
|
380
|
+
- `deleteCodeContext(contextId)` - Delete a specific context
|
|
381
|
+
|
|
249
382
|
<h2 id="port-forwarding">🌐 Port Forwarding</h2>
|
|
250
383
|
|
|
251
384
|
The SDK automatically handles preview URL routing for exposed ports. Just add one line to your worker:
|
|
@@ -314,7 +447,7 @@ const sandbox = getSandbox(env.Sandbox, "node-app");
|
|
|
314
447
|
|
|
315
448
|
// Write a simple Express server
|
|
316
449
|
await sandbox.writeFile(
|
|
317
|
-
"/app.js",
|
|
450
|
+
"/workspace/app.js",
|
|
318
451
|
`
|
|
319
452
|
const express = require('express');
|
|
320
453
|
const app = express();
|
|
@@ -404,14 +537,100 @@ console.log(`Service available at: ${preview.url}`);
|
|
|
404
537
|
// See the example in examples/basic/src/index.ts for the routing implementation.
|
|
405
538
|
```
|
|
406
539
|
|
|
540
|
+
### Data Analysis with Code Interpreter
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
const sandbox = getSandbox(env.Sandbox, "analysis");
|
|
544
|
+
|
|
545
|
+
// Create a Python context for data analysis
|
|
546
|
+
const pythonCtx = await sandbox.createCodeContext({ language: 'python' });
|
|
547
|
+
|
|
548
|
+
// Load and analyze data
|
|
549
|
+
const analysis = await sandbox.runCode(`
|
|
550
|
+
import pandas as pd
|
|
551
|
+
import matplotlib.pyplot as plt
|
|
552
|
+
|
|
553
|
+
# Create sample data
|
|
554
|
+
data = {
|
|
555
|
+
'Month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
|
|
556
|
+
'Sales': [10000, 12000, 15000, 14000, 18000],
|
|
557
|
+
'Profit': [2000, 2500, 3200, 2800, 4000]
|
|
558
|
+
}
|
|
559
|
+
df = pd.DataFrame(data)
|
|
560
|
+
|
|
561
|
+
# Display summary statistics
|
|
562
|
+
print("Sales Summary:")
|
|
563
|
+
print(df.describe())
|
|
564
|
+
|
|
565
|
+
# Create visualization
|
|
566
|
+
plt.figure(figsize=(10, 6))
|
|
567
|
+
plt.subplot(1, 2, 1)
|
|
568
|
+
plt.bar(df['Month'], df['Sales'])
|
|
569
|
+
plt.title('Monthly Sales')
|
|
570
|
+
plt.xlabel('Month')
|
|
571
|
+
plt.ylabel('Sales ($)')
|
|
572
|
+
|
|
573
|
+
plt.subplot(1, 2, 2)
|
|
574
|
+
plt.plot(df['Month'], df['Profit'], marker='o', color='green')
|
|
575
|
+
plt.title('Monthly Profit')
|
|
576
|
+
plt.xlabel('Month')
|
|
577
|
+
plt.ylabel('Profit ($)')
|
|
578
|
+
|
|
579
|
+
plt.tight_layout()
|
|
580
|
+
plt.show()
|
|
581
|
+
|
|
582
|
+
# Return the data as JSON
|
|
583
|
+
df.to_dict('records')
|
|
584
|
+
`, {
|
|
585
|
+
context: pythonCtx,
|
|
586
|
+
onResult: (result) => {
|
|
587
|
+
if (result.png) {
|
|
588
|
+
// Handle the chart image
|
|
589
|
+
console.log('Chart generated:', result.png.substring(0, 50) + '...');
|
|
590
|
+
}
|
|
591
|
+
if (result.json) {
|
|
592
|
+
// Handle the structured data
|
|
593
|
+
console.log('Data:', result.json);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// Multi-language workflow: Process in Python, analyze in JavaScript
|
|
599
|
+
await sandbox.runCode(`
|
|
600
|
+
# Save processed data
|
|
601
|
+
df.to_json('/tmp/sales_data.json', orient='records')
|
|
602
|
+
`, { context: pythonCtx });
|
|
603
|
+
|
|
604
|
+
const jsCtx = await sandbox.createCodeContext({ language: 'javascript' });
|
|
605
|
+
const jsAnalysis = await sandbox.runCode(`
|
|
606
|
+
const fs = require('fs');
|
|
607
|
+
const data = JSON.parse(fs.readFileSync('/tmp/sales_data.json', 'utf8'));
|
|
608
|
+
|
|
609
|
+
// Calculate growth rate
|
|
610
|
+
const growth = data.map((curr, idx) => {
|
|
611
|
+
if (idx === 0) return { ...curr, growth: 0 };
|
|
612
|
+
const prev = data[idx - 1];
|
|
613
|
+
return {
|
|
614
|
+
...curr,
|
|
615
|
+
growth: ((curr.Sales - prev.Sales) / prev.Sales * 100).toFixed(2) + '%'
|
|
616
|
+
};
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
console.log('Growth Analysis:', growth);
|
|
620
|
+
growth;
|
|
621
|
+
`, { context: jsCtx });
|
|
622
|
+
```
|
|
623
|
+
|
|
407
624
|
<h2 id="architecture">🏗️ Architecture</h2>
|
|
408
625
|
|
|
409
626
|
The SDK leverages Cloudflare's infrastructure:
|
|
410
627
|
|
|
411
628
|
- **Durable Objects**: Manages sandbox lifecycle and state
|
|
412
|
-
- **Containers**: Provides isolated execution environments
|
|
629
|
+
- **Containers**: Provides isolated execution environments with Jupyter kernels
|
|
413
630
|
- **Workers**: Handles HTTP routing and API interface
|
|
414
631
|
- **Edge Network**: Enables global distribution and low latency
|
|
632
|
+
- **Jupyter Integration**: Python (IPython) and JavaScript (TSLab) kernels for code execution
|
|
633
|
+
- **MIME Processing**: Automatic detection and handling of rich output formats
|
|
415
634
|
|
|
416
635
|
<h2 id="advanced-usage">🛠️ Advanced Usage</h2>
|
|
417
636
|
|
|
@@ -492,17 +711,71 @@ for await (const log of parseSSEStream<LogEvent>(logStream)) {
|
|
|
492
711
|
|
|
493
712
|
### Session Management
|
|
494
713
|
|
|
495
|
-
|
|
714
|
+
The SDK provides two approaches for managing execution context:
|
|
715
|
+
|
|
716
|
+
#### Implicit Sessions (Recommended)
|
|
717
|
+
|
|
718
|
+
Each sandbox maintains its own persistent session automatically:
|
|
496
719
|
|
|
497
720
|
```typescript
|
|
498
|
-
const
|
|
721
|
+
const sandbox = getSandbox(env.Sandbox, "my-app");
|
|
499
722
|
|
|
500
|
-
//
|
|
501
|
-
await sandbox.exec("cd /app"
|
|
502
|
-
await sandbox.exec("
|
|
503
|
-
|
|
723
|
+
// These commands share state (pwd, env vars, etc.)
|
|
724
|
+
await sandbox.exec("cd /app");
|
|
725
|
+
await sandbox.exec("pwd"); // Output: /app
|
|
726
|
+
await sandbox.exec("export MY_VAR=hello");
|
|
727
|
+
await sandbox.exec("echo $MY_VAR"); // Output: hello
|
|
504
728
|
```
|
|
505
729
|
|
|
730
|
+
#### Explicit Sessions for Advanced Use Cases
|
|
731
|
+
|
|
732
|
+
Create isolated execution contexts within the same sandbox:
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
const sandbox = getSandbox(env.Sandbox, "multi-env");
|
|
736
|
+
|
|
737
|
+
// Create independent sessions with different environments
|
|
738
|
+
const buildSession = await sandbox.createSession({
|
|
739
|
+
name: "build",
|
|
740
|
+
env: { NODE_ENV: "production" },
|
|
741
|
+
cwd: "/build"
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
const testSession = await sandbox.createSession({
|
|
745
|
+
name: "test",
|
|
746
|
+
env: { NODE_ENV: "test" },
|
|
747
|
+
cwd: "/test"
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
// Run commands in parallel with different contexts
|
|
751
|
+
await Promise.all([
|
|
752
|
+
buildSession.exec("npm run build"),
|
|
753
|
+
testSession.exec("npm test")
|
|
754
|
+
]);
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
#### Security with AI Agents
|
|
758
|
+
|
|
759
|
+
When using AI coding agents, separate development from execution:
|
|
760
|
+
|
|
761
|
+
```typescript
|
|
762
|
+
// Phase 1: AI agent writes code (with API keys)
|
|
763
|
+
const devSession = await sandbox.createSession({
|
|
764
|
+
name: "ai-development",
|
|
765
|
+
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }
|
|
766
|
+
});
|
|
767
|
+
await devSession.exec('opencode "build a web server"');
|
|
768
|
+
|
|
769
|
+
// Phase 2: Run the generated code (without API keys)
|
|
770
|
+
const appSession = await sandbox.createSession({
|
|
771
|
+
name: "app-runtime",
|
|
772
|
+
env: { PORT: "3000" } // Only app-specific vars
|
|
773
|
+
});
|
|
774
|
+
await appSession.exec("node server.js");
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
> **Best Practice**: Keep AI agent credentials separate from your application runtime to prevent accidental exposure of API keys.
|
|
778
|
+
|
|
506
779
|
<h2 id="debugging">🔍 Debugging</h2>
|
|
507
780
|
|
|
508
781
|
Enable verbose logging:
|
|
@@ -521,6 +794,9 @@ sandbox.client.onCommandComplete = (success, code) =>
|
|
|
521
794
|
- Maximum container runtime is limited by Durable Object constraints
|
|
522
795
|
- WebSocket support for preview URLs coming soon
|
|
523
796
|
- Some system calls may be restricted in the container environment
|
|
797
|
+
- Code interpreter has no internet access (sandbox restriction)
|
|
798
|
+
- Some Python/JavaScript packages may not be pre-installed
|
|
799
|
+
- Resource limits apply to code execution (CPU, memory)
|
|
524
800
|
|
|
525
801
|
<h2 id="contributing">🤝 Contributing</h2>
|
|
526
802
|
|
|
@@ -534,11 +810,21 @@ cd sandbox-sdk
|
|
|
534
810
|
# Install dependencies
|
|
535
811
|
npm install
|
|
536
812
|
|
|
813
|
+
# Install Bun (if not already installed)
|
|
814
|
+
# Visit https://bun.sh for installation instructions
|
|
815
|
+
curl -fsSL https://bun.sh/install | bash
|
|
816
|
+
|
|
817
|
+
# Install container dependencies (required for TypeScript checking)
|
|
818
|
+
cd packages/sandbox/container_src && bun install && cd -
|
|
819
|
+
|
|
537
820
|
# Run tests
|
|
538
821
|
npm test
|
|
539
822
|
|
|
540
823
|
# Build the project
|
|
541
824
|
npm run build
|
|
825
|
+
|
|
826
|
+
# Run type checking and linting
|
|
827
|
+
npm run check
|
|
542
828
|
```
|
|
543
829
|
|
|
544
830
|
<h2 id="license">📄 License</h2>
|