@computesdk/codesandbox 1.5.7 → 1.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -18
- package/dist/index.js +12 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -17,20 +17,16 @@ npm install @computesdk/codesandbox
|
|
|
17
17
|
export CSB_API_KEY=your_api_key_here
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Quick Start
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Gateway Mode (Recommended)
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
import { createCompute } from 'computesdk';
|
|
26
|
-
import { codesandbox } from '@computesdk/codesandbox';
|
|
24
|
+
Use the gateway for zero-config auto-detection:
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
provider: codesandbox({ apiKey: process.env.CSB_API_KEY })
|
|
31
|
-
});
|
|
26
|
+
```typescript
|
|
27
|
+
import { compute } from 'computesdk';
|
|
32
28
|
|
|
33
|
-
//
|
|
29
|
+
// Auto-detects CodeSandbox from CSB_API_KEY environment variable
|
|
34
30
|
const sandbox = await compute.sandbox.create();
|
|
35
31
|
|
|
36
32
|
// Execute JavaScript/Node.js code
|
|
@@ -66,24 +62,28 @@ console.log(pythonResult.stdout);
|
|
|
66
62
|
// }
|
|
67
63
|
// Running in: CodeSandbox
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
await compute.sandbox.destroy(sandbox.sandboxId);
|
|
65
|
+
await sandbox.destroy();
|
|
71
66
|
```
|
|
72
67
|
|
|
73
|
-
### Direct
|
|
68
|
+
### Direct Mode
|
|
69
|
+
|
|
70
|
+
For direct SDK usage without the gateway:
|
|
74
71
|
|
|
75
72
|
```typescript
|
|
76
73
|
import { codesandbox } from '@computesdk/codesandbox';
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
apiKey: 'your_api_key',
|
|
75
|
+
const compute = codesandbox({
|
|
76
|
+
apiKey: process.env.CSB_API_KEY,
|
|
81
77
|
templateId: 'universal', // Optional: specify template
|
|
82
78
|
timeout: 600000 // 10 minutes
|
|
83
79
|
});
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
const sandbox = await compute.sandbox.create();
|
|
82
|
+
|
|
83
|
+
const result = await sandbox.runCode('console.log("Hello from CodeSandbox!");');
|
|
84
|
+
console.log(result.stdout);
|
|
85
|
+
|
|
86
|
+
await sandbox.destroy();
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
## Configuration
|
package/dist/index.js
CHANGED
|
@@ -142,17 +142,21 @@ var codesandbox = (0, import_provider.defineProvider)({
|
|
|
142
142
|
);
|
|
143
143
|
}
|
|
144
144
|
},
|
|
145
|
-
runCommand: async (sandbox, command,
|
|
145
|
+
runCommand: async (sandbox, command, options) => {
|
|
146
146
|
const startTime = Date.now();
|
|
147
147
|
try {
|
|
148
148
|
const client = await sandbox.connect();
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
let fullCommand = command;
|
|
150
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
151
|
+
const envPrefix = Object.entries(options.env).map(([k, v]) => `${k}="${(0, import_provider.escapeShellArg)(v)}"`).join(" ");
|
|
152
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
153
|
+
}
|
|
154
|
+
if (options?.cwd) {
|
|
155
|
+
fullCommand = `cd "${(0, import_provider.escapeShellArg)(options.cwd)}" && ${fullCommand}`;
|
|
156
|
+
}
|
|
157
|
+
if (options?.background) {
|
|
158
|
+
fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
|
|
159
|
+
}
|
|
156
160
|
const output = await client.commands.run(fullCommand);
|
|
157
161
|
return {
|
|
158
162
|
stdout: output,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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 { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\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 = defineProvider<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<CodeResult> => {\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 code.includes('raise ')\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 output: output,\n exitCode: 0,\n language: effectiveRuntime\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<CommandResult> => {\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, properly quoting each arg\n const quotedArgs = args.map((arg: string) => {\n if (arg.includes(' ') || arg.includes('\"') || arg.includes(\"'\") || arg.includes('$') || arg.includes('`')) {\n return `\"${arg.replace(/\"/g, '\\\\\"')}\"`;\n }\n return arg;\n });\n const fullCommand = quotedArgs.length > 0 ? `${command} ${quotedArgs.join(' ')}` : command;\n\n // Execute command using CodeSandbox client.commands.run()\n const output = await client.commands.run(fullCommand);\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\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 (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 getUrl: async (sandbox: CodesandboxSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n const protocol = options.protocol || 'https';\n // CodeSandbox provides URLs in the format: https://{sandbox-id}.{cluster}.csb.app:{port}\n // Use the actual CodeSandbox URL format\n return `${protocol}://${sandbox.id}.${sandbox.cluster}.csb.app:${options.port}`;\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 type: entry.isDirectory ? 'directory' as const : 'file' as const,\n size: entry.size || 0,\n modified: 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 // Provider-specific typed getInstance method\n getInstance: (sandbox: CodesandboxSandbox): CodesandboxSandbox => {\n return sandbox;\n },\n\n }\n }\n});\n"],"mappings":"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","names":[]}
|
|
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 { defineProvider, escapeShellArg } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\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 = defineProvider<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<CodeResult> => {\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 code.includes('raise ')\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 output: output,\n exitCode: 0,\n language: effectiveRuntime\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, options?: RunCommandOptions): Promise<CommandResult> => {\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 // Build command with options\n let fullCommand = command;\n \n // Handle environment variables\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env)\n .map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`)\n .join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n \n // Handle working directory\n if (options?.cwd) {\n fullCommand = `cd \"${escapeShellArg(options.cwd)}\" && ${fullCommand}`;\n }\n \n // Handle background execution\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n // Execute command using CodeSandbox client.commands.run()\n const output = await client.commands.run(fullCommand);\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\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 (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 getUrl: async (sandbox: CodesandboxSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n const protocol = options.protocol || 'https';\n // CodeSandbox provides URLs in the format: https://{sandbox-id}.{cluster}.csb.app:{port}\n // Use the actual CodeSandbox URL format\n return `${protocol}://${sandbox.id}.${sandbox.cluster}.csb.app:${options.port}`;\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 type: entry.isDirectory ? 'directory' as const : 'file' as const,\n size: entry.size || 0,\n modified: 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 // Provider-specific typed getInstance method\n getInstance: (sandbox: CodesandboxSandbox): CodesandboxSandbox => {\n return sandbox;\n },\n\n }\n }\n});\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { CodeSandbox } from "@codesandbox/sdk";
|
|
3
|
-
import { defineProvider } from "@computesdk/provider";
|
|
3
|
+
import { defineProvider, escapeShellArg } from "@computesdk/provider";
|
|
4
4
|
var codesandbox = defineProvider({
|
|
5
5
|
name: "codesandbox",
|
|
6
6
|
methods: {
|
|
@@ -118,17 +118,21 @@ var codesandbox = defineProvider({
|
|
|
118
118
|
);
|
|
119
119
|
}
|
|
120
120
|
},
|
|
121
|
-
runCommand: async (sandbox, command,
|
|
121
|
+
runCommand: async (sandbox, command, options) => {
|
|
122
122
|
const startTime = Date.now();
|
|
123
123
|
try {
|
|
124
124
|
const client = await sandbox.connect();
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
let fullCommand = command;
|
|
126
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
127
|
+
const envPrefix = Object.entries(options.env).map(([k, v]) => `${k}="${escapeShellArg(v)}"`).join(" ");
|
|
128
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
129
|
+
}
|
|
130
|
+
if (options?.cwd) {
|
|
131
|
+
fullCommand = `cd "${escapeShellArg(options.cwd)}" && ${fullCommand}`;
|
|
132
|
+
}
|
|
133
|
+
if (options?.background) {
|
|
134
|
+
fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;
|
|
135
|
+
}
|
|
132
136
|
const output = await client.commands.run(fullCommand);
|
|
133
137
|
return {
|
|
134
138
|
stdout: output,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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 { defineProvider } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\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 = defineProvider<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<CodeResult> => {\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 code.includes('raise ')\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 output: output,\n exitCode: 0,\n language: effectiveRuntime\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<CommandResult> => {\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, properly quoting each arg\n const quotedArgs = args.map((arg: string) => {\n if (arg.includes(' ') || arg.includes('\"') || arg.includes(\"'\") || arg.includes('$') || arg.includes('`')) {\n return `\"${arg.replace(/\"/g, '\\\\\"')}\"`;\n }\n return arg;\n });\n const fullCommand = quotedArgs.length > 0 ? `${command} ${quotedArgs.join(' ')}` : command;\n\n // Execute command using CodeSandbox client.commands.run()\n const output = await client.commands.run(fullCommand);\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\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 (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 getUrl: async (sandbox: CodesandboxSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n const protocol = options.protocol || 'https';\n // CodeSandbox provides URLs in the format: https://{sandbox-id}.{cluster}.csb.app:{port}\n // Use the actual CodeSandbox URL format\n return `${protocol}://${sandbox.id}.${sandbox.cluster}.csb.app:${options.port}`;\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 type: entry.isDirectory ? 'directory' as const : 'file' as const,\n size: entry.size || 0,\n modified: 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 // Provider-specific typed getInstance method\n getInstance: (sandbox: CodesandboxSandbox): CodesandboxSandbox => {\n return sandbox;\n },\n\n }\n }\n});\n"],"mappings":"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","names":[]}
|
|
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 { defineProvider, escapeShellArg } from '@computesdk/provider';\n\nimport type { Runtime, CodeResult, CommandResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from '@computesdk/provider';\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 = defineProvider<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<CodeResult> => {\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 code.includes('raise ')\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 output: output,\n exitCode: 0,\n language: effectiveRuntime\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, options?: RunCommandOptions): Promise<CommandResult> => {\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 // Build command with options\n let fullCommand = command;\n \n // Handle environment variables\n if (options?.env && Object.keys(options.env).length > 0) {\n const envPrefix = Object.entries(options.env)\n .map(([k, v]) => `${k}=\"${escapeShellArg(v)}\"`)\n .join(' ');\n fullCommand = `${envPrefix} ${fullCommand}`;\n }\n \n // Handle working directory\n if (options?.cwd) {\n fullCommand = `cd \"${escapeShellArg(options.cwd)}\" && ${fullCommand}`;\n }\n \n // Handle background execution\n if (options?.background) {\n fullCommand = `nohup ${fullCommand} > /dev/null 2>&1 &`;\n }\n\n // Execute command using CodeSandbox client.commands.run()\n const output = await client.commands.run(fullCommand);\n\n return {\n stdout: output,\n stderr: '',\n exitCode: 0,\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 (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 getUrl: async (sandbox: CodesandboxSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n const protocol = options.protocol || 'https';\n // CodeSandbox provides URLs in the format: https://{sandbox-id}.{cluster}.csb.app:{port}\n // Use the actual CodeSandbox URL format\n return `${protocol}://${sandbox.id}.${sandbox.cluster}.csb.app:${options.port}`;\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 type: entry.isDirectory ? 'directory' as const : 'file' as const,\n size: entry.size || 0,\n modified: 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 // Provider-specific typed getInstance method\n getInstance: (sandbox: CodesandboxSandbox): CodesandboxSandbox => {\n return sandbox;\n },\n\n }\n }\n});\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computesdk/codesandbox",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.9",
|
|
4
4
|
"description": "CodeSandbox provider for ComputeSDK - fast browser-compatible sandboxes with npm and Python support",
|
|
5
5
|
"author": "Garrison",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@codesandbox/sdk": "^2.0.7",
|
|
22
|
-
"@computesdk/provider": "1.0.
|
|
23
|
-
"computesdk": "1.10.
|
|
22
|
+
"@computesdk/provider": "1.0.3",
|
|
23
|
+
"computesdk": "1.10.2"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"computesdk",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"tsup": "^8.0.0",
|
|
52
52
|
"typescript": "^5.0.0",
|
|
53
53
|
"vitest": "^1.0.0",
|
|
54
|
-
"@computesdk/test-utils": "1.5.
|
|
54
|
+
"@computesdk/test-utils": "1.5.1"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup",
|