@cloudflare/sandbox 0.3.1 → 0.3.2

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/Dockerfile +22 -24
  3. package/README.md +1 -1
  4. package/container_src/bun.lock +31 -77
  5. package/container_src/control-process.ts +1 -1
  6. package/container_src/index.ts +34 -43
  7. package/container_src/interpreter-service.ts +276 -0
  8. package/container_src/isolation.ts +1 -1
  9. package/container_src/mime-processor.ts +1 -1
  10. package/container_src/package.json +4 -4
  11. package/container_src/runtime/executors/javascript/node_executor.ts +123 -0
  12. package/container_src/runtime/executors/python/ipython_executor.py +338 -0
  13. package/container_src/runtime/executors/typescript/ts_executor.ts +138 -0
  14. package/container_src/runtime/process-pool.ts +464 -0
  15. package/container_src/startup.sh +6 -79
  16. package/dist/{chunk-LALY4SFU.js → chunk-FXYPFGOZ.js} +10 -10
  17. package/dist/chunk-FXYPFGOZ.js.map +1 -0
  18. package/dist/{chunk-LFLJGISB.js → chunk-H4PW2LGW.js} +6 -6
  19. package/dist/chunk-H4PW2LGW.js.map +1 -0
  20. package/dist/{chunk-FKBV7CZS.js → chunk-JTKON2SH.js} +9 -9
  21. package/dist/chunk-JTKON2SH.js.map +1 -0
  22. package/dist/{chunk-EGC5IYXA.js → chunk-W7TVRPBG.js} +2 -2
  23. package/dist/chunk-W7TVRPBG.js.map +1 -0
  24. package/dist/{chunk-BEQUGUY4.js → chunk-Z6OZPC6U.js} +9 -6
  25. package/dist/chunk-Z6OZPC6U.js.map +1 -0
  26. package/dist/{client-Dny_ro_v.d.ts → client-COGWU6bz.d.ts} +3 -3
  27. package/dist/client.d.ts +1 -1
  28. package/dist/errors.d.ts +9 -9
  29. package/dist/errors.js +5 -5
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +13 -11
  32. package/dist/interpreter-client.d.ts +4 -0
  33. package/dist/interpreter-client.js +9 -0
  34. package/dist/interpreter-types.d.ts +5 -5
  35. package/dist/interpreter-types.js +1 -1
  36. package/dist/interpreter.d.ts +2 -2
  37. package/dist/interpreter.js +2 -2
  38. package/dist/request-handler.d.ts +1 -1
  39. package/dist/request-handler.js +5 -5
  40. package/dist/sandbox.d.ts +1 -1
  41. package/dist/sandbox.js +5 -5
  42. package/package.json +1 -1
  43. package/src/errors.ts +15 -14
  44. package/src/index.ts +16 -5
  45. package/src/{jupyter-client.ts → interpreter-client.ts} +6 -3
  46. package/src/interpreter-types.ts +102 -95
  47. package/src/interpreter.ts +8 -8
  48. package/src/sandbox.ts +3 -3
  49. package/container_src/jupyter-server.ts +0 -579
  50. package/container_src/jupyter-service.ts +0 -461
  51. package/container_src/jupyter_config.py +0 -48
  52. package/dist/chunk-BEQUGUY4.js.map +0 -1
  53. package/dist/chunk-EGC5IYXA.js.map +0 -1
  54. package/dist/chunk-FKBV7CZS.js.map +0 -1
  55. package/dist/chunk-LALY4SFU.js.map +0 -1
  56. package/dist/chunk-LFLJGISB.js.map +0 -1
  57. package/dist/jupyter-client.d.ts +0 -4
  58. package/dist/jupyter-client.js +0 -9
  59. /package/dist/{jupyter-client.js.map → interpreter-client.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sandbox.ts","../src/request-handler.ts"],"sourcesContent":["import { Container, getContainer } from \"@cloudflare/containers\";\nimport { CodeInterpreter } from \"./interpreter\";\nimport { InterpreterClient } from \"./interpreter-client\";\nimport type {\n CodeContext,\n CreateContextOptions,\n ExecutionResult,\n RunCodeOptions,\n} from \"./interpreter-types\";\nimport { isLocalhostPattern } from \"./request-handler\";\nimport {\n logSecurityEvent,\n SecurityError,\n sanitizeSandboxId,\n validatePort,\n} from \"./security\";\nimport { parseSSEStream } from \"./sse-parser\";\nimport type {\n ExecEvent,\n ExecOptions,\n ExecResult,\n ExecuteResponse,\n ExecutionSession,\n ISandbox,\n Process,\n ProcessOptions,\n ProcessStatus,\n StreamOptions,\n} from \"./types\";\nimport { ProcessNotFoundError, SandboxError } from \"./types\";\n\nexport function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string) {\n const stub = getContainer(ns, id);\n\n // Store the name on first access\n stub.setSandboxName?.(id);\n\n return stub;\n}\n\nexport class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {\n defaultPort = 3000; // Default port for the container's Bun server\n sleepAfter = \"20m\"; // Keep container warm for 20 minutes to avoid cold starts\n client: InterpreterClient;\n private sandboxName: string | null = null;\n private codeInterpreter: CodeInterpreter;\n private defaultSession: ExecutionSession | null = null;\n\n constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n this.client = new InterpreterClient({\n onCommandComplete: (success, exitCode, _stdout, _stderr, command) => {\n console.log(\n `[Container] Command completed: ${command}, Success: ${success}, Exit code: ${exitCode}`\n );\n },\n onCommandStart: (command) => {\n console.log(`[Container] Command started: ${command}`);\n },\n onError: (error, _command) => {\n console.error(`[Container] Command error: ${error}`);\n },\n onOutput: (stream, data, _command) => {\n console.log(`[Container] [${stream}] ${data}`);\n },\n port: 3000, // Control plane port\n stub: this,\n });\n\n // Initialize code interpreter\n this.codeInterpreter = new CodeInterpreter(this);\n\n // Load the sandbox name from storage on initialization\n this.ctx.blockConcurrencyWhile(async () => {\n this.sandboxName =\n (await this.ctx.storage.get<string>(\"sandboxName\")) || null;\n });\n }\n\n // RPC method to set the sandbox name\n async setSandboxName(name: string): Promise<void> {\n if (!this.sandboxName) {\n this.sandboxName = name;\n await this.ctx.storage.put(\"sandboxName\", name);\n console.log(`[Sandbox] Stored sandbox name via RPC: ${name}`);\n }\n }\n\n // RPC method to set environment variables\n async setEnvVars(envVars: Record<string, string>): Promise<void> {\n this.envVars = { ...this.envVars, ...envVars };\n console.log(`[Sandbox] Updated environment variables`);\n \n // If we have a default session, update its environment too\n if (this.defaultSession) {\n await this.defaultSession.setEnvVars(envVars);\n }\n }\n\n override onStart() {\n console.log(\"Sandbox successfully started\");\n }\n\n override onStop() {\n console.log(\"Sandbox successfully shut down\");\n }\n\n override onError(error: unknown) {\n console.log(\"Sandbox error:\", error);\n }\n\n // Override fetch to route internal container requests to appropriate ports\n override async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n\n // Capture and store the sandbox name from the header if present\n if (!this.sandboxName && request.headers.has(\"X-Sandbox-Name\")) {\n const name = request.headers.get(\"X-Sandbox-Name\")!;\n this.sandboxName = name;\n await this.ctx.storage.put(\"sandboxName\", name);\n console.log(`[Sandbox] Stored sandbox name: ${this.sandboxName}`);\n }\n\n // Determine which port to route to\n const port = this.determinePort(url);\n\n // Route to the appropriate port\n return await this.containerFetch(request, port);\n }\n\n private determinePort(url: URL): number {\n // Extract port from proxy requests (e.g., /proxy/8080/*)\n const proxyMatch = url.pathname.match(/^\\/proxy\\/(\\d+)/);\n if (proxyMatch) {\n return parseInt(proxyMatch[1]);\n }\n\n if (url.port) {\n return parseInt(url.port);\n }\n\n // All other requests go to control plane on port 3000\n // This includes /api/* endpoints and any other control requests\n return 3000;\n }\n\n // Helper to ensure default session is initialized\n private async ensureDefaultSession(): Promise<ExecutionSession> {\n if (!this.defaultSession) {\n const sessionId = `sandbox-${this.sandboxName || 'default'}`;\n this.defaultSession = await this.createSession({\n id: sessionId,\n env: this.envVars || {},\n cwd: '/workspace',\n isolation: true\n });\n console.log(`[Sandbox] Default session initialized: ${sessionId}`);\n }\n return this.defaultSession;\n }\n\n\n async exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n const session = await this.ensureDefaultSession();\n return session.exec(command, options);\n }\n\n async startProcess(\n command: string,\n options?: ProcessOptions\n ): Promise<Process> {\n const session = await this.ensureDefaultSession();\n return session.startProcess(command, options);\n }\n\n async listProcesses(): Promise<Process[]> {\n const session = await this.ensureDefaultSession();\n return session.listProcesses();\n }\n\n async getProcess(id: string): Promise<Process | null> {\n const session = await this.ensureDefaultSession();\n return session.getProcess(id);\n }\n\n async killProcess(id: string, signal?: string): Promise<void> {\n const session = await this.ensureDefaultSession();\n return session.killProcess(id, signal);\n }\n\n async killAllProcesses(): Promise<number> {\n const session = await this.ensureDefaultSession();\n return session.killAllProcesses();\n }\n\n async cleanupCompletedProcesses(): Promise<number> {\n const session = await this.ensureDefaultSession();\n return session.cleanupCompletedProcesses();\n }\n\n async getProcessLogs(\n id: string\n ): Promise<{ stdout: string; stderr: string }> {\n const session = await this.ensureDefaultSession();\n return session.getProcessLogs(id);\n }\n\n // Streaming methods - delegates to default session\n async execStream(\n command: string,\n options?: StreamOptions\n ): Promise<ReadableStream<Uint8Array>> {\n const session = await this.ensureDefaultSession();\n return session.execStream(command, options);\n }\n\n async streamProcessLogs(\n processId: string,\n options?: { signal?: AbortSignal }\n ): Promise<ReadableStream<Uint8Array>> {\n const session = await this.ensureDefaultSession();\n return session.streamProcessLogs(processId, options);\n }\n\n async gitCheckout(\n repoUrl: string,\n options: { branch?: string; targetDir?: string }\n ) {\n const session = await this.ensureDefaultSession();\n return session.gitCheckout(repoUrl, options);\n }\n\n async mkdir(path: string, options: { recursive?: boolean } = {}) {\n const session = await this.ensureDefaultSession();\n return session.mkdir(path, options);\n }\n\n async writeFile(\n path: string,\n content: string,\n options: { encoding?: string } = {}\n ) {\n const session = await this.ensureDefaultSession();\n return session.writeFile(path, content, options);\n }\n\n async deleteFile(path: string) {\n const session = await this.ensureDefaultSession();\n return session.deleteFile(path);\n }\n\n async renameFile(oldPath: string, newPath: string) {\n const session = await this.ensureDefaultSession();\n return session.renameFile(oldPath, newPath);\n }\n\n async moveFile(sourcePath: string, destinationPath: string) {\n const session = await this.ensureDefaultSession();\n return session.moveFile(sourcePath, destinationPath);\n }\n\n async readFile(path: string, options: { encoding?: string } = {}) {\n const session = await this.ensureDefaultSession();\n return session.readFile(path, options);\n }\n\n async listFiles(\n path: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ) {\n const session = await this.ensureDefaultSession();\n return session.listFiles(path, options);\n }\n\n async exposePort(port: number, options: { name?: string; hostname: string }) {\n await this.client.exposePort(port, options?.name);\n\n // We need the sandbox name to construct preview URLs\n if (!this.sandboxName) {\n throw new Error(\n \"Sandbox name not available. Ensure sandbox is accessed through getSandbox()\"\n );\n }\n\n const url = this.constructPreviewUrl(\n port,\n this.sandboxName,\n options.hostname\n );\n\n return {\n url,\n port,\n name: options?.name,\n };\n }\n\n async unexposePort(port: number) {\n if (!validatePort(port)) {\n logSecurityEvent(\n \"INVALID_PORT_UNEXPOSE\",\n {\n port,\n },\n \"high\"\n );\n throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n await this.client.unexposePort(port);\n\n logSecurityEvent(\n \"PORT_UNEXPOSED\",\n {\n port,\n },\n \"low\"\n );\n }\n\n async getExposedPorts(hostname: string) {\n const response = await this.client.getExposedPorts();\n\n // We need the sandbox name to construct preview URLs\n if (!this.sandboxName) {\n throw new Error(\n \"Sandbox name not available. Ensure sandbox is accessed through getSandbox()\"\n );\n }\n\n return response.ports.map((port) => ({\n url: this.constructPreviewUrl(port.port, this.sandboxName!, hostname),\n port: port.port,\n name: port.name,\n exposedAt: port.exposedAt,\n }));\n }\n\n private constructPreviewUrl(\n port: number,\n sandboxId: string,\n hostname: string\n ): string {\n if (!validatePort(port)) {\n logSecurityEvent(\n \"INVALID_PORT_REJECTED\",\n {\n port,\n sandboxId,\n hostname,\n },\n \"high\"\n );\n throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n let sanitizedSandboxId: string;\n try {\n sanitizedSandboxId = sanitizeSandboxId(sandboxId);\n } catch (error) {\n logSecurityEvent(\n \"INVALID_SANDBOX_ID_REJECTED\",\n {\n sandboxId,\n port,\n hostname,\n error: error instanceof Error ? error.message : \"Unknown error\",\n },\n \"high\"\n );\n throw error;\n }\n\n const isLocalhost = isLocalhostPattern(hostname);\n\n if (isLocalhost) {\n // Unified subdomain approach for localhost (RFC 6761)\n const [host, portStr] = hostname.split(\":\");\n const mainPort = portStr || \"80\";\n\n // Use URL constructor for safe URL building\n try {\n const baseUrl = new URL(`http://${host}:${mainPort}`);\n // Construct subdomain safely\n const subdomainHost = `${port}-${sanitizedSandboxId}.${host}`;\n baseUrl.hostname = subdomainHost;\n\n const finalUrl = baseUrl.toString();\n\n logSecurityEvent(\n \"PREVIEW_URL_CONSTRUCTED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n resultUrl: finalUrl,\n environment: \"localhost\",\n },\n \"low\"\n );\n\n return finalUrl;\n } catch (error) {\n logSecurityEvent(\n \"URL_CONSTRUCTION_FAILED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n error: error instanceof Error ? error.message : \"Unknown error\",\n },\n \"high\"\n );\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n }\n }\n\n // Production subdomain logic - enforce HTTPS\n try {\n // Always use HTTPS for production (non-localhost)\n const protocol = \"https\";\n const baseUrl = new URL(`${protocol}://${hostname}`);\n\n // Construct subdomain safely\n const subdomainHost = `${port}-${sanitizedSandboxId}.${hostname}`;\n baseUrl.hostname = subdomainHost;\n\n const finalUrl = baseUrl.toString();\n\n logSecurityEvent(\n \"PREVIEW_URL_CONSTRUCTED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n resultUrl: finalUrl,\n environment: \"production\",\n },\n \"low\"\n );\n\n return finalUrl;\n } catch (error) {\n logSecurityEvent(\n \"URL_CONSTRUCTION_FAILED\",\n {\n port,\n sandboxId: sanitizedSandboxId,\n hostname,\n error: error instanceof Error ? error.message : \"Unknown error\",\n },\n \"high\"\n );\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n }\n }\n\n // Code Interpreter Methods\n\n /**\n * Create a new code execution context\n */\n async createCodeContext(\n options?: CreateContextOptions\n ): Promise<CodeContext> {\n return this.codeInterpreter.createCodeContext(options);\n }\n\n /**\n * Run code with streaming callbacks\n */\n async runCode(\n code: string,\n options?: RunCodeOptions\n ): Promise<ExecutionResult> {\n const execution = await this.codeInterpreter.runCode(code, options);\n // Convert to plain object for RPC serialization\n return execution.toJSON();\n }\n\n /**\n * Run code and return a streaming response\n */\n async runCodeStream(\n code: string,\n options?: RunCodeOptions\n ): Promise<ReadableStream> {\n return this.codeInterpreter.runCodeStream(code, options);\n }\n\n /**\n * List all code contexts\n */\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.codeInterpreter.listCodeContexts();\n }\n\n /**\n * Delete a code context\n */\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.codeInterpreter.deleteCodeContext(contextId);\n }\n\n // ============================================================================\n // Session Management (Simple Isolation)\n // ============================================================================\n\n /**\n * Create a new execution session with isolation\n * Returns a session object with exec() method\n */\n\n async createSession(options: {\n id?: string;\n env?: Record<string, string>;\n cwd?: string;\n isolation?: boolean;\n }): Promise<ExecutionSession> {\n const sessionId = options.id || `session-${Date.now()}`;\n \n await this.client.createSession({\n id: sessionId,\n env: options.env,\n cwd: options.cwd,\n isolation: options.isolation\n });\n // Return comprehensive ExecutionSession object that implements all ISandbox methods\n return {\n id: sessionId,\n \n // Command execution - clean method names\n exec: async (command: string, options?: ExecOptions) => {\n const result = await this.client.exec(sessionId, command);\n return {\n ...result,\n command,\n duration: 0,\n timestamp: new Date().toISOString()\n };\n },\n \n execStream: async (command: string, options?: StreamOptions) => {\n return await this.client.execStream(sessionId, command);\n },\n \n // Process management - route to session-aware methods\n startProcess: async (command: string, options?: ProcessOptions) => {\n // Use session-specific process management\n const response = await this.client.startProcess(command, sessionId, {\n processId: options?.processId,\n timeout: options?.timeout,\n env: options?.env,\n cwd: options?.cwd,\n encoding: options?.encoding,\n autoCleanup: options?.autoCleanup,\n });\n \n // Convert response to Process object with bound methods\n const process = response.process;\n return {\n id: process.id,\n pid: process.pid,\n command: process.command,\n status: process.status as ProcessStatus,\n startTime: new Date(process.startTime),\n endTime: process.endTime ? new Date(process.endTime) : undefined,\n exitCode: process.exitCode ?? undefined,\n kill: async (signal?: string) => {\n await this.client.killProcess(process.id);\n },\n getStatus: async () => {\n const resp = await this.client.getProcess(process.id);\n return resp.process?.status as ProcessStatus || \"error\";\n },\n getLogs: async () => {\n return await this.client.getProcessLogs(process.id);\n },\n };\n },\n \n listProcesses: async () => {\n // Get processes for this specific session\n const response = await this.client.listProcesses(sessionId);\n \n // Convert to Process objects with bound methods\n return response.processes.map(p => ({\n id: p.id,\n pid: p.pid,\n command: p.command,\n status: p.status as ProcessStatus,\n startTime: new Date(p.startTime),\n endTime: p.endTime ? new Date(p.endTime) : undefined,\n exitCode: p.exitCode ?? undefined,\n kill: async (signal?: string) => {\n await this.client.killProcess(p.id);\n },\n getStatus: async () => {\n const processResp = await this.client.getProcess(p.id);\n return processResp.process?.status as ProcessStatus || \"error\";\n },\n getLogs: async () => {\n return this.client.getProcessLogs(p.id);\n },\n }));\n },\n \n getProcess: async (id: string) => {\n const response = await this.client.getProcess(id);\n if (!response.process) return null;\n \n const p = response.process;\n return {\n id: p.id,\n pid: p.pid,\n command: p.command,\n status: p.status as ProcessStatus,\n startTime: new Date(p.startTime),\n endTime: p.endTime ? new Date(p.endTime) : undefined,\n exitCode: p.exitCode ?? undefined,\n kill: async (signal?: string) => {\n await this.client.killProcess(p.id);\n },\n getStatus: async () => {\n const processResp = await this.client.getProcess(p.id);\n return processResp.process?.status as ProcessStatus || \"error\";\n },\n getLogs: async () => {\n return this.client.getProcessLogs(p.id);\n },\n };\n },\n \n killProcess: async (id: string, signal?: string) => {\n await this.client.killProcess(id);\n },\n \n killAllProcesses: async () => {\n // Kill all processes for this specific session\n const response = await this.client.killAllProcesses(sessionId);\n return response.killedCount;\n },\n \n streamProcessLogs: async (processId: string, options?: { signal?: AbortSignal }) => {\n return await this.client.streamProcessLogs(processId, options);\n },\n \n getProcessLogs: async (id: string) => {\n return await this.client.getProcessLogs(id);\n },\n \n cleanupCompletedProcesses: async () => {\n // This would need a new endpoint to cleanup processes for a specific session\n // For now, return 0 as no cleanup is performed\n return 0;\n },\n \n // File operations - clean method names (no \"InSession\" suffix)\n writeFile: async (path: string, content: string, options?: { encoding?: string }) => {\n return await this.client.writeFile(path, content, options?.encoding, sessionId);\n },\n \n readFile: async (path: string, options?: { encoding?: string }) => {\n return await this.client.readFile(path, options?.encoding, sessionId);\n },\n \n mkdir: async (path: string, options?: { recursive?: boolean }) => {\n return await this.client.mkdir(path, options?.recursive, sessionId);\n },\n \n deleteFile: async (path: string) => {\n return await this.client.deleteFile(path, sessionId);\n },\n \n renameFile: async (oldPath: string, newPath: string) => {\n return await this.client.renameFile(oldPath, newPath, sessionId);\n },\n \n moveFile: async (sourcePath: string, destinationPath: string) => {\n return await this.client.moveFile(sourcePath, destinationPath, sessionId);\n },\n \n listFiles: async (path: string, options?: { recursive?: boolean; includeHidden?: boolean }) => {\n return await this.client.listFiles(path, sessionId, options);\n },\n \n gitCheckout: async (repoUrl: string, options?: { branch?: string; targetDir?: string }) => {\n return await this.client.gitCheckout(repoUrl, sessionId, options?.branch, options?.targetDir);\n },\n \n // Port management\n exposePort: async (port: number, options: { name?: string; hostname: string }) => {\n return await this.exposePort(port, options);\n },\n \n unexposePort: async (port: number) => {\n return await this.unexposePort(port);\n },\n \n getExposedPorts: async (hostname: string) => {\n return await this.getExposedPorts(hostname);\n },\n \n // Environment management\n setEnvVars: async (envVars: Record<string, string>) => {\n // TODO: Implement session-specific environment updates\n console.log(`[Session ${sessionId}] Environment variables update not yet implemented`);\n },\n \n // Code Interpreter API\n createCodeContext: async (options?: any) => {\n return await this.createCodeContext(options);\n },\n \n runCode: async (code: string, options?: any) => {\n return await this.runCode(code, options);\n },\n \n runCodeStream: async (code: string, options?: any) => {\n return await this.runCodeStream(code, options);\n },\n \n listCodeContexts: async () => {\n return await this.listCodeContexts();\n },\n \n deleteCodeContext: async (contextId: string) => {\n return await this.deleteCodeContext(contextId);\n }\n };\n }\n}\n","import { getSandbox, type Sandbox } from \"./sandbox\";\nimport {\n logSecurityEvent,\n sanitizeSandboxId,\n validatePort\n} from \"./security\";\n\nexport interface SandboxEnv {\n Sandbox: DurableObjectNamespace<Sandbox>;\n}\n\nexport interface RouteInfo {\n port: number;\n sandboxId: string;\n path: string;\n}\n\nexport async function proxyToSandbox<E extends SandboxEnv>(\n request: Request,\n env: E\n): Promise<Response | null> {\n try {\n const url = new URL(request.url);\n const routeInfo = extractSandboxRoute(url);\n\n if (!routeInfo) {\n return null; // Not a request to an exposed container port\n }\n\n const { sandboxId, port, path } = routeInfo;\n const sandbox = getSandbox(env.Sandbox, sandboxId);\n\n // Build proxy request with proper headers\n let proxyUrl: string;\n\n // Route based on the target port\n if (port !== 3000) {\n // Route directly to user's service on the specified port\n proxyUrl = `http://localhost:${port}${path}${url.search}`;\n } else {\n // Port 3000 is our control plane - route normally\n proxyUrl = `http://localhost:3000${path}${url.search}`;\n }\n\n const proxyRequest = new Request(proxyUrl, {\n method: request.method,\n headers: {\n ...Object.fromEntries(request.headers),\n 'X-Original-URL': request.url,\n 'X-Forwarded-Host': url.hostname,\n 'X-Forwarded-Proto': url.protocol.replace(':', ''),\n 'X-Sandbox-Name': sandboxId, // Pass the friendly name\n },\n body: request.body,\n });\n\n return sandbox.containerFetch(proxyRequest, port);\n } catch (error) {\n console.error('[Sandbox] Proxy routing error:', error);\n return new Response('Proxy routing error', { status: 500 });\n }\n}\n\nfunction extractSandboxRoute(url: URL): RouteInfo | null {\n // Parse subdomain pattern: port-sandboxId.domain\n const subdomainMatch = url.hostname.match(/^(\\d{4,5})-([^.-][^.]*[^.-]|[^.-])\\.(.+)$/);\n\n if (!subdomainMatch) {\n // Log malformed subdomain attempts\n if (url.hostname.includes('-') && url.hostname.includes('.')) {\n logSecurityEvent('MALFORMED_SUBDOMAIN_ATTEMPT', {\n hostname: url.hostname,\n url: url.toString()\n }, 'medium');\n }\n return null;\n }\n\n const portStr = subdomainMatch[1];\n const sandboxId = subdomainMatch[2];\n const domain = subdomainMatch[3];\n\n const port = parseInt(portStr, 10);\n if (!validatePort(port)) {\n logSecurityEvent('INVALID_PORT_IN_SUBDOMAIN', {\n port,\n portStr,\n sandboxId,\n hostname: url.hostname,\n url: url.toString()\n }, 'high');\n return null;\n }\n\n let sanitizedSandboxId: string;\n try {\n sanitizedSandboxId = sanitizeSandboxId(sandboxId);\n } catch (error) {\n logSecurityEvent('INVALID_SANDBOX_ID_IN_SUBDOMAIN', {\n sandboxId,\n port,\n hostname: url.hostname,\n url: url.toString(),\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 'high');\n return null;\n }\n\n // DNS subdomain length limit is 63 characters\n if (sandboxId.length > 63) {\n logSecurityEvent('SANDBOX_ID_LENGTH_VIOLATION', {\n sandboxId,\n length: sandboxId.length,\n port,\n hostname: url.hostname\n }, 'medium');\n return null;\n }\n\n logSecurityEvent('SANDBOX_ROUTE_EXTRACTED', {\n port,\n sandboxId: sanitizedSandboxId,\n domain,\n path: url.pathname || \"/\",\n hostname: url.hostname\n }, 'low');\n\n return {\n port,\n sandboxId: sanitizedSandboxId,\n path: url.pathname || \"/\",\n };\n}\n\nexport function isLocalhostPattern(hostname: string): boolean {\n const hostPart = hostname.split(\":\")[0];\n return (\n hostPart === \"localhost\" ||\n hostPart === \"127.0.0.1\" ||\n hostPart === \"::1\" ||\n hostPart === \"[::1]\" ||\n hostPart === \"0.0.0.0\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,WAAW,oBAAoB;;;ACiBxC,eAAsB,eACpB,SACA,KAC0B;AAC1B,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,UAAM,YAAY,oBAAoB,GAAG;AAEzC,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,WAAW,MAAM,KAAK,IAAI;AAClC,UAAM,UAAU,WAAW,IAAI,SAAS,SAAS;AAGjD,QAAI;AAGJ,QAAI,SAAS,KAAM;AAEjB,iBAAW,oBAAoB,IAAI,GAAG,IAAI,GAAG,IAAI,MAAM;AAAA,IACzD,OAAO;AAEL,iBAAW,wBAAwB,IAAI,GAAG,IAAI,MAAM;AAAA,IACtD;AAEA,UAAM,eAAe,IAAI,QAAQ,UAAU;AAAA,MACzC,QAAQ,QAAQ;AAAA,MAChB,SAAS;AAAA,QACP,GAAG,OAAO,YAAY,QAAQ,OAAO;AAAA,QACrC,kBAAkB,QAAQ;AAAA,QAC1B,oBAAoB,IAAI;AAAA,QACxB,qBAAqB,IAAI,SAAS,QAAQ,KAAK,EAAE;AAAA,QACjD,kBAAkB;AAAA;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ;AAAA,IAChB,CAAC;AAED,WAAO,QAAQ,eAAe,cAAc,IAAI;AAAA,EAClD,SAAS,OAAO;AACd,YAAQ,MAAM,kCAAkC,KAAK;AACrD,WAAO,IAAI,SAAS,uBAAuB,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC5D;AACF;AAEA,SAAS,oBAAoB,KAA4B;AAEvD,QAAM,iBAAiB,IAAI,SAAS,MAAM,2CAA2C;AAErF,MAAI,CAAC,gBAAgB;AAEnB,QAAI,IAAI,SAAS,SAAS,GAAG,KAAK,IAAI,SAAS,SAAS,GAAG,GAAG;AAC5D,uBAAiB,+BAA+B;AAAA,QAC9C,UAAU,IAAI;AAAA,QACd,KAAK,IAAI,SAAS;AAAA,MACpB,GAAG,QAAQ;AAAA,IACb;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe,CAAC;AAChC,QAAM,YAAY,eAAe,CAAC;AAClC,QAAM,SAAS,eAAe,CAAC;AAE/B,QAAM,OAAO,SAAS,SAAS,EAAE;AACjC,MAAI,CAAC,aAAa,IAAI,GAAG;AACvB,qBAAiB,6BAA6B;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,IAAI;AAAA,MACd,KAAK,IAAI,SAAS;AAAA,IACpB,GAAG,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,yBAAqB,kBAAkB,SAAS;AAAA,EAClD,SAAS,OAAO;AACd,qBAAiB,mCAAmC;AAAA,MAClD;AAAA,MACA;AAAA,MACA,UAAU,IAAI;AAAA,MACd,KAAK,IAAI,SAAS;AAAA,MAClB,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD,GAAG,MAAM;AACT,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,SAAS,IAAI;AACzB,qBAAiB,+BAA+B;AAAA,MAC9C;AAAA,MACA,QAAQ,UAAU;AAAA,MAClB;AAAA,MACA,UAAU,IAAI;AAAA,IAChB,GAAG,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,mBAAiB,2BAA2B;AAAA,IAC1C;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,MAAM,IAAI,YAAY;AAAA,IACtB,UAAU,IAAI;AAAA,EAChB,GAAG,KAAK;AAER,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,IACX,MAAM,IAAI,YAAY;AAAA,EACxB;AACF;AAEO,SAAS,mBAAmB,UAA2B;AAC5D,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,CAAC;AACtC,SACE,aAAa,eACb,aAAa,eACb,aAAa,SACb,aAAa,WACb,aAAa;AAEjB;;;ADhHO,SAAS,WAAW,IAAqC,IAAY;AAC1E,QAAM,OAAO,aAAa,IAAI,EAAE;AAGhC,OAAK,iBAAiB,EAAE;AAExB,SAAO;AACT;AAEO,IAAM,UAAN,cAAqC,UAAmC;AAAA,EAC7E,cAAc;AAAA;AAAA,EACd,aAAa;AAAA;AAAA,EACb;AAAA,EACQ,cAA6B;AAAA,EAC7B;AAAA,EACA,iBAA0C;AAAA,EAElD,YAAY,KAAyB,KAAU;AAC7C,UAAM,KAAK,GAAG;AACd,SAAK,SAAS,IAAI,kBAAkB;AAAA,MAClC,mBAAmB,CAAC,SAAS,UAAU,SAAS,SAAS,YAAY;AACnE,gBAAQ;AAAA,UACN,kCAAkC,OAAO,cAAc,OAAO,gBAAgB,QAAQ;AAAA,QACxF;AAAA,MACF;AAAA,MACA,gBAAgB,CAAC,YAAY;AAC3B,gBAAQ,IAAI,gCAAgC,OAAO,EAAE;AAAA,MACvD;AAAA,MACA,SAAS,CAAC,OAAO,aAAa;AAC5B,gBAAQ,MAAM,8BAA8B,KAAK,EAAE;AAAA,MACrD;AAAA,MACA,UAAU,CAAC,QAAQ,MAAM,aAAa;AACpC,gBAAQ,IAAI,gBAAgB,MAAM,KAAK,IAAI,EAAE;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAGD,SAAK,kBAAkB,IAAI,gBAAgB,IAAI;AAG/C,SAAK,IAAI,sBAAsB,YAAY;AACzC,WAAK,cACF,MAAM,KAAK,IAAI,QAAQ,IAAY,aAAa,KAAM;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,eAAe,MAA6B;AAChD,QAAI,CAAC,KAAK,aAAa;AACrB,WAAK,cAAc;AACnB,YAAM,KAAK,IAAI,QAAQ,IAAI,eAAe,IAAI;AAC9C,cAAQ,IAAI,0CAA0C,IAAI,EAAE;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,WAAW,SAAgD;AAC/D,SAAK,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AAC7C,YAAQ,IAAI,yCAAyC;AAGrD,QAAI,KAAK,gBAAgB;AACvB,YAAM,KAAK,eAAe,WAAW,OAAO;AAAA,IAC9C;AAAA,EACF;AAAA,EAES,UAAU;AACjB,YAAQ,IAAI,8BAA8B;AAAA,EAC5C;AAAA,EAES,SAAS;AAChB,YAAQ,IAAI,gCAAgC;AAAA,EAC9C;AAAA,EAES,QAAQ,OAAgB;AAC/B,YAAQ,IAAI,kBAAkB,KAAK;AAAA,EACrC;AAAA;AAAA,EAGA,MAAe,MAAM,SAAqC;AACxD,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAG/B,QAAI,CAAC,KAAK,eAAe,QAAQ,QAAQ,IAAI,gBAAgB,GAAG;AAC9D,YAAM,OAAO,QAAQ,QAAQ,IAAI,gBAAgB;AACjD,WAAK,cAAc;AACnB,YAAM,KAAK,IAAI,QAAQ,IAAI,eAAe,IAAI;AAC9C,cAAQ,IAAI,kCAAkC,KAAK,WAAW,EAAE;AAAA,IAClE;AAGA,UAAM,OAAO,KAAK,cAAc,GAAG;AAGnC,WAAO,MAAM,KAAK,eAAe,SAAS,IAAI;AAAA,EAChD;AAAA,EAEQ,cAAc,KAAkB;AAEtC,UAAM,aAAa,IAAI,SAAS,MAAM,iBAAiB;AACvD,QAAI,YAAY;AACd,aAAO,SAAS,WAAW,CAAC,CAAC;AAAA,IAC/B;AAEA,QAAI,IAAI,MAAM;AACZ,aAAO,SAAS,IAAI,IAAI;AAAA,IAC1B;AAIA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,uBAAkD;AAC9D,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAM,YAAY,WAAW,KAAK,eAAe,SAAS;AAC1D,WAAK,iBAAiB,MAAM,KAAK,cAAc;AAAA,QAC7C,IAAI;AAAA,QACJ,KAAK,KAAK,WAAW,CAAC;AAAA,QACtB,KAAK;AAAA,QACL,WAAW;AAAA,MACb,CAAC;AACD,cAAQ,IAAI,0CAA0C,SAAS,EAAE;AAAA,IACnE;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAGA,MAAM,KAAK,SAAiB,SAA4C;AACtE,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,KAAK,SAAS,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,aACJ,SACA,SACkB;AAClB,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,aAAa,SAAS,OAAO;AAAA,EAC9C;AAAA,EAEA,MAAM,gBAAoC;AACxC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,cAAc;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,IAAqC;AACpD,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,EAAE;AAAA,EAC9B;AAAA,EAEA,MAAM,YAAY,IAAY,QAAgC;AAC5D,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,YAAY,IAAI,MAAM;AAAA,EACvC;AAAA,EAEA,MAAM,mBAAoC;AACxC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,iBAAiB;AAAA,EAClC;AAAA,EAEA,MAAM,4BAA6C;AACjD,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,0BAA0B;AAAA,EAC3C;AAAA,EAEA,MAAM,eACJ,IAC6C;AAC7C,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,eAAe,EAAE;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,WACJ,SACA,SACqC;AACrC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,SAAS,OAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,kBACJ,WACA,SACqC;AACrC,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,kBAAkB,WAAW,OAAO;AAAA,EACrD;AAAA,EAEA,MAAM,YACJ,SACA,SACA;AACA,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,YAAY,SAAS,OAAO;AAAA,EAC7C;AAAA,EAEA,MAAM,MAAM,MAAc,UAAmC,CAAC,GAAG;AAC/D,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,MAAM,MAAM,OAAO;AAAA,EACpC;AAAA,EAEA,MAAM,UACJ,MACA,SACA,UAAiC,CAAC,GAClC;AACA,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,UAAU,MAAM,SAAS,OAAO;AAAA,EACjD;AAAA,EAEA,MAAM,WAAW,MAAc;AAC7B,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,IAAI;AAAA,EAChC;AAAA,EAEA,MAAM,WAAW,SAAiB,SAAiB;AACjD,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,WAAW,SAAS,OAAO;AAAA,EAC5C;AAAA,EAEA,MAAM,SAAS,YAAoB,iBAAyB;AAC1D,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,SAAS,YAAY,eAAe;AAAA,EACrD;AAAA,EAEA,MAAM,SAAS,MAAc,UAAiC,CAAC,GAAG;AAChE,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,SAAS,MAAM,OAAO;AAAA,EACvC;AAAA,EAEA,MAAM,UACJ,MACA,UAGI,CAAC,GACL;AACA,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,WAAO,QAAQ,UAAU,MAAM,OAAO;AAAA,EACxC;AAAA,EAEA,MAAM,WAAW,MAAc,SAA8C;AAC3E,UAAM,KAAK,OAAO,WAAW,MAAM,SAAS,IAAI;AAGhD,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,KAAK;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL,QAAQ;AAAA,IACV;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,MAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,MAAc;AAC/B,QAAI,CAAC,aAAa,IAAI,GAAG;AACvB;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,wBAAwB,IAAI;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,KAAK,OAAO,aAAa,IAAI;AAEnC;AAAA,MACE;AAAA,MACA;AAAA,QACE;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,UAAkB;AACtC,UAAM,WAAW,MAAM,KAAK,OAAO,gBAAgB;AAGnD,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO,SAAS,MAAM,IAAI,CAAC,UAAU;AAAA,MACnC,KAAK,KAAK,oBAAoB,KAAK,MAAM,KAAK,aAAc,QAAQ;AAAA,MACpE,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,IAClB,EAAE;AAAA,EACJ;AAAA,EAEQ,oBACN,MACA,WACA,UACQ;AACR,QAAI,CAAC,aAAa,IAAI,GAAG;AACvB;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,wBAAwB,IAAI;AAAA,MAC9B;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,2BAAqB,kBAAkB,SAAS;AAAA,IAClD,SAAS,OAAO;AACd;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD;AAAA,QACA;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAEA,UAAM,cAAc,mBAAmB,QAAQ;AAE/C,QAAI,aAAa;AAEf,YAAM,CAAC,MAAM,OAAO,IAAI,SAAS,MAAM,GAAG;AAC1C,YAAM,WAAW,WAAW;AAG5B,UAAI;AACF,cAAM,UAAU,IAAI,IAAI,UAAU,IAAI,IAAI,QAAQ,EAAE;AAEpD,cAAM,gBAAgB,GAAG,IAAI,IAAI,kBAAkB,IAAI,IAAI;AAC3D,gBAAQ,WAAW;AAEnB,cAAM,WAAW,QAAQ,SAAS;AAElC;AAAA,UACE;AAAA,UACA;AAAA,YACE;AAAA,YACA,WAAW;AAAA,YACX;AAAA,YACA,WAAW;AAAA,YACX,aAAa;AAAA,UACf;AAAA,UACA;AAAA,QACF;AAEA,eAAO;AAAA,MACT,SAAS,OAAO;AACd;AAAA,UACE;AAAA,UACA;AAAA,YACE;AAAA,YACA,WAAW;AAAA,YACX;AAAA,YACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UAClD;AAAA,UACA;AAAA,QACF;AACA,cAAM,IAAI;AAAA,UACR,oCACE,iBAAiB,QAAQ,MAAM,UAAU,eAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AAEF,YAAM,WAAW;AACjB,YAAM,UAAU,IAAI,IAAI,GAAG,QAAQ,MAAM,QAAQ,EAAE;AAGnD,YAAM,gBAAgB,GAAG,IAAI,IAAI,kBAAkB,IAAI,QAAQ;AAC/D,cAAQ,WAAW;AAEnB,YAAM,WAAW,QAAQ,SAAS;AAElC;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd;AAAA,QACE;AAAA,QACA;AAAA,UACE;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD;AAAA,QACA;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,oCACE,iBAAiB,QAAQ,MAAM,UAAU,eAC3C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,SACsB;AACtB,WAAO,KAAK,gBAAgB,kBAAkB,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QACJ,MACA,SAC0B;AAC1B,UAAM,YAAY,MAAM,KAAK,gBAAgB,QAAQ,MAAM,OAAO;AAElE,WAAO,UAAU,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cACJ,MACA,SACyB;AACzB,WAAO,KAAK,gBAAgB,cAAc,MAAM,OAAO;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAA2C;AAC/C,WAAO,KAAK,gBAAgB,iBAAiB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,WAAkC;AACxD,WAAO,KAAK,gBAAgB,kBAAkB,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,cAAc,SAKU;AAC5B,UAAM,YAAY,QAAQ,MAAM,WAAW,KAAK,IAAI,CAAC;AAErD,UAAM,KAAK,OAAO,cAAc;AAAA,MAC9B,IAAI;AAAA,MACJ,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,MACb,WAAW,QAAQ;AAAA,IACrB,CAAC;AAED,WAAO;AAAA,MACL,IAAI;AAAA;AAAA,MAGJ,MAAM,OAAO,SAAiBA,aAA0B;AACtD,cAAM,SAAS,MAAM,KAAK,OAAO,KAAK,WAAW,OAAO;AACxD,eAAO;AAAA,UACL,GAAG;AAAA,UACH;AAAA,UACA,UAAU;AAAA,UACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF;AAAA,MAEA,YAAY,OAAO,SAAiBA,aAA4B;AAC9D,eAAO,MAAM,KAAK,OAAO,WAAW,WAAW,OAAO;AAAA,MACxD;AAAA;AAAA,MAGA,cAAc,OAAO,SAAiBA,aAA6B;AAEjE,cAAM,WAAW,MAAM,KAAK,OAAO,aAAa,SAAS,WAAW;AAAA,UAClE,WAAWA,UAAS;AAAA,UACpB,SAASA,UAAS;AAAA,UAClB,KAAKA,UAAS;AAAA,UACd,KAAKA,UAAS;AAAA,UACd,UAAUA,UAAS;AAAA,UACnB,aAAaA,UAAS;AAAA,QACxB,CAAC;AAGD,cAAM,UAAU,SAAS;AACzB,eAAO;AAAA,UACL,IAAI,QAAQ;AAAA,UACZ,KAAK,QAAQ;AAAA,UACb,SAAS,QAAQ;AAAA,UACjB,QAAQ,QAAQ;AAAA,UAChB,WAAW,IAAI,KAAK,QAAQ,SAAS;AAAA,UACrC,SAAS,QAAQ,UAAU,IAAI,KAAK,QAAQ,OAAO,IAAI;AAAA,UACvD,UAAU,QAAQ,YAAY;AAAA,UAC9B,MAAM,OAAO,WAAoB;AAC/B,kBAAM,KAAK,OAAO,YAAY,QAAQ,EAAE;AAAA,UAC1C;AAAA,UACA,WAAW,YAAY;AACrB,kBAAM,OAAO,MAAM,KAAK,OAAO,WAAW,QAAQ,EAAE;AACpD,mBAAO,KAAK,SAAS,UAA2B;AAAA,UAClD;AAAA,UACA,SAAS,YAAY;AACnB,mBAAO,MAAM,KAAK,OAAO,eAAe,QAAQ,EAAE;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAAA,MAEA,eAAe,YAAY;AAEzB,cAAM,WAAW,MAAM,KAAK,OAAO,cAAc,SAAS;AAG1D,eAAO,SAAS,UAAU,IAAI,QAAM;AAAA,UAClC,IAAI,EAAE;AAAA,UACN,KAAK,EAAE;AAAA,UACP,SAAS,EAAE;AAAA,UACX,QAAQ,EAAE;AAAA,UACV,WAAW,IAAI,KAAK,EAAE,SAAS;AAAA,UAC/B,SAAS,EAAE,UAAU,IAAI,KAAK,EAAE,OAAO,IAAI;AAAA,UAC3C,UAAU,EAAE,YAAY;AAAA,UACxB,MAAM,OAAO,WAAoB;AAC/B,kBAAM,KAAK,OAAO,YAAY,EAAE,EAAE;AAAA,UACpC;AAAA,UACA,WAAW,YAAY;AACrB,kBAAM,cAAc,MAAM,KAAK,OAAO,WAAW,EAAE,EAAE;AACrD,mBAAO,YAAY,SAAS,UAA2B;AAAA,UACzD;AAAA,UACA,SAAS,YAAY;AACnB,mBAAO,KAAK,OAAO,eAAe,EAAE,EAAE;AAAA,UACxC;AAAA,QACF,EAAE;AAAA,MACJ;AAAA,MAEA,YAAY,OAAO,OAAe;AAChC,cAAM,WAAW,MAAM,KAAK,OAAO,WAAW,EAAE;AAChD,YAAI,CAAC,SAAS,QAAS,QAAO;AAE9B,cAAM,IAAI,SAAS;AACnB,eAAO;AAAA,UACL,IAAI,EAAE;AAAA,UACN,KAAK,EAAE;AAAA,UACP,SAAS,EAAE;AAAA,UACX,QAAQ,EAAE;AAAA,UACV,WAAW,IAAI,KAAK,EAAE,SAAS;AAAA,UAC/B,SAAS,EAAE,UAAU,IAAI,KAAK,EAAE,OAAO,IAAI;AAAA,UAC3C,UAAU,EAAE,YAAY;AAAA,UACxB,MAAM,OAAO,WAAoB;AAC/B,kBAAM,KAAK,OAAO,YAAY,EAAE,EAAE;AAAA,UACpC;AAAA,UACA,WAAW,YAAY;AACrB,kBAAM,cAAc,MAAM,KAAK,OAAO,WAAW,EAAE,EAAE;AACrD,mBAAO,YAAY,SAAS,UAA2B;AAAA,UACzD;AAAA,UACA,SAAS,YAAY;AACnB,mBAAO,KAAK,OAAO,eAAe,EAAE,EAAE;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,MAEA,aAAa,OAAO,IAAY,WAAoB;AAClD,cAAM,KAAK,OAAO,YAAY,EAAE;AAAA,MAClC;AAAA,MAEA,kBAAkB,YAAY;AAE5B,cAAM,WAAW,MAAM,KAAK,OAAO,iBAAiB,SAAS;AAC7D,eAAO,SAAS;AAAA,MAClB;AAAA,MAEA,mBAAmB,OAAO,WAAmBA,aAAuC;AAClF,eAAO,MAAM,KAAK,OAAO,kBAAkB,WAAWA,QAAO;AAAA,MAC/D;AAAA,MAEA,gBAAgB,OAAO,OAAe;AACpC,eAAO,MAAM,KAAK,OAAO,eAAe,EAAE;AAAA,MAC5C;AAAA,MAEA,2BAA2B,YAAY;AAGrC,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,WAAW,OAAO,MAAc,SAAiBA,aAAoC;AACnF,eAAO,MAAM,KAAK,OAAO,UAAU,MAAM,SAASA,UAAS,UAAU,SAAS;AAAA,MAChF;AAAA,MAEA,UAAU,OAAO,MAAcA,aAAoC;AACjE,eAAO,MAAM,KAAK,OAAO,SAAS,MAAMA,UAAS,UAAU,SAAS;AAAA,MACtE;AAAA,MAEA,OAAO,OAAO,MAAcA,aAAsC;AAChE,eAAO,MAAM,KAAK,OAAO,MAAM,MAAMA,UAAS,WAAW,SAAS;AAAA,MACpE;AAAA,MAEA,YAAY,OAAO,SAAiB;AAClC,eAAO,MAAM,KAAK,OAAO,WAAW,MAAM,SAAS;AAAA,MACrD;AAAA,MAEA,YAAY,OAAO,SAAiB,YAAoB;AACtD,eAAO,MAAM,KAAK,OAAO,WAAW,SAAS,SAAS,SAAS;AAAA,MACjE;AAAA,MAEA,UAAU,OAAO,YAAoB,oBAA4B;AAC/D,eAAO,MAAM,KAAK,OAAO,SAAS,YAAY,iBAAiB,SAAS;AAAA,MAC1E;AAAA,MAEA,WAAW,OAAO,MAAcA,aAA+D;AAC7F,eAAO,MAAM,KAAK,OAAO,UAAU,MAAM,WAAWA,QAAO;AAAA,MAC7D;AAAA,MAEA,aAAa,OAAO,SAAiBA,aAAsD;AACzF,eAAO,MAAM,KAAK,OAAO,YAAY,SAAS,WAAWA,UAAS,QAAQA,UAAS,SAAS;AAAA,MAC9F;AAAA;AAAA,MAGA,YAAY,OAAO,MAAcA,aAAiD;AAChF,eAAO,MAAM,KAAK,WAAW,MAAMA,QAAO;AAAA,MAC5C;AAAA,MAEA,cAAc,OAAO,SAAiB;AACpC,eAAO,MAAM,KAAK,aAAa,IAAI;AAAA,MACrC;AAAA,MAEA,iBAAiB,OAAO,aAAqB;AAC3C,eAAO,MAAM,KAAK,gBAAgB,QAAQ;AAAA,MAC5C;AAAA;AAAA,MAGA,YAAY,OAAO,YAAoC;AAErD,gBAAQ,IAAI,YAAY,SAAS,oDAAoD;AAAA,MACvF;AAAA;AAAA,MAGA,mBAAmB,OAAOA,aAAkB;AAC1C,eAAO,MAAM,KAAK,kBAAkBA,QAAO;AAAA,MAC7C;AAAA,MAEA,SAAS,OAAO,MAAcA,aAAkB;AAC9C,eAAO,MAAM,KAAK,QAAQ,MAAMA,QAAO;AAAA,MACzC;AAAA,MAEA,eAAe,OAAO,MAAcA,aAAkB;AACpD,eAAO,MAAM,KAAK,cAAc,MAAMA,QAAO;AAAA,MAC/C;AAAA,MAEA,kBAAkB,YAAY;AAC5B,eAAO,MAAM,KAAK,iBAAiB;AAAA,MACrC;AAAA,MAEA,mBAAmB,OAAO,cAAsB;AAC9C,eAAO,MAAM,KAAK,kBAAkB,SAAS;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACF;","names":["options"]}
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  Execution,
3
3
  ResultImpl
