@computesdk/modal 1.7.2 → 1.8.0

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/dist/index.js CHANGED
@@ -57,7 +57,7 @@ var modal = (0, import_computesdk.createProvider)({
57
57
  sandboxId = options.sandboxId;
58
58
  } else {
59
59
  const app = await import_modal.App.lookup("computesdk-modal", { createIfMissing: true });
60
- const image = await app.imageFromRegistry("node:20-alpine");
60
+ const image = await app.imageFromRegistry("node:20");
61
61
  const sandboxOptions = {};
62
62
  if (config.ports && config.ports.length > 0) {
63
63
  sandboxOptions.unencryptedPorts = config.ports;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Modal Provider - Factory-based Implementation\n * \n * Full-featured provider with serverless sandbox execution using the factory pattern.\n * Leverages Modal's JavaScript SDK for real sandbox management.\n * \n * Note: Modal's JavaScript SDK is in alpha. This implementation provides a working\n * foundation but may need updates as the Modal API evolves.\n */\n\nimport { createProvider } from 'computesdk';\nimport type {\n CodeResult,\n CommandResult,\n SandboxInfo,\n Runtime,\n CreateSandboxOptions,\n FileEntry\n} from 'computesdk';\n\n// Import Modal SDK\nimport { App, Sandbox, initializeClient } from 'modal';\n\n/**\n * Modal-specific configuration options\n */\nexport interface ModalConfig {\n /** Modal API token ID - if not provided, will fallback to MODAL_TOKEN_ID environment variable */\n tokenId?: string;\n /** Modal API token secret - if not provided, will fallback to MODAL_TOKEN_SECRET environment variable */\n tokenSecret?: string;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Modal environment (sandbox or main) */\n environment?: string;\n /** Ports to expose */\n ports?: number[];\n}\n\n/**\n * Modal sandbox interface - wraps Modal's Sandbox class\n */\ninterface ModalSandbox {\n sandbox: any; // Modal Sandbox instance (using any due to alpha SDK)\n sandboxId: string;\n}\n\n/**\n * Detect runtime from code content\n */\nfunction detectRuntime(code: string): Runtime {\n // Strong Node.js indicators\n if (code.includes('console.log') || \n code.includes('process.') ||\n code.includes('require(') ||\n code.includes('module.exports') ||\n code.includes('__dirname') ||\n code.includes('__filename') ||\n code.includes('throw new Error') || // JavaScript error throwing\n code.includes('new Error(')) {\n return 'node';\n }\n\n // Strong Python indicators\n if (code.includes('print(') ||\n code.includes('import ') ||\n code.includes('def ') ||\n code.includes('sys.') ||\n code.includes('json.') ||\n code.includes('f\"') ||\n code.includes(\"f'\") ||\n code.includes('raise ')) {\n return 'python';\n }\n\n // Default to Node.js for Modal (now using Node.js base image)\n return 'node';\n}\n\n/**\n * Create a Modal provider instance using the factory pattern\n */\nexport const modal = createProvider<ModalSandbox, ModalConfig>({\n name: 'modal',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: ModalConfig, options?: CreateSandboxOptions) => {\n // Validate API credentials\n const tokenId = config.tokenId || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_ID) || '';\n const tokenSecret = config.tokenSecret || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_SECRET) || '';\n\n if (!tokenId || !tokenSecret) {\n throw new Error(\n `Missing Modal API credentials. Provide 'tokenId' and 'tokenSecret' in config or set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n\n try {\n // Initialize Modal client with credentials\n initializeClient({ tokenId, tokenSecret });\n\n let sandbox: any;\n let sandboxId: string;\n\n if (options?.sandboxId) {\n // Reconnect to existing Modal sandbox\n sandbox = await Sandbox.fromId(options.sandboxId);\n sandboxId = options.sandboxId;\n } else {\n // Create new Modal sandbox with Node.js (more appropriate for a Node.js SDK)\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const image = await app.imageFromRegistry('node:20-alpine');\n \n // Configure sandbox options\n const sandboxOptions: any = {}; // Using 'any' since Modal SDK is alpha\n \n // Configure ports if provided (using unencrypted ports by default)\n if (config.ports && config.ports.length > 0) {\n sandboxOptions.unencryptedPorts = config.ports;\n }\n \n // Add timeout if specified\n if (config.timeout) {\n sandboxOptions.timeout = config.timeout;\n }\n \n sandbox = await app.createSandbox(image, sandboxOptions);\n sandboxId = sandbox.sandboxId;\n }\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('credentials')) {\n throw new Error(\n `Modal authentication failed. Please check your MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `Modal quota exceeded. Please check your usage at https://modal.com/`\n );\n }\n }\n throw new Error(\n `Failed to create Modal sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: ModalConfig, sandboxId: string) => {\n const tokenId = config.tokenId || process.env.MODAL_TOKEN_ID!;\n const tokenSecret = config.tokenSecret || process.env.MODAL_TOKEN_SECRET!;\n\n try {\n initializeClient({ tokenId, tokenSecret });\n const sandbox = await Sandbox.fromId(sandboxId);\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\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: ModalConfig) => {\n throw new Error(\n `Modal provider does not support listing sandboxes. Modal sandboxes are managed individually through the Modal console. Use getById to reconnect to specific sandboxes by ID.`\n );\n },\n\n destroy: async (_config: ModalConfig, sandboxId: string) => {\n try {\n const sandbox = await Sandbox.fromId(sandboxId);\n if (sandbox && typeof sandbox.terminate === 'function') {\n await sandbox.terminate();\n }\n } catch (error) {\n // Sandbox might already be terminated or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (modalSandbox: ModalSandbox, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const startTime = Date.now();\n\n try {\n // Auto-detect runtime from code if not specified\n const detectedRuntime = runtime || detectRuntime(code);\n\n // Create appropriate sandbox and command for the runtime\n let executionSandbox = modalSandbox.sandbox;\n let command: string[];\n let shouldCleanupSandbox = false;\n\n if (detectedRuntime === 'node') {\n // Use existing Node.js sandbox (now the default)\n command = ['node', '-e', code];\n } else {\n // For Python execution, create a Python sandbox dynamically\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const pythonImage = await app.imageFromRegistry('python:3.13-slim');\n executionSandbox = await app.createSandbox(pythonImage);\n command = ['python3', '-c', code];\n shouldCleanupSandbox = true; // Clean up temporary Python sandbox\n }\n\n const process = await executionSandbox.exec(command, {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n // Clean up temporary Python sandbox if created\n if (shouldCleanupSandbox && executionSandbox !== modalSandbox.sandbox) {\n try {\n await executionSandbox.terminate();\n } catch (e) {\n // Ignore cleanup errors\n }\n }\n\n // Check for syntax errors in stderr\n if (exitCode !== 0 && stderr && (\n stderr.includes('SyntaxError') ||\n stderr.includes('invalid syntax')\n )) {\n throw new Error(`Syntax error: ${stderr.trim()}`);\n }\n\n return {\n output: (stdout || '') + (stderr || ''),\n exitCode: exitCode || 0,\n language: detectedRuntime,\n };\n } catch (error) {\n // Handle syntax errors and runtime errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error; // Re-throw syntax errors\n }\n\n throw new Error(\n `Modal execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (modalSandbox: ModalSandbox, command: string, args: string[] = []): Promise<CommandResult> => {\n const startTime = Date.now();\n\n try {\n // Execute command using Modal's exec method with working pattern\n const process = await modalSandbox.sandbox.exec([command, ...args], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n return {\n stdout: stdout || '',\n stderr: stderr || '',\n exitCode: 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 (modalSandbox: ModalSandbox): Promise<SandboxInfo> => {\n // Get actual sandbox status using Modal's poll method\n let status: 'running' | 'stopped' | 'error' = 'running';\n try {\n const pollResult = await modalSandbox.sandbox.poll();\n if (pollResult !== null) {\n // Sandbox has finished\n status = pollResult === 0 ? 'stopped' : 'error';\n }\n } catch (error) {\n // If polling fails, assume running\n status = 'running';\n }\n\n return {\n id: modalSandbox.sandboxId,\n provider: 'modal',\n runtime: 'node', // Modal default (now using Node.js)\n status,\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n modalSandboxId: modalSandbox.sandboxId,\n realModalImplementation: true\n }\n };\n },\n\n getUrl: async (modalSandbox: ModalSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n // Use Modal's built-in tunnels method to get tunnel information\n const tunnels = await modalSandbox.sandbox.tunnels();\n const tunnel = tunnels[options.port];\n \n if (!tunnel) {\n throw new Error(`No tunnel found for port ${options.port}. Available ports: ${Object.keys(tunnels).join(', ')}`);\n }\n \n let url = tunnel.url;\n \n // If a specific protocol is requested, replace the URL's protocol\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to get Modal tunnel URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n // Optional filesystem methods - Modal supports filesystem operations\n filesystem: {\n readFile: async (modalSandbox: ModalSandbox, path: string): Promise<string> => {\n try {\n // Use Modal's file open API to read files\n const file = await modalSandbox.sandbox.open(path);\n \n // Read the entire file content\n let content = '';\n if (file && typeof file.read === 'function') {\n const data = await file.read();\n content = typeof data === 'string' ? data : new TextDecoder().decode(data);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n \n return content;\n } catch (error) {\n // Fallback to using cat command with working stream pattern\n try {\n const process = await modalSandbox.sandbox.exec(['cat', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [content, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`cat failed: ${stderr}`);\n }\n\n return content.trim(); // Remove extra newlines\n } catch (fallbackError) {\n throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n writeFile: async (modalSandbox: ModalSandbox, path: string, content: string): Promise<void> => {\n try {\n // Use Modal's file open API to write files\n const file = await modalSandbox.sandbox.open(path);\n \n // Write content to the file\n if (file && typeof file.write === 'function') {\n await file.write(content);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n } catch (error) {\n // Fallback to using shell command with proper escaping\n try {\n const process = await modalSandbox.sandbox.exec(['sh', '-c', `printf '%s' \"${content.replace(/\"/g, '\\\\\"')}\" > \"${path}\"`], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`write failed: ${stderr}`);\n }\n } catch (fallbackError) {\n throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n mkdir: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['mkdir', '-p', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`mkdir failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n readdir: async (modalSandbox: ModalSandbox, path: string): Promise<FileEntry[]> => {\n try {\n // Use simple -l flag for BusyBox compatibility (Alpine/node:20-alpine uses BusyBox ls)\n const process = await modalSandbox.sandbox.exec(['ls', '-la', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [output, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`ls failed: ${stderr}`);\n }\n\n const lines = output.split('\\n').slice(1); // Skip header\n\n return lines\n .filter((line: string) => line.trim())\n .map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const permissions = parts[0] || '';\n const size = parseInt(parts[4]) || 0;\n const dateStr = (parts[5] || '') + ' ' + (parts[6] || '');\n const date = dateStr.trim() ? new Date(dateStr) : new Date();\n const name = parts.slice(8).join(' ') || parts[parts.length - 1] || 'unknown';\n\n return {\n name,\n path: `${path}/${name}`.replace('//', '/'),\n isDirectory: permissions.startsWith('d'),\n size,\n lastModified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n } catch (error) {\n throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n exists: async (modalSandbox: ModalSandbox, path: string): Promise<boolean> => {\n try {\n const process = await modalSandbox.sandbox.exec(['test', '-e', path]);\n const exitCode = await process.wait();\n return exitCode === 0;\n } catch (error) {\n return false;\n }\n },\n\n remove: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['rm', '-rf', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`rm failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n // Provider-specific typed getInstance method\n getInstance: (sandbox: ModalSandbox): ModalSandbox => {\n return sandbox;\n },\n\n }\n }\n});"],"mappings":"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","names":["process"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Modal Provider - Factory-based Implementation\n * \n * Full-featured provider with serverless sandbox execution using the factory pattern.\n * Leverages Modal's JavaScript SDK for real sandbox management.\n * \n * Note: Modal's JavaScript SDK is in alpha. This implementation provides a working\n * foundation but may need updates as the Modal API evolves.\n */\n\nimport { createProvider } from 'computesdk';\nimport type {\n CodeResult,\n CommandResult,\n SandboxInfo,\n Runtime,\n CreateSandboxOptions,\n FileEntry\n} from 'computesdk';\n\n// Import Modal SDK\nimport { App, Sandbox, initializeClient } from 'modal';\n\n/**\n * Modal-specific configuration options\n */\nexport interface ModalConfig {\n /** Modal API token ID - if not provided, will fallback to MODAL_TOKEN_ID environment variable */\n tokenId?: string;\n /** Modal API token secret - if not provided, will fallback to MODAL_TOKEN_SECRET environment variable */\n tokenSecret?: string;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Modal environment (sandbox or main) */\n environment?: string;\n /** Ports to expose */\n ports?: number[];\n}\n\n/**\n * Modal sandbox interface - wraps Modal's Sandbox class\n */\ninterface ModalSandbox {\n sandbox: any; // Modal Sandbox instance (using any due to alpha SDK)\n sandboxId: string;\n}\n\n/**\n * Detect runtime from code content\n */\nfunction detectRuntime(code: string): Runtime {\n // Strong Node.js indicators\n if (code.includes('console.log') || \n code.includes('process.') ||\n code.includes('require(') ||\n code.includes('module.exports') ||\n code.includes('__dirname') ||\n code.includes('__filename') ||\n code.includes('throw new Error') || // JavaScript error throwing\n code.includes('new Error(')) {\n return 'node';\n }\n\n // Strong Python indicators\n if (code.includes('print(') ||\n code.includes('import ') ||\n code.includes('def ') ||\n code.includes('sys.') ||\n code.includes('json.') ||\n code.includes('f\"') ||\n code.includes(\"f'\") ||\n code.includes('raise ')) {\n return 'python';\n }\n\n // Default to Node.js for Modal (now using Node.js base image)\n return 'node';\n}\n\n/**\n * Create a Modal provider instance using the factory pattern\n */\nexport const modal = createProvider<ModalSandbox, ModalConfig>({\n name: 'modal',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: ModalConfig, options?: CreateSandboxOptions) => {\n // Validate API credentials\n const tokenId = config.tokenId || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_ID) || '';\n const tokenSecret = config.tokenSecret || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_SECRET) || '';\n\n if (!tokenId || !tokenSecret) {\n throw new Error(\n `Missing Modal API credentials. Provide 'tokenId' and 'tokenSecret' in config or set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n\n try {\n // Initialize Modal client with credentials\n initializeClient({ tokenId, tokenSecret });\n\n let sandbox: any;\n let sandboxId: string;\n\n if (options?.sandboxId) {\n // Reconnect to existing Modal sandbox\n sandbox = await Sandbox.fromId(options.sandboxId);\n sandboxId = options.sandboxId;\n } else {\n // Create new Modal sandbox with Node.js (more appropriate for a Node.js SDK)\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const image = await app.imageFromRegistry('node:20');\n \n // Configure sandbox options\n const sandboxOptions: any = {}; // Using 'any' since Modal SDK is alpha\n \n // Configure ports if provided (using unencrypted ports by default)\n if (config.ports && config.ports.length > 0) {\n sandboxOptions.unencryptedPorts = config.ports;\n }\n \n // Add timeout if specified\n if (config.timeout) {\n sandboxOptions.timeout = config.timeout;\n }\n \n sandbox = await app.createSandbox(image, sandboxOptions);\n sandboxId = sandbox.sandboxId;\n }\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('credentials')) {\n throw new Error(\n `Modal authentication failed. Please check your MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `Modal quota exceeded. Please check your usage at https://modal.com/`\n );\n }\n }\n throw new Error(\n `Failed to create Modal sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: ModalConfig, sandboxId: string) => {\n const tokenId = config.tokenId || process.env.MODAL_TOKEN_ID!;\n const tokenSecret = config.tokenSecret || process.env.MODAL_TOKEN_SECRET!;\n\n try {\n initializeClient({ tokenId, tokenSecret });\n const sandbox = await Sandbox.fromId(sandboxId);\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\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: ModalConfig) => {\n throw new Error(\n `Modal provider does not support listing sandboxes. Modal sandboxes are managed individually through the Modal console. Use getById to reconnect to specific sandboxes by ID.`\n );\n },\n\n destroy: async (_config: ModalConfig, sandboxId: string) => {\n try {\n const sandbox = await Sandbox.fromId(sandboxId);\n if (sandbox && typeof sandbox.terminate === 'function') {\n await sandbox.terminate();\n }\n } catch (error) {\n // Sandbox might already be terminated or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (modalSandbox: ModalSandbox, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const startTime = Date.now();\n\n try {\n // Auto-detect runtime from code if not specified\n const detectedRuntime = runtime || detectRuntime(code);\n\n // Create appropriate sandbox and command for the runtime\n let executionSandbox = modalSandbox.sandbox;\n let command: string[];\n let shouldCleanupSandbox = false;\n\n if (detectedRuntime === 'node') {\n // Use existing Node.js sandbox (now the default)\n command = ['node', '-e', code];\n } else {\n // For Python execution, create a Python sandbox dynamically\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const pythonImage = await app.imageFromRegistry('python:3.13-slim');\n executionSandbox = await app.createSandbox(pythonImage);\n command = ['python3', '-c', code];\n shouldCleanupSandbox = true; // Clean up temporary Python sandbox\n }\n\n const process = await executionSandbox.exec(command, {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n // Clean up temporary Python sandbox if created\n if (shouldCleanupSandbox && executionSandbox !== modalSandbox.sandbox) {\n try {\n await executionSandbox.terminate();\n } catch (e) {\n // Ignore cleanup errors\n }\n }\n\n // Check for syntax errors in stderr\n if (exitCode !== 0 && stderr && (\n stderr.includes('SyntaxError') ||\n stderr.includes('invalid syntax')\n )) {\n throw new Error(`Syntax error: ${stderr.trim()}`);\n }\n\n return {\n output: (stdout || '') + (stderr || ''),\n exitCode: exitCode || 0,\n language: detectedRuntime,\n };\n } catch (error) {\n // Handle syntax errors and runtime errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error; // Re-throw syntax errors\n }\n\n throw new Error(\n `Modal execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (modalSandbox: ModalSandbox, command: string, args: string[] = []): Promise<CommandResult> => {\n const startTime = Date.now();\n\n try {\n // Execute command using Modal's exec method with working pattern\n const process = await modalSandbox.sandbox.exec([command, ...args], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n return {\n stdout: stdout || '',\n stderr: stderr || '',\n exitCode: 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 (modalSandbox: ModalSandbox): Promise<SandboxInfo> => {\n // Get actual sandbox status using Modal's poll method\n let status: 'running' | 'stopped' | 'error' = 'running';\n try {\n const pollResult = await modalSandbox.sandbox.poll();\n if (pollResult !== null) {\n // Sandbox has finished\n status = pollResult === 0 ? 'stopped' : 'error';\n }\n } catch (error) {\n // If polling fails, assume running\n status = 'running';\n }\n\n return {\n id: modalSandbox.sandboxId,\n provider: 'modal',\n runtime: 'node', // Modal default (now using Node.js)\n status,\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n modalSandboxId: modalSandbox.sandboxId,\n realModalImplementation: true\n }\n };\n },\n\n getUrl: async (modalSandbox: ModalSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n // Use Modal's built-in tunnels method to get tunnel information\n const tunnels = await modalSandbox.sandbox.tunnels();\n const tunnel = tunnels[options.port];\n \n if (!tunnel) {\n throw new Error(`No tunnel found for port ${options.port}. Available ports: ${Object.keys(tunnels).join(', ')}`);\n }\n \n let url = tunnel.url;\n \n // If a specific protocol is requested, replace the URL's protocol\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to get Modal tunnel URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n // Optional filesystem methods - Modal supports filesystem operations\n filesystem: {\n readFile: async (modalSandbox: ModalSandbox, path: string): Promise<string> => {\n try {\n // Use Modal's file open API to read files\n const file = await modalSandbox.sandbox.open(path);\n \n // Read the entire file content\n let content = '';\n if (file && typeof file.read === 'function') {\n const data = await file.read();\n content = typeof data === 'string' ? data : new TextDecoder().decode(data);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n \n return content;\n } catch (error) {\n // Fallback to using cat command with working stream pattern\n try {\n const process = await modalSandbox.sandbox.exec(['cat', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [content, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`cat failed: ${stderr}`);\n }\n\n return content.trim(); // Remove extra newlines\n } catch (fallbackError) {\n throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n writeFile: async (modalSandbox: ModalSandbox, path: string, content: string): Promise<void> => {\n try {\n // Use Modal's file open API to write files\n const file = await modalSandbox.sandbox.open(path);\n \n // Write content to the file\n if (file && typeof file.write === 'function') {\n await file.write(content);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n } catch (error) {\n // Fallback to using shell command with proper escaping\n try {\n const process = await modalSandbox.sandbox.exec(['sh', '-c', `printf '%s' \"${content.replace(/\"/g, '\\\\\"')}\" > \"${path}\"`], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`write failed: ${stderr}`);\n }\n } catch (fallbackError) {\n throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n mkdir: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['mkdir', '-p', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`mkdir failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n readdir: async (modalSandbox: ModalSandbox, path: string): Promise<FileEntry[]> => {\n try {\n // Use simple -l flag for BusyBox compatibility (Alpine/node:20-alpine uses BusyBox ls)\n const process = await modalSandbox.sandbox.exec(['ls', '-la', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [output, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`ls failed: ${stderr}`);\n }\n\n const lines = output.split('\\n').slice(1); // Skip header\n\n return lines\n .filter((line: string) => line.trim())\n .map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const permissions = parts[0] || '';\n const size = parseInt(parts[4]) || 0;\n const dateStr = (parts[5] || '') + ' ' + (parts[6] || '');\n const date = dateStr.trim() ? new Date(dateStr) : new Date();\n const name = parts.slice(8).join(' ') || parts[parts.length - 1] || 'unknown';\n\n return {\n name,\n path: `${path}/${name}`.replace('//', '/'),\n isDirectory: permissions.startsWith('d'),\n size,\n lastModified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n } catch (error) {\n throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n exists: async (modalSandbox: ModalSandbox, path: string): Promise<boolean> => {\n try {\n const process = await modalSandbox.sandbox.exec(['test', '-e', path]);\n const exitCode = await process.wait();\n return exitCode === 0;\n } catch (error) {\n return false;\n }\n },\n\n remove: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['rm', '-rf', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`rm failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n // Provider-specific typed getInstance method\n getInstance: (sandbox: ModalSandbox): ModalSandbox => {\n return sandbox;\n },\n\n }\n }\n});"],"mappings":"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","names":["process"]}
package/dist/index.mjs CHANGED
@@ -33,7 +33,7 @@ var modal = createProvider({
33
33
  sandboxId = options.sandboxId;
34
34
  } else {
35
35
  const app = await App.lookup("computesdk-modal", { createIfMissing: true });
36
- const image = await app.imageFromRegistry("node:20-alpine");
36
+ const image = await app.imageFromRegistry("node:20");
37
37
  const sandboxOptions = {};
38
38
  if (config.ports && config.ports.length > 0) {
39
39
  sandboxOptions.unencryptedPorts = config.ports;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Modal Provider - Factory-based Implementation\n * \n * Full-featured provider with serverless sandbox execution using the factory pattern.\n * Leverages Modal's JavaScript SDK for real sandbox management.\n * \n * Note: Modal's JavaScript SDK is in alpha. This implementation provides a working\n * foundation but may need updates as the Modal API evolves.\n */\n\nimport { createProvider } from 'computesdk';\nimport type {\n CodeResult,\n CommandResult,\n SandboxInfo,\n Runtime,\n CreateSandboxOptions,\n FileEntry\n} from 'computesdk';\n\n// Import Modal SDK\nimport { App, Sandbox, initializeClient } from 'modal';\n\n/**\n * Modal-specific configuration options\n */\nexport interface ModalConfig {\n /** Modal API token ID - if not provided, will fallback to MODAL_TOKEN_ID environment variable */\n tokenId?: string;\n /** Modal API token secret - if not provided, will fallback to MODAL_TOKEN_SECRET environment variable */\n tokenSecret?: string;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Modal environment (sandbox or main) */\n environment?: string;\n /** Ports to expose */\n ports?: number[];\n}\n\n/**\n * Modal sandbox interface - wraps Modal's Sandbox class\n */\ninterface ModalSandbox {\n sandbox: any; // Modal Sandbox instance (using any due to alpha SDK)\n sandboxId: string;\n}\n\n/**\n * Detect runtime from code content\n */\nfunction detectRuntime(code: string): Runtime {\n // Strong Node.js indicators\n if (code.includes('console.log') || \n code.includes('process.') ||\n code.includes('require(') ||\n code.includes('module.exports') ||\n code.includes('__dirname') ||\n code.includes('__filename') ||\n code.includes('throw new Error') || // JavaScript error throwing\n code.includes('new Error(')) {\n return 'node';\n }\n\n // Strong Python indicators\n if (code.includes('print(') ||\n code.includes('import ') ||\n code.includes('def ') ||\n code.includes('sys.') ||\n code.includes('json.') ||\n code.includes('f\"') ||\n code.includes(\"f'\") ||\n code.includes('raise ')) {\n return 'python';\n }\n\n // Default to Node.js for Modal (now using Node.js base image)\n return 'node';\n}\n\n/**\n * Create a Modal provider instance using the factory pattern\n */\nexport const modal = createProvider<ModalSandbox, ModalConfig>({\n name: 'modal',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: ModalConfig, options?: CreateSandboxOptions) => {\n // Validate API credentials\n const tokenId = config.tokenId || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_ID) || '';\n const tokenSecret = config.tokenSecret || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_SECRET) || '';\n\n if (!tokenId || !tokenSecret) {\n throw new Error(\n `Missing Modal API credentials. Provide 'tokenId' and 'tokenSecret' in config or set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n\n try {\n // Initialize Modal client with credentials\n initializeClient({ tokenId, tokenSecret });\n\n let sandbox: any;\n let sandboxId: string;\n\n if (options?.sandboxId) {\n // Reconnect to existing Modal sandbox\n sandbox = await Sandbox.fromId(options.sandboxId);\n sandboxId = options.sandboxId;\n } else {\n // Create new Modal sandbox with Node.js (more appropriate for a Node.js SDK)\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const image = await app.imageFromRegistry('node:20-alpine');\n \n // Configure sandbox options\n const sandboxOptions: any = {}; // Using 'any' since Modal SDK is alpha\n \n // Configure ports if provided (using unencrypted ports by default)\n if (config.ports && config.ports.length > 0) {\n sandboxOptions.unencryptedPorts = config.ports;\n }\n \n // Add timeout if specified\n if (config.timeout) {\n sandboxOptions.timeout = config.timeout;\n }\n \n sandbox = await app.createSandbox(image, sandboxOptions);\n sandboxId = sandbox.sandboxId;\n }\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('credentials')) {\n throw new Error(\n `Modal authentication failed. Please check your MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `Modal quota exceeded. Please check your usage at https://modal.com/`\n );\n }\n }\n throw new Error(\n `Failed to create Modal sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: ModalConfig, sandboxId: string) => {\n const tokenId = config.tokenId || process.env.MODAL_TOKEN_ID!;\n const tokenSecret = config.tokenSecret || process.env.MODAL_TOKEN_SECRET!;\n\n try {\n initializeClient({ tokenId, tokenSecret });\n const sandbox = await Sandbox.fromId(sandboxId);\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\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: ModalConfig) => {\n throw new Error(\n `Modal provider does not support listing sandboxes. Modal sandboxes are managed individually through the Modal console. Use getById to reconnect to specific sandboxes by ID.`\n );\n },\n\n destroy: async (_config: ModalConfig, sandboxId: string) => {\n try {\n const sandbox = await Sandbox.fromId(sandboxId);\n if (sandbox && typeof sandbox.terminate === 'function') {\n await sandbox.terminate();\n }\n } catch (error) {\n // Sandbox might already be terminated or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (modalSandbox: ModalSandbox, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const startTime = Date.now();\n\n try {\n // Auto-detect runtime from code if not specified\n const detectedRuntime = runtime || detectRuntime(code);\n\n // Create appropriate sandbox and command for the runtime\n let executionSandbox = modalSandbox.sandbox;\n let command: string[];\n let shouldCleanupSandbox = false;\n\n if (detectedRuntime === 'node') {\n // Use existing Node.js sandbox (now the default)\n command = ['node', '-e', code];\n } else {\n // For Python execution, create a Python sandbox dynamically\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const pythonImage = await app.imageFromRegistry('python:3.13-slim');\n executionSandbox = await app.createSandbox(pythonImage);\n command = ['python3', '-c', code];\n shouldCleanupSandbox = true; // Clean up temporary Python sandbox\n }\n\n const process = await executionSandbox.exec(command, {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n // Clean up temporary Python sandbox if created\n if (shouldCleanupSandbox && executionSandbox !== modalSandbox.sandbox) {\n try {\n await executionSandbox.terminate();\n } catch (e) {\n // Ignore cleanup errors\n }\n }\n\n // Check for syntax errors in stderr\n if (exitCode !== 0 && stderr && (\n stderr.includes('SyntaxError') ||\n stderr.includes('invalid syntax')\n )) {\n throw new Error(`Syntax error: ${stderr.trim()}`);\n }\n\n return {\n output: (stdout || '') + (stderr || ''),\n exitCode: exitCode || 0,\n language: detectedRuntime,\n };\n } catch (error) {\n // Handle syntax errors and runtime errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error; // Re-throw syntax errors\n }\n\n throw new Error(\n `Modal execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (modalSandbox: ModalSandbox, command: string, args: string[] = []): Promise<CommandResult> => {\n const startTime = Date.now();\n\n try {\n // Execute command using Modal's exec method with working pattern\n const process = await modalSandbox.sandbox.exec([command, ...args], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n return {\n stdout: stdout || '',\n stderr: stderr || '',\n exitCode: 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 (modalSandbox: ModalSandbox): Promise<SandboxInfo> => {\n // Get actual sandbox status using Modal's poll method\n let status: 'running' | 'stopped' | 'error' = 'running';\n try {\n const pollResult = await modalSandbox.sandbox.poll();\n if (pollResult !== null) {\n // Sandbox has finished\n status = pollResult === 0 ? 'stopped' : 'error';\n }\n } catch (error) {\n // If polling fails, assume running\n status = 'running';\n }\n\n return {\n id: modalSandbox.sandboxId,\n provider: 'modal',\n runtime: 'node', // Modal default (now using Node.js)\n status,\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n modalSandboxId: modalSandbox.sandboxId,\n realModalImplementation: true\n }\n };\n },\n\n getUrl: async (modalSandbox: ModalSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n // Use Modal's built-in tunnels method to get tunnel information\n const tunnels = await modalSandbox.sandbox.tunnels();\n const tunnel = tunnels[options.port];\n \n if (!tunnel) {\n throw new Error(`No tunnel found for port ${options.port}. Available ports: ${Object.keys(tunnels).join(', ')}`);\n }\n \n let url = tunnel.url;\n \n // If a specific protocol is requested, replace the URL's protocol\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to get Modal tunnel URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n // Optional filesystem methods - Modal supports filesystem operations\n filesystem: {\n readFile: async (modalSandbox: ModalSandbox, path: string): Promise<string> => {\n try {\n // Use Modal's file open API to read files\n const file = await modalSandbox.sandbox.open(path);\n \n // Read the entire file content\n let content = '';\n if (file && typeof file.read === 'function') {\n const data = await file.read();\n content = typeof data === 'string' ? data : new TextDecoder().decode(data);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n \n return content;\n } catch (error) {\n // Fallback to using cat command with working stream pattern\n try {\n const process = await modalSandbox.sandbox.exec(['cat', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [content, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`cat failed: ${stderr}`);\n }\n\n return content.trim(); // Remove extra newlines\n } catch (fallbackError) {\n throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n writeFile: async (modalSandbox: ModalSandbox, path: string, content: string): Promise<void> => {\n try {\n // Use Modal's file open API to write files\n const file = await modalSandbox.sandbox.open(path);\n \n // Write content to the file\n if (file && typeof file.write === 'function') {\n await file.write(content);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n } catch (error) {\n // Fallback to using shell command with proper escaping\n try {\n const process = await modalSandbox.sandbox.exec(['sh', '-c', `printf '%s' \"${content.replace(/\"/g, '\\\\\"')}\" > \"${path}\"`], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`write failed: ${stderr}`);\n }\n } catch (fallbackError) {\n throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n mkdir: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['mkdir', '-p', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`mkdir failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n readdir: async (modalSandbox: ModalSandbox, path: string): Promise<FileEntry[]> => {\n try {\n // Use simple -l flag for BusyBox compatibility (Alpine/node:20-alpine uses BusyBox ls)\n const process = await modalSandbox.sandbox.exec(['ls', '-la', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [output, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`ls failed: ${stderr}`);\n }\n\n const lines = output.split('\\n').slice(1); // Skip header\n\n return lines\n .filter((line: string) => line.trim())\n .map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const permissions = parts[0] || '';\n const size = parseInt(parts[4]) || 0;\n const dateStr = (parts[5] || '') + ' ' + (parts[6] || '');\n const date = dateStr.trim() ? new Date(dateStr) : new Date();\n const name = parts.slice(8).join(' ') || parts[parts.length - 1] || 'unknown';\n\n return {\n name,\n path: `${path}/${name}`.replace('//', '/'),\n isDirectory: permissions.startsWith('d'),\n size,\n lastModified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n } catch (error) {\n throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n exists: async (modalSandbox: ModalSandbox, path: string): Promise<boolean> => {\n try {\n const process = await modalSandbox.sandbox.exec(['test', '-e', path]);\n const exitCode = await process.wait();\n return exitCode === 0;\n } catch (error) {\n return false;\n }\n },\n\n remove: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['rm', '-rf', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`rm failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n // Provider-specific typed getInstance method\n getInstance: (sandbox: ModalSandbox): ModalSandbox => {\n return sandbox;\n },\n\n }\n }\n});"],"mappings":"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","names":["process"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Modal Provider - Factory-based Implementation\n * \n * Full-featured provider with serverless sandbox execution using the factory pattern.\n * Leverages Modal's JavaScript SDK for real sandbox management.\n * \n * Note: Modal's JavaScript SDK is in alpha. This implementation provides a working\n * foundation but may need updates as the Modal API evolves.\n */\n\nimport { createProvider } from 'computesdk';\nimport type {\n CodeResult,\n CommandResult,\n SandboxInfo,\n Runtime,\n CreateSandboxOptions,\n FileEntry\n} from 'computesdk';\n\n// Import Modal SDK\nimport { App, Sandbox, initializeClient } from 'modal';\n\n/**\n * Modal-specific configuration options\n */\nexport interface ModalConfig {\n /** Modal API token ID - if not provided, will fallback to MODAL_TOKEN_ID environment variable */\n tokenId?: string;\n /** Modal API token secret - if not provided, will fallback to MODAL_TOKEN_SECRET environment variable */\n tokenSecret?: string;\n /** Default runtime environment */\n runtime?: Runtime;\n /** Execution timeout in milliseconds */\n timeout?: number;\n /** Modal environment (sandbox or main) */\n environment?: string;\n /** Ports to expose */\n ports?: number[];\n}\n\n/**\n * Modal sandbox interface - wraps Modal's Sandbox class\n */\ninterface ModalSandbox {\n sandbox: any; // Modal Sandbox instance (using any due to alpha SDK)\n sandboxId: string;\n}\n\n/**\n * Detect runtime from code content\n */\nfunction detectRuntime(code: string): Runtime {\n // Strong Node.js indicators\n if (code.includes('console.log') || \n code.includes('process.') ||\n code.includes('require(') ||\n code.includes('module.exports') ||\n code.includes('__dirname') ||\n code.includes('__filename') ||\n code.includes('throw new Error') || // JavaScript error throwing\n code.includes('new Error(')) {\n return 'node';\n }\n\n // Strong Python indicators\n if (code.includes('print(') ||\n code.includes('import ') ||\n code.includes('def ') ||\n code.includes('sys.') ||\n code.includes('json.') ||\n code.includes('f\"') ||\n code.includes(\"f'\") ||\n code.includes('raise ')) {\n return 'python';\n }\n\n // Default to Node.js for Modal (now using Node.js base image)\n return 'node';\n}\n\n/**\n * Create a Modal provider instance using the factory pattern\n */\nexport const modal = createProvider<ModalSandbox, ModalConfig>({\n name: 'modal',\n methods: {\n sandbox: {\n // Collection operations (map to compute.sandbox.*)\n create: async (config: ModalConfig, options?: CreateSandboxOptions) => {\n // Validate API credentials\n const tokenId = config.tokenId || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_ID) || '';\n const tokenSecret = config.tokenSecret || (typeof process !== 'undefined' && process.env?.MODAL_TOKEN_SECRET) || '';\n\n if (!tokenId || !tokenSecret) {\n throw new Error(\n `Missing Modal API credentials. Provide 'tokenId' and 'tokenSecret' in config or set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n\n try {\n // Initialize Modal client with credentials\n initializeClient({ tokenId, tokenSecret });\n\n let sandbox: any;\n let sandboxId: string;\n\n if (options?.sandboxId) {\n // Reconnect to existing Modal sandbox\n sandbox = await Sandbox.fromId(options.sandboxId);\n sandboxId = options.sandboxId;\n } else {\n // Create new Modal sandbox with Node.js (more appropriate for a Node.js SDK)\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const image = await app.imageFromRegistry('node:20');\n \n // Configure sandbox options\n const sandboxOptions: any = {}; // Using 'any' since Modal SDK is alpha\n \n // Configure ports if provided (using unencrypted ports by default)\n if (config.ports && config.ports.length > 0) {\n sandboxOptions.unencryptedPorts = config.ports;\n }\n \n // Add timeout if specified\n if (config.timeout) {\n sandboxOptions.timeout = config.timeout;\n }\n \n sandbox = await app.createSandbox(image, sandboxOptions);\n sandboxId = sandbox.sandboxId;\n }\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\n sandboxId\n };\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('unauthorized') || error.message.includes('credentials')) {\n throw new Error(\n `Modal authentication failed. Please check your MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables. Get your credentials from https://modal.com/`\n );\n }\n if (error.message.includes('quota') || error.message.includes('limit')) {\n throw new Error(\n `Modal quota exceeded. Please check your usage at https://modal.com/`\n );\n }\n }\n throw new Error(\n `Failed to create Modal sandbox: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: ModalConfig, sandboxId: string) => {\n const tokenId = config.tokenId || process.env.MODAL_TOKEN_ID!;\n const tokenSecret = config.tokenSecret || process.env.MODAL_TOKEN_SECRET!;\n\n try {\n initializeClient({ tokenId, tokenSecret });\n const sandbox = await Sandbox.fromId(sandboxId);\n\n const modalSandbox: ModalSandbox = {\n sandbox,\n sandboxId\n };\n\n return {\n sandbox: modalSandbox,\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: ModalConfig) => {\n throw new Error(\n `Modal provider does not support listing sandboxes. Modal sandboxes are managed individually through the Modal console. Use getById to reconnect to specific sandboxes by ID.`\n );\n },\n\n destroy: async (_config: ModalConfig, sandboxId: string) => {\n try {\n const sandbox = await Sandbox.fromId(sandboxId);\n if (sandbox && typeof sandbox.terminate === 'function') {\n await sandbox.terminate();\n }\n } catch (error) {\n // Sandbox might already be terminated or doesn't exist\n // This is acceptable for destroy operations\n }\n },\n\n // Instance operations (map to individual Sandbox methods)\n runCode: async (modalSandbox: ModalSandbox, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const startTime = Date.now();\n\n try {\n // Auto-detect runtime from code if not specified\n const detectedRuntime = runtime || detectRuntime(code);\n\n // Create appropriate sandbox and command for the runtime\n let executionSandbox = modalSandbox.sandbox;\n let command: string[];\n let shouldCleanupSandbox = false;\n\n if (detectedRuntime === 'node') {\n // Use existing Node.js sandbox (now the default)\n command = ['node', '-e', code];\n } else {\n // For Python execution, create a Python sandbox dynamically\n const app = await App.lookup('computesdk-modal', { createIfMissing: true });\n const pythonImage = await app.imageFromRegistry('python:3.13-slim');\n executionSandbox = await app.createSandbox(pythonImage);\n command = ['python3', '-c', code];\n shouldCleanupSandbox = true; // Clean up temporary Python sandbox\n }\n\n const process = await executionSandbox.exec(command, {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n // Clean up temporary Python sandbox if created\n if (shouldCleanupSandbox && executionSandbox !== modalSandbox.sandbox) {\n try {\n await executionSandbox.terminate();\n } catch (e) {\n // Ignore cleanup errors\n }\n }\n\n // Check for syntax errors in stderr\n if (exitCode !== 0 && stderr && (\n stderr.includes('SyntaxError') ||\n stderr.includes('invalid syntax')\n )) {\n throw new Error(`Syntax error: ${stderr.trim()}`);\n }\n\n return {\n output: (stdout || '') + (stderr || ''),\n exitCode: exitCode || 0,\n language: detectedRuntime,\n };\n } catch (error) {\n // Handle syntax errors and runtime errors\n if (error instanceof Error && error.message.includes('Syntax error')) {\n throw error; // Re-throw syntax errors\n }\n\n throw new Error(\n `Modal execution failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n runCommand: async (modalSandbox: ModalSandbox, command: string, args: string[] = []): Promise<CommandResult> => {\n const startTime = Date.now();\n\n try {\n // Execute command using Modal's exec method with working pattern\n const process = await modalSandbox.sandbox.exec([command, ...args], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n // Use working stream reading pattern from debug\n const [stdout, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n return {\n stdout: stdout || '',\n stderr: stderr || '',\n exitCode: 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 (modalSandbox: ModalSandbox): Promise<SandboxInfo> => {\n // Get actual sandbox status using Modal's poll method\n let status: 'running' | 'stopped' | 'error' = 'running';\n try {\n const pollResult = await modalSandbox.sandbox.poll();\n if (pollResult !== null) {\n // Sandbox has finished\n status = pollResult === 0 ? 'stopped' : 'error';\n }\n } catch (error) {\n // If polling fails, assume running\n status = 'running';\n }\n\n return {\n id: modalSandbox.sandboxId,\n provider: 'modal',\n runtime: 'node', // Modal default (now using Node.js)\n status,\n createdAt: new Date(),\n timeout: 300000,\n metadata: {\n modalSandboxId: modalSandbox.sandboxId,\n realModalImplementation: true\n }\n };\n },\n\n getUrl: async (modalSandbox: ModalSandbox, options: { port: number; protocol?: string }): Promise<string> => {\n try {\n // Use Modal's built-in tunnels method to get tunnel information\n const tunnels = await modalSandbox.sandbox.tunnels();\n const tunnel = tunnels[options.port];\n \n if (!tunnel) {\n throw new Error(`No tunnel found for port ${options.port}. Available ports: ${Object.keys(tunnels).join(', ')}`);\n }\n \n let url = tunnel.url;\n \n // If a specific protocol is requested, replace the URL's protocol\n if (options.protocol) {\n const urlObj = new URL(url);\n urlObj.protocol = options.protocol + ':';\n url = urlObj.toString();\n }\n \n return url;\n } catch (error) {\n throw new Error(\n `Failed to get Modal tunnel URL for port ${options.port}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n // Optional filesystem methods - Modal supports filesystem operations\n filesystem: {\n readFile: async (modalSandbox: ModalSandbox, path: string): Promise<string> => {\n try {\n // Use Modal's file open API to read files\n const file = await modalSandbox.sandbox.open(path);\n \n // Read the entire file content\n let content = '';\n if (file && typeof file.read === 'function') {\n const data = await file.read();\n content = typeof data === 'string' ? data : new TextDecoder().decode(data);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n \n return content;\n } catch (error) {\n // Fallback to using cat command with working stream pattern\n try {\n const process = await modalSandbox.sandbox.exec(['cat', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [content, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`cat failed: ${stderr}`);\n }\n\n return content.trim(); // Remove extra newlines\n } catch (fallbackError) {\n throw new Error(`Failed to read file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n writeFile: async (modalSandbox: ModalSandbox, path: string, content: string): Promise<void> => {\n try {\n // Use Modal's file open API to write files\n const file = await modalSandbox.sandbox.open(path);\n \n // Write content to the file\n if (file && typeof file.write === 'function') {\n await file.write(content);\n }\n \n // Close the file if it has a close method\n if (file && typeof file.close === 'function') {\n await file.close();\n }\n } catch (error) {\n // Fallback to using shell command with proper escaping\n try {\n const process = await modalSandbox.sandbox.exec(['sh', '-c', `printf '%s' \"${content.replace(/\"/g, '\\\\\"')}\" > \"${path}\"`], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`write failed: ${stderr}`);\n }\n } catch (fallbackError) {\n throw new Error(`Failed to write file ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n mkdir: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['mkdir', '-p', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`mkdir failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to create directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n readdir: async (modalSandbox: ModalSandbox, path: string): Promise<FileEntry[]> => {\n try {\n // Use simple -l flag for BusyBox compatibility (Alpine/node:20-alpine uses BusyBox ls)\n const process = await modalSandbox.sandbox.exec(['ls', '-la', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [output, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`ls failed: ${stderr}`);\n }\n\n const lines = output.split('\\n').slice(1); // Skip header\n\n return lines\n .filter((line: string) => line.trim())\n .map((line: string) => {\n const parts = line.trim().split(/\\s+/);\n const permissions = parts[0] || '';\n const size = parseInt(parts[4]) || 0;\n const dateStr = (parts[5] || '') + ' ' + (parts[6] || '');\n const date = dateStr.trim() ? new Date(dateStr) : new Date();\n const name = parts.slice(8).join(' ') || parts[parts.length - 1] || 'unknown';\n\n return {\n name,\n path: `${path}/${name}`.replace('//', '/'),\n isDirectory: permissions.startsWith('d'),\n size,\n lastModified: isNaN(date.getTime()) ? new Date() : date\n };\n });\n } catch (error) {\n throw new Error(`Failed to read directory ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n exists: async (modalSandbox: ModalSandbox, path: string): Promise<boolean> => {\n try {\n const process = await modalSandbox.sandbox.exec(['test', '-e', path]);\n const exitCode = await process.wait();\n return exitCode === 0;\n } catch (error) {\n return false;\n }\n },\n\n remove: async (modalSandbox: ModalSandbox, path: string): Promise<void> => {\n try {\n const process = await modalSandbox.sandbox.exec(['rm', '-rf', path], {\n stdout: 'pipe',\n stderr: 'pipe'\n });\n\n const [, stderr] = await Promise.all([\n process.stdout.readText(),\n process.stderr.readText()\n ]);\n\n const exitCode = await process.wait();\n\n if (exitCode !== 0) {\n throw new Error(`rm failed: ${stderr}`);\n }\n } catch (error) {\n throw new Error(`Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n },\n\n // Provider-specific typed getInstance method\n getInstance: (sandbox: ModalSandbox): ModalSandbox => {\n return sandbox;\n },\n\n }\n }\n});"],"mappings":";AAUA,SAAS,sBAAsB;AAW/B,SAAS,KAAK,SAAS,wBAAwB;AA+B/C,SAAS,cAAc,MAAuB;AAE5C,MAAI,KAAK,SAAS,aAAa,KAC3B,KAAK,SAAS,UAAU,KACxB,KAAK,SAAS,UAAU,KACxB,KAAK,SAAS,gBAAgB,KAC9B,KAAK,SAAS,WAAW,KACzB,KAAK,SAAS,YAAY,KAC1B,KAAK,SAAS,iBAAiB;AAAA,EAC/B,KAAK,SAAS,YAAY,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,SAAS,QAAQ,KACtB,KAAK,SAAS,SAAS,KACvB,KAAK,SAAS,MAAM,KACpB,KAAK,SAAS,MAAM,KACpB,KAAK,SAAS,OAAO,KACrB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,IAAI,KAClB,KAAK,SAAS,QAAQ,GAAG;AAC3B,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAKO,IAAM,QAAQ,eAA0C;AAAA,EAC7D,MAAM;AAAA,EACN,SAAS;AAAA,IACP,SAAS;AAAA;AAAA,MAEP,QAAQ,OAAO,QAAqB,YAAmC;AAErE,cAAM,UAAU,OAAO,WAAY,OAAO,YAAY,eAAe,QAAQ,KAAK,kBAAmB;AACrG,cAAM,cAAc,OAAO,eAAgB,OAAO,YAAY,eAAe,QAAQ,KAAK,sBAAuB;AAEjH,YAAI,CAAC,WAAW,CAAC,aAAa;AAC5B,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,YAAI;AAEF,2BAAiB,EAAE,SAAS,YAAY,CAAC;AAEzC,cAAI;AACJ,cAAI;AAEJ,cAAI,SAAS,WAAW;AAEtB,sBAAU,MAAM,QAAQ,OAAO,QAAQ,SAAS;AAChD,wBAAY,QAAQ;AAAA,UACtB,OAAO;AAEL,kBAAM,MAAM,MAAM,IAAI,OAAO,oBAAoB,EAAE,iBAAiB,KAAK,CAAC;AAC1E,kBAAM,QAAQ,MAAM,IAAI,kBAAkB,SAAS;AAGnD,kBAAM,iBAAsB,CAAC;AAG7B,gBAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,6BAAe,mBAAmB,OAAO;AAAA,YAC3C;AAGA,gBAAI,OAAO,SAAS;AAClB,6BAAe,UAAU,OAAO;AAAA,YAClC;AAEA,sBAAU,MAAM,IAAI,cAAc,OAAO,cAAc;AACvD,wBAAY,QAAQ;AAAA,UACtB;AAEA,gBAAM,eAA6B;AAAA,YACjC;AAAA,YACA;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,SAAS;AAAA,YACT;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AACd,cAAI,iBAAiB,OAAO;AAC1B,gBAAI,MAAM,QAAQ,SAAS,cAAc,KAAK,MAAM,QAAQ,SAAS,aAAa,GAAG;AACnF,oBAAM,IAAI;AAAA,gBACR;AAAA,cACF;AAAA,YACF;AACA,gBAAI,MAAM,QAAQ,SAAS,OAAO,KAAK,MAAM,QAAQ,SAAS,OAAO,GAAG;AACtE,oBAAM,IAAI;AAAA,gBACR;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA,gBAAM,IAAI;AAAA,YACR,mCAAmC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UAC3F;AAAA,QACF;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,QAAqB,cAAsB;AACzD,cAAM,UAAU,OAAO,WAAW,QAAQ,IAAI;AAC9C,cAAM,cAAc,OAAO,eAAe,QAAQ,IAAI;AAEtD,YAAI;AACF,2BAAiB,EAAE,SAAS,YAAY,CAAC;AACzC,gBAAM,UAAU,MAAM,QAAQ,OAAO,SAAS;AAE9C,gBAAM,eAA6B;AAAA,YACjC;AAAA,YACA;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,SAAS;AAAA,YACT;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AAEd,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,YAAyB;AACpC,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,SAAsB,cAAsB;AAC1D,YAAI;AACF,gBAAM,UAAU,MAAM,QAAQ,OAAO,SAAS;AAC9C,cAAI,WAAW,OAAO,QAAQ,cAAc,YAAY;AACtD,kBAAM,QAAQ,UAAU;AAAA,UAC1B;AAAA,QACF,SAAS,OAAO;AAAA,QAGhB;AAAA,MACF;AAAA;AAAA,MAGA,SAAS,OAAO,cAA4B,MAAc,YAA2C;AACnG,cAAM,YAAY,KAAK,IAAI;AAE3B,YAAI;AAEF,gBAAM,kBAAkB,WAAW,cAAc,IAAI;AAGrD,cAAI,mBAAmB,aAAa;AACpC,cAAI;AACJ,cAAI,uBAAuB;AAE3B,cAAI,oBAAoB,QAAQ;AAE9B,sBAAU,CAAC,QAAQ,MAAM,IAAI;AAAA,UAC/B,OAAO;AAEL,kBAAM,MAAM,MAAM,IAAI,OAAO,oBAAoB,EAAE,iBAAiB,KAAK,CAAC;AAC1E,kBAAM,cAAc,MAAM,IAAI,kBAAkB,kBAAkB;AAClE,+BAAmB,MAAM,IAAI,cAAc,WAAW;AACtD,sBAAU,CAAC,WAAW,MAAM,IAAI;AAChC,mCAAuB;AAAA,UACzB;AAEA,gBAAMA,WAAU,MAAM,iBAAiB,KAAK,SAAS;AAAA,YACnD,QAAQ;AAAA,YACR,QAAQ;AAAA,UACV,CAAC;AAGD,gBAAM,CAAC,QAAQ,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,YACzCA,SAAQ,OAAO,SAAS;AAAA,YACxBA,SAAQ,OAAO,SAAS;AAAA,UAC1B,CAAC;AAED,gBAAM,WAAW,MAAMA,SAAQ,KAAK;AAGpC,cAAI,wBAAwB,qBAAqB,aAAa,SAAS;AACrE,gBAAI;AACF,oBAAM,iBAAiB,UAAU;AAAA,YACnC,SAAS,GAAG;AAAA,YAEZ;AAAA,UACF;AAGA,cAAI,aAAa,KAAK,WACpB,OAAO,SAAS,aAAa,KAC7B,OAAO,SAAS,gBAAgB,IAC/B;AACD,kBAAM,IAAI,MAAM,iBAAiB,OAAO,KAAK,CAAC,EAAE;AAAA,UAClD;AAEA,iBAAO;AAAA,YACL,SAAS,UAAU,OAAO,UAAU;AAAA,YACpC,UAAU,YAAY;AAAA,YACtB,UAAU;AAAA,UACZ;AAAA,QACF,SAAS,OAAO;AAEd,cAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,cAAc,GAAG;AACpE,kBAAM;AAAA,UACR;AAEA,gBAAM,IAAI;AAAA,YACR,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACnF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,YAAY,OAAO,cAA4B,SAAiB,OAAiB,CAAC,MAA8B;AAC9G,cAAM,YAAY,KAAK,IAAI;AAE3B,YAAI;AAEF,gBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,SAAS,GAAG,IAAI,GAAG;AAAA,YAClE,QAAQ;AAAA,YACR,QAAQ;AAAA,UACV,CAAC;AAGD,gBAAM,CAAC,QAAQ,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,YACzCA,SAAQ,OAAO,SAAS;AAAA,YACxBA,SAAQ,OAAO,SAAS;AAAA,UAC1B,CAAC;AAED,gBAAM,WAAW,MAAMA,SAAQ,KAAK;AAEpC,iBAAO;AAAA,YACL,QAAQ,UAAU;AAAA,YAClB,QAAQ,UAAU;AAAA,YAClB,UAAU,YAAY;AAAA,YACtB,YAAY,KAAK,IAAI,IAAI;AAAA,UAC3B;AAAA,QACF,SAAS,OAAO;AACd,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC7D,UAAU;AAAA,YACV,YAAY,KAAK,IAAI,IAAI;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,iBAAqD;AAEnE,YAAI,SAA0C;AAC9C,YAAI;AACF,gBAAM,aAAa,MAAM,aAAa,QAAQ,KAAK;AACnD,cAAI,eAAe,MAAM;AAEvB,qBAAS,eAAe,IAAI,YAAY;AAAA,UAC1C;AAAA,QACF,SAAS,OAAO;AAEd,mBAAS;AAAA,QACX;AAEA,eAAO;AAAA,UACL,IAAI,aAAa;AAAA,UACjB,UAAU;AAAA,UACV,SAAS;AAAA;AAAA,UACT;AAAA,UACA,WAAW,oBAAI,KAAK;AAAA,UACpB,SAAS;AAAA,UACT,UAAU;AAAA,YACR,gBAAgB,aAAa;AAAA,YAC7B,yBAAyB;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MAEA,QAAQ,OAAO,cAA4B,YAAkE;AAC3G,YAAI;AAEF,gBAAM,UAAU,MAAM,aAAa,QAAQ,QAAQ;AACnD,gBAAM,SAAS,QAAQ,QAAQ,IAAI;AAEnC,cAAI,CAAC,QAAQ;AACX,kBAAM,IAAI,MAAM,4BAA4B,QAAQ,IAAI,sBAAsB,OAAO,KAAK,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,UACjH;AAEA,cAAI,MAAM,OAAO;AAGjB,cAAI,QAAQ,UAAU;AACpB,kBAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,mBAAO,WAAW,QAAQ,WAAW;AACrC,kBAAM,OAAO,SAAS;AAAA,UACxB;AAEA,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,IAAI;AAAA,YACR,2CAA2C,QAAQ,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACpH;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,YAAY;AAAA,QACV,UAAU,OAAO,cAA4B,SAAkC;AAC7E,cAAI;AAEF,kBAAM,OAAO,MAAM,aAAa,QAAQ,KAAK,IAAI;AAGjD,gBAAI,UAAU;AACd,gBAAI,QAAQ,OAAO,KAAK,SAAS,YAAY;AAC3C,oBAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,wBAAU,OAAO,SAAS,WAAW,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA,YAC3E;AAGA,gBAAI,QAAQ,OAAO,KAAK,UAAU,YAAY;AAC5C,oBAAM,KAAK,MAAM;AAAA,YACnB;AAEA,mBAAO;AAAA,UACT,SAAS,OAAO;AAEd,gBAAI;AACF,oBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,OAAO,IAAI,GAAG;AAAA,gBAC7D,QAAQ;AAAA,gBACR,QAAQ;AAAA,cACV,CAAC;AAED,oBAAM,CAAC,SAAS,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,gBAC1CA,SAAQ,OAAO,SAAS;AAAA,gBACxBA,SAAQ,OAAO,SAAS;AAAA,cAC1B,CAAC;AAED,oBAAM,WAAW,MAAMA,SAAQ,KAAK;AAEpC,kBAAI,aAAa,GAAG;AAClB,sBAAM,IAAI,MAAM,eAAe,MAAM,EAAE;AAAA,cACzC;AAEA,qBAAO,QAAQ,KAAK;AAAA,YACtB,SAAS,eAAe;AACtB,oBAAM,IAAI,MAAM,uBAAuB,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,YAC1G;AAAA,UACF;AAAA,QACF;AAAA,QAEA,WAAW,OAAO,cAA4B,MAAc,YAAmC;AAC7F,cAAI;AAEF,kBAAM,OAAO,MAAM,aAAa,QAAQ,KAAK,IAAI;AAGjD,gBAAI,QAAQ,OAAO,KAAK,UAAU,YAAY;AAC5C,oBAAM,KAAK,MAAM,OAAO;AAAA,YAC1B;AAGA,gBAAI,QAAQ,OAAO,KAAK,UAAU,YAAY;AAC5C,oBAAM,KAAK,MAAM;AAAA,YACnB;AAAA,UACF,SAAS,OAAO;AAEd,gBAAI;AACF,oBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,MAAM,MAAM,gBAAgB,QAAQ,QAAQ,MAAM,KAAK,CAAC,QAAQ,IAAI,GAAG,GAAG;AAAA,gBACzH,QAAQ;AAAA,gBACR,QAAQ;AAAA,cACV,CAAC;AAED,oBAAM,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,gBACnCA,SAAQ,OAAO,SAAS;AAAA,gBACxBA,SAAQ,OAAO,SAAS;AAAA,cAC1B,CAAC;AAED,oBAAM,WAAW,MAAMA,SAAQ,KAAK;AAEpC,kBAAI,aAAa,GAAG;AAClB,sBAAM,IAAI,MAAM,iBAAiB,MAAM,EAAE;AAAA,cAC3C;AAAA,YACF,SAAS,eAAe;AACtB,oBAAM,IAAI,MAAM,wBAAwB,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,YAC3G;AAAA,UACF;AAAA,QACF;AAAA,QAEA,OAAO,OAAO,cAA4B,SAAgC;AACxE,cAAI;AACF,kBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,SAAS,MAAM,IAAI,GAAG;AAAA,cACrE,QAAQ;AAAA,cACR,QAAQ;AAAA,YACV,CAAC;AAED,kBAAM,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,cACnCA,SAAQ,OAAO,SAAS;AAAA,cACxBA,SAAQ,OAAO,SAAS;AAAA,YAC1B,CAAC;AAED,kBAAM,WAAW,MAAMA,SAAQ,KAAK;AAEpC,gBAAI,aAAa,GAAG;AAClB,oBAAM,IAAI,MAAM,iBAAiB,MAAM,EAAE;AAAA,YAC3C;AAAA,UACF,SAAS,OAAO;AACd,kBAAM,IAAI,MAAM,8BAA8B,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,UACjH;AAAA,QACF;AAAA,QAEA,SAAS,OAAO,cAA4B,SAAuC;AACjF,cAAI;AAEF,kBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,MAAM,OAAO,IAAI,GAAG;AAAA,cACnE,QAAQ;AAAA,cACR,QAAQ;AAAA,YACV,CAAC;AAED,kBAAM,CAAC,QAAQ,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,cACzCA,SAAQ,OAAO,SAAS;AAAA,cACxBA,SAAQ,OAAO,SAAS;AAAA,YAC1B,CAAC;AAED,kBAAM,WAAW,MAAMA,SAAQ,KAAK;AAEpC,gBAAI,aAAa,GAAG;AAClB,oBAAM,IAAI,MAAM,cAAc,MAAM,EAAE;AAAA,YACxC;AAEA,kBAAM,QAAQ,OAAO,MAAM,IAAI,EAAE,MAAM,CAAC;AAExC,mBAAO,MACJ,OAAO,CAAC,SAAiB,KAAK,KAAK,CAAC,EACpC,IAAI,CAAC,SAAiB;AACrB,oBAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,oBAAM,cAAc,MAAM,CAAC,KAAK;AAChC,oBAAM,OAAO,SAAS,MAAM,CAAC,CAAC,KAAK;AACnC,oBAAM,WAAW,MAAM,CAAC,KAAK,MAAM,OAAO,MAAM,CAAC,KAAK;AACtD,oBAAM,OAAO,QAAQ,KAAK,IAAI,IAAI,KAAK,OAAO,IAAI,oBAAI,KAAK;AAC3D,oBAAM,OAAO,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,MAAM,MAAM,SAAS,CAAC,KAAK;AAEpE,qBAAO;AAAA,gBACL;AAAA,gBACA,MAAM,GAAG,IAAI,IAAI,IAAI,GAAG,QAAQ,MAAM,GAAG;AAAA,gBACzC,aAAa,YAAY,WAAW,GAAG;AAAA,gBACvC;AAAA,gBACA,cAAc,MAAM,KAAK,QAAQ,CAAC,IAAI,oBAAI,KAAK,IAAI;AAAA,cACrD;AAAA,YACF,CAAC;AAAA,UACL,SAAS,OAAO;AACd,kBAAM,IAAI,MAAM,4BAA4B,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,UAC/G;AAAA,QACF;AAAA,QAEA,QAAQ,OAAO,cAA4B,SAAmC;AAC5E,cAAI;AACF,kBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,QAAQ,MAAM,IAAI,CAAC;AACpE,kBAAM,WAAW,MAAMA,SAAQ,KAAK;AACpC,mBAAO,aAAa;AAAA,UACtB,SAAS,OAAO;AACd,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,QAEA,QAAQ,OAAO,cAA4B,SAAgC;AACzE,cAAI;AACF,kBAAMA,WAAU,MAAM,aAAa,QAAQ,KAAK,CAAC,MAAM,OAAO,IAAI,GAAG;AAAA,cACnE,QAAQ;AAAA,cACR,QAAQ;AAAA,YACV,CAAC;AAED,kBAAM,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,cACnCA,SAAQ,OAAO,SAAS;AAAA,cACxBA,SAAQ,OAAO,SAAS;AAAA,YAC1B,CAAC;AAED,kBAAM,WAAW,MAAMA,SAAQ,KAAK;AAEpC,gBAAI,aAAa,GAAG;AAClB,oBAAM,IAAI,MAAM,cAAc,MAAM,EAAE;AAAA,YACxC;AAAA,UACF,SAAS,OAAO;AACd,kBAAM,IAAI,MAAM,oBAAoB,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,UACvG;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,aAAa,CAAC,YAAwC;AACpD,eAAO;AAAA,MACT;AAAA,IAEF;AAAA,EACF;AACF,CAAC;","names":["process"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@computesdk/modal",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "Modal provider for ComputeSDK - serverless Python execution with GPU support and zero cold starts",
5
5
  "author": "Garrison",
6
6
  "license": "MIT",