@computesdk/cloudflare 1.6.3 โ 1.6.5
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/README.md +96 -212
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
# @computesdk/cloudflare
|
|
2
2
|
|
|
3
|
-
Cloudflare provider for ComputeSDK
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **๐ Secure Isolation**: Each sandbox runs in its own container with full process isolation
|
|
8
|
-
- **โก Edge-Native**: Runs on Cloudflare's global network for low latency worldwide
|
|
9
|
-
- **๐ Full Filesystem Support**: Read, write, and manage files within the sandbox
|
|
10
|
-
- **๐ง Command Execution**: Run any command or process inside the container
|
|
11
|
-
- **๐ Port Forwarding**: Expose services running in your sandbox via public URLs
|
|
12
|
-
- **๐ Git Integration**: Clone repositories directly into sandboxes
|
|
13
|
-
- **๐งช Code Interpreter**: Execute Python and JavaScript with rich outputs
|
|
14
|
-
- **๐ฎ Session Management**: Maintain state across multiple operations
|
|
3
|
+
Cloudflare provider for ComputeSDK โ execute code in secure, isolated sandboxes on Cloudflare's edge network.
|
|
15
4
|
|
|
16
5
|
## Installation
|
|
17
6
|
|
|
@@ -19,101 +8,44 @@ Cloudflare provider for ComputeSDK - execute code in secure sandboxes on Cloudfl
|
|
|
19
8
|
npm install @computesdk/cloudflare
|
|
20
9
|
```
|
|
21
10
|
|
|
22
|
-
##
|
|
11
|
+
## Setup
|
|
23
12
|
|
|
24
|
-
|
|
13
|
+
Run the setup command to deploy a gateway Worker to your Cloudflare account:
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- Account Settings:Read
|
|
30
|
-
- Workers Scripts:Read
|
|
31
|
-
- Workers KV Storage:Read
|
|
32
|
-
- Workers Tail:Read
|
|
15
|
+
```bash
|
|
16
|
+
npx @computesdk/cloudflare
|
|
17
|
+
```
|
|
33
18
|
|
|
34
|
-
|
|
35
|
-
2. **wrangler.toml configuration** with Sandbox Durable Object binding
|
|
36
|
-
3. **Dockerfile** setup (temporary requirement)
|
|
19
|
+
This requires two environment variables:
|
|
37
20
|
|
|
38
|
-
|
|
21
|
+
- `CLOUDFLARE_API_TOKEN` โ a Cloudflare API token with the following permissions:
|
|
22
|
+
- Workers Scripts: Read & Edit
|
|
23
|
+
- Workers KV Storage: Read & Edit
|
|
24
|
+
- Account Settings: Read
|
|
25
|
+
- Workers Tail: Read
|
|
26
|
+
- `CLOUDFLARE_ACCOUNT_ID` โ your Cloudflare account ID
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
```dockerfile
|
|
42
|
-
FROM docker.io/cloudflare/sandbox:0.3.0
|
|
28
|
+
You can set these in a `.env` file or export them in your shell. Get your API token at [dash.cloudflare.com/profile/api-tokens](https://dash.cloudflare.com/profile/api-tokens).
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
EXPOSE 3000
|
|
46
|
-
```
|
|
30
|
+
The setup command will deploy the gateway Worker and output two values:
|
|
47
31
|
|
|
48
|
-
2. **Configure wrangler.toml**:
|
|
49
|
-
```toml
|
|
50
|
-
[durable_objects]
|
|
51
|
-
bindings = [
|
|
52
|
-
{ name = "Sandbox", class_name = "Sandbox" }
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
[[migrations]]
|
|
56
|
-
tag = "v1"
|
|
57
|
-
new_sqlite_classes = ["Sandbox"]
|
|
58
|
-
|
|
59
|
-
[[containers]]
|
|
60
|
-
class_name = "Sandbox"
|
|
61
|
-
image = "./Dockerfile"
|
|
62
|
-
max_instances = 1
|
|
63
32
|
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
import { getSandbox } from "@cloudflare/sandbox";
|
|
68
|
-
|
|
69
|
-
// Export the Sandbox class in your Worker
|
|
70
|
-
export { Sandbox } from "@cloudflare/sandbox";
|
|
71
|
-
|
|
72
|
-
export default {
|
|
73
|
-
async fetch(request: Request, env: Env) {
|
|
74
|
-
// Your worker code here
|
|
75
|
-
},
|
|
76
|
-
};
|
|
33
|
+
CLOUDFLARE_SANDBOX_URL=https://computesdk-sandbox.<subdomain>.workers.dev
|
|
34
|
+
CLOUDFLARE_SANDBOX_SECRET=<generated-secret>
|
|
77
35
|
```
|
|
78
36
|
|
|
79
|
-
|
|
37
|
+
Add these to your `.env` file. These are the only env vars needed at runtime.
|
|
80
38
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Use the gateway for zero-config auto-detection:
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
import { compute } from 'computesdk';
|
|
87
|
-
|
|
88
|
-
// Auto-detects from environment (when running in Cloudflare Workers)
|
|
89
|
-
const sandbox = await compute.sandbox.create();
|
|
90
|
-
|
|
91
|
-
// Execute Python code
|
|
92
|
-
const result = await sandbox.runCode(`
|
|
93
|
-
import sys
|
|
94
|
-
print(f"Python version: {sys.version}")
|
|
95
|
-
print("Hello from Cloudflare!")
|
|
96
|
-
`);
|
|
97
|
-
|
|
98
|
-
console.log(result.stdout);
|
|
99
|
-
await sandbox.destroy();
|
|
100
|
-
```
|
|
39
|
+
> **Note:** Docker must be installed for the setup command to build the sandbox container image.
|
|
101
40
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
For direct SDK usage without the gateway:
|
|
41
|
+
## Quick Start
|
|
105
42
|
|
|
106
43
|
```typescript
|
|
107
44
|
import { cloudflare } from '@computesdk/cloudflare';
|
|
108
45
|
|
|
109
|
-
// Initialize with your Durable Object binding
|
|
110
46
|
const compute = cloudflare({
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
timeout: 300000,
|
|
114
|
-
envVars: {
|
|
115
|
-
MY_VAR: 'hello world'
|
|
116
|
-
}
|
|
47
|
+
sandboxUrl: process.env.CLOUDFLARE_SANDBOX_URL,
|
|
48
|
+
sandboxSecret: process.env.CLOUDFLARE_SANDBOX_SECRET,
|
|
117
49
|
});
|
|
118
50
|
|
|
119
51
|
const sandbox = await compute.sandbox.create();
|
|
@@ -125,164 +57,130 @@ print(f"Python version: {sys.version}")
|
|
|
125
57
|
print("Hello from Cloudflare!")
|
|
126
58
|
`);
|
|
127
59
|
|
|
128
|
-
console.log(result.
|
|
129
|
-
|
|
130
|
-
// Execute shell commands
|
|
131
|
-
const cmdResult = await sandbox.runCommand('ls', ['-la']);
|
|
132
|
-
console.log(cmdResult.stdout);
|
|
133
|
-
|
|
134
|
-
// File operations
|
|
135
|
-
await sandbox.filesystem.writeFile('/tmp/hello.txt', 'Hello Cloudflare!');
|
|
136
|
-
const content = await sandbox.filesystem.readFile('/tmp/hello.txt');
|
|
137
|
-
console.log(content); // "Hello Cloudflare!"
|
|
138
|
-
|
|
139
|
-
// Expose a web service
|
|
140
|
-
await sandbox.runCode(`
|
|
141
|
-
import http.server
|
|
142
|
-
import socketserver
|
|
143
|
-
PORT = 3000
|
|
144
|
-
Handler = http.server.SimpleHTTPRequestHandler
|
|
145
|
-
with socketserver.TCPServer(("", PORT), Handler) as httpd:
|
|
146
|
-
print(f"Server running on port {PORT}")
|
|
147
|
-
httpd.serve_forever()
|
|
148
|
-
`);
|
|
149
|
-
|
|
150
|
-
// Get the public URL
|
|
151
|
-
const url = await sandbox.getUrl({ port: 3000 });
|
|
152
|
-
console.log(`Service available at: ${url}`);
|
|
153
|
-
|
|
60
|
+
console.log(result.output);
|
|
154
61
|
await sandbox.destroy();
|
|
155
62
|
```
|
|
156
63
|
|
|
157
|
-
##
|
|
64
|
+
## Usage
|
|
158
65
|
|
|
159
|
-
###
|
|
66
|
+
### Run Code
|
|
160
67
|
|
|
161
68
|
The provider automatically detects the runtime based on code content:
|
|
162
69
|
|
|
163
70
|
```typescript
|
|
164
|
-
//
|
|
71
|
+
// Detected as Python
|
|
165
72
|
await sandbox.runCode('print("Hello Python")');
|
|
166
73
|
|
|
167
|
-
//
|
|
74
|
+
// Detected as Node.js
|
|
168
75
|
await sandbox.runCode('console.log("Hello Node.js")');
|
|
169
76
|
|
|
170
77
|
// Explicitly specify runtime
|
|
171
78
|
await sandbox.runCode('print("Hello")', 'python');
|
|
172
79
|
```
|
|
173
80
|
|
|
174
|
-
###
|
|
81
|
+
### Run Commands
|
|
175
82
|
|
|
176
83
|
```typescript
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const compute = cloudflare({
|
|
180
|
-
sandboxBinding: env.Sandbox,
|
|
181
|
-
envVars: {
|
|
182
|
-
API_KEY: 'your-api-key',
|
|
183
|
-
DATABASE_URL: 'postgresql://localhost:5432/mydb',
|
|
184
|
-
NODE_ENV: 'production'
|
|
185
|
-
}
|
|
186
|
-
});
|
|
84
|
+
const result = await sandbox.runCommand('ls -la /app');
|
|
85
|
+
console.log(result.stdout);
|
|
187
86
|
```
|
|
188
87
|
|
|
189
|
-
###
|
|
88
|
+
### File System
|
|
190
89
|
|
|
191
90
|
```typescript
|
|
192
|
-
//
|
|
193
|
-
await sandbox.
|
|
194
|
-
const
|
|
195
|
-
const app = express();
|
|
196
|
-
app.get('/', (req, res) => res.json({ message: 'Hello from Cloudflare!' }));
|
|
197
|
-
app.listen(8080);
|
|
198
|
-
`);
|
|
199
|
-
|
|
200
|
-
// Get public URL
|
|
201
|
-
const url = await sandbox.getUrl({ port: 8080, protocol: 'https' });
|
|
202
|
-
console.log(`API available at: ${url}`);
|
|
203
|
-
```
|
|
91
|
+
// Write and read files
|
|
92
|
+
await sandbox.filesystem.writeFile('/app/config.json', JSON.stringify({ key: 'value' }));
|
|
93
|
+
const content = await sandbox.filesystem.readFile('/app/config.json');
|
|
204
94
|
|
|
205
|
-
### File System Operations
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
95
|
// Create directories
|
|
209
|
-
await sandbox.filesystem.mkdir('/app');
|
|
210
|
-
|
|
211
|
-
// Write files
|
|
212
|
-
await sandbox.filesystem.writeFile('/app/package.json', JSON.stringify({
|
|
213
|
-
name: 'my-app',
|
|
214
|
-
version: '1.0.0'
|
|
215
|
-
}, null, 2));
|
|
216
|
-
|
|
217
|
-
// Read files
|
|
218
|
-
const packageJson = await sandbox.filesystem.readFile('/app/package.json');
|
|
219
|
-
const config = JSON.parse(packageJson);
|
|
96
|
+
await sandbox.filesystem.mkdir('/app/data');
|
|
220
97
|
|
|
221
98
|
// List directory contents
|
|
222
99
|
const files = await sandbox.filesystem.readdir('/app');
|
|
223
|
-
files.forEach(file => {
|
|
224
|
-
console.log(`${file.name} (${file.isDirectory ? 'dir' : 'file'})`);
|
|
225
|
-
});
|
|
226
100
|
|
|
227
|
-
// Check
|
|
228
|
-
|
|
229
|
-
console.log('Package.json found!');
|
|
230
|
-
}
|
|
101
|
+
// Check existence
|
|
102
|
+
const exists = await sandbox.filesystem.exists('/app/config.json');
|
|
231
103
|
|
|
232
|
-
// Remove files
|
|
233
|
-
await sandbox.filesystem.remove('/app/temp');
|
|
104
|
+
// Remove files
|
|
105
|
+
await sandbox.filesystem.remove('/app/temp.txt');
|
|
234
106
|
```
|
|
235
107
|
|
|
236
|
-
###
|
|
108
|
+
### Port Forwarding
|
|
237
109
|
|
|
238
110
|
```typescript
|
|
239
|
-
//
|
|
111
|
+
// Start a web server in the sandbox
|
|
240
112
|
await sandbox.runCode(`
|
|
241
|
-
import
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
print(result.stdout)
|
|
113
|
+
import http.server, socketserver
|
|
114
|
+
PORT = 3000
|
|
115
|
+
with socketserver.TCPServer(("", PORT), http.server.SimpleHTTPRequestHandler) as httpd:
|
|
116
|
+
httpd.serve_forever()
|
|
246
117
|
`);
|
|
247
118
|
|
|
248
|
-
//
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
119
|
+
// Get the public URL
|
|
120
|
+
const url = await sandbox.getUrl({ port: 3000 });
|
|
121
|
+
console.log(`Service available at: ${url}`);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Environment Variables
|
|
125
|
+
|
|
126
|
+
Pass environment variables to the sandbox at initialization:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const compute = cloudflare({
|
|
130
|
+
sandboxUrl: process.env.CLOUDFLARE_SANDBOX_URL,
|
|
131
|
+
sandboxSecret: process.env.CLOUDFLARE_SANDBOX_SECRET,
|
|
132
|
+
envVars: {
|
|
133
|
+
API_KEY: 'your-api-key',
|
|
134
|
+
DATABASE_URL: 'postgresql://localhost:5432/mydb',
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Or per-sandbox at creation time:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const sandbox = await compute.sandbox.create({
|
|
143
|
+
envs: { NODE_ENV: 'production' },
|
|
144
|
+
});
|
|
254
145
|
```
|
|
255
146
|
|
|
256
|
-
## Configuration
|
|
147
|
+
## Configuration
|
|
257
148
|
|
|
258
149
|
```typescript
|
|
259
150
|
interface CloudflareConfig {
|
|
260
|
-
/**
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
/**
|
|
151
|
+
/** URL of the deployed gateway Worker */
|
|
152
|
+
sandboxUrl?: string;
|
|
153
|
+
/** Shared secret for authenticating with the gateway Worker */
|
|
154
|
+
sandboxSecret?: string;
|
|
155
|
+
/** Durable Object binding (direct mode only โ see below) */
|
|
156
|
+
sandboxBinding?: any;
|
|
157
|
+
/** Default runtime: 'python' | 'node' | 'bun' | 'deno' */
|
|
158
|
+
runtime?: Runtime;
|
|
159
|
+
/** Execution timeout in milliseconds */
|
|
267
160
|
timeout?: number;
|
|
268
|
-
|
|
269
161
|
/** Environment variables to pass to sandbox */
|
|
270
162
|
envVars?: Record<string, string>;
|
|
271
|
-
|
|
272
|
-
/** Base URL for preview URLs (defaults to worker domain) */
|
|
273
|
-
baseUrl?: string;
|
|
274
163
|
}
|
|
275
164
|
```
|
|
276
165
|
|
|
277
|
-
##
|
|
166
|
+
## Direct Mode
|
|
167
|
+
|
|
168
|
+
If your code already runs inside a Cloudflare Worker, you can skip the gateway and use the Durable Object binding directly:
|
|
278
169
|
|
|
279
170
|
```typescript
|
|
280
171
|
import { cloudflare } from '@computesdk/cloudflare';
|
|
281
172
|
|
|
173
|
+
const compute = cloudflare({
|
|
174
|
+
sandboxBinding: env.Sandbox,
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This requires configuring the Sandbox Durable Object binding in your `wrangler.toml`. See the [Cloudflare Sandbox docs](https://developers.cloudflare.com/sandbox/get-started/) for setup instructions.
|
|
179
|
+
|
|
180
|
+
## Error Handling
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
282
183
|
try {
|
|
283
|
-
const compute = cloudflare({ sandboxBinding: env.Sandbox });
|
|
284
|
-
const sandbox = await compute.sandbox.create();
|
|
285
|
-
|
|
286
184
|
const result = await sandbox.runCode('invalid python syntax');
|
|
287
185
|
} catch (error) {
|
|
288
186
|
if (error.message.includes('Syntax error')) {
|
|
@@ -295,24 +193,10 @@ try {
|
|
|
295
193
|
|
|
296
194
|
## Limitations
|
|
297
195
|
|
|
298
|
-
- Requires Cloudflare Workers environment with Durable Objects
|
|
299
|
-
- Container setup currently requires Docker configuration
|
|
300
196
|
- Resource limits apply based on your Cloudflare plan
|
|
301
197
|
- Some system calls may be restricted in the container environment
|
|
302
|
-
|
|
303
|
-
## Examples
|
|
304
|
-
|
|
305
|
-
Check out the [examples directory](../../examples) for complete working examples:
|
|
306
|
-
|
|
307
|
-
- **Basic Usage**: Simple code execution
|
|
308
|
-
- **Web Server**: Express.js app with public URLs
|
|
309
|
-
- **Data Processing**: Python data analysis with file I/O
|
|
310
|
-
- **CI/CD**: Automated testing and building
|
|
198
|
+
- Listing all sandboxes is not supported โ use `getById` to reconnect to a specific sandbox
|
|
311
199
|
|
|
312
200
|
## License
|
|
313
201
|
|
|
314
|
-
MIT
|
|
315
|
-
|
|
316
|
-
## Contributing
|
|
317
|
-
|
|
318
|
-
See the [main repository](https://github.com/computesdk/computesdk) for contribution guidelines.
|
|
202
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computesdk/cloudflare",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"description": "Cloudflare provider for ComputeSDK - edge code execution using Cloudflare Workers and Durable Objects",
|
|
5
5
|
"author": "Garrison",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@cloudflare/sandbox": "^0.7.18",
|
|
26
|
-
"@computesdk/provider": "1.0
|
|
27
|
-
"computesdk": "2.5.
|
|
26
|
+
"@computesdk/provider": "1.2.0",
|
|
27
|
+
"computesdk": "2.5.4"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [
|
|
30
30
|
"computesdk",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"typescript": "^5.0.0",
|
|
61
61
|
"vitest": "^1.0.0",
|
|
62
62
|
"wrangler": "^3.0.0",
|
|
63
|
-
"@computesdk/test-utils": "1.6.
|
|
63
|
+
"@computesdk/test-utils": "1.6.1"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "tsup",
|