4
- } from "./chunk-EGC5IYXA.js";
4
+ } from "./chunk-W7TVRPBG.js";
5
5
 
6
6
  // src/interpreter.ts
7
7
  var CodeInterpreter = class {
8
- jupyterClient;
8
+ interpreterClient;
9
9
  contexts = /* @__PURE__ */ new Map();
10
10
  constructor(sandbox) {
11
- this.jupyterClient = sandbox.client;
11
+ this.interpreterClient = sandbox.client;
12
12
  }
13
13
  /**
14
14
  * Create a new code execution context
15
15
  */
16
16
  async createCodeContext(options = {}) {
17
- const context = await this.jupyterClient.createCodeContext(options);
17
+ const context = await this.interpreterClient.createCodeContext(options);
18
18
  this.contexts.set(context.id, context);
19
19
  return context;
20
20
  }
@@ -28,7 +28,7 @@ var CodeInterpreter = class {
28
28
  context = await this.getOrCreateDefaultContext(language);
29
29
  }
30
30
  const execution = new Execution(code, context);
31
- await this.jupyterClient.runCodeStream(context.id, code, options.language, {
31
+ await this.interpreterClient.runCodeStream(context.id, code, options.language, {
32
32
  onStdout: (output) => {
33
33
  execution.logs.stdout.push(output.text);
34
34
  if (options.onStdout) return options.onStdout(output);
@@ -57,7 +57,7 @@ var CodeInterpreter = class {
57
57
  const language = options.language || "python";
58
58
  context = await this.getOrCreateDefaultContext(language);
59
59
  }
60
- const response = await this.jupyterClient.doFetch("/api/execute/code", {
60
+ const response = await this.interpreterClient.doFetch("/api/execute/code", {
61
61
  method: "POST",
62
62
  headers: {
63
63
  "Content-Type": "application/json",
@@ -84,7 +84,7 @@ var CodeInterpreter = class {
84
84
  * List all code contexts
85
85
  */
86
86
  async listCodeContexts() {
87
- const contexts = await this.jupyterClient.listCodeContexts();
87
+ const contexts = await this.interpreterClient.listCodeContexts();
88
88
  for (const context of contexts) {
89
89
  this.contexts.set(context.id, context);
90
90
  }
@@ -94,7 +94,7 @@ var CodeInterpreter = class {
94
94
  * Delete a code context
95
95
  */
96
96
  async deleteCodeContext(contextId) {
97
- await this.jupyterClient.deleteCodeContext(contextId);
97
+ await this.interpreterClient.deleteCodeContext(contextId);
98
98
  this.contexts.delete(contextId);
99
99
  }
100
100
  async getOrCreateDefaultContext(language) {
@@ -110,4 +110,4 @@ var CodeInterpreter = class {
110
110
  export {
111
111
  CodeInterpreter
112
112
  };
113
- //# sourceMappingURL=chunk-FKBV7CZS.js.map
113
+ //# sourceMappingURL=chunk-JTKON2SH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/interpreter.ts"],"sourcesContent":["import type { InterpreterClient } from \"./interpreter-client.js\";\nimport {\n type CodeContext,\n type CreateContextOptions,\n Execution,\n ResultImpl,\n type RunCodeOptions,\n} from \"./interpreter-types.js\";\nimport type { Sandbox } from \"./sandbox.js\";\n\nexport class CodeInterpreter {\n private interpreterClient: InterpreterClient;\n private contexts = new Map<string, CodeContext>();\n\n constructor(sandbox: Sandbox) {\n this.interpreterClient = sandbox.client as InterpreterClient;\n }\n\n /**\n * Create a new code execution context\n */\n async createCodeContext(\n options: CreateContextOptions = {}\n ): Promise<CodeContext> {\n const context = await this.interpreterClient.createCodeContext(options);\n this.contexts.set(context.id, context);\n return context;\n }\n\n /**\n * Run code with optional context\n */\n async runCode(\n code: string,\n options: RunCodeOptions = {}\n ): Promise<Execution> {\n // Get or create context\n let context = options.context;\n if (!context) {\n // Try to find or create a default context for the language\n const language = options.language || \"python\";\n context = await this.getOrCreateDefaultContext(language);\n }\n\n // Create execution object to collect results\n const execution = new Execution(code, context);\n\n // Stream execution\n await this.interpreterClient.runCodeStream(context.id, code, options.language, {\n onStdout: (output) => {\n execution.logs.stdout.push(output.text);\n if (options.onStdout) return options.onStdout(output);\n },\n onStderr: (output) => {\n execution.logs.stderr.push(output.text);\n if (options.onStderr) return options.onStderr(output);\n },\n onResult: async (result) => {\n execution.results.push(new ResultImpl(result) as any);\n if (options.onResult) return options.onResult(result);\n },\n onError: (error) => {\n execution.error = error;\n if (options.onError) return options.onError(error);\n },\n });\n\n return execution;\n }\n\n /**\n * Run code and return a streaming response\n */\n async runCodeStream(\n code: string,\n options: RunCodeOptions = {}\n ): Promise<ReadableStream> {\n // Get or create context\n let context = options.context;\n if (!context) {\n const language = options.language || \"python\";\n context = await this.getOrCreateDefaultContext(language);\n }\n\n // Create streaming response\n const response = await this.interpreterClient.doFetch(\"/api/execute/code\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({\n context_id: context.id,\n code,\n language: options.language,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response\n .json()\n .catch(() => ({ error: \"Unknown error\" }))) as { error?: string };\n throw new Error(\n errorData.error || `Failed to execute code: ${response.status}`\n );\n }\n\n if (!response.body) {\n throw new Error(\"No response body for streaming execution\");\n }\n\n return response.body;\n }\n\n /**\n * List all code contexts\n */\n async listCodeContexts(): Promise<CodeContext[]> {\n const contexts = await this.interpreterClient.listCodeContexts();\n\n // Update local cache\n for (const context of contexts) {\n this.contexts.set(context.id, context);\n }\n\n return contexts;\n }\n\n /**\n * Delete a code context\n */\n async deleteCodeContext(contextId: string): Promise<void> {\n await this.interpreterClient.deleteCodeContext(contextId);\n this.contexts.delete(contextId);\n }\n\n private async getOrCreateDefaultContext(\n language: \"python\" | \"javascript\" | \"typescript\"\n ): Promise<CodeContext> {\n // Check if we have a cached context for this language\n for (const context of this.contexts.values()) {\n if (context.language === language) {\n return context;\n }\n }\n\n // Create new default context\n return this.createCodeContext({ language });\n }\n}\n"],"mappings":"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","names":[]}
@@ -20,7 +20,7 @@ var Execution = class {
20
20
  */
21
21
  error;
22
22
  /**
23
- * Execution count (for Jupyter)
23
+ * Execution count (for interpreter)
24
24
  */
25
25
  executionCount;
26
26
  /**
@@ -105,4 +105,4 @@ export {
105
105
  Execution,
106
106
  ResultImpl
107
107
  };
108
- //# sourceMappingURL=chunk-EGC5IYXA.js.map
108
+ //# sourceMappingURL=chunk-W7TVRPBG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/interpreter-types.ts"],"sourcesContent":["// Context Management\nexport interface CreateContextOptions {\n /**\n * Programming language for the context\n * @default 'python'\n */\n language?: \"python\" | \"javascript\" | \"typescript\";\n\n /**\n * Working directory for the context\n * @default '/workspace'\n */\n cwd?: string;\n\n /**\n * Environment variables for the context\n */\n envVars?: Record<string, string>;\n\n /**\n * Request timeout in milliseconds\n * @default 30000\n */\n timeout?: number;\n}\n\nexport interface CodeContext {\n /**\n * Unique identifier for the context\n */\n readonly id: string;\n\n /**\n * Programming language of the context\n */\n readonly language: string;\n\n /**\n * Current working directory\n */\n readonly cwd: string;\n\n /**\n * When the context was created\n */\n readonly createdAt: Date;\n\n /**\n * When the context was last used\n */\n readonly lastUsed: Date;\n}\n\n// Execution Options\nexport interface RunCodeOptions {\n /**\n * Context to run the code in. If not provided, uses default context for the language\n */\n context?: CodeContext;\n\n /**\n * Language to use if context is not provided\n * @default 'python'\n */\n language?: \"python\" | \"javascript\" | \"typescript\";\n\n /**\n * Environment variables for this execution\n */\n envVars?: Record<string, string>;\n\n /**\n * Execution timeout in milliseconds\n * @default 60000\n */\n timeout?: number;\n\n /**\n * AbortSignal for cancelling execution\n */\n signal?: AbortSignal;\n\n /**\n * Callback for stdout output\n */\n onStdout?: (output: OutputMessage) => void | Promise<void>;\n\n /**\n * Callback for stderr output\n */\n onStderr?: (output: OutputMessage) => void | Promise<void>;\n\n /**\n * Callback for execution results (charts, tables, etc)\n */\n onResult?: (result: Result) => void | Promise<void>;\n\n /**\n * Callback for execution errors\n */\n onError?: (error: ExecutionError) => void | Promise<void>;\n}\n\n// Output Messages\nexport interface OutputMessage {\n /**\n * The output text\n */\n text: string;\n\n /**\n * Timestamp of the output\n */\n timestamp: number;\n}\n\n// Execution Results\nexport interface Result {\n /**\n * Plain text representation\n */\n text?: string;\n\n /**\n * HTML representation (tables, formatted output)\n */\n html?: string;\n\n /**\n * PNG image data (base64 encoded)\n */\n png?: string;\n\n /**\n * JPEG image data (base64 encoded)\n */\n jpeg?: string;\n\n /**\n * SVG image data\n */\n svg?: string;\n\n /**\n * LaTeX representation\n */\n latex?: string;\n\n /**\n * Markdown representation\n */\n markdown?: string;\n\n /**\n * JavaScript code to execute\n */\n javascript?: string;\n\n /**\n * JSON data\n */\n json?: any;\n\n /**\n * Chart data if the result is a visualization\n */\n chart?: ChartData;\n\n /**\n * Raw data object\n */\n data?: any;\n\n /**\n * Available output formats\n */\n formats(): string[];\n}\n\n// Chart Data\nexport interface ChartData {\n /**\n * Type of chart\n */\n type:\n | \"line\"\n | \"bar\"\n | \"scatter\"\n | \"pie\"\n | \"histogram\"\n | \"heatmap\"\n | \"unknown\";\n\n /**\n * Chart title\n */\n title?: string;\n\n /**\n * Chart data (format depends on library)\n */\n data: any;\n\n /**\n * Chart layout/configuration\n */\n layout?: any;\n\n /**\n * Additional configuration\n */\n config?: any;\n\n /**\n * Library that generated the chart\n */\n library?: \"matplotlib\" | \"plotly\" | \"altair\" | \"seaborn\" | \"unknown\";\n\n /**\n * Base64 encoded image if available\n */\n image?: string;\n}\n\n// Execution Error\nexport interface ExecutionError {\n /**\n * Error name/type (e.g., 'NameError', 'SyntaxError')\n */\n name: string;\n\n /**\n * Error message\n */\n value: string;\n\n /**\n * Stack trace\n */\n traceback: string[];\n\n /**\n * Line number where error occurred\n */\n lineNumber?: number;\n}\n\n// Serializable execution result\nexport interface ExecutionResult {\n code: string;\n logs: {\n stdout: string[];\n stderr: string[];\n };\n error?: ExecutionError;\n executionCount?: number;\n results: Array<{\n text?: string;\n html?: string;\n png?: string;\n jpeg?: string;\n svg?: string;\n latex?: string;\n markdown?: string;\n javascript?: string;\n json?: any;\n chart?: ChartData;\n data?: any;\n }>;\n}\n\n// Execution Result Container\nexport class Execution {\n /**\n * All results from the execution\n */\n public results: Result[] = [];\n\n /**\n * Accumulated stdout and stderr\n */\n public logs = {\n stdout: [] as string[],\n stderr: [] as string[],\n };\n\n /**\n * Execution error if any\n */\n public error?: ExecutionError;\n\n /**\n * Execution count (for interpreter)\n */\n public executionCount?: number;\n\n constructor(\n public readonly code: string,\n public readonly context: CodeContext\n ) {}\n\n /**\n * Convert to a plain object for serialization\n */\n toJSON(): ExecutionResult {\n return {\n code: this.code,\n logs: this.logs,\n error: this.error,\n executionCount: this.executionCount,\n results: this.results.map((result) => ({\n text: result.text,\n html: result.html,\n png: result.png,\n jpeg: result.jpeg,\n svg: result.svg,\n latex: result.latex,\n markdown: result.markdown,\n javascript: result.javascript,\n json: result.json,\n chart: result.chart,\n data: result.data,\n })),\n };\n }\n}\n\n// Implementation of Result\nexport class ResultImpl implements Result {\n constructor(private raw: any) {}\n\n get text(): string | undefined {\n return this.raw.text || this.raw.data?.[\"text/plain\"];\n }\n\n get html(): string | undefined {\n return this.raw.html || this.raw.data?.[\"text/html\"];\n }\n\n get png(): string | undefined {\n return this.raw.png || this.raw.data?.[\"image/png\"];\n }\n\n get jpeg(): string | undefined {\n return this.raw.jpeg || this.raw.data?.[\"image/jpeg\"];\n }\n\n get svg(): string | undefined {\n return this.raw.svg || this.raw.data?.[\"image/svg+xml\"];\n }\n\n get latex(): string | undefined {\n return this.raw.latex || this.raw.data?.[\"text/latex\"];\n }\n\n get markdown(): string | undefined {\n return this.raw.markdown || this.raw.data?.[\"text/markdown\"];\n }\n\n get javascript(): string | undefined {\n return this.raw.javascript || this.raw.data?.[\"application/javascript\"];\n }\n\n get json(): any {\n return this.raw.json || this.raw.data?.[\"application/json\"];\n }\n\n get chart(): ChartData | undefined {\n return this.raw.chart;\n }\n\n get data(): any {\n return this.raw.data;\n }\n\n formats(): string[] {\n const formats: string[] = [];\n if (this.text) formats.push(\"text\");\n if (this.html) formats.push(\"html\");\n if (this.png) formats.push(\"png\");\n if (this.jpeg) formats.push(\"jpeg\");\n if (this.svg) formats.push(\"svg\");\n if (this.latex) formats.push(\"latex\");\n if (this.markdown) formats.push(\"markdown\");\n if (this.javascript) formats.push(\"javascript\");\n if (this.json) formats.push(\"json\");\n if (this.chart) formats.push(\"chart\");\n return formats;\n }\n}\n"],"mappings":";AAgRO,IAAM,YAAN,MAAgB;AAAA,EAwBrB,YACkB,MACA,SAChB;AAFgB;AACA;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAvBI,UAAoB,CAAC;AAAA;AAAA;AAAA;AAAA,EAKrB,OAAO;AAAA,IACZ,QAAQ,CAAC;AAAA,IACT,QAAQ,CAAC;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKO;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAUP,SAA0B;AACxB,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,gBAAgB,KAAK;AAAA,MACrB,SAAS,KAAK,QAAQ,IAAI,CAAC,YAAY;AAAA,QACrC,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,KAAK,OAAO;AAAA,QACZ,MAAM,OAAO;AAAA,QACb,KAAK,OAAO;AAAA,QACZ,OAAO,OAAO;AAAA,QACd,UAAU,OAAO;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,MACf,EAAE;AAAA,IACJ;AAAA,EACF;AACF;AAGO,IAAM,aAAN,MAAmC;AAAA,EACxC,YAAoB,KAAU;AAAV;AAAA,EAAW;AAAA,EAE/B,IAAI,OAA2B;AAC7B,WAAO,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,YAAY;AAAA,EACtD;AAAA,EAEA,IAAI,OAA2B;AAC7B,WAAO,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,WAAW;AAAA,EACrD;AAAA,EAEA,IAAI,MAA0B;AAC5B,WAAO,KAAK,IAAI,OAAO,KAAK,IAAI,OAAO,WAAW;AAAA,EACpD;AAAA,EAEA,IAAI,OAA2B;AAC7B,WAAO,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,YAAY;AAAA,EACtD;AAAA,EAEA,IAAI,MAA0B;AAC5B,WAAO,KAAK,IAAI,OAAO,KAAK,IAAI,OAAO,eAAe;AAAA,EACxD;AAAA,EAEA,IAAI,QAA4B;AAC9B,WAAO,KAAK,IAAI,SAAS,KAAK,IAAI,OAAO,YAAY;AAAA,EACvD;AAAA,EAEA,IAAI,WAA+B;AACjC,WAAO,KAAK,IAAI,YAAY,KAAK,IAAI,OAAO,eAAe;AAAA,EAC7D;AAAA,EAEA,IAAI,aAAiC;AACnC,WAAO,KAAK,IAAI,cAAc,KAAK,IAAI,OAAO,wBAAwB;AAAA,EACxE;AAAA,EAEA,IAAI,OAAY;AACd,WAAO,KAAK,IAAI,QAAQ,KAAK,IAAI,OAAO,kBAAkB;AAAA,EAC5D;AAAA,EAEA,IAAI,QAA+B;AACjC,WAAO,KAAK,IAAI;AAAA,EAClB;AAAA,EAEA,IAAI,OAAY;AACd,WAAO,KAAK,IAAI;AAAA,EAClB;AAAA,EAEA,UAAoB;AAClB,UAAM,UAAoB,CAAC;AAC3B,QAAI,KAAK,KAAM,SAAQ,KAAK,MAAM;AAClC,QAAI,KAAK,KAAM,SAAQ,KAAK,MAAM;AAClC,QAAI,KAAK,IAAK,SAAQ,KAAK,KAAK;AAChC,QAAI,KAAK,KAAM,SAAQ,KAAK,MAAM;AAClC,QAAI,KAAK,IAAK,SAAQ,KAAK,KAAK;AAChC,QAAI,KAAK,MAAO,SAAQ,KAAK,OAAO;AACpC,QAAI,KAAK,SAAU,SAAQ,KAAK,UAAU;AAC1C,QAAI,KAAK,WAAY,SAAQ,KAAK,YAAY;AAC9C,QAAI,KAAK,KAAM,SAAQ,KAAK,MAAM;AAClC,QAAI,KAAK,MAAO,SAAQ,KAAK,OAAO;AACpC,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -4,10 +4,10 @@ import {
4
4
  import {
5
5
  isRetryableError,
6
6
  parseErrorResponse
7
- } from "./chunk-LALY4SFU.js";
7
+ } from "./chunk-FXYPFGOZ.js";
8
8
 
9
- // src/jupyter-client.ts
10
- var JupyterClient = class extends HttpClient {
9
+ // src/interpreter-client.ts
10
+ var InterpreterClient = class extends HttpClient {
11
11
  maxRetries = 3;
12
12
  retryDelayMs = 1e3;
13
13
  async createCodeContext(options = {}) {
@@ -150,7 +150,10 @@ var JupyterClient = class extends HttpClient {
150
150
  break;
151
151
  }
152
152
  } catch (error) {
153
- console.error("[JupyterClient] Error parsing execution result:", error);
153
+ console.error(
154
+ "[InterpreterClient] Error parsing execution result:",
155
+ error
156
+ );
154
157
  }
155
158
  }
156
159
  async listCodeContexts() {
@@ -232,6 +235,6 @@ var JupyterClient = class extends HttpClient {
232
235
  };
233
236
 
234
237
  export {
235
- JupyterClient
238
+ InterpreterClient
236
239
  };
237
- //# sourceMappingURL=chunk-BEQUGUY4.js.map
240
+ //# sourceMappingURL=chunk-Z6OZPC6U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/interpreter-client.ts"],"sourcesContent":["import { HttpClient } from \"./client.js\";\nimport { isRetryableError, parseErrorResponse } from \"./errors.js\";\nimport type {\n CodeContext,\n CreateContextOptions,\n ExecutionError,\n OutputMessage,\n Result,\n} from \"./interpreter-types.js\";\n\n// API Response types\ninterface ContextResponse {\n id: string;\n language: string;\n cwd: string;\n createdAt: string; // ISO date string from JSON\n lastUsed: string; // ISO date string from JSON\n}\n\ninterface ContextListResponse {\n contexts: ContextResponse[];\n}\n\n// Streaming execution data from the server\ninterface StreamingExecutionData {\n type: \"result\" | \"stdout\" | \"stderr\" | \"error\" | \"execution_complete\";\n text?: string;\n html?: string;\n png?: string; // base64\n jpeg?: string; // base64\n svg?: string;\n latex?: string;\n markdown?: string;\n javascript?: string;\n json?: unknown;\n chart?: {\n type:\n | \"line\"\n | \"bar\"\n | \"scatter\"\n | \"pie\"\n | \"histogram\"\n | \"heatmap\"\n | \"unknown\";\n data: unknown;\n options?: unknown;\n };\n data?: unknown;\n metadata?: Record<string, unknown>;\n execution_count?: number;\n ename?: string;\n evalue?: string;\n traceback?: string[];\n lineNumber?: number;\n timestamp?: number;\n}\n\nexport interface ExecutionCallbacks {\n onStdout?: (output: OutputMessage) => void | Promise<void>;\n onStderr?: (output: OutputMessage) => void | Promise<void>;\n onResult?: (result: Result) => void | Promise<void>;\n onError?: (error: ExecutionError) => void | Promise<void>;\n}\n\nexport class InterpreterClient extends HttpClient {\n private readonly maxRetries = 3;\n private readonly retryDelayMs = 1000;\n\n async createCodeContext(\n options: CreateContextOptions = {}\n ): Promise<CodeContext> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch(\"/api/contexts\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n language: options.language || \"python\",\n cwd: options.cwd || \"/workspace\",\n env_vars: options.envVars,\n }),\n });\n\n if (!response.ok) {\n throw await parseErrorResponse(response);\n }\n\n const data = (await response.json()) as ContextResponse;\n return {\n id: data.id,\n language: data.language,\n cwd: data.cwd,\n createdAt: new Date(data.createdAt),\n lastUsed: new Date(data.lastUsed),\n };\n });\n }\n\n async runCodeStream(\n contextId: string | undefined,\n code: string,\n language: string | undefined,\n callbacks: ExecutionCallbacks\n ): Promise<void> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch(\"/api/execute/code\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n },\n body: JSON.stringify({\n context_id: contextId,\n code,\n language,\n }),\n });\n\n if (!response.ok) {\n throw await parseErrorResponse(response);\n }\n\n if (!response.body) {\n throw new Error(\"No response body for streaming execution\");\n }\n\n // Process streaming response\n for await (const chunk of this.readLines(response.body)) {\n await this.parseExecutionResult(chunk, callbacks);\n }\n });\n }\n\n private async *readLines(\n stream: ReadableStream<Uint8Array>\n ): AsyncGenerator<string> {\n const reader = stream.getReader();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (value) {\n buffer += new TextDecoder().decode(value);\n }\n if (done) break;\n\n let newlineIdx = buffer.indexOf(\"\\n\");\n while (newlineIdx !== -1) {\n yield buffer.slice(0, newlineIdx);\n buffer = buffer.slice(newlineIdx + 1);\n newlineIdx = buffer.indexOf(\"\\n\");\n }\n }\n\n // Yield any remaining data\n if (buffer.length > 0) {\n yield buffer;\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private async parseExecutionResult(\n line: string,\n callbacks: ExecutionCallbacks\n ) {\n if (!line.trim()) return;\n\n try {\n const data = JSON.parse(line) as StreamingExecutionData;\n\n switch (data.type) {\n case \"stdout\":\n if (callbacks.onStdout && data.text) {\n await callbacks.onStdout({\n text: data.text,\n timestamp: data.timestamp || Date.now(),\n });\n }\n break;\n\n case \"stderr\":\n if (callbacks.onStderr && data.text) {\n await callbacks.onStderr({\n text: data.text,\n timestamp: data.timestamp || Date.now(),\n });\n }\n break;\n\n case \"result\":\n if (callbacks.onResult) {\n // Convert raw result to Result interface\n const result: Result = {\n text: data.text,\n html: data.html,\n png: data.png,\n jpeg: data.jpeg,\n svg: data.svg,\n latex: data.latex,\n markdown: data.markdown,\n javascript: data.javascript,\n json: data.json,\n chart: data.chart,\n data: data.data,\n formats: () => {\n const formats: string[] = [];\n if (data.text) formats.push(\"text\");\n if (data.html) formats.push(\"html\");\n if (data.png) formats.push(\"png\");\n if (data.jpeg) formats.push(\"jpeg\");\n if (data.svg) formats.push(\"svg\");\n if (data.latex) formats.push(\"latex\");\n if (data.markdown) formats.push(\"markdown\");\n if (data.javascript) formats.push(\"javascript\");\n if (data.json) formats.push(\"json\");\n if (data.chart) formats.push(\"chart\");\n return formats;\n },\n };\n await callbacks.onResult(result);\n }\n break;\n\n case \"error\":\n if (callbacks.onError) {\n await callbacks.onError({\n name: data.ename || \"Error\",\n value: data.evalue || data.text || \"Unknown error\",\n traceback: data.traceback || [],\n lineNumber: data.lineNumber,\n });\n }\n break;\n\n case \"execution_complete\":\n // Execution completed successfully\n break;\n }\n } catch (error) {\n console.error(\n \"[InterpreterClient] Error parsing execution result:\",\n error\n );\n }\n }\n\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch(\"/api/contexts\", {\n method: \"GET\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n if (!response.ok) {\n throw await parseErrorResponse(response);\n }\n\n const data = (await response.json()) as ContextListResponse;\n return data.contexts.map((ctx) => ({\n id: ctx.id,\n language: ctx.language,\n cwd: ctx.cwd,\n createdAt: new Date(ctx.createdAt),\n lastUsed: new Date(ctx.lastUsed),\n }));\n });\n }\n\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch(`/api/contexts/${contextId}`, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n if (!response.ok) {\n throw await parseErrorResponse(response);\n }\n });\n }\n\n // Override parent doFetch to be public for this class\n public async doFetch(path: string, options?: RequestInit): Promise<Response> {\n return super.doFetch(path, options);\n }\n\n /**\n * Execute an operation with automatic retry for transient errors\n */\n private async executeWithRetry<T>(operation: () => Promise<T>): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error as Error;\n\n // Check if it's a retryable error (circuit breaker or interpreter not ready)\n if (this.isRetryableError(error)) {\n // Don't retry on the last attempt\n if (attempt < this.maxRetries - 1) {\n // Exponential backoff with jitter\n const delay =\n this.retryDelayMs * 2 ** attempt + Math.random() * 1000;\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n }\n\n // Non-retryable error or last attempt - throw immediately\n throw error;\n }\n }\n\n // All retries exhausted - throw a clean error without implementation details\n if (lastError?.message.includes(\"Code execution\")) {\n // If the error already has a clean message about code execution, use it\n throw lastError;\n }\n\n // Otherwise, throw a generic but user-friendly error\n throw new Error(\"Unable to execute code at this time\");\n }\n\n /**\n * Check if an error is retryable\n */\n private isRetryableError(error: unknown): boolean {\n // Use the SDK's built-in retryable check\n if (isRetryableError(error)) {\n return true;\n }\n\n // Also check for circuit breaker specific errors\n if (error instanceof Error) {\n // Circuit breaker errors (from the container's response)\n if (error.message.includes(\"Circuit breaker is open\")) {\n return true;\n }\n\n // Check if error has a status property\n if (\"status\" in error && error.status === \"circuit_open\") {\n return true;\n }\n }\n\n return false;\n }\n}\n"],"mappings":"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","names":[]}
@@ -8,7 +8,7 @@ interface ExecutionCallbacks {
8
8
  onResult?: (result: Result) => void | Promise<void>;
9
9
  onError?: (error: ExecutionError) => void | Promise<void>;
10
10
  }
11
- declare class JupyterClient extends HttpClient {
11
+ declare class InterpreterClient extends HttpClient {
12
12
  private readonly maxRetries;
13
13
  private readonly retryDelayMs;
14
14
  createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;
@@ -32,7 +32,7 @@ declare function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string): Du
32
32
  declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
33
33
  defaultPort: number;
34
34
  sleepAfter: string;
35
- client: JupyterClient;
35
+ client: InterpreterClient;
36
36
  private sandboxName;
37
37
  private codeInterpreter;
38
38
  private defaultSession;
@@ -220,4 +220,4 @@ declare class HttpClient {
220
220
  }): Promise<ReadableStream<Uint8Array>>;
221
221
  }
222
222
 
223
- export { type ExecutionCallbacks as E, HttpClient as H, JupyterClient as J, Sandbox as S, getSandbox as g };
223
+ export { type ExecutionCallbacks as E, HttpClient as H, InterpreterClient as I, Sandbox as S, getSandbox as g };
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { H as HttpClient } from './client-Dny_ro_v.js';
1
+ export { H as HttpClient } from './client-COGWU6bz.js';
2
2
  import './types.js';
3
3
  import '@cloudflare/containers';
4
4
  import './interpreter-types.js';
package/dist/errors.d.ts CHANGED
@@ -13,17 +13,17 @@ declare class SandboxError extends Error {
13
13
  constructor(message: string);
14
14
  }
15
15
  /**
16
- * Error thrown when Jupyter functionality is requested but the service is still initializing.
16
+ * Error thrown when interpreter functionality is requested but the service is still initializing.
17
17
  *
18
- * Note: With the current implementation, requests wait for Jupyter to be ready.
18
+ * Note: With the current implementation, requests wait for interpreter to be ready.
19
19
  * This error is only thrown when:
20
- * 1. The request times out waiting for Jupyter (default: 30 seconds)
21
- * 2. Jupyter initialization actually fails
20
+ * 1. The request times out waiting for interpreter (default: 30 seconds)
21
+ * 2. interpreter initialization actually fails
22
22
  *
23
23
  * Most requests will succeed after a delay, not throw this error.
24
24
  */
25
- declare class JupyterNotReadyError extends SandboxError {
26
- readonly code = "JUPYTER_NOT_READY";
25
+ declare class InterpreterNotReadyError extends SandboxError {
26
+ readonly code = "INTERPRETER_NOT_READY";
27
27
  readonly retryAfter: number;
28
28
  readonly progress?: number;
29
29
  constructor(message?: string, options?: {
@@ -76,9 +76,9 @@ declare class ServiceUnavailableError extends SandboxError {
76
76
  constructor(message?: string, retryAfter?: number);
77
77
  }
78
78
  /**
79
- * Type guard to check if an error is a JupyterNotReadyError
79
+ * Type guard to check if an error is a InterpreterNotReadyError
80
80
  */
81
- declare function isJupyterNotReadyError(error: unknown): error is JupyterNotReadyError;
81
+ declare function isInterpreterNotReadyError(error: unknown): error is InterpreterNotReadyError;
82
82
  /**
83
83
  * Type guard to check if an error is any SandboxError
84
84
  */
@@ -92,4 +92,4 @@ declare function isRetryableError(error: unknown): boolean;
92
92
  */
93
93
  declare function parseErrorResponse(response: Response): Promise<SandboxError>;
94
94
 
95
- export { CodeExecutionError, ContainerNotReadyError, ContextNotFoundError, JupyterNotReadyError, SandboxError, type SandboxErrorResponse, SandboxNetworkError, ServiceUnavailableError, isJupyterNotReadyError, isRetryableError, isSandboxError, parseErrorResponse };
95
+ export { CodeExecutionError, ContainerNotReadyError, ContextNotFoundError, InterpreterNotReadyError, SandboxError, type SandboxErrorResponse, SandboxNetworkError, ServiceUnavailableError, isInterpreterNotReadyError, isRetryableError, isSandboxError, parseErrorResponse };
package/dist/errors.js CHANGED
@@ -2,24 +2,24 @@ import {
2
2
  CodeExecutionError,
3
3
  ContainerNotReadyError,
4
4
  ContextNotFoundError,
5
- JupyterNotReadyError,
5
+ InterpreterNotReadyError,
6
6
  SandboxError,
7
7
  SandboxNetworkError,
8
8
  ServiceUnavailableError,
9
- isJupyterNotReadyError,
9
+ isInterpreterNotReadyError,
10
10
  isRetryableError,
11
11
  isSandboxError,
12
12
  parseErrorResponse
13
- } from "./chunk-LALY4SFU.js";
13
+ } from "./chunk-FXYPFGOZ.js";
14
14
  export {
15
15
  CodeExecutionError,
16
16
  ContainerNotReadyError,
17
17
  ContextNotFoundError,
18
- JupyterNotReadyError,
18
+ InterpreterNotReadyError,
19
19
  SandboxError,
20
20
  SandboxNetworkError,
21
21
  ServiceUnavailableError,
22
- isJupyterNotReadyError,
22
+ isInterpreterNotReadyError,
23
23
  isRetryableError,
24
24
  isSandboxError,
25
25
  parseErrorResponse
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { CodeExecutionError, ContainerNotReadyError, ContextNotFoundError, JupyterNotReadyError, SandboxError, SandboxErrorResponse, SandboxNetworkError, ServiceUnavailableError, isJupyterNotReadyError, isRetryableError, isSandboxError, parseErrorResponse } from './errors.js';
1
+ export { CodeExecutionError, ContainerNotReadyError, ContextNotFoundError, InterpreterNotReadyError, InterpreterNotReadyError as JupyterNotReadyError, SandboxError, SandboxErrorResponse, SandboxNetworkError, ServiceUnavailableError, isInterpreterNotReadyError, isInterpreterNotReadyError as isJupyterNotReadyError, isRetryableError, isSandboxError, parseErrorResponse } from './errors.js';
2
2
  export { ChartData, CodeContext, CreateContextOptions, Execution, ExecutionError, OutputMessage, Result, ResultImpl, RunCodeOptions } from './interpreter-types.js';
3
3
  export { RouteInfo, SandboxEnv, proxyToSandbox } from './request-handler.js';
4
- export { S as Sandbox, g as getSandbox } from './client-Dny_ro_v.js';
4
+ export { S as Sandbox, g as getSandbox } from './client-COGWU6bz.js';
5
5
  export { asyncIterableToSSEStream, parseSSEStream, responseToAsyncIterable } from './sse-parser.js';
6
6
  export { DeleteFileResponse, ExecEvent, ExecOptions, ExecResult, ExecuteResponse, ExecutionSession, GitCheckoutResponse, ISandbox, ListFilesResponse, LogEvent, MkdirResponse, MoveFileResponse, Process, ProcessOptions, ProcessStatus, ReadFileResponse, RenameFileResponse, StreamOptions, WriteFileResponse } from './types.js';
7
7
  import '@cloudflare/containers';
package/dist/index.js CHANGED
@@ -7,32 +7,33 @@ import {
7
7
  Sandbox,
8
8
  getSandbox,
9
9
  proxyToSandbox
10
- } from "./chunk-LFLJGISB.js";
10
+ } from "./chunk-H4PW2LGW.js";
11
11
  import "./chunk-6UAWTJ5S.js";
12
- import "./chunk-FKBV7CZS.js";
13
- import {
14
- ResultImpl
15
- } from "./chunk-EGC5IYXA.js";
16
- import "./chunk-BEQUGUY4.js";
12
+ import "./chunk-Z6OZPC6U.js";
17
13
  import "./chunk-SMUEY5JR.js";
18
14
  import {
19
15
  CodeExecutionError,
20
16
  ContainerNotReadyError,
21
17
  ContextNotFoundError,
22
- JupyterNotReadyError,
18
+ InterpreterNotReadyError,
23
19
  SandboxError,
24
20
  SandboxNetworkError,
25
21
  ServiceUnavailableError,
26
- isJupyterNotReadyError,
22
+ isInterpreterNotReadyError,
27
23
  isRetryableError,
28
24
  isSandboxError,
29
25
  parseErrorResponse
30
- } from "./chunk-LALY4SFU.js";
26
+ } from "./chunk-FXYPFGOZ.js";
27
+ import "./chunk-JTKON2SH.js";
28
+ import {
29
+ ResultImpl
30
+ } from "./chunk-W7TVRPBG.js";
31
31
  export {
32
32
  CodeExecutionError,
33
33
  ContainerNotReadyError,
34
34
  ContextNotFoundError,
35
- JupyterNotReadyError,
35
+ InterpreterNotReadyError,
36
+ InterpreterNotReadyError as JupyterNotReadyError,
36
37
  ResultImpl,
37
38
  Sandbox,
38
39
  SandboxError,
@@ -40,7 +41,8 @@ export {
40
41
  ServiceUnavailableError,
41
42
  asyncIterableToSSEStream,
42
43
  getSandbox,
43
- isJupyterNotReadyError,
44
+ isInterpreterNotReadyError,
45
+ isInterpreterNotReadyError as isJupyterNotReadyError,
44
46
  isRetryableError,
45
47
  isSandboxError,
46
48
  parseErrorResponse,
@@ -0,0 +1,4 @@
1
+ export { E as ExecutionCallbacks, I as InterpreterClient } from './client-COGWU6bz.js';
2
+ import './interpreter-types.js';
3
+ import './types.js';
4
+ import '@cloudflare/containers';
@@ -0,0 +1,9 @@
1
+ import {
2
+ InterpreterClient
3
+ } from "./chunk-Z6OZPC6U.js";
4
+ import "./chunk-SMUEY5JR.js";
5
+ import "./chunk-FXYPFGOZ.js";
6
+ export {
7
+ InterpreterClient
8
+ };
9
+ //# sourceMappingURL=interpreter-client.js.map
@@ -3,7 +3,7 @@ interface CreateContextOptions {
3
3
  * Programming language for the context
4
4
  * @default 'python'
5
5
  */
6
- language?: 'python' | 'javascript' | 'typescript';
6
+ language?: "python" | "javascript" | "typescript";
7
7
  /**
8
8
  * Working directory for the context
9
9
  * @default '/workspace'
@@ -50,7 +50,7 @@ interface RunCodeOptions {
50
50
  * Language to use if context is not provided
51
51
  * @default 'python'
52
52
  */
53
- language?: 'python' | 'javascript' | 'typescript';
53
+ language?: "python" | "javascript" | "typescript";
54
54
  /**
55
55
  * Environment variables for this execution
56
56
  */
@@ -145,7 +145,7 @@ interface ChartData {
145
145
  /**
146
146
  * Type of chart
147
147
  */
148
- type: 'line' | 'bar' | 'scatter' | 'pie' | 'histogram' | 'heatmap' | 'unknown';
148
+ type: "line" | "bar" | "scatter" | "pie" | "histogram" | "heatmap" | "unknown";
149
149
  /**
150
150
  * Chart title
151
151
  */
@@ -165,7 +165,7 @@ interface ChartData {
165
165
  /**
166
166
  * Library that generated the chart
167
167
  */
168
- library?: 'matplotlib' | 'plotly' | 'altair' | 'seaborn' | 'unknown';
168
+ library?: "matplotlib" | "plotly" | "altair" | "seaborn" | "unknown";
169
169
  /**
170
170
  * Base64 encoded image if available
171
171
  */
@@ -230,7 +230,7 @@ declare class Execution {
230
230
  */
231
231
  error?: ExecutionError;
232
232
  /**
233
- * Execution count (for Jupyter)
233
+ * Execution count (for interpreter)
234
234
  */
235
235
  executionCount?: number;
236
236
  constructor(code: string, context: CodeContext);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Execution,
3
3
  ResultImpl
4
- } from "./chunk-EGC5IYXA.js";
4
+ } from "./chunk-W7TVRPBG.js";
5
5
  export {
6
6
  Execution,
7
7
  ResultImpl
@@ -1,10 +1,10 @@
1
1
  import { CreateContextOptions, CodeContext, RunCodeOptions, Execution } from './interpreter-types.js';
2
- import { S as Sandbox } from './client-Dny_ro_v.js';
2
+ import { S as Sandbox } from './client-COGWU6bz.js';
3
3
  import './types.js';
4
4
  import '@cloudflare/containers';
5
5
 
6
6
  declare class CodeInterpreter {
7
- private jupyterClient;
7
+ private interpreterClient;
8
8
  private contexts;
9
9
  constructor(sandbox: Sandbox);
10
10
  /**
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CodeInterpreter
3
- } from "./chunk-FKBV7CZS.js";
4
- import "./chunk-EGC5IYXA.js";
3
+ } from "./chunk-JTKON2SH.js";
4
+ import "./chunk-W7TVRPBG.js";
5
5
  export {
6
6
  CodeInterpreter
7
7
  };
@@ -1,4 +1,4 @@
1
- import { S as Sandbox } from './client-Dny_ro_v.js';
1
+ import { S as Sandbox } from './client-COGWU6bz.js';
2
2
  import './types.js';
3
3
  import './interpreter-types.js';
4
4
  import '@cloudflare/containers';
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  isLocalhostPattern,
3
3
  proxyToSandbox
4
- } from "./chunk-LFLJGISB.js";
4
+ } from "./chunk-H4PW2LGW.js";
5
5
  import "./chunk-6UAWTJ5S.js";
6
- import "./chunk-FKBV7CZS.js";
7
- import "./chunk-EGC5IYXA.js";
8
- import "./chunk-BEQUGUY4.js";
6
+ import "./chunk-Z6OZPC6U.js";
9
7
  import "./chunk-SMUEY5JR.js";
10
- import "./chunk-LALY4SFU.js";
8
+ import "./chunk-FXYPFGOZ.js";
9
+ import "./chunk-JTKON2SH.js";
10
+ import "./chunk-W7TVRPBG.js";
11
11
  export {
12
12
  isLocalhostPattern,
13
13
  proxyToSandbox
package/dist/sandbox.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import './types.js';
2
2
  import '@cloudflare/containers';
3
+ export { S as Sandbox, g as getSandbox } from './client-COGWU6bz.js';
3
4
  import './interpreter-types.js';
4
- export { S as Sandbox, g as getSandbox } from './client-Dny_ro_v.js';
package/dist/sandbox.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  Sandbox,
3
3
  getSandbox
4
- } from "./chunk-LFLJGISB.js";
4
+ } from "./chunk-H4PW2LGW.js";
5
5
  import "./chunk-6UAWTJ5S.js";
6
- import "./chunk-FKBV7CZS.js";
7
- import "./chunk-EGC5IYXA.js";
8
- import "./chunk-BEQUGUY4.js";
6
+ import "./chunk-Z6OZPC6U.js";
9
7
  import "./chunk-SMUEY5JR.js";
10
- import "./chunk-LALY4SFU.js";
8
+ import "./chunk-FXYPFGOZ.js";
9
+ import "./chunk-JTKON2SH.js";
10
+ import "./chunk-W7TVRPBG.js";
11
11
  export {
12
12
  Sandbox,
13
13
  getSandbox
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/sandbox",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cloudflare/sandbox-sdk"