@computesdk/cloudflare 1.4.1 → 1.5.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.
@@ -0,0 +1,33 @@
1
+ import * as _computesdk_provider from '@computesdk/provider';
2
+ import { Runtime } from '@computesdk/provider';
3
+
4
+ interface CloudflareConfig {
5
+ /** URL of the deployed gateway Worker (e.g. https://computesdk-sandbox.user.workers.dev) */
6
+ sandboxUrl?: string;
7
+ /** Shared secret for authenticating with the gateway Worker */
8
+ sandboxSecret?: string;
9
+ /** Cloudflare Sandbox Durable Object binding from Workers environment */
10
+ sandboxBinding?: any;
11
+ /** Default runtime environment */
12
+ runtime?: Runtime;
13
+ /** Execution timeout in milliseconds */
14
+ timeout?: number;
15
+ /** Environment variables to pass to sandbox */
16
+ envVars?: Record<string, string>;
17
+ /** Options passed to getSandbox() for lifecycle control (direct mode only) */
18
+ sandboxOptions?: {
19
+ sleepAfter?: string | number;
20
+ keepAlive?: boolean;
21
+ };
22
+ }
23
+ interface CloudflareSandbox {
24
+ sandboxId: string;
25
+ exposedPorts: Map<number, string>;
26
+ remote: boolean;
27
+ sandboxUrl?: string;
28
+ sandboxSecret?: string;
29
+ sandbox?: any;
30
+ }
31
+ declare const cloudflare: (config: CloudflareConfig) => _computesdk_provider.Provider<CloudflareSandbox, any, any>;
32
+
33
+ export { type CloudflareConfig, cloudflare };
@@ -0,0 +1,33 @@
1
+ import * as _computesdk_provider from '@computesdk/provider';
2
+ import { Runtime } from '@computesdk/provider';
3
+
4
+ interface CloudflareConfig {
5
+ /** URL of the deployed gateway Worker (e.g. https://computesdk-sandbox.user.workers.dev) */
6
+ sandboxUrl?: string;
7
+ /** Shared secret for authenticating with the gateway Worker */
8
+ sandboxSecret?: string;
9
+ /** Cloudflare Sandbox Durable Object binding from Workers environment */
10
+ sandboxBinding?: any;
11
+ /** Default runtime environment */
12
+ runtime?: Runtime;
13
+ /** Execution timeout in milliseconds */
14
+ timeout?: number;
15
+ /** Environment variables to pass to sandbox */
16
+ envVars?: Record<string, string>;
17
+ /** Options passed to getSandbox() for lifecycle control (direct mode only) */
18
+ sandboxOptions?: {
19
+ sleepAfter?: string | number;
20
+ keepAlive?: boolean;
21
+ };
22
+ }
23
+ interface CloudflareSandbox {
24
+ sandboxId: string;
25
+ exposedPorts: Map<number, string>;
26
+ remote: boolean;
27
+ sandboxUrl?: string;
28
+ sandboxSecret?: string;
29
+ sandbox?: any;
30
+ }
31
+ declare const cloudflare: (config: CloudflareConfig) => _computesdk_provider.Provider<CloudflareSandbox, any, any>;
32
+
33
+ export { type CloudflareConfig, cloudflare };
package/dist/index.js ADDED
@@ -0,0 +1,450 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ cloudflare: () => cloudflare
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+ var import_provider = require("@computesdk/provider");
37
+ var _getSandboxFn = null;
38
+ async function getSandbox(binding, id, options) {
39
+ if (!_getSandboxFn) {
40
+ const mod = await import("@cloudflare/sandbox");
41
+ _getSandboxFn = mod.getSandbox;
42
+ }
43
+ return _getSandboxFn(binding, id, options);
44
+ }
45
+ function isRemote(config) {
46
+ return !!(config.sandboxUrl && config.sandboxSecret);
47
+ }
48
+ function detectRuntime(code) {
49
+ 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 ")) {
50
+ return "python";
51
+ }
52
+ if (code.includes("console.log") || code.includes("process.") || code.includes("require(") || code.includes("module.exports") || code.includes("__dirname") || code.includes("__filename")) {
53
+ return "node";
54
+ }
55
+ return "python";
56
+ }
57
+ function runtimeToLanguage(runtime) {
58
+ switch (runtime) {
59
+ case "python":
60
+ return "python";
61
+ case "node":
62
+ return "javascript";
63
+ case "bun":
64
+ return "javascript";
65
+ case "deno":
66
+ return "typescript";
67
+ default:
68
+ return "python";
69
+ }
70
+ }
71
+ async function workerRequest(cfSandbox, path, body = {}) {
72
+ const res = await fetch(`${cfSandbox.sandboxUrl}${path}`, {
73
+ method: "POST",
74
+ headers: {
75
+ "Content-Type": "application/json",
76
+ "Authorization": `Bearer ${cfSandbox.sandboxSecret}`
77
+ },
78
+ body: JSON.stringify({ sandboxId: cfSandbox.sandboxId, ...body })
79
+ });
80
+ let data;
81
+ try {
82
+ data = await res.json();
83
+ } catch {
84
+ const text = await res.text().catch(() => "(unreadable)");
85
+ throw new Error(`Worker request failed: ${res.status} - ${text.slice(0, 200)}`);
86
+ }
87
+ if (!res.ok) {
88
+ throw new Error(data.error || `Worker request failed: ${res.status}`);
89
+ }
90
+ return data;
91
+ }
92
+ function shellEscape(s) {
93
+ return s.replace(/["$`\\!]/g, "\\$&");
94
+ }
95
+ function processExecution(execution, detectedRuntime) {
96
+ const stdoutParts = [];
97
+ const stderrParts = [];
98
+ if (execution.logs) {
99
+ if (execution.logs.stdout) stdoutParts.push(...execution.logs.stdout);
100
+ if (execution.logs.stderr) stderrParts.push(...execution.logs.stderr);
101
+ }
102
+ if (execution.results && Array.isArray(execution.results)) {
103
+ for (const res of execution.results) {
104
+ if (res.text) stdoutParts.push(res.text);
105
+ }
106
+ }
107
+ if (execution.error) {
108
+ const errorMsg = execution.error.message || execution.error.name || "Execution error";
109
+ if (errorMsg.includes("SyntaxError") || errorMsg.includes("invalid syntax")) {
110
+ throw new Error(`Syntax error: ${errorMsg}`);
111
+ }
112
+ stderrParts.push(errorMsg);
113
+ }
114
+ const stdout = stdoutParts.join("\n");
115
+ const stderr = stderrParts.join("\n");
116
+ return {
117
+ output: stderr ? `${stdout}${stdout && stderr ? "\n" : ""}${stderr}` : stdout,
118
+ exitCode: execution.error ? 1 : 0,
119
+ language: detectedRuntime
120
+ };
121
+ }
122
+ function parseLsOutput(stdout) {
123
+ const lines = stdout.split("\n").filter((line) => line.trim() && !line.startsWith("total"));
124
+ return lines.map((line) => {
125
+ const parts = line.trim().split(/\s+/);
126
+ const permissions = parts[0] || "";
127
+ const size = parseInt(parts[4]) || 0;
128
+ const dateStr = (parts[5] || "") + " " + (parts[6] || "");
129
+ const date = dateStr.trim() ? new Date(dateStr) : /* @__PURE__ */ new Date();
130
+ const name = parts.slice(8).join(" ") || parts[parts.length - 1] || "unknown";
131
+ return {
132
+ name,
133
+ type: permissions.startsWith("d") ? "directory" : "file",
134
+ size,
135
+ modified: isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date
136
+ };
137
+ });
138
+ }
139
+ var cloudflare = (0, import_provider.defineProvider)({
140
+ name: "cloudflare",
141
+ methods: {
142
+ sandbox: {
143
+ // ─── Collection operations ───────────────────────────────────────
144
+ create: async (config, options) => {
145
+ const {
146
+ runtime: _runtime,
147
+ timeout: optTimeout,
148
+ envs,
149
+ name: _name,
150
+ metadata: _metadata,
151
+ templateId: _templateId,
152
+ snapshotId: _snapshotId,
153
+ sandboxId: optSandboxId,
154
+ namespace: _namespace,
155
+ directory: _directory,
156
+ overlays: _overlays,
157
+ servers: _servers,
158
+ ports: _ports,
159
+ ...rest
160
+ } = options || {};
161
+ const sandboxId = optSandboxId || `cf-sandbox-${Date.now()}`;
162
+ const envVars = { ...config.envVars, ...envs };
163
+ const timeout = optTimeout ?? config.timeout;
164
+ if (isRemote(config)) {
165
+ await workerRequest(
166
+ { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: /* @__PURE__ */ new Map() },
167
+ "/v1/sandbox/create",
168
+ {
169
+ envVars: Object.keys(envVars).length > 0 ? envVars : void 0,
170
+ ...timeout ? { timeout } : {},
171
+ ...rest
172
+ // Pass through provider-specific options
173
+ }
174
+ );
175
+ return {
176
+ sandbox: {
177
+ sandboxId,
178
+ remote: true,
179
+ sandboxUrl: config.sandboxUrl,
180
+ sandboxSecret: config.sandboxSecret,
181
+ exposedPorts: /* @__PURE__ */ new Map()
182
+ },
183
+ sandboxId
184
+ };
185
+ }
186
+ if (!config.sandboxBinding) {
187
+ throw new Error(
188
+ "Missing Cloudflare config. Either:\n 1. Set CLOUDFLARE_SANDBOX_URL + CLOUDFLARE_SANDBOX_SECRET (remote mode)\n 2. Provide sandboxBinding from your Workers environment (direct mode)\nRun `npx @computesdk/cloudflare` to deploy a gateway Worker."
189
+ );
190
+ }
191
+ try {
192
+ const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);
193
+ if (Object.keys(envVars).length > 0) {
194
+ await sandbox.setEnvVars(envVars);
195
+ }
196
+ return {
197
+ sandbox: {
198
+ sandbox,
199
+ sandboxId,
200
+ remote: false,
201
+ exposedPorts: /* @__PURE__ */ new Map()
202
+ },
203
+ sandboxId
204
+ };
205
+ } catch (error) {
206
+ if (error instanceof Error) {
207
+ if (error.message.includes("unauthorized") || error.message.includes("binding")) {
208
+ throw new Error(
209
+ "Cloudflare Sandbox binding failed. Ensure your Durable Object binding is properly configured in wrangler.toml. See https://developers.cloudflare.com/sandbox/get-started/ for setup instructions."
210
+ );
211
+ }
212
+ if (error.message.includes("quota") || error.message.includes("limit")) {
213
+ throw new Error("Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/");
214
+ }
215
+ }
216
+ throw new Error(`Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`);
217
+ }
218
+ },
219
+ getById: async (config, sandboxId) => {
220
+ if (isRemote(config)) {
221
+ try {
222
+ const cfSandbox = {
223
+ sandboxId,
224
+ remote: true,
225
+ sandboxUrl: config.sandboxUrl,
226
+ sandboxSecret: config.sandboxSecret,
227
+ exposedPorts: /* @__PURE__ */ new Map()
228
+ };
229
+ await workerRequest(cfSandbox, "/v1/sandbox/exec", { command: "true" });
230
+ return { sandbox: cfSandbox, sandboxId };
231
+ } catch {
232
+ return null;
233
+ }
234
+ }
235
+ if (!config.sandboxBinding) return null;
236
+ try {
237
+ const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);
238
+ await sandbox.exec("true");
239
+ return {
240
+ sandbox: { sandbox, sandboxId, remote: false, exposedPorts: /* @__PURE__ */ new Map() },
241
+ sandboxId
242
+ };
243
+ } catch {
244
+ return null;
245
+ }
246
+ },
247
+ list: async (_config) => {
248
+ throw new Error(
249
+ "Cloudflare provider does not support listing sandboxes. Durable Objects do not have a native list API. Use getById to reconnect to specific sandboxes by ID."
250
+ );
251
+ },
252
+ destroy: async (config, sandboxId) => {
253
+ try {
254
+ if (isRemote(config)) {
255
+ await workerRequest(
256
+ { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: /* @__PURE__ */ new Map() },
257
+ "/v1/sandbox/destroy"
258
+ );
259
+ return;
260
+ }
261
+ if (config.sandboxBinding) {
262
+ const sandbox = await getSandbox(config.sandboxBinding, sandboxId);
263
+ await sandbox.destroy();
264
+ }
265
+ } catch {
266
+ }
267
+ },
268
+ // ─── Instance operations ─────────────────────────────────────────
269
+ runCode: async (cfSandbox, code, runtime) => {
270
+ const detectedRuntime = runtime || detectRuntime(code);
271
+ const language = runtimeToLanguage(detectedRuntime);
272
+ if (cfSandbox.remote) {
273
+ const execution = await workerRequest(cfSandbox, "/v1/sandbox/runCode", { code, language });
274
+ return processExecution(execution, detectedRuntime);
275
+ }
276
+ try {
277
+ const execution = await cfSandbox.sandbox.runCode(code, { language });
278
+ return processExecution(execution, detectedRuntime);
279
+ } catch (error) {
280
+ if (error instanceof Error && error.message.includes("Syntax error")) throw error;
281
+ throw new Error(`Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`);
282
+ }
283
+ },
284
+ runCommand: async (cfSandbox, command, options) => {
285
+ const startTime = Date.now();
286
+ if (cfSandbox.remote) {
287
+ try {
288
+ let fullCommand = command;
289
+ if (options?.background) {
290
+ fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
291
+ }
292
+ const result = await workerRequest(cfSandbox, "/v1/sandbox/exec", {
293
+ command: fullCommand,
294
+ cwd: options?.cwd,
295
+ env: options?.env,
296
+ timeout: options?.timeout
297
+ });
298
+ return {
299
+ stdout: result.stdout || "",
300
+ stderr: result.stderr || "",
301
+ exitCode: result.exitCode,
302
+ durationMs: Date.now() - startTime
303
+ };
304
+ } catch (error) {
305
+ return {
306
+ stdout: "",
307
+ stderr: error instanceof Error ? error.message : String(error),
308
+ exitCode: 127,
309
+ durationMs: Date.now() - startTime
310
+ };
311
+ }
312
+ }
313
+ try {
314
+ let fullCommand = command;
315
+ if (options?.background) {
316
+ fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
317
+ }
318
+ const execResult = await cfSandbox.sandbox.exec(fullCommand, {
319
+ cwd: options?.cwd,
320
+ env: options?.env,
321
+ timeout: options?.timeout
322
+ });
323
+ return {
324
+ stdout: execResult.stdout || "",
325
+ stderr: execResult.stderr || "",
326
+ exitCode: execResult.exitCode,
327
+ durationMs: Date.now() - startTime
328
+ };
329
+ } catch (error) {
330
+ return {
331
+ stdout: "",
332
+ stderr: error instanceof Error ? error.message : String(error),
333
+ exitCode: 127,
334
+ durationMs: Date.now() - startTime
335
+ };
336
+ }
337
+ },
338
+ getInfo: async (cfSandbox) => {
339
+ try {
340
+ if (cfSandbox.remote) {
341
+ await workerRequest(cfSandbox, "/v1/sandbox/info");
342
+ } else {
343
+ await cfSandbox.sandbox.exec("true");
344
+ }
345
+ return {
346
+ id: cfSandbox.sandboxId,
347
+ provider: "cloudflare",
348
+ runtime: "python",
349
+ status: "running",
350
+ createdAt: /* @__PURE__ */ new Date(),
351
+ timeout: 3e5,
352
+ metadata: {
353
+ cloudflareSandboxId: cfSandbox.sandboxId,
354
+ mode: cfSandbox.remote ? "remote" : "direct"
355
+ }
356
+ };
357
+ } catch (error) {
358
+ return {
359
+ id: cfSandbox.sandboxId,
360
+ provider: "cloudflare",
361
+ runtime: "python",
362
+ status: "error",
363
+ createdAt: /* @__PURE__ */ new Date(),
364
+ timeout: 3e5,
365
+ metadata: {
366
+ cloudflareSandboxId: cfSandbox.sandboxId,
367
+ mode: cfSandbox.remote ? "remote" : "direct",
368
+ error: error instanceof Error ? error.message : String(error)
369
+ }
370
+ };
371
+ }
372
+ },
373
+ getUrl: async (cfSandbox, options) => {
374
+ const { port, protocol = "https" } = options;
375
+ if (cfSandbox.exposedPorts.has(port)) {
376
+ return cfSandbox.exposedPorts.get(port);
377
+ }
378
+ let preview;
379
+ if (cfSandbox.remote) {
380
+ preview = await workerRequest(cfSandbox, "/v1/sandbox/exposePort", { port, options: {} });
381
+ } else {
382
+ preview = await cfSandbox.sandbox.exposePort(port, {});
383
+ }
384
+ const url = `${protocol}://${preview.url}`;
385
+ cfSandbox.exposedPorts.set(port, url);
386
+ return url;
387
+ },
388
+ // ─── Filesystem ────────────────────────────────────────────────
389
+ filesystem: {
390
+ readFile: async (cfSandbox, path) => {
391
+ if (cfSandbox.remote) {
392
+ const file2 = await workerRequest(cfSandbox, "/v1/sandbox/readFile", { path });
393
+ return file2.content || "";
394
+ }
395
+ const file = await cfSandbox.sandbox.readFile(path);
396
+ return file.content || "";
397
+ },
398
+ writeFile: async (cfSandbox, path, content) => {
399
+ if (cfSandbox.remote) {
400
+ await workerRequest(cfSandbox, "/v1/sandbox/writeFile", { path, content });
401
+ return;
402
+ }
403
+ await cfSandbox.sandbox.writeFile(path, content);
404
+ },
405
+ mkdir: async (cfSandbox, path) => {
406
+ if (cfSandbox.remote) {
407
+ await workerRequest(cfSandbox, "/v1/sandbox/mkdir", { path });
408
+ return;
409
+ }
410
+ await cfSandbox.sandbox.mkdir(path, { recursive: true });
411
+ },
412
+ readdir: async (cfSandbox, path) => {
413
+ let result;
414
+ if (cfSandbox.remote) {
415
+ result = await workerRequest(cfSandbox, "/v1/sandbox/exec", {
416
+ command: `ls -la "${shellEscape(path)}"`,
417
+ cwd: "/"
418
+ });
419
+ } else {
420
+ result = await cfSandbox.sandbox.exec(`ls -la "${shellEscape(path)}"`, { cwd: "/" });
421
+ }
422
+ if (result.exitCode !== 0) {
423
+ throw new Error(`Directory listing failed: ${result.stderr}`);
424
+ }
425
+ return parseLsOutput(result.stdout);
426
+ },
427
+ exists: async (cfSandbox, path) => {
428
+ if (cfSandbox.remote) {
429
+ const result2 = await workerRequest(cfSandbox, "/v1/sandbox/exists", { path });
430
+ return result2.exists;
431
+ }
432
+ const result = await cfSandbox.sandbox.exists(path);
433
+ return result.exists;
434
+ },
435
+ remove: async (cfSandbox, path) => {
436
+ if (cfSandbox.remote) {
437
+ await workerRequest(cfSandbox, "/v1/sandbox/deleteFile", { path });
438
+ return;
439
+ }
440
+ await cfSandbox.sandbox.deleteFile(path);
441
+ }
442
+ }
443
+ }
444
+ }
445
+ });
446
+ // Annotate the CommonJS export names for ESM import in node:
447
+ 0 && (module.exports = {
448
+ cloudflare
449
+ });
450
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Cloudflare Provider - Factory-based Implementation (Dual-Mode)\n *\n * Supports two connection modes:\n *\n * 1. **Remote mode** — User deploys a gateway Worker to their Cloudflare account\n * via `npx @computesdk/cloudflare`, then connects from anywhere using\n * CLOUDFLARE_SANDBOX_URL + CLOUDFLARE_SANDBOX_SECRET.\n *\n * 2. **Direct mode** — User's code runs inside a Cloudflare Worker with the\n * Durable Object binding available. Uses the @cloudflare/sandbox SDK directly.\n *\n * The mode is selected automatically based on which config fields are provided.\n */\n\nimport { defineProvider } from '@computesdk/provider';\n\n/**\n * Lazy-load @cloudflare/sandbox to avoid importing it in Node.js environments.\n * The SDK only works inside the Cloudflare Workers runtime (its transitive dep\n * @cloudflare/containers uses extensionless ESM imports that break in Node).\n * Remote mode never needs this import.\n */\nlet _getSandboxFn: ((binding: any, id: string, options?: any) => any) | null = null;\nasync function getSandbox(binding: any, id: string, options?: any): Promise<any> {\n if (!_getSandboxFn) {\n const mod = await import('@cloudflare/sandbox');\n _getSandboxFn = mod.getSandbox as (binding: any, id: string, options?: any) => any;\n }\n return _getSandboxFn(binding, id, options);\n}\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\n// ─── Config ──────────────────────────────────────────────────────────────────\n\nexport interface CloudflareConfig {\n // Remote mode (from anywhere — talks to deployed gateway Worker)\n /** URL of the deployed gateway Worker (e.g. https://computesdk-sandbox.user.workers.dev) */\n sandboxUrl?: string;\n /** Shared secret for authenticating with the gateway Worker */\n sandboxSecret?: string;\n\n // Direct mode (inside a Cloudflare Worker — uses DO binding)\n /** Cloudflare Sandbox Durable Object binding from Workers environment */\n sandboxBinding?: any;\n\n // Shared options\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 /** Options passed to getSandbox() for lifecycle control (direct mode only) */\n sandboxOptions?: {\n sleepAfter?: string | number;\n keepAlive?: boolean;\n };\n}\n\n// ─── Internal types ──────────────────────────────────────────────────────────\n\ninterface CloudflareSandbox {\n sandboxId: string;\n exposedPorts: Map<number, string>;\n // Remote mode fields\n remote: boolean;\n sandboxUrl?: string;\n sandboxSecret?: string;\n // Direct mode fields\n sandbox?: any; // The @cloudflare/sandbox instance\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction isRemote(config: CloudflareConfig): boolean {\n return !!(config.sandboxUrl && config.sandboxSecret);\n}\n\nfunction detectRuntime(code: string): Runtime {\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 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 return 'python';\n}\n\nfunction runtimeToLanguage(runtime: Runtime): 'python' | 'javascript' | 'typescript' {\n switch (runtime) {\n case 'python': return 'python';\n case 'node': return 'javascript';\n case 'bun': return 'javascript';\n case 'deno': return 'typescript';\n default: return 'python';\n }\n}\n\n/**\n * Make an authenticated request to the remote gateway Worker\n */\nasync function workerRequest(\n cfSandbox: CloudflareSandbox,\n path: string,\n body: Record<string, any> = {}\n): Promise<any> {\n const res = await fetch(`${cfSandbox.sandboxUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${cfSandbox.sandboxSecret}`,\n },\n body: JSON.stringify({ sandboxId: cfSandbox.sandboxId, ...body }),\n });\n\n let data: any;\n try {\n data = await res.json();\n } catch {\n const text = await res.text().catch(() => '(unreadable)');\n throw new Error(`Worker request failed: ${res.status} - ${text.slice(0, 200)}`);\n }\n\n if (!res.ok) {\n throw new Error(data.error || `Worker request failed: ${res.status}`);\n }\n\n return data;\n}\n\n/**\n * Escape a string for safe use inside double-quoted shell arguments.\n */\nfunction shellEscape(s: string): string {\n return s.replace(/[\"$`\\\\!]/g, '\\\\$&');\n}\n\n/**\n * Process code execution results into a CodeResult (shared by remote and direct modes)\n */\nfunction processExecution(execution: any, detectedRuntime: Runtime): CodeResult {\n const stdoutParts: string[] = [];\n const stderrParts: string[] = [];\n\n if (execution.logs) {\n if (execution.logs.stdout) stdoutParts.push(...execution.logs.stdout);\n if (execution.logs.stderr) stderrParts.push(...execution.logs.stderr);\n }\n if (execution.results && Array.isArray(execution.results)) {\n for (const res of execution.results) {\n if (res.text) stdoutParts.push(res.text);\n }\n }\n if (execution.error) {\n const errorMsg = execution.error.message || execution.error.name || 'Execution error';\n if (errorMsg.includes('SyntaxError') || errorMsg.includes('invalid syntax')) {\n throw new Error(`Syntax error: ${errorMsg}`);\n }\n stderrParts.push(errorMsg);\n }\n\n const stdout = stdoutParts.join('\\n');\n const stderr = stderrParts.join('\\n');\n\n return {\n output: stderr ? `${stdout}${stdout && stderr ? '\\n' : ''}${stderr}` : stdout,\n exitCode: execution.error ? 1 : 0,\n language: detectedRuntime\n };\n}\n\n/**\n * Parse ls -la output into FileEntry objects (used by both modes for readdir)\n */\nfunction parseLsOutput(stdout: string): FileEntry[] {\n const lines = 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 type: permissions.startsWith('d') ? 'directory' as const : 'file' as const,\n size,\n modified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n}\n\n// ─── Provider ────────────────────────────────────────────────────────────────\n\nexport const cloudflare = defineProvider<CloudflareSandbox, CloudflareConfig>({\n name: 'cloudflare',\n methods: {\n sandbox: {\n // ─── Collection operations ───────────────────────────────────────\n\n create: async (config: CloudflareConfig, options?: CreateSandboxOptions) => {\n // Destructure known ComputeSDK fields, collect the rest for passthrough\n const {\n runtime: _runtime,\n timeout: optTimeout,\n envs,\n name: _name,\n metadata: _metadata,\n templateId: _templateId,\n snapshotId: _snapshotId,\n sandboxId: optSandboxId,\n namespace: _namespace,\n directory: _directory,\n overlays: _overlays,\n servers: _servers,\n ports: _ports,\n ...rest\n } = options || {};\n\n const sandboxId = optSandboxId || `cf-sandbox-${Date.now()}`;\n const envVars = { ...config.envVars, ...envs };\n // options.timeout takes precedence over config.timeout\n const timeout = optTimeout ?? config.timeout;\n\n // Remote mode\n if (isRemote(config)) {\n await workerRequest(\n { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: new Map() },\n '/v1/sandbox/create',\n {\n envVars: Object.keys(envVars).length > 0 ? envVars : undefined,\n ...(timeout ? { timeout } : {}),\n ...rest, // Pass through provider-specific options\n }\n );\n\n return {\n sandbox: {\n sandboxId,\n remote: true,\n sandboxUrl: config.sandboxUrl,\n sandboxSecret: config.sandboxSecret,\n exposedPorts: new Map(),\n },\n sandboxId\n };\n }\n\n // Direct mode\n if (!config.sandboxBinding) {\n throw new Error(\n 'Missing Cloudflare config. Either:\\n' +\n ' 1. Set CLOUDFLARE_SANDBOX_URL + CLOUDFLARE_SANDBOX_SECRET (remote mode)\\n' +\n ' 2. Provide sandboxBinding from your Workers environment (direct mode)\\n' +\n 'Run `npx @computesdk/cloudflare` to deploy a gateway Worker.'\n );\n }\n\n try {\n const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);\n\n if (Object.keys(envVars).length > 0) {\n await sandbox.setEnvVars(envVars);\n }\n\n return {\n sandbox: {\n sandbox,\n sandboxId,\n remote: false,\n exposedPorts: new Map(),\n },\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/sandbox/get-started/ for setup instructions.'\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error('Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/');\n }\n }\n throw new Error(`Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n getById: async (config: CloudflareConfig, sandboxId: string) => {\n // Remote mode\n if (isRemote(config)) {\n try {\n const cfSandbox: CloudflareSandbox = {\n sandboxId,\n remote: true,\n sandboxUrl: config.sandboxUrl,\n sandboxSecret: config.sandboxSecret,\n exposedPorts: new Map(),\n };\n // Verify sandbox is alive\n await workerRequest(cfSandbox, '/v1/sandbox/exec', { command: 'true' });\n return { sandbox: cfSandbox, sandboxId };\n } catch {\n return null;\n }\n }\n\n // Direct mode\n if (!config.sandboxBinding) return null;\n\n try {\n const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);\n await sandbox.exec('true');\n return {\n sandbox: { sandbox, sandboxId, remote: false, exposedPorts: new Map() },\n sandboxId\n };\n } catch {\n return null;\n }\n },\n\n list: async (_config: CloudflareConfig) => {\n throw new Error(\n 'Cloudflare provider does not support listing sandboxes. ' +\n 'Durable Objects do not have a native list API. ' +\n 'Use getById to reconnect to specific sandboxes by ID.'\n );\n },\n\n destroy: async (config: CloudflareConfig, sandboxId: string) => {\n try {\n if (isRemote(config)) {\n await workerRequest(\n { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: new Map() },\n '/v1/sandbox/destroy'\n );\n return;\n }\n\n if (config.sandboxBinding) {\n const sandbox = await getSandbox(config.sandboxBinding, sandboxId);\n await sandbox.destroy();\n }\n } catch {\n // Sandbox might already be destroyed\n }\n },\n\n // ─── Instance operations ─────────────────────────────────────────\n\n runCode: async (cfSandbox: CloudflareSandbox, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const detectedRuntime = runtime || detectRuntime(code);\n const language = runtimeToLanguage(detectedRuntime);\n\n // Remote mode\n if (cfSandbox.remote) {\n const execution = await workerRequest(cfSandbox, '/v1/sandbox/runCode', { code, language });\n return processExecution(execution, detectedRuntime);\n }\n\n // Direct mode\n try {\n const execution = await cfSandbox.sandbox.runCode(code, { language });\n return processExecution(execution, detectedRuntime);\n } catch (error) {\n if (error instanceof Error && error.message.includes('Syntax error')) throw error;\n throw new Error(`Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n runCommand: async (cfSandbox: CloudflareSandbox, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n const startTime = Date.now();\n\n // Remote mode\n if (cfSandbox.remote) {\n try {\n let fullCommand = command;\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n const result = await workerRequest(cfSandbox, '/v1/sandbox/exec', {\n command: fullCommand,\n cwd: options?.cwd,\n env: options?.env,\n timeout: options?.timeout,\n });\n\n return {\n stdout: result.stdout || '',\n stderr: result.stderr || '',\n exitCode: result.exitCode,\n durationMs: Date.now() - startTime\n };\n } catch (error) {\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127,\n durationMs: Date.now() - startTime\n };\n }\n }\n\n // Direct mode\n try {\n let fullCommand = command;\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n const execResult = await cfSandbox.sandbox.exec(fullCommand, {\n cwd: options?.cwd,\n env: options?.env,\n timeout: options?.timeout,\n });\n\n return {\n stdout: execResult.stdout || '',\n stderr: execResult.stderr || '',\n exitCode: execResult.exitCode,\n durationMs: Date.now() - startTime\n };\n } catch (error) {\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127,\n durationMs: Date.now() - startTime\n };\n }\n },\n\n getInfo: async (cfSandbox: CloudflareSandbox): Promise<SandboxInfo> => {\n try {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/info');\n } else {\n await cfSandbox.sandbox.exec('true');\n }\n\n return {\n id: cfSandbox.sandboxId,\n provider: 'cloudflare',\n runtime: 'python',\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: cfSandbox.sandboxId,\n mode: cfSandbox.remote ? 'remote' : 'direct',\n }\n };\n } catch (error) {\n return {\n id: cfSandbox.sandboxId,\n provider: 'cloudflare',\n runtime: 'python',\n status: 'error',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: cfSandbox.sandboxId,\n mode: cfSandbox.remote ? 'remote' : 'direct',\n error: error instanceof Error ? error.message : String(error)\n }\n };\n }\n },\n\n getUrl: async (cfSandbox: CloudflareSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n const { port, protocol = 'https' } = options;\n\n if (cfSandbox.exposedPorts.has(port)) {\n return cfSandbox.exposedPorts.get(port)!;\n }\n\n let preview: any;\n if (cfSandbox.remote) {\n preview = await workerRequest(cfSandbox, '/v1/sandbox/exposePort', { port, options: {} });\n } else {\n preview = await cfSandbox.sandbox.exposePort(port, {});\n }\n\n const url = `${protocol}://${preview.url}`;\n cfSandbox.exposedPorts.set(port, url);\n return url;\n },\n\n // ─── Filesystem ────────────────────────────────────────────────\n\n filesystem: {\n readFile: async (cfSandbox: CloudflareSandbox, path: string): Promise<string> => {\n if (cfSandbox.remote) {\n const file = await workerRequest(cfSandbox, '/v1/sandbox/readFile', { path });\n return file.content || '';\n }\n const file = await cfSandbox.sandbox.readFile(path);\n return file.content || '';\n },\n\n writeFile: async (cfSandbox: CloudflareSandbox, path: string, content: string): Promise<void> => {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/writeFile', { path, content });\n return;\n }\n await cfSandbox.sandbox.writeFile(path, content);\n },\n\n mkdir: async (cfSandbox: CloudflareSandbox, path: string): Promise<void> => {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/mkdir', { path });\n return;\n }\n await cfSandbox.sandbox.mkdir(path, { recursive: true });\n },\n\n readdir: async (cfSandbox: CloudflareSandbox, path: string): Promise<FileEntry[]> => {\n // Both modes use ls -la since there's no native readdir\n let result: any;\n if (cfSandbox.remote) {\n result = await workerRequest(cfSandbox, '/v1/sandbox/exec', {\n command: `ls -la \"${shellEscape(path)}\"`,\n cwd: '/',\n });\n } else {\n result = await cfSandbox.sandbox.exec(`ls -la \"${shellEscape(path)}\"`, { cwd: '/' });\n }\n\n if (result.exitCode !== 0) {\n throw new Error(`Directory listing failed: ${result.stderr}`);\n }\n\n return parseLsOutput(result.stdout);\n },\n\n exists: async (cfSandbox: CloudflareSandbox, path: string): Promise<boolean> => {\n if (cfSandbox.remote) {\n const result = await workerRequest(cfSandbox, '/v1/sandbox/exists', { path });\n return result.exists;\n }\n const result = await cfSandbox.sandbox.exists(path);\n return result.exists;\n },\n\n remove: async (cfSandbox: CloudflareSandbox, path: string): Promise<void> => {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/deleteFile', { path });\n return;\n }\n await cfSandbox.sandbox.deleteFile(path);\n }\n }\n }\n }\n});\n"],"mappings":"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","names":["file","result"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,415 @@
1
+ // src/index.ts
2
+ import { defineProvider } from "@computesdk/provider";
3
+ var _getSandboxFn = null;
4
+ async function getSandbox(binding, id, options) {
5
+ if (!_getSandboxFn) {
6
+ const mod = await import("@cloudflare/sandbox");
7
+ _getSandboxFn = mod.getSandbox;
8
+ }
9
+ return _getSandboxFn(binding, id, options);
10
+ }
11
+ function isRemote(config) {
12
+ return !!(config.sandboxUrl && config.sandboxSecret);
13
+ }
14
+ function detectRuntime(code) {
15
+ 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 ")) {
16
+ return "python";
17
+ }
18
+ if (code.includes("console.log") || code.includes("process.") || code.includes("require(") || code.includes("module.exports") || code.includes("__dirname") || code.includes("__filename")) {
19
+ return "node";
20
+ }
21
+ return "python";
22
+ }
23
+ function runtimeToLanguage(runtime) {
24
+ switch (runtime) {
25
+ case "python":
26
+ return "python";
27
+ case "node":
28
+ return "javascript";
29
+ case "bun":
30
+ return "javascript";
31
+ case "deno":
32
+ return "typescript";
33
+ default:
34
+ return "python";
35
+ }
36
+ }
37
+ async function workerRequest(cfSandbox, path, body = {}) {
38
+ const res = await fetch(`${cfSandbox.sandboxUrl}${path}`, {
39
+ method: "POST",
40
+ headers: {
41
+ "Content-Type": "application/json",
42
+ "Authorization": `Bearer ${cfSandbox.sandboxSecret}`
43
+ },
44
+ body: JSON.stringify({ sandboxId: cfSandbox.sandboxId, ...body })
45
+ });
46
+ let data;
47
+ try {
48
+ data = await res.json();
49
+ } catch {
50
+ const text = await res.text().catch(() => "(unreadable)");
51
+ throw new Error(`Worker request failed: ${res.status} - ${text.slice(0, 200)}`);
52
+ }
53
+ if (!res.ok) {
54
+ throw new Error(data.error || `Worker request failed: ${res.status}`);
55
+ }
56
+ return data;
57
+ }
58
+ function shellEscape(s) {
59
+ return s.replace(/["$`\\!]/g, "\\$&");
60
+ }
61
+ function processExecution(execution, detectedRuntime) {
62
+ const stdoutParts = [];
63
+ const stderrParts = [];
64
+ if (execution.logs) {
65
+ if (execution.logs.stdout) stdoutParts.push(...execution.logs.stdout);
66
+ if (execution.logs.stderr) stderrParts.push(...execution.logs.stderr);
67
+ }
68
+ if (execution.results && Array.isArray(execution.results)) {
69
+ for (const res of execution.results) {
70
+ if (res.text) stdoutParts.push(res.text);
71
+ }
72
+ }
73
+ if (execution.error) {
74
+ const errorMsg = execution.error.message || execution.error.name || "Execution error";
75
+ if (errorMsg.includes("SyntaxError") || errorMsg.includes("invalid syntax")) {
76
+ throw new Error(`Syntax error: ${errorMsg}`);
77
+ }
78
+ stderrParts.push(errorMsg);
79
+ }
80
+ const stdout = stdoutParts.join("\n");
81
+ const stderr = stderrParts.join("\n");
82
+ return {
83
+ output: stderr ? `${stdout}${stdout && stderr ? "\n" : ""}${stderr}` : stdout,
84
+ exitCode: execution.error ? 1 : 0,
85
+ language: detectedRuntime
86
+ };
87
+ }
88
+ function parseLsOutput(stdout) {
89
+ const lines = stdout.split("\n").filter((line) => line.trim() && !line.startsWith("total"));
90
+ return lines.map((line) => {
91
+ const parts = line.trim().split(/\s+/);
92
+ const permissions = parts[0] || "";
93
+ const size = parseInt(parts[4]) || 0;
94
+ const dateStr = (parts[5] || "") + " " + (parts[6] || "");
95
+ const date = dateStr.trim() ? new Date(dateStr) : /* @__PURE__ */ new Date();
96
+ const name = parts.slice(8).join(" ") || parts[parts.length - 1] || "unknown";
97
+ return {
98
+ name,
99
+ type: permissions.startsWith("d") ? "directory" : "file",
100
+ size,
101
+ modified: isNaN(date.getTime()) ? /* @__PURE__ */ new Date() : date
102
+ };
103
+ });
104
+ }
105
+ var cloudflare = defineProvider({
106
+ name: "cloudflare",
107
+ methods: {
108
+ sandbox: {
109
+ // ─── Collection operations ───────────────────────────────────────
110
+ create: async (config, options) => {
111
+ const {
112
+ runtime: _runtime,
113
+ timeout: optTimeout,
114
+ envs,
115
+ name: _name,
116
+ metadata: _metadata,
117
+ templateId: _templateId,
118
+ snapshotId: _snapshotId,
119
+ sandboxId: optSandboxId,
120
+ namespace: _namespace,
121
+ directory: _directory,
122
+ overlays: _overlays,
123
+ servers: _servers,
124
+ ports: _ports,
125
+ ...rest
126
+ } = options || {};
127
+ const sandboxId = optSandboxId || `cf-sandbox-${Date.now()}`;
128
+ const envVars = { ...config.envVars, ...envs };
129
+ const timeout = optTimeout ?? config.timeout;
130
+ if (isRemote(config)) {
131
+ await workerRequest(
132
+ { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: /* @__PURE__ */ new Map() },
133
+ "/v1/sandbox/create",
134
+ {
135
+ envVars: Object.keys(envVars).length > 0 ? envVars : void 0,
136
+ ...timeout ? { timeout } : {},
137
+ ...rest
138
+ // Pass through provider-specific options
139
+ }
140
+ );
141
+ return {
142
+ sandbox: {
143
+ sandboxId,
144
+ remote: true,
145
+ sandboxUrl: config.sandboxUrl,
146
+ sandboxSecret: config.sandboxSecret,
147
+ exposedPorts: /* @__PURE__ */ new Map()
148
+ },
149
+ sandboxId
150
+ };
151
+ }
152
+ if (!config.sandboxBinding) {
153
+ throw new Error(
154
+ "Missing Cloudflare config. Either:\n 1. Set CLOUDFLARE_SANDBOX_URL + CLOUDFLARE_SANDBOX_SECRET (remote mode)\n 2. Provide sandboxBinding from your Workers environment (direct mode)\nRun `npx @computesdk/cloudflare` to deploy a gateway Worker."
155
+ );
156
+ }
157
+ try {
158
+ const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);
159
+ if (Object.keys(envVars).length > 0) {
160
+ await sandbox.setEnvVars(envVars);
161
+ }
162
+ return {
163
+ sandbox: {
164
+ sandbox,
165
+ sandboxId,
166
+ remote: false,
167
+ exposedPorts: /* @__PURE__ */ new Map()
168
+ },
169
+ sandboxId
170
+ };
171
+ } catch (error) {
172
+ if (error instanceof Error) {
173
+ if (error.message.includes("unauthorized") || error.message.includes("binding")) {
174
+ throw new Error(
175
+ "Cloudflare Sandbox binding failed. Ensure your Durable Object binding is properly configured in wrangler.toml. See https://developers.cloudflare.com/sandbox/get-started/ for setup instructions."
176
+ );
177
+ }
178
+ if (error.message.includes("quota") || error.message.includes("limit")) {
179
+ throw new Error("Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/");
180
+ }
181
+ }
182
+ throw new Error(`Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`);
183
+ }
184
+ },
185
+ getById: async (config, sandboxId) => {
186
+ if (isRemote(config)) {
187
+ try {
188
+ const cfSandbox = {
189
+ sandboxId,
190
+ remote: true,
191
+ sandboxUrl: config.sandboxUrl,
192
+ sandboxSecret: config.sandboxSecret,
193
+ exposedPorts: /* @__PURE__ */ new Map()
194
+ };
195
+ await workerRequest(cfSandbox, "/v1/sandbox/exec", { command: "true" });
196
+ return { sandbox: cfSandbox, sandboxId };
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
201
+ if (!config.sandboxBinding) return null;
202
+ try {
203
+ const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);
204
+ await sandbox.exec("true");
205
+ return {
206
+ sandbox: { sandbox, sandboxId, remote: false, exposedPorts: /* @__PURE__ */ new Map() },
207
+ sandboxId
208
+ };
209
+ } catch {
210
+ return null;
211
+ }
212
+ },
213
+ list: async (_config) => {
214
+ throw new Error(
215
+ "Cloudflare provider does not support listing sandboxes. Durable Objects do not have a native list API. Use getById to reconnect to specific sandboxes by ID."
216
+ );
217
+ },
218
+ destroy: async (config, sandboxId) => {
219
+ try {
220
+ if (isRemote(config)) {
221
+ await workerRequest(
222
+ { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: /* @__PURE__ */ new Map() },
223
+ "/v1/sandbox/destroy"
224
+ );
225
+ return;
226
+ }
227
+ if (config.sandboxBinding) {
228
+ const sandbox = await getSandbox(config.sandboxBinding, sandboxId);
229
+ await sandbox.destroy();
230
+ }
231
+ } catch {
232
+ }
233
+ },
234
+ // ─── Instance operations ─────────────────────────────────────────
235
+ runCode: async (cfSandbox, code, runtime) => {
236
+ const detectedRuntime = runtime || detectRuntime(code);
237
+ const language = runtimeToLanguage(detectedRuntime);
238
+ if (cfSandbox.remote) {
239
+ const execution = await workerRequest(cfSandbox, "/v1/sandbox/runCode", { code, language });
240
+ return processExecution(execution, detectedRuntime);
241
+ }
242
+ try {
243
+ const execution = await cfSandbox.sandbox.runCode(code, { language });
244
+ return processExecution(execution, detectedRuntime);
245
+ } catch (error) {
246
+ if (error instanceof Error && error.message.includes("Syntax error")) throw error;
247
+ throw new Error(`Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`);
248
+ }
249
+ },
250
+ runCommand: async (cfSandbox, command, options) => {
251
+ const startTime = Date.now();
252
+ if (cfSandbox.remote) {
253
+ try {
254
+ let fullCommand = command;
255
+ if (options?.background) {
256
+ fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
257
+ }
258
+ const result = await workerRequest(cfSandbox, "/v1/sandbox/exec", {
259
+ command: fullCommand,
260
+ cwd: options?.cwd,
261
+ env: options?.env,
262
+ timeout: options?.timeout
263
+ });
264
+ return {
265
+ stdout: result.stdout || "",
266
+ stderr: result.stderr || "",
267
+ exitCode: result.exitCode,
268
+ durationMs: Date.now() - startTime
269
+ };
270
+ } catch (error) {
271
+ return {
272
+ stdout: "",
273
+ stderr: error instanceof Error ? error.message : String(error),
274
+ exitCode: 127,
275
+ durationMs: Date.now() - startTime
276
+ };
277
+ }
278
+ }
279
+ try {
280
+ let fullCommand = command;
281
+ if (options?.background) {
282
+ fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
283
+ }
284
+ const execResult = await cfSandbox.sandbox.exec(fullCommand, {
285
+ cwd: options?.cwd,
286
+ env: options?.env,
287
+ timeout: options?.timeout
288
+ });
289
+ return {
290
+ stdout: execResult.stdout || "",
291
+ stderr: execResult.stderr || "",
292
+ exitCode: execResult.exitCode,
293
+ durationMs: Date.now() - startTime
294
+ };
295
+ } catch (error) {
296
+ return {
297
+ stdout: "",
298
+ stderr: error instanceof Error ? error.message : String(error),
299
+ exitCode: 127,
300
+ durationMs: Date.now() - startTime
301
+ };
302
+ }
303
+ },
304
+ getInfo: async (cfSandbox) => {
305
+ try {
306
+ if (cfSandbox.remote) {
307
+ await workerRequest(cfSandbox, "/v1/sandbox/info");
308
+ } else {
309
+ await cfSandbox.sandbox.exec("true");
310
+ }
311
+ return {
312
+ id: cfSandbox.sandboxId,
313
+ provider: "cloudflare",
314
+ runtime: "python",
315
+ status: "running",
316
+ createdAt: /* @__PURE__ */ new Date(),
317
+ timeout: 3e5,
318
+ metadata: {
319
+ cloudflareSandboxId: cfSandbox.sandboxId,
320
+ mode: cfSandbox.remote ? "remote" : "direct"
321
+ }
322
+ };
323
+ } catch (error) {
324
+ return {
325
+ id: cfSandbox.sandboxId,
326
+ provider: "cloudflare",
327
+ runtime: "python",
328
+ status: "error",
329
+ createdAt: /* @__PURE__ */ new Date(),
330
+ timeout: 3e5,
331
+ metadata: {
332
+ cloudflareSandboxId: cfSandbox.sandboxId,
333
+ mode: cfSandbox.remote ? "remote" : "direct",
334
+ error: error instanceof Error ? error.message : String(error)
335
+ }
336
+ };
337
+ }
338
+ },
339
+ getUrl: async (cfSandbox, options) => {
340
+ const { port, protocol = "https" } = options;
341
+ if (cfSandbox.exposedPorts.has(port)) {
342
+ return cfSandbox.exposedPorts.get(port);
343
+ }
344
+ let preview;
345
+ if (cfSandbox.remote) {
346
+ preview = await workerRequest(cfSandbox, "/v1/sandbox/exposePort", { port, options: {} });
347
+ } else {
348
+ preview = await cfSandbox.sandbox.exposePort(port, {});
349
+ }
350
+ const url = `${protocol}://${preview.url}`;
351
+ cfSandbox.exposedPorts.set(port, url);
352
+ return url;
353
+ },
354
+ // ─── Filesystem ────────────────────────────────────────────────
355
+ filesystem: {
356
+ readFile: async (cfSandbox, path) => {
357
+ if (cfSandbox.remote) {
358
+ const file2 = await workerRequest(cfSandbox, "/v1/sandbox/readFile", { path });
359
+ return file2.content || "";
360
+ }
361
+ const file = await cfSandbox.sandbox.readFile(path);
362
+ return file.content || "";
363
+ },
364
+ writeFile: async (cfSandbox, path, content) => {
365
+ if (cfSandbox.remote) {
366
+ await workerRequest(cfSandbox, "/v1/sandbox/writeFile", { path, content });
367
+ return;
368
+ }
369
+ await cfSandbox.sandbox.writeFile(path, content);
370
+ },
371
+ mkdir: async (cfSandbox, path) => {
372
+ if (cfSandbox.remote) {
373
+ await workerRequest(cfSandbox, "/v1/sandbox/mkdir", { path });
374
+ return;
375
+ }
376
+ await cfSandbox.sandbox.mkdir(path, { recursive: true });
377
+ },
378
+ readdir: async (cfSandbox, path) => {
379
+ let result;
380
+ if (cfSandbox.remote) {
381
+ result = await workerRequest(cfSandbox, "/v1/sandbox/exec", {
382
+ command: `ls -la "${shellEscape(path)}"`,
383
+ cwd: "/"
384
+ });
385
+ } else {
386
+ result = await cfSandbox.sandbox.exec(`ls -la "${shellEscape(path)}"`, { cwd: "/" });
387
+ }
388
+ if (result.exitCode !== 0) {
389
+ throw new Error(`Directory listing failed: ${result.stderr}`);
390
+ }
391
+ return parseLsOutput(result.stdout);
392
+ },
393
+ exists: async (cfSandbox, path) => {
394
+ if (cfSandbox.remote) {
395
+ const result2 = await workerRequest(cfSandbox, "/v1/sandbox/exists", { path });
396
+ return result2.exists;
397
+ }
398
+ const result = await cfSandbox.sandbox.exists(path);
399
+ return result.exists;
400
+ },
401
+ remove: async (cfSandbox, path) => {
402
+ if (cfSandbox.remote) {
403
+ await workerRequest(cfSandbox, "/v1/sandbox/deleteFile", { path });
404
+ return;
405
+ }
406
+ await cfSandbox.sandbox.deleteFile(path);
407
+ }
408
+ }
409
+ }
410
+ }
411
+ });
412
+ export {
413
+ cloudflare
414
+ };
415
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Cloudflare Provider - Factory-based Implementation (Dual-Mode)\n *\n * Supports two connection modes:\n *\n * 1. **Remote mode** — User deploys a gateway Worker to their Cloudflare account\n * via `npx @computesdk/cloudflare`, then connects from anywhere using\n * CLOUDFLARE_SANDBOX_URL + CLOUDFLARE_SANDBOX_SECRET.\n *\n * 2. **Direct mode** — User's code runs inside a Cloudflare Worker with the\n * Durable Object binding available. Uses the @cloudflare/sandbox SDK directly.\n *\n * The mode is selected automatically based on which config fields are provided.\n */\n\nimport { defineProvider } from '@computesdk/provider';\n\n/**\n * Lazy-load @cloudflare/sandbox to avoid importing it in Node.js environments.\n * The SDK only works inside the Cloudflare Workers runtime (its transitive dep\n * @cloudflare/containers uses extensionless ESM imports that break in Node).\n * Remote mode never needs this import.\n */\nlet _getSandboxFn: ((binding: any, id: string, options?: any) => any) | null = null;\nasync function getSandbox(binding: any, id: string, options?: any): Promise<any> {\n if (!_getSandboxFn) {\n const mod = await import('@cloudflare/sandbox');\n _getSandboxFn = mod.getSandbox as (binding: any, id: string, options?: any) => any;\n }\n return _getSandboxFn(binding, id, options);\n}\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\n\n// ─── Config ──────────────────────────────────────────────────────────────────\n\nexport interface CloudflareConfig {\n // Remote mode (from anywhere — talks to deployed gateway Worker)\n /** URL of the deployed gateway Worker (e.g. https://computesdk-sandbox.user.workers.dev) */\n sandboxUrl?: string;\n /** Shared secret for authenticating with the gateway Worker */\n sandboxSecret?: string;\n\n // Direct mode (inside a Cloudflare Worker — uses DO binding)\n /** Cloudflare Sandbox Durable Object binding from Workers environment */\n sandboxBinding?: any;\n\n // Shared options\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 /** Options passed to getSandbox() for lifecycle control (direct mode only) */\n sandboxOptions?: {\n sleepAfter?: string | number;\n keepAlive?: boolean;\n };\n}\n\n// ─── Internal types ──────────────────────────────────────────────────────────\n\ninterface CloudflareSandbox {\n sandboxId: string;\n exposedPorts: Map<number, string>;\n // Remote mode fields\n remote: boolean;\n sandboxUrl?: string;\n sandboxSecret?: string;\n // Direct mode fields\n sandbox?: any; // The @cloudflare/sandbox instance\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction isRemote(config: CloudflareConfig): boolean {\n return !!(config.sandboxUrl && config.sandboxSecret);\n}\n\nfunction detectRuntime(code: string): Runtime {\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 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 return 'python';\n}\n\nfunction runtimeToLanguage(runtime: Runtime): 'python' | 'javascript' | 'typescript' {\n switch (runtime) {\n case 'python': return 'python';\n case 'node': return 'javascript';\n case 'bun': return 'javascript';\n case 'deno': return 'typescript';\n default: return 'python';\n }\n}\n\n/**\n * Make an authenticated request to the remote gateway Worker\n */\nasync function workerRequest(\n cfSandbox: CloudflareSandbox,\n path: string,\n body: Record<string, any> = {}\n): Promise<any> {\n const res = await fetch(`${cfSandbox.sandboxUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${cfSandbox.sandboxSecret}`,\n },\n body: JSON.stringify({ sandboxId: cfSandbox.sandboxId, ...body }),\n });\n\n let data: any;\n try {\n data = await res.json();\n } catch {\n const text = await res.text().catch(() => '(unreadable)');\n throw new Error(`Worker request failed: ${res.status} - ${text.slice(0, 200)}`);\n }\n\n if (!res.ok) {\n throw new Error(data.error || `Worker request failed: ${res.status}`);\n }\n\n return data;\n}\n\n/**\n * Escape a string for safe use inside double-quoted shell arguments.\n */\nfunction shellEscape(s: string): string {\n return s.replace(/[\"$`\\\\!]/g, '\\\\$&');\n}\n\n/**\n * Process code execution results into a CodeResult (shared by remote and direct modes)\n */\nfunction processExecution(execution: any, detectedRuntime: Runtime): CodeResult {\n const stdoutParts: string[] = [];\n const stderrParts: string[] = [];\n\n if (execution.logs) {\n if (execution.logs.stdout) stdoutParts.push(...execution.logs.stdout);\n if (execution.logs.stderr) stderrParts.push(...execution.logs.stderr);\n }\n if (execution.results && Array.isArray(execution.results)) {\n for (const res of execution.results) {\n if (res.text) stdoutParts.push(res.text);\n }\n }\n if (execution.error) {\n const errorMsg = execution.error.message || execution.error.name || 'Execution error';\n if (errorMsg.includes('SyntaxError') || errorMsg.includes('invalid syntax')) {\n throw new Error(`Syntax error: ${errorMsg}`);\n }\n stderrParts.push(errorMsg);\n }\n\n const stdout = stdoutParts.join('\\n');\n const stderr = stderrParts.join('\\n');\n\n return {\n output: stderr ? `${stdout}${stdout && stderr ? '\\n' : ''}${stderr}` : stdout,\n exitCode: execution.error ? 1 : 0,\n language: detectedRuntime\n };\n}\n\n/**\n * Parse ls -la output into FileEntry objects (used by both modes for readdir)\n */\nfunction parseLsOutput(stdout: string): FileEntry[] {\n const lines = 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 type: permissions.startsWith('d') ? 'directory' as const : 'file' as const,\n size,\n modified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n}\n\n// ─── Provider ────────────────────────────────────────────────────────────────\n\nexport const cloudflare = defineProvider<CloudflareSandbox, CloudflareConfig>({\n name: 'cloudflare',\n methods: {\n sandbox: {\n // ─── Collection operations ───────────────────────────────────────\n\n create: async (config: CloudflareConfig, options?: CreateSandboxOptions) => {\n // Destructure known ComputeSDK fields, collect the rest for passthrough\n const {\n runtime: _runtime,\n timeout: optTimeout,\n envs,\n name: _name,\n metadata: _metadata,\n templateId: _templateId,\n snapshotId: _snapshotId,\n sandboxId: optSandboxId,\n namespace: _namespace,\n directory: _directory,\n overlays: _overlays,\n servers: _servers,\n ports: _ports,\n ...rest\n } = options || {};\n\n const sandboxId = optSandboxId || `cf-sandbox-${Date.now()}`;\n const envVars = { ...config.envVars, ...envs };\n // options.timeout takes precedence over config.timeout\n const timeout = optTimeout ?? config.timeout;\n\n // Remote mode\n if (isRemote(config)) {\n await workerRequest(\n { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: new Map() },\n '/v1/sandbox/create',\n {\n envVars: Object.keys(envVars).length > 0 ? envVars : undefined,\n ...(timeout ? { timeout } : {}),\n ...rest, // Pass through provider-specific options\n }\n );\n\n return {\n sandbox: {\n sandboxId,\n remote: true,\n sandboxUrl: config.sandboxUrl,\n sandboxSecret: config.sandboxSecret,\n exposedPorts: new Map(),\n },\n sandboxId\n };\n }\n\n // Direct mode\n if (!config.sandboxBinding) {\n throw new Error(\n 'Missing Cloudflare config. Either:\\n' +\n ' 1. Set CLOUDFLARE_SANDBOX_URL + CLOUDFLARE_SANDBOX_SECRET (remote mode)\\n' +\n ' 2. Provide sandboxBinding from your Workers environment (direct mode)\\n' +\n 'Run `npx @computesdk/cloudflare` to deploy a gateway Worker.'\n );\n }\n\n try {\n const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);\n\n if (Object.keys(envVars).length > 0) {\n await sandbox.setEnvVars(envVars);\n }\n\n return {\n sandbox: {\n sandbox,\n sandboxId,\n remote: false,\n exposedPorts: new Map(),\n },\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/sandbox/get-started/ for setup instructions.'\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error('Cloudflare resource limits exceeded. Check your usage at https://dash.cloudflare.com/');\n }\n }\n throw new Error(`Failed to create Cloudflare sandbox: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n getById: async (config: CloudflareConfig, sandboxId: string) => {\n // Remote mode\n if (isRemote(config)) {\n try {\n const cfSandbox: CloudflareSandbox = {\n sandboxId,\n remote: true,\n sandboxUrl: config.sandboxUrl,\n sandboxSecret: config.sandboxSecret,\n exposedPorts: new Map(),\n };\n // Verify sandbox is alive\n await workerRequest(cfSandbox, '/v1/sandbox/exec', { command: 'true' });\n return { sandbox: cfSandbox, sandboxId };\n } catch {\n return null;\n }\n }\n\n // Direct mode\n if (!config.sandboxBinding) return null;\n\n try {\n const sandbox = await getSandbox(config.sandboxBinding, sandboxId, config.sandboxOptions);\n await sandbox.exec('true');\n return {\n sandbox: { sandbox, sandboxId, remote: false, exposedPorts: new Map() },\n sandboxId\n };\n } catch {\n return null;\n }\n },\n\n list: async (_config: CloudflareConfig) => {\n throw new Error(\n 'Cloudflare provider does not support listing sandboxes. ' +\n 'Durable Objects do not have a native list API. ' +\n 'Use getById to reconnect to specific sandboxes by ID.'\n );\n },\n\n destroy: async (config: CloudflareConfig, sandboxId: string) => {\n try {\n if (isRemote(config)) {\n await workerRequest(\n { sandboxId, remote: true, sandboxUrl: config.sandboxUrl, sandboxSecret: config.sandboxSecret, exposedPorts: new Map() },\n '/v1/sandbox/destroy'\n );\n return;\n }\n\n if (config.sandboxBinding) {\n const sandbox = await getSandbox(config.sandboxBinding, sandboxId);\n await sandbox.destroy();\n }\n } catch {\n // Sandbox might already be destroyed\n }\n },\n\n // ─── Instance operations ─────────────────────────────────────────\n\n runCode: async (cfSandbox: CloudflareSandbox, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const detectedRuntime = runtime || detectRuntime(code);\n const language = runtimeToLanguage(detectedRuntime);\n\n // Remote mode\n if (cfSandbox.remote) {\n const execution = await workerRequest(cfSandbox, '/v1/sandbox/runCode', { code, language });\n return processExecution(execution, detectedRuntime);\n }\n\n // Direct mode\n try {\n const execution = await cfSandbox.sandbox.runCode(code, { language });\n return processExecution(execution, detectedRuntime);\n } catch (error) {\n if (error instanceof Error && error.message.includes('Syntax error')) throw error;\n throw new Error(`Cloudflare execution failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n runCommand: async (cfSandbox: CloudflareSandbox, command: string, options?: RunCommandOptions): Promise<CommandResult> => {\n const startTime = Date.now();\n\n // Remote mode\n if (cfSandbox.remote) {\n try {\n let fullCommand = command;\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n const result = await workerRequest(cfSandbox, '/v1/sandbox/exec', {\n command: fullCommand,\n cwd: options?.cwd,\n env: options?.env,\n timeout: options?.timeout,\n });\n\n return {\n stdout: result.stdout || '',\n stderr: result.stderr || '',\n exitCode: result.exitCode,\n durationMs: Date.now() - startTime\n };\n } catch (error) {\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127,\n durationMs: Date.now() - startTime\n };\n }\n }\n\n // Direct mode\n try {\n let fullCommand = command;\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n const execResult = await cfSandbox.sandbox.exec(fullCommand, {\n cwd: options?.cwd,\n env: options?.env,\n timeout: options?.timeout,\n });\n\n return {\n stdout: execResult.stdout || '',\n stderr: execResult.stderr || '',\n exitCode: execResult.exitCode,\n durationMs: Date.now() - startTime\n };\n } catch (error) {\n return {\n stdout: '',\n stderr: error instanceof Error ? error.message : String(error),\n exitCode: 127,\n durationMs: Date.now() - startTime\n };\n }\n },\n\n getInfo: async (cfSandbox: CloudflareSandbox): Promise<SandboxInfo> => {\n try {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/info');\n } else {\n await cfSandbox.sandbox.exec('true');\n }\n\n return {\n id: cfSandbox.sandboxId,\n provider: 'cloudflare',\n runtime: 'python',\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: cfSandbox.sandboxId,\n mode: cfSandbox.remote ? 'remote' : 'direct',\n }\n };\n } catch (error) {\n return {\n id: cfSandbox.sandboxId,\n provider: 'cloudflare',\n runtime: 'python',\n status: 'error',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cloudflareSandboxId: cfSandbox.sandboxId,\n mode: cfSandbox.remote ? 'remote' : 'direct',\n error: error instanceof Error ? error.message : String(error)\n }\n };\n }\n },\n\n getUrl: async (cfSandbox: CloudflareSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n const { port, protocol = 'https' } = options;\n\n if (cfSandbox.exposedPorts.has(port)) {\n return cfSandbox.exposedPorts.get(port)!;\n }\n\n let preview: any;\n if (cfSandbox.remote) {\n preview = await workerRequest(cfSandbox, '/v1/sandbox/exposePort', { port, options: {} });\n } else {\n preview = await cfSandbox.sandbox.exposePort(port, {});\n }\n\n const url = `${protocol}://${preview.url}`;\n cfSandbox.exposedPorts.set(port, url);\n return url;\n },\n\n // ─── Filesystem ────────────────────────────────────────────────\n\n filesystem: {\n readFile: async (cfSandbox: CloudflareSandbox, path: string): Promise<string> => {\n if (cfSandbox.remote) {\n const file = await workerRequest(cfSandbox, '/v1/sandbox/readFile', { path });\n return file.content || '';\n }\n const file = await cfSandbox.sandbox.readFile(path);\n return file.content || '';\n },\n\n writeFile: async (cfSandbox: CloudflareSandbox, path: string, content: string): Promise<void> => {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/writeFile', { path, content });\n return;\n }\n await cfSandbox.sandbox.writeFile(path, content);\n },\n\n mkdir: async (cfSandbox: CloudflareSandbox, path: string): Promise<void> => {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/mkdir', { path });\n return;\n }\n await cfSandbox.sandbox.mkdir(path, { recursive: true });\n },\n\n readdir: async (cfSandbox: CloudflareSandbox, path: string): Promise<FileEntry[]> => {\n // Both modes use ls -la since there's no native readdir\n let result: any;\n if (cfSandbox.remote) {\n result = await workerRequest(cfSandbox, '/v1/sandbox/exec', {\n command: `ls -la \"${shellEscape(path)}\"`,\n cwd: '/',\n });\n } else {\n result = await cfSandbox.sandbox.exec(`ls -la \"${shellEscape(path)}\"`, { cwd: '/' });\n }\n\n if (result.exitCode !== 0) {\n throw new Error(`Directory listing failed: ${result.stderr}`);\n }\n\n return parseLsOutput(result.stdout);\n },\n\n exists: async (cfSandbox: CloudflareSandbox, path: string): Promise<boolean> => {\n if (cfSandbox.remote) {\n const result = await workerRequest(cfSandbox, '/v1/sandbox/exists', { path });\n return result.exists;\n }\n const result = await cfSandbox.sandbox.exists(path);\n return result.exists;\n },\n\n remove: async (cfSandbox: CloudflareSandbox, path: string): Promise<void> => {\n if (cfSandbox.remote) {\n await workerRequest(cfSandbox, '/v1/sandbox/deleteFile', { path });\n return;\n }\n await cfSandbox.sandbox.deleteFile(path);\n }\n }\n }\n }\n});\n"],"mappings":"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","names":["file","result"]}
package/dist/setup.mjs ADDED
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/setup.ts
4
+ import { execSync } from "child_process";
5
+ import { mkdtempSync, cpSync, rmSync, readFileSync, existsSync } from "fs";
6
+ import { join, dirname, resolve } from "path";
7
+ import { fileURLToPath } from "url";
8
+ import { randomBytes } from "crypto";
9
+ import { tmpdir } from "os";
10
+ function loadEnvFile(filePath) {
11
+ if (!existsSync(filePath)) return;
12
+ const content = readFileSync(filePath, "utf8");
13
+ for (const line of content.split("\n")) {
14
+ const trimmed = line.trim();
15
+ if (!trimmed || trimmed.startsWith("#")) continue;
16
+ const eqIndex = trimmed.indexOf("=");
17
+ if (eqIndex === -1) continue;
18
+ const key = trimmed.slice(0, eqIndex).trim();
19
+ let value = trimmed.slice(eqIndex + 1).trim();
20
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
21
+ value = value.slice(1, -1);
22
+ }
23
+ if (!process.env[key]) {
24
+ process.env[key] = value;
25
+ }
26
+ }
27
+ }
28
+ var cwd = process.cwd();
29
+ loadEnvFile(join(cwd, ".env"));
30
+ loadEnvFile(resolve(cwd, "..", ".env"));
31
+ loadEnvFile(resolve(cwd, "..", "..", ".env"));
32
+ var WORKER_NAME = "computesdk-sandbox";
33
+ async function setup() {
34
+ const apiToken = process.env.CLOUDFLARE_API_TOKEN;
35
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
36
+ console.log("\n ComputeSDK Cloudflare Setup\n");
37
+ if (!apiToken || !accountId) {
38
+ console.error(" Missing required environment variables:\n");
39
+ if (!apiToken) console.error(" CLOUDFLARE_API_TOKEN");
40
+ if (!accountId) console.error(" CLOUDFLARE_ACCOUNT_ID");
41
+ console.error("\n Set these before running setup.");
42
+ console.error(" Get your API token at: https://dash.cloudflare.com/profile/api-tokens\n");
43
+ process.exit(1);
44
+ }
45
+ console.log(" Verifying Cloudflare credentials...");
46
+ const verifyRes = await fetch(
47
+ `https://api.cloudflare.com/client/v4/accounts/${accountId}`,
48
+ { headers: { "Authorization": `Bearer ${apiToken}` } }
49
+ );
50
+ if (!verifyRes.ok) {
51
+ const body = await verifyRes.text();
52
+ console.error(` Invalid credentials (HTTP ${verifyRes.status}): ${body}`);
53
+ console.error(" Check your CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID.\n");
54
+ process.exit(1);
55
+ }
56
+ try {
57
+ execSync("which docker", { stdio: "pipe" });
58
+ } catch {
59
+ console.error(" Docker is required but not found.");
60
+ console.error(" Wrangler needs Docker to build the sandbox container image.");
61
+ console.error(" Install Docker Desktop: https://www.docker.com/products/docker-desktop\n");
62
+ process.exit(1);
63
+ }
64
+ const secret = randomBytes(32).toString("hex");
65
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
66
+ const workerSrc = join(packageRoot, "src", "worker");
67
+ const tmpDir = mkdtempSync(join(tmpdir(), "computesdk-cf-"));
68
+ cpSync(workerSrc, tmpDir, { recursive: true });
69
+ console.log(" Installing Worker dependencies...");
70
+ try {
71
+ execSync("npm install --production", { cwd: tmpDir, stdio: "pipe" });
72
+ } catch {
73
+ console.error(" Failed to install dependencies. Ensure npm is available.");
74
+ rmSync(tmpDir, { recursive: true, force: true });
75
+ process.exit(1);
76
+ }
77
+ console.log(` Deploying ${WORKER_NAME} to your account...`);
78
+ const env = {
79
+ ...process.env,
80
+ CLOUDFLARE_API_TOKEN: apiToken,
81
+ CLOUDFLARE_ACCOUNT_ID: accountId
82
+ };
83
+ try {
84
+ execSync(`npx wrangler deploy --name ${WORKER_NAME}`, {
85
+ cwd: tmpDir,
86
+ stdio: "inherit",
87
+ env
88
+ });
89
+ } catch {
90
+ console.error("\n Deploy failed.");
91
+ console.error(" Ensure your API token has Workers Scripts:Edit permission.");
92
+ console.error(" Create a token at: https://dash.cloudflare.com/profile/api-tokens\n");
93
+ rmSync(tmpDir, { recursive: true, force: true });
94
+ process.exit(1);
95
+ }
96
+ console.log(" Setting SANDBOX_SECRET...");
97
+ try {
98
+ execSync(
99
+ `npx wrangler secret put SANDBOX_SECRET --name ${WORKER_NAME}`,
100
+ { cwd: tmpDir, stdio: ["pipe", "pipe", "pipe"], env, input: `${secret}
101
+ ` }
102
+ );
103
+ } catch {
104
+ console.error("\n Failed to set Worker secret.");
105
+ console.error(" You can set it manually: npx wrangler secret put SANDBOX_SECRET --name computesdk-sandbox\n");
106
+ rmSync(tmpDir, { recursive: true, force: true });
107
+ process.exit(1);
108
+ }
109
+ const subdomain = await getWorkersSubdomain(apiToken, accountId);
110
+ const workerUrl = `https://${WORKER_NAME}.${subdomain}.workers.dev`;
111
+ console.log(" Verifying deployment...");
112
+ try {
113
+ const healthRes = await fetch(`${workerUrl}/v1/health`);
114
+ if (!healthRes.ok) {
115
+ console.warn(` Warning: Health check returned HTTP ${healthRes.status}.`);
116
+ } else {
117
+ let health;
118
+ try {
119
+ health = await healthRes.json();
120
+ } catch {
121
+ const text = await healthRes.text().catch(() => "(unreadable)");
122
+ console.warn(` Warning: Health check returned non-JSON response: ${text.slice(0, 200)}`);
123
+ }
124
+ if (health && health.status !== "ok") {
125
+ console.warn(" Warning: Health check returned unexpected response.");
126
+ }
127
+ }
128
+ } catch {
129
+ console.warn(" Warning: Could not reach Worker. It may take a moment to propagate.");
130
+ }
131
+ rmSync(tmpDir, { recursive: true, force: true });
132
+ console.log("\n Setup complete! Add these to your .env:\n");
133
+ console.log(` CLOUDFLARE_SANDBOX_URL=${workerUrl}`);
134
+ console.log(` CLOUDFLARE_SANDBOX_SECRET=${secret}`);
135
+ console.log("");
136
+ console.log(" Then use it with ComputeSDK:\n");
137
+ console.log(" import { compute } from 'computesdk';");
138
+ console.log(" const sandbox = await compute.sandbox.create();");
139
+ console.log(` await sandbox.runCode('print("hello")');
140
+ `);
141
+ }
142
+ async function getWorkersSubdomain(token, accountId) {
143
+ const res = await fetch(
144
+ `https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/subdomain`,
145
+ { headers: { "Authorization": `Bearer ${token}` } }
146
+ );
147
+ if (!res.ok) {
148
+ console.warn(" Warning: Could not determine Workers subdomain. Using account ID.");
149
+ return accountId;
150
+ }
151
+ let data;
152
+ try {
153
+ data = await res.json();
154
+ } catch {
155
+ console.warn(" Warning: Workers subdomain API returned non-JSON response. Using account ID.");
156
+ return accountId;
157
+ }
158
+ return data.result?.subdomain || accountId;
159
+ }
160
+ setup().catch((err) => {
161
+ console.error(`
162
+ Unexpected error: ${err.message}
163
+ `);
164
+ process.exit(1);
165
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@computesdk/cloudflare",
3
- "version": "1.4.1",
3
+ "version": "1.5.1",
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.0",
26
- "@computesdk/provider": "1.0.29",
27
- "computesdk": "2.4.0"
26
+ "computesdk": "2.5.1",
27
+ "@computesdk/provider": "1.0.31"
28
28
  },
29
29
  "keywords": [
30
30
  "computesdk",