@cloudflare/sandbox 0.3.3 → 0.3.5
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/CHANGELOG.md +12 -0
- package/Dockerfile +1 -0
- package/README.md +58 -5
- package/container_src/handler/file.ts +51 -0
- package/container_src/index.ts +8 -0
- package/container_src/isolation.ts +199 -24
- package/dist/{chunk-SMUEY5JR.js → chunk-32UDXUPC.js} +31 -1
- package/dist/chunk-32UDXUPC.js.map +1 -0
- package/dist/chunk-5DILEXGY.js +85 -0
- package/dist/chunk-5DILEXGY.js.map +1 -0
- package/dist/{chunk-Z6OZPC6U.js → chunk-D3U63BZP.js} +2 -2
- package/dist/{chunk-H4PW2LGW.js → chunk-SQLJNZ3K.js} +9 -2
- package/dist/chunk-SQLJNZ3K.js.map +1 -0
- package/dist/{client-COGWU6bz.d.ts → client-B3RUab0s.d.ts} +3 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/file-stream.d.ts +65 -0
- package/dist/file-stream.js +10 -0
- package/dist/file-stream.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +10 -4
- package/dist/interpreter-client.d.ts +1 -1
- package/dist/interpreter-client.js +2 -2
- package/dist/interpreter.d.ts +1 -1
- package/dist/request-handler.d.ts +1 -1
- package/dist/request-handler.js +3 -3
- package/dist/sandbox.d.ts +1 -1
- package/dist/sandbox.js +3 -3
- package/dist/types.d.ts +56 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +39 -0
- package/src/file-stream.ts +162 -0
- package/src/index.ts +6 -0
- package/src/sandbox.ts +11 -2
- package/src/types.ts +69 -0
- package/dist/chunk-H4PW2LGW.js.map +0 -1
- package/dist/chunk-SMUEY5JR.js.map +0 -1
- /package/dist/{chunk-Z6OZPC6U.js.map → chunk-D3U63BZP.js.map} +0 -0
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["// Core Types\n\nexport interface BaseExecOptions {\n /**\n * Maximum execution time in milliseconds\n */\n timeout?: number;\n\n /**\n * Environment variables for the command\n */\n env?: Record<string, string>;\n\n /**\n * Working directory for command execution\n */\n cwd?: string;\n\n /**\n * Text encoding for output (default: 'utf8')\n */\n encoding?: string;\n}\n\nexport interface ExecOptions extends BaseExecOptions {\n /**\n * Enable real-time output streaming via callbacks\n */\n stream?: boolean;\n\n /**\n * Callback for real-time output data\n */\n onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;\n\n /**\n * Callback when command completes (only when stream: true)\n */\n onComplete?: (result: ExecResult) => void;\n\n /**\n * Callback for execution errors\n */\n onError?: (error: Error) => void;\n\n /**\n * AbortSignal for cancelling execution\n */\n signal?: AbortSignal;\n}\n\nexport interface ExecResult {\n /**\n * Whether the command succeeded (exitCode === 0)\n */\n success: boolean;\n\n /**\n * Process exit code\n */\n exitCode: number;\n\n /**\n * Standard output content\n */\n stdout: string;\n\n /**\n * Standard error content\n */\n stderr: string;\n\n /**\n * Command that was executed\n */\n command: string;\n\n\n /**\n * Execution duration in milliseconds\n */\n duration: number;\n\n /**\n * ISO timestamp when command started\n */\n timestamp: string;\n}\n\n// Background Process Types\n\nexport interface ProcessOptions extends BaseExecOptions {\n /**\n * Custom process ID for later reference\n * If not provided, a UUID will be generated\n */\n processId?: string;\n\n /**\n * Automatically cleanup process record after exit (default: true)\n */\n autoCleanup?: boolean;\n\n /**\n * Callback when process exits\n */\n onExit?: (code: number | null) => void;\n\n /**\n * Callback for real-time output (background processes)\n */\n onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;\n\n /**\n * Callback when process starts successfully\n */\n onStart?: (process: Process) => void;\n\n /**\n * Callback for process errors\n */\n onError?: (error: Error) => void;\n}\n\nexport type ProcessStatus =\n | 'starting' // Process is being initialized\n | 'running' // Process is actively running\n | 'completed' // Process exited successfully (code 0)\n | 'failed' // Process exited with non-zero code\n | 'killed' // Process was terminated by signal\n | 'error'; // Process failed to start or encountered error\n\nexport interface Process {\n /**\n * Unique process identifier\n */\n readonly id: string;\n\n /**\n * System process ID (if available and running)\n */\n readonly pid?: number;\n\n /**\n * Command that was executed\n */\n readonly command: string;\n\n\n /**\n * Current process status\n */\n readonly status: ProcessStatus;\n\n /**\n * When the process was started\n */\n readonly startTime: Date;\n\n /**\n * When the process ended (if completed)\n */\n readonly endTime?: Date;\n\n /**\n * Process exit code (if completed)\n */\n readonly exitCode?: number;\n\n /**\n * Kill the process\n */\n kill(signal?: string): Promise<void>;\n\n /**\n * Get current process status (refreshed)\n */\n getStatus(): Promise<ProcessStatus>;\n\n /**\n * Get accumulated logs\n */\n getLogs(): Promise<{ stdout: string; stderr: string }>;\n}\n\n// Streaming Types\n\nexport interface ExecEvent {\n type: 'start' | 'stdout' | 'stderr' | 'complete' | 'error';\n timestamp: string;\n data?: string;\n command?: string;\n exitCode?: number;\n result?: ExecResult;\n error?: string; // Changed to string for serialization\n}\n\nexport interface LogEvent {\n type: 'stdout' | 'stderr' | 'exit' | 'error';\n timestamp: string;\n data: string;\n processId: string;\n exitCode?: number; // For 'exit' events\n}\n\nexport interface StreamOptions extends BaseExecOptions {\n /**\n * Buffer size for streaming output\n */\n bufferSize?: number;\n\n /**\n * AbortSignal for cancelling stream\n */\n signal?: AbortSignal;\n}\n\n// Error Types\n\nexport class SandboxError extends Error {\n constructor(message: string, public code?: string) {\n super(message);\n this.name = 'SandboxError';\n }\n}\n\nexport class ProcessNotFoundError extends SandboxError {\n constructor(processId: string) {\n super(`Process not found: ${processId}`, 'PROCESS_NOT_FOUND');\n this.name = 'ProcessNotFoundError';\n }\n}\n\nexport class ProcessAlreadyExistsError extends SandboxError {\n constructor(processId: string) {\n super(`Process already exists: ${processId}`, 'PROCESS_EXISTS');\n this.name = 'ProcessAlreadyExistsError';\n }\n}\n\nexport class ExecutionTimeoutError extends SandboxError {\n constructor(timeout: number) {\n super(`Execution timed out after ${timeout}ms`, 'EXECUTION_TIMEOUT');\n this.name = 'ExecutionTimeoutError';\n }\n}\n\n// Internal Container Types\n\nexport interface ProcessRecord {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: Date;\n endTime?: Date;\n exitCode?: number;\n\n // Internal fields\n stdout: string; // Accumulated output (ephemeral)\n stderr: string; // Accumulated output (ephemeral)\n\n // Streaming\n outputListeners: Set<(stream: 'stdout' | 'stderr', data: string) => void>;\n statusListeners: Set<(status: ProcessStatus) => void>;\n}\n\n// Container Request/Response Types\n\nexport interface StartProcessRequest {\n command: string;\n options?: {\n processId?: string;\n timeout?: number;\n env?: Record<string, string>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n };\n}\n\nexport interface StartProcessResponse {\n process: {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string;\n endTime?: string | null;\n exitCode?: number | null;\n sessionId: string;\n };\n}\n\nexport interface ListProcessesResponse {\n processes: Array<{\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string;\n endTime?: string;\n exitCode?: number;\n }>;\n}\n\nexport interface GetProcessResponse {\n process: {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string;\n endTime?: string;\n exitCode?: number;\n } | null;\n}\n\nexport interface GetProcessLogsResponse {\n stdout: string;\n stderr: string;\n processId: string;\n}\n\n// Import code interpreter types\nimport type {\n CodeContext,\n CreateContextOptions,\n ExecutionResult, \n RunCodeOptions\n} from './interpreter-types';\n\n// Main Sandbox Interface\n\nexport interface ISandbox {\n // Enhanced execution API\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n\n // Background process management\n startProcess(command: string, options?: ProcessOptions): Promise<Process>;\n listProcesses(): Promise<Process[]>;\n getProcess(id: string): Promise<Process | null>;\n killProcess(id: string, signal?: string): Promise<void>;\n killAllProcesses(): Promise<number>;\n\n // Advanced streaming - returns ReadableStream that can be converted to AsyncIterable\n execStream(command: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>>;\n streamProcessLogs(processId: string, options?: { signal?: AbortSignal }): Promise<ReadableStream<Uint8Array>>;\n\n // Utility methods\n cleanupCompletedProcesses(): Promise<number>;\n getProcessLogs(id: string): Promise<{ stdout: string; stderr: string }>;\n\n // File operations\n gitCheckout(repoUrl: string, options: { branch?: string; targetDir?: string }): Promise<GitCheckoutResponse>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<MkdirResponse>;\n writeFile(path: string, content: string, options?: { encoding?: string }): Promise<WriteFileResponse>;\n deleteFile(path: string): Promise<DeleteFileResponse>;\n renameFile(oldPath: string, newPath: string): Promise<RenameFileResponse>;\n moveFile(sourcePath: string, destinationPath: string): Promise<MoveFileResponse>;\n readFile(path: string, options?: { encoding?: string }): Promise<ReadFileResponse>;\n listFiles(path: string, options?: { recursive?: boolean; includeHidden?: boolean }): Promise<ListFilesResponse>;\n\n // Port management\n exposePort(port: number, options: { name?: string; hostname: string }): Promise<{ url: string; port: number; name?: string }>;\n unexposePort(port: number): Promise<void>;\n getExposedPorts(hostname: string): Promise<Array<{ url: string; port: number; name?: string; exposedAt: string }>>;\n\n // Environment management\n setEnvVars(envVars: Record<string, string>): Promise<void>;\n setSandboxName(name: string): Promise<void>;\n\n // Code Interpreter API\n createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;\n runCode(code: string, options?: RunCodeOptions): Promise<ExecutionResult>;\n runCodeStream(code: string, options?: RunCodeOptions): Promise<ReadableStream>;\n listCodeContexts(): Promise<CodeContext[]>;\n deleteCodeContext(contextId: string): Promise<void>;\n}\n\n// Execution session returned by createSession()\n// Sessions are full-featured sandbox objects with scoped execution context\n// Inherits all ISandbox methods except createSession (sessions can't create sub-sessions),\n// and setSandboxName (sessions inherit sandbox name).\nexport interface ExecutionSession extends Omit<ISandbox, 'createSession' | 'setSandboxName'> {\n /**\n * Session ID\n */\n id: string;\n}\n\n// API Response Types\n\nexport interface ExecuteResponse {\n success: boolean;\n stdout: string;\n stderr: string;\n exitCode: number;\n command: string;\n timestamp: string;\n}\n\nexport interface GitCheckoutResponse {\n success: boolean;\n stdout: string;\n stderr: string;\n exitCode: number;\n repoUrl: string;\n branch: string;\n targetDir: string;\n timestamp: string;\n}\n\nexport interface MkdirResponse {\n success: boolean;\n stdout: string;\n stderr: string;\n exitCode: number;\n path: string;\n recursive: boolean;\n timestamp: string;\n}\n\nexport interface WriteFileResponse {\n success: boolean;\n exitCode: number;\n path: string;\n timestamp: string;\n}\n\nexport interface ReadFileResponse {\n success: boolean;\n exitCode: number;\n path: string;\n content: string;\n timestamp: string;\n}\n\nexport interface DeleteFileResponse {\n success: boolean;\n exitCode: number;\n path: string;\n timestamp: string;\n}\n\nexport interface RenameFileResponse {\n success: boolean;\n exitCode: number;\n oldPath: string;\n newPath: string;\n timestamp: string;\n}\n\nexport interface MoveFileResponse {\n success: boolean;\n exitCode: number;\n sourcePath: string;\n destinationPath: string;\n timestamp: string;\n}\n\nexport interface ListFilesResponse {\n success: boolean;\n exitCode: number;\n path: string;\n files: Array<{\n name: string;\n absolutePath: string;\n relativePath: string;\n type: 'file' | 'directory' | 'symlink' | 'other';\n size: number;\n modifiedAt: string;\n mode: string;\n permissions: {\n readable: boolean;\n writable: boolean;\n executable: boolean;\n };\n }>;\n timestamp: string;\n}\n\n// Type Guards\n\nexport function isExecResult(value: any): value is ExecResult {\n return value &&\n typeof value.success === 'boolean' &&\n typeof value.exitCode === 'number' &&\n typeof value.stdout === 'string' &&\n typeof value.stderr === 'string';\n}\n\nexport function isProcess(value: any): value is Process {\n return value &&\n typeof value.id === 'string' &&\n typeof value.command === 'string' &&\n typeof value.status === 'string';\n}\n\nexport function isProcessStatus(value: string): value is ProcessStatus {\n return ['starting', 'running', 'completed', 'failed', 'killed', 'error'].includes(value);\n}"],"mappings":";AA2NO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YAAY,SAAwB,MAAe;AACjD,UAAM,OAAO;AADqB;AAElC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACrD,YAAY,WAAmB;AAC7B,UAAM,sBAAsB,SAAS,IAAI,mBAAmB;AAC5D,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,4BAAN,cAAwC,aAAa;AAAA,EAC1D,YAAY,WAAmB;AAC7B,UAAM,2BAA2B,SAAS,IAAI,gBAAgB;AAC9D,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EACtD,YAAY,SAAiB;AAC3B,UAAM,6BAA6B,OAAO,MAAM,mBAAmB;AACnE,SAAK,OAAO;AAAA,EACd;AACF;AA+OO,SAAS,aAAa,OAAiC;AAC5D,SAAO,SACL,OAAO,MAAM,YAAY,aACzB,OAAO,MAAM,aAAa,YAC1B,OAAO,MAAM,WAAW,YACxB,OAAO,MAAM,WAAW;AAC5B;AAEO,SAAS,UAAU,OAA8B;AACtD,SAAO,SACL,OAAO,MAAM,OAAO,YACpB,OAAO,MAAM,YAAY,YACzB,OAAO,MAAM,WAAW;AAC5B;AAEO,SAAS,gBAAgB,OAAuC;AACrE,SAAO,CAAC,YAAY,WAAW,aAAa,UAAU,UAAU,OAAO,EAAE,SAAS,KAAK;AACzF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["// Core Types\n\nexport interface BaseExecOptions {\n /**\n * Maximum execution time in milliseconds\n */\n timeout?: number;\n\n /**\n * Environment variables for the command\n */\n env?: Record<string, string>;\n\n /**\n * Working directory for command execution\n */\n cwd?: string;\n\n /**\n * Text encoding for output (default: 'utf8')\n */\n encoding?: string;\n}\n\nexport interface ExecOptions extends BaseExecOptions {\n /**\n * Enable real-time output streaming via callbacks\n */\n stream?: boolean;\n\n /**\n * Callback for real-time output data\n */\n onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;\n\n /**\n * Callback when command completes (only when stream: true)\n */\n onComplete?: (result: ExecResult) => void;\n\n /**\n * Callback for execution errors\n */\n onError?: (error: Error) => void;\n\n /**\n * AbortSignal for cancelling execution\n */\n signal?: AbortSignal;\n}\n\nexport interface ExecResult {\n /**\n * Whether the command succeeded (exitCode === 0)\n */\n success: boolean;\n\n /**\n * Process exit code\n */\n exitCode: number;\n\n /**\n * Standard output content\n */\n stdout: string;\n\n /**\n * Standard error content\n */\n stderr: string;\n\n /**\n * Command that was executed\n */\n command: string;\n\n\n /**\n * Execution duration in milliseconds\n */\n duration: number;\n\n /**\n * ISO timestamp when command started\n */\n timestamp: string;\n}\n\n// Background Process Types\n\nexport interface ProcessOptions extends BaseExecOptions {\n /**\n * Custom process ID for later reference\n * If not provided, a UUID will be generated\n */\n processId?: string;\n\n /**\n * Automatically cleanup process record after exit (default: true)\n */\n autoCleanup?: boolean;\n\n /**\n * Callback when process exits\n */\n onExit?: (code: number | null) => void;\n\n /**\n * Callback for real-time output (background processes)\n */\n onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;\n\n /**\n * Callback when process starts successfully\n */\n onStart?: (process: Process) => void;\n\n /**\n * Callback for process errors\n */\n onError?: (error: Error) => void;\n}\n\nexport type ProcessStatus =\n | 'starting' // Process is being initialized\n | 'running' // Process is actively running\n | 'completed' // Process exited successfully (code 0)\n | 'failed' // Process exited with non-zero code\n | 'killed' // Process was terminated by signal\n | 'error'; // Process failed to start or encountered error\n\nexport interface Process {\n /**\n * Unique process identifier\n */\n readonly id: string;\n\n /**\n * System process ID (if available and running)\n */\n readonly pid?: number;\n\n /**\n * Command that was executed\n */\n readonly command: string;\n\n\n /**\n * Current process status\n */\n readonly status: ProcessStatus;\n\n /**\n * When the process was started\n */\n readonly startTime: Date;\n\n /**\n * When the process ended (if completed)\n */\n readonly endTime?: Date;\n\n /**\n * Process exit code (if completed)\n */\n readonly exitCode?: number;\n\n /**\n * Kill the process\n */\n kill(signal?: string): Promise<void>;\n\n /**\n * Get current process status (refreshed)\n */\n getStatus(): Promise<ProcessStatus>;\n\n /**\n * Get accumulated logs\n */\n getLogs(): Promise<{ stdout: string; stderr: string }>;\n}\n\n// Streaming Types\n\nexport interface ExecEvent {\n type: 'start' | 'stdout' | 'stderr' | 'complete' | 'error';\n timestamp: string;\n data?: string;\n command?: string;\n exitCode?: number;\n result?: ExecResult;\n error?: string; // Changed to string for serialization\n}\n\nexport interface LogEvent {\n type: 'stdout' | 'stderr' | 'exit' | 'error';\n timestamp: string;\n data: string;\n processId: string;\n exitCode?: number; // For 'exit' events\n}\n\nexport interface StreamOptions extends BaseExecOptions {\n /**\n * Buffer size for streaming output\n */\n bufferSize?: number;\n\n /**\n * AbortSignal for cancelling stream\n */\n signal?: AbortSignal;\n}\n\n// File Streaming Types\n\n/**\n * SSE events for file streaming\n */\nexport type FileStreamEvent =\n | {\n type: 'metadata';\n mimeType: string;\n size: number;\n isBinary: boolean;\n encoding: 'utf-8' | 'base64';\n }\n | {\n type: 'chunk';\n data: string; // base64 for binary, UTF-8 for text\n }\n | {\n type: 'complete';\n bytesRead: number;\n }\n | {\n type: 'error';\n error: string;\n };\n\n/**\n * File metadata from streaming\n */\nexport interface FileMetadata {\n mimeType: string;\n size: number;\n isBinary: boolean;\n encoding: 'utf-8' | 'base64';\n}\n\n/**\n * File stream chunk - either string (text) or Uint8Array (binary, auto-decoded)\n */\nexport type FileChunk = string | Uint8Array;\n\n/**\n * AsyncIterable of file chunks with metadata\n */\nexport interface FileStream extends AsyncIterable<FileChunk> {\n metadata?: FileMetadata;\n}\n\n// Error Types\n\nexport class SandboxError extends Error {\n constructor(message: string, public code?: string) {\n super(message);\n this.name = 'SandboxError';\n }\n}\n\nexport class ProcessNotFoundError extends SandboxError {\n constructor(processId: string) {\n super(`Process not found: ${processId}`, 'PROCESS_NOT_FOUND');\n this.name = 'ProcessNotFoundError';\n }\n}\n\nexport class ProcessAlreadyExistsError extends SandboxError {\n constructor(processId: string) {\n super(`Process already exists: ${processId}`, 'PROCESS_EXISTS');\n this.name = 'ProcessAlreadyExistsError';\n }\n}\n\nexport class ExecutionTimeoutError extends SandboxError {\n constructor(timeout: number) {\n super(`Execution timed out after ${timeout}ms`, 'EXECUTION_TIMEOUT');\n this.name = 'ExecutionTimeoutError';\n }\n}\n\n// Internal Container Types\n\nexport interface ProcessRecord {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: Date;\n endTime?: Date;\n exitCode?: number;\n\n // Internal fields\n stdout: string; // Accumulated output (ephemeral)\n stderr: string; // Accumulated output (ephemeral)\n\n // Streaming\n outputListeners: Set<(stream: 'stdout' | 'stderr', data: string) => void>;\n statusListeners: Set<(status: ProcessStatus) => void>;\n}\n\n// Container Request/Response Types\n\nexport interface StartProcessRequest {\n command: string;\n options?: {\n processId?: string;\n timeout?: number;\n env?: Record<string, string>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n };\n}\n\nexport interface StartProcessResponse {\n process: {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string;\n endTime?: string | null;\n exitCode?: number | null;\n sessionId: string;\n };\n}\n\nexport interface ListProcessesResponse {\n processes: Array<{\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string;\n endTime?: string;\n exitCode?: number;\n }>;\n}\n\nexport interface GetProcessResponse {\n process: {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string;\n endTime?: string;\n exitCode?: number;\n } | null;\n}\n\nexport interface GetProcessLogsResponse {\n stdout: string;\n stderr: string;\n processId: string;\n}\n\n// Import code interpreter types\nimport type {\n CodeContext,\n CreateContextOptions,\n ExecutionResult, \n RunCodeOptions\n} from './interpreter-types';\n\n// Main Sandbox Interface\n\nexport interface ISandbox {\n // Enhanced execution API\n exec(command: string, options?: ExecOptions): Promise<ExecResult>;\n\n // Background process management\n startProcess(command: string, options?: ProcessOptions): Promise<Process>;\n listProcesses(): Promise<Process[]>;\n getProcess(id: string): Promise<Process | null>;\n killProcess(id: string, signal?: string): Promise<void>;\n killAllProcesses(): Promise<number>;\n\n // Advanced streaming - returns ReadableStream that can be converted to AsyncIterable\n execStream(command: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>>;\n streamProcessLogs(processId: string, options?: { signal?: AbortSignal }): Promise<ReadableStream<Uint8Array>>;\n\n // Utility methods\n cleanupCompletedProcesses(): Promise<number>;\n getProcessLogs(id: string): Promise<{ stdout: string; stderr: string }>;\n\n // File operations\n gitCheckout(repoUrl: string, options: { branch?: string; targetDir?: string }): Promise<GitCheckoutResponse>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<MkdirResponse>;\n writeFile(path: string, content: string, options?: { encoding?: string }): Promise<WriteFileResponse>;\n deleteFile(path: string): Promise<DeleteFileResponse>;\n renameFile(oldPath: string, newPath: string): Promise<RenameFileResponse>;\n moveFile(sourcePath: string, destinationPath: string): Promise<MoveFileResponse>;\n readFile(path: string, options?: { encoding?: string }): Promise<ReadFileResponse>;\n readFileStream(path: string): Promise<ReadableStream<Uint8Array>>;\n listFiles(path: string, options?: { recursive?: boolean; includeHidden?: boolean }): Promise<ListFilesResponse>;\n\n // Port management\n exposePort(port: number, options: { name?: string; hostname: string }): Promise<{ url: string; port: number; name?: string }>;\n unexposePort(port: number): Promise<void>;\n getExposedPorts(hostname: string): Promise<Array<{ url: string; port: number; name?: string; exposedAt: string }>>;\n\n // Environment management\n setEnvVars(envVars: Record<string, string>): Promise<void>;\n setSandboxName(name: string): Promise<void>;\n\n // Code Interpreter API\n createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;\n runCode(code: string, options?: RunCodeOptions): Promise<ExecutionResult>;\n runCodeStream(code: string, options?: RunCodeOptions): Promise<ReadableStream>;\n listCodeContexts(): Promise<CodeContext[]>;\n deleteCodeContext(contextId: string): Promise<void>;\n}\n\n// Execution session returned by createSession()\n// Sessions are full-featured sandbox objects with scoped execution context\n// Inherits all ISandbox methods except createSession (sessions can't create sub-sessions),\n// and setSandboxName (sessions inherit sandbox name).\nexport interface ExecutionSession extends Omit<ISandbox, 'createSession' | 'setSandboxName'> {\n /**\n * Session ID\n */\n id: string;\n}\n\n// API Response Types\n\nexport interface ExecuteResponse {\n success: boolean;\n stdout: string;\n stderr: string;\n exitCode: number;\n command: string;\n timestamp: string;\n}\n\nexport interface GitCheckoutResponse {\n success: boolean;\n stdout: string;\n stderr: string;\n exitCode: number;\n repoUrl: string;\n branch: string;\n targetDir: string;\n timestamp: string;\n}\n\nexport interface MkdirResponse {\n success: boolean;\n stdout: string;\n stderr: string;\n exitCode: number;\n path: string;\n recursive: boolean;\n timestamp: string;\n}\n\nexport interface WriteFileResponse {\n success: boolean;\n exitCode: number;\n path: string;\n timestamp: string;\n}\n\nexport interface ReadFileResponse {\n success: boolean;\n exitCode: number;\n path: string;\n content: string;\n timestamp: string;\n\n /**\n * Encoding used for content (utf-8 for text, base64 for binary)\n */\n encoding?: 'utf-8' | 'base64';\n\n /**\n * Whether the file is detected as binary\n */\n isBinary?: boolean;\n\n /**\n * MIME type of the file (e.g., 'image/png', 'text/plain')\n */\n mimeType?: string;\n\n /**\n * File size in bytes\n */\n size?: number;\n}\n\nexport interface DeleteFileResponse {\n success: boolean;\n exitCode: number;\n path: string;\n timestamp: string;\n}\n\nexport interface RenameFileResponse {\n success: boolean;\n exitCode: number;\n oldPath: string;\n newPath: string;\n timestamp: string;\n}\n\nexport interface MoveFileResponse {\n success: boolean;\n exitCode: number;\n sourcePath: string;\n destinationPath: string;\n timestamp: string;\n}\n\nexport interface ListFilesResponse {\n success: boolean;\n exitCode: number;\n path: string;\n files: Array<{\n name: string;\n absolutePath: string;\n relativePath: string;\n type: 'file' | 'directory' | 'symlink' | 'other';\n size: number;\n modifiedAt: string;\n mode: string;\n permissions: {\n readable: boolean;\n writable: boolean;\n executable: boolean;\n };\n }>;\n timestamp: string;\n}\n\n// Type Guards\n\nexport function isExecResult(value: any): value is ExecResult {\n return value &&\n typeof value.success === 'boolean' &&\n typeof value.exitCode === 'number' &&\n typeof value.stdout === 'string' &&\n typeof value.stderr === 'string';\n}\n\nexport function isProcess(value: any): value is Process {\n return value &&\n typeof value.id === 'string' &&\n typeof value.command === 'string' &&\n typeof value.status === 'string';\n}\n\nexport function isProcessStatus(value: string): value is ProcessStatus {\n return ['starting', 'running', 'completed', 'failed', 'killed', 'error'].includes(value);\n}"],"mappings":";AA2QO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YAAY,SAAwB,MAAe;AACjD,UAAM,OAAO;AADqB;AAElC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACrD,YAAY,WAAmB;AAC7B,UAAM,sBAAsB,SAAS,IAAI,mBAAmB;AAC5D,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,4BAAN,cAAwC,aAAa;AAAA,EAC1D,YAAY,WAAmB;AAC7B,UAAM,2BAA2B,SAAS,IAAI,gBAAgB;AAC9D,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EACtD,YAAY,SAAiB;AAC3B,UAAM,6BAA6B,OAAO,MAAM,mBAAmB;AACnE,SAAK,OAAO;AAAA,EACd;AACF;AAoQO,SAAS,aAAa,OAAiC;AAC5D,SAAO,SACL,OAAO,MAAM,YAAY,aACzB,OAAO,MAAM,aAAa,YAC1B,OAAO,MAAM,WAAW,YACxB,OAAO,MAAM,WAAW;AAC5B;AAEO,SAAS,UAAU,OAA8B;AACtD,SAAO,SACL,OAAO,MAAM,OAAO,YACpB,OAAO,MAAM,YAAY,YACzB,OAAO,MAAM,WAAW;AAC5B;AAEO,SAAS,gBAAgB,OAAuC;AACrE,SAAO,CAAC,YAAY,WAAW,aAAa,UAAU,UAAU,OAAO,EAAE,SAAS,KAAK;AACzF;","names":[]}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -481,6 +481,45 @@ export class HttpClient {
|
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
+
async readFileStream(
|
|
485
|
+
path: string,
|
|
486
|
+
sessionId: string
|
|
487
|
+
): Promise<ReadableStream<Uint8Array>> {
|
|
488
|
+
try {
|
|
489
|
+
const response = await this.doFetch(`/api/read/stream`, {
|
|
490
|
+
method: "POST",
|
|
491
|
+
headers: {
|
|
492
|
+
"Content-Type": "application/json",
|
|
493
|
+
},
|
|
494
|
+
body: JSON.stringify({
|
|
495
|
+
path,
|
|
496
|
+
sessionId,
|
|
497
|
+
} as ReadFileRequest),
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
if (!response.ok) {
|
|
501
|
+
const errorData = (await response.json().catch(() => ({}))) as {
|
|
502
|
+
error?: string;
|
|
503
|
+
};
|
|
504
|
+
throw new Error(
|
|
505
|
+
errorData.error || `HTTP error! status: ${response.status}`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (!response.body) {
|
|
510
|
+
throw new Error("No response body for file streaming");
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
console.log(
|
|
514
|
+
`[HTTP Client] Started streaming file: ${path}${sessionId ? ` in session: ${sessionId}` : ''}`
|
|
515
|
+
);
|
|
516
|
+
return response.body;
|
|
517
|
+
} catch (error) {
|
|
518
|
+
console.error("[HTTP Client] Error streaming file:", error);
|
|
519
|
+
throw error;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
484
523
|
async deleteFile(
|
|
485
524
|
path: string,
|
|
486
525
|
sessionId: string
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File streaming utilities for reading binary and text files
|
|
3
|
+
* Provides simple AsyncIterable API over SSE stream with automatic base64 decoding
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { parseSSEStream } from './sse-parser';
|
|
7
|
+
import type { FileChunk, FileMetadata, FileStreamEvent } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Convert ReadableStream of SSE file events to AsyncIterable of file chunks
|
|
11
|
+
* Automatically decodes base64 for binary files and provides metadata
|
|
12
|
+
*
|
|
13
|
+
* @param stream - The SSE ReadableStream from readFileStream()
|
|
14
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
15
|
+
* @returns AsyncIterable that yields file chunks (string for text, Uint8Array for binary)
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const stream = await sandbox.readFileStream('/path/to/file.png');
|
|
20
|
+
*
|
|
21
|
+
* for await (const chunk of streamFile(stream)) {
|
|
22
|
+
* if (chunk instanceof Uint8Array) {
|
|
23
|
+
* // Binary chunk - already decoded from base64
|
|
24
|
+
* console.log('Binary chunk:', chunk.byteLength, 'bytes');
|
|
25
|
+
* } else {
|
|
26
|
+
* // Text chunk
|
|
27
|
+
* console.log('Text chunk:', chunk);
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* // Access metadata
|
|
32
|
+
* const iter = streamFile(stream);
|
|
33
|
+
* for await (const chunk of iter) {
|
|
34
|
+
* console.log('MIME type:', iter.metadata?.mimeType);
|
|
35
|
+
* // process chunk...
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export async function* streamFile(
|
|
40
|
+
stream: ReadableStream<Uint8Array>,
|
|
41
|
+
signal?: AbortSignal
|
|
42
|
+
): AsyncGenerator<FileChunk, void, undefined> {
|
|
43
|
+
let metadata: FileMetadata | undefined;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
for await (const event of parseSSEStream<FileStreamEvent>(stream, signal)) {
|
|
47
|
+
switch (event.type) {
|
|
48
|
+
case 'metadata':
|
|
49
|
+
// Store metadata for access via iterator
|
|
50
|
+
metadata = {
|
|
51
|
+
mimeType: event.mimeType,
|
|
52
|
+
size: event.size,
|
|
53
|
+
isBinary: event.isBinary,
|
|
54
|
+
encoding: event.encoding,
|
|
55
|
+
};
|
|
56
|
+
// Store on generator function for external access
|
|
57
|
+
(streamFile as any).metadata = metadata;
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
case 'chunk':
|
|
61
|
+
// Auto-decode base64 for binary files
|
|
62
|
+
if (metadata?.isBinary && metadata?.encoding === 'base64') {
|
|
63
|
+
// Decode base64 to Uint8Array
|
|
64
|
+
const binaryString = atob(event.data);
|
|
65
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
66
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
67
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
68
|
+
}
|
|
69
|
+
yield bytes;
|
|
70
|
+
} else {
|
|
71
|
+
// Text file - yield as-is
|
|
72
|
+
yield event.data;
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
|
|
76
|
+
case 'complete':
|
|
77
|
+
// Stream completed successfully
|
|
78
|
+
console.log(`[streamFile] File streaming complete: ${event.bytesRead} bytes read`);
|
|
79
|
+
return;
|
|
80
|
+
|
|
81
|
+
case 'error':
|
|
82
|
+
// Stream error
|
|
83
|
+
throw new Error(`File streaming error: ${event.error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('[streamFile] Error streaming file:', error);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Helper to collect entire file from stream into memory
|
|
94
|
+
* Useful for smaller files where you want the complete content at once
|
|
95
|
+
*
|
|
96
|
+
* @param stream - The SSE ReadableStream from readFileStream()
|
|
97
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
98
|
+
* @returns Object with content (string or Uint8Array) and metadata
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const stream = await sandbox.readFileStream('/path/to/image.png');
|
|
103
|
+
* const { content, metadata } = await collectFile(stream);
|
|
104
|
+
*
|
|
105
|
+
* if (content instanceof Uint8Array) {
|
|
106
|
+
* console.log('Binary file:', metadata.mimeType, content.byteLength, 'bytes');
|
|
107
|
+
* } else {
|
|
108
|
+
* console.log('Text file:', metadata.mimeType, content.length, 'chars');
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export async function collectFile(
|
|
113
|
+
stream: ReadableStream<Uint8Array>,
|
|
114
|
+
signal?: AbortSignal
|
|
115
|
+
): Promise<{ content: string | Uint8Array; metadata: FileMetadata }> {
|
|
116
|
+
let metadata: FileMetadata | undefined;
|
|
117
|
+
const chunks: FileChunk[] = [];
|
|
118
|
+
|
|
119
|
+
for await (const chunk of streamFile(stream, signal)) {
|
|
120
|
+
chunks.push(chunk);
|
|
121
|
+
// Capture metadata from first iteration
|
|
122
|
+
if (!metadata && (streamFile as any).metadata) {
|
|
123
|
+
metadata = (streamFile as any).metadata;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!metadata) {
|
|
128
|
+
throw new Error('No metadata received from file stream');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Combine chunks based on type
|
|
132
|
+
if (chunks.length === 0) {
|
|
133
|
+
// Empty file
|
|
134
|
+
return {
|
|
135
|
+
content: metadata.isBinary ? new Uint8Array(0) : '',
|
|
136
|
+
metadata,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check if binary or text based on first chunk
|
|
141
|
+
if (chunks[0] instanceof Uint8Array) {
|
|
142
|
+
// Binary file - concatenate Uint8Arrays
|
|
143
|
+
const totalLength = chunks.reduce((sum, chunk) => {
|
|
144
|
+
return sum + (chunk as Uint8Array).byteLength;
|
|
145
|
+
}, 0);
|
|
146
|
+
|
|
147
|
+
const result = new Uint8Array(totalLength);
|
|
148
|
+
let offset = 0;
|
|
149
|
+
for (const chunk of chunks) {
|
|
150
|
+
result.set(chunk as Uint8Array, offset);
|
|
151
|
+
offset += (chunk as Uint8Array).byteLength;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { content: result, metadata };
|
|
155
|
+
} else {
|
|
156
|
+
// Text file - concatenate strings
|
|
157
|
+
return {
|
|
158
|
+
content: chunks.join(''),
|
|
159
|
+
metadata,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -52,6 +52,8 @@ export {
|
|
|
52
52
|
parseSSEStream,
|
|
53
53
|
responseToAsyncIterable,
|
|
54
54
|
} from "./sse-parser";
|
|
55
|
+
// Export file streaming utilities
|
|
56
|
+
export { streamFile, collectFile } from "./file-stream";
|
|
55
57
|
export type {
|
|
56
58
|
DeleteFileResponse,
|
|
57
59
|
ExecEvent,
|
|
@@ -59,6 +61,10 @@ export type {
|
|
|
59
61
|
ExecResult,
|
|
60
62
|
ExecuteResponse,
|
|
61
63
|
ExecutionSession,
|
|
64
|
+
FileChunk,
|
|
65
|
+
FileMetadata,
|
|
66
|
+
FileStream,
|
|
67
|
+
FileStreamEvent,
|
|
62
68
|
GitCheckoutResponse,
|
|
63
69
|
ISandbox,
|
|
64
70
|
ListFilesResponse,
|
package/src/sandbox.ts
CHANGED
|
@@ -46,7 +46,7 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
46
46
|
private codeInterpreter: CodeInterpreter;
|
|
47
47
|
private defaultSession: ExecutionSession | null = null;
|
|
48
48
|
|
|
49
|
-
constructor(ctx: DurableObjectState
|
|
49
|
+
constructor(ctx: DurableObjectState<{}>, env: Env) {
|
|
50
50
|
super(ctx, env);
|
|
51
51
|
this.client = new InterpreterClient({
|
|
52
52
|
onCommandComplete: (success, exitCode, _stdout, _stderr, command) => {
|
|
@@ -264,6 +264,11 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
264
264
|
return session.readFile(path, options);
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
async readFileStream(path: string): Promise<ReadableStream<Uint8Array>> {
|
|
268
|
+
const session = await this.ensureDefaultSession();
|
|
269
|
+
return session.readFileStream(path);
|
|
270
|
+
}
|
|
271
|
+
|
|
267
272
|
async listFiles(
|
|
268
273
|
path: string,
|
|
269
274
|
options: {
|
|
@@ -678,7 +683,11 @@ export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
|
678
683
|
readFile: async (path: string, options?: { encoding?: string }) => {
|
|
679
684
|
return await this.client.readFile(path, options?.encoding, sessionId);
|
|
680
685
|
},
|
|
681
|
-
|
|
686
|
+
|
|
687
|
+
readFileStream: async (path: string) => {
|
|
688
|
+
return await this.client.readFileStream(path, sessionId);
|
|
689
|
+
},
|
|
690
|
+
|
|
682
691
|
mkdir: async (path: string, options?: { recursive?: boolean }) => {
|
|
683
692
|
return await this.client.mkdir(path, options?.recursive, sessionId);
|
|
684
693
|
},
|
package/src/types.ts
CHANGED
|
@@ -215,6 +215,54 @@ export interface StreamOptions extends BaseExecOptions {
|
|
|
215
215
|
signal?: AbortSignal;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
// File Streaming Types
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* SSE events for file streaming
|
|
222
|
+
*/
|
|
223
|
+
export type FileStreamEvent =
|
|
224
|
+
| {
|
|
225
|
+
type: 'metadata';
|
|
226
|
+
mimeType: string;
|
|
227
|
+
size: number;
|
|
228
|
+
isBinary: boolean;
|
|
229
|
+
encoding: 'utf-8' | 'base64';
|
|
230
|
+
}
|
|
231
|
+
| {
|
|
232
|
+
type: 'chunk';
|
|
233
|
+
data: string; // base64 for binary, UTF-8 for text
|
|
234
|
+
}
|
|
235
|
+
| {
|
|
236
|
+
type: 'complete';
|
|
237
|
+
bytesRead: number;
|
|
238
|
+
}
|
|
239
|
+
| {
|
|
240
|
+
type: 'error';
|
|
241
|
+
error: string;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* File metadata from streaming
|
|
246
|
+
*/
|
|
247
|
+
export interface FileMetadata {
|
|
248
|
+
mimeType: string;
|
|
249
|
+
size: number;
|
|
250
|
+
isBinary: boolean;
|
|
251
|
+
encoding: 'utf-8' | 'base64';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* File stream chunk - either string (text) or Uint8Array (binary, auto-decoded)
|
|
256
|
+
*/
|
|
257
|
+
export type FileChunk = string | Uint8Array;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* AsyncIterable of file chunks with metadata
|
|
261
|
+
*/
|
|
262
|
+
export interface FileStream extends AsyncIterable<FileChunk> {
|
|
263
|
+
metadata?: FileMetadata;
|
|
264
|
+
}
|
|
265
|
+
|
|
218
266
|
// Error Types
|
|
219
267
|
|
|
220
268
|
export class SandboxError extends Error {
|
|
@@ -359,6 +407,7 @@ export interface ISandbox {
|
|
|
359
407
|
renameFile(oldPath: string, newPath: string): Promise<RenameFileResponse>;
|
|
360
408
|
moveFile(sourcePath: string, destinationPath: string): Promise<MoveFileResponse>;
|
|
361
409
|
readFile(path: string, options?: { encoding?: string }): Promise<ReadFileResponse>;
|
|
410
|
+
readFileStream(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
362
411
|
listFiles(path: string, options?: { recursive?: boolean; includeHidden?: boolean }): Promise<ListFilesResponse>;
|
|
363
412
|
|
|
364
413
|
// Port management
|
|
@@ -434,6 +483,26 @@ export interface ReadFileResponse {
|
|
|
434
483
|
path: string;
|
|
435
484
|
content: string;
|
|
436
485
|
timestamp: string;
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Encoding used for content (utf-8 for text, base64 for binary)
|
|
489
|
+
*/
|
|
490
|
+
encoding?: 'utf-8' | 'base64';
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Whether the file is detected as binary
|
|
494
|
+
*/
|
|
495
|
+
isBinary?: boolean;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* MIME type of the file (e.g., 'image/png', 'text/plain')
|
|
499
|
+
*/
|
|
500
|
+
mimeType?: string;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* File size in bytes
|
|
504
|
+
*/
|
|
505
|
+
size?: number;
|
|
437
506
|
}
|
|
438
507
|
|
|
439
508
|
export interface DeleteFileResponse {
|
|
@@ -1 +0,0 @@
|
|
|
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":"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","names":["options"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import type { ExecuteRequest } from \"../container_src/types\";\nimport type { Sandbox } from \"./index\";\nimport type {\n BaseExecOptions,\n DeleteFileResponse,\n ExecuteResponse,\n GetProcessLogsResponse,\n GetProcessResponse,\n GitCheckoutResponse,\n ListFilesResponse,\n ListProcessesResponse,\n MkdirResponse,\n MoveFileResponse,\n ReadFileResponse,\n RenameFileResponse,\n StartProcessRequest,\n StartProcessResponse,\n WriteFileResponse,\n} from \"./types\";\n\n\ninterface CommandsResponse {\n availableCommands: string[];\n timestamp: string;\n}\n\ninterface GitCheckoutRequest {\n repoUrl: string;\n branch?: string;\n targetDir?: string;\n sessionId: string;\n}\n\n\ninterface MkdirRequest {\n path: string;\n recursive?: boolean;\n sessionId: string;\n}\n\n\ninterface WriteFileRequest {\n path: string;\n content: string;\n encoding?: string;\n sessionId: string;\n}\n\n\ninterface ReadFileRequest {\n path: string;\n encoding?: string;\n sessionId: string;\n}\n\n\ninterface DeleteFileRequest {\n path: string;\n sessionId: string;\n}\n\n\ninterface RenameFileRequest {\n oldPath: string;\n newPath: string;\n sessionId: string;\n}\n\n\ninterface MoveFileRequest {\n sourcePath: string;\n destinationPath: string;\n sessionId: string;\n}\n\n\ninterface ListFilesRequest {\n path: string;\n options?: {\n recursive?: boolean;\n includeHidden?: boolean;\n };\n sessionId: string;\n}\n\n\ninterface PreviewInfo {\n url: string;\n port: number;\n name?: string;\n}\n\ninterface ExposedPort extends PreviewInfo {\n exposedAt: string;\n timestamp: string;\n}\n\ninterface ExposePortResponse {\n success: boolean;\n port: number;\n name?: string;\n exposedAt: string;\n timestamp: string;\n}\n\ninterface UnexposePortResponse {\n success: boolean;\n port: number;\n timestamp: string;\n}\n\ninterface GetExposedPortsResponse {\n ports: ExposedPort[];\n count: number;\n timestamp: string;\n}\n\ninterface PingResponse {\n message: string;\n timestamp: string;\n}\n\ninterface HttpClientOptions {\n stub?: Sandbox;\n baseUrl?: string;\n port?: number;\n onCommandStart?: (command: string) => void;\n onOutput?: (\n stream: \"stdout\" | \"stderr\",\n data: string,\n command: string\n ) => void;\n onCommandComplete?: (\n success: boolean,\n exitCode: number,\n stdout: string,\n stderr: string,\n command: string\n ) => void;\n onError?: (error: string, command?: string) => void;\n}\n\nexport class HttpClient {\n private baseUrl: string;\n private options: HttpClientOptions;\n\n constructor(options: HttpClientOptions = {}) {\n this.options = {\n ...options,\n };\n this.baseUrl = this.options.baseUrl!;\n }\n\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n const url = this.options.stub\n ? `http://localhost:${this.options.port}${path}`\n : `${this.baseUrl}${path}`;\n const method = options?.method || \"GET\";\n\n console.log(`[HTTP Client] Making ${method} request to ${url}`);\n\n try {\n let response: Response;\n\n if (this.options.stub) {\n response = await this.options.stub.containerFetch(\n url,\n options,\n this.options.port\n );\n } else {\n response = await fetch(url, options);\n }\n\n console.log(\n `[HTTP Client] Response: ${response.status} ${response.statusText}`\n );\n\n if (!response.ok) {\n console.error(\n `[HTTP Client] Request failed: ${method} ${url} - ${response.status} ${response.statusText}`\n );\n }\n\n return response;\n } catch (error) {\n console.error(`[HTTP Client] Request error: ${method} ${url}`, error);\n throw error;\n }\n }\n\n async createSession(options: {\n id: string;\n env?: Record<string, string>;\n cwd?: string;\n isolation?: boolean;\n }): Promise<{ success: boolean; id: string; message: string }> {\n try {\n const response = await this.doFetch(`/api/session/create`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(options),\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `Failed to create session: ${response.status}`\n );\n }\n\n const data = await response.json() as { success: boolean; id: string; message: string };\n console.log(`[HTTP Client] Session created: ${options.id}`);\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error creating session:\", error);\n throw error;\n }\n }\n\n async exec(\n sessionId: string,\n command: string,\n options?: Pick<BaseExecOptions, \"cwd\" | \"env\">\n ): Promise<ExecuteResponse> {\n try {\n // Always use session-specific endpoint\n const response = await this.doFetch(`/api/execute`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ id: sessionId, command }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `Failed to execute in session: ${response.status}`\n );\n }\n\n const data = await response.json() as { stdout: string; stderr: string; exitCode: number; success: boolean };\n console.log(\n `[HTTP Client] Command executed in session ${sessionId}: ${command}`\n );\n \n // Convert to ExecuteResponse format for consistency\n const executeResponse: ExecuteResponse = {\n ...data,\n command,\n timestamp: new Date().toISOString()\n };\n\n // Call the callback if provided\n this.options.onCommandComplete?.(\n executeResponse.success,\n executeResponse.exitCode,\n executeResponse.stdout,\n executeResponse.stderr,\n executeResponse.command\n );\n\n return executeResponse;\n } catch (error) {\n console.error(\"[HTTP Client] Error executing in session:\", error);\n this.options.onError?.(\n error instanceof Error ? error.message : \"Unknown error\",\n command\n );\n throw error;\n }\n }\n\n async execStream(\n sessionId: string,\n command: string\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n // Always use session-specific streaming endpoint\n const response = await this.doFetch(`/api/execute/stream`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ \n id: sessionId,\n command\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `Failed to stream execute in session: ${response.status}`\n );\n }\n\n if (!response.body) {\n throw new Error(\"No response body for streaming execution\");\n }\n\n console.log(\n `[HTTP Client] Started streaming command in session ${sessionId}: ${command}`\n );\n return response.body;\n } catch (error) {\n console.error(\"[HTTP Client] Error streaming execute in session:\", error);\n throw error;\n }\n }\n\n async gitCheckout(\n repoUrl: string,\n sessionId: string,\n branch: string = \"main\",\n targetDir?: string\n ): Promise<GitCheckoutResponse> {\n try {\n const response = await this.doFetch(`/api/git/checkout`, {\n body: JSON.stringify({\n branch,\n repoUrl,\n targetDir,\n sessionId,\n } as GitCheckoutRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: GitCheckoutResponse = await response.json();\n console.log(\n `[HTTP Client] Git checkout completed: ${repoUrl}, Success: ${data.success}, Target: ${data.targetDir}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error in git checkout:\", error);\n throw error;\n }\n }\n\n async mkdir(\n path: string,\n recursive: boolean = false,\n sessionId: string\n ): Promise<MkdirResponse> {\n try {\n const response = await this.doFetch(`/api/mkdir`, {\n body: JSON.stringify({\n path,\n recursive,\n sessionId,\n } as MkdirRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: MkdirResponse = await response.json();\n console.log(\n `[HTTP Client] Directory created: ${path}, Success: ${data.success}, Recursive: ${data.recursive}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error creating directory:\", error);\n throw error;\n }\n }\n\n async writeFile(\n path: string,\n content: string,\n encoding: string = \"utf-8\",\n sessionId: string\n ): Promise<WriteFileResponse> {\n try {\n const response = await this.doFetch(`/api/write`, {\n body: JSON.stringify({\n content,\n encoding,\n path,\n sessionId,\n } as WriteFileRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: WriteFileResponse = await response.json();\n console.log(\n `[HTTP Client] File written: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error writing file:\", error);\n throw error;\n }\n }\n\n async readFile(\n path: string,\n encoding: string = \"utf-8\",\n sessionId: string\n ): Promise<ReadFileResponse> {\n try {\n const response = await this.doFetch(`/api/read`, {\n body: JSON.stringify({\n encoding,\n path,\n sessionId,\n } as ReadFileRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: ReadFileResponse = await response.json();\n console.log(\n `[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error reading file:\", error);\n throw error;\n }\n }\n\n async deleteFile(\n path: string,\n sessionId: string\n ): Promise<DeleteFileResponse> {\n try {\n const response = await this.doFetch(`/api/delete`, {\n body: JSON.stringify({\n path,\n sessionId,\n } as DeleteFileRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: DeleteFileResponse = await response.json();\n console.log(\n `[HTTP Client] File deleted: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error deleting file:\", error);\n throw error;\n }\n }\n\n async renameFile(\n oldPath: string,\n newPath: string,\n sessionId: string\n ): Promise<RenameFileResponse> {\n try {\n const response = await this.doFetch(`/api/rename`, {\n body: JSON.stringify({\n newPath,\n oldPath,\n sessionId,\n } as RenameFileRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: RenameFileResponse = await response.json();\n console.log(\n `[HTTP Client] File renamed: ${oldPath} -> ${newPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error renaming file:\", error);\n throw error;\n }\n }\n\n async moveFile(\n sourcePath: string,\n destinationPath: string,\n sessionId: string\n ): Promise<MoveFileResponse> {\n try {\n const response = await this.doFetch(`/api/move`, {\n body: JSON.stringify({\n destinationPath,\n sourcePath,\n sessionId,\n } as MoveFileRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: MoveFileResponse = await response.json();\n console.log(\n `[HTTP Client] File moved: ${sourcePath} -> ${destinationPath}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error moving file:\", error);\n throw error;\n }\n }\n\n async listFiles(\n path: string,\n sessionId: string,\n options?: {\n recursive?: boolean;\n includeHidden?: boolean;\n }\n ): Promise<ListFilesResponse> {\n try {\n const response = await this.doFetch(`/api/list-files`, {\n body: JSON.stringify({\n path,\n options,\n sessionId,\n } as ListFilesRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: ListFilesResponse = await response.json();\n console.log(\n `[HTTP Client] Listed ${data.files.length} files in: ${path}, Success: ${data.success}${sessionId ? ` in session: ${sessionId}` : ''}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error listing files:\", error);\n throw error;\n }\n }\n\n async exposePort(port: number, name?: string): Promise<ExposePortResponse> {\n try {\n const response = await this.doFetch(`/api/expose-port`, {\n body: JSON.stringify({\n port,\n name,\n }),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n console.log(errorData);\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: ExposePortResponse = await response.json();\n console.log(\n `[HTTP Client] Port exposed: ${port}${\n name ? ` (${name})` : \"\"\n }, Success: ${data.success}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error exposing port:\", error);\n throw error;\n }\n }\n\n async unexposePort(port: number): Promise<UnexposePortResponse> {\n try {\n const response = await this.doFetch(`/api/unexpose-port`, {\n body: JSON.stringify({\n port,\n }),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"DELETE\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: UnexposePortResponse = await response.json();\n console.log(\n `[HTTP Client] Port unexposed: ${port}, Success: ${data.success}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error unexposing port:\", error);\n throw error;\n }\n }\n\n async getExposedPorts(): Promise<GetExposedPortsResponse> {\n try {\n const response = await this.doFetch(`/api/exposed-ports`, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: GetExposedPortsResponse = await response.json();\n console.log(`[HTTP Client] Got ${data.count} exposed ports`);\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error getting exposed ports:\", error);\n throw error;\n }\n }\n\n async ping(): Promise<string> {\n try {\n const response = await this.doFetch(`/api/ping`, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const data: PingResponse = await response.json();\n console.log(`[HTTP Client] Ping response: ${data.message}`);\n return data.timestamp;\n } catch (error) {\n console.error(\"[HTTP Client] Error pinging server:\", error);\n throw error;\n }\n }\n\n\n // Process management methods\n async startProcess(\n command: string,\n sessionId: string,\n options?: {\n processId?: string;\n timeout?: number;\n env?: Record<string, string>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n }\n ): Promise<StartProcessResponse> {\n try {\n const response = await this.doFetch(\"/api/process/start\", {\n body: JSON.stringify({\n command,\n sessionId,\n options,\n } as StartProcessRequest),\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: StartProcessResponse = await response.json();\n console.log(\n `[HTTP Client] Process started: ${command}, ID: ${data.process.id}`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error starting process:\", error);\n throw error;\n }\n }\n\n async listProcesses(sessionId?: string): Promise<ListProcessesResponse> {\n try {\n const url = sessionId \n ? `/api/process/list?session=${encodeURIComponent(sessionId)}`\n : \"/api/process/list\";\n const response = await this.doFetch(url, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: ListProcessesResponse = await response.json();\n console.log(`[HTTP Client] Listed ${data.processes.length} processes`);\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error listing processes:\", error);\n throw error;\n }\n }\n\n async getProcess(processId: string): Promise<GetProcessResponse> {\n try {\n const response = await this.doFetch(`/api/process/${processId}`, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: GetProcessResponse = await response.json();\n console.log(\n `[HTTP Client] Got process ${processId}: ${\n data.process?.status || \"not found\"\n }`\n );\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error getting process:\", error);\n throw error;\n }\n }\n\n async killProcess(\n processId: string\n ): Promise<{ success: boolean; message: string }> {\n try {\n const response = await this.doFetch(`/api/process/${processId}`, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"DELETE\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data = (await response.json()) as {\n success: boolean;\n message: string;\n };\n console.log(`[HTTP Client] Killed process ${processId}`);\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error killing process:\", error);\n throw error;\n }\n }\n\n async killAllProcesses(sessionId?: string): Promise<{\n success: boolean;\n killedCount: number;\n message: string;\n }> {\n try {\n const url = sessionId \n ? `/api/process/kill-all?session=${encodeURIComponent(sessionId)}`\n : \"/api/process/kill-all\";\n const response = await this.doFetch(url, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"DELETE\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data = (await response.json()) as {\n success: boolean;\n killedCount: number;\n message: string;\n };\n console.log(`[HTTP Client] Killed ${data.killedCount} processes`);\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error killing all processes:\", error);\n throw error;\n }\n }\n\n async getProcessLogs(processId: string): Promise<GetProcessLogsResponse> {\n try {\n const response = await this.doFetch(`/api/process/${processId}/logs`, {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"GET\",\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n const data: GetProcessLogsResponse = await response.json();\n console.log(`[HTTP Client] Got logs for process ${processId}`);\n\n return data;\n } catch (error) {\n console.error(\"[HTTP Client] Error getting process logs:\", error);\n throw error;\n }\n }\n\n async streamProcessLogs(\n processId: string,\n options?: { signal?: AbortSignal }\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const response = await this.doFetch(`/api/process/${processId}/stream`, {\n headers: {\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n },\n method: \"GET\",\n signal: options?.signal,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(\n errorData.error || `HTTP error! status: ${response.status}`\n );\n }\n\n if (!response.body) {\n throw new Error(\"No response body for streaming request\");\n }\n\n console.log(\n `[HTTP Client] Started streaming logs for process ${processId}`\n );\n\n return response.body;\n } catch (error) {\n console.error(\"[HTTP Client] Error streaming process logs:\", error);\n throw error;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|