@computesdk/codesandbox 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,232 @@
1
+ # @computesdk/codesandbox
2
+
3
+ CodeSandbox provider for ComputeSDK - Execute code in secure, isolated CodeSandbox environments with full filesystem and development environment support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @computesdk/codesandbox
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ 1. Get your CodeSandbox API key from [codesandbox.io/t/api](https://codesandbox.io/t/api)
14
+ 2. Set the environment variable:
15
+
16
+ ```bash
17
+ export CSB_API_KEY=your_api_key_here
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### With ComputeSDK
23
+
24
+ ```typescript
25
+ import { compute } from 'computesdk';
26
+ import { codesandbox } from '@computesdk/codesandbox';
27
+
28
+ // Set as default provider
29
+ compute.setConfig({
30
+ provider: codesandbox({ apiKey: process.env.CSB_API_KEY })
31
+ });
32
+
33
+ // Create sandbox
34
+ const sandbox = await compute.sandbox.create({});
35
+
36
+ // Execute JavaScript/Node.js code
37
+ const result = await sandbox.runCode(`
38
+ const message = "Hello from CodeSandbox!";
39
+ console.log(message);
40
+
41
+ const data = { users: 3, tasks: 15 };
42
+ console.log(JSON.stringify(data, null, 2));
43
+ `);
44
+
45
+ console.log(result.stdout);
46
+ // Output:
47
+ // Hello from CodeSandbox!
48
+ // {
49
+ // "users": 3,
50
+ // "tasks": 15
51
+ // }
52
+
53
+ // Execute Python code
54
+ const pythonResult = await sandbox.runCode(`
55
+ import json
56
+ data = {"framework": "CodeSandbox", "language": "Python"}
57
+ print(json.dumps(data, indent=2))
58
+ print(f"Running in: {data['framework']}")
59
+ `, 'python');
60
+
61
+ console.log(pythonResult.stdout);
62
+ // Output:
63
+ // {
64
+ // "framework": "CodeSandbox",
65
+ // "language": "Python"
66
+ // }
67
+ // Running in: CodeSandbox
68
+
69
+ // Clean up
70
+ await compute.sandbox.destroy(sandbox.sandboxId);
71
+ ```
72
+
73
+ ### Direct Usage
74
+
75
+ ```typescript
76
+ import { codesandbox } from '@computesdk/codesandbox';
77
+
78
+ // Create provider
79
+ const provider = codesandbox({
80
+ apiKey: 'your_api_key',
81
+ templateId: 'universal', // Optional: specify template
82
+ timeout: 600000 // 10 minutes
83
+ });
84
+
85
+ // Use with compute singleton
86
+ const sandbox = await compute.sandbox.create({ provider });
87
+ ```
88
+
89
+ ## Configuration
90
+
91
+ ### Environment Variables
92
+
93
+ ```bash
94
+ export CSB_API_KEY=your_api_key_here
95
+ ```
96
+
97
+ ### Configuration Options
98
+
99
+ ```typescript
100
+ interface CodesandboxConfig {
101
+ /** CodeSandbox API key - if not provided, will use CSB_API_KEY env var */
102
+ apiKey?: string;
103
+ /** Template to use for new sandboxes (defaults to universal template) */
104
+ templateId?: string;
105
+ /** Default runtime environment */
106
+ runtime?: 'python' | 'node';
107
+ /** Execution timeout in milliseconds */
108
+ timeout?: number;
109
+ }
110
+ ```
111
+
112
+ ## Features
113
+
114
+ - ✅ **Code Execution** - Python and Node.js runtime support
115
+ - ✅ **Command Execution** - Run shell commands in sandbox
116
+ - ✅ **Filesystem Operations** - Full file system access via CodeSandbox API
117
+ - ✅ **Template Support** - Create sandboxes from custom templates
118
+ - ✅ **Auto Runtime Detection** - Automatically detects Python vs Node.js
119
+ - ✅ **Development Environment** - Full development setup with package managers
120
+ - ✅ **Persistence** - Files persist across hibernation/resume cycles
121
+ - ✅ **Snapshot/Resume** - Fast sandbox restoration from snapshots
122
+
123
+ ## API Reference
124
+
125
+ ### Code Execution
126
+
127
+ ```typescript
128
+ // Execute Node.js code
129
+ const result = await sandbox.runCode(`
130
+ const fs = require('fs');
131
+ const data = { timestamp: Date.now() };
132
+ console.log('Processing data:', JSON.stringify(data));
133
+ `);
134
+
135
+ // Execute Python code
136
+ const result = await sandbox.runCode(`
137
+ import datetime
138
+ import json
139
+
140
+ data = {'timestamp': datetime.datetime.now().isoformat()}
141
+ print('Processing data:', json.dumps(data))
142
+ `, 'python');
143
+
144
+ // Auto-detection (based on code patterns)
145
+ const result = await sandbox.runCode('print("Auto-detected as Python")');
146
+ ```
147
+
148
+ ### Command Execution
149
+
150
+ ```typescript
151
+ // List files
152
+ const result = await sandbox.runCommand('ls', ['-la']);
153
+
154
+ // Install Node.js packages
155
+ const result = await sandbox.runCommand('npm', ['install', 'lodash']);
156
+
157
+ // Install Python packages
158
+ const result = await sandbox.runCommand('pip', ['install', 'requests']);
159
+
160
+ // Run development server
161
+ const result = await sandbox.runCommand('npm', ['run', 'dev']);
162
+ ```
163
+
164
+ ### Filesystem Operations
165
+
166
+ ```typescript
167
+ // Write file
168
+ await sandbox.filesystem.writeFile('/project/workspace/app.js', `
169
+ const express = require('express');
170
+ const app = express();
171
+
172
+ app.get('/', (req, res) => {
173
+ res.json({ message: 'Hello from CodeSandbox!' });
174
+ });
175
+
176
+ app.listen(3000, () => {
177
+ console.log('Server running on port 3000');
178
+ });
179
+ `);
180
+
181
+ // Read file
182
+ const content = await sandbox.filesystem.readFile('/project/workspace/package.json');
183
+
184
+ // Create directory
185
+ await sandbox.filesystem.mkdir('/project/workspace/src');
186
+
187
+ // List directory contents
188
+ const files = await sandbox.filesystem.readdir('/project/workspace');
189
+
190
+ // Check if file exists
191
+ const exists = await sandbox.filesystem.exists('/project/workspace/app.js');
192
+
193
+ // Remove file or directory
194
+ await sandbox.filesystem.remove('/project/workspace/temp.txt');
195
+ ```
196
+
197
+ ### Sandbox Management
198
+
199
+ ```typescript
200
+ // Get sandbox info
201
+ const info = await sandbox.getInfo();
202
+ console.log(info.id, info.provider, info.status);
203
+
204
+ // Resume existing sandbox
205
+ const existing = await compute.sandbox.getById(provider, 'sandbox-id');
206
+
207
+ // Hibernate sandbox (saves state)
208
+ await compute.sandbox.destroy(provider, 'sandbox-id'); // Actually hibernates
209
+
210
+ // Note: CodeSandbox doesn't support listing all sandboxes
211
+ // Each sandbox is managed individually
212
+ ```
213
+
214
+ ## Best Practices
215
+
216
+ 1. **Resource Management**: Use hibernation instead of destroying sandboxes to preserve state
217
+ 2. **Error Handling**: Use try-catch blocks for robust error handling
218
+ 3. **Timeouts**: Set appropriate timeouts for long-running tasks
219
+ 4. **File Organization**: Organize files in `/project/workspace/` directory
220
+ 5. **Template Usage**: Use appropriate templates for your project type
221
+ 6. **API Key Security**: Never commit API keys to version control
222
+ 7. **Snapshot Management**: Leverage CodeSandbox's snapshot/resume capabilities
223
+
224
+ ## Support
225
+
226
+ - [CodeSandbox Documentation](https://codesandbox.io/docs/sdk)
227
+ - [ComputeSDK Issues](https://github.com/computesdk/computesdk/issues)
228
+ - [CodeSandbox Support](https://codesandbox.io/support)
229
+
230
+ ## License
231
+
232
+ MIT
@@ -0,0 +1,22 @@
1
+ import * as computesdk from 'computesdk';
2
+ import { Runtime } from 'computesdk';
3
+
4
+ /**
5
+ * Codesandbox-specific configuration options
6
+ */
7
+ interface CodesandboxConfig {
8
+ /** CodeSandbox API key - if not provided, will fallback to CSB_API_KEY environment variable */
9
+ apiKey?: string;
10
+ /** Template to use for new sandboxes */
11
+ templateId?: string;
12
+ /** Default runtime environment */
13
+ runtime?: Runtime;
14
+ /** Execution timeout in milliseconds */
15
+ timeout?: number;
16
+ }
17
+ /**
18
+ * Create a Codesandbox provider instance using the factory pattern
19
+ */
20
+ declare const codesandbox: (config: CodesandboxConfig) => computesdk.Provider;
21
+
22
+ export { type CodesandboxConfig, codesandbox };
@@ -0,0 +1,22 @@
1
+ import * as computesdk from 'computesdk';
2
+ import { Runtime } from 'computesdk';
3
+
4
+ /**
5
+ * Codesandbox-specific configuration options
6
+ */
7
+ interface CodesandboxConfig {
8
+ /** CodeSandbox API key - if not provided, will fallback to CSB_API_KEY environment variable */
9
+ apiKey?: string;
10
+ /** Template to use for new sandboxes */
11
+ templateId?: string;
12
+ /** Default runtime environment */
13
+ runtime?: Runtime;
14
+ /** Execution timeout in milliseconds */
15
+ timeout?: number;
16
+ }
17
+ /**
18
+ * Create a Codesandbox provider instance using the factory pattern
19
+ */
20
+ declare const codesandbox: (config: CodesandboxConfig) => computesdk.Provider;
21
+
22
+ export { type CodesandboxConfig, codesandbox };
package/dist/index.js ADDED
@@ -0,0 +1,236 @@
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
+ codesandbox: () => codesandbox
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+ var import_sdk = require("@codesandbox/sdk");
27
+ var import_computesdk = require("computesdk");
28
+ var codesandbox = (0, import_computesdk.createProvider)({
29
+ name: "codesandbox",
30
+ methods: {
31
+ sandbox: {
32
+ // Collection operations (compute.sandbox.*)
33
+ create: async (config, options) => {
34
+ const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.CSB_API_KEY || "";
35
+ if (!apiKey) {
36
+ throw new Error(
37
+ `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`
38
+ );
39
+ }
40
+ const sdk = new import_sdk.CodeSandbox(apiKey);
41
+ try {
42
+ let sandbox;
43
+ let sandboxId;
44
+ if (options?.sandboxId) {
45
+ sandbox = await sdk.sandboxes.resume(options.sandboxId);
46
+ sandboxId = options.sandboxId;
47
+ } else {
48
+ const createOptions = {};
49
+ if (config.templateId) {
50
+ createOptions.id = config.templateId;
51
+ }
52
+ sandbox = await sdk.sandboxes.create(createOptions);
53
+ sandboxId = sandbox.id;
54
+ }
55
+ return {
56
+ sandbox,
57
+ sandboxId
58
+ };
59
+ } catch (error) {
60
+ if (error instanceof Error) {
61
+ if (error.message.includes("unauthorized") || error.message.includes("API key")) {
62
+ throw new Error(
63
+ `CodeSandbox authentication failed. Please check your CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`
64
+ );
65
+ }
66
+ if (error.message.includes("quota") || error.message.includes("limit")) {
67
+ throw new Error(
68
+ `CodeSandbox quota exceeded. Please check your usage at https://codesandbox.io/dashboard`
69
+ );
70
+ }
71
+ }
72
+ throw new Error(
73
+ `Failed to create CodeSandbox sandbox: ${error instanceof Error ? error.message : String(error)}`
74
+ );
75
+ }
76
+ },
77
+ getById: async (config, sandboxId) => {
78
+ const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.CSB_API_KEY || "";
79
+ if (!apiKey) {
80
+ throw new Error(
81
+ `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`
82
+ );
83
+ }
84
+ const sdk = new import_sdk.CodeSandbox(apiKey);
85
+ try {
86
+ const sandbox = await sdk.sandboxes.resume(sandboxId);
87
+ return {
88
+ sandbox,
89
+ sandboxId
90
+ };
91
+ } catch (error) {
92
+ return null;
93
+ }
94
+ },
95
+ list: async (_config) => {
96
+ throw new Error(
97
+ `CodeSandbox provider does not support listing sandboxes. CodeSandbox SDK does not provide a native list API. Consider using the CodeSandbox dashboard or implement your own tracking system.`
98
+ );
99
+ },
100
+ destroy: async (config, sandboxId) => {
101
+ const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.CSB_API_KEY || "";
102
+ if (!apiKey) {
103
+ throw new Error(
104
+ `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`
105
+ );
106
+ }
107
+ const sdk = new import_sdk.CodeSandbox(apiKey);
108
+ try {
109
+ await sdk.sandboxes.shutdown(sandboxId);
110
+ } catch (error) {
111
+ }
112
+ },
113
+ // Instance operations (sandbox.*)
114
+ runCode: async (sandbox, code, runtime) => {
115
+ const startTime = Date.now();
116
+ try {
117
+ const client = await sandbox.connect();
118
+ const effectiveRuntime = runtime || // Strong Python indicators
119
+ (code.includes("print(") || code.includes("import ") || code.includes("def ") || code.includes("sys.") || code.includes("json.") || code.includes("__") || code.includes('f"') || code.includes("f'") ? "python" : "node");
120
+ const encoded = Buffer.from(code).toString("base64");
121
+ let command;
122
+ if (effectiveRuntime === "python") {
123
+ command = `echo "${encoded}" | base64 -d | python3`;
124
+ } else {
125
+ command = `echo "${encoded}" | base64 -d | node`;
126
+ }
127
+ const output = await client.commands.run(command);
128
+ if (output.includes("SyntaxError") || output.includes("invalid syntax") || output.includes("Unexpected token") || output.includes("Unexpected identifier")) {
129
+ throw new Error(`Syntax error: ${output.trim()}`);
130
+ }
131
+ return {
132
+ stdout: output,
133
+ stderr: "",
134
+ exitCode: 0,
135
+ executionTime: Date.now() - startTime,
136
+ sandboxId: sandbox.id,
137
+ provider: "codesandbox"
138
+ };
139
+ } catch (error) {
140
+ if (error instanceof Error && error.message.includes("Syntax error")) {
141
+ throw error;
142
+ }
143
+ throw new Error(
144
+ `CodeSandbox execution failed: ${error instanceof Error ? error.message : String(error)}`
145
+ );
146
+ }
147
+ },
148
+ runCommand: async (sandbox, command, args = []) => {
149
+ const startTime = Date.now();
150
+ try {
151
+ const client = await sandbox.connect();
152
+ const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
153
+ const output = await client.commands.run(fullCommand);
154
+ return {
155
+ stdout: output,
156
+ stderr: "",
157
+ exitCode: 0,
158
+ executionTime: Date.now() - startTime,
159
+ sandboxId: sandbox.id,
160
+ provider: "codesandbox"
161
+ };
162
+ } catch (error) {
163
+ return {
164
+ stdout: "",
165
+ stderr: error instanceof Error ? error.message : String(error),
166
+ exitCode: 127,
167
+ // Command not found exit code
168
+ executionTime: Date.now() - startTime,
169
+ sandboxId: sandbox.id,
170
+ provider: "codesandbox"
171
+ };
172
+ }
173
+ },
174
+ getInfo: async (sandbox) => {
175
+ return {
176
+ id: sandbox.id,
177
+ provider: "codesandbox",
178
+ runtime: "node",
179
+ // CodeSandbox default
180
+ status: "running",
181
+ createdAt: /* @__PURE__ */ new Date(),
182
+ timeout: 3e5,
183
+ metadata: {
184
+ cluster: sandbox.cluster,
185
+ bootupType: sandbox.bootupType,
186
+ isUpToDate: sandbox.isUpToDate
187
+ }
188
+ };
189
+ },
190
+ // Filesystem operations using CodeSandbox client.fs API
191
+ filesystem: {
192
+ readFile: async (sandbox, path) => {
193
+ const client = await sandbox.connect();
194
+ return await client.fs.readTextFile(path);
195
+ },
196
+ writeFile: async (sandbox, path, content) => {
197
+ const client = await sandbox.connect();
198
+ await client.fs.writeTextFile(path, content);
199
+ },
200
+ mkdir: async (sandbox, path) => {
201
+ const client = await sandbox.connect();
202
+ await client.commands.run(`mkdir -p "${path}"`);
203
+ },
204
+ readdir: async (sandbox, path) => {
205
+ const client = await sandbox.connect();
206
+ const entries = await client.fs.readdir(path);
207
+ return entries.map((entry) => ({
208
+ name: entry.name,
209
+ path: `${path}/${entry.name}`.replace(/\/+/g, "/"),
210
+ isDirectory: entry.isDirectory || false,
211
+ size: entry.size || 0,
212
+ lastModified: entry.lastModified ? new Date(entry.lastModified) : /* @__PURE__ */ new Date()
213
+ }));
214
+ },
215
+ exists: async (sandbox, path) => {
216
+ const client = await sandbox.connect();
217
+ try {
218
+ await client.commands.run(`ls "${path}"`);
219
+ return true;
220
+ } catch {
221
+ return false;
222
+ }
223
+ },
224
+ remove: async (sandbox, path) => {
225
+ const client = await sandbox.connect();
226
+ await client.fs.remove(path);
227
+ }
228
+ }
229
+ }
230
+ }
231
+ });
232
+ // Annotate the CommonJS export names for ESM import in node:
233
+ 0 && (module.exports = {
234
+ codesandbox
235
+ });
236
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Codesandbox Provider - Factory-based Implementation\n * \n * Full-featured provider with filesystem support using the factory pattern.\n */\n\nimport { CodeSandbox } from '@codesandbox/sdk';\nimport type { Sandbox as CodesandboxSandbox } from '@codesandbox/sdk';\nimport { createProvider } from 'computesdk';\nimport type { Runtime, ExecutionResult, SandboxInfo, CreateSandboxOptions, FileEntry } from 'computesdk';\n\n/**\n * Codesandbox-specific configuration options\n */\nexport interface CodesandboxConfig {\n /** CodeSandbox API key - if not provided, will fallback to CSB_API_KEY environment variable */\n apiKey?: string;\n /** Template to use for new sandboxes */\n templateId?: string;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * Create a Codesandbox provider instance using the factory pattern\n */\nexport const codesandbox = createProvider<CodesandboxSandbox, CodesandboxConfig>({\n name: 'codesandbox',\n methods: {\n sandbox: {\n // Collection operations (compute.sandbox.*)\n create: async (config: CodesandboxConfig, options?: CreateSandboxOptions) => {\n // Validate API key\n const apiKey = config.apiKey || (typeof process !== 'undefined' && process.env?.CSB_API_KEY) || '';\n\n if (!apiKey) {\n throw new Error(\n `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`\n );\n }\n\n const sdk = new CodeSandbox(apiKey);\n\n try {\n let sandbox: CodesandboxSandbox;\n let sandboxId: string;\n\n if (options?.sandboxId) {\n // Resume existing CodeSandbox using sdk.sandboxes.resume()\n sandbox = await sdk.sandboxes.resume(options.sandboxId);\n sandboxId = options.sandboxId;\n } else {\n // Create new CodeSandbox using sdk.sandboxes.create()\n const createOptions: any = {};\n \n if (config.templateId) {\n createOptions.id = config.templateId;\n }\n\n sandbox = await sdk.sandboxes.create(createOptions);\n sandboxId = sandbox.id;\n }\n\n return {\n sandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('API key')) {\n throw new Error(\n `CodeSandbox authentication failed. Please check your CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `CodeSandbox quota exceeded. Please check your usage at https://codesandbox.io/dashboard`\n );\n }\n }\n throw new Error(\n `Failed to create CodeSandbox sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: CodesandboxConfig, sandboxId: string) => {\n const apiKey = config.apiKey || (typeof process !== 'undefined' && process.env?.CSB_API_KEY) || '';\n\n if (!apiKey) {\n throw new Error(\n `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`\n );\n }\n\n const sdk = new CodeSandbox(apiKey);\n\n try {\n // Resume existing sandbox using sdk.sandboxes.resume()\n const sandbox = await sdk.sandboxes.resume(sandboxId);\n\n return {\n sandbox,\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: CodesandboxConfig) => {\n throw new Error(\n `CodeSandbox provider does not support listing sandboxes. CodeSandbox SDK does not provide a native list API. Consider using the CodeSandbox dashboard or implement your own tracking system.`\n );\n },\n\n destroy: async (config: CodesandboxConfig, sandboxId: string) => {\n const apiKey = config.apiKey || (typeof process !== 'undefined' && process.env?.CSB_API_KEY) || '';\n\n if (!apiKey) {\n throw new Error(\n `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`\n );\n }\n\n const sdk = new CodeSandbox(apiKey);\n\n try {\n // Shutdown the sandbox using sdk.sandboxes.shutdown() to clean it up\n await sdk.sandboxes.shutdown(sandboxId);\n } catch (error) {\n // Sandbox might already be shutdown or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (sandbox.*)\n runCode: async (sandbox: CodesandboxSandbox, code: string, runtime?: Runtime): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n // Connect to the sandbox client using sandbox.connect()\n const client = await sandbox.connect();\n\n // Auto-detect runtime if not specified\n const effectiveRuntime = runtime || (\n // Strong Python indicators\n 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 ? 'python'\n // Default to Node.js for all other cases (including ambiguous)\n : 'node'\n );\n\n // Use base64 encoding for reliability and consistency\n const encoded = Buffer.from(code).toString('base64');\n let command: string;\n\n if (effectiveRuntime === 'python') {\n // Execute Python code using client.commands.run()\n command = `echo \"${encoded}\" | base64 -d | python3`;\n } else {\n // Execute Node.js code using client.commands.run()\n command = `echo \"${encoded}\" | base64 -d | node`;\n }\n\n // Execute the command using CodeSandbox client.commands.run()\n // This returns the full output as a string\n const output = await client.commands.run(command);\n\n // Check for syntax errors in the output and throw them (similar to other providers)\n if (output.includes('SyntaxError') || \n output.includes('invalid syntax') ||\n output.includes('Unexpected token') ||\n output.includes('Unexpected identifier')) {\n throw new Error(`Syntax error: ${output.trim()}`);\n }\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\n executionTime: Date.now() - startTime,\n sandboxId: sandbox.id,\n provider: 'codesandbox'\n };\n } catch (error) {\n // Re-throw syntax errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error;\n }\n throw new Error(\n `CodeSandbox execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (sandbox: CodesandboxSandbox, command: string, args: string[] = []): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n // Connect to the sandbox client using sandbox.connect()\n const client = await sandbox.connect();\n\n // Construct full command with arguments\n const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;\n\n // Execute command using CodeSandbox client.commands.run()\n // This returns the full output as a string\n const output = await client.commands.run(fullCommand);\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\n executionTime: Date.now() - startTime,\n sandboxId: sandbox.id,\n provider: 'codesandbox'\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: sandbox.id,\n provider: 'codesandbox'\n };\n }\n },\n\n getInfo: async (sandbox: CodesandboxSandbox): Promise<SandboxInfo> => {\n return {\n id: sandbox.id,\n provider: 'codesandbox',\n runtime: 'node', // CodeSandbox default\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cluster: sandbox.cluster,\n bootupType: sandbox.bootupType,\n isUpToDate: sandbox.isUpToDate\n }\n };\n },\n\n // Filesystem operations using CodeSandbox client.fs API\n filesystem: {\n readFile: async (sandbox: CodesandboxSandbox, path: string): Promise<string> => {\n // Connect to the sandbox client and use client.fs.readTextFile()\n const client = await sandbox.connect();\n return await client.fs.readTextFile(path);\n },\n\n writeFile: async (sandbox: CodesandboxSandbox, path: string, content: string): Promise<void> => {\n // Connect to the sandbox client and use client.fs.writeTextFile()\n const client = await sandbox.connect();\n await client.fs.writeTextFile(path, content);\n },\n\n mkdir: async (sandbox: CodesandboxSandbox, path: string): Promise<void> => {\n // CodeSandbox doesn't have a direct mkdir API, use commands to create directory\n const client = await sandbox.connect();\n await client.commands.run(`mkdir -p \"${path}\"`);\n },\n\n readdir: async (sandbox: CodesandboxSandbox, path: string): Promise<FileEntry[]> => {\n // Connect to the sandbox client and use client.fs.readdir()\n const client = await sandbox.connect();\n const entries = await client.fs.readdir(path);\n\n return entries.map((entry: any) => ({\n name: entry.name,\n path: `${path}/${entry.name}`.replace(/\\/+/g, '/'),\n isDirectory: entry.isDirectory || false,\n size: entry.size || 0,\n lastModified: entry.lastModified ? new Date(entry.lastModified) : new Date()\n }));\n },\n\n exists: async (sandbox: CodesandboxSandbox, path: string): Promise<boolean> => {\n // CodeSandbox doesn't have a direct exists API, use ls command to check\n const client = await sandbox.connect();\n try {\n await client.commands.run(`ls \"${path}\"`);\n return true;\n } catch {\n return false;\n }\n },\n\n remove: async (sandbox: CodesandboxSandbox, path: string): Promise<void> => {\n // Connect to the sandbox client and use client.fs.remove()\n const client = await sandbox.connect();\n await client.fs.remove(path);\n }\n }\n }\n }\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,iBAA4B;AAE5B,wBAA+B;AAoBxB,IAAM,kBAAc,kCAAsD;AAAA,EAC/E,MAAM;AAAA,EACN,SAAS;AAAA,IACP,SAAS;AAAA;AAAA,MAEP,QAAQ,OAAO,QAA2B,YAAmC;AAE3E,cAAM,SAAS,OAAO,UAAW,OAAO,YAAY,eAAe,QAAQ,KAAK,eAAgB;AAEhG,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,cAAM,MAAM,IAAI,uBAAY,MAAM;AAElC,YAAI;AACF,cAAI;AACJ,cAAI;AAEJ,cAAI,SAAS,WAAW;AAEtB,sBAAU,MAAM,IAAI,UAAU,OAAO,QAAQ,SAAS;AACtD,wBAAY,QAAQ;AAAA,UACtB,OAAO;AAEL,kBAAM,gBAAqB,CAAC;AAE5B,gBAAI,OAAO,YAAY;AACrB,4BAAc,KAAK,OAAO;AAAA,YAC5B;AAEA,sBAAU,MAAM,IAAI,UAAU,OAAO,aAAa;AAClD,wBAAY,QAAQ;AAAA,UACtB;AAEA,iBAAO;AAAA,YACL;AAAA,YACA;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AACd,cAAI,iBAAiB,OAAO;AAC1B,gBAAI,MAAM,QAAQ,SAAS,cAAc,KAAK,MAAM,QAAQ,SAAS,SAAS,GAAG;AAC/E,oBAAM,IAAI;AAAA,gBACR;AAAA,cACF;AAAA,YACF;AACA,gBAAI,MAAM,QAAQ,SAAS,OAAO,KAAK,MAAM,QAAQ,SAAS,OAAO,GAAG;AACtE,oBAAM,IAAI;AAAA,gBACR;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA,gBAAM,IAAI;AAAA,YACR,yCAAyC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACjG;AAAA,QACF;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,QAA2B,cAAsB;AAC/D,cAAM,SAAS,OAAO,UAAW,OAAO,YAAY,eAAe,QAAQ,KAAK,eAAgB;AAEhG,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,cAAM,MAAM,IAAI,uBAAY,MAAM;AAElC,YAAI;AAEF,gBAAM,UAAU,MAAM,IAAI,UAAU,OAAO,SAAS;AAEpD,iBAAO;AAAA,YACL;AAAA,YACA;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AAEd,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,YAA+B;AAC1C,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,QAA2B,cAAsB;AAC/D,cAAM,SAAS,OAAO,UAAW,OAAO,YAAY,eAAe,QAAQ,KAAK,eAAgB;AAEhG,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,cAAM,MAAM,IAAI,uBAAY,MAAM;AAElC,YAAI;AAEF,gBAAM,IAAI,UAAU,SAAS,SAAS;AAAA,QACxC,SAAS,OAAO;AAAA,QAGhB;AAAA,MACF;AAAA;AAAA,MAGA,SAAS,OAAO,SAA6B,MAAc,YAAgD;AACzG,cAAM,YAAY,KAAK,IAAI;AAE3B,YAAI;AAEF,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AAGrC,gBAAM,mBAAmB;AAAA,WAEvB,KAAK,SAAS,QAAQ,KACtB,KAAK,SAAS,SAAS,KACvB,KAAK,SAAS,MAAM,KACpB,KAAK,SAAS,MAAM,KACpB,KAAK,SAAS,OAAO,KACrB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,IAAI,IACd,WAEA;AAIN,gBAAM,UAAU,OAAO,KAAK,IAAI,EAAE,SAAS,QAAQ;AACnD,cAAI;AAEJ,cAAI,qBAAqB,UAAU;AAEjC,sBAAU,SAAS,OAAO;AAAA,UAC5B,OAAO;AAEL,sBAAU,SAAS,OAAO;AAAA,UAC5B;AAIA,gBAAM,SAAS,MAAM,OAAO,SAAS,IAAI,OAAO;AAGhD,cAAI,OAAO,SAAS,aAAa,KAC7B,OAAO,SAAS,gBAAgB,KAChC,OAAO,SAAS,kBAAkB,KAClC,OAAO,SAAS,uBAAuB,GAAG;AAC5C,kBAAM,IAAI,MAAM,iBAAiB,OAAO,KAAK,CAAC,EAAE;AAAA,UAClD;AAEA,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,eAAe,KAAK,IAAI,IAAI;AAAA,YAC5B,WAAW,QAAQ;AAAA,YACnB,UAAU;AAAA,UACZ;AAAA,QACF,SAAS,OAAO;AAEd,cAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,cAAc,GAAG;AACpE,kBAAM;AAAA,UACR;AACA,gBAAM,IAAI;AAAA,YACR,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACzF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,YAAY,OAAO,SAA6B,SAAiB,OAAiB,CAAC,MAAgC;AACjH,cAAM,YAAY,KAAK,IAAI;AAE3B,YAAI;AAEF,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AAGrC,gBAAM,cAAc,KAAK,SAAS,IAAI,GAAG,OAAO,IAAI,KAAK,KAAK,GAAG,CAAC,KAAK;AAIvE,gBAAM,SAAS,MAAM,OAAO,SAAS,IAAI,WAAW;AAEpD,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR,UAAU;AAAA,YACV,eAAe,KAAK,IAAI,IAAI;AAAA,YAC5B,WAAW,QAAQ;AAAA,YACnB,UAAU;AAAA,UACZ;AAAA,QACF,SAAS,OAAO;AAEd,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC7D,UAAU;AAAA;AAAA,YACV,eAAe,KAAK,IAAI,IAAI;AAAA,YAC5B,WAAW,QAAQ;AAAA,YACnB,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,YAAsD;AACpE,eAAO;AAAA,UACL,IAAI,QAAQ;AAAA,UACZ,UAAU;AAAA,UACV,SAAS;AAAA;AAAA,UACT,QAAQ;AAAA,UACR,WAAW,oBAAI,KAAK;AAAA,UACpB,SAAS;AAAA,UACT,UAAU;AAAA,YACR,SAAS,QAAQ;AAAA,YACjB,YAAY,QAAQ;AAAA,YACpB,YAAY,QAAQ;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,YAAY;AAAA,QACV,UAAU,OAAO,SAA6B,SAAkC;AAE9E,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,iBAAO,MAAM,OAAO,GAAG,aAAa,IAAI;AAAA,QAC1C;AAAA,QAEA,WAAW,OAAO,SAA6B,MAAc,YAAmC;AAE9F,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,gBAAM,OAAO,GAAG,cAAc,MAAM,OAAO;AAAA,QAC7C;AAAA,QAEA,OAAO,OAAO,SAA6B,SAAgC;AAEzE,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,gBAAM,OAAO,SAAS,IAAI,aAAa,IAAI,GAAG;AAAA,QAChD;AAAA,QAEA,SAAS,OAAO,SAA6B,SAAuC;AAElF,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,gBAAM,UAAU,MAAM,OAAO,GAAG,QAAQ,IAAI;AAE5C,iBAAO,QAAQ,IAAI,CAAC,WAAgB;AAAA,YAClC,MAAM,MAAM;AAAA,YACZ,MAAM,GAAG,IAAI,IAAI,MAAM,IAAI,GAAG,QAAQ,QAAQ,GAAG;AAAA,YACjD,aAAa,MAAM,eAAe;AAAA,YAClC,MAAM,MAAM,QAAQ;AAAA,YACpB,cAAc,MAAM,eAAe,IAAI,KAAK,MAAM,YAAY,IAAI,oBAAI,KAAK;AAAA,UAC7E,EAAE;AAAA,QACJ;AAAA,QAEA,QAAQ,OAAO,SAA6B,SAAmC;AAE7E,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,cAAI;AACF,kBAAM,OAAO,SAAS,IAAI,OAAO,IAAI,GAAG;AACxC,mBAAO;AAAA,UACT,QAAQ;AACN,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,QAEA,QAAQ,OAAO,SAA6B,SAAgC;AAE1E,gBAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,gBAAM,OAAO,GAAG,OAAO,IAAI;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,211 @@
1
+ // src/index.ts
2
+ import { CodeSandbox } from "@codesandbox/sdk";
3
+ import { createProvider } from "computesdk";
4
+ var codesandbox = createProvider({
5
+ name: "codesandbox",
6
+ methods: {
7
+ sandbox: {
8
+ // Collection operations (compute.sandbox.*)
9
+ create: async (config, options) => {
10
+ const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.CSB_API_KEY || "";
11
+ if (!apiKey) {
12
+ throw new Error(
13
+ `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`
14
+ );
15
+ }
16
+ const sdk = new CodeSandbox(apiKey);
17
+ try {
18
+ let sandbox;
19
+ let sandboxId;
20
+ if (options?.sandboxId) {
21
+ sandbox = await sdk.sandboxes.resume(options.sandboxId);
22
+ sandboxId = options.sandboxId;
23
+ } else {
24
+ const createOptions = {};
25
+ if (config.templateId) {
26
+ createOptions.id = config.templateId;
27
+ }
28
+ sandbox = await sdk.sandboxes.create(createOptions);
29
+ sandboxId = sandbox.id;
30
+ }
31
+ return {
32
+ sandbox,
33
+ sandboxId
34
+ };
35
+ } catch (error) {
36
+ if (error instanceof Error) {
37
+ if (error.message.includes("unauthorized") || error.message.includes("API key")) {
38
+ throw new Error(
39
+ `CodeSandbox authentication failed. Please check your CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`
40
+ );
41
+ }
42
+ if (error.message.includes("quota") || error.message.includes("limit")) {
43
+ throw new Error(
44
+ `CodeSandbox quota exceeded. Please check your usage at https://codesandbox.io/dashboard`
45
+ );
46
+ }
47
+ }
48
+ throw new Error(
49
+ `Failed to create CodeSandbox sandbox: ${error instanceof Error ? error.message : String(error)}`
50
+ );
51
+ }
52
+ },
53
+ getById: async (config, sandboxId) => {
54
+ const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.CSB_API_KEY || "";
55
+ if (!apiKey) {
56
+ throw new Error(
57
+ `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`
58
+ );
59
+ }
60
+ const sdk = new CodeSandbox(apiKey);
61
+ try {
62
+ const sandbox = await sdk.sandboxes.resume(sandboxId);
63
+ return {
64
+ sandbox,
65
+ sandboxId
66
+ };
67
+ } catch (error) {
68
+ return null;
69
+ }
70
+ },
71
+ list: async (_config) => {
72
+ throw new Error(
73
+ `CodeSandbox provider does not support listing sandboxes. CodeSandbox SDK does not provide a native list API. Consider using the CodeSandbox dashboard or implement your own tracking system.`
74
+ );
75
+ },
76
+ destroy: async (config, sandboxId) => {
77
+ const apiKey = config.apiKey || typeof process !== "undefined" && process.env?.CSB_API_KEY || "";
78
+ if (!apiKey) {
79
+ throw new Error(
80
+ `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`
81
+ );
82
+ }
83
+ const sdk = new CodeSandbox(apiKey);
84
+ try {
85
+ await sdk.sandboxes.shutdown(sandboxId);
86
+ } catch (error) {
87
+ }
88
+ },
89
+ // Instance operations (sandbox.*)
90
+ runCode: async (sandbox, code, runtime) => {
91
+ const startTime = Date.now();
92
+ try {
93
+ const client = await sandbox.connect();
94
+ const effectiveRuntime = runtime || // Strong Python indicators
95
+ (code.includes("print(") || code.includes("import ") || code.includes("def ") || code.includes("sys.") || code.includes("json.") || code.includes("__") || code.includes('f"') || code.includes("f'") ? "python" : "node");
96
+ const encoded = Buffer.from(code).toString("base64");
97
+ let command;
98
+ if (effectiveRuntime === "python") {
99
+ command = `echo "${encoded}" | base64 -d | python3`;
100
+ } else {
101
+ command = `echo "${encoded}" | base64 -d | node`;
102
+ }
103
+ const output = await client.commands.run(command);
104
+ if (output.includes("SyntaxError") || output.includes("invalid syntax") || output.includes("Unexpected token") || output.includes("Unexpected identifier")) {
105
+ throw new Error(`Syntax error: ${output.trim()}`);
106
+ }
107
+ return {
108
+ stdout: output,
109
+ stderr: "",
110
+ exitCode: 0,
111
+ executionTime: Date.now() - startTime,
112
+ sandboxId: sandbox.id,
113
+ provider: "codesandbox"
114
+ };
115
+ } catch (error) {
116
+ if (error instanceof Error && error.message.includes("Syntax error")) {
117
+ throw error;
118
+ }
119
+ throw new Error(
120
+ `CodeSandbox execution failed: ${error instanceof Error ? error.message : String(error)}`
121
+ );
122
+ }
123
+ },
124
+ runCommand: async (sandbox, command, args = []) => {
125
+ const startTime = Date.now();
126
+ try {
127
+ const client = await sandbox.connect();
128
+ const fullCommand = args.length > 0 ? `${command} ${args.join(" ")}` : command;
129
+ const output = await client.commands.run(fullCommand);
130
+ return {
131
+ stdout: output,
132
+ stderr: "",
133
+ exitCode: 0,
134
+ executionTime: Date.now() - startTime,
135
+ sandboxId: sandbox.id,
136
+ provider: "codesandbox"
137
+ };
138
+ } catch (error) {
139
+ return {
140
+ stdout: "",
141
+ stderr: error instanceof Error ? error.message : String(error),
142
+ exitCode: 127,
143
+ // Command not found exit code
144
+ executionTime: Date.now() - startTime,
145
+ sandboxId: sandbox.id,
146
+ provider: "codesandbox"
147
+ };
148
+ }
149
+ },
150
+ getInfo: async (sandbox) => {
151
+ return {
152
+ id: sandbox.id,
153
+ provider: "codesandbox",
154
+ runtime: "node",
155
+ // CodeSandbox default
156
+ status: "running",
157
+ createdAt: /* @__PURE__ */ new Date(),
158
+ timeout: 3e5,
159
+ metadata: {
160
+ cluster: sandbox.cluster,
161
+ bootupType: sandbox.bootupType,
162
+ isUpToDate: sandbox.isUpToDate
163
+ }
164
+ };
165
+ },
166
+ // Filesystem operations using CodeSandbox client.fs API
167
+ filesystem: {
168
+ readFile: async (sandbox, path) => {
169
+ const client = await sandbox.connect();
170
+ return await client.fs.readTextFile(path);
171
+ },
172
+ writeFile: async (sandbox, path, content) => {
173
+ const client = await sandbox.connect();
174
+ await client.fs.writeTextFile(path, content);
175
+ },
176
+ mkdir: async (sandbox, path) => {
177
+ const client = await sandbox.connect();
178
+ await client.commands.run(`mkdir -p "${path}"`);
179
+ },
180
+ readdir: async (sandbox, path) => {
181
+ const client = await sandbox.connect();
182
+ const entries = await client.fs.readdir(path);
183
+ return entries.map((entry) => ({
184
+ name: entry.name,
185
+ path: `${path}/${entry.name}`.replace(/\/+/g, "/"),
186
+ isDirectory: entry.isDirectory || false,
187
+ size: entry.size || 0,
188
+ lastModified: entry.lastModified ? new Date(entry.lastModified) : /* @__PURE__ */ new Date()
189
+ }));
190
+ },
191
+ exists: async (sandbox, path) => {
192
+ const client = await sandbox.connect();
193
+ try {
194
+ await client.commands.run(`ls "${path}"`);
195
+ return true;
196
+ } catch {
197
+ return false;
198
+ }
199
+ },
200
+ remove: async (sandbox, path) => {
201
+ const client = await sandbox.connect();
202
+ await client.fs.remove(path);
203
+ }
204
+ }
205
+ }
206
+ }
207
+ });
208
+ export {
209
+ codesandbox
210
+ };
211
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Codesandbox Provider - Factory-based Implementation\n * \n * Full-featured provider with filesystem support using the factory pattern.\n */\n\nimport { CodeSandbox } from '@codesandbox/sdk';\nimport type { Sandbox as CodesandboxSandbox } from '@codesandbox/sdk';\nimport { createProvider } from 'computesdk';\nimport type { Runtime, ExecutionResult, SandboxInfo, CreateSandboxOptions, FileEntry } from 'computesdk';\n\n/**\n * Codesandbox-specific configuration options\n */\nexport interface CodesandboxConfig {\n /** CodeSandbox API key - if not provided, will fallback to CSB_API_KEY environment variable */\n apiKey?: string;\n /** Template to use for new sandboxes */\n templateId?: string;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * Create a Codesandbox provider instance using the factory pattern\n */\nexport const codesandbox = createProvider<CodesandboxSandbox, CodesandboxConfig>({\n name: 'codesandbox',\n methods: {\n sandbox: {\n // Collection operations (compute.sandbox.*)\n create: async (config: CodesandboxConfig, options?: CreateSandboxOptions) => {\n // Validate API key\n const apiKey = config.apiKey || (typeof process !== 'undefined' && process.env?.CSB_API_KEY) || '';\n\n if (!apiKey) {\n throw new Error(\n `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`\n );\n }\n\n const sdk = new CodeSandbox(apiKey);\n\n try {\n let sandbox: CodesandboxSandbox;\n let sandboxId: string;\n\n if (options?.sandboxId) {\n // Resume existing CodeSandbox using sdk.sandboxes.resume()\n sandbox = await sdk.sandboxes.resume(options.sandboxId);\n sandboxId = options.sandboxId;\n } else {\n // Create new CodeSandbox using sdk.sandboxes.create()\n const createOptions: any = {};\n \n if (config.templateId) {\n createOptions.id = config.templateId;\n }\n\n sandbox = await sdk.sandboxes.create(createOptions);\n sandboxId = sandbox.id;\n }\n\n return {\n sandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('API key')) {\n throw new Error(\n `CodeSandbox authentication failed. Please check your CSB_API_KEY environment variable. Get your API key from https://codesandbox.io/t/api`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `CodeSandbox quota exceeded. Please check your usage at https://codesandbox.io/dashboard`\n );\n }\n }\n throw new Error(\n `Failed to create CodeSandbox sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: CodesandboxConfig, sandboxId: string) => {\n const apiKey = config.apiKey || (typeof process !== 'undefined' && process.env?.CSB_API_KEY) || '';\n\n if (!apiKey) {\n throw new Error(\n `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`\n );\n }\n\n const sdk = new CodeSandbox(apiKey);\n\n try {\n // Resume existing sandbox using sdk.sandboxes.resume()\n const sandbox = await sdk.sandboxes.resume(sandboxId);\n\n return {\n sandbox,\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: CodesandboxConfig) => {\n throw new Error(\n `CodeSandbox provider does not support listing sandboxes. CodeSandbox SDK does not provide a native list API. Consider using the CodeSandbox dashboard or implement your own tracking system.`\n );\n },\n\n destroy: async (config: CodesandboxConfig, sandboxId: string) => {\n const apiKey = config.apiKey || (typeof process !== 'undefined' && process.env?.CSB_API_KEY) || '';\n\n if (!apiKey) {\n throw new Error(\n `Missing CodeSandbox API key. Provide 'apiKey' in config or set CSB_API_KEY environment variable.`\n );\n }\n\n const sdk = new CodeSandbox(apiKey);\n\n try {\n // Shutdown the sandbox using sdk.sandboxes.shutdown() to clean it up\n await sdk.sandboxes.shutdown(sandboxId);\n } catch (error) {\n // Sandbox might already be shutdown or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (sandbox.*)\n runCode: async (sandbox: CodesandboxSandbox, code: string, runtime?: Runtime): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n // Connect to the sandbox client using sandbox.connect()\n const client = await sandbox.connect();\n\n // Auto-detect runtime if not specified\n const effectiveRuntime = runtime || (\n // Strong Python indicators\n 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 ? 'python'\n // Default to Node.js for all other cases (including ambiguous)\n : 'node'\n );\n\n // Use base64 encoding for reliability and consistency\n const encoded = Buffer.from(code).toString('base64');\n let command: string;\n\n if (effectiveRuntime === 'python') {\n // Execute Python code using client.commands.run()\n command = `echo \"${encoded}\" | base64 -d | python3`;\n } else {\n // Execute Node.js code using client.commands.run()\n command = `echo \"${encoded}\" | base64 -d | node`;\n }\n\n // Execute the command using CodeSandbox client.commands.run()\n // This returns the full output as a string\n const output = await client.commands.run(command);\n\n // Check for syntax errors in the output and throw them (similar to other providers)\n if (output.includes('SyntaxError') || \n output.includes('invalid syntax') ||\n output.includes('Unexpected token') ||\n output.includes('Unexpected identifier')) {\n throw new Error(`Syntax error: ${output.trim()}`);\n }\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\n executionTime: Date.now() - startTime,\n sandboxId: sandbox.id,\n provider: 'codesandbox'\n };\n } catch (error) {\n // Re-throw syntax errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error;\n }\n throw new Error(\n `CodeSandbox execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (sandbox: CodesandboxSandbox, command: string, args: string[] = []): Promise<ExecutionResult> => {\n const startTime = Date.now();\n\n try {\n // Connect to the sandbox client using sandbox.connect()\n const client = await sandbox.connect();\n\n // Construct full command with arguments\n const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;\n\n // Execute command using CodeSandbox client.commands.run()\n // This returns the full output as a string\n const output = await client.commands.run(fullCommand);\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\n executionTime: Date.now() - startTime,\n sandboxId: sandbox.id,\n provider: 'codesandbox'\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: sandbox.id,\n provider: 'codesandbox'\n };\n }\n },\n\n getInfo: async (sandbox: CodesandboxSandbox): Promise<SandboxInfo> => {\n return {\n id: sandbox.id,\n provider: 'codesandbox',\n runtime: 'node', // CodeSandbox default\n status: 'running',\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n cluster: sandbox.cluster,\n bootupType: sandbox.bootupType,\n isUpToDate: sandbox.isUpToDate\n }\n };\n },\n\n // Filesystem operations using CodeSandbox client.fs API\n filesystem: {\n readFile: async (sandbox: CodesandboxSandbox, path: string): Promise<string> => {\n // Connect to the sandbox client and use client.fs.readTextFile()\n const client = await sandbox.connect();\n return await client.fs.readTextFile(path);\n },\n\n writeFile: async (sandbox: CodesandboxSandbox, path: string, content: string): Promise<void> => {\n // Connect to the sandbox client and use client.fs.writeTextFile()\n const client = await sandbox.connect();\n await client.fs.writeTextFile(path, content);\n },\n\n mkdir: async (sandbox: CodesandboxSandbox, path: string): Promise<void> => {\n // CodeSandbox doesn't have a direct mkdir API, use commands to create directory\n const client = await sandbox.connect();\n await client.commands.run(`mkdir -p \"${path}\"`);\n },\n\n readdir: async (sandbox: CodesandboxSandbox, path: string): Promise<FileEntry[]> => {\n // Connect to the sandbox client and use client.fs.readdir()\n const client = await sandbox.connect();\n const entries = await client.fs.readdir(path);\n\n return entries.map((entry: any) => ({\n name: entry.name,\n path: `${path}/${entry.name}`.replace(/\\/+/g, '/'),\n isDirectory: entry.isDirectory || false,\n size: entry.size || 0,\n lastModified: entry.lastModified ? new Date(entry.lastModified) : new Date()\n }));\n },\n\n exists: async (sandbox: CodesandboxSandbox, path: string): Promise<boolean> => {\n // CodeSandbox doesn't have a direct exists API, use ls command to check\n const client = await sandbox.connect();\n try {\n await client.commands.run(`ls \"${path}\"`);\n return true;\n } catch {\n return false;\n }\n },\n\n remove: async (sandbox: CodesandboxSandbox, path: string): Promise<void> => {\n // Connect to the sandbox client and use client.fs.remove()\n const client = await sandbox.connect();\n await client.fs.remove(path);\n }\n }\n }\n }\n});\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@computesdk/codesandbox",
3
+ "version": "1.0.1",
4
+ "description": "CodeSandbox 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
+ "@codesandbox/sdk": "^2.0.7",
22
+ "computesdk": "1.1.1"
23
+ },
24
+ "keywords": [
25
+ "codesandbox",
26
+ "sandbox",
27
+ "code-execution",
28
+ "javascript",
29
+ "python",
30
+ "cloud",
31
+ "compute"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/computesdk/computesdk.git",
36
+ "directory": "packages/codesandbox"
37
+ },
38
+ "homepage": "https://github.com/computesdk/computesdk/tree/main/packages/codesandbox",
39
+ "bugs": {
40
+ "url": "https://github.com/computesdk/computesdk/issues"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "@vitest/coverage-v8": "^1.0.0",
45
+ "eslint": "^8.37.0",
46
+ "rimraf": "^5.0.0",
47
+ "tsup": "^8.0.0",
48
+ "typescript": "^5.0.0",
49
+ "vitest": "^1.0.0",
50
+ "@computesdk/test-utils": "1.1.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "clean": "rimraf dist",
55
+ "dev": "tsup --watch",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest watch",
58
+ "test:coverage": "vitest run --coverage",
59
+ "typecheck": "tsc --noEmit",
60
+ "lint": "eslint"
61
+ }
62
+ }