@computesdk/cloudflare 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 computesdk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,288 @@
1
+ # @computesdk/cloudflare
2
+
3
+ Cloudflare provider for ComputeSDK - execute code in secure sandboxes on Cloudflare's edge network using Durable Objects.
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
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @computesdk/cloudflare
20
+ ```
21
+
22
+ ## Prerequisites
23
+
24
+ This provider requires a Cloudflare Workers environment with Durable Objects configured. You'll need:
25
+
26
+ Note: Cloudflare API key should include the following permissions:
27
+ - Workers Scripts:Edit
28
+ - Workers KV Storage:Edit
29
+ - Account Settings:Read
30
+ - Workers Scripts:Read
31
+ - Workers KV Storage:Read
32
+ - Workers Tail:Read
33
+
34
+ 1. **Cloudflare Workers account** with Durable Objects enabled
35
+ 2. **wrangler.toml configuration** with Sandbox Durable Object binding
36
+ 3. **Dockerfile** setup (temporary requirement)
37
+
38
+ ### Setup Instructions
39
+
40
+ 1. **Create a Dockerfile** (temporary requirement):
41
+ ```dockerfile
42
+ FROM docker.io/cloudflare/sandbox:0.3.0
43
+
44
+ # Expose the ports you want to expose
45
+ EXPOSE 3000
46
+ ```
47
+
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
+ ```
64
+
65
+ 3. **Export the Sandbox class in your Worker**:
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
+ };
77
+ ```
78
+
79
+ ## Basic Usage
80
+
81
+ ```typescript
82
+ import { cloudflare } from '@computesdk/cloudflare';
83
+
84
+ // Initialize the provider with your Durable Object binding
85
+ const provider = cloudflare({
86
+ sandboxBinding: env.Sandbox, // Your Durable Object binding
87
+ runtime: 'python',
88
+ timeout: 300000,
89
+ envVars: {
90
+ MY_VAR: 'hello world'
91
+ }
92
+ });
93
+
94
+ // Create a sandbox
95
+ const sandbox = await provider.sandbox.create();
96
+
97
+ // Execute Python code
98
+ const result = await sandbox.runCode(`
99
+ import sys
100
+ print(f"Python version: {sys.version}")
101
+ print("Hello from Cloudflare!")
102
+ `);
103
+
104
+ console.log(result.stdout);
105
+
106
+ // Execute shell commands
107
+ const cmdResult = await sandbox.runCommand('ls', ['-la']);
108
+ console.log(cmdResult.stdout);
109
+
110
+ // File operations
111
+ await sandbox.filesystem.writeFile('/tmp/hello.txt', 'Hello Cloudflare!');
112
+ const content = await sandbox.filesystem.readFile('/tmp/hello.txt');
113
+ console.log(content); // "Hello Cloudflare!"
114
+
115
+ // Expose a web service
116
+ await sandbox.runCode(`
117
+ import http.server
118
+ import socketserver
119
+ PORT = 3000
120
+ Handler = http.server.SimpleHTTPRequestHandler
121
+ with socketserver.TCPServer(("", PORT), Handler) as httpd:
122
+ print(f"Server running on port {PORT}")
123
+ httpd.serve_forever()
124
+ `);
125
+
126
+ // Get the public URL
127
+ const url = await sandbox.getUrl({ port: 3000 });
128
+ console.log(`Service available at: ${url}`);
129
+
130
+ // Clean up
131
+ await sandbox.destroy();
132
+ ```
133
+
134
+ ## Advanced Usage
135
+
136
+ ### Runtime Detection
137
+
138
+ The provider automatically detects the runtime based on code content:
139
+
140
+ ```typescript
141
+ // Automatically detected as Python
142
+ await sandbox.runCode('print("Hello Python")');
143
+
144
+ // Automatically detected as Node.js
145
+ await sandbox.runCode('console.log("Hello Node.js")');
146
+
147
+ // Explicitly specify runtime
148
+ await sandbox.runCode('print("Hello")', 'python');
149
+ ```
150
+
151
+ ### Environment Variables
152
+
153
+ ```typescript
154
+ const provider = cloudflare({
155
+ sandboxBinding: env.Sandbox,
156
+ envVars: {
157
+ API_KEY: 'your-api-key',
158
+ DATABASE_URL: 'postgresql://localhost:5432/mydb',
159
+ NODE_ENV: 'production'
160
+ }
161
+ });
162
+ ```
163
+
164
+ ### Port Forwarding
165
+
166
+ ```typescript
167
+ // Start a web server
168
+ await sandbox.runCode(`
169
+ const express = require('express');
170
+ const app = express();
171
+ app.get('/', (req, res) => res.json({ message: 'Hello from Cloudflare!' }));
172
+ app.listen(8080);
173
+ `);
174
+
175
+ // Get public URL
176
+ const url = await sandbox.getUrl({ port: 8080, protocol: 'https' });
177
+ console.log(`API available at: ${url}`);
178
+ ```
179
+
180
+ ### File System Operations
181
+
182
+ ```typescript
183
+ // Create directories
184
+ await sandbox.filesystem.mkdir('/app');
185
+
186
+ // Write files
187
+ await sandbox.filesystem.writeFile('/app/package.json', JSON.stringify({
188
+ name: 'my-app',
189
+ version: '1.0.0'
190
+ }, null, 2));
191
+
192
+ // Read files
193
+ const packageJson = await sandbox.filesystem.readFile('/app/package.json');
194
+ const config = JSON.parse(packageJson);
195
+
196
+ // List directory contents
197
+ const files = await sandbox.filesystem.readdir('/app');
198
+ files.forEach(file => {
199
+ console.log(`${file.name} (${file.isDirectory ? 'dir' : 'file'})`);
200
+ });
201
+
202
+ // Check if file exists
203
+ if (await sandbox.filesystem.exists('/app/package.json')) {
204
+ console.log('Package.json found!');
205
+ }
206
+
207
+ // Remove files/directories
208
+ await sandbox.filesystem.remove('/app/temp');
209
+ ```
210
+
211
+ ### Git Operations
212
+
213
+ ```typescript
214
+ // Clone a repository
215
+ await sandbox.runCode(`
216
+ import subprocess
217
+ result = subprocess.run([
218
+ 'git', 'clone', 'https://github.com/user/repo.git', '/app'
219
+ ], capture_output=True, text=True)
220
+ print(result.stdout)
221
+ `);
222
+
223
+ // Or using the built-in git functionality (if available)
224
+ const result = await sandbox.runCommand('git', [
225
+ 'clone',
226
+ 'https://github.com/user/repo.git',
227
+ '/app'
228
+ ]);
229
+ ```
230
+
231
+ ## Configuration Options
232
+
233
+ ```typescript
234
+ interface CloudflareConfig {
235
+ /** Cloudflare Sandbox binding from Workers environment (required) */
236
+ sandboxBinding: any;
237
+
238
+ /** Default runtime environment */
239
+ runtime?: 'python' | 'node';
240
+
241
+ /** Execution timeout in milliseconds (default: 300000) */
242
+ timeout?: number;
243
+
244
+ /** Environment variables to pass to sandbox */
245
+ envVars?: Record<string, string>;
246
+
247
+ /** Base URL for preview URLs (defaults to worker domain) */
248
+ baseUrl?: string;
249
+ }
250
+ ```
251
+
252
+ ## Error Handling
253
+
254
+ ```typescript
255
+ try {
256
+ const result = await sandbox.runCode('invalid python syntax');
257
+ } catch (error) {
258
+ if (error.message.includes('Syntax error')) {
259
+ console.log('Code has syntax errors');
260
+ } else {
261
+ console.log('Execution failed:', error.message);
262
+ }
263
+ }
264
+ ```
265
+
266
+ ## Limitations
267
+
268
+ - Requires Cloudflare Workers environment with Durable Objects
269
+ - Container setup currently requires Docker configuration
270
+ - Resource limits apply based on your Cloudflare plan
271
+ - Some system calls may be restricted in the container environment
272
+
273
+ ## Examples
274
+
275
+ Check out the [examples directory](../../examples) for complete working examples:
276
+
277
+ - **Basic Usage**: Simple code execution
278
+ - **Web Server**: Express.js app with public URLs
279
+ - **Data Processing**: Python data analysis with file I/O
280
+ - **CI/CD**: Automated testing and building
281
+
282
+ ## License
283
+
284
+ MIT
285
+
286
+ ## Contributing
287
+
288
+ See the [main repository](https://github.com/computesdk/computesdk) for contribution guidelines.
@@ -0,0 +1,32 @@
1
+ import * as computesdk from 'computesdk';
2
+ import { Runtime } from 'computesdk';
3
+
4
+ /**
5
+ * Cloudflare-specific configuration options
6
+ */
7
+ interface CloudflareConfig {
8
+ /** Cloudflare Sandbox binding from Workers environment - the Durable Object binding */
9
+ sandboxBinding?: any;
10
+ /** Default runtime environment */
11
+ runtime?: Runtime;
12
+ /** Execution timeout in milliseconds */
13
+ timeout?: number;
14
+ /** Environment variables to pass to sandbox */
15
+ envVars?: Record<string, string>;
16
+ /** Base URL for preview URLs (defaults to worker domain) */
17
+ baseUrl?: string;
18
+ }
19
+ /**
20
+ * Cloudflare sandbox wrapper - wraps the Cloudflare Sandbox instance
21
+ */
22
+ interface CloudflareSandbox {
23
+ sandbox: any;
24
+ sandboxId: string;
25
+ exposedPorts: Map<number, string>;
26
+ }
27
+ /**
28
+ * Create a Cloudflare provider instance using the factory pattern
29
+ */
30
+ declare const cloudflare: (config: CloudflareConfig) => computesdk.Provider<CloudflareSandbox, any, any>;
31
+
32
+ export { type CloudflareConfig, cloudflare };
@@ -0,0 +1,32 @@
1
+ import * as computesdk from 'computesdk';
2
+ import { Runtime } from 'computesdk';
3
+
4
+ /**
5
+ * Cloudflare-specific configuration options
6
+ */
7
+ interface CloudflareConfig {
8
+ /** Cloudflare Sandbox binding from Workers environment - the Durable Object binding */
9
+ sandboxBinding?: any;
10
+ /** Default runtime environment */
11
+ runtime?: Runtime;
12
+ /** Execution timeout in milliseconds */
13
+ timeout?: number;
14
+ /** Environment variables to pass to sandbox */
15
+ envVars?: Record<string, string>;
16
+ /** Base URL for preview URLs (defaults to worker domain) */
17
+ baseUrl?: string;
18
+ }
19
+ /**
20
+ * Cloudflare sandbox wrapper - wraps the Cloudflare Sandbox instance
21
+ */
22
+ interface CloudflareSandbox {
23
+ sandbox: any;
24
+ sandboxId: string;
25
+ exposedPorts: Map<number, string>;
26
+ }
27
+ /**
28
+ * Create a Cloudflare provider instance using the factory pattern
29
+ */
30
+ declare const cloudflare: (config: CloudflareConfig) => computesdk.Provider<CloudflareSandbox, any, any>;
31
+
32
+ export { type CloudflareConfig, cloudflare };
package/dist/index.js ADDED
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ cloudflare: () => cloudflare
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+ var import_sandbox = require("@cloudflare/sandbox");
27
+ var import_computesdk = require("computesdk");
28
+ function detectRuntime(code) {
29
+ if (code.includes("print(") || code.includes("import ") || code.includes("def ") || code.includes("sys.") || code.includes("json.") || code.includes("__") || code.includes('f"') || code.includes("f'") || code.includes("raise ")) {
30
+ return "python";
31
+ }
32
+ if (code.includes("console.log") || code.includes("process.") || code.includes("require(") || code.includes("module.exports") || code.includes("__dirname") || code.includes("__filename")) {
33
+ return "node";
34
+ }
35
+ return "python";
36
+ }
37
+ var cloudflare = (0, import_computesdk.createProvider)({
38
+ name: "cloudflare",
39
+ methods: {
40
+ sandbox: {
41
+ // Collection operations (map to compute.sandbox.*)
42
+ create: async (config, options) => {
43
+ if (!config.sandboxBinding) {
44
+ throw new Error(
45
+ `Missing Cloudflare Sandbox binding. Provide 'sandboxBinding' in config with the Durable Object binding from your Cloudflare Workers environment (env.Sandbox). See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`
46
+ );
47
+ }
48
+ const sandboxId = options?.sandboxId || `cf-sandbox-${Date.now()}`;
49
+ try {
50
+ const sandbox = (0, import_sandbox.getSandbox)(config.sandboxBinding, sandboxId);
51
+ if (config.envVars) {
52
+ await sandbox.setEnvVars(config.envVars);
53
+ }
54
+ const cloudflareSandbox = {
55
+ sandbox,
56
+ sandboxId,
57
+ exposedPorts: /* @__PURE__ */ new Map()
58
+ };
59
+ return {
60
+ sandbox: cloudflareSandbox,
61
+ sandboxId
62
+ };
63
+ } catch (error) {
64
+ if (error instanceof Error) {
65
+ if (error.message.includes("unauthorized") || error.message.includes("binding")) {
66
+ throw new Error(
67
+ `Cloudflare Sandbox binding failed. Ensure your Durable Object binding is properly configured in wrangler.toml. See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`
68
+ );
69
+ }
70
+ if (error.message.includes("quota") || error.message.includes("limit")) {
71
+ throw new Error(
72
+ `Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/`
73
+ );
74
+ }
75
+ }
76
+ throw new Error(
77
+ `Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`
78
+ );
79
+ }
80
+ },
81
+ getById: async (config, sandboxId) => {
82
+ if (!config.sandboxBinding) {
83
+ return null;
84
+ }
85
+ try {
86
+ const sandbox = (0, import_sandbox.getSandbox)(config.sandboxBinding, sandboxId);
87
+ try {
88
+ await sandbox.ping();
89
+ } catch {
90
+ }
91
+ const cloudflareSandbox = {
92
+ sandbox,
93
+ sandboxId,
94
+ exposedPorts: /* @__PURE__ */ new Map()
95
+ };
96
+ return {
97
+ sandbox: cloudflareSandbox,
98
+ sandboxId
99
+ };
100
+ } catch (error) {
101
+ return null;
102
+ }
103
+ },
104
+ list: async (_config) => {
105
+ throw new Error(
106
+ `Cloudflare provider does not support listing sandboxes. Cloudflare sandboxes are managed through Durable Objects and don't have a native list API. Use getById to reconnect to specific sandboxes by ID, or implement your own tracking system.`
107
+ );
108
+ },
109
+ destroy: async (config, sandboxId) => {
110
+ try {
111
+ if (config.sandboxBinding) {
112
+ const sandbox = (0, import_sandbox.getSandbox)(config.sandboxBinding, sandboxId);
113
+ await sandbox.killAllProcesses();
114
+ }
115
+ } catch (error) {
116
+ }
117
+ },
118
+ // Instance operations (map to individual Sandbox methods)
119
+ runCode: async (cloudflareSandbox, code, runtime) => {
120
+ const startTime = Date.now();
121
+ try {
122
+ const { sandbox, sandboxId } = cloudflareSandbox;
123
+ const detectedRuntime = runtime || detectRuntime(code);
124
+ let result;
125
+ if (detectedRuntime === "python") {
126
+ const execution = await sandbox.runCode(code, { language: "python" });
127
+ let stdout = "";
128
+ let stderr = "";
129
+ if (execution.results && Array.isArray(execution.results)) {
130
+ for (const res of execution.results) {
131
+ if (res.text) {
132
+ stdout += res.text;
133
+ }
134
+ }
135
+ }
136
+ result = {
137
+ stdout,
138
+ stderr,
139
+ exitCode: 0,
140
+ // Cloudflare code interpreter doesn't expose exit codes directly
141
+ executionTime: Date.now() - startTime,
142
+ sandboxId,
143
+ provider: "cloudflare"
144
+ };
145
+ } else {
146
+ const execResult = await sandbox.exec(`node -e "${code.replace(/"/g, '\\"')}"`);
147
+ result = {
148
+ stdout: execResult.stdout || "",
149
+ stderr: execResult.stderr || "",
150
+ exitCode: execResult.exitCode || 0,
151
+ executionTime: Date.now() - startTime,
152
+ sandboxId,
153
+ provider: "cloudflare"
154
+ };
155
+ }
156
+ if (result.stderr && (result.stderr.includes("SyntaxError") || result.stderr.includes("invalid syntax") || result.stderr.includes("Unexpected token"))) {
157
+ throw new Error(`Syntax error: ${result.stderr.trim()}`);
158
+ }
159
+ return result;
160
+ } catch (error) {
161
+ if (error instanceof Error && error.message.includes("Syntax error")) {
162
+ throw error;
163
+ }
164
+ throw new Error(
165
+ `Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`
166
+ );
167
+ }
168
+ },
169
+ runCommand: async (cloudflareSandbox, command, args = []) => {
170
+ const startTime = Date.now();
171
+ try {
172
+ const { sandbox, sandboxId } = cloudflareSandbox;
173
+ const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
174
+ const execResult = await sandbox.exec(fullCommand);
175
+ return {
176
+ stdout: execResult.stdout || "",
177
+ stderr: execResult.stderr || "",
178
+ exitCode: execResult.exitCode || 0,
179
+ executionTime: Date.now() - startTime,
180
+ sandboxId,
181
+ provider: "cloudflare"
182
+ };
183
+ } catch (error) {
184
+ return {
185
+ stdout: "",
186
+ stderr: error instanceof Error ? error.message : String(error),
187
+ exitCode: 127,
188
+ // Command not found exit code
189
+ executionTime: Date.now() - startTime,
190
+ sandboxId: cloudflareSandbox.sandboxId,
191
+ provider: "cloudflare"
192
+ };
193
+ }
194
+ },
195
+ getInfo: async (cloudflareSandbox) => {
196
+ try {
197
+ const { sandbox, sandboxId } = cloudflareSandbox;
198
+ try {
199
+ await sandbox.ping();
200
+ } catch {
201
+ }
202
+ return {
203
+ id: sandboxId,
204
+ provider: "cloudflare",
205
+ runtime: "python",
206
+ // Cloudflare default
207
+ status: "running",
208
+ createdAt: /* @__PURE__ */ new Date(),
209
+ timeout: 3e5,
210
+ metadata: {
211
+ cloudflareSandboxId: sandboxId,
212
+ durableObjectSandbox: true
213
+ }
214
+ };
215
+ } catch (error) {
216
+ return {
217
+ id: cloudflareSandbox.sandboxId,
218
+ provider: "cloudflare",
219
+ runtime: "python",
220
+ status: "error",
221
+ createdAt: /* @__PURE__ */ new Date(),
222
+ timeout: 3e5,
223
+ metadata: {
224
+ cloudflareSandboxId: cloudflareSandbox.sandboxId,
225
+ durableObjectSandbox: true,
226
+ error: error instanceof Error ? error.message : String(error)
227
+ }
228
+ };
229
+ }
230
+ },
231
+ getUrl: async (cloudflareSandbox, options) => {
232
+ try {
233
+ const { sandbox, exposedPorts } = cloudflareSandbox;
234
+ const { port, protocol = "https" } = options;
235
+ if (exposedPorts.has(port)) {
236
+ return exposedPorts.get(port);
237
+ }
238
+ const preview = await sandbox.exposePort(port);
239
+ const url = `${protocol}://${preview.url}`;
240
+ exposedPorts.set(port, url);
241
+ return url;
242
+ } catch (error) {
243
+ throw new Error(
244
+ `Failed to expose port ${options.port}: ${error instanceof Error ? error.message : String(error)}`
245
+ );
246
+ }
247
+ },
248
+ // Filesystem methods - Cloudflare has full filesystem support
249
+ filesystem: {
250
+ readFile: async (cloudflareSandbox, path) => {
251
+ try {
252
+ const { sandbox } = cloudflareSandbox;
253
+ const file = await sandbox.readFile(path);
254
+ return file.content || "";
255
+ } catch (error) {
256
+ throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);
257
+ }
258
+ },
259
+ writeFile: async (cloudflareSandbox, path, content) => {
260
+ try {
261
+ const { sandbox } = cloudflareSandbox;
262
+ await sandbox.writeFile(path, content);
263
+ } catch (error) {
264
+ throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);
265
+ }
266
+ },
267
+ mkdir: async (cloudflareSandbox, path) => {
268
+ try {
269
+ const { sandbox } = cloudflareSandbox;
270
+ await sandbox.mkdir(path);
271
+ } catch (error) {
272
+ throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);
273
+ }
274
+ },
275
+ readdir: async (cloudflareSandbox, path) => {
276
+ try {
277
+ const { sandbox } = cloudflareSandbox;
278
+ const result = await sandbox.exec(`ls -la "${path}"`);
279
+ if (result.exitCode !== 0) {
280
+ throw new Error(`Directory listing failed: ${result.stderr}`);
281
+ }
282
+ const lines = result.stdout.split("\n").filter((line) => line.trim() && !line.startsWith("total"));
283
+ return lines.map((line) => {
284
+ const parts = line.trim().split(/\s+/);
285
+ const permissions = parts[0] || "";
286
+ const size = parseInt(parts[4]) || 0;
287
+ const dateStr = (parts[5] || "") + " " + (parts[6] || "");
288
+ const date = dateStr.trim() ? new Date(dateStr) : /* @__PURE__ */ new Date();
289
+ const name = parts.slice(8).join(" ") || parts[parts.length - 1] || "unknown";
290
+ return {
291
+ name,
292
+ path: `${path}/${name}`.replace("//", "/"),
293
+ isDirectory: permissions.startsWith("d"),
294
+ size,
295
+ lastModified: isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date
296
+ };
297
+ });
298
+ } catch (error) {
299
+ throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);
300
+ }
301
+ },
302
+ exists: async (cloudflareSandbox, path) => {
303
+ try {
304
+ const { sandbox } = cloudflareSandbox;
305
+ const result = await sandbox.exec(`test -e "${path}"`);
306
+ return result.exitCode === 0;
307
+ } catch (error) {
308
+ return false;
309
+ }
310
+ },
311
+ remove: async (cloudflareSandbox, path) => {
312
+ try {
313
+ const { sandbox } = cloudflareSandbox;
314
+ const result = await sandbox.exec(`rm -rf "${path}"`);
315
+ if (result.exitCode !== 0) {
316
+ throw new Error(`Remove failed: ${result.stderr}`);
317
+ }
318
+ } catch (error) {
319
+ throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);
320
+ }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ });
326
+ // Annotate the CommonJS export names for ESM import in node:
327
+ 0 && (module.exports = {
328
+ cloudflare
329
+ });
330
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Cloudflare Provider - Factory-based Implementation\n * \n * Full-featured provider using Cloudflare Sandbox SDK with all required methods.\n * Leverages Cloudflare's edge network and Durable Objects for sandboxed execution.\n */\n\nimport { getSandbox } from '@cloudflare/sandbox';\nimport { createProvider } from 'computesdk';\nimport type { \n ExecutionResult, \n SandboxInfo, \n Runtime,\n CreateSandboxOptions,\n FileEntry\n} from 'computesdk';\n\n/**\n * Cloudflare-specific configuration options\n */\nexport interface CloudflareConfig {\n /** Cloudflare Sandbox binding from Workers environment - the Durable Object binding */\n sandboxBinding?: any;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Environment variables to pass to sandbox */\n envVars?: Record<string, string>;\n /** Base URL for preview URLs (defaults to worker domain) */\n baseUrl?: string;\n}\n\n/**\n * Cloudflare sandbox wrapper - wraps the Cloudflare Sandbox instance\n */\ninterface CloudflareSandbox {\n sandbox: any; // The actual Cloudflare Sandbox instance from getSandbox()\n sandboxId: string;\n exposedPorts: Map<number, string>; // Track exposed ports and their URLs\n}\n\n/**\n * Detect runtime from code content\n */\nfunction detectRuntime(code: string): Runtime {\n // Strong Python indicators\n if (code.includes('print(') || \n code.includes('import ') ||\n code.includes('def ') ||\n code.includes('sys.') ||\n code.includes('json.') ||\n code.includes('__') ||\n code.includes('f\"') ||\n code.includes(\"f'\") ||\n code.includes('raise ')) {\n return 'python';\n }\n\n // Strong Node.js indicators\n if (code.includes('console.log') || \n code.includes('process.') ||\n code.includes('require(') ||\n code.includes('module.exports') ||\n code.includes('__dirname') ||\n code.includes('__filename')) {\n return 'node';\n }\n\n // Default to Python for Cloudflare (matches their examples)\n return 'python';\n}\n\n/**\n * Create a Cloudflare provider instance using the factory pattern\n */\nexport const cloudflare = createProvider<CloudflareSandbox, CloudflareConfig>({\n name: 'cloudflare',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: CloudflareConfig, options?: CreateSandboxOptions) => {\n // Validate Cloudflare Workers environment binding\n if (!config.sandboxBinding) {\n throw new Error(\n `Missing Cloudflare Sandbox binding. Provide 'sandboxBinding' in config with the Durable Object binding from your Cloudflare Workers environment (env.Sandbox). ` +\n `See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`\n );\n }\n\n const sandboxId = options?.sandboxId || `cf-sandbox-${Date.now()}`;\n\n try {\n // Create or connect to Cloudflare sandbox using getSandbox\n const sandbox = getSandbox(config.sandboxBinding, sandboxId);\n\n // Set environment variables if provided\n if (config.envVars) {\n await sandbox.setEnvVars(config.envVars);\n }\n\n const cloudflareSandbox: CloudflareSandbox = {\n sandbox,\n sandboxId,\n exposedPorts: new Map()\n };\n\n return {\n sandbox: cloudflareSandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('binding')) {\n throw new Error(\n `Cloudflare Sandbox binding failed. Ensure your Durable Object binding is properly configured in wrangler.toml. ` +\n `See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/`\n );\n }\n }\n throw new Error(\n `Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: CloudflareConfig, sandboxId: string) => {\n if (!config.sandboxBinding) {\n return null;\n }\n\n try {\n // Reconnect to existing Cloudflare sandbox\n const sandbox = getSandbox(config.sandboxBinding, sandboxId);\n\n // Test connection - Note: ping may not be available on all sandbox versions\n try {\n await (sandbox as any).ping();\n } catch {\n // ping not supported, continue\n }\n\n const cloudflareSandbox: CloudflareSandbox = {\n sandbox,\n sandboxId,\n exposedPorts: new Map()\n };\n\n return {\n sandbox: cloudflareSandbox,\n sandboxId\n };\n } catch (error) {\n // Sandbox doesn't exist or can't be accessed\n return null;\n }\n },\n\n list: async (_config: CloudflareConfig) => {\n throw new Error(\n `Cloudflare provider does not support listing sandboxes. Cloudflare sandboxes are managed through Durable Objects and don't have a native list API. ` +\n `Use getById to reconnect to specific sandboxes by ID, or implement your own tracking system.`\n );\n },\n\n destroy: async (config: CloudflareConfig, sandboxId: string) => {\n try {\n if (config.sandboxBinding) {\n const sandbox = getSandbox(config.sandboxBinding, sandboxId);\n \n // Stop all processes and clean up\n await sandbox.killAllProcesses();\n \n // Note: Cloudflare Durable Objects manage their own lifecycle\n // The actual destruction happens automatically when the object is no longer referenced\n }\n } catch (error) {\n // Sandbox might already be destroyed or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (cloudflareSandbox: CloudflareSandbox, code: string, runtime?: Runtime): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n const { sandbox, sandboxId } = cloudflareSandbox;\n \n // Auto-detect runtime from code if not specified\n const detectedRuntime = runtime || detectRuntime(code);\n \n let result;\n\n if (detectedRuntime === 'python') {\n // Use Cloudflare's code interpreter for Python\n const execution = await sandbox.runCode(code, { language: 'python' });\n \n // Process the execution result\n let stdout = '';\n let stderr = '';\n \n // Handle streaming results if available\n if (execution.results && Array.isArray(execution.results)) {\n for (const res of execution.results) {\n if (res.text) {\n stdout += res.text;\n }\n }\n }\n \n result = {\n stdout,\n stderr,\n exitCode: 0, // Cloudflare code interpreter doesn't expose exit codes directly\n executionTime: Date.now() - startTime,\n sandboxId,\n provider: 'cloudflare'\n };\n } else {\n // For Node.js/JavaScript, use exec with node command\n const execResult = await sandbox.exec(`node -e \"${code.replace(/\"/g, '\\\\\"')}\"`);\n \n result = {\n stdout: execResult.stdout || '',\n stderr: execResult.stderr || '',\n exitCode: execResult.exitCode || 0,\n executionTime: Date.now() - startTime,\n sandboxId,\n provider: 'cloudflare'\n };\n }\n\n // Check for syntax errors\n if (result.stderr && (\n result.stderr.includes('SyntaxError') ||\n result.stderr.includes('invalid syntax') ||\n result.stderr.includes('Unexpected token')\n )) {\n throw new Error(`Syntax error: ${result.stderr.trim()}`);\n }\n\n return result;\n } catch (error) {\n // Re-throw syntax errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error;\n }\n \n throw new Error(\n `Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (cloudflareSandbox: CloudflareSandbox, command: string, args: string[] = []): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n const { sandbox, sandboxId } = cloudflareSandbox;\n \n // Construct full command with arguments\n const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;\n\n // Execute command using Cloudflare's exec method\n const execResult = await sandbox.exec(fullCommand);\n\n return {\n stdout: execResult.stdout || '',\n stderr: execResult.stderr || '',\n exitCode: execResult.exitCode || 0,\n executionTime: Date.now() - startTime,\n sandboxId,\n provider: 'cloudflare'\n };\n } catch (error) {\n // For command failures, return error info instead of throwing\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127, // Command not found exit code\n executionTime: Date.now() - startTime,\n sandboxId: cloudflareSandbox.sandboxId,\n provider: 'cloudflare'\n };\n }\n },\n\n getInfo: async (cloudflareSandbox: CloudflareSandbox): Promise<SandboxInfo> => {\n try {\n const { sandbox, sandboxId } = cloudflareSandbox;\n \n // Test if sandbox is still alive - ping may not be available\n try {\n await (sandbox as any).ping();\n } catch {\n // ping not supported, continue\n }\n\n return {\n id: sandboxId,\n provider: 'cloudflare',\n runtime: 'python', // Cloudflare default\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: sandboxId,\n durableObjectSandbox: true\n }\n };\n } catch (error) {\n return {\n id: cloudflareSandbox.sandboxId,\n provider: 'cloudflare',\n runtime: 'python',\n status: 'error',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: cloudflareSandbox.sandboxId,\n durableObjectSandbox: true,\n error: error instanceof Error ? error.message : String(error)\n }\n };\n }\n },\n\n getUrl: async (cloudflareSandbox: CloudflareSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n const { sandbox, exposedPorts } = cloudflareSandbox;\n const { port, protocol = 'https' } = options;\n\n // Check if port is already exposed\n if (exposedPorts.has(port)) {\n return exposedPorts.get(port)!;\n }\n\n // Expose the port using Cloudflare's exposePort method\n const preview = await sandbox.exposePort(port);\n const url = `${protocol}://${preview.url}`;\n \n // Cache the exposed URL\n exposedPorts.set(port, url);\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to expose port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n // Filesystem methods - Cloudflare has full filesystem support\n filesystem: {\n readFile: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<string> => {\n try {\n const { sandbox } = cloudflareSandbox;\n const file = await sandbox.readFile(path);\n return file.content || '';\n } catch (error) {\n throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n writeFile: async (cloudflareSandbox: CloudflareSandbox, path: string, content: string): Promise<void> => {\n try {\n const { sandbox } = cloudflareSandbox;\n await sandbox.writeFile(path, content);\n } catch (error) {\n throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n mkdir: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<void> => {\n try {\n const { sandbox } = cloudflareSandbox;\n await sandbox.mkdir(path);\n } catch (error) {\n throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n readdir: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<FileEntry[]> => {\n try {\n const { sandbox } = cloudflareSandbox;\n \n // Use ls command to get directory listing\n const result = await sandbox.exec(`ls -la \"${path}\"`);\n \n if (result.exitCode !== 0) {\n throw new Error(`Directory listing failed: ${result.stderr}`);\n }\n\n const lines = result.stdout.split('\\n').filter((line: string) => line.trim() && !line.startsWith('total'));\n\n return lines.map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const permissions = parts[0] || '';\n const size = parseInt(parts[4]) || 0;\n const dateStr = (parts[5] || '') + ' ' + (parts[6] || '');\n const date = dateStr.trim() ? new Date(dateStr) : new Date();\n const name = parts.slice(8).join(' ') || parts[parts.length - 1] || 'unknown';\n\n return {\n name,\n path: `${path}/${name}`.replace('//', '/'),\n isDirectory: permissions.startsWith('d'),\n size,\n lastModified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n } catch (error) {\n throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n exists: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<boolean> => {\n try {\n const { sandbox } = cloudflareSandbox;\n const result = await sandbox.exec(`test -e \"${path}\"`);\n return result.exitCode === 0;\n } catch (error) {\n return false;\n }\n },\n\n remove: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<void> => {\n try {\n const { sandbox } = cloudflareSandbox;\n const result = await sandbox.exec(`rm -rf \"${path}\"`);\n \n if (result.exitCode !== 0) {\n throw new Error(`Remove failed: ${result.stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n }\n }\n }\n});"],"mappings":"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","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,305 @@
1
+ // src/index.ts
2
+ import { getSandbox } from "@cloudflare/sandbox";
3
+ import { createProvider } from "computesdk";
4
+ function detectRuntime(code) {
5
+ if (code.includes("print(") || code.includes("import ") || code.includes("def ") || code.includes("sys.") || code.includes("json.") || code.includes("__") || code.includes('f"') || code.includes("f'") || code.includes("raise ")) {
6
+ return "python";
7
+ }
8
+ if (code.includes("console.log") || code.includes("process.") || code.includes("require(") || code.includes("module.exports") || code.includes("__dirname") || code.includes("__filename")) {
9
+ return "node";
10
+ }
11
+ return "python";
12
+ }
13
+ var cloudflare = createProvider({
14
+ name: "cloudflare",
15
+ methods: {
16
+ sandbox: {
17
+ // Collection operations (map to compute.sandbox.*)
18
+ create: async (config, options) => {
19
+ if (!config.sandboxBinding) {
20
+ throw new Error(
21
+ `Missing Cloudflare Sandbox binding. Provide 'sandboxBinding' in config with the Durable Object binding from your Cloudflare Workers environment (env.Sandbox). See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`
22
+ );
23
+ }
24
+ const sandboxId = options?.sandboxId || `cf-sandbox-${Date.now()}`;
25
+ try {
26
+ const sandbox = getSandbox(config.sandboxBinding, sandboxId);
27
+ if (config.envVars) {
28
+ await sandbox.setEnvVars(config.envVars);
29
+ }
30
+ const cloudflareSandbox = {
31
+ sandbox,
32
+ sandboxId,
33
+ exposedPorts: /* @__PURE__ */ new Map()
34
+ };
35
+ return {
36
+ sandbox: cloudflareSandbox,
37
+ sandboxId
38
+ };
39
+ } catch (error) {
40
+ if (error instanceof Error) {
41
+ if (error.message.includes("unauthorized") || error.message.includes("binding")) {
42
+ throw new Error(
43
+ `Cloudflare Sandbox binding failed. Ensure your Durable Object binding is properly configured in wrangler.toml. See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`
44
+ );
45
+ }
46
+ if (error.message.includes("quota") || error.message.includes("limit")) {
47
+ throw new Error(
48
+ `Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/`
49
+ );
50
+ }
51
+ }
52
+ throw new Error(
53
+ `Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`
54
+ );
55
+ }
56
+ },
57
+ getById: async (config, sandboxId) => {
58
+ if (!config.sandboxBinding) {
59
+ return null;
60
+ }
61
+ try {
62
+ const sandbox = getSandbox(config.sandboxBinding, sandboxId);
63
+ try {
64
+ await sandbox.ping();
65
+ } catch {
66
+ }
67
+ const cloudflareSandbox = {
68
+ sandbox,
69
+ sandboxId,
70
+ exposedPorts: /* @__PURE__ */ new Map()
71
+ };
72
+ return {
73
+ sandbox: cloudflareSandbox,
74
+ sandboxId
75
+ };
76
+ } catch (error) {
77
+ return null;
78
+ }
79
+ },
80
+ list: async (_config) => {
81
+ throw new Error(
82
+ `Cloudflare provider does not support listing sandboxes. Cloudflare sandboxes are managed through Durable Objects and don't have a native list API. Use getById to reconnect to specific sandboxes by ID, or implement your own tracking system.`
83
+ );
84
+ },
85
+ destroy: async (config, sandboxId) => {
86
+ try {
87
+ if (config.sandboxBinding) {
88
+ const sandbox = getSandbox(config.sandboxBinding, sandboxId);
89
+ await sandbox.killAllProcesses();
90
+ }
91
+ } catch (error) {
92
+ }
93
+ },
94
+ // Instance operations (map to individual Sandbox methods)
95
+ runCode: async (cloudflareSandbox, code, runtime) => {
96
+ const startTime = Date.now();
97
+ try {
98
+ const { sandbox, sandboxId } = cloudflareSandbox;
99
+ const detectedRuntime = runtime || detectRuntime(code);
100
+ let result;
101
+ if (detectedRuntime === "python") {
102
+ const execution = await sandbox.runCode(code, { language: "python" });
103
+ let stdout = "";
104
+ let stderr = "";
105
+ if (execution.results && Array.isArray(execution.results)) {
106
+ for (const res of execution.results) {
107
+ if (res.text) {
108
+ stdout += res.text;
109
+ }
110
+ }
111
+ }
112
+ result = {
113
+ stdout,
114
+ stderr,
115
+ exitCode: 0,
116
+ // Cloudflare code interpreter doesn't expose exit codes directly
117
+ executionTime: Date.now() - startTime,
118
+ sandboxId,
119
+ provider: "cloudflare"
120
+ };
121
+ } else {
122
+ const execResult = await sandbox.exec(`node -e "${code.replace(/"/g, '\\"')}"`);
123
+ result = {
124
+ stdout: execResult.stdout || "",
125
+ stderr: execResult.stderr || "",
126
+ exitCode: execResult.exitCode || 0,
127
+ executionTime: Date.now() - startTime,
128
+ sandboxId,
129
+ provider: "cloudflare"
130
+ };
131
+ }
132
+ if (result.stderr && (result.stderr.includes("SyntaxError") || result.stderr.includes("invalid syntax") || result.stderr.includes("Unexpected token"))) {
133
+ throw new Error(`Syntax error: ${result.stderr.trim()}`);
134
+ }
135
+ return result;
136
+ } catch (error) {
137
+ if (error instanceof Error && error.message.includes("Syntax error")) {
138
+ throw error;
139
+ }
140
+ throw new Error(
141
+ `Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`
142
+ );
143
+ }
144
+ },
145
+ runCommand: async (cloudflareSandbox, command, args = []) => {
146
+ const startTime = Date.now();
147
+ try {
148
+ const { sandbox, sandboxId } = cloudflareSandbox;
149
+ const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
150
+ const execResult = await sandbox.exec(fullCommand);
151
+ return {
152
+ stdout: execResult.stdout || "",
153
+ stderr: execResult.stderr || "",
154
+ exitCode: execResult.exitCode || 0,
155
+ executionTime: Date.now() - startTime,
156
+ sandboxId,
157
+ provider: "cloudflare"
158
+ };
159
+ } catch (error) {
160
+ return {
161
+ stdout: "",
162
+ stderr: error instanceof Error ? error.message : String(error),
163
+ exitCode: 127,
164
+ // Command not found exit code
165
+ executionTime: Date.now() - startTime,
166
+ sandboxId: cloudflareSandbox.sandboxId,
167
+ provider: "cloudflare"
168
+ };
169
+ }
170
+ },
171
+ getInfo: async (cloudflareSandbox) => {
172
+ try {
173
+ const { sandbox, sandboxId } = cloudflareSandbox;
174
+ try {
175
+ await sandbox.ping();
176
+ } catch {
177
+ }
178
+ return {
179
+ id: sandboxId,
180
+ provider: "cloudflare",
181
+ runtime: "python",
182
+ // Cloudflare default
183
+ status: "running",
184
+ createdAt: /* @__PURE__ */ new Date(),
185
+ timeout: 3e5,
186
+ metadata: {
187
+ cloudflareSandboxId: sandboxId,
188
+ durableObjectSandbox: true
189
+ }
190
+ };
191
+ } catch (error) {
192
+ return {
193
+ id: cloudflareSandbox.sandboxId,
194
+ provider: "cloudflare",
195
+ runtime: "python",
196
+ status: "error",
197
+ createdAt: /* @__PURE__ */ new Date(),
198
+ timeout: 3e5,
199
+ metadata: {
200
+ cloudflareSandboxId: cloudflareSandbox.sandboxId,
201
+ durableObjectSandbox: true,
202
+ error: error instanceof Error ? error.message : String(error)
203
+ }
204
+ };
205
+ }
206
+ },
207
+ getUrl: async (cloudflareSandbox, options) => {
208
+ try {
209
+ const { sandbox, exposedPorts } = cloudflareSandbox;
210
+ const { port, protocol = "https" } = options;
211
+ if (exposedPorts.has(port)) {
212
+ return exposedPorts.get(port);
213
+ }
214
+ const preview = await sandbox.exposePort(port);
215
+ const url = `${protocol}://${preview.url}`;
216
+ exposedPorts.set(port, url);
217
+ return url;
218
+ } catch (error) {
219
+ throw new Error(
220
+ `Failed to expose port ${options.port}: ${error instanceof Error ? error.message : String(error)}`
221
+ );
222
+ }
223
+ },
224
+ // Filesystem methods - Cloudflare has full filesystem support
225
+ filesystem: {
226
+ readFile: async (cloudflareSandbox, path) => {
227
+ try {
228
+ const { sandbox } = cloudflareSandbox;
229
+ const file = await sandbox.readFile(path);
230
+ return file.content || "";
231
+ } catch (error) {
232
+ throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);
233
+ }
234
+ },
235
+ writeFile: async (cloudflareSandbox, path, content) => {
236
+ try {
237
+ const { sandbox } = cloudflareSandbox;
238
+ await sandbox.writeFile(path, content);
239
+ } catch (error) {
240
+ throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);
241
+ }
242
+ },
243
+ mkdir: async (cloudflareSandbox, path) => {
244
+ try {
245
+ const { sandbox } = cloudflareSandbox;
246
+ await sandbox.mkdir(path);
247
+ } catch (error) {
248
+ throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);
249
+ }
250
+ },
251
+ readdir: async (cloudflareSandbox, path) => {
252
+ try {
253
+ const { sandbox } = cloudflareSandbox;
254
+ const result = await sandbox.exec(`ls -la "${path}"`);
255
+ if (result.exitCode !== 0) {
256
+ throw new Error(`Directory listing failed: ${result.stderr}`);
257
+ }
258
+ const lines = result.stdout.split("\n").filter((line) => line.trim() && !line.startsWith("total"));
259
+ return lines.map((line) => {
260
+ const parts = line.trim().split(/\s+/);
261
+ const permissions = parts[0] || "";
262
+ const size = parseInt(parts[4]) || 0;
263
+ const dateStr = (parts[5] || "") + " " + (parts[6] || "");
264
+ const date = dateStr.trim() ? new Date(dateStr) : /* @__PURE__ */ new Date();
265
+ const name = parts.slice(8).join(" ") || parts[parts.length - 1] || "unknown";
266
+ return {
267
+ name,
268
+ path: `${path}/${name}`.replace("//", "/"),
269
+ isDirectory: permissions.startsWith("d"),
270
+ size,
271
+ lastModified: isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date
272
+ };
273
+ });
274
+ } catch (error) {
275
+ throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);
276
+ }
277
+ },
278
+ exists: async (cloudflareSandbox, path) => {
279
+ try {
280
+ const { sandbox } = cloudflareSandbox;
281
+ const result = await sandbox.exec(`test -e "${path}"`);
282
+ return result.exitCode === 0;
283
+ } catch (error) {
284
+ return false;
285
+ }
286
+ },
287
+ remove: async (cloudflareSandbox, path) => {
288
+ try {
289
+ const { sandbox } = cloudflareSandbox;
290
+ const result = await sandbox.exec(`rm -rf "${path}"`);
291
+ if (result.exitCode !== 0) {
292
+ throw new Error(`Remove failed: ${result.stderr}`);
293
+ }
294
+ } catch (error) {
295
+ throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);
296
+ }
297
+ }
298
+ }
299
+ }
300
+ }
301
+ });
302
+ export {
303
+ cloudflare
304
+ };
305
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Cloudflare Provider - Factory-based Implementation\n * \n * Full-featured provider using Cloudflare Sandbox SDK with all required methods.\n * Leverages Cloudflare's edge network and Durable Objects for sandboxed execution.\n */\n\nimport { getSandbox } from '@cloudflare/sandbox';\nimport { createProvider } from 'computesdk';\nimport type { \n ExecutionResult, \n SandboxInfo, \n Runtime,\n CreateSandboxOptions,\n FileEntry\n} from 'computesdk';\n\n/**\n * Cloudflare-specific configuration options\n */\nexport interface CloudflareConfig {\n /** Cloudflare Sandbox binding from Workers environment - the Durable Object binding */\n sandboxBinding?: any;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Environment variables to pass to sandbox */\n envVars?: Record<string, string>;\n /** Base URL for preview URLs (defaults to worker domain) */\n baseUrl?: string;\n}\n\n/**\n * Cloudflare sandbox wrapper - wraps the Cloudflare Sandbox instance\n */\ninterface CloudflareSandbox {\n sandbox: any; // The actual Cloudflare Sandbox instance from getSandbox()\n sandboxId: string;\n exposedPorts: Map<number, string>; // Track exposed ports and their URLs\n}\n\n/**\n * Detect runtime from code content\n */\nfunction detectRuntime(code: string): Runtime {\n // Strong Python indicators\n if (code.includes('print(') || \n code.includes('import ') ||\n code.includes('def ') ||\n code.includes('sys.') ||\n code.includes('json.') ||\n code.includes('__') ||\n code.includes('f\"') ||\n code.includes(\"f'\") ||\n code.includes('raise ')) {\n return 'python';\n }\n\n // Strong Node.js indicators\n if (code.includes('console.log') || \n code.includes('process.') ||\n code.includes('require(') ||\n code.includes('module.exports') ||\n code.includes('__dirname') ||\n code.includes('__filename')) {\n return 'node';\n }\n\n // Default to Python for Cloudflare (matches their examples)\n return 'python';\n}\n\n/**\n * Create a Cloudflare provider instance using the factory pattern\n */\nexport const cloudflare = createProvider<CloudflareSandbox, CloudflareConfig>({\n name: 'cloudflare',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: CloudflareConfig, options?: CreateSandboxOptions) => {\n // Validate Cloudflare Workers environment binding\n if (!config.sandboxBinding) {\n throw new Error(\n `Missing Cloudflare Sandbox binding. Provide 'sandboxBinding' in config with the Durable Object binding from your Cloudflare Workers environment (env.Sandbox). ` +\n `See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`\n );\n }\n\n const sandboxId = options?.sandboxId || `cf-sandbox-${Date.now()}`;\n\n try {\n // Create or connect to Cloudflare sandbox using getSandbox\n const sandbox = getSandbox(config.sandboxBinding, sandboxId);\n\n // Set environment variables if provided\n if (config.envVars) {\n await sandbox.setEnvVars(config.envVars);\n }\n\n const cloudflareSandbox: CloudflareSandbox = {\n sandbox,\n sandboxId,\n exposedPorts: new Map()\n };\n\n return {\n sandbox: cloudflareSandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('binding')) {\n throw new Error(\n `Cloudflare Sandbox binding failed. Ensure your Durable Object binding is properly configured in wrangler.toml. ` +\n `See https://developers.cloudflare.com/durable-objects/get-started/ for setup instructions.`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/`\n );\n }\n }\n throw new Error(\n `Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: CloudflareConfig, sandboxId: string) => {\n if (!config.sandboxBinding) {\n return null;\n }\n\n try {\n // Reconnect to existing Cloudflare sandbox\n const sandbox = getSandbox(config.sandboxBinding, sandboxId);\n\n // Test connection - Note: ping may not be available on all sandbox versions\n try {\n await (sandbox as any).ping();\n } catch {\n // ping not supported, continue\n }\n\n const cloudflareSandbox: CloudflareSandbox = {\n sandbox,\n sandboxId,\n exposedPorts: new Map()\n };\n\n return {\n sandbox: cloudflareSandbox,\n sandboxId\n };\n } catch (error) {\n // Sandbox doesn't exist or can't be accessed\n return null;\n }\n },\n\n list: async (_config: CloudflareConfig) => {\n throw new Error(\n `Cloudflare provider does not support listing sandboxes. Cloudflare sandboxes are managed through Durable Objects and don't have a native list API. ` +\n `Use getById to reconnect to specific sandboxes by ID, or implement your own tracking system.`\n );\n },\n\n destroy: async (config: CloudflareConfig, sandboxId: string) => {\n try {\n if (config.sandboxBinding) {\n const sandbox = getSandbox(config.sandboxBinding, sandboxId);\n \n // Stop all processes and clean up\n await sandbox.killAllProcesses();\n \n // Note: Cloudflare Durable Objects manage their own lifecycle\n // The actual destruction happens automatically when the object is no longer referenced\n }\n } catch (error) {\n // Sandbox might already be destroyed or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (cloudflareSandbox: CloudflareSandbox, code: string, runtime?: Runtime): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n const { sandbox, sandboxId } = cloudflareSandbox;\n \n // Auto-detect runtime from code if not specified\n const detectedRuntime = runtime || detectRuntime(code);\n \n let result;\n\n if (detectedRuntime === 'python') {\n // Use Cloudflare's code interpreter for Python\n const execution = await sandbox.runCode(code, { language: 'python' });\n \n // Process the execution result\n let stdout = '';\n let stderr = '';\n \n // Handle streaming results if available\n if (execution.results && Array.isArray(execution.results)) {\n for (const res of execution.results) {\n if (res.text) {\n stdout += res.text;\n }\n }\n }\n \n result = {\n stdout,\n stderr,\n exitCode: 0, // Cloudflare code interpreter doesn't expose exit codes directly\n executionTime: Date.now() - startTime,\n sandboxId,\n provider: 'cloudflare'\n };\n } else {\n // For Node.js/JavaScript, use exec with node command\n const execResult = await sandbox.exec(`node -e \"${code.replace(/\"/g, '\\\\\"')}\"`);\n \n result = {\n stdout: execResult.stdout || '',\n stderr: execResult.stderr || '',\n exitCode: execResult.exitCode || 0,\n executionTime: Date.now() - startTime,\n sandboxId,\n provider: 'cloudflare'\n };\n }\n\n // Check for syntax errors\n if (result.stderr && (\n result.stderr.includes('SyntaxError') ||\n result.stderr.includes('invalid syntax') ||\n result.stderr.includes('Unexpected token')\n )) {\n throw new Error(`Syntax error: ${result.stderr.trim()}`);\n }\n\n return result;\n } catch (error) {\n // Re-throw syntax errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error;\n }\n \n throw new Error(\n `Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (cloudflareSandbox: CloudflareSandbox, command: string, args: string[] = []): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n const { sandbox, sandboxId } = cloudflareSandbox;\n \n // Construct full command with arguments\n const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;\n\n // Execute command using Cloudflare's exec method\n const execResult = await sandbox.exec(fullCommand);\n\n return {\n stdout: execResult.stdout || '',\n stderr: execResult.stderr || '',\n exitCode: execResult.exitCode || 0,\n executionTime: Date.now() - startTime,\n sandboxId,\n provider: 'cloudflare'\n };\n } catch (error) {\n // For command failures, return error info instead of throwing\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127, // Command not found exit code\n executionTime: Date.now() - startTime,\n sandboxId: cloudflareSandbox.sandboxId,\n provider: 'cloudflare'\n };\n }\n },\n\n getInfo: async (cloudflareSandbox: CloudflareSandbox): Promise<SandboxInfo> => {\n try {\n const { sandbox, sandboxId } = cloudflareSandbox;\n \n // Test if sandbox is still alive - ping may not be available\n try {\n await (sandbox as any).ping();\n } catch {\n // ping not supported, continue\n }\n\n return {\n id: sandboxId,\n provider: 'cloudflare',\n runtime: 'python', // Cloudflare default\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: sandboxId,\n durableObjectSandbox: true\n }\n };\n } catch (error) {\n return {\n id: cloudflareSandbox.sandboxId,\n provider: 'cloudflare',\n runtime: 'python',\n status: 'error',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: cloudflareSandbox.sandboxId,\n durableObjectSandbox: true,\n error: error instanceof Error ? error.message : String(error)\n }\n };\n }\n },\n\n getUrl: async (cloudflareSandbox: CloudflareSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n const { sandbox, exposedPorts } = cloudflareSandbox;\n const { port, protocol = 'https' } = options;\n\n // Check if port is already exposed\n if (exposedPorts.has(port)) {\n return exposedPorts.get(port)!;\n }\n\n // Expose the port using Cloudflare's exposePort method\n const preview = await sandbox.exposePort(port);\n const url = `${protocol}://${preview.url}`;\n \n // Cache the exposed URL\n exposedPorts.set(port, url);\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to expose port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n // Filesystem methods - Cloudflare has full filesystem support\n filesystem: {\n readFile: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<string> => {\n try {\n const { sandbox } = cloudflareSandbox;\n const file = await sandbox.readFile(path);\n return file.content || '';\n } catch (error) {\n throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n writeFile: async (cloudflareSandbox: CloudflareSandbox, path: string, content: string): Promise<void> => {\n try {\n const { sandbox } = cloudflareSandbox;\n await sandbox.writeFile(path, content);\n } catch (error) {\n throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n mkdir: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<void> => {\n try {\n const { sandbox } = cloudflareSandbox;\n await sandbox.mkdir(path);\n } catch (error) {\n throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n readdir: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<FileEntry[]> => {\n try {\n const { sandbox } = cloudflareSandbox;\n \n // Use ls command to get directory listing\n const result = await sandbox.exec(`ls -la \"${path}\"`);\n \n if (result.exitCode !== 0) {\n throw new Error(`Directory listing failed: ${result.stderr}`);\n }\n\n const lines = result.stdout.split('\\n').filter((line: string) => line.trim() && !line.startsWith('total'));\n\n return lines.map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const permissions = parts[0] || '';\n const size = parseInt(parts[4]) || 0;\n const dateStr = (parts[5] || '') + ' ' + (parts[6] || '');\n const date = dateStr.trim() ? new Date(dateStr) : new Date();\n const name = parts.slice(8).join(' ') || parts[parts.length - 1] || 'unknown';\n\n return {\n name,\n path: `${path}/${name}`.replace('//', '/'),\n isDirectory: permissions.startsWith('d'),\n size,\n lastModified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n } catch (error) {\n throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n exists: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<boolean> => {\n try {\n const { sandbox } = cloudflareSandbox;\n const result = await sandbox.exec(`test -e \"${path}\"`);\n return result.exitCode === 0;\n } catch (error) {\n return false;\n }\n },\n\n remove: async (cloudflareSandbox: CloudflareSandbox, path: string): Promise<void> => {\n try {\n const { sandbox } = cloudflareSandbox;\n const result = await sandbox.exec(`rm -rf \"${path}\"`);\n \n if (result.exitCode !== 0) {\n throw new Error(`Remove failed: ${result.stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n }\n }\n }\n});"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@computesdk/cloudflare",
3
+ "version": "1.0.1",
4
+ "description": "Cloudflare provider for ComputeSDK",
5
+ "author": "Garrison",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@cloudflare/sandbox": "^0.3.0",
22
+ "computesdk": "1.7.0"
23
+ },
24
+ "keywords": [
25
+ "cloudflare",
26
+ "sandbox",
27
+ "code-execution",
28
+ "python",
29
+ "javascript",
30
+ "cloud",
31
+ "compute",
32
+ "durable-objects",
33
+ "workers"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/computesdk/computesdk.git",
38
+ "directory": "packages/cloudflare"
39
+ },
40
+ "homepage": "https://github.com/computesdk/computesdk/tree/main/packages/cloudflare",
41
+ "bugs": {
42
+ "url": "https://github.com/computesdk/computesdk/issues"
43
+ },
44
+ "devDependencies": {
45
+ "@cloudflare/workers-types": "^4.20250826.0",
46
+ "@types/node": "^20.0.0",
47
+ "@vitest/coverage-v8": "^1.0.0",
48
+ "eslint": "^8.37.0",
49
+ "miniflare": "^3.20241106.2",
50
+ "rimraf": "^5.0.0",
51
+ "tsup": "^8.0.0",
52
+ "typescript": "^5.0.0",
53
+ "vitest": "^1.0.0",
54
+ "wrangler": "^3.0.0",
55
+ "@computesdk/test-utils": "1.3.1"
56
+ },
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "clean": "rimraf dist",
60
+ "dev": "tsup --watch",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest watch",
63
+ "test:coverage": "vitest run --coverage",
64
+ "typecheck": "tsc --noEmit",
65
+ "lint": "eslint"
66
+ }
67
+ }