@cloudflare/sandbox 0.6.7 → 0.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["errorResponse: ErrorResponse<TContext>","response: Response","request: WSRequest","sseData: string","errorData: NewErrorResponse","data: ExecuteRequest","data: GitCheckoutRequest","lastError: Error | undefined","data: StartProcessRequest","clientOptions: HttpClientOptions","code?: string","proxyUrl: string","sanitizedSandboxId: string","provider: BucketProvider | null","s3fsArgs: string[]","request: Request","port: number | undefined","error: unknown","result: ExecResult","timeoutId: ReturnType<typeof setTimeout> | undefined","timeoutPromise: Promise<never> | undefined","metadata: FileMetadata | null","chunks: Array<string | Uint8Array>"],"sources":["../src/errors/classes.ts","../src/errors/adapter.ts","../src/clients/transport/base-transport.ts","../src/clients/transport/http-transport.ts","../src/clients/transport/ws-transport.ts","../src/clients/transport/factory.ts","../src/clients/base-client.ts","../src/clients/command-client.ts","../src/clients/file-client.ts","../src/clients/git-client.ts","../src/clients/interpreter-client.ts","../src/clients/port-client.ts","../src/clients/process-client.ts","../src/clients/utility-client.ts","../src/clients/sandbox-client.ts","../src/security.ts","../src/interpreter.ts","../src/request-handler.ts","../src/sse-parser.ts","../src/storage-mount/errors.ts","../src/storage-mount/credential-detection.ts","../src/storage-mount/provider-detection.ts","../src/version.ts","../src/sandbox.ts","../src/file-stream.ts"],"sourcesContent":["/**\n * Type-safe error classes that wrap ErrorResponse from container\n *\n * All error classes extend SandboxError<TContext> which wraps the full ErrorResponse\n * and provides type-safe accessors for error properties.\n */\n\nimport type {\n CodeExecutionContext,\n CommandErrorContext,\n CommandNotFoundContext,\n ContextNotFoundContext,\n ErrorResponse,\n FileExistsContext,\n FileNotFoundContext,\n FileSystemContext,\n GitAuthFailedContext,\n GitBranchNotFoundContext,\n GitErrorContext,\n GitRepositoryNotFoundContext,\n InternalErrorContext,\n InterpreterNotReadyContext,\n InvalidPortContext,\n PortAlreadyExposedContext,\n PortErrorContext,\n PortNotExposedContext,\n ProcessErrorContext,\n ProcessExitedBeforeReadyContext,\n ProcessNotFoundContext,\n ProcessReadyTimeoutContext,\n SessionAlreadyExistsContext,\n ValidationFailedContext\n} from '@repo/shared/errors';\n\n/**\n * Base SDK error that wraps ErrorResponse\n * Preserves all error information from container\n */\nexport class SandboxError<TContext = Record<string, unknown>> extends Error {\n constructor(public readonly errorResponse: ErrorResponse<TContext>) {\n super(errorResponse.message);\n this.name = 'SandboxError';\n }\n\n // Convenience accessors\n get code() {\n return this.errorResponse.code;\n }\n get context() {\n return this.errorResponse.context;\n }\n get httpStatus() {\n return this.errorResponse.httpStatus;\n }\n get operation() {\n return this.errorResponse.operation;\n }\n get suggestion() {\n return this.errorResponse.suggestion;\n }\n get timestamp() {\n return this.errorResponse.timestamp;\n }\n get documentation() {\n return this.errorResponse.documentation;\n }\n\n // Custom serialization for logging\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n context: this.context,\n httpStatus: this.httpStatus,\n operation: this.operation,\n suggestion: this.suggestion,\n timestamp: this.timestamp,\n documentation: this.documentation,\n stack: this.stack\n };\n }\n}\n\n// ============================================================================\n// File System Errors\n// ============================================================================\n\n/**\n * Error thrown when a file or directory is not found\n */\nexport class FileNotFoundError extends SandboxError<FileNotFoundContext> {\n constructor(errorResponse: ErrorResponse<FileNotFoundContext>) {\n super(errorResponse);\n this.name = 'FileNotFoundError';\n }\n\n // Type-safe accessors\n get path() {\n return this.context.path;\n }\n}\n\n/**\n * Error thrown when a file already exists\n */\nexport class FileExistsError extends SandboxError<FileExistsContext> {\n constructor(errorResponse: ErrorResponse<FileExistsContext>) {\n super(errorResponse);\n this.name = 'FileExistsError';\n }\n\n // Type-safe accessor\n get path() {\n return this.context.path;\n }\n}\n\n/**\n * Generic file system error (permissions, disk full, etc.)\n */\nexport class FileSystemError extends SandboxError<FileSystemContext> {\n constructor(errorResponse: ErrorResponse<FileSystemContext>) {\n super(errorResponse);\n this.name = 'FileSystemError';\n }\n\n // Type-safe accessors\n get path() {\n return this.context.path;\n }\n get stderr() {\n return this.context.stderr;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n\n/**\n * Error thrown when permission is denied\n */\nexport class PermissionDeniedError extends SandboxError<FileSystemContext> {\n constructor(errorResponse: ErrorResponse<FileSystemContext>) {\n super(errorResponse);\n this.name = 'PermissionDeniedError';\n }\n\n get path() {\n return this.context.path;\n }\n}\n\n// ============================================================================\n// Command Errors\n// ============================================================================\n\n/**\n * Error thrown when a command is not found\n */\nexport class CommandNotFoundError extends SandboxError<CommandNotFoundContext> {\n constructor(errorResponse: ErrorResponse<CommandNotFoundContext>) {\n super(errorResponse);\n this.name = 'CommandNotFoundError';\n }\n\n // Type-safe accessor\n get command() {\n return this.context.command;\n }\n}\n\n/**\n * Generic command execution error\n */\nexport class CommandError extends SandboxError<CommandErrorContext> {\n constructor(errorResponse: ErrorResponse<CommandErrorContext>) {\n super(errorResponse);\n this.name = 'CommandError';\n }\n\n // Type-safe accessors\n get command() {\n return this.context.command;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n get stdout() {\n return this.context.stdout;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n// ============================================================================\n// Process Errors\n// ============================================================================\n\n/**\n * Error thrown when a process is not found\n */\nexport class ProcessNotFoundError extends SandboxError<ProcessNotFoundContext> {\n constructor(errorResponse: ErrorResponse<ProcessNotFoundContext>) {\n super(errorResponse);\n this.name = 'ProcessNotFoundError';\n }\n\n // Type-safe accessor\n get processId() {\n return this.context.processId;\n }\n}\n\n/**\n * Generic process error\n */\nexport class ProcessError extends SandboxError<ProcessErrorContext> {\n constructor(errorResponse: ErrorResponse<ProcessErrorContext>) {\n super(errorResponse);\n this.name = 'ProcessError';\n }\n\n // Type-safe accessors\n get processId() {\n return this.context.processId;\n }\n get pid() {\n return this.context.pid;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n// ============================================================================\n// Session Errors\n// ============================================================================\n\n/**\n * Error thrown when a session already exists\n */\nexport class SessionAlreadyExistsError extends SandboxError<SessionAlreadyExistsContext> {\n constructor(errorResponse: ErrorResponse<SessionAlreadyExistsContext>) {\n super(errorResponse);\n this.name = 'SessionAlreadyExistsError';\n }\n\n // Type-safe accessors\n get sessionId() {\n return this.context.sessionId;\n }\n}\n\n// ============================================================================\n// Port Errors\n// ============================================================================\n\n/**\n * Error thrown when a port is already exposed\n */\nexport class PortAlreadyExposedError extends SandboxError<PortAlreadyExposedContext> {\n constructor(errorResponse: ErrorResponse<PortAlreadyExposedContext>) {\n super(errorResponse);\n this.name = 'PortAlreadyExposedError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get portName() {\n return this.context.portName;\n }\n}\n\n/**\n * Error thrown when a port is not exposed\n */\nexport class PortNotExposedError extends SandboxError<PortNotExposedContext> {\n constructor(errorResponse: ErrorResponse<PortNotExposedContext>) {\n super(errorResponse);\n this.name = 'PortNotExposedError';\n }\n\n // Type-safe accessor\n get port() {\n return this.context.port;\n }\n}\n\n/**\n * Error thrown when a port number is invalid\n */\nexport class InvalidPortError extends SandboxError<InvalidPortContext> {\n constructor(errorResponse: ErrorResponse<InvalidPortContext>) {\n super(errorResponse);\n this.name = 'InvalidPortError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get reason() {\n return this.context.reason;\n }\n}\n\n/**\n * Error thrown when a service on a port is not responding\n */\nexport class ServiceNotRespondingError extends SandboxError<PortErrorContext> {\n constructor(errorResponse: ErrorResponse<PortErrorContext>) {\n super(errorResponse);\n this.name = 'ServiceNotRespondingError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get portName() {\n return this.context.portName;\n }\n}\n\n/**\n * Error thrown when a port is already in use\n */\nexport class PortInUseError extends SandboxError<PortErrorContext> {\n constructor(errorResponse: ErrorResponse<PortErrorContext>) {\n super(errorResponse);\n this.name = 'PortInUseError';\n }\n\n // Type-safe accessor\n get port() {\n return this.context.port;\n }\n}\n\n/**\n * Generic port operation error\n */\nexport class PortError extends SandboxError<PortErrorContext> {\n constructor(errorResponse: ErrorResponse<PortErrorContext>) {\n super(errorResponse);\n this.name = 'PortError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get portName() {\n return this.context.portName;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n/**\n * Error thrown when port exposure requires a custom domain\n */\nexport class CustomDomainRequiredError extends SandboxError<InternalErrorContext> {\n constructor(errorResponse: ErrorResponse<InternalErrorContext>) {\n super(errorResponse);\n this.name = 'CustomDomainRequiredError';\n }\n}\n\n// ============================================================================\n// Git Errors\n// ============================================================================\n\n/**\n * Error thrown when a git repository is not found\n */\nexport class GitRepositoryNotFoundError extends SandboxError<GitRepositoryNotFoundContext> {\n constructor(errorResponse: ErrorResponse<GitRepositoryNotFoundContext>) {\n super(errorResponse);\n this.name = 'GitRepositoryNotFoundError';\n }\n\n // Type-safe accessor\n get repository() {\n return this.context.repository;\n }\n}\n\n/**\n * Error thrown when git authentication fails\n */\nexport class GitAuthenticationError extends SandboxError<GitAuthFailedContext> {\n constructor(errorResponse: ErrorResponse<GitAuthFailedContext>) {\n super(errorResponse);\n this.name = 'GitAuthenticationError';\n }\n\n // Type-safe accessor\n get repository() {\n return this.context.repository;\n }\n}\n\n/**\n * Error thrown when a git branch is not found\n */\nexport class GitBranchNotFoundError extends SandboxError<GitBranchNotFoundContext> {\n constructor(errorResponse: ErrorResponse<GitBranchNotFoundContext>) {\n super(errorResponse);\n this.name = 'GitBranchNotFoundError';\n }\n\n // Type-safe accessors\n get branch() {\n return this.context.branch;\n }\n get repository() {\n return this.context.repository;\n }\n}\n\n/**\n * Error thrown when a git network operation fails\n */\nexport class GitNetworkError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitNetworkError';\n }\n\n // Type-safe accessors\n get repository() {\n return this.context.repository;\n }\n get branch() {\n return this.context.branch;\n }\n get targetDir() {\n return this.context.targetDir;\n }\n}\n\n/**\n * Error thrown when git clone fails\n */\nexport class GitCloneError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitCloneError';\n }\n\n // Type-safe accessors\n get repository() {\n return this.context.repository;\n }\n get targetDir() {\n return this.context.targetDir;\n }\n get stderr() {\n return this.context.stderr;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n\n/**\n * Error thrown when git checkout fails\n */\nexport class GitCheckoutError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitCheckoutError';\n }\n\n // Type-safe accessors\n get branch() {\n return this.context.branch;\n }\n get repository() {\n return this.context.repository;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n/**\n * Error thrown when a git URL is invalid\n */\nexport class InvalidGitUrlError extends SandboxError<ValidationFailedContext> {\n constructor(errorResponse: ErrorResponse<ValidationFailedContext>) {\n super(errorResponse);\n this.name = 'InvalidGitUrlError';\n }\n\n // Type-safe accessor\n get validationErrors() {\n return this.context.validationErrors;\n }\n}\n\n/**\n * Generic git operation error\n */\nexport class GitError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitError';\n }\n\n // Type-safe accessors\n get repository() {\n return this.context.repository;\n }\n get branch() {\n return this.context.branch;\n }\n get targetDir() {\n return this.context.targetDir;\n }\n get stderr() {\n return this.context.stderr;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n\n// ============================================================================\n// Code Interpreter Errors\n// ============================================================================\n\n/**\n * Error thrown when interpreter is not ready\n */\nexport class InterpreterNotReadyError extends SandboxError<InterpreterNotReadyContext> {\n constructor(errorResponse: ErrorResponse<InterpreterNotReadyContext>) {\n super(errorResponse);\n this.name = 'InterpreterNotReadyError';\n }\n\n // Type-safe accessors\n get retryAfter() {\n return this.context.retryAfter;\n }\n get progress() {\n return this.context.progress;\n }\n}\n\n/**\n * Error thrown when a context is not found\n */\nexport class ContextNotFoundError extends SandboxError<ContextNotFoundContext> {\n constructor(errorResponse: ErrorResponse<ContextNotFoundContext>) {\n super(errorResponse);\n this.name = 'ContextNotFoundError';\n }\n\n // Type-safe accessor\n get contextId() {\n return this.context.contextId;\n }\n}\n\n/**\n * Error thrown when code execution fails\n */\nexport class CodeExecutionError extends SandboxError<CodeExecutionContext> {\n constructor(errorResponse: ErrorResponse<CodeExecutionContext>) {\n super(errorResponse);\n this.name = 'CodeExecutionError';\n }\n\n // Type-safe accessors\n get contextId() {\n return this.context.contextId;\n }\n get ename() {\n return this.context.ename;\n }\n get evalue() {\n return this.context.evalue;\n }\n get traceback() {\n return this.context.traceback;\n }\n}\n\n// ============================================================================\n// Validation Errors\n// ============================================================================\n\n/**\n * Error thrown when validation fails\n */\nexport class ValidationFailedError extends SandboxError<ValidationFailedContext> {\n constructor(errorResponse: ErrorResponse<ValidationFailedContext>) {\n super(errorResponse);\n this.name = 'ValidationFailedError';\n }\n\n // Type-safe accessor\n get validationErrors() {\n return this.context.validationErrors;\n }\n}\n\n// ============================================================================\n// Process Readiness Errors\n// ============================================================================\n\n/**\n * Error thrown when a process does not become ready within the timeout period\n */\nexport class ProcessReadyTimeoutError extends SandboxError<ProcessReadyTimeoutContext> {\n constructor(errorResponse: ErrorResponse<ProcessReadyTimeoutContext>) {\n super(errorResponse);\n this.name = 'ProcessReadyTimeoutError';\n }\n\n // Type-safe accessors\n get processId() {\n return this.context.processId;\n }\n get command() {\n return this.context.command;\n }\n get condition() {\n return this.context.condition;\n }\n get timeout() {\n return this.context.timeout;\n }\n}\n\n/**\n * Error thrown when a process exits before becoming ready\n */\nexport class ProcessExitedBeforeReadyError extends SandboxError<ProcessExitedBeforeReadyContext> {\n constructor(errorResponse: ErrorResponse<ProcessExitedBeforeReadyContext>) {\n super(errorResponse);\n this.name = 'ProcessExitedBeforeReadyError';\n }\n\n // Type-safe accessors\n get processId() {\n return this.context.processId;\n }\n get command() {\n return this.context.command;\n }\n get condition() {\n return this.context.condition;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n","/**\n * Error adapter that converts ErrorResponse to appropriate Error class\n *\n * Simple switch statement - we trust the container sends correct context\n * No validation overhead since we control both sides\n */\n\nimport type {\n CodeExecutionContext,\n CommandErrorContext,\n CommandNotFoundContext,\n ContextNotFoundContext,\n ErrorResponse,\n FileExistsContext,\n FileNotFoundContext,\n FileSystemContext,\n GitAuthFailedContext,\n GitBranchNotFoundContext,\n GitErrorContext,\n GitRepositoryNotFoundContext,\n InternalErrorContext,\n InterpreterNotReadyContext,\n InvalidPortContext,\n PortAlreadyExposedContext,\n PortErrorContext,\n PortNotExposedContext,\n ProcessErrorContext,\n ProcessNotFoundContext,\n SessionAlreadyExistsContext,\n ValidationFailedContext\n} from '@repo/shared/errors';\nimport { ErrorCode } from '@repo/shared/errors';\n\nimport {\n CodeExecutionError,\n CommandError,\n CommandNotFoundError,\n ContextNotFoundError,\n CustomDomainRequiredError,\n FileExistsError,\n FileNotFoundError,\n FileSystemError,\n GitAuthenticationError,\n GitBranchNotFoundError,\n GitCheckoutError,\n GitCloneError,\n GitError,\n GitNetworkError,\n GitRepositoryNotFoundError,\n InterpreterNotReadyError,\n InvalidGitUrlError,\n InvalidPortError,\n PermissionDeniedError,\n PortAlreadyExposedError,\n PortError,\n PortInUseError,\n PortNotExposedError,\n ProcessError,\n ProcessNotFoundError,\n SandboxError,\n ServiceNotRespondingError,\n SessionAlreadyExistsError,\n ValidationFailedError\n} from './classes';\n\n/**\n * Convert ErrorResponse to appropriate Error class\n * Simple switch statement - we trust the container sends correct context\n */\nexport function createErrorFromResponse(errorResponse: ErrorResponse): Error {\n // We trust the container sends correct context, use type assertions\n switch (errorResponse.code) {\n // File System Errors\n case ErrorCode.FILE_NOT_FOUND:\n return new FileNotFoundError(\n errorResponse as unknown as ErrorResponse<FileNotFoundContext>\n );\n\n case ErrorCode.FILE_EXISTS:\n return new FileExistsError(\n errorResponse as unknown as ErrorResponse<FileExistsContext>\n );\n\n case ErrorCode.PERMISSION_DENIED:\n return new PermissionDeniedError(\n errorResponse as unknown as ErrorResponse<FileSystemContext>\n );\n\n case ErrorCode.IS_DIRECTORY:\n case ErrorCode.NOT_DIRECTORY:\n case ErrorCode.NO_SPACE:\n case ErrorCode.TOO_MANY_FILES:\n case ErrorCode.RESOURCE_BUSY:\n case ErrorCode.READ_ONLY:\n case ErrorCode.NAME_TOO_LONG:\n case ErrorCode.TOO_MANY_LINKS:\n case ErrorCode.FILESYSTEM_ERROR:\n return new FileSystemError(\n errorResponse as unknown as ErrorResponse<FileSystemContext>\n );\n\n // Command Errors\n case ErrorCode.COMMAND_NOT_FOUND:\n return new CommandNotFoundError(\n errorResponse as unknown as ErrorResponse<CommandNotFoundContext>\n );\n\n case ErrorCode.COMMAND_PERMISSION_DENIED:\n case ErrorCode.COMMAND_EXECUTION_ERROR:\n case ErrorCode.INVALID_COMMAND:\n case ErrorCode.STREAM_START_ERROR:\n return new CommandError(\n errorResponse as unknown as ErrorResponse<CommandErrorContext>\n );\n\n // Process Errors\n case ErrorCode.PROCESS_NOT_FOUND:\n return new ProcessNotFoundError(\n errorResponse as unknown as ErrorResponse<ProcessNotFoundContext>\n );\n\n case ErrorCode.PROCESS_PERMISSION_DENIED:\n case ErrorCode.PROCESS_ERROR:\n return new ProcessError(\n errorResponse as unknown as ErrorResponse<ProcessErrorContext>\n );\n\n // Session Errors\n case ErrorCode.SESSION_ALREADY_EXISTS:\n return new SessionAlreadyExistsError(\n errorResponse as unknown as ErrorResponse<SessionAlreadyExistsContext>\n );\n\n // Port Errors\n case ErrorCode.PORT_ALREADY_EXPOSED:\n return new PortAlreadyExposedError(\n errorResponse as unknown as ErrorResponse<PortAlreadyExposedContext>\n );\n\n case ErrorCode.PORT_NOT_EXPOSED:\n return new PortNotExposedError(\n errorResponse as unknown as ErrorResponse<PortNotExposedContext>\n );\n\n case ErrorCode.INVALID_PORT_NUMBER:\n case ErrorCode.INVALID_PORT:\n return new InvalidPortError(\n errorResponse as unknown as ErrorResponse<InvalidPortContext>\n );\n\n case ErrorCode.SERVICE_NOT_RESPONDING:\n return new ServiceNotRespondingError(\n errorResponse as unknown as ErrorResponse<PortErrorContext>\n );\n\n case ErrorCode.PORT_IN_USE:\n return new PortInUseError(\n errorResponse as unknown as ErrorResponse<PortErrorContext>\n );\n\n case ErrorCode.PORT_OPERATION_ERROR:\n return new PortError(\n errorResponse as unknown as ErrorResponse<PortErrorContext>\n );\n\n case ErrorCode.CUSTOM_DOMAIN_REQUIRED:\n return new CustomDomainRequiredError(\n errorResponse as unknown as ErrorResponse<InternalErrorContext>\n );\n\n // Git Errors\n case ErrorCode.GIT_REPOSITORY_NOT_FOUND:\n return new GitRepositoryNotFoundError(\n errorResponse as unknown as ErrorResponse<GitRepositoryNotFoundContext>\n );\n\n case ErrorCode.GIT_AUTH_FAILED:\n return new GitAuthenticationError(\n errorResponse as unknown as ErrorResponse<GitAuthFailedContext>\n );\n\n case ErrorCode.GIT_BRANCH_NOT_FOUND:\n return new GitBranchNotFoundError(\n errorResponse as unknown as ErrorResponse<GitBranchNotFoundContext>\n );\n\n case ErrorCode.GIT_NETWORK_ERROR:\n return new GitNetworkError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n case ErrorCode.GIT_CLONE_FAILED:\n return new GitCloneError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n case ErrorCode.GIT_CHECKOUT_FAILED:\n return new GitCheckoutError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n case ErrorCode.INVALID_GIT_URL:\n return new InvalidGitUrlError(\n errorResponse as unknown as ErrorResponse<ValidationFailedContext>\n );\n\n case ErrorCode.GIT_OPERATION_FAILED:\n return new GitError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n // Code Interpreter Errors\n case ErrorCode.INTERPRETER_NOT_READY:\n return new InterpreterNotReadyError(\n errorResponse as unknown as ErrorResponse<InterpreterNotReadyContext>\n );\n\n case ErrorCode.CONTEXT_NOT_FOUND:\n return new ContextNotFoundError(\n errorResponse as unknown as ErrorResponse<ContextNotFoundContext>\n );\n\n case ErrorCode.CODE_EXECUTION_ERROR:\n return new CodeExecutionError(\n errorResponse as unknown as ErrorResponse<CodeExecutionContext>\n );\n\n // Validation Errors\n case ErrorCode.VALIDATION_FAILED:\n return new ValidationFailedError(\n errorResponse as unknown as ErrorResponse<ValidationFailedContext>\n );\n\n // Generic Errors\n case ErrorCode.INVALID_JSON_RESPONSE:\n case ErrorCode.UNKNOWN_ERROR:\n case ErrorCode.INTERNAL_ERROR:\n return new SandboxError(\n errorResponse as unknown as ErrorResponse<InternalErrorContext>\n );\n\n default:\n // Fallback for unknown error codes\n return new SandboxError(errorResponse);\n }\n}\n","import type { Logger } from '@repo/shared';\nimport { createNoOpLogger } from '@repo/shared';\nimport type { ITransport, TransportConfig, TransportMode } from './types';\n\n/**\n * Container startup retry configuration\n */\nconst TIMEOUT_MS = 120_000; // 2 minutes total retry budget\nconst MIN_TIME_FOR_RETRY_MS = 15_000; // Need at least 15s remaining to retry\n\n/**\n * Abstract base transport with shared retry logic\n *\n * Handles 503 retry for container startup - shared by all transports.\n * Subclasses implement the transport-specific fetch and stream logic.\n */\nexport abstract class BaseTransport implements ITransport {\n protected config: TransportConfig;\n protected logger: Logger;\n\n constructor(config: TransportConfig) {\n this.config = config;\n this.logger = config.logger ?? createNoOpLogger();\n }\n\n abstract getMode(): TransportMode;\n abstract connect(): Promise<void>;\n abstract disconnect(): void;\n abstract isConnected(): boolean;\n\n /**\n * Fetch with automatic retry for 503 (container starting)\n *\n * This is the primary entry point for making requests. It wraps the\n * transport-specific doFetch() with retry logic for container startup.\n */\n async fetch(path: string, options?: RequestInit): Promise<Response> {\n const startTime = Date.now();\n let attempt = 0;\n\n while (true) {\n const response = await this.doFetch(path, options);\n\n // Check for retryable 503 (container starting)\n if (response.status === 503) {\n const elapsed = Date.now() - startTime;\n const remaining = TIMEOUT_MS - elapsed;\n\n if (remaining > MIN_TIME_FOR_RETRY_MS) {\n const delay = Math.min(3000 * 2 ** attempt, 30000);\n\n this.logger.info('Container not ready, retrying', {\n status: response.status,\n attempt: attempt + 1,\n delayMs: delay,\n remainingSec: Math.floor(remaining / 1000),\n mode: this.getMode()\n });\n\n await this.sleep(delay);\n attempt++;\n continue;\n }\n\n this.logger.error(\n 'Container failed to become ready',\n new Error(\n `Failed after ${attempt + 1} attempts over ${Math.floor(elapsed / 1000)}s`\n )\n );\n }\n\n return response;\n }\n }\n\n /**\n * Transport-specific fetch implementation (no retry)\n * Subclasses implement the actual HTTP or WebSocket fetch.\n */\n protected abstract doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response>;\n\n /**\n * Transport-specific stream implementation\n * Subclasses implement HTTP SSE or WebSocket streaming.\n */\n abstract fetchStream(\n path: string,\n body?: unknown,\n method?: 'GET' | 'POST'\n ): Promise<ReadableStream<Uint8Array>>;\n\n /**\n * Sleep utility for retry delays\n */\n protected sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { BaseTransport } from './base-transport';\nimport type { TransportConfig, TransportMode } from './types';\n\n/**\n * HTTP transport implementation\n *\n * Uses standard fetch API for communication with the container.\n * HTTP is stateless, so connect/disconnect are no-ops.\n */\nexport class HttpTransport extends BaseTransport {\n private baseUrl: string;\n\n constructor(config: TransportConfig) {\n super(config);\n this.baseUrl = config.baseUrl ?? 'http://localhost:3000';\n }\n\n getMode(): TransportMode {\n return 'http';\n }\n\n async connect(): Promise<void> {\n // No-op for HTTP - stateless protocol\n }\n\n disconnect(): void {\n // No-op for HTTP - stateless protocol\n }\n\n isConnected(): boolean {\n return true; // HTTP is always \"connected\"\n }\n\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n const url = this.buildUrl(path);\n\n if (this.config.stub) {\n return this.config.stub.containerFetch(\n url,\n options || {},\n this.config.port\n );\n }\n return globalThis.fetch(url, options);\n }\n\n async fetchStream(\n path: string,\n body?: unknown,\n method: 'GET' | 'POST' = 'POST'\n ): Promise<ReadableStream<Uint8Array>> {\n const url = this.buildUrl(path);\n const options = this.buildStreamOptions(body, method);\n\n let response: Response;\n if (this.config.stub) {\n response = await this.config.stub.containerFetch(\n url,\n options,\n this.config.port\n );\n } else {\n response = await globalThis.fetch(url, options);\n }\n\n if (!response.ok) {\n const errorBody = await response.text();\n throw new Error(`HTTP error! status: ${response.status} - ${errorBody}`);\n }\n\n if (!response.body) {\n throw new Error('No response body for streaming');\n }\n\n return response.body;\n }\n\n private buildUrl(path: string): string {\n if (this.config.stub) {\n return `http://localhost:${this.config.port}${path}`;\n }\n return `${this.baseUrl}${path}`;\n }\n\n private buildStreamOptions(\n body: unknown,\n method: 'GET' | 'POST'\n ): RequestInit {\n return {\n method,\n headers:\n body && method === 'POST'\n ? { 'Content-Type': 'application/json' }\n : undefined,\n body: body && method === 'POST' ? JSON.stringify(body) : undefined\n };\n }\n}\n","import {\n generateRequestId,\n isWSError,\n isWSResponse,\n isWSStreamChunk,\n type WSMethod,\n type WSRequest,\n type WSResponse,\n type WSServerMessage,\n type WSStreamChunk\n} from '@repo/shared';\nimport { BaseTransport } from './base-transport';\nimport type { TransportConfig, TransportMode } from './types';\n\n/**\n * Pending request tracker for response matching\n */\ninterface PendingRequest {\n resolve: (response: WSResponse) => void;\n reject: (error: Error) => void;\n streamController?: ReadableStreamDefaultController<Uint8Array>;\n isStreaming: boolean;\n timeoutId?: ReturnType<typeof setTimeout>;\n}\n\n/**\n * WebSocket transport state\n */\ntype WSTransportState = 'disconnected' | 'connecting' | 'connected' | 'error';\n\n/**\n * WebSocket transport implementation\n *\n * Multiplexes HTTP-like requests over a single WebSocket connection.\n * Useful when running inside Workers/DO where sub-request limits apply.\n */\nexport class WebSocketTransport extends BaseTransport {\n private ws: WebSocket | null = null;\n private state: WSTransportState = 'disconnected';\n private pendingRequests: Map<string, PendingRequest> = new Map();\n private connectPromise: Promise<void> | null = null;\n\n // Bound event handlers for proper add/remove\n private boundHandleMessage: (event: MessageEvent) => void;\n private boundHandleClose: (event: CloseEvent) => void;\n\n constructor(config: TransportConfig) {\n super(config);\n\n if (!config.wsUrl) {\n throw new Error('wsUrl is required for WebSocket transport');\n }\n\n // Bind handlers once in constructor\n this.boundHandleMessage = this.handleMessage.bind(this);\n this.boundHandleClose = this.handleClose.bind(this);\n }\n\n getMode(): TransportMode {\n return 'websocket';\n }\n\n /**\n * Check if WebSocket is connected\n */\n isConnected(): boolean {\n return this.state === 'connected' && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Connect to the WebSocket server\n *\n * The connection promise is assigned synchronously so concurrent\n * callers share the same connection attempt.\n */\n async connect(): Promise<void> {\n // Already connected\n if (this.isConnected()) {\n return;\n }\n\n // Connection in progress - wait for it\n if (this.connectPromise) {\n return this.connectPromise;\n }\n\n // Assign synchronously so concurrent callers await the same promise\n this.connectPromise = this.doConnect();\n\n try {\n await this.connectPromise;\n } catch (error) {\n // Clear promise AFTER await so concurrent callers see the same rejection\n this.connectPromise = null;\n throw error;\n }\n }\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect(): void {\n this.cleanup();\n }\n\n /**\n * Transport-specific fetch implementation\n * Converts WebSocket response to standard Response object.\n */\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n await this.connect();\n\n const method = (options?.method || 'GET') as WSMethod;\n const body = this.parseBody(options?.body);\n\n const result = await this.request(method, path, body);\n\n return new Response(JSON.stringify(result.body), {\n status: result.status,\n headers: { 'Content-Type': 'application/json' }\n });\n }\n\n /**\n * Streaming fetch implementation\n */\n async fetchStream(\n path: string,\n body?: unknown,\n method: 'GET' | 'POST' = 'POST'\n ): Promise<ReadableStream<Uint8Array>> {\n return this.requestStream(method, path, body);\n }\n\n /**\n * Parse request body from RequestInit\n */\n private parseBody(body: RequestInit['body']): unknown {\n if (!body) {\n return undefined;\n }\n\n if (typeof body === 'string') {\n try {\n return JSON.parse(body);\n } catch (error) {\n throw new Error(\n `Request body must be valid JSON: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n throw new Error(\n `WebSocket transport only supports string bodies. Got: ${typeof body}`\n );\n }\n\n /**\n * Internal connection logic\n */\n private async doConnect(): Promise<void> {\n this.state = 'connecting';\n // Use fetch-based WebSocket for DO context (Workers style)\n if (this.config.stub) {\n await this.connectViaFetch();\n } else {\n // Use standard WebSocket for browser/Node\n await this.connectViaWebSocket();\n }\n }\n\n /**\n * Connect using fetch-based WebSocket (Cloudflare Workers style)\n * This is required when running inside a Durable Object.\n *\n * Uses stub.fetch() which routes WebSocket upgrade requests through the\n * parent Container class that supports the WebSocket protocol.\n */\n private async connectViaFetch(): Promise<void> {\n const timeoutMs = this.config.connectTimeoutMs ?? 30000;\n\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // Build the WebSocket URL for the container\n const wsPath = new URL(this.config.wsUrl!).pathname;\n const httpUrl = `http://localhost:${this.config.port || 3000}${wsPath}`;\n\n // Create a Request with WebSocket upgrade headers\n const request = new Request(httpUrl, {\n headers: {\n Upgrade: 'websocket',\n Connection: 'Upgrade'\n },\n signal: controller.signal\n });\n\n const response = await this.config.stub!.fetch(request);\n\n clearTimeout(timeout);\n\n // Check if upgrade was successful\n if (response.status !== 101) {\n throw new Error(\n `WebSocket upgrade failed: ${response.status} ${response.statusText}`\n );\n }\n\n // Get the WebSocket from the response (Workers-specific API)\n const ws = (response as unknown as { webSocket?: WebSocket }).webSocket;\n if (!ws) {\n throw new Error('No WebSocket in upgrade response');\n }\n\n // Accept the WebSocket connection (Workers-specific)\n (ws as unknown as { accept: () => void }).accept();\n\n this.ws = ws;\n this.state = 'connected';\n\n // Set up event handlers\n this.ws.addEventListener('close', this.boundHandleClose);\n this.ws.addEventListener('message', this.boundHandleMessage);\n\n this.logger.debug('WebSocket connected via fetch', {\n url: this.config.wsUrl\n });\n } catch (error) {\n clearTimeout(timeout);\n this.state = 'error';\n this.logger.error(\n 'WebSocket fetch connection failed',\n error instanceof Error ? error : new Error(String(error))\n );\n throw error;\n }\n }\n\n /**\n * Connect using standard WebSocket API (browser/Node style)\n */\n private connectViaWebSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timeoutMs = this.config.connectTimeoutMs ?? 30000;\n const timeout = setTimeout(() => {\n this.cleanup();\n reject(new Error(`WebSocket connection timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n\n try {\n this.ws = new WebSocket(this.config.wsUrl!);\n\n // One-time open handler for connection\n const onOpen = () => {\n clearTimeout(timeout);\n this.ws?.removeEventListener('open', onOpen);\n this.ws?.removeEventListener('error', onConnectError);\n this.state = 'connected';\n this.logger.debug('WebSocket connected', { url: this.config.wsUrl });\n resolve();\n };\n\n // One-time error handler for connection\n const onConnectError = () => {\n clearTimeout(timeout);\n this.ws?.removeEventListener('open', onOpen);\n this.ws?.removeEventListener('error', onConnectError);\n this.state = 'error';\n this.logger.error(\n 'WebSocket error',\n new Error('WebSocket connection failed')\n );\n reject(new Error('WebSocket connection failed'));\n };\n\n this.ws.addEventListener('open', onOpen);\n this.ws.addEventListener('error', onConnectError);\n this.ws.addEventListener('close', this.boundHandleClose);\n this.ws.addEventListener('message', this.boundHandleMessage);\n } catch (error) {\n clearTimeout(timeout);\n this.state = 'error';\n reject(error);\n }\n });\n }\n\n /**\n * Send a request and wait for response\n */\n private async request<T>(\n method: WSMethod,\n path: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n await this.connect();\n\n const id = generateRequestId();\n const request: WSRequest = {\n type: 'request',\n id,\n method,\n path,\n body\n };\n\n return new Promise((resolve, reject) => {\n const timeoutMs = this.config.requestTimeoutMs ?? 120000;\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(\n new Error(`Request timeout after ${timeoutMs}ms: ${method} ${path}`)\n );\n }, timeoutMs);\n\n this.pendingRequests.set(id, {\n resolve: (response: WSResponse) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n resolve({ status: response.status, body: response.body as T });\n },\n reject: (error: Error) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n reject(error);\n },\n isStreaming: false,\n timeoutId\n });\n\n try {\n this.send(request);\n } catch (error) {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /**\n * Send a streaming request and return a ReadableStream\n *\n * The stream will receive data chunks as they arrive over the WebSocket.\n * Format matches SSE for compatibility with existing streaming code.\n */\n private async requestStream(\n method: WSMethod,\n path: string,\n body?: unknown\n ): Promise<ReadableStream<Uint8Array>> {\n await this.connect();\n\n const id = generateRequestId();\n const request: WSRequest = {\n type: 'request',\n id,\n method,\n path,\n body\n };\n\n return new ReadableStream<Uint8Array>({\n start: (controller) => {\n const timeoutMs = this.config.requestTimeoutMs ?? 120000;\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(id);\n controller.error(\n new Error(`Stream timeout after ${timeoutMs}ms: ${method} ${path}`)\n );\n }, timeoutMs);\n\n this.pendingRequests.set(id, {\n resolve: (response: WSResponse) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n // Final response - close the stream\n if (response.status >= 400) {\n controller.error(\n new Error(\n `Stream error: ${response.status} - ${JSON.stringify(response.body)}`\n )\n );\n } else {\n controller.close();\n }\n },\n reject: (error: Error) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n controller.error(error);\n },\n streamController: controller,\n isStreaming: true,\n timeoutId\n });\n\n try {\n this.send(request);\n } catch (error) {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n controller.error(\n error instanceof Error ? error : new Error(String(error))\n );\n }\n },\n cancel: () => {\n const pending = this.pendingRequests.get(id);\n if (pending?.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n this.pendingRequests.delete(id);\n // Could send a cancel message to server if needed\n }\n });\n }\n\n /**\n * Send a message over the WebSocket\n */\n private send(message: WSRequest): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected');\n }\n\n this.ws.send(JSON.stringify(message));\n this.logger.debug('WebSocket sent', {\n id: message.id,\n method: message.method,\n path: message.path\n });\n }\n\n /**\n * Handle incoming WebSocket messages\n */\n private handleMessage(event: MessageEvent): void {\n try {\n const message = JSON.parse(event.data) as WSServerMessage;\n\n if (isWSResponse(message)) {\n this.handleResponse(message);\n } else if (isWSStreamChunk(message)) {\n this.handleStreamChunk(message);\n } else if (isWSError(message)) {\n this.handleError(message);\n } else {\n this.logger.warn('Unknown WebSocket message type', { message });\n }\n } catch (error) {\n this.logger.error(\n 'Failed to parse WebSocket message',\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\n\n /**\n * Handle a response message\n */\n private handleResponse(response: WSResponse): void {\n const pending = this.pendingRequests.get(response.id);\n if (!pending) {\n this.logger.warn('Received response for unknown request', {\n id: response.id\n });\n return;\n }\n\n this.logger.debug('WebSocket response', {\n id: response.id,\n status: response.status,\n done: response.done\n });\n\n // Only resolve when done is true\n if (response.done) {\n pending.resolve(response);\n }\n }\n\n /**\n * Handle a stream chunk message\n */\n private handleStreamChunk(chunk: WSStreamChunk): void {\n const pending = this.pendingRequests.get(chunk.id);\n if (!pending || !pending.streamController) {\n this.logger.warn('Received stream chunk for unknown request', {\n id: chunk.id\n });\n return;\n }\n\n // Convert to SSE format for compatibility with existing parsers\n const encoder = new TextEncoder();\n let sseData: string;\n if (chunk.event) {\n sseData = `event: ${chunk.event}\\ndata: ${chunk.data}\\n\\n`;\n } else {\n sseData = `data: ${chunk.data}\\n\\n`;\n }\n\n try {\n pending.streamController.enqueue(encoder.encode(sseData));\n } catch (error) {\n // Stream was cancelled or errored - clean up the pending request\n this.logger.debug('Failed to enqueue stream chunk, cleaning up', {\n id: chunk.id,\n error: error instanceof Error ? error.message : String(error)\n });\n // Clear timeout and remove from pending requests\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n this.pendingRequests.delete(chunk.id);\n }\n }\n\n /**\n * Handle an error message\n */\n private handleError(error: {\n id?: string;\n code: string;\n message: string;\n status: number;\n }): void {\n if (error.id) {\n const pending = this.pendingRequests.get(error.id);\n if (pending) {\n pending.reject(new Error(`${error.code}: ${error.message}`));\n return;\n }\n }\n\n // Global error - log it\n this.logger.error('WebSocket error message', new Error(error.message), {\n code: error.code,\n status: error.status\n });\n }\n\n /**\n * Handle WebSocket close\n */\n private handleClose(event: CloseEvent): void {\n this.state = 'disconnected';\n this.ws = null;\n\n const closeError = new Error(\n `WebSocket closed: ${event.code} ${event.reason || 'No reason'}`\n );\n\n // Reject all pending requests, clear their timeouts, and error their stream controllers\n for (const [, pending] of this.pendingRequests) {\n // Clear timeout first to prevent memory leak\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n // Error stream controller if it exists\n if (pending.streamController) {\n try {\n pending.streamController.error(closeError);\n } catch {\n // Stream may already be closed/errored\n }\n }\n pending.reject(closeError);\n }\n this.pendingRequests.clear();\n }\n\n /**\n * Cleanup resources\n */\n private cleanup(): void {\n if (this.ws) {\n this.ws.removeEventListener('close', this.boundHandleClose);\n this.ws.removeEventListener('message', this.boundHandleMessage);\n this.ws.close();\n this.ws = null;\n }\n this.state = 'disconnected';\n this.connectPromise = null;\n // Clear all pending request timeouts before clearing the map\n for (const pending of this.pendingRequests.values()) {\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n }\n this.pendingRequests.clear();\n }\n}\n","import { HttpTransport } from './http-transport';\nimport type { ITransport, TransportConfig, TransportMode } from './types';\nimport { WebSocketTransport } from './ws-transport';\n\n/**\n * Transport options with mode selection\n */\nexport interface TransportOptions extends TransportConfig {\n /** Transport mode */\n mode: TransportMode;\n}\n\n/**\n * Create a transport instance based on mode\n *\n * This is the primary API for creating transports. It handles\n * the selection of HTTP or WebSocket transport based on the mode.\n *\n * @example\n * ```typescript\n * // HTTP transport (default)\n * const http = createTransport({\n * mode: 'http',\n * baseUrl: 'http://localhost:3000'\n * });\n *\n * // WebSocket transport\n * const ws = createTransport({\n * mode: 'websocket',\n * wsUrl: 'ws://localhost:3000/ws'\n * });\n * ```\n */\nexport function createTransport(options: TransportOptions): ITransport {\n switch (options.mode) {\n case 'websocket':\n return new WebSocketTransport(options);\n\n default:\n return new HttpTransport(options);\n }\n}\n","import type { Logger } from '@repo/shared';\nimport { createNoOpLogger } from '@repo/shared';\nimport type { ErrorResponse as NewErrorResponse } from '../errors';\nimport { createErrorFromResponse, ErrorCode } from '../errors';\nimport type { SandboxError } from '../errors/classes';\nimport { createTransport, type ITransport } from './transport';\nimport type { HttpClientOptions, ResponseHandler } from './types';\n\n/**\n * Abstract base class providing common HTTP/WebSocket functionality for all domain clients\n *\n * All requests go through the Transport abstraction layer, which handles:\n * - HTTP and WebSocket modes transparently\n * - Automatic retry for 503 errors (container starting)\n * - Streaming responses\n *\n * WebSocket mode is useful when running inside Workers/Durable Objects\n * where sub-request limits apply.\n */\nexport abstract class BaseHttpClient {\n protected options: HttpClientOptions;\n protected logger: Logger;\n protected transport: ITransport;\n\n constructor(options: HttpClientOptions = {}) {\n this.options = options;\n this.logger = options.logger ?? createNoOpLogger();\n\n // Always create a Transport - it handles both HTTP and WebSocket modes\n if (options.transport) {\n this.transport = options.transport;\n } else {\n const mode = options.transportMode ?? 'http';\n this.transport = createTransport({\n mode,\n baseUrl: options.baseUrl ?? 'http://localhost:3000',\n wsUrl: options.wsUrl,\n logger: this.logger,\n stub: options.stub,\n port: options.port\n });\n }\n }\n\n /**\n * Check if using WebSocket transport\n */\n protected isWebSocketMode(): boolean {\n return this.transport.getMode() === 'websocket';\n }\n\n /**\n * Core fetch method - delegates to Transport which handles retry logic\n */\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n return this.transport.fetch(path, options);\n }\n\n /**\n * Make a POST request with JSON body\n */\n protected async post<T>(\n endpoint: string,\n data: unknown,\n responseHandler?: ResponseHandler<T>\n ): Promise<T> {\n const response = await this.doFetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(data)\n });\n\n return this.handleResponse(response, responseHandler);\n }\n\n /**\n * Make a GET request\n */\n protected async get<T>(\n endpoint: string,\n responseHandler?: ResponseHandler<T>\n ): Promise<T> {\n const response = await this.doFetch(endpoint, {\n method: 'GET'\n });\n\n return this.handleResponse(response, responseHandler);\n }\n\n /**\n * Make a DELETE request\n */\n protected async delete<T>(\n endpoint: string,\n responseHandler?: ResponseHandler<T>\n ): Promise<T> {\n const response = await this.doFetch(endpoint, {\n method: 'DELETE'\n });\n\n return this.handleResponse(response, responseHandler);\n }\n\n /**\n * Handle HTTP response with error checking and parsing\n */\n protected async handleResponse<T>(\n response: Response,\n customHandler?: ResponseHandler<T>\n ): Promise<T> {\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n if (customHandler) {\n return customHandler(response);\n }\n\n try {\n return await response.json();\n } catch (error) {\n // Handle malformed JSON responses gracefully\n const errorResponse: NewErrorResponse = {\n code: ErrorCode.INVALID_JSON_RESPONSE,\n message: `Invalid JSON response: ${\n error instanceof Error ? error.message : 'Unknown parsing error'\n }`,\n context: {},\n httpStatus: response.status,\n timestamp: new Date().toISOString()\n };\n throw createErrorFromResponse(errorResponse);\n }\n }\n\n /**\n * Handle error responses with consistent error throwing\n */\n protected async handleErrorResponse(response: Response): Promise<never> {\n let errorData: NewErrorResponse;\n\n try {\n errorData = await response.json();\n } catch {\n // Fallback if response isn't JSON or parsing fails\n errorData = {\n code: ErrorCode.INTERNAL_ERROR,\n message: `HTTP error! status: ${response.status}`,\n context: { statusText: response.statusText },\n httpStatus: response.status,\n timestamp: new Date().toISOString()\n };\n }\n\n // Convert ErrorResponse to appropriate Error class\n const error = createErrorFromResponse(errorData);\n\n // Call error callback if provided\n this.options.onError?.(errorData.message, undefined);\n\n throw error;\n }\n\n /**\n * Create a streaming response handler for Server-Sent Events\n */\n protected async handleStreamResponse(\n response: Response\n ): Promise<ReadableStream<Uint8Array>> {\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n if (!response.body) {\n throw new Error('No response body for streaming');\n }\n\n return response.body;\n }\n\n /**\n * Stream request handler\n *\n * For HTTP mode, uses doFetch + handleStreamResponse to get proper error typing.\n * For WebSocket mode, uses Transport's streaming support.\n *\n * @param path - The API path to call\n * @param body - Optional request body (for POST requests)\n * @param method - HTTP method (default: POST, use GET for process logs)\n */\n protected async doStreamFetch(\n path: string,\n body?: unknown,\n method: 'GET' | 'POST' = 'POST'\n ): Promise<ReadableStream<Uint8Array>> {\n // WebSocket mode uses Transport's streaming directly\n if (this.transport.getMode() === 'websocket') {\n try {\n return await this.transport.fetchStream(path, body, method);\n } catch (error) {\n this.logError(`stream ${method} ${path}`, error);\n throw error;\n }\n }\n\n // HTTP mode: use doFetch + handleStreamResponse for proper error typing\n const response = await this.doFetch(path, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: body && method === 'POST' ? JSON.stringify(body) : undefined\n });\n\n return this.handleStreamResponse(response);\n }\n\n /**\n * Utility method to log successful operations\n */\n protected logSuccess(operation: string, details?: string): void {\n this.logger.info(operation, details ? { details } : undefined);\n }\n\n /**\n * Utility method to log errors intelligently\n * Only logs unexpected errors (5xx), not expected errors (4xx)\n *\n * - 4xx errors (validation, not found, conflicts): Don't log (expected client errors)\n * - 5xx errors (server failures, internal errors): DO log (unexpected server errors)\n */\n protected logError(operation: string, error: unknown): void {\n // Check if it's a SandboxError with HTTP status\n if (error && typeof error === 'object' && 'httpStatus' in error) {\n const httpStatus = (error as SandboxError).httpStatus;\n\n // Only log server errors (5xx), not client errors (4xx)\n if (httpStatus >= 500) {\n this.logger.error(\n `Unexpected error in ${operation}`,\n error instanceof Error ? error : new Error(String(error)),\n { httpStatus }\n );\n }\n // 4xx errors are expected (validation, not found, etc.) - don't log\n } else {\n // Non-SandboxError (unexpected) - log it\n this.logger.error(\n `Error in ${operation}`,\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\n}\n","import type { ExecuteRequest } from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { BaseApiResponse } from './types';\n\n/**\n * Request interface for command execution\n */\nexport type { ExecuteRequest };\n\n/**\n * Response interface for command execution\n */\nexport interface ExecuteResponse extends BaseApiResponse {\n stdout: string;\n stderr: string;\n exitCode: number;\n command: string;\n}\n\n/**\n * Client for command execution operations\n */\nexport class CommandClient extends BaseHttpClient {\n /**\n * Execute a command and return the complete result\n * @param command - The command to execute\n * @param sessionId - The session ID for this command execution\n * @param timeoutMs - Optional timeout in milliseconds (unlimited by default)\n * @param env - Optional environment variables for this command\n * @param cwd - Optional working directory for this command\n */\n async execute(\n command: string,\n sessionId: string,\n options?: {\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n }\n ): Promise<ExecuteResponse> {\n try {\n const data: ExecuteRequest = {\n command,\n sessionId,\n ...(options?.timeoutMs !== undefined && {\n timeoutMs: options.timeoutMs\n }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd })\n };\n\n const response = await this.post<ExecuteResponse>('/api/execute', data);\n\n this.logSuccess(\n 'Command executed',\n `${command}, Success: ${response.success}`\n );\n\n // Call the callback if provided\n this.options.onCommandComplete?.(\n response.success,\n response.exitCode,\n response.stdout,\n response.stderr,\n response.command\n );\n\n return response;\n } catch (error) {\n this.logError('execute', error);\n\n // Call error callback if provided\n this.options.onError?.(\n error instanceof Error ? error.message : String(error),\n command\n );\n\n throw error;\n }\n }\n\n /**\n * Execute a command and return a stream of events\n * @param command - The command to execute\n * @param sessionId - The session ID for this command execution\n * @param options - Optional per-command execution settings\n */\n async executeStream(\n command: string,\n sessionId: string,\n options?: {\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n }\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const data = {\n command,\n sessionId,\n ...(options?.timeoutMs !== undefined && {\n timeoutMs: options.timeoutMs\n }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd })\n };\n\n // Use doStreamFetch which handles both WebSocket and HTTP streaming\n const stream = await this.doStreamFetch('/api/execute/stream', data);\n\n this.logSuccess('Command stream started', command);\n\n return stream;\n } catch (error) {\n this.logError('executeStream', error);\n\n // Call error callback if provided\n this.options.onError?.(\n error instanceof Error ? error.message : String(error),\n command\n );\n\n throw error;\n }\n }\n}\n","import type {\n DeleteFileResult,\n FileExistsResult,\n ListFilesOptions,\n ListFilesResult,\n MkdirResult,\n MoveFileResult,\n ReadFileResult,\n RenameFileResult,\n WriteFileResult\n} from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { HttpClientOptions, SessionRequest } from './types';\n\n/**\n * Request interface for creating directories\n */\nexport interface MkdirRequest extends SessionRequest {\n path: string;\n recursive?: boolean;\n}\n\n/**\n * Request interface for writing files\n */\nexport interface WriteFileRequest extends SessionRequest {\n path: string;\n content: string;\n encoding?: string;\n}\n\n/**\n * Request interface for reading files\n */\nexport interface ReadFileRequest extends SessionRequest {\n path: string;\n encoding?: string;\n}\n\n/**\n * Request interface for file operations (delete, rename, move)\n */\nexport interface FileOperationRequest extends SessionRequest {\n path: string;\n newPath?: string; // For rename/move operations\n}\n\n/**\n * Client for file system operations\n */\nexport class FileClient extends BaseHttpClient {\n /**\n * Create a directory\n * @param path - Directory path to create\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (recursive)\n */\n async mkdir(\n path: string,\n sessionId: string,\n options?: { recursive?: boolean }\n ): Promise<MkdirResult> {\n try {\n const data = {\n path,\n sessionId,\n recursive: options?.recursive ?? false\n };\n\n const response = await this.post<MkdirResult>('/api/mkdir', data);\n\n this.logSuccess(\n 'Directory created',\n `${path} (recursive: ${data.recursive})`\n );\n return response;\n } catch (error) {\n this.logError('mkdir', error);\n throw error;\n }\n }\n\n /**\n * Write content to a file\n * @param path - File path to write to\n * @param content - Content to write\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (encoding)\n */\n async writeFile(\n path: string,\n content: string,\n sessionId: string,\n options?: { encoding?: string }\n ): Promise<WriteFileResult> {\n try {\n const data = {\n path,\n content,\n sessionId,\n encoding: options?.encoding\n };\n\n const response = await this.post<WriteFileResult>('/api/write', data);\n\n this.logSuccess('File written', `${path} (${content.length} chars)`);\n return response;\n } catch (error) {\n this.logError('writeFile', error);\n throw error;\n }\n }\n\n /**\n * Read content from a file\n * @param path - File path to read from\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (encoding)\n */\n async readFile(\n path: string,\n sessionId: string,\n options?: { encoding?: string }\n ): Promise<ReadFileResult> {\n try {\n const data = {\n path,\n sessionId,\n encoding: options?.encoding\n };\n\n const response = await this.post<ReadFileResult>('/api/read', data);\n\n this.logSuccess(\n 'File read',\n `${path} (${response.content.length} chars)`\n );\n return response;\n } catch (error) {\n this.logError('readFile', error);\n throw error;\n }\n }\n\n /**\n * Stream a file using Server-Sent Events\n * Returns a ReadableStream of SSE events containing metadata, chunks, and completion\n * @param path - File path to stream\n * @param sessionId - The session ID for this operation\n */\n async readFileStream(\n path: string,\n sessionId: string\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const data = {\n path,\n sessionId\n };\n\n // Use doStreamFetch which handles both WebSocket and HTTP streaming\n const stream = await this.doStreamFetch('/api/read/stream', data);\n this.logSuccess('File stream started', path);\n return stream;\n } catch (error) {\n this.logError('readFileStream', error);\n throw error;\n }\n }\n\n /**\n * Delete a file\n * @param path - File path to delete\n * @param sessionId - The session ID for this operation\n */\n async deleteFile(path: string, sessionId: string): Promise<DeleteFileResult> {\n try {\n const data = { path, sessionId };\n\n const response = await this.post<DeleteFileResult>('/api/delete', data);\n\n this.logSuccess('File deleted', path);\n return response;\n } catch (error) {\n this.logError('deleteFile', error);\n throw error;\n }\n }\n\n /**\n * Rename a file\n * @param path - Current file path\n * @param newPath - New file path\n * @param sessionId - The session ID for this operation\n */\n async renameFile(\n path: string,\n newPath: string,\n sessionId: string\n ): Promise<RenameFileResult> {\n try {\n const data = { oldPath: path, newPath, sessionId };\n\n const response = await this.post<RenameFileResult>('/api/rename', data);\n\n this.logSuccess('File renamed', `${path} -> ${newPath}`);\n return response;\n } catch (error) {\n this.logError('renameFile', error);\n throw error;\n }\n }\n\n /**\n * Move a file\n * @param path - Current file path\n * @param newPath - Destination file path\n * @param sessionId - The session ID for this operation\n */\n async moveFile(\n path: string,\n newPath: string,\n sessionId: string\n ): Promise<MoveFileResult> {\n try {\n const data = { sourcePath: path, destinationPath: newPath, sessionId };\n\n const response = await this.post<MoveFileResult>('/api/move', data);\n\n this.logSuccess('File moved', `${path} -> ${newPath}`);\n return response;\n } catch (error) {\n this.logError('moveFile', error);\n throw error;\n }\n }\n\n /**\n * List files in a directory\n * @param path - Directory path to list\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (recursive, includeHidden)\n */\n async listFiles(\n path: string,\n sessionId: string,\n options?: ListFilesOptions\n ): Promise<ListFilesResult> {\n try {\n const data = {\n path,\n sessionId,\n options: options || {}\n };\n\n const response = await this.post<ListFilesResult>(\n '/api/list-files',\n data\n );\n\n this.logSuccess('Files listed', `${path} (${response.count} files)`);\n return response;\n } catch (error) {\n this.logError('listFiles', error);\n throw error;\n }\n }\n\n /**\n * Check if a file or directory exists\n * @param path - Path to check\n * @param sessionId - The session ID for this operation\n */\n async exists(path: string, sessionId: string): Promise<FileExistsResult> {\n try {\n const data = {\n path,\n sessionId\n };\n\n const response = await this.post<FileExistsResult>('/api/exists', data);\n\n this.logSuccess(\n 'Path existence checked',\n `${path} (exists: ${response.exists})`\n );\n return response;\n } catch (error) {\n this.logError('exists', error);\n throw error;\n }\n }\n}\n","import type { GitCheckoutResult } from '@repo/shared';\nimport { GitLogger } from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { HttpClientOptions, SessionRequest } from './types';\n\n// Re-export for convenience\nexport type { GitCheckoutResult };\n\n/**\n * Request interface for Git checkout operations\n */\nexport interface GitCheckoutRequest extends SessionRequest {\n repoUrl: string;\n branch?: string;\n targetDir?: string;\n}\n\n/**\n * Client for Git repository operations\n */\nexport class GitClient extends BaseHttpClient {\n constructor(options: HttpClientOptions = {}) {\n super(options);\n // Wrap logger with GitLogger to auto-redact credentials\n this.logger = new GitLogger(this.logger);\n }\n\n /**\n * Clone a Git repository\n * @param repoUrl - URL of the Git repository to clone\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (branch, targetDir)\n */\n async checkout(\n repoUrl: string,\n sessionId: string,\n options?: {\n branch?: string;\n targetDir?: string;\n }\n ): Promise<GitCheckoutResult> {\n try {\n // Determine target directory - use provided path or generate from repo name\n let targetDir = options?.targetDir;\n if (!targetDir) {\n const repoName = this.extractRepoName(repoUrl);\n // Ensure absolute path in /workspace\n targetDir = `/workspace/${repoName}`;\n }\n\n const data: GitCheckoutRequest = {\n repoUrl,\n sessionId,\n targetDir\n };\n\n // Only include branch if explicitly specified\n // This allows Git to use the repository's default branch\n if (options?.branch) {\n data.branch = options.branch;\n }\n\n const response = await this.post<GitCheckoutResult>(\n '/api/git/checkout',\n data\n );\n\n this.logSuccess(\n 'Repository cloned',\n `${repoUrl} (branch: ${response.branch}) -> ${response.targetDir}`\n );\n\n return response;\n } catch (error) {\n this.logError('checkout', error);\n throw error;\n }\n }\n\n /**\n * Extract repository name from URL for default directory name\n */\n private extractRepoName(repoUrl: string): string {\n try {\n const url = new URL(repoUrl);\n const pathParts = url.pathname.split('/');\n const repoName = pathParts[pathParts.length - 1];\n\n // Remove .git extension if present\n return repoName.replace(/\\.git$/, '');\n } catch {\n // Fallback for invalid URLs\n const parts = repoUrl.split('/');\n const repoName = parts[parts.length - 1];\n return repoName.replace(/\\.git$/, '') || 'repo';\n }\n }\n}\n","import {\n type CodeContext,\n type ContextCreateResult,\n type ContextListResult,\n type CreateContextOptions,\n type ExecutionError,\n type OutputMessage,\n type Result,\n ResultImpl\n} from '@repo/shared';\nimport type { ErrorResponse } from '../errors';\nimport {\n createErrorFromResponse,\n ErrorCode,\n InterpreterNotReadyError\n} from '../errors';\nimport { BaseHttpClient } from './base-client.js';\nimport type { HttpClientOptions } from './types.js';\n\n// Streaming execution data from the server\ninterface StreamingExecutionData {\n type: 'result' | 'stdout' | 'stderr' | 'error' | 'execution_complete';\n text?: string;\n html?: string;\n png?: string; // base64\n jpeg?: string; // base64\n svg?: string;\n latex?: string;\n markdown?: string;\n javascript?: string;\n json?: unknown;\n chart?: {\n type:\n | 'line'\n | 'bar'\n | 'scatter'\n | 'pie'\n | 'histogram'\n | 'heatmap'\n | 'unknown';\n data: unknown;\n options?: unknown;\n };\n data?: unknown;\n metadata?: Record<string, unknown>;\n execution_count?: number;\n ename?: string;\n evalue?: string;\n traceback?: string[];\n lineNumber?: number;\n timestamp?: number;\n}\n\nexport interface ExecutionCallbacks {\n onStdout?: (output: OutputMessage) => void | Promise<void>;\n onStderr?: (output: OutputMessage) => void | Promise<void>;\n onResult?: (result: Result) => void | Promise<void>;\n onError?: (error: ExecutionError) => void | Promise<void>;\n}\n\nexport class InterpreterClient extends BaseHttpClient {\n private readonly maxRetries = 3;\n private readonly retryDelayMs = 1000;\n\n async createCodeContext(\n options: CreateContextOptions = {}\n ): Promise<CodeContext> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch('/api/contexts', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n language: options.language || 'python',\n cwd: options.cwd || '/workspace',\n env_vars: options.envVars\n })\n });\n\n if (!response.ok) {\n const error = await this.parseErrorResponse(response);\n throw error;\n }\n\n const data = (await response.json()) as ContextCreateResult;\n if (!data.success) {\n throw new Error(`Failed to create context: ${JSON.stringify(data)}`);\n }\n\n return {\n id: data.contextId,\n language: data.language,\n cwd: data.cwd || '/workspace',\n createdAt: new Date(data.timestamp),\n lastUsed: new Date(data.timestamp)\n };\n });\n }\n\n async runCodeStream(\n contextId: string | undefined,\n code: string,\n language: string | undefined,\n callbacks: ExecutionCallbacks,\n timeoutMs?: number\n ): Promise<void> {\n return this.executeWithRetry(async () => {\n // Use doStreamFetch which handles both WebSocket and HTTP streaming\n const stream = await this.doStreamFetch('/api/execute/code', {\n context_id: contextId,\n code,\n language,\n ...(timeoutMs !== undefined && { timeout_ms: timeoutMs })\n });\n\n // Process streaming response\n for await (const chunk of this.readLines(stream)) {\n await this.parseExecutionResult(chunk, callbacks);\n }\n });\n }\n\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch('/api/contexts', {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' }\n });\n\n if (!response.ok) {\n const error = await this.parseErrorResponse(response);\n throw error;\n }\n\n const data = (await response.json()) as ContextListResult;\n if (!data.success) {\n throw new Error(`Failed to list contexts: ${JSON.stringify(data)}`);\n }\n\n return data.contexts.map((ctx) => ({\n id: ctx.id,\n language: ctx.language,\n cwd: ctx.cwd || '/workspace',\n createdAt: new Date(data.timestamp),\n lastUsed: new Date(data.timestamp)\n }));\n });\n }\n\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch(`/api/contexts/${contextId}`, {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' }\n });\n\n if (!response.ok) {\n const error = await this.parseErrorResponse(response);\n throw error;\n }\n });\n }\n\n /**\n * Get a raw stream for code execution.\n * Used by CodeInterpreter.runCodeStreaming() for direct stream access.\n */\n async streamCode(\n contextId: string,\n code: string,\n language?: string\n ): Promise<ReadableStream<Uint8Array>> {\n return this.doStreamFetch('/api/execute/code', {\n context_id: contextId,\n code,\n language\n });\n }\n\n /**\n * Execute an operation with automatic retry for transient errors\n */\n private async executeWithRetry<T>(operation: () => Promise<T>): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n this.logError('executeWithRetry', error);\n lastError = error as Error;\n\n // Check if it's a retryable error (interpreter not ready)\n if (this.isRetryableError(error)) {\n // Don't retry on the last attempt\n if (attempt < this.maxRetries - 1) {\n // Exponential backoff with jitter\n const delay =\n this.retryDelayMs * 2 ** attempt + Math.random() * 1000;\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n }\n\n // Not retryable or last attempt - throw the error\n throw error;\n }\n }\n\n throw lastError || new Error('Execution failed after retries');\n }\n\n private isRetryableError(error: unknown): boolean {\n if (error instanceof InterpreterNotReadyError) {\n return true;\n }\n\n if (error instanceof Error) {\n return (\n error.message.includes('not ready') ||\n error.message.includes('initializing')\n );\n }\n\n return false;\n }\n\n private async parseErrorResponse(response: Response): Promise<Error> {\n try {\n const errorData = (await response.json()) as ErrorResponse;\n return createErrorFromResponse(errorData);\n } catch {\n // Fallback if response isn't JSON\n const errorResponse: ErrorResponse = {\n code: ErrorCode.INTERNAL_ERROR,\n message: `HTTP ${response.status}: ${response.statusText}`,\n context: {},\n httpStatus: response.status,\n timestamp: new Date().toISOString()\n };\n return createErrorFromResponse(errorResponse);\n }\n }\n\n private async *readLines(\n stream: ReadableStream<Uint8Array>\n ): AsyncGenerator<string> {\n const reader = stream.getReader();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (value) {\n buffer += new TextDecoder().decode(value);\n }\n if (done) break;\n\n let newlineIdx = buffer.indexOf('\\n');\n while (newlineIdx !== -1) {\n yield buffer.slice(0, newlineIdx);\n buffer = buffer.slice(newlineIdx + 1);\n newlineIdx = buffer.indexOf('\\n');\n }\n }\n\n // Yield any remaining data\n if (buffer.length > 0) {\n yield buffer;\n }\n } finally {\n // Cancel the stream first to properly terminate HTTP connections when breaking early\n try {\n await reader.cancel();\n } catch {\n // Ignore cancel errors (stream may already be closed)\n }\n reader.releaseLock();\n }\n }\n\n private async parseExecutionResult(\n line: string,\n callbacks: ExecutionCallbacks\n ) {\n if (!line.trim()) return;\n\n // Skip lines that don't start with \"data: \" (SSE format)\n if (!line.startsWith('data: ')) return;\n\n try {\n // Strip \"data: \" prefix and parse JSON\n const jsonData = line.substring(6); // \"data: \" is 6 characters\n const data = JSON.parse(jsonData) as StreamingExecutionData;\n\n switch (data.type) {\n case 'stdout':\n if (callbacks.onStdout && data.text) {\n await callbacks.onStdout({\n text: data.text,\n timestamp: data.timestamp || Date.now()\n });\n }\n break;\n\n case 'stderr':\n if (callbacks.onStderr && data.text) {\n await callbacks.onStderr({\n text: data.text,\n timestamp: data.timestamp || Date.now()\n });\n }\n break;\n\n case 'result':\n if (callbacks.onResult) {\n // Create a ResultImpl instance from the raw data\n const result = new ResultImpl(data);\n await callbacks.onResult(result);\n }\n break;\n\n case 'error':\n if (callbacks.onError) {\n await callbacks.onError({\n name: data.ename || 'Error',\n message: data.evalue || 'Unknown error',\n traceback: data.traceback || []\n });\n }\n break;\n\n case 'execution_complete':\n // Signal completion - callbacks can handle cleanup if needed\n break;\n }\n } catch (error) {\n this.logError('parseExecutionResult', error);\n }\n }\n}\n","import type {\n PortCloseResult,\n PortExposeResult,\n PortListResult,\n PortWatchRequest\n} from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\n\n// Re-export for convenience\nexport type { PortExposeResult, PortCloseResult, PortListResult };\n\n/**\n * Request interface for exposing ports\n */\nexport interface ExposePortRequest {\n port: number;\n name?: string;\n}\n\n/**\n * Request interface for unexposing ports\n */\nexport interface UnexposePortRequest {\n port: number;\n}\n\n/**\n * Client for port management and preview URL operations\n */\nexport class PortClient extends BaseHttpClient {\n /**\n * Expose a port and get a preview URL\n * @param port - Port number to expose\n * @param sessionId - The session ID for this operation\n * @param name - Optional name for the port\n */\n async exposePort(\n port: number,\n sessionId: string,\n name?: string\n ): Promise<PortExposeResult> {\n try {\n const data = { port, sessionId, name };\n\n const response = await this.post<PortExposeResult>(\n '/api/expose-port',\n data\n );\n\n this.logSuccess(\n 'Port exposed',\n `${port} exposed at ${response.url}${name ? ` (${name})` : ''}`\n );\n\n return response;\n } catch (error) {\n this.logError('exposePort', error);\n throw error;\n }\n }\n\n /**\n * Unexpose a port and remove its preview URL\n * @param port - Port number to unexpose\n * @param sessionId - The session ID for this operation\n */\n async unexposePort(\n port: number,\n sessionId: string\n ): Promise<PortCloseResult> {\n try {\n const url = `/api/exposed-ports/${port}?session=${encodeURIComponent(\n sessionId\n )}`;\n const response = await this.delete<PortCloseResult>(url);\n\n this.logSuccess('Port unexposed', `${port}`);\n return response;\n } catch (error) {\n this.logError('unexposePort', error);\n throw error;\n }\n }\n\n /**\n * Get all currently exposed ports\n * @param sessionId - The session ID for this operation\n */\n async getExposedPorts(sessionId: string): Promise<PortListResult> {\n try {\n const url = `/api/exposed-ports?session=${encodeURIComponent(sessionId)}`;\n const response = await this.get<PortListResult>(url);\n\n this.logSuccess(\n 'Exposed ports retrieved',\n `${response.ports.length} ports exposed`\n );\n\n return response;\n } catch (error) {\n this.logError('getExposedPorts', error);\n throw error;\n }\n }\n\n /**\n * Watch a port for readiness via SSE stream\n * @param request - Port watch configuration\n * @returns SSE stream that emits PortWatchEvent objects\n */\n async watchPort(\n request: PortWatchRequest\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const stream = await this.doStreamFetch('/api/port-watch', request);\n this.logSuccess('Port watch started', `port ${request.port}`);\n return stream;\n } catch (error) {\n this.logError('watchPort', error);\n throw error;\n }\n }\n}\n","import type {\n ProcessCleanupResult,\n ProcessInfoResult,\n ProcessKillResult,\n ProcessListResult,\n ProcessLogsResult,\n ProcessStartResult,\n StartProcessRequest\n} from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { HttpClientOptions } from './types';\n\n// Re-export for convenience\nexport type {\n StartProcessRequest,\n ProcessStartResult,\n ProcessListResult,\n ProcessInfoResult,\n ProcessKillResult,\n ProcessLogsResult,\n ProcessCleanupResult\n};\n\n/**\n * Client for background process management\n */\nexport class ProcessClient extends BaseHttpClient {\n /**\n * Start a background process\n * @param command - Command to execute as a background process\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (processId)\n */\n async startProcess(\n command: string,\n sessionId: string,\n options?: {\n processId?: string;\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n }\n ): Promise<ProcessStartResult> {\n try {\n const data: StartProcessRequest = {\n command,\n sessionId,\n ...(options?.processId !== undefined && {\n processId: options.processId\n }),\n ...(options?.timeoutMs !== undefined && {\n timeoutMs: options.timeoutMs\n }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(options?.encoding !== undefined && { encoding: options.encoding }),\n ...(options?.autoCleanup !== undefined && {\n autoCleanup: options.autoCleanup\n })\n };\n\n const response = await this.post<ProcessStartResult>(\n '/api/process/start',\n data\n );\n\n this.logSuccess(\n 'Process started',\n `${command} (ID: ${response.processId})`\n );\n\n return response;\n } catch (error) {\n this.logError('startProcess', error);\n throw error;\n }\n }\n\n /**\n * List all processes (sandbox-scoped, not session-scoped)\n */\n async listProcesses(): Promise<ProcessListResult> {\n try {\n const url = `/api/process/list`;\n const response = await this.get<ProcessListResult>(url);\n\n this.logSuccess(\n 'Processes listed',\n `${response.processes.length} processes`\n );\n return response;\n } catch (error) {\n this.logError('listProcesses', error);\n throw error;\n }\n }\n\n /**\n * Get information about a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to retrieve\n */\n async getProcess(processId: string): Promise<ProcessInfoResult> {\n try {\n const url = `/api/process/${processId}`;\n const response = await this.get<ProcessInfoResult>(url);\n\n this.logSuccess('Process retrieved', `ID: ${processId}`);\n return response;\n } catch (error) {\n this.logError('getProcess', error);\n throw error;\n }\n }\n\n /**\n * Kill a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to kill\n */\n async killProcess(processId: string): Promise<ProcessKillResult> {\n try {\n const url = `/api/process/${processId}`;\n const response = await this.delete<ProcessKillResult>(url);\n\n this.logSuccess('Process killed', `ID: ${processId}`);\n return response;\n } catch (error) {\n this.logError('killProcess', error);\n throw error;\n }\n }\n\n /**\n * Kill all running processes (sandbox-scoped, not session-scoped)\n */\n async killAllProcesses(): Promise<ProcessCleanupResult> {\n try {\n const url = `/api/process/kill-all`;\n const response = await this.delete<ProcessCleanupResult>(url);\n\n this.logSuccess(\n 'All processes killed',\n `${response.cleanedCount} processes terminated`\n );\n\n return response;\n } catch (error) {\n this.logError('killAllProcesses', error);\n throw error;\n }\n }\n\n /**\n * Get logs from a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to get logs from\n */\n async getProcessLogs(processId: string): Promise<ProcessLogsResult> {\n try {\n const url = `/api/process/${processId}/logs`;\n const response = await this.get<ProcessLogsResult>(url);\n\n this.logSuccess(\n 'Process logs retrieved',\n `ID: ${processId}, stdout: ${response.stdout.length} chars, stderr: ${response.stderr.length} chars`\n );\n\n return response;\n } catch (error) {\n this.logError('getProcessLogs', error);\n throw error;\n }\n }\n\n /**\n * Stream logs from a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to stream logs from\n */\n async streamProcessLogs(\n processId: string\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const url = `/api/process/${processId}/stream`;\n // Use doStreamFetch with GET method (process log streaming is GET)\n const stream = await this.doStreamFetch(url, undefined, 'GET');\n\n this.logSuccess('Process log stream started', `ID: ${processId}`);\n\n return stream;\n } catch (error) {\n this.logError('streamProcessLogs', error);\n throw error;\n }\n }\n}\n","import { BaseHttpClient } from './base-client';\nimport type { BaseApiResponse, HttpClientOptions } from './types';\n\n/**\n * Response interface for ping operations\n */\nexport interface PingResponse extends BaseApiResponse {\n message: string;\n uptime?: number;\n}\n\n/**\n * Response interface for getting available commands\n */\nexport interface CommandsResponse extends BaseApiResponse {\n availableCommands: string[];\n count: number;\n}\n\n/**\n * Response interface for getting container version\n */\nexport interface VersionResponse extends BaseApiResponse {\n version: string;\n}\n\n/**\n * Request interface for creating sessions\n */\nexport interface CreateSessionRequest {\n id: string;\n env?: Record<string, string>;\n cwd?: string;\n}\n\n/**\n * Response interface for creating sessions\n */\nexport interface CreateSessionResponse extends BaseApiResponse {\n id: string;\n message: string;\n}\n\n/**\n * Request interface for deleting sessions\n */\nexport interface DeleteSessionRequest {\n sessionId: string;\n}\n\n/**\n * Response interface for deleting sessions\n */\nexport interface DeleteSessionResponse extends BaseApiResponse {\n sessionId: string;\n}\n\n/**\n * Client for health checks and utility operations\n */\nexport class UtilityClient extends BaseHttpClient {\n /**\n * Ping the sandbox to check if it's responsive\n */\n async ping(): Promise<string> {\n try {\n const response = await this.get<PingResponse>('/api/ping');\n\n this.logSuccess('Ping successful', response.message);\n return response.message;\n } catch (error) {\n this.logError('ping', error);\n throw error;\n }\n }\n\n /**\n * Get list of available commands in the sandbox environment\n */\n async getCommands(): Promise<string[]> {\n try {\n const response = await this.get<CommandsResponse>('/api/commands');\n\n this.logSuccess(\n 'Commands retrieved',\n `${response.count} commands available`\n );\n\n return response.availableCommands;\n } catch (error) {\n this.logError('getCommands', error);\n throw error;\n }\n }\n\n /**\n * Create a new execution session\n * @param options - Session configuration (id, env, cwd)\n */\n async createSession(\n options: CreateSessionRequest\n ): Promise<CreateSessionResponse> {\n try {\n const response = await this.post<CreateSessionResponse>(\n '/api/session/create',\n options\n );\n\n this.logSuccess('Session created', `ID: ${options.id}`);\n return response;\n } catch (error) {\n this.logError('createSession', error);\n throw error;\n }\n }\n\n /**\n * Delete an execution session\n * @param sessionId - Session ID to delete\n */\n async deleteSession(sessionId: string): Promise<DeleteSessionResponse> {\n try {\n const response = await this.post<DeleteSessionResponse>(\n '/api/session/delete',\n { sessionId }\n );\n\n this.logSuccess('Session deleted', `ID: ${sessionId}`);\n return response;\n } catch (error) {\n this.logError('deleteSession', error);\n throw error;\n }\n }\n\n /**\n * Get the container version\n * Returns the version embedded in the Docker image during build\n */\n async getVersion(): Promise<string> {\n try {\n const response = await this.get<VersionResponse>('/api/version');\n\n this.logSuccess('Version retrieved', response.version);\n return response.version;\n } catch (error) {\n // If version endpoint doesn't exist (old container), return 'unknown'\n // This allows for backward compatibility\n this.logger.debug(\n 'Failed to get container version (may be old container)',\n { error }\n );\n return 'unknown';\n }\n }\n}\n","import { CommandClient } from './command-client';\nimport { FileClient } from './file-client';\nimport { GitClient } from './git-client';\nimport { InterpreterClient } from './interpreter-client';\nimport { PortClient } from './port-client';\nimport { ProcessClient } from './process-client';\nimport {\n createTransport,\n type ITransport,\n type TransportMode\n} from './transport';\nimport type { HttpClientOptions } from './types';\nimport { UtilityClient } from './utility-client';\n\n/**\n * Main sandbox client that composes all domain-specific clients\n * Provides organized access to all sandbox functionality\n *\n * Supports two transport modes:\n * - HTTP (default): Each request is a separate HTTP call\n * - WebSocket: All requests multiplexed over a single connection\n *\n * WebSocket mode reduces sub-request count when running inside Workers/Durable Objects.\n */\nexport class SandboxClient {\n public readonly commands: CommandClient;\n public readonly files: FileClient;\n public readonly processes: ProcessClient;\n public readonly ports: PortClient;\n public readonly git: GitClient;\n public readonly interpreter: InterpreterClient;\n public readonly utils: UtilityClient;\n\n private transport: ITransport | null = null;\n\n constructor(options: HttpClientOptions) {\n // Create shared transport if WebSocket mode is enabled\n if (options.transportMode === 'websocket' && options.wsUrl) {\n this.transport = createTransport({\n mode: 'websocket',\n wsUrl: options.wsUrl,\n baseUrl: options.baseUrl,\n logger: options.logger,\n stub: options.stub,\n port: options.port\n });\n }\n\n // Ensure baseUrl is provided for all clients\n const clientOptions: HttpClientOptions = {\n baseUrl: 'http://localhost:3000',\n ...options,\n // Share transport across all clients\n transport: this.transport ?? options.transport\n };\n\n // Initialize all domain clients with shared options\n this.commands = new CommandClient(clientOptions);\n this.files = new FileClient(clientOptions);\n this.processes = new ProcessClient(clientOptions);\n this.ports = new PortClient(clientOptions);\n this.git = new GitClient(clientOptions);\n this.interpreter = new InterpreterClient(clientOptions);\n this.utils = new UtilityClient(clientOptions);\n }\n\n /**\n * Get the current transport mode\n */\n getTransportMode(): TransportMode {\n return this.transport?.getMode() ?? 'http';\n }\n\n /**\n * Check if WebSocket is connected (only relevant in WebSocket mode)\n */\n isWebSocketConnected(): boolean {\n return this.transport?.isConnected() ?? false;\n }\n\n /**\n * Connect WebSocket transport (no-op in HTTP mode)\n * Called automatically on first request, but can be called explicitly\n * to establish connection upfront.\n */\n async connect(): Promise<void> {\n if (this.transport) {\n await this.transport.connect();\n }\n }\n\n /**\n * Disconnect WebSocket transport (no-op in HTTP mode)\n * Should be called when the sandbox is destroyed.\n */\n disconnect(): void {\n if (this.transport) {\n this.transport.disconnect();\n }\n }\n}\n","/**\n * Security utilities for URL construction and input validation\n *\n * This module contains critical security functions to prevent:\n * - URL injection attacks\n * - SSRF (Server-Side Request Forgery) attacks\n * - DNS rebinding attacks\n * - Host header injection\n * - Open redirect vulnerabilities\n */\n\nexport class SecurityError extends Error {\n constructor(\n message: string,\n public readonly code?: string\n ) {\n super(message);\n this.name = 'SecurityError';\n }\n}\n\n/**\n * Validates port numbers for sandbox services\n * Only allows non-system ports to prevent conflicts and security issues\n */\nexport function validatePort(port: number): boolean {\n // Must be a valid integer\n if (!Number.isInteger(port)) {\n return false;\n }\n\n // Only allow non-system ports (1024-65535)\n if (port < 1024 || port > 65535) {\n return false;\n }\n\n // Exclude ports reserved by our system\n const reservedPorts = [\n 3000, // Control plane port\n 8787 // Common wrangler dev port\n ];\n\n if (reservedPorts.includes(port)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Sanitizes and validates sandbox IDs for DNS compliance and security\n * Only enforces critical requirements - allows maximum developer flexibility\n */\nexport function sanitizeSandboxId(id: string): string {\n // Basic validation: not empty, reasonable length limit (DNS subdomain limit is 63 chars)\n if (!id || id.length > 63) {\n throw new SecurityError(\n 'Sandbox ID must be 1-63 characters long.',\n 'INVALID_SANDBOX_ID_LENGTH'\n );\n }\n\n // DNS compliance: cannot start or end with hyphens (RFC requirement)\n if (id.startsWith('-') || id.endsWith('-')) {\n throw new SecurityError(\n 'Sandbox ID cannot start or end with hyphens (DNS requirement).',\n 'INVALID_SANDBOX_ID_HYPHENS'\n );\n }\n\n // Prevent reserved names that cause technical conflicts\n const reservedNames = [\n 'www',\n 'api',\n 'admin',\n 'root',\n 'system',\n 'cloudflare',\n 'workers'\n ];\n\n const lowerCaseId = id.toLowerCase();\n if (reservedNames.includes(lowerCaseId)) {\n throw new SecurityError(\n `Reserved sandbox ID '${id}' is not allowed.`,\n 'RESERVED_SANDBOX_ID'\n );\n }\n\n return id;\n}\n\n/**\n * Validates language for code interpreter\n * Only allows supported languages\n */\nexport function validateLanguage(language: string | undefined): void {\n if (!language) {\n return; // undefined is valid, will default to python\n }\n\n const supportedLanguages = [\n 'python',\n 'python3',\n 'javascript',\n 'js',\n 'node',\n 'typescript',\n 'ts'\n ];\n const normalized = language.toLowerCase();\n\n if (!supportedLanguages.includes(normalized)) {\n throw new SecurityError(\n `Unsupported language '${language}'. Supported languages: python, javascript, typescript`,\n 'INVALID_LANGUAGE'\n );\n }\n}\n","import {\n type CodeContext,\n type CreateContextOptions,\n Execution,\n type ExecutionError,\n type OutputMessage,\n type Result,\n ResultImpl,\n type RunCodeOptions\n} from '@repo/shared';\nimport type { InterpreterClient } from './clients/interpreter-client.js';\nimport type { Sandbox } from './sandbox.js';\nimport { validateLanguage } from './security.js';\n\nexport class CodeInterpreter {\n private interpreterClient: InterpreterClient;\n private contexts = new Map<string, CodeContext>();\n\n constructor(sandbox: Sandbox) {\n // In init-testing architecture, client is a SandboxClient with an interpreter property\n this.interpreterClient = (sandbox.client as any)\n .interpreter as InterpreterClient;\n }\n\n /**\n * Create a new code execution context\n */\n async createCodeContext(\n options: CreateContextOptions = {}\n ): Promise<CodeContext> {\n // Validate language before sending to container\n validateLanguage(options.language);\n\n const context = await this.interpreterClient.createCodeContext(options);\n this.contexts.set(context.id, context);\n return context;\n }\n\n /**\n * Run code with optional context\n */\n async runCode(\n code: string,\n options: RunCodeOptions = {}\n ): Promise<Execution> {\n // Get or create context\n let context = options.context;\n if (!context) {\n // Try to find or create a default context for the language\n const language = options.language || 'python';\n context = await this.getOrCreateDefaultContext(language);\n }\n\n // Create execution object to collect results\n const execution = new Execution(code, context);\n\n // Stream execution\n await this.interpreterClient.runCodeStream(\n context.id,\n code,\n options.language,\n {\n onStdout: (output: OutputMessage) => {\n execution.logs.stdout.push(output.text);\n if (options.onStdout) return options.onStdout(output);\n },\n onStderr: (output: OutputMessage) => {\n execution.logs.stderr.push(output.text);\n if (options.onStderr) return options.onStderr(output);\n },\n onResult: async (result: Result) => {\n execution.results.push(new ResultImpl(result) as any);\n if (options.onResult) return options.onResult(result);\n },\n onError: (error: ExecutionError) => {\n execution.error = error;\n if (options.onError) return options.onError(error);\n }\n }\n );\n\n return execution;\n }\n\n /**\n * Run code and return a streaming response\n */\n async runCodeStream(\n code: string,\n options: RunCodeOptions = {}\n ): Promise<ReadableStream> {\n // Get or create context\n let context = options.context;\n if (!context) {\n const language = options.language || 'python';\n context = await this.getOrCreateDefaultContext(language);\n }\n\n // Use streamCode which handles both HTTP and WebSocket streaming\n return this.interpreterClient.streamCode(\n context.id,\n code,\n options.language\n );\n }\n\n /**\n * List all code contexts\n */\n async listCodeContexts(): Promise<CodeContext[]> {\n const contexts = await this.interpreterClient.listCodeContexts();\n\n // Update local cache\n for (const context of contexts) {\n this.contexts.set(context.id, context);\n }\n\n return contexts;\n }\n\n /**\n * Delete a code context\n */\n async deleteCodeContext(contextId: string): Promise<void> {\n await this.interpreterClient.deleteCodeContext(contextId);\n this.contexts.delete(contextId);\n }\n\n private async getOrCreateDefaultContext(\n language: 'python' | 'javascript' | 'typescript'\n ): Promise<CodeContext> {\n // Check if we have a cached context for this language\n for (const context of this.contexts.values()) {\n if (context.language === language) {\n return context;\n }\n }\n\n // Create new default context\n return this.createCodeContext({ language });\n }\n}\n","import { switchPort } from '@cloudflare/containers';\nimport { createLogger, type LogContext, TraceContext } from '@repo/shared';\nimport { getSandbox, type Sandbox } from './sandbox';\nimport { sanitizeSandboxId, validatePort } from './security';\n\nexport interface SandboxEnv<T extends Sandbox<any> = Sandbox<any>> {\n Sandbox: DurableObjectNamespace<T>;\n}\n\nexport interface RouteInfo {\n port: number;\n sandboxId: string;\n path: string;\n token: string;\n}\n\nexport async function proxyToSandbox<\n T extends Sandbox<any>,\n E extends SandboxEnv<T>\n>(request: Request, env: E): Promise<Response | null> {\n // Create logger context for this request\n const traceId =\n TraceContext.fromHeaders(request.headers) || TraceContext.generate();\n const logger = createLogger({\n component: 'sandbox-do',\n traceId,\n operation: 'proxy'\n });\n\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, token } = routeInfo;\n // Preview URLs always use normalized (lowercase) IDs\n const sandbox = getSandbox(env.Sandbox, sandboxId, { normalizeId: true });\n\n // Critical security check: Validate token (mandatory for all user ports)\n // Skip check for control plane port 3000\n if (port !== 3000) {\n // Validate the token matches the port\n const isValidToken = await sandbox.validatePortToken(port, token);\n if (!isValidToken) {\n logger.warn('Invalid token access blocked', {\n port,\n sandboxId,\n path,\n hostname: url.hostname,\n url: request.url,\n method: request.method,\n userAgent: request.headers.get('User-Agent') || 'unknown'\n });\n\n return new Response(\n JSON.stringify({\n error: `Access denied: Invalid token or port not exposed`,\n code: 'INVALID_TOKEN'\n }),\n {\n status: 404,\n headers: {\n 'Content-Type': 'application/json'\n }\n }\n );\n }\n }\n\n // Detect WebSocket upgrade request\n const upgradeHeader = request.headers.get('Upgrade');\n if (upgradeHeader?.toLowerCase() === 'websocket') {\n // WebSocket path: Must use fetch() not containerFetch()\n // This bypasses JSRPC serialization boundary which cannot handle WebSocket upgrades\n return await sandbox.fetch(switchPort(request, port));\n }\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 // @ts-expect-error - duplex required for body streaming in modern runtimes\n duplex: 'half'\n });\n\n return await sandbox.containerFetch(proxyRequest, port);\n } catch (error) {\n logger.error(\n 'Proxy routing error',\n error instanceof Error ? error : new Error(String(error))\n );\n return new Response('Proxy routing error', { status: 500 });\n }\n}\n\nfunction extractSandboxRoute(url: URL): RouteInfo | null {\n // Parse subdomain pattern: port-sandboxId-token.domain (tokens mandatory)\n // Token is always exactly 16 chars (generated by generatePortToken)\n const subdomainMatch = url.hostname.match(\n /^(\\d{4,5})-([^.-][^.]*?[^.-]|[^.-])-([a-z0-9_-]{16})\\.(.+)$/\n );\n\n if (!subdomainMatch) {\n return null;\n }\n\n const portStr = subdomainMatch[1];\n const sandboxId = subdomainMatch[2];\n const token = subdomainMatch[3]; // Mandatory token\n const domain = subdomainMatch[4];\n\n const port = parseInt(portStr, 10);\n if (!validatePort(port)) {\n return null;\n }\n\n let sanitizedSandboxId: string;\n try {\n sanitizedSandboxId = sanitizeSandboxId(sandboxId);\n } catch (error) {\n return null;\n }\n\n // DNS subdomain length limit is 63 characters\n if (sandboxId.length > 63) {\n return null;\n }\n\n return {\n port,\n sandboxId: sanitizedSandboxId,\n path: url.pathname || '/',\n token\n };\n}\n\nexport function isLocalhostPattern(hostname: string): boolean {\n // Handle IPv6 addresses in brackets (with or without port)\n if (hostname.startsWith('[')) {\n if (hostname.includes(']:')) {\n // [::1]:port format\n const ipv6Part = hostname.substring(0, hostname.indexOf(']:') + 1);\n return ipv6Part === '[::1]';\n } else {\n // [::1] format without port\n return hostname === '[::1]';\n }\n }\n\n // Handle bare IPv6 without brackets\n if (hostname === '::1') {\n return true;\n }\n\n // For IPv4 and regular hostnames, split on colon to remove port\n const hostPart = hostname.split(':')[0];\n\n return (\n hostPart === 'localhost' ||\n hostPart === '127.0.0.1' ||\n hostPart === '0.0.0.0'\n );\n}\n","/**\n * Server-Sent Events (SSE) parser for streaming responses\n * Converts ReadableStream<Uint8Array> to typed AsyncIterable<T>\n */\n\n/**\n * Parse a ReadableStream of SSE events into typed AsyncIterable\n * @param stream - The ReadableStream from fetch response\n * @param signal - Optional AbortSignal for cancellation\n */\nexport async function* parseSSEStream<T>(\n stream: ReadableStream<Uint8Array>,\n signal?: AbortSignal\n): AsyncIterable<T> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n // Check for cancellation\n if (signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n const { done, value } = await reader.read();\n if (done) break;\n\n // Decode chunk and add to buffer\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events in buffer\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n // Skip empty lines\n if (line.trim() === '') continue;\n\n // Process SSE data lines\n if (line.startsWith('data: ')) {\n const data = line.substring(6);\n\n // Skip [DONE] markers or empty data\n if (data === '[DONE]' || data.trim() === '') continue;\n\n try {\n const event = JSON.parse(data) as T;\n yield event;\n } catch {\n // Skip invalid JSON events and continue processing\n }\n }\n // Handle other SSE fields if needed (event:, id:, retry:)\n // For now, we only care about data: lines\n }\n }\n\n // Process any remaining data in buffer\n if (buffer.trim() && buffer.startsWith('data: ')) {\n const data = buffer.substring(6);\n if (data !== '[DONE]' && data.trim()) {\n try {\n const event = JSON.parse(data) as T;\n yield event;\n } catch {\n // Skip invalid JSON in final event\n }\n }\n }\n } finally {\n // Clean up resources\n try {\n await reader.cancel();\n } catch {}\n reader.releaseLock();\n }\n}\n\n/**\n * Helper to convert a Response with SSE stream directly to AsyncIterable\n * @param response - Response object with SSE stream\n * @param signal - Optional AbortSignal for cancellation\n */\nexport async function* responseToAsyncIterable<T>(\n response: Response,\n signal?: AbortSignal\n): AsyncIterable<T> {\n if (!response.ok) {\n throw new Error(\n `Response not ok: ${response.status} ${response.statusText}`\n );\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n yield* parseSSEStream<T>(response.body, signal);\n}\n\n/**\n * Create an SSE-formatted ReadableStream from an AsyncIterable\n * (Useful for Worker endpoints that need to forward AsyncIterable as SSE)\n * @param events - AsyncIterable of events\n * @param options - Stream options\n */\nexport function asyncIterableToSSEStream<T>(\n events: AsyncIterable<T>,\n options?: {\n signal?: AbortSignal;\n serialize?: (event: T) => string;\n }\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const serialize = options?.serialize || JSON.stringify;\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const event of events) {\n if (options?.signal?.aborted) {\n controller.error(new Error('Operation was aborted'));\n break;\n }\n\n const data = serialize(event);\n const sseEvent = `data: ${data}\\n\\n`;\n controller.enqueue(encoder.encode(sseEvent));\n }\n\n // Send completion marker\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'));\n } catch (error) {\n controller.error(error);\n } finally {\n controller.close();\n }\n },\n\n cancel() {\n // Handle stream cancellation\n }\n });\n}\n","/**\n * Bucket mounting error classes\n *\n * These are SDK-side validation errors that follow the same pattern as SecurityError.\n * They are thrown before any container interaction occurs.\n */\n\nimport { ErrorCode } from '@repo/shared/errors';\n\n/**\n * Base error for bucket mounting operations\n */\nexport class BucketMountError extends Error {\n public readonly code: ErrorCode;\n\n constructor(message: string, code: ErrorCode = ErrorCode.BUCKET_MOUNT_ERROR) {\n super(message);\n this.name = 'BucketMountError';\n this.code = code;\n }\n}\n\n/**\n * Thrown when S3FS mount command fails\n */\nexport class S3FSMountError extends BucketMountError {\n constructor(message: string) {\n super(message, ErrorCode.S3FS_MOUNT_ERROR);\n this.name = 'S3FSMountError';\n }\n}\n\n/**\n * Thrown when no credentials found in environment\n */\nexport class MissingCredentialsError extends BucketMountError {\n constructor(message: string) {\n super(message, ErrorCode.MISSING_CREDENTIALS);\n this.name = 'MissingCredentialsError';\n }\n}\n\n/**\n * Thrown when bucket name, mount path, or options are invalid\n */\nexport class InvalidMountConfigError extends BucketMountError {\n constructor(message: string) {\n super(message, ErrorCode.INVALID_MOUNT_CONFIG);\n this.name = 'InvalidMountConfigError';\n }\n}\n","import type { BucketCredentials, MountBucketOptions } from '@repo/shared';\nimport { MissingCredentialsError } from './errors';\n\n/**\n * Detect credentials for bucket mounting from environment variables\n * Priority order:\n * 1. Explicit options.credentials\n * 2. Standard AWS env vars: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY\n * 3. Error: no credentials found\n *\n * @param options - Mount options\n * @param envVars - Environment variables\n * @returns Detected credentials\n * @throws MissingCredentialsError if no credentials found\n */\nexport function detectCredentials(\n options: MountBucketOptions,\n envVars: Record<string, string | undefined>\n): BucketCredentials {\n // Priority 1: Explicit credentials in options\n if (options.credentials) {\n return options.credentials;\n }\n\n // Priority 2: Standard AWS env vars\n const awsAccessKeyId = envVars.AWS_ACCESS_KEY_ID;\n const awsSecretAccessKey = envVars.AWS_SECRET_ACCESS_KEY;\n\n if (awsAccessKeyId && awsSecretAccessKey) {\n return {\n accessKeyId: awsAccessKeyId,\n secretAccessKey: awsSecretAccessKey\n };\n }\n\n // No credentials found - throw error with helpful message\n throw new MissingCredentialsError(\n `No credentials found. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY ` +\n `environment variables, or pass explicit credentials in options.`\n );\n}\n","/**\n * Provider detection and s3fs flag configuration\n *\n * Based on s3fs-fuse documentation:\n * https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3\n */\n\nimport type { BucketProvider } from '@repo/shared';\n\n/**\n * Detect provider from endpoint URL using pattern matching\n */\nexport function detectProviderFromUrl(endpoint: string): BucketProvider | null {\n try {\n const url = new URL(endpoint);\n const hostname = url.hostname.toLowerCase();\n\n if (hostname.endsWith('.r2.cloudflarestorage.com')) {\n return 'r2';\n }\n\n // Match AWS S3: *.amazonaws.com or s3.amazonaws.com\n if (\n hostname.endsWith('.amazonaws.com') ||\n hostname === 's3.amazonaws.com'\n ) {\n return 's3';\n }\n\n if (hostname === 'storage.googleapis.com') {\n return 'gcs';\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get s3fs flags for a given provider\n *\n * Based on s3fs-fuse wiki recommendations:\n * https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3\n */\nexport function getProviderFlags(provider: BucketProvider | null): string[] {\n if (!provider) {\n return ['use_path_request_style'];\n }\n\n switch (provider) {\n case 'r2':\n return ['nomixupload'];\n\n case 's3':\n return [];\n\n case 'gcs':\n return [];\n\n default:\n return ['use_path_request_style'];\n }\n}\n\n/**\n * Resolve s3fs options by combining provider defaults with user overrides\n */\nexport function resolveS3fsOptions(\n provider: BucketProvider | null,\n userOptions?: string[]\n): string[] {\n const providerFlags = getProviderFlags(provider);\n\n if (!userOptions || userOptions.length === 0) {\n return providerFlags;\n }\n\n // Merge provider flags with user options\n // User options take precedence (come last in the array)\n const allFlags = [...providerFlags, ...userOptions];\n\n // Deduplicate flags (keep last occurrence)\n const flagMap = new Map<string, string>();\n\n for (const flag of allFlags) {\n // Split on '=' to get the flag name\n const [flagName] = flag.split('=');\n flagMap.set(flagName, flag);\n }\n\n return Array.from(flagMap.values());\n}\n","/**\n * SDK version - automatically synchronized with package.json by Changesets\n * This file is auto-updated by .github/changeset-version.ts during releases\n * DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump\n */\nexport const SDK_VERSION = '0.6.7';\n","import { Container, getContainer, switchPort } from '@cloudflare/containers';\nimport type {\n BucketCredentials,\n BucketProvider,\n CodeContext,\n CreateContextOptions,\n ExecEvent,\n ExecOptions,\n ExecResult,\n ExecutionResult,\n ExecutionSession,\n ISandbox,\n LogEvent,\n MountBucketOptions,\n PortWatchEvent,\n Process,\n ProcessOptions,\n ProcessStatus,\n RunCodeOptions,\n SandboxOptions,\n SessionOptions,\n StreamOptions,\n WaitForExitResult,\n WaitForLogResult,\n WaitForPortOptions\n} from '@repo/shared';\nimport {\n createLogger,\n getEnvString,\n isTerminalStatus,\n type SessionDeleteResult,\n shellEscape,\n TraceContext\n} from '@repo/shared';\nimport { type ExecuteResponse, SandboxClient } from './clients';\nimport type { ErrorResponse } from './errors';\nimport {\n CustomDomainRequiredError,\n ErrorCode,\n ProcessExitedBeforeReadyError,\n ProcessReadyTimeoutError,\n SessionAlreadyExistsError\n} from './errors';\nimport { CodeInterpreter } from './interpreter';\nimport { isLocalhostPattern } from './request-handler';\nimport { SecurityError, sanitizeSandboxId, validatePort } from './security';\nimport { parseSSEStream } from './sse-parser';\nimport {\n detectCredentials,\n detectProviderFromUrl,\n resolveS3fsOptions\n} from './storage-mount';\nimport {\n InvalidMountConfigError,\n S3FSMountError\n} from './storage-mount/errors';\nimport type { MountInfo } from './storage-mount/types';\nimport { SDK_VERSION } from './version';\n\nexport function getSandbox<T extends Sandbox<any>>(\n ns: DurableObjectNamespace<T>,\n id: string,\n options?: SandboxOptions\n): T {\n const sanitizedId = sanitizeSandboxId(id);\n const effectiveId = options?.normalizeId\n ? sanitizedId.toLowerCase()\n : sanitizedId;\n\n const hasUppercase = /[A-Z]/.test(sanitizedId);\n if (!options?.normalizeId && hasUppercase) {\n const logger = createLogger({ component: 'sandbox-do' });\n logger.warn(\n `Sandbox ID \"${sanitizedId}\" contains uppercase letters, which causes issues with preview URLs (hostnames are case-insensitive). ` +\n `normalizeId will default to true in a future version to prevent this. ` +\n `Use lowercase IDs or pass { normalizeId: true } to prepare.`\n );\n }\n\n const stub = getContainer(ns, effectiveId);\n\n stub.setSandboxName?.(effectiveId, options?.normalizeId);\n\n if (options?.baseUrl) {\n stub.setBaseUrl(options.baseUrl);\n }\n\n if (options?.sleepAfter !== undefined) {\n stub.setSleepAfter(options.sleepAfter);\n }\n\n if (options?.keepAlive !== undefined) {\n stub.setKeepAlive(options.keepAlive);\n }\n\n if (options?.containerTimeouts) {\n stub.setContainerTimeouts(options.containerTimeouts);\n }\n\n return Object.assign(stub, {\n wsConnect: connect(stub)\n }) as T;\n}\n\nexport function connect(stub: {\n fetch: (request: Request) => Promise<Response>;\n}) {\n return async (request: Request, port: number) => {\n if (!validatePort(port)) {\n throw new SecurityError(\n `Invalid or restricted port: ${port}. Ports must be in range 1024-65535 and not reserved.`\n );\n }\n const portSwitchedRequest = switchPort(request, port);\n return await stub.fetch(portSwitchedRequest);\n };\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: string | number = '10m'; // Sleep the sandbox if no requests are made in this timeframe\n\n client: SandboxClient;\n private codeInterpreter: CodeInterpreter;\n private sandboxName: string | null = null;\n private normalizeId: boolean = false;\n private baseUrl: string | null = null;\n private defaultSession: string | null = null;\n envVars: Record<string, string> = {};\n private logger: ReturnType<typeof createLogger>;\n private keepAliveEnabled: boolean = false;\n private activeMounts: Map<string, MountInfo> = new Map();\n private transport: 'http' | 'websocket' = 'http';\n\n /**\n * Default container startup timeouts (conservative for production)\n * Based on Cloudflare docs: \"Containers take several minutes to provision\"\n */\n private readonly DEFAULT_CONTAINER_TIMEOUTS = {\n // Time to get container instance and launch VM\n // @cloudflare/containers default: 8s (too short for cold starts)\n instanceGetTimeoutMS: 30_000, // 30 seconds\n\n // Time for application to start and ports to be ready\n // @cloudflare/containers default: 20s\n portReadyTimeoutMS: 90_000, // 90 seconds (allows for heavy containers)\n\n // Polling interval for checking container readiness\n // @cloudflare/containers default: 300ms (too aggressive)\n waitIntervalMS: 1000 // 1 second (reduces load)\n };\n\n /**\n * Active container timeout configuration\n * Can be set via options, env vars, or defaults\n */\n private containerTimeouts = { ...this.DEFAULT_CONTAINER_TIMEOUTS };\n\n /**\n * Create a SandboxClient with current transport settings\n */\n private createSandboxClient(): SandboxClient {\n return new SandboxClient({\n logger: this.logger,\n port: 3000,\n stub: this,\n ...(this.transport === 'websocket' && {\n transportMode: 'websocket' as const,\n wsUrl: 'ws://localhost:3000/ws'\n })\n });\n }\n\n constructor(ctx: DurableObjectState<{}>, env: Env) {\n super(ctx, env);\n\n const envObj = env as Record<string, unknown>;\n // Set sandbox environment variables from env object\n const sandboxEnvKeys = ['SANDBOX_LOG_LEVEL', 'SANDBOX_LOG_FORMAT'] as const;\n sandboxEnvKeys.forEach((key) => {\n if (envObj?.[key]) {\n this.envVars[key] = String(envObj[key]);\n }\n });\n\n // Initialize timeouts with env var fallbacks\n this.containerTimeouts = this.getDefaultTimeouts(envObj);\n\n this.logger = createLogger({\n component: 'sandbox-do',\n sandboxId: this.ctx.id.toString()\n });\n\n // Read transport setting from env var\n const transportEnv = envObj?.SANDBOX_TRANSPORT;\n if (transportEnv === 'websocket') {\n this.transport = 'websocket';\n } else if (transportEnv != null && transportEnv !== 'http') {\n this.logger.warn(\n `Invalid SANDBOX_TRANSPORT value: \"${transportEnv}\". Must be \"http\" or \"websocket\". Defaulting to \"http\".`\n );\n }\n\n // Create client with transport based on env var (may be updated from storage)\n this.client = this.createSandboxClient();\n\n // Initialize code interpreter - pass 'this' after client is ready\n // The CodeInterpreter extracts client.interpreter from the sandbox\n this.codeInterpreter = new CodeInterpreter(this);\n\n this.ctx.blockConcurrencyWhile(async () => {\n this.sandboxName =\n (await this.ctx.storage.get<string>('sandboxName')) || null;\n this.normalizeId =\n (await this.ctx.storage.get<boolean>('normalizeId')) || false;\n this.defaultSession =\n (await this.ctx.storage.get<string>('defaultSession')) || null;\n\n // Load saved timeout configuration (highest priority)\n const storedTimeouts =\n await this.ctx.storage.get<\n NonNullable<SandboxOptions['containerTimeouts']>\n >('containerTimeouts');\n if (storedTimeouts) {\n this.containerTimeouts = {\n ...this.containerTimeouts,\n ...storedTimeouts\n };\n }\n });\n }\n\n async setSandboxName(name: string, normalizeId?: boolean): Promise<void> {\n if (!this.sandboxName) {\n this.sandboxName = name;\n this.normalizeId = normalizeId || false;\n await this.ctx.storage.put('sandboxName', name);\n await this.ctx.storage.put('normalizeId', this.normalizeId);\n }\n }\n\n // RPC method to set the base URL\n async setBaseUrl(baseUrl: string): Promise<void> {\n if (!this.baseUrl) {\n this.baseUrl = baseUrl;\n await this.ctx.storage.put('baseUrl', baseUrl);\n } else {\n if (this.baseUrl !== baseUrl) {\n throw new Error(\n 'Base URL already set and different from one previously provided'\n );\n }\n }\n }\n\n // RPC method to set the sleep timeout\n async setSleepAfter(sleepAfter: string | number): Promise<void> {\n this.sleepAfter = sleepAfter;\n }\n\n // RPC method to enable keepAlive mode\n async setKeepAlive(keepAlive: boolean): Promise<void> {\n this.keepAliveEnabled = keepAlive;\n if (keepAlive) {\n this.logger.info(\n 'KeepAlive mode enabled - container will stay alive until explicitly destroyed'\n );\n } else {\n this.logger.info(\n 'KeepAlive mode disabled - container will timeout normally'\n );\n }\n }\n\n // RPC method to set environment variables\n async setEnvVars(envVars: Record<string, string>): Promise<void> {\n // Update local state for new sessions\n this.envVars = { ...this.envVars, ...envVars };\n\n // If default session already exists, update it directly\n if (this.defaultSession) {\n // Set environment variables by executing export commands in the existing session\n for (const [key, value] of Object.entries(envVars)) {\n const escapedValue = value.replace(/'/g, \"'\\\\''\");\n const exportCommand = `export ${key}='${escapedValue}'`;\n\n const result = await this.client.commands.execute(\n exportCommand,\n this.defaultSession\n );\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to set ${key}: ${result.stderr || 'Unknown error'}`\n );\n }\n }\n }\n }\n\n /**\n * RPC method to configure container startup timeouts\n */\n async setContainerTimeouts(\n timeouts: NonNullable<SandboxOptions['containerTimeouts']>\n ): Promise<void> {\n const validated = { ...this.containerTimeouts };\n\n // Validate each timeout if provided\n if (timeouts.instanceGetTimeoutMS !== undefined) {\n validated.instanceGetTimeoutMS = this.validateTimeout(\n timeouts.instanceGetTimeoutMS,\n 'instanceGetTimeoutMS',\n 5_000,\n 300_000\n );\n }\n\n if (timeouts.portReadyTimeoutMS !== undefined) {\n validated.portReadyTimeoutMS = this.validateTimeout(\n timeouts.portReadyTimeoutMS,\n 'portReadyTimeoutMS',\n 10_000,\n 600_000\n );\n }\n\n if (timeouts.waitIntervalMS !== undefined) {\n validated.waitIntervalMS = this.validateTimeout(\n timeouts.waitIntervalMS,\n 'waitIntervalMS',\n 100,\n 5_000\n );\n }\n\n this.containerTimeouts = validated;\n\n // Persist to storage\n await this.ctx.storage.put('containerTimeouts', this.containerTimeouts);\n\n this.logger.debug('Container timeouts updated', this.containerTimeouts);\n }\n\n /**\n * Validate a timeout value is within acceptable range\n * Throws error if invalid - used for user-provided values\n */\n private validateTimeout(\n value: number,\n name: string,\n min: number,\n max: number\n ): number {\n if (\n typeof value !== 'number' ||\n Number.isNaN(value) ||\n !Number.isFinite(value)\n ) {\n throw new Error(`${name} must be a valid finite number, got ${value}`);\n }\n\n if (value < min || value > max) {\n throw new Error(\n `${name} must be between ${min}-${max}ms, got ${value}ms`\n );\n }\n\n return value;\n }\n\n /**\n * Get default timeouts with env var fallbacks and validation\n * Precedence: SDK defaults < Env vars < User config\n */\n private getDefaultTimeouts(\n env: Record<string, unknown>\n ): typeof this.DEFAULT_CONTAINER_TIMEOUTS {\n const parseAndValidate = (\n envVar: string | undefined,\n name: keyof typeof this.DEFAULT_CONTAINER_TIMEOUTS,\n min: number,\n max: number\n ): number => {\n const defaultValue = this.DEFAULT_CONTAINER_TIMEOUTS[name];\n\n if (envVar === undefined) {\n return defaultValue;\n }\n\n const parsed = parseInt(envVar, 10);\n\n if (Number.isNaN(parsed)) {\n this.logger.warn(\n `Invalid ${name}: \"${envVar}\" is not a number. Using default: ${defaultValue}ms`\n );\n return defaultValue;\n }\n\n if (parsed < min || parsed > max) {\n this.logger.warn(\n `Invalid ${name}: ${parsed}ms. Must be ${min}-${max}ms. Using default: ${defaultValue}ms`\n );\n return defaultValue;\n }\n\n return parsed;\n };\n\n return {\n instanceGetTimeoutMS: parseAndValidate(\n getEnvString(env, 'SANDBOX_INSTANCE_TIMEOUT_MS'),\n 'instanceGetTimeoutMS',\n 5_000, // Min 5s\n 300_000 // Max 5min\n ),\n portReadyTimeoutMS: parseAndValidate(\n getEnvString(env, 'SANDBOX_PORT_TIMEOUT_MS'),\n 'portReadyTimeoutMS',\n 10_000, // Min 10s\n 600_000 // Max 10min\n ),\n waitIntervalMS: parseAndValidate(\n getEnvString(env, 'SANDBOX_POLL_INTERVAL_MS'),\n 'waitIntervalMS',\n 100, // Min 100ms\n 5_000 // Max 5s\n )\n };\n }\n\n /*\n * Mount an S3-compatible bucket as a local directory using S3FS-FUSE\n *\n * Requires explicit endpoint URL. Credentials are auto-detected from environment\n * variables or can be provided explicitly.\n *\n * @param bucket - Bucket name\n * @param mountPath - Absolute path in container to mount at\n * @param options - Configuration options with required endpoint\n * @throws MissingCredentialsError if no credentials found in environment\n * @throws S3FSMountError if S3FS mount command fails\n * @throws InvalidMountConfigError if bucket name, mount path, or endpoint is invalid\n */\n async mountBucket(\n bucket: string,\n mountPath: string,\n options: MountBucketOptions\n ): Promise<void> {\n this.logger.info(`Mounting bucket ${bucket} to ${mountPath}`);\n\n // Validate options\n this.validateMountOptions(bucket, mountPath, options);\n\n // Detect provider from explicit option or URL pattern\n const provider: BucketProvider | null =\n options.provider || detectProviderFromUrl(options.endpoint);\n\n this.logger.debug(`Detected provider: ${provider || 'unknown'}`, {\n explicitProvider: options.provider\n });\n\n // Detect credentials\n const credentials = detectCredentials(options, this.envVars);\n\n // Generate unique password file path\n const passwordFilePath = this.generatePasswordFilePath();\n\n // Reserve mount path before async operations so concurrent mounts see it\n this.activeMounts.set(mountPath, {\n bucket,\n mountPath,\n endpoint: options.endpoint,\n provider,\n passwordFilePath,\n mounted: false\n });\n\n try {\n // Create password file with credentials\n await this.createPasswordFile(passwordFilePath, bucket, credentials);\n\n // Create mount directory\n await this.exec(`mkdir -p ${shellEscape(mountPath)}`);\n\n // Execute S3FS mount with password file\n await this.executeS3FSMount(\n bucket,\n mountPath,\n options,\n provider,\n passwordFilePath\n );\n\n // Mark as successfully mounted\n this.activeMounts.set(mountPath, {\n bucket,\n mountPath,\n endpoint: options.endpoint,\n provider,\n passwordFilePath,\n mounted: true\n });\n\n this.logger.info(`Successfully mounted bucket ${bucket} to ${mountPath}`);\n } catch (error) {\n // Clean up password file on failure\n await this.deletePasswordFile(passwordFilePath);\n\n // Clean up reservation on failure\n this.activeMounts.delete(mountPath);\n throw error;\n }\n }\n\n /**\n * Manually unmount a bucket filesystem\n *\n * @param mountPath - Absolute path where the bucket is mounted\n * @throws InvalidMountConfigError if mount path doesn't exist or isn't mounted\n */\n async unmountBucket(mountPath: string): Promise<void> {\n this.logger.info(`Unmounting bucket from ${mountPath}`);\n\n // Look up mount by path\n const mountInfo = this.activeMounts.get(mountPath);\n\n // Throw error if mount doesn't exist\n if (!mountInfo) {\n throw new InvalidMountConfigError(\n `No active mount found at path: ${mountPath}`\n );\n }\n\n // Unmount the filesystem\n try {\n await this.exec(`fusermount -u ${shellEscape(mountPath)}`);\n mountInfo.mounted = false;\n\n // Only remove from tracking if unmount succeeded\n this.activeMounts.delete(mountPath);\n } finally {\n // Always cleanup password file, even if unmount fails\n await this.deletePasswordFile(mountInfo.passwordFilePath);\n }\n\n this.logger.info(`Successfully unmounted bucket from ${mountPath}`);\n }\n\n /**\n * Validate mount options\n */\n private validateMountOptions(\n bucket: string,\n mountPath: string,\n options: MountBucketOptions\n ): void {\n // Require endpoint field\n if (!options.endpoint) {\n throw new InvalidMountConfigError(\n 'Endpoint is required. Provide the full S3-compatible endpoint URL.'\n );\n }\n\n // Basic URL validation\n try {\n new URL(options.endpoint);\n } catch (error) {\n throw new InvalidMountConfigError(\n `Invalid endpoint URL: \"${options.endpoint}\". Must be a valid HTTP(S) URL.`\n );\n }\n\n // Validate bucket name (S3-compatible naming rules)\n const bucketNameRegex = /^[a-z0-9]([a-z0-9.-]{0,61}[a-z0-9])?$/;\n if (!bucketNameRegex.test(bucket)) {\n throw new InvalidMountConfigError(\n `Invalid bucket name: \"${bucket}\". Bucket names must be 3-63 characters, ` +\n `lowercase alphanumeric, dots, or hyphens, and cannot start/end with dots or hyphens.`\n );\n }\n\n // Validate mount path is absolute\n if (!mountPath.startsWith('/')) {\n throw new InvalidMountConfigError(\n `Mount path must be absolute (start with /): \"${mountPath}\"`\n );\n }\n\n // Check for duplicate mount path\n if (this.activeMounts.has(mountPath)) {\n const existingMount = this.activeMounts.get(mountPath);\n throw new InvalidMountConfigError(\n `Mount path \"${mountPath}\" is already in use by bucket \"${existingMount?.bucket}\". ` +\n `Unmount the existing bucket first or use a different mount path.`\n );\n }\n }\n\n /**\n * Generate unique password file path for s3fs credentials\n */\n private generatePasswordFilePath(): string {\n const uuid = crypto.randomUUID();\n return `/tmp/.passwd-s3fs-${uuid}`;\n }\n\n /**\n * Create password file with s3fs credentials\n * Format: bucket:accessKeyId:secretAccessKey\n */\n private async createPasswordFile(\n passwordFilePath: string,\n bucket: string,\n credentials: BucketCredentials\n ): Promise<void> {\n const content = `${bucket}:${credentials.accessKeyId}:${credentials.secretAccessKey}`;\n\n await this.writeFile(passwordFilePath, content);\n\n await this.exec(`chmod 0600 ${shellEscape(passwordFilePath)}`);\n\n this.logger.debug(`Created password file: ${passwordFilePath}`);\n }\n\n /**\n * Delete password file\n */\n private async deletePasswordFile(passwordFilePath: string): Promise<void> {\n try {\n await this.exec(`rm -f ${shellEscape(passwordFilePath)}`);\n this.logger.debug(`Deleted password file: ${passwordFilePath}`);\n } catch (error) {\n this.logger.warn(`Failed to delete password file ${passwordFilePath}`, {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n\n /**\n * Execute S3FS mount command\n */\n private async executeS3FSMount(\n bucket: string,\n mountPath: string,\n options: MountBucketOptions,\n provider: BucketProvider | null,\n passwordFilePath: string\n ): Promise<void> {\n // Resolve s3fs options (provider defaults + user overrides)\n const resolvedOptions = resolveS3fsOptions(provider, options.s3fsOptions);\n\n // Build s3fs mount command\n const s3fsArgs: string[] = [];\n\n // Add password file option FIRST\n s3fsArgs.push(`passwd_file=${passwordFilePath}`);\n\n // Add resolved provider-specific and user options\n s3fsArgs.push(...resolvedOptions);\n\n // Add read-only flag if requested\n if (options.readOnly) {\n s3fsArgs.push('ro');\n }\n\n // Add endpoint URL\n s3fsArgs.push(`url=${options.endpoint}`);\n\n // Build final command with escaped options\n const optionsStr = shellEscape(s3fsArgs.join(','));\n const mountCmd = `s3fs ${shellEscape(bucket)} ${shellEscape(mountPath)} -o ${optionsStr}`;\n\n this.logger.debug('Executing s3fs mount', {\n bucket,\n mountPath,\n provider,\n resolvedOptions\n });\n\n // Execute mount command\n const result = await this.exec(mountCmd);\n\n if (result.exitCode !== 0) {\n throw new S3FSMountError(\n `S3FS mount failed: ${result.stderr || result.stdout || 'Unknown error'}`\n );\n }\n\n this.logger.debug('Mount command executed successfully');\n }\n\n /**\n * Cleanup and destroy the sandbox container\n */\n override async destroy(): Promise<void> {\n this.logger.info('Destroying sandbox container');\n\n // Disconnect WebSocket transport if active\n this.client.disconnect();\n\n // Unmount all mounted buckets and cleanup password files\n for (const [mountPath, mountInfo] of this.activeMounts.entries()) {\n if (mountInfo.mounted) {\n try {\n this.logger.info(\n `Unmounting bucket ${mountInfo.bucket} from ${mountPath}`\n );\n await this.exec(`fusermount -u ${shellEscape(mountPath)}`);\n mountInfo.mounted = false;\n } catch (error) {\n const errorMsg =\n error instanceof Error ? error.message : String(error);\n this.logger.warn(\n `Failed to unmount bucket ${mountInfo.bucket} from ${mountPath}: ${errorMsg}`\n );\n }\n }\n\n // Always cleanup password file\n await this.deletePasswordFile(mountInfo.passwordFilePath);\n }\n\n await super.destroy();\n }\n\n override onStart() {\n this.logger.debug('Sandbox started');\n\n // Check version compatibility asynchronously (don't block startup)\n this.checkVersionCompatibility().catch((error) => {\n this.logger.error(\n 'Version compatibility check failed',\n error instanceof Error ? error : new Error(String(error))\n );\n });\n }\n\n /**\n * Check if the container version matches the SDK version\n * Logs a warning if there's a mismatch\n */\n private async checkVersionCompatibility(): Promise<void> {\n try {\n // Get the SDK version (imported from version.ts)\n const sdkVersion = SDK_VERSION;\n\n // Get container version\n const containerVersion = await this.client.utils.getVersion();\n\n // If container version is unknown, it's likely an old container without the endpoint\n if (containerVersion === 'unknown') {\n this.logger.warn(\n 'Container version check: Container version could not be determined. ' +\n 'This may indicate an outdated container image. ' +\n 'Please update your container to match SDK version ' +\n sdkVersion\n );\n return;\n }\n\n // Check if versions match\n if (containerVersion !== sdkVersion) {\n const message =\n `Version mismatch detected! SDK version (${sdkVersion}) does not match ` +\n `container version (${containerVersion}). This may cause compatibility issues. ` +\n `Please update your container image to version ${sdkVersion}`;\n\n // Log warning - we can't reliably detect dev vs prod environment in Durable Objects\n // so we always use warning level as requested by the user\n this.logger.warn(message);\n } else {\n this.logger.debug('Version check passed', {\n sdkVersion,\n containerVersion\n });\n }\n } catch (error) {\n // Don't fail the sandbox initialization if version check fails\n this.logger.debug('Version compatibility check encountered an error', {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n\n override async onStop() {\n this.logger.debug('Sandbox stopped');\n\n // Clear in-memory state that references the old container\n // This prevents stale references after container restarts\n this.defaultSession = null;\n this.activeMounts.clear();\n\n // Persist cleanup to storage so state is clean on next container start\n await Promise.all([\n this.ctx.storage.delete('portTokens'),\n this.ctx.storage.delete('defaultSession')\n ]);\n }\n\n override onError(error: unknown) {\n this.logger.error(\n 'Sandbox error',\n error instanceof Error ? error : new Error(String(error))\n );\n }\n\n /**\n * Override Container.containerFetch to use production-friendly timeouts\n * Automatically starts container with longer timeouts if not running\n */\n override async containerFetch(\n requestOrUrl: Request | string | URL,\n portOrInit?: number | RequestInit,\n portParam?: number\n ): Promise<Response> {\n // Parse arguments to extract request and port\n const { request, port } = this.parseContainerFetchArgs(\n requestOrUrl,\n portOrInit,\n portParam\n );\n\n const state = await this.getState();\n\n // If container not healthy, start it with production timeouts\n if (state.status !== 'healthy') {\n try {\n this.logger.debug('Starting container with configured timeouts', {\n instanceTimeout: this.containerTimeouts.instanceGetTimeoutMS,\n portTimeout: this.containerTimeouts.portReadyTimeoutMS\n });\n\n await this.startAndWaitForPorts({\n ports: port,\n cancellationOptions: {\n instanceGetTimeoutMS: this.containerTimeouts.instanceGetTimeoutMS,\n portReadyTimeoutMS: this.containerTimeouts.portReadyTimeoutMS,\n waitInterval: this.containerTimeouts.waitIntervalMS,\n abort: request.signal\n }\n });\n } catch (e) {\n // 1. Provisioning: Container VM not yet available\n if (this.isNoInstanceError(e)) {\n return new Response(\n 'Container is currently provisioning. This can take several minutes on first deployment. Please retry in a moment.',\n {\n status: 503,\n headers: { 'Retry-After': '10' }\n }\n );\n }\n\n // 2. Transient startup errors: Container starting, port not ready yet\n if (this.isTransientStartupError(e)) {\n this.logger.debug(\n 'Transient container startup error, returning 503',\n {\n error: e instanceof Error ? e.message : String(e)\n }\n );\n return new Response(\n 'Container is starting. Please retry in a moment.',\n {\n status: 503,\n headers: { 'Retry-After': '3' }\n }\n );\n }\n\n // 3. Permanent errors: Configuration issues, missing images, etc.\n this.logger.error(\n 'Container startup failed with permanent error',\n e instanceof Error ? e : new Error(String(e))\n );\n return new Response(\n `Failed to start container: ${e instanceof Error ? e.message : String(e)}`,\n { status: 500 }\n );\n }\n }\n\n // Delegate to parent for the actual fetch (handles TCP port access internally)\n return await super.containerFetch(requestOrUrl, portOrInit, portParam);\n }\n\n /**\n * Helper: Check if error is \"no container instance available\"\n * This indicates the container VM is still being provisioned.\n */\n private isNoInstanceError(error: unknown): boolean {\n return (\n error instanceof Error &&\n error.message.toLowerCase().includes('no container instance')\n );\n }\n\n /**\n * Helper: Check if error is a transient startup error that should trigger retry\n *\n * These errors occur during normal container startup and are recoverable:\n * - Port not yet mapped (container starting, app not listening yet)\n * - Connection refused (port mapped but app not ready)\n * - Timeouts during startup (recoverable with retry)\n * - Network transients (temporary connectivity issues)\n *\n * Errors NOT included (permanent failures):\n * - \"no such image\" - missing Docker image\n * - \"container already exists\" - name collision\n * - Configuration errors\n */\n private isTransientStartupError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n\n const msg = error.message.toLowerCase();\n\n // Transient errors from workerd container-client.c++ and @cloudflare/containers\n const transientPatterns = [\n // Port mapping race conditions (workerd DockerPort::connect)\n 'container port not found',\n 'connection refused: container port',\n\n // Application startup delays (@cloudflare/containers)\n 'the container is not listening',\n 'failed to verify port',\n 'container did not start',\n\n // Network transients (workerd)\n 'network connection lost',\n 'container suddenly disconnected',\n\n // Monitor race conditions (workerd)\n 'monitor failed to find container',\n\n // Timeouts (various layers)\n 'timed out',\n 'timeout',\n 'the operation was aborted'\n ];\n\n return transientPatterns.some((pattern) => msg.includes(pattern));\n }\n\n /**\n * Helper: Parse containerFetch arguments (supports multiple signatures)\n */\n private parseContainerFetchArgs(\n requestOrUrl: Request | string | URL,\n portOrInit?: number | RequestInit,\n portParam?: number\n ): { request: Request; port: number } {\n let request: Request;\n let port: number | undefined;\n\n if (requestOrUrl instanceof Request) {\n request = requestOrUrl;\n port = typeof portOrInit === 'number' ? portOrInit : undefined;\n } else {\n const url =\n typeof requestOrUrl === 'string'\n ? requestOrUrl\n : requestOrUrl.toString();\n const init = typeof portOrInit === 'number' ? {} : portOrInit || {};\n port =\n typeof portOrInit === 'number'\n ? portOrInit\n : typeof portParam === 'number'\n ? portParam\n : undefined;\n request = new Request(url, init);\n }\n\n port ??= this.defaultPort;\n\n if (port === undefined) {\n throw new Error('No port specified for container fetch');\n }\n\n return { request, port };\n }\n\n /**\n * Override onActivityExpired to prevent automatic shutdown when keepAlive is enabled\n * When keepAlive is disabled, calls parent implementation which stops the container\n */\n override async onActivityExpired(): Promise<void> {\n if (this.keepAliveEnabled) {\n this.logger.debug(\n 'Activity expired but keepAlive is enabled - container will stay alive'\n );\n // Do nothing - don't call stop(), container stays alive\n } else {\n // Default behavior: stop the container\n this.logger.debug('Activity expired - stopping container');\n await super.onActivityExpired();\n }\n }\n\n // Override fetch to route internal container requests to appropriate ports\n override async fetch(request: Request): Promise<Response> {\n // Extract or generate trace ID from request\n const traceId =\n TraceContext.fromHeaders(request.headers) || TraceContext.generate();\n\n // Create request-specific logger with trace ID\n const requestLogger = this.logger.child({ traceId, operation: 'fetch' });\n\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 }\n\n // Detect WebSocket upgrade request (RFC 6455 compliant)\n const upgradeHeader = request.headers.get('Upgrade');\n const connectionHeader = request.headers.get('Connection');\n const isWebSocket =\n upgradeHeader?.toLowerCase() === 'websocket' &&\n connectionHeader?.toLowerCase().includes('upgrade');\n\n if (isWebSocket) {\n // WebSocket path: Let parent Container class handle WebSocket proxying\n // This bypasses containerFetch() which uses JSRPC and cannot handle WebSocket upgrades\n try {\n requestLogger.debug('WebSocket upgrade requested', {\n path: url.pathname,\n port: this.determinePort(url)\n });\n return await super.fetch(request);\n } catch (error) {\n requestLogger.error(\n 'WebSocket connection failed',\n error instanceof Error ? error : new Error(String(error)),\n { path: url.pathname }\n );\n throw error;\n }\n }\n\n // Non-WebSocket: Use existing port determination and HTTP routing logic\n const port = this.determinePort(url);\n\n // Route to the appropriate port\n return await this.containerFetch(request, port);\n }\n\n wsConnect(request: Request, port: number): Promise<Response> {\n // Stub - actual implementation is attached by getSandbox() on the stub object\n throw new Error(\n 'wsConnect must be called on the stub returned by getSandbox()'\n );\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], 10);\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 /**\n * Ensure default session exists - lazy initialization\n * This is called automatically by all public methods that need a session\n *\n * The session ID is persisted to DO storage. On container restart, if the\n * container already has this session (from a previous instance), we sync\n * our state rather than failing on duplicate creation.\n */\n private async ensureDefaultSession(): Promise<string> {\n const sessionId = `sandbox-${this.sandboxName || 'default'}`;\n\n // Fast path: session already initialized in this instance\n if (this.defaultSession === sessionId) {\n return this.defaultSession;\n }\n\n // Create session in container\n try {\n await this.client.utils.createSession({\n id: sessionId,\n env: this.envVars || {},\n cwd: '/workspace'\n });\n\n this.defaultSession = sessionId;\n await this.ctx.storage.put('defaultSession', sessionId);\n this.logger.debug('Default session initialized', { sessionId });\n } catch (error: unknown) {\n // Session may already exist (e.g., after hot reload or concurrent request)\n if (error instanceof SessionAlreadyExistsError) {\n this.logger.debug(\n 'Session exists in container but not in DO state, syncing',\n { sessionId }\n );\n this.defaultSession = sessionId;\n await this.ctx.storage.put('defaultSession', sessionId);\n } else {\n throw error;\n }\n }\n\n return this.defaultSession;\n }\n\n // Enhanced exec method - always returns ExecResult with optional streaming\n // This replaces the old exec method to match ISandbox interface\n async exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n const session = await this.ensureDefaultSession();\n return this.execWithSession(command, session, options);\n }\n\n /**\n * Internal session-aware exec implementation\n * Used by both public exec() and session wrappers\n */\n private async execWithSession(\n command: string,\n sessionId: string,\n options?: ExecOptions\n ): Promise<ExecResult> {\n const startTime = Date.now();\n const timestamp = new Date().toISOString();\n\n let timeoutId: NodeJS.Timeout | undefined;\n\n try {\n // Handle cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n let result: ExecResult;\n\n if (options?.stream && options?.onOutput) {\n // Streaming with callbacks - we need to collect the final result\n result = await this.executeWithStreaming(\n command,\n sessionId,\n options,\n startTime,\n timestamp\n );\n } else {\n // Regular execution with session\n const commandOptions =\n options &&\n (options.timeout !== undefined ||\n options.env !== undefined ||\n options.cwd !== undefined)\n ? {\n timeoutMs: options.timeout,\n env: options.env,\n cwd: options.cwd\n }\n : undefined;\n\n const response = await this.client.commands.execute(\n command,\n sessionId,\n commandOptions\n );\n\n const duration = Date.now() - startTime;\n result = this.mapExecuteResponseToExecResult(\n response,\n duration,\n sessionId\n );\n }\n\n // Call completion callback if provided\n if (options?.onComplete) {\n options.onComplete(result);\n }\n\n return result;\n } catch (error) {\n if (options?.onError && error instanceof Error) {\n options.onError(error);\n }\n throw error;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async executeWithStreaming(\n command: string,\n sessionId: string,\n options: ExecOptions,\n startTime: number,\n timestamp: string\n ): Promise<ExecResult> {\n let stdout = '';\n let stderr = '';\n\n try {\n const stream = await this.client.commands.executeStream(\n command,\n sessionId,\n {\n timeoutMs: options.timeout,\n env: options.env,\n cwd: options.cwd\n }\n );\n\n for await (const event of parseSSEStream<ExecEvent>(stream)) {\n // Check for cancellation\n if (options.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n switch (event.type) {\n case 'stdout':\n case 'stderr':\n if (event.data) {\n // Update accumulated output\n if (event.type === 'stdout') stdout += event.data;\n if (event.type === 'stderr') stderr += event.data;\n\n // Call user's callback\n if (options.onOutput) {\n options.onOutput(event.type, event.data);\n }\n }\n break;\n\n case 'complete': {\n // Use result from complete event if available\n const duration = Date.now() - startTime;\n return {\n success: (event.exitCode ?? 0) === 0,\n exitCode: event.exitCode ?? 0,\n stdout,\n stderr,\n command,\n duration,\n timestamp,\n sessionId\n };\n }\n\n case 'error':\n throw new Error(event.data || 'Command execution failed');\n }\n }\n\n // If we get here without a complete event, something went wrong\n throw new Error('Stream ended without completion event');\n } catch (error) {\n if (options.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n throw error;\n }\n }\n\n private mapExecuteResponseToExecResult(\n response: ExecuteResponse,\n duration: number,\n sessionId?: string\n ): ExecResult {\n return {\n success: response.success,\n exitCode: response.exitCode,\n stdout: response.stdout,\n stderr: response.stderr,\n command: response.command,\n duration,\n timestamp: response.timestamp,\n sessionId\n };\n }\n\n /**\n * Create a Process domain object from HTTP client DTO\n * Centralizes process object creation with bound methods\n * This eliminates duplication across startProcess, listProcesses, getProcess, and session wrappers\n */\n private createProcessFromDTO(\n data: {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string | Date;\n endTime?: string | Date;\n exitCode?: number;\n },\n sessionId: string\n ): Process {\n return {\n id: data.id,\n pid: data.pid,\n command: data.command,\n status: data.status,\n startTime:\n typeof data.startTime === 'string'\n ? new Date(data.startTime)\n : data.startTime,\n endTime: data.endTime\n ? typeof data.endTime === 'string'\n ? new Date(data.endTime)\n : data.endTime\n : undefined,\n exitCode: data.exitCode,\n sessionId,\n\n kill: async (signal?: string) => {\n await this.killProcess(data.id, signal);\n },\n\n getStatus: async () => {\n const current = await this.getProcess(data.id);\n return current?.status || 'error';\n },\n\n getLogs: async () => {\n const logs = await this.getProcessLogs(data.id);\n return { stdout: logs.stdout, stderr: logs.stderr };\n },\n\n waitForLog: async (\n pattern: string | RegExp,\n timeout?: number\n ): Promise<WaitForLogResult> => {\n return this.waitForLogPattern(data.id, data.command, pattern, timeout);\n },\n\n waitForPort: async (\n port: number,\n options?: WaitForPortOptions\n ): Promise<void> => {\n await this.waitForPortReady(data.id, data.command, port, options);\n },\n\n waitForExit: async (timeout?: number): Promise<WaitForExitResult> => {\n return this.waitForProcessExit(data.id, data.command, timeout);\n }\n };\n }\n\n /**\n * Wait for a log pattern to appear in process output\n */\n private async waitForLogPattern(\n processId: string,\n command: string,\n pattern: string | RegExp,\n timeout?: number\n ): Promise<WaitForLogResult> {\n const startTime = Date.now();\n const conditionStr = this.conditionToString(pattern);\n let collectedStdout = '';\n let collectedStderr = '';\n\n // First check existing logs\n try {\n const existingLogs = await this.getProcessLogs(processId);\n // Ensure existing logs end with newline for proper line separation from streamed output\n collectedStdout = existingLogs.stdout;\n if (collectedStdout && !collectedStdout.endsWith('\\n')) {\n collectedStdout += '\\n';\n }\n collectedStderr = existingLogs.stderr;\n if (collectedStderr && !collectedStderr.endsWith('\\n')) {\n collectedStderr += '\\n';\n }\n\n // Check stdout\n const stdoutResult = this.matchPattern(existingLogs.stdout, pattern);\n if (stdoutResult) {\n return stdoutResult;\n }\n\n // Check stderr\n const stderrResult = this.matchPattern(existingLogs.stderr, pattern);\n if (stderrResult) {\n return stderrResult;\n }\n } catch (error) {\n // Process might have already exited, continue to streaming\n this.logger.debug('Could not get existing logs, will stream', {\n processId,\n error: error instanceof Error ? error.message : String(error)\n });\n }\n\n // Stream new logs and check for pattern\n const stream = await this.streamProcessLogs(processId);\n\n // Set up timeout if specified\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutPromise: Promise<never> | undefined;\n\n if (timeout !== undefined) {\n const remainingTime = timeout - (Date.now() - startTime);\n if (remainingTime <= 0) {\n throw this.createReadyTimeoutError(\n processId,\n command,\n conditionStr,\n timeout\n );\n }\n\n timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n this.createReadyTimeoutError(\n processId,\n command,\n conditionStr,\n timeout\n )\n );\n }, remainingTime);\n });\n }\n\n try {\n // Process stream\n const streamProcessor = async (): Promise<WaitForLogResult> => {\n const DEBOUNCE_MS = 50;\n let lastCheckTime = 0;\n let pendingCheck = false;\n\n const checkPattern = (): WaitForLogResult | null => {\n // Check both stdout and stderr buffers\n const stdoutResult = this.matchPattern(collectedStdout, pattern);\n if (stdoutResult) return stdoutResult;\n const stderrResult = this.matchPattern(collectedStderr, pattern);\n if (stderrResult) return stderrResult;\n return null;\n };\n\n for await (const event of parseSSEStream<LogEvent>(stream)) {\n // Handle different event types\n if (event.type === 'stdout' || event.type === 'stderr') {\n const data = event.data || '';\n\n if (event.type === 'stdout') {\n collectedStdout += data;\n } else {\n collectedStderr += data;\n }\n pendingCheck = true;\n\n // Debounce pattern matching - check at most every 50ms\n const now = Date.now();\n if (now - lastCheckTime >= DEBOUNCE_MS) {\n lastCheckTime = now;\n pendingCheck = false;\n const result = checkPattern();\n if (result) return result;\n }\n }\n\n // Process exited - do final check before throwing\n if (event.type === 'exit') {\n if (pendingCheck) {\n const result = checkPattern();\n if (result) return result;\n }\n throw this.createExitedBeforeReadyError(\n processId,\n command,\n conditionStr,\n event.exitCode ?? 1\n );\n }\n }\n\n // Stream ended - do final check before throwing\n if (pendingCheck) {\n const result = checkPattern();\n if (result) return result;\n }\n // Stream ended without finding pattern - this indicates process exited\n throw this.createExitedBeforeReadyError(\n processId,\n command,\n conditionStr,\n 0\n );\n };\n\n // Race with timeout if specified, otherwise just run stream processor\n if (timeoutPromise) {\n return await Promise.race([streamProcessor(), timeoutPromise]);\n }\n return await streamProcessor();\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * Wait for a port to become available (for process readiness checking)\n */\n private async waitForPortReady(\n processId: string,\n command: string,\n port: number,\n options?: WaitForPortOptions\n ): Promise<void> {\n const {\n mode = 'http',\n path = '/',\n status = { min: 200, max: 399 },\n timeout,\n interval = 500\n } = options ?? {};\n\n const conditionStr =\n mode === 'http' ? `port ${port} (HTTP ${path})` : `port ${port} (TCP)`;\n\n // Normalize status to min/max\n const statusMin = typeof status === 'number' ? status : status.min;\n const statusMax = typeof status === 'number' ? status : status.max;\n\n // Open streaming watch - container handles internal polling\n const stream = await this.client.ports.watchPort({\n port,\n mode,\n path,\n statusMin,\n statusMax,\n processId,\n interval\n });\n\n // Set up timeout if specified\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutPromise: Promise<never> | undefined;\n\n if (timeout !== undefined) {\n timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n this.createReadyTimeoutError(\n processId,\n command,\n conditionStr,\n timeout\n )\n );\n }, timeout);\n });\n }\n\n try {\n const streamProcessor = async (): Promise<void> => {\n for await (const event of parseSSEStream<PortWatchEvent>(stream)) {\n switch (event.type) {\n case 'ready':\n return; // Success!\n case 'process_exited':\n throw this.createExitedBeforeReadyError(\n processId,\n command,\n conditionStr,\n event.exitCode ?? 1\n );\n case 'error':\n throw new Error(event.error || 'Port watch failed');\n // 'watching' - continue\n }\n }\n throw new Error('Port watch stream ended unexpectedly');\n };\n\n if (timeoutPromise) {\n await Promise.race([streamProcessor(), timeoutPromise]);\n } else {\n await streamProcessor();\n }\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n // Cancel the stream to stop container-side polling\n try {\n await stream.cancel();\n } catch {\n // Stream may already be closed\n }\n }\n }\n\n /**\n * Wait for a process to exit\n * Returns the exit code\n */\n private async waitForProcessExit(\n processId: string,\n command: string,\n timeout?: number\n ): Promise<WaitForExitResult> {\n const stream = await this.streamProcessLogs(processId);\n\n // Set up timeout if specified\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutPromise: Promise<never> | undefined;\n\n if (timeout !== undefined) {\n timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n this.createReadyTimeoutError(\n processId,\n command,\n 'process exit',\n timeout\n )\n );\n }, timeout);\n });\n }\n\n try {\n const streamProcessor = async (): Promise<WaitForExitResult> => {\n for await (const event of parseSSEStream<LogEvent>(stream)) {\n if (event.type === 'exit') {\n return {\n exitCode: event.exitCode ?? 1\n };\n }\n }\n\n // Stream ended without exit event - shouldn't happen, but handle gracefully\n throw new Error(\n `Process ${processId} stream ended unexpectedly without exit event`\n );\n };\n\n if (timeoutPromise) {\n return await Promise.race([streamProcessor(), timeoutPromise]);\n }\n return await streamProcessor();\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * Match a pattern against text\n */\n private matchPattern(\n text: string,\n pattern: string | RegExp\n ): WaitForLogResult | null {\n if (typeof pattern === 'string') {\n // Simple substring match\n if (text.includes(pattern)) {\n // Find the line containing the pattern\n const lines = text.split('\\n');\n for (const line of lines) {\n if (line.includes(pattern)) {\n return { line };\n }\n }\n return { line: pattern };\n }\n } else {\n const safePattern = new RegExp(\n pattern.source,\n pattern.flags.replace('g', '')\n );\n const match = text.match(safePattern);\n if (match) {\n // Find the full line containing the match\n const lines = text.split('\\n');\n for (const line of lines) {\n const lineMatch = line.match(safePattern);\n if (lineMatch) {\n return { line, match: lineMatch };\n }\n }\n return { line: match[0], match };\n }\n }\n return null;\n }\n\n /**\n * Convert a log pattern to a human-readable string\n */\n private conditionToString(pattern: string | RegExp): string {\n if (typeof pattern === 'string') {\n return `\"${pattern}\"`;\n }\n return pattern.toString();\n }\n\n /**\n * Create a ProcessReadyTimeoutError\n */\n private createReadyTimeoutError(\n processId: string,\n command: string,\n condition: string,\n timeout: number\n ): ProcessReadyTimeoutError {\n return new ProcessReadyTimeoutError({\n code: ErrorCode.PROCESS_READY_TIMEOUT,\n message: `Process did not become ready within ${timeout}ms. Waiting for: ${condition}`,\n context: {\n processId,\n command,\n condition,\n timeout\n },\n httpStatus: 408,\n timestamp: new Date().toISOString(),\n suggestion: `Check if your process outputs ${condition}. You can increase the timeout parameter.`\n });\n }\n\n /**\n * Create a ProcessExitedBeforeReadyError\n */\n private createExitedBeforeReadyError(\n processId: string,\n command: string,\n condition: string,\n exitCode: number\n ): ProcessExitedBeforeReadyError {\n return new ProcessExitedBeforeReadyError({\n code: ErrorCode.PROCESS_EXITED_BEFORE_READY,\n message: `Process exited with code ${exitCode} before becoming ready. Waiting for: ${condition}`,\n context: {\n processId,\n command,\n condition,\n exitCode\n },\n httpStatus: 500,\n timestamp: new Date().toISOString(),\n suggestion: 'Check process logs with getLogs() for error messages'\n });\n }\n\n // Background process management\n async startProcess(\n command: string,\n options?: ProcessOptions,\n sessionId?: string\n ): Promise<Process> {\n // Use the new HttpClient method to start the process\n try {\n const session = sessionId ?? (await this.ensureDefaultSession());\n const requestOptions = {\n ...(options?.processId !== undefined && {\n processId: options.processId\n }),\n ...(options?.timeout !== undefined && { timeoutMs: options.timeout }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(options?.encoding !== undefined && { encoding: options.encoding }),\n ...(options?.autoCleanup !== undefined && {\n autoCleanup: options.autoCleanup\n })\n };\n\n const response = await this.client.processes.startProcess(\n command,\n session,\n requestOptions\n );\n\n const processObj = this.createProcessFromDTO(\n {\n id: response.processId,\n pid: response.pid,\n command: response.command,\n status: 'running' as ProcessStatus,\n startTime: new Date(),\n endTime: undefined,\n exitCode: undefined\n },\n session\n );\n\n // Call onStart callback if provided\n if (options?.onStart) {\n options.onStart(processObj);\n }\n\n // Start background streaming if output/exit callbacks are provided\n if (options?.onOutput || options?.onExit) {\n // Fire and forget - don't await, let it run in background\n this.startProcessCallbackStream(response.processId, options).catch(\n () => {\n // Error already handled in startProcessCallbackStream\n }\n );\n }\n\n return processObj;\n } catch (error) {\n if (options?.onError && error instanceof Error) {\n options.onError(error);\n }\n\n throw error;\n }\n }\n\n /**\n * Start background streaming for process callbacks\n * Opens SSE stream to container and routes events to callbacks\n */\n private async startProcessCallbackStream(\n processId: string,\n options: ProcessOptions\n ): Promise<void> {\n try {\n const stream = await this.client.processes.streamProcessLogs(processId);\n\n for await (const event of parseSSEStream<{\n type: string;\n data?: string;\n exitCode?: number;\n processId?: string;\n }>(stream)) {\n switch (event.type) {\n case 'stdout':\n if (event.data && options.onOutput) {\n options.onOutput('stdout', event.data);\n }\n break;\n case 'stderr':\n if (event.data && options.onOutput) {\n options.onOutput('stderr', event.data);\n }\n break;\n case 'exit':\n case 'complete':\n if (options.onExit) {\n options.onExit(event.exitCode ?? null);\n }\n return; // Stream complete\n }\n }\n } catch (error) {\n // Call onError if streaming fails\n if (options.onError && error instanceof Error) {\n options.onError(error);\n }\n // Don't rethrow - background streaming failure shouldn't crash the caller\n this.logger.error(\n 'Background process streaming failed',\n error instanceof Error ? error : new Error(String(error)),\n { processId }\n );\n }\n }\n\n async listProcesses(sessionId?: string): Promise<Process[]> {\n const session = sessionId ?? (await this.ensureDefaultSession());\n const response = await this.client.processes.listProcesses();\n\n return response.processes.map((processData) =>\n this.createProcessFromDTO(\n {\n id: processData.id,\n pid: processData.pid,\n command: processData.command,\n status: processData.status,\n startTime: processData.startTime,\n endTime: processData.endTime,\n exitCode: processData.exitCode\n },\n session\n )\n );\n }\n\n async getProcess(id: string, sessionId?: string): Promise<Process | null> {\n const session = sessionId ?? (await this.ensureDefaultSession());\n const response = await this.client.processes.getProcess(id);\n if (!response.process) {\n return null;\n }\n\n const processData = response.process;\n return this.createProcessFromDTO(\n {\n id: processData.id,\n pid: processData.pid,\n command: processData.command,\n status: processData.status,\n startTime: processData.startTime,\n endTime: processData.endTime,\n exitCode: processData.exitCode\n },\n session\n );\n }\n\n async killProcess(\n id: string,\n signal?: string,\n sessionId?: string\n ): Promise<void> {\n // Note: signal parameter is not currently supported by the HTTP client\n await this.client.processes.killProcess(id);\n }\n\n async killAllProcesses(sessionId?: string): Promise<number> {\n const response = await this.client.processes.killAllProcesses();\n return response.cleanedCount;\n }\n\n async cleanupCompletedProcesses(sessionId?: string): Promise<number> {\n // Not yet implemented - requires container endpoint\n return 0;\n }\n\n async getProcessLogs(\n id: string,\n sessionId?: string\n ): Promise<{ stdout: string; stderr: string; processId: string }> {\n const response = await this.client.processes.getProcessLogs(id);\n return {\n stdout: response.stdout,\n stderr: response.stderr,\n processId: response.processId\n };\n }\n\n // Streaming methods - return ReadableStream for RPC compatibility\n async execStream(\n command: string,\n options?: StreamOptions\n ): Promise<ReadableStream<Uint8Array>> {\n // Check for cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n const session = await this.ensureDefaultSession();\n // Get the stream from CommandClient\n return this.client.commands.executeStream(command, session, {\n timeoutMs: options?.timeout,\n env: options?.env,\n cwd: options?.cwd\n });\n }\n\n /**\n * Internal session-aware execStream implementation\n */\n private async execStreamWithSession(\n command: string,\n sessionId: string,\n options?: StreamOptions\n ): Promise<ReadableStream<Uint8Array>> {\n // Check for cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n return this.client.commands.executeStream(command, sessionId, {\n timeoutMs: options?.timeout,\n env: options?.env,\n cwd: options?.cwd\n });\n }\n\n /**\n * Stream logs from a background process as a ReadableStream.\n */\n async streamProcessLogs(\n processId: string,\n options?: { signal?: AbortSignal }\n ): Promise<ReadableStream<Uint8Array>> {\n // Check for cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n return this.client.processes.streamProcessLogs(processId);\n }\n\n async gitCheckout(\n repoUrl: string,\n options?: { branch?: string; targetDir?: string; sessionId?: string }\n ) {\n const session = options?.sessionId ?? (await this.ensureDefaultSession());\n return this.client.git.checkout(repoUrl, session, {\n branch: options?.branch,\n targetDir: options?.targetDir\n });\n }\n\n async mkdir(\n path: string,\n options: { recursive?: boolean; sessionId?: string } = {}\n ) {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.mkdir(path, session, {\n recursive: options.recursive\n });\n }\n\n async writeFile(\n path: string,\n content: string,\n options: { encoding?: string; sessionId?: string } = {}\n ) {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.writeFile(path, content, session, {\n encoding: options.encoding\n });\n }\n\n async deleteFile(path: string, sessionId?: string) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.deleteFile(path, session);\n }\n\n async renameFile(oldPath: string, newPath: string, sessionId?: string) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.renameFile(oldPath, newPath, session);\n }\n\n async moveFile(\n sourcePath: string,\n destinationPath: string,\n sessionId?: string\n ) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.moveFile(sourcePath, destinationPath, session);\n }\n\n async readFile(\n path: string,\n options: { encoding?: string; sessionId?: string } = {}\n ) {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.readFile(path, session, {\n encoding: options.encoding\n });\n }\n\n /**\n * Stream a file from the sandbox using Server-Sent Events\n * Returns a ReadableStream that can be consumed with streamFile() or collectFile() utilities\n * @param path - Path to the file to stream\n * @param options - Optional session ID\n */\n async readFileStream(\n path: string,\n options: { sessionId?: string } = {}\n ): Promise<ReadableStream<Uint8Array>> {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.readFileStream(path, session);\n }\n\n async listFiles(\n path: string,\n options?: { recursive?: boolean; includeHidden?: boolean }\n ) {\n const session = await this.ensureDefaultSession();\n return this.client.files.listFiles(path, session, options);\n }\n\n async exists(path: string, sessionId?: string) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.exists(path, session);\n }\n\n async exposePort(port: number, options: { name?: string; hostname: string }) {\n // Check if hostname is workers.dev domain (doesn't support wildcard subdomains)\n if (options.hostname.endsWith('.workers.dev')) {\n const errorResponse: ErrorResponse = {\n code: ErrorCode.CUSTOM_DOMAIN_REQUIRED,\n message: `Port exposure requires a custom domain. .workers.dev domains do not support wildcard subdomains required for port proxying.`,\n context: { originalError: options.hostname },\n httpStatus: 400,\n timestamp: new Date().toISOString()\n };\n throw new CustomDomainRequiredError(errorResponse);\n }\n\n const sessionId = await this.ensureDefaultSession();\n await this.client.ports.exposePort(port, sessionId, 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 // Generate and store token for this port (storage is protected by input gates)\n const token = this.generatePortToken();\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n tokens[port.toString()] = token;\n await this.ctx.storage.put('portTokens', tokens);\n\n const url = this.constructPreviewUrl(\n port,\n this.sandboxName,\n options.hostname,\n token\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 throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n const sessionId = await this.ensureDefaultSession();\n await this.client.ports.unexposePort(port, sessionId);\n\n // Clean up token for this port (storage is protected by input gates)\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n if (tokens[port.toString()]) {\n delete tokens[port.toString()];\n await this.ctx.storage.put('portTokens', tokens);\n }\n }\n\n async getExposedPorts(hostname: string) {\n const sessionId = await this.ensureDefaultSession();\n const response = await this.client.ports.getExposedPorts(sessionId);\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 // Read all tokens from storage (protected by input gates)\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n\n return response.ports.map((port) => {\n const token = tokens[port.port.toString()];\n if (!token) {\n throw new Error(\n `Port ${port.port} is exposed but has no token. This should not happen.`\n );\n }\n\n return {\n url: this.constructPreviewUrl(\n port.port,\n this.sandboxName!,\n hostname,\n token\n ),\n port: port.port,\n status: port.status\n };\n });\n }\n\n async isPortExposed(port: number): Promise<boolean> {\n try {\n const sessionId = await this.ensureDefaultSession();\n const response = await this.client.ports.getExposedPorts(sessionId);\n return response.ports.some((exposedPort) => exposedPort.port === port);\n } catch (error) {\n this.logger.error(\n 'Error checking if port is exposed',\n error instanceof Error ? error : new Error(String(error)),\n { port }\n );\n return false;\n }\n }\n\n async validatePortToken(port: number, token: string): Promise<boolean> {\n // First check if port is exposed\n const isExposed = await this.isPortExposed(port);\n if (!isExposed) {\n return false;\n }\n\n // Read stored token from storage (protected by input gates)\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n const storedToken = tokens[port.toString()];\n if (!storedToken) {\n // This should not happen - all exposed ports must have tokens\n this.logger.error(\n 'Port is exposed but has no token - bug detected',\n undefined,\n { port }\n );\n return false;\n }\n\n // Constant-time comparison to prevent timing attacks\n return storedToken === token;\n }\n\n private generatePortToken(): string {\n // Generate cryptographically secure 16-character token using Web Crypto API\n // Available in Cloudflare Workers runtime\n const array = new Uint8Array(12); // 12 bytes = 16 base64url chars (after padding removal)\n crypto.getRandomValues(array);\n\n // Convert to base64url format (URL-safe, no padding, lowercase)\n const base64 = btoa(String.fromCharCode(...array));\n return base64\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n .toLowerCase();\n }\n\n private constructPreviewUrl(\n port: number,\n sandboxId: string,\n hostname: string,\n token: string\n ): string {\n if (!validatePort(port)) {\n throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n // Hostnames are case-insensitive, routing requests to wrong DO instance when keys contain uppercase letters\n const effectiveId = this.sandboxName || sandboxId;\n const hasUppercase = /[A-Z]/.test(effectiveId);\n if (!this.normalizeId && hasUppercase) {\n throw new SecurityError(\n `Preview URLs require lowercase sandbox IDs. Your ID \"${effectiveId}\" contains uppercase letters.\\n\\n` +\n `To fix this:\\n` +\n `1. Create a new sandbox with: getSandbox(ns, \"${effectiveId}\", { normalizeId: true })\\n` +\n `2. This will create a sandbox with ID: \"${effectiveId.toLowerCase()}\"\\n\\n` +\n `Note: Due to DNS case-insensitivity, IDs with uppercase letters cannot be used with preview URLs.`\n );\n }\n\n const sanitizedSandboxId = sanitizeSandboxId(sandboxId).toLowerCase();\n\n const isLocalhost = isLocalhostPattern(hostname);\n\n if (isLocalhost) {\n const [host, portStr] = hostname.split(':');\n const mainPort = portStr || '80';\n\n try {\n const baseUrl = new URL(`http://${host}:${mainPort}`);\n const subdomainHost = `${port}-${sanitizedSandboxId}-${token}.${host}`;\n baseUrl.hostname = subdomainHost;\n\n return baseUrl.toString();\n } catch (error) {\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n }\n }\n\n try {\n const baseUrl = new URL(`https://${hostname}`);\n const subdomainHost = `${port}-${sanitizedSandboxId}-${token}.${hostname}`;\n baseUrl.hostname = subdomainHost;\n\n return baseUrl.toString();\n } catch (error) {\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n }\n }\n\n // ============================================================================\n // Session Management - Advanced Use Cases\n // ============================================================================\n\n /**\n * Create isolated execution session for advanced use cases\n * Returns ExecutionSession with full sandbox API bound to specific session\n */\n async createSession(options?: SessionOptions): Promise<ExecutionSession> {\n const sessionId = options?.id || `session-${Date.now()}`;\n\n const mergedEnv = {\n ...this.envVars,\n ...(options?.env ?? {})\n };\n const envPayload =\n Object.keys(mergedEnv).length > 0 ? mergedEnv : undefined;\n\n // Create session in container\n await this.client.utils.createSession({\n id: sessionId,\n ...(envPayload && { env: envPayload }),\n ...(options?.cwd && { cwd: options.cwd })\n });\n\n // Return wrapper that binds sessionId to all operations\n return this.getSessionWrapper(sessionId);\n }\n\n /**\n * Get an existing session by ID\n * Returns ExecutionSession wrapper bound to the specified session\n *\n * This is useful for retrieving sessions across different requests/contexts\n * without storing the ExecutionSession object (which has RPC lifecycle limitations)\n *\n * @param sessionId - The ID of an existing session\n * @returns ExecutionSession wrapper bound to the session\n */\n async getSession(sessionId: string): Promise<ExecutionSession> {\n // No need to verify session exists in container - operations will fail naturally if it doesn't\n return this.getSessionWrapper(sessionId);\n }\n\n /**\n * Delete an execution session\n * Cleans up session resources and removes it from the container\n * Note: Cannot delete the default session. To reset the default session,\n * use sandbox.destroy() to terminate the entire sandbox.\n *\n * @param sessionId - The ID of the session to delete\n * @returns Result with success status, sessionId, and timestamp\n * @throws Error if attempting to delete the default session\n */\n async deleteSession(sessionId: string): Promise<SessionDeleteResult> {\n // Prevent deletion of default session\n if (this.defaultSession && sessionId === this.defaultSession) {\n throw new Error(\n `Cannot delete default session '${sessionId}'. Use sandbox.destroy() to terminate the sandbox.`\n );\n }\n\n const response = await this.client.utils.deleteSession(sessionId);\n\n // Map HTTP response to result type\n return {\n success: response.success,\n sessionId: response.sessionId,\n timestamp: response.timestamp\n };\n }\n\n /**\n * Internal helper to create ExecutionSession wrapper for a given sessionId\n * Used by both createSession and getSession\n */\n private getSessionWrapper(sessionId: string): ExecutionSession {\n return {\n id: sessionId,\n\n // Command execution - delegate to internal session-aware methods\n exec: (command, options) =>\n this.execWithSession(command, sessionId, options),\n execStream: (command, options) =>\n this.execStreamWithSession(command, sessionId, options),\n\n // Process management\n startProcess: (command, options) =>\n this.startProcess(command, options, sessionId),\n listProcesses: () => this.listProcesses(sessionId),\n getProcess: (id) => this.getProcess(id, sessionId),\n killProcess: (id, signal) => this.killProcess(id, signal),\n killAllProcesses: () => this.killAllProcesses(),\n cleanupCompletedProcesses: () => this.cleanupCompletedProcesses(),\n getProcessLogs: (id) => this.getProcessLogs(id),\n streamProcessLogs: (processId, options) =>\n this.streamProcessLogs(processId, options),\n\n // File operations - pass sessionId via options or parameter\n writeFile: (path, content, options) =>\n this.writeFile(path, content, { ...options, sessionId }),\n readFile: (path, options) =>\n this.readFile(path, { ...options, sessionId }),\n readFileStream: (path) => this.readFileStream(path, { sessionId }),\n mkdir: (path, options) => this.mkdir(path, { ...options, sessionId }),\n deleteFile: (path) => this.deleteFile(path, sessionId),\n renameFile: (oldPath, newPath) =>\n this.renameFile(oldPath, newPath, sessionId),\n moveFile: (sourcePath, destPath) =>\n this.moveFile(sourcePath, destPath, sessionId),\n listFiles: (path, options) =>\n this.client.files.listFiles(path, sessionId, options),\n exists: (path) => this.exists(path, sessionId),\n\n // Git operations\n gitCheckout: (repoUrl, options) =>\n this.gitCheckout(repoUrl, { ...options, sessionId }),\n\n // Environment management - needs special handling\n setEnvVars: async (envVars: Record<string, string>) => {\n try {\n // Set environment variables by executing export commands\n for (const [key, value] of Object.entries(envVars)) {\n const escapedValue = value.replace(/'/g, \"'\\\\''\");\n const exportCommand = `export ${key}='${escapedValue}'`;\n\n const result = await this.client.commands.execute(\n exportCommand,\n sessionId\n );\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to set ${key}: ${result.stderr || 'Unknown error'}`\n );\n }\n }\n } catch (error) {\n this.logger.error(\n 'Failed to set environment variables',\n error instanceof Error ? error : new Error(String(error)),\n { sessionId }\n );\n throw error;\n }\n },\n\n // Code interpreter methods - delegate to sandbox's code interpreter\n createCodeContext: (options) =>\n this.codeInterpreter.createCodeContext(options),\n runCode: async (code, options) => {\n const execution = await this.codeInterpreter.runCode(code, options);\n return execution.toJSON();\n },\n runCodeStream: (code, options) =>\n this.codeInterpreter.runCodeStream(code, options),\n listCodeContexts: () => this.codeInterpreter.listCodeContexts(),\n deleteCodeContext: (contextId) =>\n this.codeInterpreter.deleteCodeContext(contextId),\n\n // Bucket mounting - sandbox-level operations\n mountBucket: (bucket, mountPath, options) =>\n this.mountBucket(bucket, mountPath, options),\n unmountBucket: (mountPath) => this.unmountBucket(mountPath)\n };\n }\n\n // ============================================================================\n // Code interpreter methods - delegate to CodeInterpreter wrapper\n // ============================================================================\n\n async createCodeContext(\n options?: CreateContextOptions\n ): Promise<CodeContext> {\n return this.codeInterpreter.createCodeContext(options);\n }\n\n async runCode(\n code: string,\n options?: RunCodeOptions\n ): Promise<ExecutionResult> {\n const execution = await this.codeInterpreter.runCode(code, options);\n return execution.toJSON();\n }\n\n async runCodeStream(\n code: string,\n options?: RunCodeOptions\n ): Promise<ReadableStream> {\n return this.codeInterpreter.runCodeStream(code, options);\n }\n\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.codeInterpreter.listCodeContexts();\n }\n\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.codeInterpreter.deleteCodeContext(contextId);\n }\n}\n","import type { FileChunk, FileMetadata, FileStreamEvent } from '@repo/shared';\n\n/**\n * Parse SSE (Server-Sent Events) lines from a stream\n */\nasync function* parseSSE(\n stream: ReadableStream<Uint8Array>\n): AsyncGenerator<FileStreamEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in the buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6); // Remove 'data: ' prefix\n try {\n const event = JSON.parse(data) as FileStreamEvent;\n yield event;\n } catch {\n // Skip invalid JSON events and continue processing\n }\n }\n }\n }\n } finally {\n // Cancel the stream first to properly terminate HTTP connections when breaking early\n try {\n await reader.cancel();\n } catch {\n // Ignore cancel errors (stream may already be closed)\n }\n reader.releaseLock();\n }\n}\n\n/**\n * Stream a file from the sandbox with automatic base64 decoding for binary files\n *\n * @param stream - The ReadableStream from readFileStream()\n * @returns AsyncGenerator that yields FileChunk (string for text, Uint8Array for binary)\n *\n * @example\n * ```ts\n * const stream = await sandbox.readFileStream('/path/to/file.png');\n * for await (const chunk of streamFile(stream)) {\n * if (chunk instanceof Uint8Array) {\n * // Binary chunk\n * console.log('Binary chunk:', chunk.length, 'bytes');\n * } else {\n * // Text chunk\n * console.log('Text chunk:', chunk);\n * }\n * }\n * ```\n */\nexport async function* streamFile(\n stream: ReadableStream<Uint8Array>\n): AsyncGenerator<FileChunk, FileMetadata> {\n let metadata: FileMetadata | null = null;\n\n for await (const event of parseSSE(stream)) {\n switch (event.type) {\n case 'metadata':\n metadata = {\n mimeType: event.mimeType,\n size: event.size,\n isBinary: event.isBinary,\n encoding: event.encoding\n };\n break;\n\n case 'chunk':\n if (!metadata) {\n throw new Error('Received chunk before metadata');\n }\n\n if (metadata.isBinary && metadata.encoding === 'base64') {\n // Decode base64 to Uint8Array for binary files\n const binaryString = atob(event.data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n yield bytes;\n } else {\n // Text files - yield as-is\n yield event.data;\n }\n break;\n\n case 'complete':\n if (!metadata) {\n throw new Error('Stream completed without metadata');\n }\n return metadata;\n\n case 'error':\n throw new Error(`File streaming error: ${event.error}`);\n }\n }\n\n throw new Error('Stream ended unexpectedly');\n}\n\n/**\n * Collect an entire file into memory from a stream\n *\n * @param stream - The ReadableStream from readFileStream()\n * @returns Object containing the file content and metadata\n *\n * @example\n * ```ts\n * const stream = await sandbox.readFileStream('/path/to/file.txt');\n * const { content, metadata } = await collectFile(stream);\n * console.log('Content:', content);\n * console.log('MIME type:', metadata.mimeType);\n * ```\n */\nexport async function collectFile(stream: ReadableStream<Uint8Array>): Promise<{\n content: string | Uint8Array;\n metadata: FileMetadata;\n}> {\n const chunks: Array<string | Uint8Array> = [];\n\n // Iterate through the generator and get the return value (metadata)\n const generator = streamFile(stream);\n let result = await generator.next();\n\n while (!result.done) {\n chunks.push(result.value);\n result = await generator.next();\n }\n\n const metadata = result.value;\n\n if (!metadata) {\n throw new Error('Failed to get file metadata');\n }\n\n // Combine chunks based on type\n if (metadata.isBinary) {\n // Binary file - combine Uint8Arrays\n const totalLength = chunks.reduce(\n (sum, chunk) => sum + (chunk instanceof Uint8Array ? chunk.length : 0),\n 0\n );\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n if (chunk instanceof Uint8Array) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n }\n return { content: combined, metadata };\n } else {\n // Text file - combine strings\n const combined = chunks.filter((c) => typeof c === 'string').join('');\n return { content: combined, metadata };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["errorResponse: ErrorResponse<TContext>","response: Response","request: WSRequest","sseData: string","errorData: NewErrorResponse","data: ExecuteRequest","data: GitCheckoutRequest","lastError: Error | undefined","data: StartProcessRequest","clientOptions: HttpClientOptions","code?: string","proxyUrl: string","sanitizedSandboxId: string","provider: BucketProvider | null","s3fsArgs: string[]","request: Request","port: number | undefined","error: unknown","result: ExecResult","timeoutId: ReturnType<typeof setTimeout> | undefined","timeoutPromise: Promise<never> | undefined","metadata: FileMetadata | null","chunks: Array<string | Uint8Array>"],"sources":["../src/errors/classes.ts","../src/errors/adapter.ts","../src/clients/transport/base-transport.ts","../src/clients/transport/http-transport.ts","../src/clients/transport/ws-transport.ts","../src/clients/transport/factory.ts","../src/clients/base-client.ts","../src/clients/command-client.ts","../src/clients/file-client.ts","../src/clients/git-client.ts","../src/clients/interpreter-client.ts","../src/clients/port-client.ts","../src/clients/process-client.ts","../src/clients/utility-client.ts","../src/clients/sandbox-client.ts","../src/security.ts","../src/interpreter.ts","../src/request-handler.ts","../src/sse-parser.ts","../src/storage-mount/errors.ts","../src/storage-mount/credential-detection.ts","../src/storage-mount/provider-detection.ts","../src/version.ts","../src/sandbox.ts","../src/file-stream.ts"],"sourcesContent":["/**\n * Type-safe error classes that wrap ErrorResponse from container\n *\n * All error classes extend SandboxError<TContext> which wraps the full ErrorResponse\n * and provides type-safe accessors for error properties.\n */\n\nimport type {\n CodeExecutionContext,\n CommandErrorContext,\n CommandNotFoundContext,\n ContextNotFoundContext,\n ErrorResponse,\n FileExistsContext,\n FileNotFoundContext,\n FileSystemContext,\n GitAuthFailedContext,\n GitBranchNotFoundContext,\n GitErrorContext,\n GitRepositoryNotFoundContext,\n InternalErrorContext,\n InterpreterNotReadyContext,\n InvalidPortContext,\n PortAlreadyExposedContext,\n PortErrorContext,\n PortNotExposedContext,\n ProcessErrorContext,\n ProcessExitedBeforeReadyContext,\n ProcessNotFoundContext,\n ProcessReadyTimeoutContext,\n SessionAlreadyExistsContext,\n ValidationFailedContext\n} from '@repo/shared/errors';\n\n/**\n * Base SDK error that wraps ErrorResponse\n * Preserves all error information from container\n */\nexport class SandboxError<TContext = Record<string, unknown>> extends Error {\n constructor(public readonly errorResponse: ErrorResponse<TContext>) {\n super(errorResponse.message);\n this.name = 'SandboxError';\n }\n\n // Convenience accessors\n get code() {\n return this.errorResponse.code;\n }\n get context() {\n return this.errorResponse.context;\n }\n get httpStatus() {\n return this.errorResponse.httpStatus;\n }\n get operation() {\n return this.errorResponse.operation;\n }\n get suggestion() {\n return this.errorResponse.suggestion;\n }\n get timestamp() {\n return this.errorResponse.timestamp;\n }\n get documentation() {\n return this.errorResponse.documentation;\n }\n\n // Custom serialization for logging\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n context: this.context,\n httpStatus: this.httpStatus,\n operation: this.operation,\n suggestion: this.suggestion,\n timestamp: this.timestamp,\n documentation: this.documentation,\n stack: this.stack\n };\n }\n}\n\n// ============================================================================\n// File System Errors\n// ============================================================================\n\n/**\n * Error thrown when a file or directory is not found\n */\nexport class FileNotFoundError extends SandboxError<FileNotFoundContext> {\n constructor(errorResponse: ErrorResponse<FileNotFoundContext>) {\n super(errorResponse);\n this.name = 'FileNotFoundError';\n }\n\n // Type-safe accessors\n get path() {\n return this.context.path;\n }\n}\n\n/**\n * Error thrown when a file already exists\n */\nexport class FileExistsError extends SandboxError<FileExistsContext> {\n constructor(errorResponse: ErrorResponse<FileExistsContext>) {\n super(errorResponse);\n this.name = 'FileExistsError';\n }\n\n // Type-safe accessor\n get path() {\n return this.context.path;\n }\n}\n\n/**\n * Generic file system error (permissions, disk full, etc.)\n */\nexport class FileSystemError extends SandboxError<FileSystemContext> {\n constructor(errorResponse: ErrorResponse<FileSystemContext>) {\n super(errorResponse);\n this.name = 'FileSystemError';\n }\n\n // Type-safe accessors\n get path() {\n return this.context.path;\n }\n get stderr() {\n return this.context.stderr;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n\n/**\n * Error thrown when permission is denied\n */\nexport class PermissionDeniedError extends SandboxError<FileSystemContext> {\n constructor(errorResponse: ErrorResponse<FileSystemContext>) {\n super(errorResponse);\n this.name = 'PermissionDeniedError';\n }\n\n get path() {\n return this.context.path;\n }\n}\n\n// ============================================================================\n// Command Errors\n// ============================================================================\n\n/**\n * Error thrown when a command is not found\n */\nexport class CommandNotFoundError extends SandboxError<CommandNotFoundContext> {\n constructor(errorResponse: ErrorResponse<CommandNotFoundContext>) {\n super(errorResponse);\n this.name = 'CommandNotFoundError';\n }\n\n // Type-safe accessor\n get command() {\n return this.context.command;\n }\n}\n\n/**\n * Generic command execution error\n */\nexport class CommandError extends SandboxError<CommandErrorContext> {\n constructor(errorResponse: ErrorResponse<CommandErrorContext>) {\n super(errorResponse);\n this.name = 'CommandError';\n }\n\n // Type-safe accessors\n get command() {\n return this.context.command;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n get stdout() {\n return this.context.stdout;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n// ============================================================================\n// Process Errors\n// ============================================================================\n\n/**\n * Error thrown when a process is not found\n */\nexport class ProcessNotFoundError extends SandboxError<ProcessNotFoundContext> {\n constructor(errorResponse: ErrorResponse<ProcessNotFoundContext>) {\n super(errorResponse);\n this.name = 'ProcessNotFoundError';\n }\n\n // Type-safe accessor\n get processId() {\n return this.context.processId;\n }\n}\n\n/**\n * Generic process error\n */\nexport class ProcessError extends SandboxError<ProcessErrorContext> {\n constructor(errorResponse: ErrorResponse<ProcessErrorContext>) {\n super(errorResponse);\n this.name = 'ProcessError';\n }\n\n // Type-safe accessors\n get processId() {\n return this.context.processId;\n }\n get pid() {\n return this.context.pid;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n// ============================================================================\n// Session Errors\n// ============================================================================\n\n/**\n * Error thrown when a session already exists\n */\nexport class SessionAlreadyExistsError extends SandboxError<SessionAlreadyExistsContext> {\n constructor(errorResponse: ErrorResponse<SessionAlreadyExistsContext>) {\n super(errorResponse);\n this.name = 'SessionAlreadyExistsError';\n }\n\n // Type-safe accessors\n get sessionId() {\n return this.context.sessionId;\n }\n}\n\n// ============================================================================\n// Port Errors\n// ============================================================================\n\n/**\n * Error thrown when a port is already exposed\n */\nexport class PortAlreadyExposedError extends SandboxError<PortAlreadyExposedContext> {\n constructor(errorResponse: ErrorResponse<PortAlreadyExposedContext>) {\n super(errorResponse);\n this.name = 'PortAlreadyExposedError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get portName() {\n return this.context.portName;\n }\n}\n\n/**\n * Error thrown when a port is not exposed\n */\nexport class PortNotExposedError extends SandboxError<PortNotExposedContext> {\n constructor(errorResponse: ErrorResponse<PortNotExposedContext>) {\n super(errorResponse);\n this.name = 'PortNotExposedError';\n }\n\n // Type-safe accessor\n get port() {\n return this.context.port;\n }\n}\n\n/**\n * Error thrown when a port number is invalid\n */\nexport class InvalidPortError extends SandboxError<InvalidPortContext> {\n constructor(errorResponse: ErrorResponse<InvalidPortContext>) {\n super(errorResponse);\n this.name = 'InvalidPortError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get reason() {\n return this.context.reason;\n }\n}\n\n/**\n * Error thrown when a service on a port is not responding\n */\nexport class ServiceNotRespondingError extends SandboxError<PortErrorContext> {\n constructor(errorResponse: ErrorResponse<PortErrorContext>) {\n super(errorResponse);\n this.name = 'ServiceNotRespondingError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get portName() {\n return this.context.portName;\n }\n}\n\n/**\n * Error thrown when a port is already in use\n */\nexport class PortInUseError extends SandboxError<PortErrorContext> {\n constructor(errorResponse: ErrorResponse<PortErrorContext>) {\n super(errorResponse);\n this.name = 'PortInUseError';\n }\n\n // Type-safe accessor\n get port() {\n return this.context.port;\n }\n}\n\n/**\n * Generic port operation error\n */\nexport class PortError extends SandboxError<PortErrorContext> {\n constructor(errorResponse: ErrorResponse<PortErrorContext>) {\n super(errorResponse);\n this.name = 'PortError';\n }\n\n // Type-safe accessors\n get port() {\n return this.context.port;\n }\n get portName() {\n return this.context.portName;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n/**\n * Error thrown when port exposure requires a custom domain\n */\nexport class CustomDomainRequiredError extends SandboxError<InternalErrorContext> {\n constructor(errorResponse: ErrorResponse<InternalErrorContext>) {\n super(errorResponse);\n this.name = 'CustomDomainRequiredError';\n }\n}\n\n// ============================================================================\n// Git Errors\n// ============================================================================\n\n/**\n * Error thrown when a git repository is not found\n */\nexport class GitRepositoryNotFoundError extends SandboxError<GitRepositoryNotFoundContext> {\n constructor(errorResponse: ErrorResponse<GitRepositoryNotFoundContext>) {\n super(errorResponse);\n this.name = 'GitRepositoryNotFoundError';\n }\n\n // Type-safe accessor\n get repository() {\n return this.context.repository;\n }\n}\n\n/**\n * Error thrown when git authentication fails\n */\nexport class GitAuthenticationError extends SandboxError<GitAuthFailedContext> {\n constructor(errorResponse: ErrorResponse<GitAuthFailedContext>) {\n super(errorResponse);\n this.name = 'GitAuthenticationError';\n }\n\n // Type-safe accessor\n get repository() {\n return this.context.repository;\n }\n}\n\n/**\n * Error thrown when a git branch is not found\n */\nexport class GitBranchNotFoundError extends SandboxError<GitBranchNotFoundContext> {\n constructor(errorResponse: ErrorResponse<GitBranchNotFoundContext>) {\n super(errorResponse);\n this.name = 'GitBranchNotFoundError';\n }\n\n // Type-safe accessors\n get branch() {\n return this.context.branch;\n }\n get repository() {\n return this.context.repository;\n }\n}\n\n/**\n * Error thrown when a git network operation fails\n */\nexport class GitNetworkError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitNetworkError';\n }\n\n // Type-safe accessors\n get repository() {\n return this.context.repository;\n }\n get branch() {\n return this.context.branch;\n }\n get targetDir() {\n return this.context.targetDir;\n }\n}\n\n/**\n * Error thrown when git clone fails\n */\nexport class GitCloneError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitCloneError';\n }\n\n // Type-safe accessors\n get repository() {\n return this.context.repository;\n }\n get targetDir() {\n return this.context.targetDir;\n }\n get stderr() {\n return this.context.stderr;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n\n/**\n * Error thrown when git checkout fails\n */\nexport class GitCheckoutError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitCheckoutError';\n }\n\n // Type-safe accessors\n get branch() {\n return this.context.branch;\n }\n get repository() {\n return this.context.repository;\n }\n get stderr() {\n return this.context.stderr;\n }\n}\n\n/**\n * Error thrown when a git URL is invalid\n */\nexport class InvalidGitUrlError extends SandboxError<ValidationFailedContext> {\n constructor(errorResponse: ErrorResponse<ValidationFailedContext>) {\n super(errorResponse);\n this.name = 'InvalidGitUrlError';\n }\n\n // Type-safe accessor\n get validationErrors() {\n return this.context.validationErrors;\n }\n}\n\n/**\n * Generic git operation error\n */\nexport class GitError extends SandboxError<GitErrorContext> {\n constructor(errorResponse: ErrorResponse<GitErrorContext>) {\n super(errorResponse);\n this.name = 'GitError';\n }\n\n // Type-safe accessors\n get repository() {\n return this.context.repository;\n }\n get branch() {\n return this.context.branch;\n }\n get targetDir() {\n return this.context.targetDir;\n }\n get stderr() {\n return this.context.stderr;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n\n// ============================================================================\n// Code Interpreter Errors\n// ============================================================================\n\n/**\n * Error thrown when interpreter is not ready\n */\nexport class InterpreterNotReadyError extends SandboxError<InterpreterNotReadyContext> {\n constructor(errorResponse: ErrorResponse<InterpreterNotReadyContext>) {\n super(errorResponse);\n this.name = 'InterpreterNotReadyError';\n }\n\n // Type-safe accessors\n get retryAfter() {\n return this.context.retryAfter;\n }\n get progress() {\n return this.context.progress;\n }\n}\n\n/**\n * Error thrown when a context is not found\n */\nexport class ContextNotFoundError extends SandboxError<ContextNotFoundContext> {\n constructor(errorResponse: ErrorResponse<ContextNotFoundContext>) {\n super(errorResponse);\n this.name = 'ContextNotFoundError';\n }\n\n // Type-safe accessor\n get contextId() {\n return this.context.contextId;\n }\n}\n\n/**\n * Error thrown when code execution fails\n */\nexport class CodeExecutionError extends SandboxError<CodeExecutionContext> {\n constructor(errorResponse: ErrorResponse<CodeExecutionContext>) {\n super(errorResponse);\n this.name = 'CodeExecutionError';\n }\n\n // Type-safe accessors\n get contextId() {\n return this.context.contextId;\n }\n get ename() {\n return this.context.ename;\n }\n get evalue() {\n return this.context.evalue;\n }\n get traceback() {\n return this.context.traceback;\n }\n}\n\n// ============================================================================\n// Validation Errors\n// ============================================================================\n\n/**\n * Error thrown when validation fails\n */\nexport class ValidationFailedError extends SandboxError<ValidationFailedContext> {\n constructor(errorResponse: ErrorResponse<ValidationFailedContext>) {\n super(errorResponse);\n this.name = 'ValidationFailedError';\n }\n\n // Type-safe accessor\n get validationErrors() {\n return this.context.validationErrors;\n }\n}\n\n// ============================================================================\n// Process Readiness Errors\n// ============================================================================\n\n/**\n * Error thrown when a process does not become ready within the timeout period\n */\nexport class ProcessReadyTimeoutError extends SandboxError<ProcessReadyTimeoutContext> {\n constructor(errorResponse: ErrorResponse<ProcessReadyTimeoutContext>) {\n super(errorResponse);\n this.name = 'ProcessReadyTimeoutError';\n }\n\n // Type-safe accessors\n get processId() {\n return this.context.processId;\n }\n get command() {\n return this.context.command;\n }\n get condition() {\n return this.context.condition;\n }\n get timeout() {\n return this.context.timeout;\n }\n}\n\n/**\n * Error thrown when a process exits before becoming ready\n */\nexport class ProcessExitedBeforeReadyError extends SandboxError<ProcessExitedBeforeReadyContext> {\n constructor(errorResponse: ErrorResponse<ProcessExitedBeforeReadyContext>) {\n super(errorResponse);\n this.name = 'ProcessExitedBeforeReadyError';\n }\n\n // Type-safe accessors\n get processId() {\n return this.context.processId;\n }\n get command() {\n return this.context.command;\n }\n get condition() {\n return this.context.condition;\n }\n get exitCode() {\n return this.context.exitCode;\n }\n}\n","/**\n * Error adapter that converts ErrorResponse to appropriate Error class\n *\n * Simple switch statement - we trust the container sends correct context\n * No validation overhead since we control both sides\n */\n\nimport type {\n CodeExecutionContext,\n CommandErrorContext,\n CommandNotFoundContext,\n ContextNotFoundContext,\n ErrorResponse,\n FileExistsContext,\n FileNotFoundContext,\n FileSystemContext,\n GitAuthFailedContext,\n GitBranchNotFoundContext,\n GitErrorContext,\n GitRepositoryNotFoundContext,\n InternalErrorContext,\n InterpreterNotReadyContext,\n InvalidPortContext,\n PortAlreadyExposedContext,\n PortErrorContext,\n PortNotExposedContext,\n ProcessErrorContext,\n ProcessNotFoundContext,\n SessionAlreadyExistsContext,\n ValidationFailedContext\n} from '@repo/shared/errors';\nimport { ErrorCode } from '@repo/shared/errors';\n\nimport {\n CodeExecutionError,\n CommandError,\n CommandNotFoundError,\n ContextNotFoundError,\n CustomDomainRequiredError,\n FileExistsError,\n FileNotFoundError,\n FileSystemError,\n GitAuthenticationError,\n GitBranchNotFoundError,\n GitCheckoutError,\n GitCloneError,\n GitError,\n GitNetworkError,\n GitRepositoryNotFoundError,\n InterpreterNotReadyError,\n InvalidGitUrlError,\n InvalidPortError,\n PermissionDeniedError,\n PortAlreadyExposedError,\n PortError,\n PortInUseError,\n PortNotExposedError,\n ProcessError,\n ProcessNotFoundError,\n SandboxError,\n ServiceNotRespondingError,\n SessionAlreadyExistsError,\n ValidationFailedError\n} from './classes';\n\n/**\n * Convert ErrorResponse to appropriate Error class\n * Simple switch statement - we trust the container sends correct context\n */\nexport function createErrorFromResponse(errorResponse: ErrorResponse): Error {\n // We trust the container sends correct context, use type assertions\n switch (errorResponse.code) {\n // File System Errors\n case ErrorCode.FILE_NOT_FOUND:\n return new FileNotFoundError(\n errorResponse as unknown as ErrorResponse<FileNotFoundContext>\n );\n\n case ErrorCode.FILE_EXISTS:\n return new FileExistsError(\n errorResponse as unknown as ErrorResponse<FileExistsContext>\n );\n\n case ErrorCode.PERMISSION_DENIED:\n return new PermissionDeniedError(\n errorResponse as unknown as ErrorResponse<FileSystemContext>\n );\n\n case ErrorCode.IS_DIRECTORY:\n case ErrorCode.NOT_DIRECTORY:\n case ErrorCode.NO_SPACE:\n case ErrorCode.TOO_MANY_FILES:\n case ErrorCode.RESOURCE_BUSY:\n case ErrorCode.READ_ONLY:\n case ErrorCode.NAME_TOO_LONG:\n case ErrorCode.TOO_MANY_LINKS:\n case ErrorCode.FILESYSTEM_ERROR:\n return new FileSystemError(\n errorResponse as unknown as ErrorResponse<FileSystemContext>\n );\n\n // Command Errors\n case ErrorCode.COMMAND_NOT_FOUND:\n return new CommandNotFoundError(\n errorResponse as unknown as ErrorResponse<CommandNotFoundContext>\n );\n\n case ErrorCode.COMMAND_PERMISSION_DENIED:\n case ErrorCode.COMMAND_EXECUTION_ERROR:\n case ErrorCode.INVALID_COMMAND:\n case ErrorCode.STREAM_START_ERROR:\n return new CommandError(\n errorResponse as unknown as ErrorResponse<CommandErrorContext>\n );\n\n // Process Errors\n case ErrorCode.PROCESS_NOT_FOUND:\n return new ProcessNotFoundError(\n errorResponse as unknown as ErrorResponse<ProcessNotFoundContext>\n );\n\n case ErrorCode.PROCESS_PERMISSION_DENIED:\n case ErrorCode.PROCESS_ERROR:\n return new ProcessError(\n errorResponse as unknown as ErrorResponse<ProcessErrorContext>\n );\n\n // Session Errors\n case ErrorCode.SESSION_ALREADY_EXISTS:\n return new SessionAlreadyExistsError(\n errorResponse as unknown as ErrorResponse<SessionAlreadyExistsContext>\n );\n\n // Port Errors\n case ErrorCode.PORT_ALREADY_EXPOSED:\n return new PortAlreadyExposedError(\n errorResponse as unknown as ErrorResponse<PortAlreadyExposedContext>\n );\n\n case ErrorCode.PORT_NOT_EXPOSED:\n return new PortNotExposedError(\n errorResponse as unknown as ErrorResponse<PortNotExposedContext>\n );\n\n case ErrorCode.INVALID_PORT_NUMBER:\n case ErrorCode.INVALID_PORT:\n return new InvalidPortError(\n errorResponse as unknown as ErrorResponse<InvalidPortContext>\n );\n\n case ErrorCode.SERVICE_NOT_RESPONDING:\n return new ServiceNotRespondingError(\n errorResponse as unknown as ErrorResponse<PortErrorContext>\n );\n\n case ErrorCode.PORT_IN_USE:\n return new PortInUseError(\n errorResponse as unknown as ErrorResponse<PortErrorContext>\n );\n\n case ErrorCode.PORT_OPERATION_ERROR:\n return new PortError(\n errorResponse as unknown as ErrorResponse<PortErrorContext>\n );\n\n case ErrorCode.CUSTOM_DOMAIN_REQUIRED:\n return new CustomDomainRequiredError(\n errorResponse as unknown as ErrorResponse<InternalErrorContext>\n );\n\n // Git Errors\n case ErrorCode.GIT_REPOSITORY_NOT_FOUND:\n return new GitRepositoryNotFoundError(\n errorResponse as unknown as ErrorResponse<GitRepositoryNotFoundContext>\n );\n\n case ErrorCode.GIT_AUTH_FAILED:\n return new GitAuthenticationError(\n errorResponse as unknown as ErrorResponse<GitAuthFailedContext>\n );\n\n case ErrorCode.GIT_BRANCH_NOT_FOUND:\n return new GitBranchNotFoundError(\n errorResponse as unknown as ErrorResponse<GitBranchNotFoundContext>\n );\n\n case ErrorCode.GIT_NETWORK_ERROR:\n return new GitNetworkError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n case ErrorCode.GIT_CLONE_FAILED:\n return new GitCloneError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n case ErrorCode.GIT_CHECKOUT_FAILED:\n return new GitCheckoutError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n case ErrorCode.INVALID_GIT_URL:\n return new InvalidGitUrlError(\n errorResponse as unknown as ErrorResponse<ValidationFailedContext>\n );\n\n case ErrorCode.GIT_OPERATION_FAILED:\n return new GitError(\n errorResponse as unknown as ErrorResponse<GitErrorContext>\n );\n\n // Code Interpreter Errors\n case ErrorCode.INTERPRETER_NOT_READY:\n return new InterpreterNotReadyError(\n errorResponse as unknown as ErrorResponse<InterpreterNotReadyContext>\n );\n\n case ErrorCode.CONTEXT_NOT_FOUND:\n return new ContextNotFoundError(\n errorResponse as unknown as ErrorResponse<ContextNotFoundContext>\n );\n\n case ErrorCode.CODE_EXECUTION_ERROR:\n return new CodeExecutionError(\n errorResponse as unknown as ErrorResponse<CodeExecutionContext>\n );\n\n // Validation Errors\n case ErrorCode.VALIDATION_FAILED:\n return new ValidationFailedError(\n errorResponse as unknown as ErrorResponse<ValidationFailedContext>\n );\n\n // Generic Errors\n case ErrorCode.INVALID_JSON_RESPONSE:\n case ErrorCode.UNKNOWN_ERROR:\n case ErrorCode.INTERNAL_ERROR:\n return new SandboxError(\n errorResponse as unknown as ErrorResponse<InternalErrorContext>\n );\n\n default:\n // Fallback for unknown error codes\n return new SandboxError(errorResponse);\n }\n}\n","import type { Logger } from '@repo/shared';\nimport { createNoOpLogger } from '@repo/shared';\nimport type { ITransport, TransportConfig, TransportMode } from './types';\n\n/**\n * Container startup retry configuration\n */\nconst TIMEOUT_MS = 120_000; // 2 minutes total retry budget\nconst MIN_TIME_FOR_RETRY_MS = 15_000; // Need at least 15s remaining to retry\n\n/**\n * Abstract base transport with shared retry logic\n *\n * Handles 503 retry for container startup - shared by all transports.\n * Subclasses implement the transport-specific fetch and stream logic.\n */\nexport abstract class BaseTransport implements ITransport {\n protected config: TransportConfig;\n protected logger: Logger;\n\n constructor(config: TransportConfig) {\n this.config = config;\n this.logger = config.logger ?? createNoOpLogger();\n }\n\n abstract getMode(): TransportMode;\n abstract connect(): Promise<void>;\n abstract disconnect(): void;\n abstract isConnected(): boolean;\n\n /**\n * Fetch with automatic retry for 503 (container starting)\n *\n * This is the primary entry point for making requests. It wraps the\n * transport-specific doFetch() with retry logic for container startup.\n */\n async fetch(path: string, options?: RequestInit): Promise<Response> {\n const startTime = Date.now();\n let attempt = 0;\n\n while (true) {\n const response = await this.doFetch(path, options);\n\n // Check for retryable 503 (container starting)\n if (response.status === 503) {\n const elapsed = Date.now() - startTime;\n const remaining = TIMEOUT_MS - elapsed;\n\n if (remaining > MIN_TIME_FOR_RETRY_MS) {\n const delay = Math.min(3000 * 2 ** attempt, 30000);\n\n this.logger.info('Container not ready, retrying', {\n status: response.status,\n attempt: attempt + 1,\n delayMs: delay,\n remainingSec: Math.floor(remaining / 1000),\n mode: this.getMode()\n });\n\n await this.sleep(delay);\n attempt++;\n continue;\n }\n\n this.logger.error(\n 'Container failed to become ready',\n new Error(\n `Failed after ${attempt + 1} attempts over ${Math.floor(elapsed / 1000)}s`\n )\n );\n }\n\n return response;\n }\n }\n\n /**\n * Transport-specific fetch implementation (no retry)\n * Subclasses implement the actual HTTP or WebSocket fetch.\n */\n protected abstract doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response>;\n\n /**\n * Transport-specific stream implementation\n * Subclasses implement HTTP SSE or WebSocket streaming.\n */\n abstract fetchStream(\n path: string,\n body?: unknown,\n method?: 'GET' | 'POST'\n ): Promise<ReadableStream<Uint8Array>>;\n\n /**\n * Sleep utility for retry delays\n */\n protected sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { BaseTransport } from './base-transport';\nimport type { TransportConfig, TransportMode } from './types';\n\n/**\n * HTTP transport implementation\n *\n * Uses standard fetch API for communication with the container.\n * HTTP is stateless, so connect/disconnect are no-ops.\n */\nexport class HttpTransport extends BaseTransport {\n private baseUrl: string;\n\n constructor(config: TransportConfig) {\n super(config);\n this.baseUrl = config.baseUrl ?? 'http://localhost:3000';\n }\n\n getMode(): TransportMode {\n return 'http';\n }\n\n async connect(): Promise<void> {\n // No-op for HTTP - stateless protocol\n }\n\n disconnect(): void {\n // No-op for HTTP - stateless protocol\n }\n\n isConnected(): boolean {\n return true; // HTTP is always \"connected\"\n }\n\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n const url = this.buildUrl(path);\n\n if (this.config.stub) {\n return this.config.stub.containerFetch(\n url,\n options || {},\n this.config.port\n );\n }\n return globalThis.fetch(url, options);\n }\n\n async fetchStream(\n path: string,\n body?: unknown,\n method: 'GET' | 'POST' = 'POST'\n ): Promise<ReadableStream<Uint8Array>> {\n const url = this.buildUrl(path);\n const options = this.buildStreamOptions(body, method);\n\n let response: Response;\n if (this.config.stub) {\n response = await this.config.stub.containerFetch(\n url,\n options,\n this.config.port\n );\n } else {\n response = await globalThis.fetch(url, options);\n }\n\n if (!response.ok) {\n const errorBody = await response.text();\n throw new Error(`HTTP error! status: ${response.status} - ${errorBody}`);\n }\n\n if (!response.body) {\n throw new Error('No response body for streaming');\n }\n\n return response.body;\n }\n\n private buildUrl(path: string): string {\n if (this.config.stub) {\n return `http://localhost:${this.config.port}${path}`;\n }\n return `${this.baseUrl}${path}`;\n }\n\n private buildStreamOptions(\n body: unknown,\n method: 'GET' | 'POST'\n ): RequestInit {\n return {\n method,\n headers:\n body && method === 'POST'\n ? { 'Content-Type': 'application/json' }\n : undefined,\n body: body && method === 'POST' ? JSON.stringify(body) : undefined\n };\n }\n}\n","import {\n generateRequestId,\n isWSError,\n isWSResponse,\n isWSStreamChunk,\n type WSMethod,\n type WSRequest,\n type WSResponse,\n type WSServerMessage,\n type WSStreamChunk\n} from '@repo/shared';\nimport { BaseTransport } from './base-transport';\nimport type { TransportConfig, TransportMode } from './types';\n\n/**\n * Pending request tracker for response matching\n */\ninterface PendingRequest {\n resolve: (response: WSResponse) => void;\n reject: (error: Error) => void;\n streamController?: ReadableStreamDefaultController<Uint8Array>;\n isStreaming: boolean;\n timeoutId?: ReturnType<typeof setTimeout>;\n}\n\n/**\n * WebSocket transport state\n */\ntype WSTransportState = 'disconnected' | 'connecting' | 'connected' | 'error';\n\n/**\n * WebSocket transport implementation\n *\n * Multiplexes HTTP-like requests over a single WebSocket connection.\n * Useful when running inside Workers/DO where sub-request limits apply.\n */\nexport class WebSocketTransport extends BaseTransport {\n private ws: WebSocket | null = null;\n private state: WSTransportState = 'disconnected';\n private pendingRequests: Map<string, PendingRequest> = new Map();\n private connectPromise: Promise<void> | null = null;\n\n // Bound event handlers for proper add/remove\n private boundHandleMessage: (event: MessageEvent) => void;\n private boundHandleClose: (event: CloseEvent) => void;\n\n constructor(config: TransportConfig) {\n super(config);\n\n if (!config.wsUrl) {\n throw new Error('wsUrl is required for WebSocket transport');\n }\n\n // Bind handlers once in constructor\n this.boundHandleMessage = this.handleMessage.bind(this);\n this.boundHandleClose = this.handleClose.bind(this);\n }\n\n getMode(): TransportMode {\n return 'websocket';\n }\n\n /**\n * Check if WebSocket is connected\n */\n isConnected(): boolean {\n return this.state === 'connected' && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Connect to the WebSocket server\n *\n * The connection promise is assigned synchronously so concurrent\n * callers share the same connection attempt.\n */\n async connect(): Promise<void> {\n // Already connected\n if (this.isConnected()) {\n return;\n }\n\n // Connection in progress - wait for it\n if (this.connectPromise) {\n return this.connectPromise;\n }\n\n // Assign synchronously so concurrent callers await the same promise\n this.connectPromise = this.doConnect();\n\n try {\n await this.connectPromise;\n } catch (error) {\n // Clear promise AFTER await so concurrent callers see the same rejection\n this.connectPromise = null;\n throw error;\n }\n }\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect(): void {\n this.cleanup();\n }\n\n /**\n * Transport-specific fetch implementation\n * Converts WebSocket response to standard Response object.\n */\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n await this.connect();\n\n const method = (options?.method || 'GET') as WSMethod;\n const body = this.parseBody(options?.body);\n\n const result = await this.request(method, path, body);\n\n return new Response(JSON.stringify(result.body), {\n status: result.status,\n headers: { 'Content-Type': 'application/json' }\n });\n }\n\n /**\n * Streaming fetch implementation\n */\n async fetchStream(\n path: string,\n body?: unknown,\n method: 'GET' | 'POST' = 'POST'\n ): Promise<ReadableStream<Uint8Array>> {\n return this.requestStream(method, path, body);\n }\n\n /**\n * Parse request body from RequestInit\n */\n private parseBody(body: RequestInit['body']): unknown {\n if (!body) {\n return undefined;\n }\n\n if (typeof body === 'string') {\n try {\n return JSON.parse(body);\n } catch (error) {\n throw new Error(\n `Request body must be valid JSON: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n throw new Error(\n `WebSocket transport only supports string bodies. Got: ${typeof body}`\n );\n }\n\n /**\n * Internal connection logic\n */\n private async doConnect(): Promise<void> {\n this.state = 'connecting';\n // Use fetch-based WebSocket for DO context (Workers style)\n if (this.config.stub) {\n await this.connectViaFetch();\n } else {\n // Use standard WebSocket for browser/Node\n await this.connectViaWebSocket();\n }\n }\n\n /**\n * Connect using fetch-based WebSocket (Cloudflare Workers style)\n * This is required when running inside a Durable Object.\n *\n * Uses stub.fetch() which routes WebSocket upgrade requests through the\n * parent Container class that supports the WebSocket protocol.\n */\n private async connectViaFetch(): Promise<void> {\n const timeoutMs = this.config.connectTimeoutMs ?? 30000;\n\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n // Build the WebSocket URL for the container\n const wsPath = new URL(this.config.wsUrl!).pathname;\n const httpUrl = `http://localhost:${this.config.port || 3000}${wsPath}`;\n\n // Create a Request with WebSocket upgrade headers\n const request = new Request(httpUrl, {\n headers: {\n Upgrade: 'websocket',\n Connection: 'Upgrade'\n },\n signal: controller.signal\n });\n\n const response = await this.config.stub!.fetch(request);\n\n clearTimeout(timeout);\n\n // Check if upgrade was successful\n if (response.status !== 101) {\n throw new Error(\n `WebSocket upgrade failed: ${response.status} ${response.statusText}`\n );\n }\n\n // Get the WebSocket from the response (Workers-specific API)\n const ws = (response as unknown as { webSocket?: WebSocket }).webSocket;\n if (!ws) {\n throw new Error('No WebSocket in upgrade response');\n }\n\n // Accept the WebSocket connection (Workers-specific)\n (ws as unknown as { accept: () => void }).accept();\n\n this.ws = ws;\n this.state = 'connected';\n\n // Set up event handlers\n this.ws.addEventListener('close', this.boundHandleClose);\n this.ws.addEventListener('message', this.boundHandleMessage);\n\n this.logger.debug('WebSocket connected via fetch', {\n url: this.config.wsUrl\n });\n } catch (error) {\n clearTimeout(timeout);\n this.state = 'error';\n this.logger.error(\n 'WebSocket fetch connection failed',\n error instanceof Error ? error : new Error(String(error))\n );\n throw error;\n }\n }\n\n /**\n * Connect using standard WebSocket API (browser/Node style)\n */\n private connectViaWebSocket(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timeoutMs = this.config.connectTimeoutMs ?? 30000;\n const timeout = setTimeout(() => {\n this.cleanup();\n reject(new Error(`WebSocket connection timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n\n try {\n this.ws = new WebSocket(this.config.wsUrl!);\n\n // One-time open handler for connection\n const onOpen = () => {\n clearTimeout(timeout);\n this.ws?.removeEventListener('open', onOpen);\n this.ws?.removeEventListener('error', onConnectError);\n this.state = 'connected';\n this.logger.debug('WebSocket connected', { url: this.config.wsUrl });\n resolve();\n };\n\n // One-time error handler for connection\n const onConnectError = () => {\n clearTimeout(timeout);\n this.ws?.removeEventListener('open', onOpen);\n this.ws?.removeEventListener('error', onConnectError);\n this.state = 'error';\n this.logger.error(\n 'WebSocket error',\n new Error('WebSocket connection failed')\n );\n reject(new Error('WebSocket connection failed'));\n };\n\n this.ws.addEventListener('open', onOpen);\n this.ws.addEventListener('error', onConnectError);\n this.ws.addEventListener('close', this.boundHandleClose);\n this.ws.addEventListener('message', this.boundHandleMessage);\n } catch (error) {\n clearTimeout(timeout);\n this.state = 'error';\n reject(error);\n }\n });\n }\n\n /**\n * Send a request and wait for response\n */\n private async request<T>(\n method: WSMethod,\n path: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n await this.connect();\n\n const id = generateRequestId();\n const request: WSRequest = {\n type: 'request',\n id,\n method,\n path,\n body\n };\n\n return new Promise((resolve, reject) => {\n const timeoutMs = this.config.requestTimeoutMs ?? 120000;\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(\n new Error(`Request timeout after ${timeoutMs}ms: ${method} ${path}`)\n );\n }, timeoutMs);\n\n this.pendingRequests.set(id, {\n resolve: (response: WSResponse) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n resolve({ status: response.status, body: response.body as T });\n },\n reject: (error: Error) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n reject(error);\n },\n isStreaming: false,\n timeoutId\n });\n\n try {\n this.send(request);\n } catch (error) {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n /**\n * Send a streaming request and return a ReadableStream\n *\n * The stream will receive data chunks as they arrive over the WebSocket.\n * Format matches SSE for compatibility with existing streaming code.\n */\n private async requestStream(\n method: WSMethod,\n path: string,\n body?: unknown\n ): Promise<ReadableStream<Uint8Array>> {\n await this.connect();\n\n const id = generateRequestId();\n const request: WSRequest = {\n type: 'request',\n id,\n method,\n path,\n body\n };\n\n return new ReadableStream<Uint8Array>({\n start: (controller) => {\n const timeoutMs = this.config.requestTimeoutMs ?? 120000;\n const timeoutId = setTimeout(() => {\n this.pendingRequests.delete(id);\n controller.error(\n new Error(`Stream timeout after ${timeoutMs}ms: ${method} ${path}`)\n );\n }, timeoutMs);\n\n this.pendingRequests.set(id, {\n resolve: (response: WSResponse) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n // Final response - close the stream\n if (response.status >= 400) {\n controller.error(\n new Error(\n `Stream error: ${response.status} - ${JSON.stringify(response.body)}`\n )\n );\n } else {\n controller.close();\n }\n },\n reject: (error: Error) => {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n controller.error(error);\n },\n streamController: controller,\n isStreaming: true,\n timeoutId\n });\n\n try {\n this.send(request);\n } catch (error) {\n clearTimeout(timeoutId);\n this.pendingRequests.delete(id);\n controller.error(\n error instanceof Error ? error : new Error(String(error))\n );\n }\n },\n cancel: () => {\n const pending = this.pendingRequests.get(id);\n if (pending?.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n this.pendingRequests.delete(id);\n // Could send a cancel message to server if needed\n }\n });\n }\n\n /**\n * Send a message over the WebSocket\n */\n private send(message: WSRequest): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected');\n }\n\n this.ws.send(JSON.stringify(message));\n this.logger.debug('WebSocket sent', {\n id: message.id,\n method: message.method,\n path: message.path\n });\n }\n\n /**\n * Handle incoming WebSocket messages\n */\n private handleMessage(event: MessageEvent): void {\n try {\n const message = JSON.parse(event.data) as WSServerMessage;\n\n if (isWSResponse(message)) {\n this.handleResponse(message);\n } else if (isWSStreamChunk(message)) {\n this.handleStreamChunk(message);\n } else if (isWSError(message)) {\n this.handleError(message);\n } else {\n this.logger.warn('Unknown WebSocket message type', { message });\n }\n } catch (error) {\n this.logger.error(\n 'Failed to parse WebSocket message',\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\n\n /**\n * Handle a response message\n */\n private handleResponse(response: WSResponse): void {\n const pending = this.pendingRequests.get(response.id);\n if (!pending) {\n this.logger.warn('Received response for unknown request', {\n id: response.id\n });\n return;\n }\n\n this.logger.debug('WebSocket response', {\n id: response.id,\n status: response.status,\n done: response.done\n });\n\n // Only resolve when done is true\n if (response.done) {\n pending.resolve(response);\n }\n }\n\n /**\n * Handle a stream chunk message\n */\n private handleStreamChunk(chunk: WSStreamChunk): void {\n const pending = this.pendingRequests.get(chunk.id);\n if (!pending || !pending.streamController) {\n this.logger.warn('Received stream chunk for unknown request', {\n id: chunk.id\n });\n return;\n }\n\n // Convert to SSE format for compatibility with existing parsers\n const encoder = new TextEncoder();\n let sseData: string;\n if (chunk.event) {\n sseData = `event: ${chunk.event}\\ndata: ${chunk.data}\\n\\n`;\n } else {\n sseData = `data: ${chunk.data}\\n\\n`;\n }\n\n try {\n pending.streamController.enqueue(encoder.encode(sseData));\n } catch (error) {\n // Stream was cancelled or errored - clean up the pending request\n this.logger.debug('Failed to enqueue stream chunk, cleaning up', {\n id: chunk.id,\n error: error instanceof Error ? error.message : String(error)\n });\n // Clear timeout and remove from pending requests\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n this.pendingRequests.delete(chunk.id);\n }\n }\n\n /**\n * Handle an error message\n */\n private handleError(error: {\n id?: string;\n code: string;\n message: string;\n status: number;\n }): void {\n if (error.id) {\n const pending = this.pendingRequests.get(error.id);\n if (pending) {\n pending.reject(new Error(`${error.code}: ${error.message}`));\n return;\n }\n }\n\n // Global error - log it\n this.logger.error('WebSocket error message', new Error(error.message), {\n code: error.code,\n status: error.status\n });\n }\n\n /**\n * Handle WebSocket close\n */\n private handleClose(event: CloseEvent): void {\n this.state = 'disconnected';\n this.ws = null;\n\n const closeError = new Error(\n `WebSocket closed: ${event.code} ${event.reason || 'No reason'}`\n );\n\n // Reject all pending requests, clear their timeouts, and error their stream controllers\n for (const [, pending] of this.pendingRequests) {\n // Clear timeout first to prevent memory leak\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n // Error stream controller if it exists\n if (pending.streamController) {\n try {\n pending.streamController.error(closeError);\n } catch {\n // Stream may already be closed/errored\n }\n }\n pending.reject(closeError);\n }\n this.pendingRequests.clear();\n }\n\n /**\n * Cleanup resources\n */\n private cleanup(): void {\n if (this.ws) {\n this.ws.removeEventListener('close', this.boundHandleClose);\n this.ws.removeEventListener('message', this.boundHandleMessage);\n this.ws.close();\n this.ws = null;\n }\n this.state = 'disconnected';\n this.connectPromise = null;\n // Clear all pending request timeouts before clearing the map\n for (const pending of this.pendingRequests.values()) {\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n }\n this.pendingRequests.clear();\n }\n}\n","import { HttpTransport } from './http-transport';\nimport type { ITransport, TransportConfig, TransportMode } from './types';\nimport { WebSocketTransport } from './ws-transport';\n\n/**\n * Transport options with mode selection\n */\nexport interface TransportOptions extends TransportConfig {\n /** Transport mode */\n mode: TransportMode;\n}\n\n/**\n * Create a transport instance based on mode\n *\n * This is the primary API for creating transports. It handles\n * the selection of HTTP or WebSocket transport based on the mode.\n *\n * @example\n * ```typescript\n * // HTTP transport (default)\n * const http = createTransport({\n * mode: 'http',\n * baseUrl: 'http://localhost:3000'\n * });\n *\n * // WebSocket transport\n * const ws = createTransport({\n * mode: 'websocket',\n * wsUrl: 'ws://localhost:3000/ws'\n * });\n * ```\n */\nexport function createTransport(options: TransportOptions): ITransport {\n switch (options.mode) {\n case 'websocket':\n return new WebSocketTransport(options);\n\n default:\n return new HttpTransport(options);\n }\n}\n","import type { Logger } from '@repo/shared';\nimport { createNoOpLogger } from '@repo/shared';\nimport type { ErrorResponse as NewErrorResponse } from '../errors';\nimport { createErrorFromResponse, ErrorCode } from '../errors';\nimport type { SandboxError } from '../errors/classes';\nimport { createTransport, type ITransport } from './transport';\nimport type { HttpClientOptions, ResponseHandler } from './types';\n\n/**\n * Abstract base class providing common HTTP/WebSocket functionality for all domain clients\n *\n * All requests go through the Transport abstraction layer, which handles:\n * - HTTP and WebSocket modes transparently\n * - Automatic retry for 503 errors (container starting)\n * - Streaming responses\n *\n * WebSocket mode is useful when running inside Workers/Durable Objects\n * where sub-request limits apply.\n */\nexport abstract class BaseHttpClient {\n protected options: HttpClientOptions;\n protected logger: Logger;\n protected transport: ITransport;\n\n constructor(options: HttpClientOptions = {}) {\n this.options = options;\n this.logger = options.logger ?? createNoOpLogger();\n\n // Always create a Transport - it handles both HTTP and WebSocket modes\n if (options.transport) {\n this.transport = options.transport;\n } else {\n const mode = options.transportMode ?? 'http';\n this.transport = createTransport({\n mode,\n baseUrl: options.baseUrl ?? 'http://localhost:3000',\n wsUrl: options.wsUrl,\n logger: this.logger,\n stub: options.stub,\n port: options.port\n });\n }\n }\n\n /**\n * Check if using WebSocket transport\n */\n protected isWebSocketMode(): boolean {\n return this.transport.getMode() === 'websocket';\n }\n\n /**\n * Core fetch method - delegates to Transport which handles retry logic\n */\n protected async doFetch(\n path: string,\n options?: RequestInit\n ): Promise<Response> {\n return this.transport.fetch(path, options);\n }\n\n /**\n * Make a POST request with JSON body\n */\n protected async post<T>(\n endpoint: string,\n data: unknown,\n responseHandler?: ResponseHandler<T>\n ): Promise<T> {\n const response = await this.doFetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(data)\n });\n\n return this.handleResponse(response, responseHandler);\n }\n\n /**\n * Make a GET request\n */\n protected async get<T>(\n endpoint: string,\n responseHandler?: ResponseHandler<T>\n ): Promise<T> {\n const response = await this.doFetch(endpoint, {\n method: 'GET'\n });\n\n return this.handleResponse(response, responseHandler);\n }\n\n /**\n * Make a DELETE request\n */\n protected async delete<T>(\n endpoint: string,\n responseHandler?: ResponseHandler<T>\n ): Promise<T> {\n const response = await this.doFetch(endpoint, {\n method: 'DELETE'\n });\n\n return this.handleResponse(response, responseHandler);\n }\n\n /**\n * Handle HTTP response with error checking and parsing\n */\n protected async handleResponse<T>(\n response: Response,\n customHandler?: ResponseHandler<T>\n ): Promise<T> {\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n if (customHandler) {\n return customHandler(response);\n }\n\n try {\n return await response.json();\n } catch (error) {\n // Handle malformed JSON responses gracefully\n const errorResponse: NewErrorResponse = {\n code: ErrorCode.INVALID_JSON_RESPONSE,\n message: `Invalid JSON response: ${\n error instanceof Error ? error.message : 'Unknown parsing error'\n }`,\n context: {},\n httpStatus: response.status,\n timestamp: new Date().toISOString()\n };\n throw createErrorFromResponse(errorResponse);\n }\n }\n\n /**\n * Handle error responses with consistent error throwing\n */\n protected async handleErrorResponse(response: Response): Promise<never> {\n let errorData: NewErrorResponse;\n\n try {\n errorData = await response.json();\n } catch {\n // Fallback if response isn't JSON or parsing fails\n errorData = {\n code: ErrorCode.INTERNAL_ERROR,\n message: `HTTP error! status: ${response.status}`,\n context: { statusText: response.statusText },\n httpStatus: response.status,\n timestamp: new Date().toISOString()\n };\n }\n\n // Convert ErrorResponse to appropriate Error class\n const error = createErrorFromResponse(errorData);\n\n // Call error callback if provided\n this.options.onError?.(errorData.message, undefined);\n\n throw error;\n }\n\n /**\n * Create a streaming response handler for Server-Sent Events\n */\n protected async handleStreamResponse(\n response: Response\n ): Promise<ReadableStream<Uint8Array>> {\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n if (!response.body) {\n throw new Error('No response body for streaming');\n }\n\n return response.body;\n }\n\n /**\n * Stream request handler\n *\n * For HTTP mode, uses doFetch + handleStreamResponse to get proper error typing.\n * For WebSocket mode, uses Transport's streaming support.\n *\n * @param path - The API path to call\n * @param body - Optional request body (for POST requests)\n * @param method - HTTP method (default: POST, use GET for process logs)\n */\n protected async doStreamFetch(\n path: string,\n body?: unknown,\n method: 'GET' | 'POST' = 'POST'\n ): Promise<ReadableStream<Uint8Array>> {\n // WebSocket mode uses Transport's streaming directly\n if (this.transport.getMode() === 'websocket') {\n try {\n return await this.transport.fetchStream(path, body, method);\n } catch (error) {\n this.logError(`stream ${method} ${path}`, error);\n throw error;\n }\n }\n\n // HTTP mode: use doFetch + handleStreamResponse for proper error typing\n const response = await this.doFetch(path, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: body && method === 'POST' ? JSON.stringify(body) : undefined\n });\n\n return this.handleStreamResponse(response);\n }\n\n /**\n * Utility method to log successful operations\n */\n protected logSuccess(operation: string, details?: string): void {\n this.logger.info(operation, details ? { details } : undefined);\n }\n\n /**\n * Utility method to log errors intelligently\n * Only logs unexpected errors (5xx), not expected errors (4xx)\n *\n * - 4xx errors (validation, not found, conflicts): Don't log (expected client errors)\n * - 5xx errors (server failures, internal errors): DO log (unexpected server errors)\n */\n protected logError(operation: string, error: unknown): void {\n // Check if it's a SandboxError with HTTP status\n if (error && typeof error === 'object' && 'httpStatus' in error) {\n const httpStatus = (error as SandboxError).httpStatus;\n\n // Only log server errors (5xx), not client errors (4xx)\n if (httpStatus >= 500) {\n this.logger.error(\n `Unexpected error in ${operation}`,\n error instanceof Error ? error : new Error(String(error)),\n { httpStatus }\n );\n }\n // 4xx errors are expected (validation, not found, etc.) - don't log\n } else {\n // Non-SandboxError (unexpected) - log it\n this.logger.error(\n `Error in ${operation}`,\n error instanceof Error ? error : new Error(String(error))\n );\n }\n }\n}\n","import type { ExecuteRequest } from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { BaseApiResponse } from './types';\n\n/**\n * Request interface for command execution\n */\nexport type { ExecuteRequest };\n\n/**\n * Response interface for command execution\n */\nexport interface ExecuteResponse extends BaseApiResponse {\n stdout: string;\n stderr: string;\n exitCode: number;\n command: string;\n}\n\n/**\n * Client for command execution operations\n */\nexport class CommandClient extends BaseHttpClient {\n /**\n * Execute a command and return the complete result\n * @param command - The command to execute\n * @param sessionId - The session ID for this command execution\n * @param timeoutMs - Optional timeout in milliseconds (unlimited by default)\n * @param env - Optional environment variables for this command\n * @param cwd - Optional working directory for this command\n */\n async execute(\n command: string,\n sessionId: string,\n options?: {\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n }\n ): Promise<ExecuteResponse> {\n try {\n const data: ExecuteRequest = {\n command,\n sessionId,\n ...(options?.timeoutMs !== undefined && {\n timeoutMs: options.timeoutMs\n }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd })\n };\n\n const response = await this.post<ExecuteResponse>('/api/execute', data);\n\n this.logSuccess(\n 'Command executed',\n `${command}, Success: ${response.success}`\n );\n\n // Call the callback if provided\n this.options.onCommandComplete?.(\n response.success,\n response.exitCode,\n response.stdout,\n response.stderr,\n response.command\n );\n\n return response;\n } catch (error) {\n this.logError('execute', error);\n\n // Call error callback if provided\n this.options.onError?.(\n error instanceof Error ? error.message : String(error),\n command\n );\n\n throw error;\n }\n }\n\n /**\n * Execute a command and return a stream of events\n * @param command - The command to execute\n * @param sessionId - The session ID for this command execution\n * @param options - Optional per-command execution settings\n */\n async executeStream(\n command: string,\n sessionId: string,\n options?: {\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n }\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const data = {\n command,\n sessionId,\n ...(options?.timeoutMs !== undefined && {\n timeoutMs: options.timeoutMs\n }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd })\n };\n\n // Use doStreamFetch which handles both WebSocket and HTTP streaming\n const stream = await this.doStreamFetch('/api/execute/stream', data);\n\n this.logSuccess('Command stream started', command);\n\n return stream;\n } catch (error) {\n this.logError('executeStream', error);\n\n // Call error callback if provided\n this.options.onError?.(\n error instanceof Error ? error.message : String(error),\n command\n );\n\n throw error;\n }\n }\n}\n","import type {\n DeleteFileResult,\n FileExistsResult,\n ListFilesOptions,\n ListFilesResult,\n MkdirResult,\n MoveFileResult,\n ReadFileResult,\n RenameFileResult,\n WriteFileResult\n} from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { HttpClientOptions, SessionRequest } from './types';\n\n/**\n * Request interface for creating directories\n */\nexport interface MkdirRequest extends SessionRequest {\n path: string;\n recursive?: boolean;\n}\n\n/**\n * Request interface for writing files\n */\nexport interface WriteFileRequest extends SessionRequest {\n path: string;\n content: string;\n encoding?: string;\n}\n\n/**\n * Request interface for reading files\n */\nexport interface ReadFileRequest extends SessionRequest {\n path: string;\n encoding?: string;\n}\n\n/**\n * Request interface for file operations (delete, rename, move)\n */\nexport interface FileOperationRequest extends SessionRequest {\n path: string;\n newPath?: string; // For rename/move operations\n}\n\n/**\n * Client for file system operations\n */\nexport class FileClient extends BaseHttpClient {\n /**\n * Create a directory\n * @param path - Directory path to create\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (recursive)\n */\n async mkdir(\n path: string,\n sessionId: string,\n options?: { recursive?: boolean }\n ): Promise<MkdirResult> {\n try {\n const data = {\n path,\n sessionId,\n recursive: options?.recursive ?? false\n };\n\n const response = await this.post<MkdirResult>('/api/mkdir', data);\n\n this.logSuccess(\n 'Directory created',\n `${path} (recursive: ${data.recursive})`\n );\n return response;\n } catch (error) {\n this.logError('mkdir', error);\n throw error;\n }\n }\n\n /**\n * Write content to a file\n * @param path - File path to write to\n * @param content - Content to write\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (encoding)\n */\n async writeFile(\n path: string,\n content: string,\n sessionId: string,\n options?: { encoding?: string }\n ): Promise<WriteFileResult> {\n try {\n const data = {\n path,\n content,\n sessionId,\n encoding: options?.encoding\n };\n\n const response = await this.post<WriteFileResult>('/api/write', data);\n\n this.logSuccess('File written', `${path} (${content.length} chars)`);\n return response;\n } catch (error) {\n this.logError('writeFile', error);\n throw error;\n }\n }\n\n /**\n * Read content from a file\n * @param path - File path to read from\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (encoding)\n */\n async readFile(\n path: string,\n sessionId: string,\n options?: { encoding?: string }\n ): Promise<ReadFileResult> {\n try {\n const data = {\n path,\n sessionId,\n encoding: options?.encoding\n };\n\n const response = await this.post<ReadFileResult>('/api/read', data);\n\n this.logSuccess(\n 'File read',\n `${path} (${response.content.length} chars)`\n );\n return response;\n } catch (error) {\n this.logError('readFile', error);\n throw error;\n }\n }\n\n /**\n * Stream a file using Server-Sent Events\n * Returns a ReadableStream of SSE events containing metadata, chunks, and completion\n * @param path - File path to stream\n * @param sessionId - The session ID for this operation\n */\n async readFileStream(\n path: string,\n sessionId: string\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const data = {\n path,\n sessionId\n };\n\n // Use doStreamFetch which handles both WebSocket and HTTP streaming\n const stream = await this.doStreamFetch('/api/read/stream', data);\n this.logSuccess('File stream started', path);\n return stream;\n } catch (error) {\n this.logError('readFileStream', error);\n throw error;\n }\n }\n\n /**\n * Delete a file\n * @param path - File path to delete\n * @param sessionId - The session ID for this operation\n */\n async deleteFile(path: string, sessionId: string): Promise<DeleteFileResult> {\n try {\n const data = { path, sessionId };\n\n const response = await this.post<DeleteFileResult>('/api/delete', data);\n\n this.logSuccess('File deleted', path);\n return response;\n } catch (error) {\n this.logError('deleteFile', error);\n throw error;\n }\n }\n\n /**\n * Rename a file\n * @param path - Current file path\n * @param newPath - New file path\n * @param sessionId - The session ID for this operation\n */\n async renameFile(\n path: string,\n newPath: string,\n sessionId: string\n ): Promise<RenameFileResult> {\n try {\n const data = { oldPath: path, newPath, sessionId };\n\n const response = await this.post<RenameFileResult>('/api/rename', data);\n\n this.logSuccess('File renamed', `${path} -> ${newPath}`);\n return response;\n } catch (error) {\n this.logError('renameFile', error);\n throw error;\n }\n }\n\n /**\n * Move a file\n * @param path - Current file path\n * @param newPath - Destination file path\n * @param sessionId - The session ID for this operation\n */\n async moveFile(\n path: string,\n newPath: string,\n sessionId: string\n ): Promise<MoveFileResult> {\n try {\n const data = { sourcePath: path, destinationPath: newPath, sessionId };\n\n const response = await this.post<MoveFileResult>('/api/move', data);\n\n this.logSuccess('File moved', `${path} -> ${newPath}`);\n return response;\n } catch (error) {\n this.logError('moveFile', error);\n throw error;\n }\n }\n\n /**\n * List files in a directory\n * @param path - Directory path to list\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (recursive, includeHidden)\n */\n async listFiles(\n path: string,\n sessionId: string,\n options?: ListFilesOptions\n ): Promise<ListFilesResult> {\n try {\n const data = {\n path,\n sessionId,\n options: options || {}\n };\n\n const response = await this.post<ListFilesResult>(\n '/api/list-files',\n data\n );\n\n this.logSuccess('Files listed', `${path} (${response.count} files)`);\n return response;\n } catch (error) {\n this.logError('listFiles', error);\n throw error;\n }\n }\n\n /**\n * Check if a file or directory exists\n * @param path - Path to check\n * @param sessionId - The session ID for this operation\n */\n async exists(path: string, sessionId: string): Promise<FileExistsResult> {\n try {\n const data = {\n path,\n sessionId\n };\n\n const response = await this.post<FileExistsResult>('/api/exists', data);\n\n this.logSuccess(\n 'Path existence checked',\n `${path} (exists: ${response.exists})`\n );\n return response;\n } catch (error) {\n this.logError('exists', error);\n throw error;\n }\n }\n}\n","import type { GitCheckoutResult } from '@repo/shared';\nimport { GitLogger } from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { HttpClientOptions, SessionRequest } from './types';\n\n// Re-export for convenience\nexport type { GitCheckoutResult };\n\n/**\n * Request interface for Git checkout operations\n */\nexport interface GitCheckoutRequest extends SessionRequest {\n repoUrl: string;\n branch?: string;\n targetDir?: string;\n}\n\n/**\n * Client for Git repository operations\n */\nexport class GitClient extends BaseHttpClient {\n constructor(options: HttpClientOptions = {}) {\n super(options);\n // Wrap logger with GitLogger to auto-redact credentials\n this.logger = new GitLogger(this.logger);\n }\n\n /**\n * Clone a Git repository\n * @param repoUrl - URL of the Git repository to clone\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (branch, targetDir)\n */\n async checkout(\n repoUrl: string,\n sessionId: string,\n options?: {\n branch?: string;\n targetDir?: string;\n }\n ): Promise<GitCheckoutResult> {\n try {\n // Determine target directory - use provided path or generate from repo name\n let targetDir = options?.targetDir;\n if (!targetDir) {\n const repoName = this.extractRepoName(repoUrl);\n // Ensure absolute path in /workspace\n targetDir = `/workspace/${repoName}`;\n }\n\n const data: GitCheckoutRequest = {\n repoUrl,\n sessionId,\n targetDir\n };\n\n // Only include branch if explicitly specified\n // This allows Git to use the repository's default branch\n if (options?.branch) {\n data.branch = options.branch;\n }\n\n const response = await this.post<GitCheckoutResult>(\n '/api/git/checkout',\n data\n );\n\n this.logSuccess(\n 'Repository cloned',\n `${repoUrl} (branch: ${response.branch}) -> ${response.targetDir}`\n );\n\n return response;\n } catch (error) {\n this.logError('checkout', error);\n throw error;\n }\n }\n\n /**\n * Extract repository name from URL for default directory name\n */\n private extractRepoName(repoUrl: string): string {\n try {\n const url = new URL(repoUrl);\n const pathParts = url.pathname.split('/');\n const repoName = pathParts[pathParts.length - 1];\n\n // Remove .git extension if present\n return repoName.replace(/\\.git$/, '');\n } catch {\n // Fallback for invalid URLs\n const parts = repoUrl.split('/');\n const repoName = parts[parts.length - 1];\n return repoName.replace(/\\.git$/, '') || 'repo';\n }\n }\n}\n","import {\n type CodeContext,\n type ContextCreateResult,\n type ContextListResult,\n type CreateContextOptions,\n type ExecutionError,\n type OutputMessage,\n type Result,\n ResultImpl\n} from '@repo/shared';\nimport type { ErrorResponse } from '../errors';\nimport {\n createErrorFromResponse,\n ErrorCode,\n InterpreterNotReadyError\n} from '../errors';\nimport { BaseHttpClient } from './base-client.js';\nimport type { HttpClientOptions } from './types.js';\n\n// Streaming execution data from the server\ninterface StreamingExecutionData {\n type: 'result' | 'stdout' | 'stderr' | 'error' | 'execution_complete';\n text?: string;\n html?: string;\n png?: string; // base64\n jpeg?: string; // base64\n svg?: string;\n latex?: string;\n markdown?: string;\n javascript?: string;\n json?: unknown;\n chart?: {\n type:\n | 'line'\n | 'bar'\n | 'scatter'\n | 'pie'\n | 'histogram'\n | 'heatmap'\n | 'unknown';\n data: unknown;\n options?: unknown;\n };\n data?: unknown;\n metadata?: Record<string, unknown>;\n execution_count?: number;\n ename?: string;\n evalue?: string;\n traceback?: string[];\n lineNumber?: number;\n timestamp?: number;\n}\n\nexport interface ExecutionCallbacks {\n onStdout?: (output: OutputMessage) => void | Promise<void>;\n onStderr?: (output: OutputMessage) => void | Promise<void>;\n onResult?: (result: Result) => void | Promise<void>;\n onError?: (error: ExecutionError) => void | Promise<void>;\n}\n\nexport class InterpreterClient extends BaseHttpClient {\n private readonly maxRetries = 3;\n private readonly retryDelayMs = 1000;\n\n async createCodeContext(\n options: CreateContextOptions = {}\n ): Promise<CodeContext> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch('/api/contexts', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n language: options.language || 'python',\n cwd: options.cwd || '/workspace',\n env_vars: options.envVars\n })\n });\n\n if (!response.ok) {\n const error = await this.parseErrorResponse(response);\n throw error;\n }\n\n const data = (await response.json()) as ContextCreateResult;\n if (!data.success) {\n throw new Error(`Failed to create context: ${JSON.stringify(data)}`);\n }\n\n return {\n id: data.contextId,\n language: data.language,\n cwd: data.cwd || '/workspace',\n createdAt: new Date(data.timestamp),\n lastUsed: new Date(data.timestamp)\n };\n });\n }\n\n async runCodeStream(\n contextId: string | undefined,\n code: string,\n language: string | undefined,\n callbacks: ExecutionCallbacks,\n timeoutMs?: number\n ): Promise<void> {\n return this.executeWithRetry(async () => {\n // Use doStreamFetch which handles both WebSocket and HTTP streaming\n const stream = await this.doStreamFetch('/api/execute/code', {\n context_id: contextId,\n code,\n language,\n ...(timeoutMs !== undefined && { timeout_ms: timeoutMs })\n });\n\n // Process streaming response\n for await (const chunk of this.readLines(stream)) {\n await this.parseExecutionResult(chunk, callbacks);\n }\n });\n }\n\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch('/api/contexts', {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' }\n });\n\n if (!response.ok) {\n const error = await this.parseErrorResponse(response);\n throw error;\n }\n\n const data = (await response.json()) as ContextListResult;\n if (!data.success) {\n throw new Error(`Failed to list contexts: ${JSON.stringify(data)}`);\n }\n\n return data.contexts.map((ctx) => ({\n id: ctx.id,\n language: ctx.language,\n cwd: ctx.cwd || '/workspace',\n createdAt: new Date(data.timestamp),\n lastUsed: new Date(data.timestamp)\n }));\n });\n }\n\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.executeWithRetry(async () => {\n const response = await this.doFetch(`/api/contexts/${contextId}`, {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' }\n });\n\n if (!response.ok) {\n const error = await this.parseErrorResponse(response);\n throw error;\n }\n });\n }\n\n /**\n * Get a raw stream for code execution.\n * Used by CodeInterpreter.runCodeStreaming() for direct stream access.\n */\n async streamCode(\n contextId: string,\n code: string,\n language?: string\n ): Promise<ReadableStream<Uint8Array>> {\n return this.doStreamFetch('/api/execute/code', {\n context_id: contextId,\n code,\n language\n });\n }\n\n /**\n * Execute an operation with automatic retry for transient errors\n */\n private async executeWithRetry<T>(operation: () => Promise<T>): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n this.logError('executeWithRetry', error);\n lastError = error as Error;\n\n // Check if it's a retryable error (interpreter not ready)\n if (this.isRetryableError(error)) {\n // Don't retry on the last attempt\n if (attempt < this.maxRetries - 1) {\n // Exponential backoff with jitter\n const delay =\n this.retryDelayMs * 2 ** attempt + Math.random() * 1000;\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n }\n\n // Not retryable or last attempt - throw the error\n throw error;\n }\n }\n\n throw lastError || new Error('Execution failed after retries');\n }\n\n private isRetryableError(error: unknown): boolean {\n if (error instanceof InterpreterNotReadyError) {\n return true;\n }\n\n if (error instanceof Error) {\n return (\n error.message.includes('not ready') ||\n error.message.includes('initializing')\n );\n }\n\n return false;\n }\n\n private async parseErrorResponse(response: Response): Promise<Error> {\n try {\n const errorData = (await response.json()) as ErrorResponse;\n return createErrorFromResponse(errorData);\n } catch {\n // Fallback if response isn't JSON\n const errorResponse: ErrorResponse = {\n code: ErrorCode.INTERNAL_ERROR,\n message: `HTTP ${response.status}: ${response.statusText}`,\n context: {},\n httpStatus: response.status,\n timestamp: new Date().toISOString()\n };\n return createErrorFromResponse(errorResponse);\n }\n }\n\n private async *readLines(\n stream: ReadableStream<Uint8Array>\n ): AsyncGenerator<string> {\n const reader = stream.getReader();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (value) {\n buffer += new TextDecoder().decode(value);\n }\n if (done) break;\n\n let newlineIdx = buffer.indexOf('\\n');\n while (newlineIdx !== -1) {\n yield buffer.slice(0, newlineIdx);\n buffer = buffer.slice(newlineIdx + 1);\n newlineIdx = buffer.indexOf('\\n');\n }\n }\n\n // Yield any remaining data\n if (buffer.length > 0) {\n yield buffer;\n }\n } finally {\n // Cancel the stream first to properly terminate HTTP connections when breaking early\n try {\n await reader.cancel();\n } catch {\n // Ignore cancel errors (stream may already be closed)\n }\n reader.releaseLock();\n }\n }\n\n private async parseExecutionResult(\n line: string,\n callbacks: ExecutionCallbacks\n ) {\n if (!line.trim()) return;\n\n // Skip lines that don't start with \"data: \" (SSE format)\n if (!line.startsWith('data: ')) return;\n\n try {\n // Strip \"data: \" prefix and parse JSON\n const jsonData = line.substring(6); // \"data: \" is 6 characters\n const data = JSON.parse(jsonData) as StreamingExecutionData;\n\n switch (data.type) {\n case 'stdout':\n if (callbacks.onStdout && data.text) {\n await callbacks.onStdout({\n text: data.text,\n timestamp: data.timestamp || Date.now()\n });\n }\n break;\n\n case 'stderr':\n if (callbacks.onStderr && data.text) {\n await callbacks.onStderr({\n text: data.text,\n timestamp: data.timestamp || Date.now()\n });\n }\n break;\n\n case 'result':\n if (callbacks.onResult) {\n // Create a ResultImpl instance from the raw data\n const result = new ResultImpl(data);\n await callbacks.onResult(result);\n }\n break;\n\n case 'error':\n if (callbacks.onError) {\n await callbacks.onError({\n name: data.ename || 'Error',\n message: data.evalue || 'Unknown error',\n traceback: data.traceback || []\n });\n }\n break;\n\n case 'execution_complete':\n // Signal completion - callbacks can handle cleanup if needed\n break;\n }\n } catch (error) {\n this.logError('parseExecutionResult', error);\n }\n }\n}\n","import type {\n PortCloseResult,\n PortExposeResult,\n PortListResult,\n PortWatchRequest\n} from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\n\n// Re-export for convenience\nexport type { PortExposeResult, PortCloseResult, PortListResult };\n\n/**\n * Request interface for exposing ports\n */\nexport interface ExposePortRequest {\n port: number;\n name?: string;\n}\n\n/**\n * Request interface for unexposing ports\n */\nexport interface UnexposePortRequest {\n port: number;\n}\n\n/**\n * Client for port management and preview URL operations\n */\nexport class PortClient extends BaseHttpClient {\n /**\n * Expose a port and get a preview URL\n * @param port - Port number to expose\n * @param sessionId - The session ID for this operation\n * @param name - Optional name for the port\n */\n async exposePort(\n port: number,\n sessionId: string,\n name?: string\n ): Promise<PortExposeResult> {\n try {\n const data = { port, sessionId, name };\n\n const response = await this.post<PortExposeResult>(\n '/api/expose-port',\n data\n );\n\n this.logSuccess(\n 'Port exposed',\n `${port} exposed at ${response.url}${name ? ` (${name})` : ''}`\n );\n\n return response;\n } catch (error) {\n this.logError('exposePort', error);\n throw error;\n }\n }\n\n /**\n * Unexpose a port and remove its preview URL\n * @param port - Port number to unexpose\n * @param sessionId - The session ID for this operation\n */\n async unexposePort(\n port: number,\n sessionId: string\n ): Promise<PortCloseResult> {\n try {\n const url = `/api/exposed-ports/${port}?session=${encodeURIComponent(\n sessionId\n )}`;\n const response = await this.delete<PortCloseResult>(url);\n\n this.logSuccess('Port unexposed', `${port}`);\n return response;\n } catch (error) {\n this.logError('unexposePort', error);\n throw error;\n }\n }\n\n /**\n * Get all currently exposed ports\n * @param sessionId - The session ID for this operation\n */\n async getExposedPorts(sessionId: string): Promise<PortListResult> {\n try {\n const url = `/api/exposed-ports?session=${encodeURIComponent(sessionId)}`;\n const response = await this.get<PortListResult>(url);\n\n this.logSuccess(\n 'Exposed ports retrieved',\n `${response.ports.length} ports exposed`\n );\n\n return response;\n } catch (error) {\n this.logError('getExposedPorts', error);\n throw error;\n }\n }\n\n /**\n * Watch a port for readiness via SSE stream\n * @param request - Port watch configuration\n * @returns SSE stream that emits PortWatchEvent objects\n */\n async watchPort(\n request: PortWatchRequest\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const stream = await this.doStreamFetch('/api/port-watch', request);\n this.logSuccess('Port watch started', `port ${request.port}`);\n return stream;\n } catch (error) {\n this.logError('watchPort', error);\n throw error;\n }\n }\n}\n","import type {\n ProcessCleanupResult,\n ProcessInfoResult,\n ProcessKillResult,\n ProcessListResult,\n ProcessLogsResult,\n ProcessStartResult,\n StartProcessRequest\n} from '@repo/shared';\nimport { BaseHttpClient } from './base-client';\nimport type { HttpClientOptions } from './types';\n\n// Re-export for convenience\nexport type {\n StartProcessRequest,\n ProcessStartResult,\n ProcessListResult,\n ProcessInfoResult,\n ProcessKillResult,\n ProcessLogsResult,\n ProcessCleanupResult\n};\n\n/**\n * Client for background process management\n */\nexport class ProcessClient extends BaseHttpClient {\n /**\n * Start a background process\n * @param command - Command to execute as a background process\n * @param sessionId - The session ID for this operation\n * @param options - Optional settings (processId)\n */\n async startProcess(\n command: string,\n sessionId: string,\n options?: {\n processId?: string;\n timeoutMs?: number;\n env?: Record<string, string>;\n cwd?: string;\n encoding?: string;\n autoCleanup?: boolean;\n }\n ): Promise<ProcessStartResult> {\n try {\n const data: StartProcessRequest = {\n command,\n sessionId,\n ...(options?.processId !== undefined && {\n processId: options.processId\n }),\n ...(options?.timeoutMs !== undefined && {\n timeoutMs: options.timeoutMs\n }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(options?.encoding !== undefined && { encoding: options.encoding }),\n ...(options?.autoCleanup !== undefined && {\n autoCleanup: options.autoCleanup\n })\n };\n\n const response = await this.post<ProcessStartResult>(\n '/api/process/start',\n data\n );\n\n this.logSuccess(\n 'Process started',\n `${command} (ID: ${response.processId})`\n );\n\n return response;\n } catch (error) {\n this.logError('startProcess', error);\n throw error;\n }\n }\n\n /**\n * List all processes (sandbox-scoped, not session-scoped)\n */\n async listProcesses(): Promise<ProcessListResult> {\n try {\n const url = `/api/process/list`;\n const response = await this.get<ProcessListResult>(url);\n\n this.logSuccess(\n 'Processes listed',\n `${response.processes.length} processes`\n );\n return response;\n } catch (error) {\n this.logError('listProcesses', error);\n throw error;\n }\n }\n\n /**\n * Get information about a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to retrieve\n */\n async getProcess(processId: string): Promise<ProcessInfoResult> {\n try {\n const url = `/api/process/${processId}`;\n const response = await this.get<ProcessInfoResult>(url);\n\n this.logSuccess('Process retrieved', `ID: ${processId}`);\n return response;\n } catch (error) {\n this.logError('getProcess', error);\n throw error;\n }\n }\n\n /**\n * Kill a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to kill\n */\n async killProcess(processId: string): Promise<ProcessKillResult> {\n try {\n const url = `/api/process/${processId}`;\n const response = await this.delete<ProcessKillResult>(url);\n\n this.logSuccess('Process killed', `ID: ${processId}`);\n return response;\n } catch (error) {\n this.logError('killProcess', error);\n throw error;\n }\n }\n\n /**\n * Kill all running processes (sandbox-scoped, not session-scoped)\n */\n async killAllProcesses(): Promise<ProcessCleanupResult> {\n try {\n const url = `/api/process/kill-all`;\n const response = await this.delete<ProcessCleanupResult>(url);\n\n this.logSuccess(\n 'All processes killed',\n `${response.cleanedCount} processes terminated`\n );\n\n return response;\n } catch (error) {\n this.logError('killAllProcesses', error);\n throw error;\n }\n }\n\n /**\n * Get logs from a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to get logs from\n */\n async getProcessLogs(processId: string): Promise<ProcessLogsResult> {\n try {\n const url = `/api/process/${processId}/logs`;\n const response = await this.get<ProcessLogsResult>(url);\n\n this.logSuccess(\n 'Process logs retrieved',\n `ID: ${processId}, stdout: ${response.stdout.length} chars, stderr: ${response.stderr.length} chars`\n );\n\n return response;\n } catch (error) {\n this.logError('getProcessLogs', error);\n throw error;\n }\n }\n\n /**\n * Stream logs from a specific process (sandbox-scoped, not session-scoped)\n * @param processId - ID of the process to stream logs from\n */\n async streamProcessLogs(\n processId: string\n ): Promise<ReadableStream<Uint8Array>> {\n try {\n const url = `/api/process/${processId}/stream`;\n // Use doStreamFetch with GET method (process log streaming is GET)\n const stream = await this.doStreamFetch(url, undefined, 'GET');\n\n this.logSuccess('Process log stream started', `ID: ${processId}`);\n\n return stream;\n } catch (error) {\n this.logError('streamProcessLogs', error);\n throw error;\n }\n }\n}\n","import { BaseHttpClient } from './base-client';\nimport type { BaseApiResponse, HttpClientOptions } from './types';\n\n/**\n * Response interface for ping operations\n */\nexport interface PingResponse extends BaseApiResponse {\n message: string;\n uptime?: number;\n}\n\n/**\n * Response interface for getting available commands\n */\nexport interface CommandsResponse extends BaseApiResponse {\n availableCommands: string[];\n count: number;\n}\n\n/**\n * Response interface for getting container version\n */\nexport interface VersionResponse extends BaseApiResponse {\n version: string;\n}\n\n/**\n * Request interface for creating sessions\n */\nexport interface CreateSessionRequest {\n id: string;\n env?: Record<string, string>;\n cwd?: string;\n}\n\n/**\n * Response interface for creating sessions\n */\nexport interface CreateSessionResponse extends BaseApiResponse {\n id: string;\n message: string;\n}\n\n/**\n * Request interface for deleting sessions\n */\nexport interface DeleteSessionRequest {\n sessionId: string;\n}\n\n/**\n * Response interface for deleting sessions\n */\nexport interface DeleteSessionResponse extends BaseApiResponse {\n sessionId: string;\n}\n\n/**\n * Client for health checks and utility operations\n */\nexport class UtilityClient extends BaseHttpClient {\n /**\n * Ping the sandbox to check if it's responsive\n */\n async ping(): Promise<string> {\n try {\n const response = await this.get<PingResponse>('/api/ping');\n\n this.logSuccess('Ping successful', response.message);\n return response.message;\n } catch (error) {\n this.logError('ping', error);\n throw error;\n }\n }\n\n /**\n * Get list of available commands in the sandbox environment\n */\n async getCommands(): Promise<string[]> {\n try {\n const response = await this.get<CommandsResponse>('/api/commands');\n\n this.logSuccess(\n 'Commands retrieved',\n `${response.count} commands available`\n );\n\n return response.availableCommands;\n } catch (error) {\n this.logError('getCommands', error);\n throw error;\n }\n }\n\n /**\n * Create a new execution session\n * @param options - Session configuration (id, env, cwd)\n */\n async createSession(\n options: CreateSessionRequest\n ): Promise<CreateSessionResponse> {\n try {\n const response = await this.post<CreateSessionResponse>(\n '/api/session/create',\n options\n );\n\n this.logSuccess('Session created', `ID: ${options.id}`);\n return response;\n } catch (error) {\n this.logError('createSession', error);\n throw error;\n }\n }\n\n /**\n * Delete an execution session\n * @param sessionId - Session ID to delete\n */\n async deleteSession(sessionId: string): Promise<DeleteSessionResponse> {\n try {\n const response = await this.post<DeleteSessionResponse>(\n '/api/session/delete',\n { sessionId }\n );\n\n this.logSuccess('Session deleted', `ID: ${sessionId}`);\n return response;\n } catch (error) {\n this.logError('deleteSession', error);\n throw error;\n }\n }\n\n /**\n * Get the container version\n * Returns the version embedded in the Docker image during build\n */\n async getVersion(): Promise<string> {\n try {\n const response = await this.get<VersionResponse>('/api/version');\n\n this.logSuccess('Version retrieved', response.version);\n return response.version;\n } catch (error) {\n // If version endpoint doesn't exist (old container), return 'unknown'\n // This allows for backward compatibility\n this.logger.debug(\n 'Failed to get container version (may be old container)',\n { error }\n );\n return 'unknown';\n }\n }\n}\n","import { CommandClient } from './command-client';\nimport { FileClient } from './file-client';\nimport { GitClient } from './git-client';\nimport { InterpreterClient } from './interpreter-client';\nimport { PortClient } from './port-client';\nimport { ProcessClient } from './process-client';\nimport {\n createTransport,\n type ITransport,\n type TransportMode\n} from './transport';\nimport type { HttpClientOptions } from './types';\nimport { UtilityClient } from './utility-client';\n\n/**\n * Main sandbox client that composes all domain-specific clients\n * Provides organized access to all sandbox functionality\n *\n * Supports two transport modes:\n * - HTTP (default): Each request is a separate HTTP call\n * - WebSocket: All requests multiplexed over a single connection\n *\n * WebSocket mode reduces sub-request count when running inside Workers/Durable Objects.\n */\nexport class SandboxClient {\n public readonly commands: CommandClient;\n public readonly files: FileClient;\n public readonly processes: ProcessClient;\n public readonly ports: PortClient;\n public readonly git: GitClient;\n public readonly interpreter: InterpreterClient;\n public readonly utils: UtilityClient;\n\n private transport: ITransport | null = null;\n\n constructor(options: HttpClientOptions) {\n // Create shared transport if WebSocket mode is enabled\n if (options.transportMode === 'websocket' && options.wsUrl) {\n this.transport = createTransport({\n mode: 'websocket',\n wsUrl: options.wsUrl,\n baseUrl: options.baseUrl,\n logger: options.logger,\n stub: options.stub,\n port: options.port\n });\n }\n\n // Ensure baseUrl is provided for all clients\n const clientOptions: HttpClientOptions = {\n baseUrl: 'http://localhost:3000',\n ...options,\n // Share transport across all clients\n transport: this.transport ?? options.transport\n };\n\n // Initialize all domain clients with shared options\n this.commands = new CommandClient(clientOptions);\n this.files = new FileClient(clientOptions);\n this.processes = new ProcessClient(clientOptions);\n this.ports = new PortClient(clientOptions);\n this.git = new GitClient(clientOptions);\n this.interpreter = new InterpreterClient(clientOptions);\n this.utils = new UtilityClient(clientOptions);\n }\n\n /**\n * Get the current transport mode\n */\n getTransportMode(): TransportMode {\n return this.transport?.getMode() ?? 'http';\n }\n\n /**\n * Check if WebSocket is connected (only relevant in WebSocket mode)\n */\n isWebSocketConnected(): boolean {\n return this.transport?.isConnected() ?? false;\n }\n\n /**\n * Connect WebSocket transport (no-op in HTTP mode)\n * Called automatically on first request, but can be called explicitly\n * to establish connection upfront.\n */\n async connect(): Promise<void> {\n if (this.transport) {\n await this.transport.connect();\n }\n }\n\n /**\n * Disconnect WebSocket transport (no-op in HTTP mode)\n * Should be called when the sandbox is destroyed.\n */\n disconnect(): void {\n if (this.transport) {\n this.transport.disconnect();\n }\n }\n}\n","/**\n * Security utilities for URL construction and input validation\n *\n * This module contains critical security functions to prevent:\n * - URL injection attacks\n * - SSRF (Server-Side Request Forgery) attacks\n * - DNS rebinding attacks\n * - Host header injection\n * - Open redirect vulnerabilities\n */\n\nexport class SecurityError extends Error {\n constructor(\n message: string,\n public readonly code?: string\n ) {\n super(message);\n this.name = 'SecurityError';\n }\n}\n\n/**\n * Validates port numbers for sandbox services\n * Only allows non-system ports to prevent conflicts and security issues\n */\nexport function validatePort(port: number): boolean {\n // Must be a valid integer\n if (!Number.isInteger(port)) {\n return false;\n }\n\n // Only allow non-system ports (1024-65535)\n if (port < 1024 || port > 65535) {\n return false;\n }\n\n // Exclude ports reserved by our system\n const reservedPorts = [\n 3000, // Control plane port\n 8787 // Common wrangler dev port\n ];\n\n if (reservedPorts.includes(port)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Sanitizes and validates sandbox IDs for DNS compliance and security\n * Only enforces critical requirements - allows maximum developer flexibility\n */\nexport function sanitizeSandboxId(id: string): string {\n // Basic validation: not empty, reasonable length limit (DNS subdomain limit is 63 chars)\n if (!id || id.length > 63) {\n throw new SecurityError(\n 'Sandbox ID must be 1-63 characters long.',\n 'INVALID_SANDBOX_ID_LENGTH'\n );\n }\n\n // DNS compliance: cannot start or end with hyphens (RFC requirement)\n if (id.startsWith('-') || id.endsWith('-')) {\n throw new SecurityError(\n 'Sandbox ID cannot start or end with hyphens (DNS requirement).',\n 'INVALID_SANDBOX_ID_HYPHENS'\n );\n }\n\n // Prevent reserved names that cause technical conflicts\n const reservedNames = [\n 'www',\n 'api',\n 'admin',\n 'root',\n 'system',\n 'cloudflare',\n 'workers'\n ];\n\n const lowerCaseId = id.toLowerCase();\n if (reservedNames.includes(lowerCaseId)) {\n throw new SecurityError(\n `Reserved sandbox ID '${id}' is not allowed.`,\n 'RESERVED_SANDBOX_ID'\n );\n }\n\n return id;\n}\n\n/**\n * Validates language for code interpreter\n * Only allows supported languages\n */\nexport function validateLanguage(language: string | undefined): void {\n if (!language) {\n return; // undefined is valid, will default to python\n }\n\n const supportedLanguages = [\n 'python',\n 'python3',\n 'javascript',\n 'js',\n 'node',\n 'typescript',\n 'ts'\n ];\n const normalized = language.toLowerCase();\n\n if (!supportedLanguages.includes(normalized)) {\n throw new SecurityError(\n `Unsupported language '${language}'. Supported languages: python, javascript, typescript`,\n 'INVALID_LANGUAGE'\n );\n }\n}\n","import {\n type CodeContext,\n type CreateContextOptions,\n Execution,\n type ExecutionError,\n type OutputMessage,\n type Result,\n ResultImpl,\n type RunCodeOptions\n} from '@repo/shared';\nimport type { InterpreterClient } from './clients/interpreter-client.js';\nimport type { Sandbox } from './sandbox.js';\nimport { validateLanguage } from './security.js';\n\nexport class CodeInterpreter {\n private interpreterClient: InterpreterClient;\n private contexts = new Map<string, CodeContext>();\n\n constructor(sandbox: Sandbox) {\n // In init-testing architecture, client is a SandboxClient with an interpreter property\n this.interpreterClient = (sandbox.client as any)\n .interpreter as InterpreterClient;\n }\n\n /**\n * Create a new code execution context\n */\n async createCodeContext(\n options: CreateContextOptions = {}\n ): Promise<CodeContext> {\n // Validate language before sending to container\n validateLanguage(options.language);\n\n const context = await this.interpreterClient.createCodeContext(options);\n this.contexts.set(context.id, context);\n return context;\n }\n\n /**\n * Run code with optional context\n */\n async runCode(\n code: string,\n options: RunCodeOptions = {}\n ): Promise<Execution> {\n // Get or create context\n let context = options.context;\n if (!context) {\n // Try to find or create a default context for the language\n const language = options.language || 'python';\n context = await this.getOrCreateDefaultContext(language);\n }\n\n // Create execution object to collect results\n const execution = new Execution(code, context);\n\n // Stream execution\n await this.interpreterClient.runCodeStream(\n context.id,\n code,\n options.language,\n {\n onStdout: (output: OutputMessage) => {\n execution.logs.stdout.push(output.text);\n if (options.onStdout) return options.onStdout(output);\n },\n onStderr: (output: OutputMessage) => {\n execution.logs.stderr.push(output.text);\n if (options.onStderr) return options.onStderr(output);\n },\n onResult: async (result: Result) => {\n execution.results.push(new ResultImpl(result) as any);\n if (options.onResult) return options.onResult(result);\n },\n onError: (error: ExecutionError) => {\n execution.error = error;\n if (options.onError) return options.onError(error);\n }\n }\n );\n\n return execution;\n }\n\n /**\n * Run code and return a streaming response\n */\n async runCodeStream(\n code: string,\n options: RunCodeOptions = {}\n ): Promise<ReadableStream> {\n // Get or create context\n let context = options.context;\n if (!context) {\n const language = options.language || 'python';\n context = await this.getOrCreateDefaultContext(language);\n }\n\n // Use streamCode which handles both HTTP and WebSocket streaming\n return this.interpreterClient.streamCode(\n context.id,\n code,\n options.language\n );\n }\n\n /**\n * List all code contexts\n */\n async listCodeContexts(): Promise<CodeContext[]> {\n const contexts = await this.interpreterClient.listCodeContexts();\n\n // Update local cache\n for (const context of contexts) {\n this.contexts.set(context.id, context);\n }\n\n return contexts;\n }\n\n /**\n * Delete a code context\n */\n async deleteCodeContext(contextId: string): Promise<void> {\n await this.interpreterClient.deleteCodeContext(contextId);\n this.contexts.delete(contextId);\n }\n\n private async getOrCreateDefaultContext(\n language: 'python' | 'javascript' | 'typescript'\n ): Promise<CodeContext> {\n // Check if we have a cached context for this language\n for (const context of this.contexts.values()) {\n if (context.language === language) {\n return context;\n }\n }\n\n // Create new default context\n return this.createCodeContext({ language });\n }\n}\n","import { switchPort } from '@cloudflare/containers';\nimport { createLogger, type LogContext, TraceContext } from '@repo/shared';\nimport { getSandbox, type Sandbox } from './sandbox';\nimport { sanitizeSandboxId, validatePort } from './security';\n\nexport interface SandboxEnv<T extends Sandbox<any> = Sandbox<any>> {\n Sandbox: DurableObjectNamespace<T>;\n}\n\nexport interface RouteInfo {\n port: number;\n sandboxId: string;\n path: string;\n token: string;\n}\n\nexport async function proxyToSandbox<\n T extends Sandbox<any>,\n E extends SandboxEnv<T>\n>(request: Request, env: E): Promise<Response | null> {\n // Create logger context for this request\n const traceId =\n TraceContext.fromHeaders(request.headers) || TraceContext.generate();\n const logger = createLogger({\n component: 'sandbox-do',\n traceId,\n operation: 'proxy'\n });\n\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, token } = routeInfo;\n // Preview URLs always use normalized (lowercase) IDs\n const sandbox = getSandbox(env.Sandbox, sandboxId, { normalizeId: true });\n\n // Critical security check: Validate token (mandatory for all user ports)\n // Skip check for control plane port 3000\n if (port !== 3000) {\n // Validate the token matches the port\n const isValidToken = await sandbox.validatePortToken(port, token);\n if (!isValidToken) {\n logger.warn('Invalid token access blocked', {\n port,\n sandboxId,\n path,\n hostname: url.hostname,\n url: request.url,\n method: request.method,\n userAgent: request.headers.get('User-Agent') || 'unknown'\n });\n\n return new Response(\n JSON.stringify({\n error: `Access denied: Invalid token or port not exposed`,\n code: 'INVALID_TOKEN'\n }),\n {\n status: 404,\n headers: {\n 'Content-Type': 'application/json'\n }\n }\n );\n }\n }\n\n // Detect WebSocket upgrade request\n const upgradeHeader = request.headers.get('Upgrade');\n if (upgradeHeader?.toLowerCase() === 'websocket') {\n // WebSocket path: Must use fetch() not containerFetch()\n // This bypasses JSRPC serialization boundary which cannot handle WebSocket upgrades\n return await sandbox.fetch(switchPort(request, port));\n }\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 // @ts-expect-error - duplex required for body streaming in modern runtimes\n duplex: 'half'\n });\n\n return await sandbox.containerFetch(proxyRequest, port);\n } catch (error) {\n logger.error(\n 'Proxy routing error',\n error instanceof Error ? error : new Error(String(error))\n );\n return new Response('Proxy routing error', { status: 500 });\n }\n}\n\nfunction extractSandboxRoute(url: URL): RouteInfo | null {\n // Parse subdomain pattern: port-sandboxId-token.domain (tokens mandatory)\n // Token is always exactly 16 chars (generated by generatePortToken)\n const subdomainMatch = url.hostname.match(\n /^(\\d{4,5})-([^.-][^.]*?[^.-]|[^.-])-([a-z0-9_-]{16})\\.(.+)$/\n );\n\n if (!subdomainMatch) {\n return null;\n }\n\n const portStr = subdomainMatch[1];\n const sandboxId = subdomainMatch[2];\n const token = subdomainMatch[3]; // Mandatory token\n const domain = subdomainMatch[4];\n\n const port = parseInt(portStr, 10);\n if (!validatePort(port)) {\n return null;\n }\n\n let sanitizedSandboxId: string;\n try {\n sanitizedSandboxId = sanitizeSandboxId(sandboxId);\n } catch (error) {\n return null;\n }\n\n // DNS subdomain length limit is 63 characters\n if (sandboxId.length > 63) {\n return null;\n }\n\n return {\n port,\n sandboxId: sanitizedSandboxId,\n path: url.pathname || '/',\n token\n };\n}\n\nexport function isLocalhostPattern(hostname: string): boolean {\n // Handle IPv6 addresses in brackets (with or without port)\n if (hostname.startsWith('[')) {\n if (hostname.includes(']:')) {\n // [::1]:port format\n const ipv6Part = hostname.substring(0, hostname.indexOf(']:') + 1);\n return ipv6Part === '[::1]';\n } else {\n // [::1] format without port\n return hostname === '[::1]';\n }\n }\n\n // Handle bare IPv6 without brackets\n if (hostname === '::1') {\n return true;\n }\n\n // For IPv4 and regular hostnames, split on colon to remove port\n const hostPart = hostname.split(':')[0];\n\n return (\n hostPart === 'localhost' ||\n hostPart === '127.0.0.1' ||\n hostPart === '0.0.0.0'\n );\n}\n","/**\n * Server-Sent Events (SSE) parser for streaming responses\n * Converts ReadableStream<Uint8Array> to typed AsyncIterable<T>\n */\n\n/**\n * Parse a ReadableStream of SSE events into typed AsyncIterable\n * @param stream - The ReadableStream from fetch response\n * @param signal - Optional AbortSignal for cancellation\n */\nexport async function* parseSSEStream<T>(\n stream: ReadableStream<Uint8Array>,\n signal?: AbortSignal\n): AsyncIterable<T> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n // Check for cancellation\n if (signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n const { done, value } = await reader.read();\n if (done) break;\n\n // Decode chunk and add to buffer\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events in buffer\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n // Skip empty lines\n if (line.trim() === '') continue;\n\n // Process SSE data lines\n if (line.startsWith('data: ')) {\n const data = line.substring(6);\n\n // Skip [DONE] markers or empty data\n if (data === '[DONE]' || data.trim() === '') continue;\n\n try {\n const event = JSON.parse(data) as T;\n yield event;\n } catch {\n // Skip invalid JSON events and continue processing\n }\n }\n // Handle other SSE fields if needed (event:, id:, retry:)\n // For now, we only care about data: lines\n }\n }\n\n // Process any remaining data in buffer\n if (buffer.trim() && buffer.startsWith('data: ')) {\n const data = buffer.substring(6);\n if (data !== '[DONE]' && data.trim()) {\n try {\n const event = JSON.parse(data) as T;\n yield event;\n } catch {\n // Skip invalid JSON in final event\n }\n }\n }\n } finally {\n // Clean up resources\n try {\n await reader.cancel();\n } catch {}\n reader.releaseLock();\n }\n}\n\n/**\n * Helper to convert a Response with SSE stream directly to AsyncIterable\n * @param response - Response object with SSE stream\n * @param signal - Optional AbortSignal for cancellation\n */\nexport async function* responseToAsyncIterable<T>(\n response: Response,\n signal?: AbortSignal\n): AsyncIterable<T> {\n if (!response.ok) {\n throw new Error(\n `Response not ok: ${response.status} ${response.statusText}`\n );\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n yield* parseSSEStream<T>(response.body, signal);\n}\n\n/**\n * Create an SSE-formatted ReadableStream from an AsyncIterable\n * (Useful for Worker endpoints that need to forward AsyncIterable as SSE)\n * @param events - AsyncIterable of events\n * @param options - Stream options\n */\nexport function asyncIterableToSSEStream<T>(\n events: AsyncIterable<T>,\n options?: {\n signal?: AbortSignal;\n serialize?: (event: T) => string;\n }\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const serialize = options?.serialize || JSON.stringify;\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const event of events) {\n if (options?.signal?.aborted) {\n controller.error(new Error('Operation was aborted'));\n break;\n }\n\n const data = serialize(event);\n const sseEvent = `data: ${data}\\n\\n`;\n controller.enqueue(encoder.encode(sseEvent));\n }\n\n // Send completion marker\n controller.enqueue(encoder.encode('data: [DONE]\\n\\n'));\n } catch (error) {\n controller.error(error);\n } finally {\n controller.close();\n }\n },\n\n cancel() {\n // Handle stream cancellation\n }\n });\n}\n","/**\n * Bucket mounting error classes\n *\n * These are SDK-side validation errors that follow the same pattern as SecurityError.\n * They are thrown before any container interaction occurs.\n */\n\nimport { ErrorCode } from '@repo/shared/errors';\n\n/**\n * Base error for bucket mounting operations\n */\nexport class BucketMountError extends Error {\n public readonly code: ErrorCode;\n\n constructor(message: string, code: ErrorCode = ErrorCode.BUCKET_MOUNT_ERROR) {\n super(message);\n this.name = 'BucketMountError';\n this.code = code;\n }\n}\n\n/**\n * Thrown when S3FS mount command fails\n */\nexport class S3FSMountError extends BucketMountError {\n constructor(message: string) {\n super(message, ErrorCode.S3FS_MOUNT_ERROR);\n this.name = 'S3FSMountError';\n }\n}\n\n/**\n * Thrown when no credentials found in environment\n */\nexport class MissingCredentialsError extends BucketMountError {\n constructor(message: string) {\n super(message, ErrorCode.MISSING_CREDENTIALS);\n this.name = 'MissingCredentialsError';\n }\n}\n\n/**\n * Thrown when bucket name, mount path, or options are invalid\n */\nexport class InvalidMountConfigError extends BucketMountError {\n constructor(message: string) {\n super(message, ErrorCode.INVALID_MOUNT_CONFIG);\n this.name = 'InvalidMountConfigError';\n }\n}\n","import type { BucketCredentials, MountBucketOptions } from '@repo/shared';\nimport { MissingCredentialsError } from './errors';\n\n/**\n * Detect credentials for bucket mounting from environment variables\n * Priority order:\n * 1. Explicit options.credentials\n * 2. Standard AWS env vars: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY\n * 3. Error: no credentials found\n *\n * @param options - Mount options\n * @param envVars - Environment variables\n * @returns Detected credentials\n * @throws MissingCredentialsError if no credentials found\n */\nexport function detectCredentials(\n options: MountBucketOptions,\n envVars: Record<string, string | undefined>\n): BucketCredentials {\n // Priority 1: Explicit credentials in options\n if (options.credentials) {\n return options.credentials;\n }\n\n // Priority 2: Standard AWS env vars\n const awsAccessKeyId = envVars.AWS_ACCESS_KEY_ID;\n const awsSecretAccessKey = envVars.AWS_SECRET_ACCESS_KEY;\n\n if (awsAccessKeyId && awsSecretAccessKey) {\n return {\n accessKeyId: awsAccessKeyId,\n secretAccessKey: awsSecretAccessKey\n };\n }\n\n // No credentials found - throw error with helpful message\n throw new MissingCredentialsError(\n `No credentials found. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY ` +\n `environment variables, or pass explicit credentials in options.`\n );\n}\n","/**\n * Provider detection and s3fs flag configuration\n *\n * Based on s3fs-fuse documentation:\n * https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3\n */\n\nimport type { BucketProvider } from '@repo/shared';\n\n/**\n * Detect provider from endpoint URL using pattern matching\n */\nexport function detectProviderFromUrl(endpoint: string): BucketProvider | null {\n try {\n const url = new URL(endpoint);\n const hostname = url.hostname.toLowerCase();\n\n if (hostname.endsWith('.r2.cloudflarestorage.com')) {\n return 'r2';\n }\n\n // Match AWS S3: *.amazonaws.com or s3.amazonaws.com\n if (\n hostname.endsWith('.amazonaws.com') ||\n hostname === 's3.amazonaws.com'\n ) {\n return 's3';\n }\n\n if (hostname === 'storage.googleapis.com') {\n return 'gcs';\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get s3fs flags for a given provider\n *\n * Based on s3fs-fuse wiki recommendations:\n * https://github.com/s3fs-fuse/s3fs-fuse/wiki/Non-Amazon-S3\n */\nexport function getProviderFlags(provider: BucketProvider | null): string[] {\n if (!provider) {\n return ['use_path_request_style'];\n }\n\n switch (provider) {\n case 'r2':\n return ['nomixupload'];\n\n case 's3':\n return [];\n\n case 'gcs':\n return [];\n\n default:\n return ['use_path_request_style'];\n }\n}\n\n/**\n * Resolve s3fs options by combining provider defaults with user overrides\n */\nexport function resolveS3fsOptions(\n provider: BucketProvider | null,\n userOptions?: string[]\n): string[] {\n const providerFlags = getProviderFlags(provider);\n\n if (!userOptions || userOptions.length === 0) {\n return providerFlags;\n }\n\n // Merge provider flags with user options\n // User options take precedence (come last in the array)\n const allFlags = [...providerFlags, ...userOptions];\n\n // Deduplicate flags (keep last occurrence)\n const flagMap = new Map<string, string>();\n\n for (const flag of allFlags) {\n // Split on '=' to get the flag name\n const [flagName] = flag.split('=');\n flagMap.set(flagName, flag);\n }\n\n return Array.from(flagMap.values());\n}\n","/**\n * SDK version - automatically synchronized with package.json by Changesets\n * This file is auto-updated by .github/changeset-version.ts during releases\n * DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump\n */\nexport const SDK_VERSION = '0.6.9';\n","import { Container, getContainer, switchPort } from '@cloudflare/containers';\nimport type {\n BucketCredentials,\n BucketProvider,\n CodeContext,\n CreateContextOptions,\n ExecEvent,\n ExecOptions,\n ExecResult,\n ExecutionResult,\n ExecutionSession,\n ISandbox,\n LogEvent,\n MountBucketOptions,\n PortWatchEvent,\n Process,\n ProcessOptions,\n ProcessStatus,\n RunCodeOptions,\n SandboxOptions,\n SessionOptions,\n StreamOptions,\n WaitForExitResult,\n WaitForLogResult,\n WaitForPortOptions\n} from '@repo/shared';\nimport {\n createLogger,\n getEnvString,\n isTerminalStatus,\n type SessionDeleteResult,\n shellEscape,\n TraceContext\n} from '@repo/shared';\nimport { type ExecuteResponse, SandboxClient } from './clients';\nimport type { ErrorResponse } from './errors';\nimport {\n CustomDomainRequiredError,\n ErrorCode,\n ProcessExitedBeforeReadyError,\n ProcessReadyTimeoutError,\n SessionAlreadyExistsError\n} from './errors';\nimport { CodeInterpreter } from './interpreter';\nimport { isLocalhostPattern } from './request-handler';\nimport { SecurityError, sanitizeSandboxId, validatePort } from './security';\nimport { parseSSEStream } from './sse-parser';\nimport {\n detectCredentials,\n detectProviderFromUrl,\n resolveS3fsOptions\n} from './storage-mount';\nimport {\n InvalidMountConfigError,\n S3FSMountError\n} from './storage-mount/errors';\nimport type { MountInfo } from './storage-mount/types';\nimport { SDK_VERSION } from './version';\n\nexport function getSandbox<T extends Sandbox<any>>(\n ns: DurableObjectNamespace<T>,\n id: string,\n options?: SandboxOptions\n): T {\n const sanitizedId = sanitizeSandboxId(id);\n const effectiveId = options?.normalizeId\n ? sanitizedId.toLowerCase()\n : sanitizedId;\n\n const hasUppercase = /[A-Z]/.test(sanitizedId);\n if (!options?.normalizeId && hasUppercase) {\n const logger = createLogger({ component: 'sandbox-do' });\n logger.warn(\n `Sandbox ID \"${sanitizedId}\" contains uppercase letters, which causes issues with preview URLs (hostnames are case-insensitive). ` +\n `normalizeId will default to true in a future version to prevent this. ` +\n `Use lowercase IDs or pass { normalizeId: true } to prepare.`\n );\n }\n\n const stub = getContainer(ns, effectiveId);\n\n stub.setSandboxName?.(effectiveId, options?.normalizeId);\n\n if (options?.baseUrl) {\n stub.setBaseUrl(options.baseUrl);\n }\n\n if (options?.sleepAfter !== undefined) {\n stub.setSleepAfter(options.sleepAfter);\n }\n\n if (options?.keepAlive !== undefined) {\n stub.setKeepAlive(options.keepAlive);\n }\n\n if (options?.containerTimeouts) {\n stub.setContainerTimeouts(options.containerTimeouts);\n }\n\n return Object.assign(stub, {\n wsConnect: connect(stub)\n }) as T;\n}\n\nexport function connect(stub: {\n fetch: (request: Request) => Promise<Response>;\n}) {\n return async (request: Request, port: number) => {\n if (!validatePort(port)) {\n throw new SecurityError(\n `Invalid or restricted port: ${port}. Ports must be in range 1024-65535 and not reserved.`\n );\n }\n const portSwitchedRequest = switchPort(request, port);\n return await stub.fetch(portSwitchedRequest);\n };\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: string | number = '10m'; // Sleep the sandbox if no requests are made in this timeframe\n\n client: SandboxClient;\n private codeInterpreter: CodeInterpreter;\n private sandboxName: string | null = null;\n private normalizeId: boolean = false;\n private baseUrl: string | null = null;\n private defaultSession: string | null = null;\n envVars: Record<string, string> = {};\n private logger: ReturnType<typeof createLogger>;\n private keepAliveEnabled: boolean = false;\n private activeMounts: Map<string, MountInfo> = new Map();\n private transport: 'http' | 'websocket' = 'http';\n\n /**\n * Default container startup timeouts (conservative for production)\n * Based on Cloudflare docs: \"Containers take several minutes to provision\"\n */\n private readonly DEFAULT_CONTAINER_TIMEOUTS = {\n // Time to get container instance and launch VM\n // @cloudflare/containers default: 8s (too short for cold starts)\n instanceGetTimeoutMS: 30_000, // 30 seconds\n\n // Time for application to start and ports to be ready\n // @cloudflare/containers default: 20s\n portReadyTimeoutMS: 90_000, // 90 seconds (allows for heavy containers)\n\n // Polling interval for checking container readiness\n // @cloudflare/containers default: 300ms (too aggressive)\n waitIntervalMS: 1000 // 1 second (reduces load)\n };\n\n /**\n * Active container timeout configuration\n * Can be set via options, env vars, or defaults\n */\n private containerTimeouts = { ...this.DEFAULT_CONTAINER_TIMEOUTS };\n\n /**\n * Create a SandboxClient with current transport settings\n */\n private createSandboxClient(): SandboxClient {\n return new SandboxClient({\n logger: this.logger,\n port: 3000,\n stub: this,\n ...(this.transport === 'websocket' && {\n transportMode: 'websocket' as const,\n wsUrl: 'ws://localhost:3000/ws'\n })\n });\n }\n\n constructor(ctx: DurableObjectState<{}>, env: Env) {\n super(ctx, env);\n\n const envObj = env as Record<string, unknown>;\n // Set sandbox environment variables from env object\n const sandboxEnvKeys = ['SANDBOX_LOG_LEVEL', 'SANDBOX_LOG_FORMAT'] as const;\n sandboxEnvKeys.forEach((key) => {\n if (envObj?.[key]) {\n this.envVars[key] = String(envObj[key]);\n }\n });\n\n // Initialize timeouts with env var fallbacks\n this.containerTimeouts = this.getDefaultTimeouts(envObj);\n\n this.logger = createLogger({\n component: 'sandbox-do',\n sandboxId: this.ctx.id.toString()\n });\n\n // Read transport setting from env var\n const transportEnv = envObj?.SANDBOX_TRANSPORT;\n if (transportEnv === 'websocket') {\n this.transport = 'websocket';\n } else if (transportEnv != null && transportEnv !== 'http') {\n this.logger.warn(\n `Invalid SANDBOX_TRANSPORT value: \"${transportEnv}\". Must be \"http\" or \"websocket\". Defaulting to \"http\".`\n );\n }\n\n // Create client with transport based on env var (may be updated from storage)\n this.client = this.createSandboxClient();\n\n // Initialize code interpreter - pass 'this' after client is ready\n // The CodeInterpreter extracts client.interpreter from the sandbox\n this.codeInterpreter = new CodeInterpreter(this);\n\n this.ctx.blockConcurrencyWhile(async () => {\n this.sandboxName =\n (await this.ctx.storage.get<string>('sandboxName')) || null;\n this.normalizeId =\n (await this.ctx.storage.get<boolean>('normalizeId')) || false;\n this.defaultSession =\n (await this.ctx.storage.get<string>('defaultSession')) || null;\n this.keepAliveEnabled =\n (await this.ctx.storage.get<boolean>('keepAliveEnabled')) || false;\n\n // Load saved timeout configuration (highest priority)\n const storedTimeouts =\n await this.ctx.storage.get<\n NonNullable<SandboxOptions['containerTimeouts']>\n >('containerTimeouts');\n if (storedTimeouts) {\n this.containerTimeouts = {\n ...this.containerTimeouts,\n ...storedTimeouts\n };\n }\n });\n }\n\n async setSandboxName(name: string, normalizeId?: boolean): Promise<void> {\n if (!this.sandboxName) {\n this.sandboxName = name;\n this.normalizeId = normalizeId || false;\n await this.ctx.storage.put('sandboxName', name);\n await this.ctx.storage.put('normalizeId', this.normalizeId);\n }\n }\n\n // RPC method to set the base URL\n async setBaseUrl(baseUrl: string): Promise<void> {\n if (!this.baseUrl) {\n this.baseUrl = baseUrl;\n await this.ctx.storage.put('baseUrl', baseUrl);\n } else {\n if (this.baseUrl !== baseUrl) {\n throw new Error(\n 'Base URL already set and different from one previously provided'\n );\n }\n }\n }\n\n // RPC method to set the sleep timeout\n async setSleepAfter(sleepAfter: string | number): Promise<void> {\n this.sleepAfter = sleepAfter;\n // Reschedule activity timeout to apply the new sleepAfter value immediately\n this.renewActivityTimeout();\n }\n\n // RPC method to enable keepAlive mode\n async setKeepAlive(keepAlive: boolean): Promise<void> {\n this.keepAliveEnabled = keepAlive;\n await this.ctx.storage.put('keepAliveEnabled', keepAlive);\n if (keepAlive) {\n this.logger.info(\n 'KeepAlive mode enabled - container will stay alive until explicitly destroyed'\n );\n } else {\n this.logger.info(\n 'KeepAlive mode disabled - container will timeout normally'\n );\n }\n }\n\n // RPC method to set environment variables\n async setEnvVars(envVars: Record<string, string>): Promise<void> {\n // Update local state for new sessions\n this.envVars = { ...this.envVars, ...envVars };\n\n // If default session already exists, update it directly\n if (this.defaultSession) {\n // Set environment variables by executing export commands in the existing session\n for (const [key, value] of Object.entries(envVars)) {\n const escapedValue = value.replace(/'/g, \"'\\\\''\");\n const exportCommand = `export ${key}='${escapedValue}'`;\n\n const result = await this.client.commands.execute(\n exportCommand,\n this.defaultSession\n );\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to set ${key}: ${result.stderr || 'Unknown error'}`\n );\n }\n }\n }\n }\n\n /**\n * RPC method to configure container startup timeouts\n */\n async setContainerTimeouts(\n timeouts: NonNullable<SandboxOptions['containerTimeouts']>\n ): Promise<void> {\n const validated = { ...this.containerTimeouts };\n\n // Validate each timeout if provided\n if (timeouts.instanceGetTimeoutMS !== undefined) {\n validated.instanceGetTimeoutMS = this.validateTimeout(\n timeouts.instanceGetTimeoutMS,\n 'instanceGetTimeoutMS',\n 5_000,\n 300_000\n );\n }\n\n if (timeouts.portReadyTimeoutMS !== undefined) {\n validated.portReadyTimeoutMS = this.validateTimeout(\n timeouts.portReadyTimeoutMS,\n 'portReadyTimeoutMS',\n 10_000,\n 600_000\n );\n }\n\n if (timeouts.waitIntervalMS !== undefined) {\n validated.waitIntervalMS = this.validateTimeout(\n timeouts.waitIntervalMS,\n 'waitIntervalMS',\n 100,\n 5_000\n );\n }\n\n this.containerTimeouts = validated;\n\n // Persist to storage\n await this.ctx.storage.put('containerTimeouts', this.containerTimeouts);\n\n this.logger.debug('Container timeouts updated', this.containerTimeouts);\n }\n\n /**\n * Validate a timeout value is within acceptable range\n * Throws error if invalid - used for user-provided values\n */\n private validateTimeout(\n value: number,\n name: string,\n min: number,\n max: number\n ): number {\n if (\n typeof value !== 'number' ||\n Number.isNaN(value) ||\n !Number.isFinite(value)\n ) {\n throw new Error(`${name} must be a valid finite number, got ${value}`);\n }\n\n if (value < min || value > max) {\n throw new Error(\n `${name} must be between ${min}-${max}ms, got ${value}ms`\n );\n }\n\n return value;\n }\n\n /**\n * Get default timeouts with env var fallbacks and validation\n * Precedence: SDK defaults < Env vars < User config\n */\n private getDefaultTimeouts(\n env: Record<string, unknown>\n ): typeof this.DEFAULT_CONTAINER_TIMEOUTS {\n const parseAndValidate = (\n envVar: string | undefined,\n name: keyof typeof this.DEFAULT_CONTAINER_TIMEOUTS,\n min: number,\n max: number\n ): number => {\n const defaultValue = this.DEFAULT_CONTAINER_TIMEOUTS[name];\n\n if (envVar === undefined) {\n return defaultValue;\n }\n\n const parsed = parseInt(envVar, 10);\n\n if (Number.isNaN(parsed)) {\n this.logger.warn(\n `Invalid ${name}: \"${envVar}\" is not a number. Using default: ${defaultValue}ms`\n );\n return defaultValue;\n }\n\n if (parsed < min || parsed > max) {\n this.logger.warn(\n `Invalid ${name}: ${parsed}ms. Must be ${min}-${max}ms. Using default: ${defaultValue}ms`\n );\n return defaultValue;\n }\n\n return parsed;\n };\n\n return {\n instanceGetTimeoutMS: parseAndValidate(\n getEnvString(env, 'SANDBOX_INSTANCE_TIMEOUT_MS'),\n 'instanceGetTimeoutMS',\n 5_000, // Min 5s\n 300_000 // Max 5min\n ),\n portReadyTimeoutMS: parseAndValidate(\n getEnvString(env, 'SANDBOX_PORT_TIMEOUT_MS'),\n 'portReadyTimeoutMS',\n 10_000, // Min 10s\n 600_000 // Max 10min\n ),\n waitIntervalMS: parseAndValidate(\n getEnvString(env, 'SANDBOX_POLL_INTERVAL_MS'),\n 'waitIntervalMS',\n 100, // Min 100ms\n 5_000 // Max 5s\n )\n };\n }\n\n /*\n * Mount an S3-compatible bucket as a local directory using S3FS-FUSE\n *\n * Requires explicit endpoint URL. Credentials are auto-detected from environment\n * variables or can be provided explicitly.\n *\n * @param bucket - Bucket name\n * @param mountPath - Absolute path in container to mount at\n * @param options - Configuration options with required endpoint\n * @throws MissingCredentialsError if no credentials found in environment\n * @throws S3FSMountError if S3FS mount command fails\n * @throws InvalidMountConfigError if bucket name, mount path, or endpoint is invalid\n */\n async mountBucket(\n bucket: string,\n mountPath: string,\n options: MountBucketOptions\n ): Promise<void> {\n this.logger.info(`Mounting bucket ${bucket} to ${mountPath}`);\n\n // Validate options\n this.validateMountOptions(bucket, mountPath, options);\n\n // Detect provider from explicit option or URL pattern\n const provider: BucketProvider | null =\n options.provider || detectProviderFromUrl(options.endpoint);\n\n this.logger.debug(`Detected provider: ${provider || 'unknown'}`, {\n explicitProvider: options.provider\n });\n\n // Detect credentials\n const credentials = detectCredentials(options, this.envVars);\n\n // Generate unique password file path\n const passwordFilePath = this.generatePasswordFilePath();\n\n // Reserve mount path before async operations so concurrent mounts see it\n this.activeMounts.set(mountPath, {\n bucket,\n mountPath,\n endpoint: options.endpoint,\n provider,\n passwordFilePath,\n mounted: false\n });\n\n try {\n // Create password file with credentials\n await this.createPasswordFile(passwordFilePath, bucket, credentials);\n\n // Create mount directory\n await this.exec(`mkdir -p ${shellEscape(mountPath)}`);\n\n // Execute S3FS mount with password file\n await this.executeS3FSMount(\n bucket,\n mountPath,\n options,\n provider,\n passwordFilePath\n );\n\n // Mark as successfully mounted\n this.activeMounts.set(mountPath, {\n bucket,\n mountPath,\n endpoint: options.endpoint,\n provider,\n passwordFilePath,\n mounted: true\n });\n\n this.logger.info(`Successfully mounted bucket ${bucket} to ${mountPath}`);\n } catch (error) {\n // Clean up password file on failure\n await this.deletePasswordFile(passwordFilePath);\n\n // Clean up reservation on failure\n this.activeMounts.delete(mountPath);\n throw error;\n }\n }\n\n /**\n * Manually unmount a bucket filesystem\n *\n * @param mountPath - Absolute path where the bucket is mounted\n * @throws InvalidMountConfigError if mount path doesn't exist or isn't mounted\n */\n async unmountBucket(mountPath: string): Promise<void> {\n this.logger.info(`Unmounting bucket from ${mountPath}`);\n\n // Look up mount by path\n const mountInfo = this.activeMounts.get(mountPath);\n\n // Throw error if mount doesn't exist\n if (!mountInfo) {\n throw new InvalidMountConfigError(\n `No active mount found at path: ${mountPath}`\n );\n }\n\n // Unmount the filesystem\n try {\n await this.exec(`fusermount -u ${shellEscape(mountPath)}`);\n mountInfo.mounted = false;\n\n // Only remove from tracking if unmount succeeded\n this.activeMounts.delete(mountPath);\n } finally {\n // Always cleanup password file, even if unmount fails\n await this.deletePasswordFile(mountInfo.passwordFilePath);\n }\n\n this.logger.info(`Successfully unmounted bucket from ${mountPath}`);\n }\n\n /**\n * Validate mount options\n */\n private validateMountOptions(\n bucket: string,\n mountPath: string,\n options: MountBucketOptions\n ): void {\n // Require endpoint field\n if (!options.endpoint) {\n throw new InvalidMountConfigError(\n 'Endpoint is required. Provide the full S3-compatible endpoint URL.'\n );\n }\n\n // Basic URL validation\n try {\n new URL(options.endpoint);\n } catch (error) {\n throw new InvalidMountConfigError(\n `Invalid endpoint URL: \"${options.endpoint}\". Must be a valid HTTP(S) URL.`\n );\n }\n\n // Validate bucket name (S3-compatible naming rules)\n const bucketNameRegex = /^[a-z0-9]([a-z0-9.-]{0,61}[a-z0-9])?$/;\n if (!bucketNameRegex.test(bucket)) {\n throw new InvalidMountConfigError(\n `Invalid bucket name: \"${bucket}\". Bucket names must be 3-63 characters, ` +\n `lowercase alphanumeric, dots, or hyphens, and cannot start/end with dots or hyphens.`\n );\n }\n\n // Validate mount path is absolute\n if (!mountPath.startsWith('/')) {\n throw new InvalidMountConfigError(\n `Mount path must be absolute (start with /): \"${mountPath}\"`\n );\n }\n\n // Check for duplicate mount path\n if (this.activeMounts.has(mountPath)) {\n const existingMount = this.activeMounts.get(mountPath);\n throw new InvalidMountConfigError(\n `Mount path \"${mountPath}\" is already in use by bucket \"${existingMount?.bucket}\". ` +\n `Unmount the existing bucket first or use a different mount path.`\n );\n }\n }\n\n /**\n * Generate unique password file path for s3fs credentials\n */\n private generatePasswordFilePath(): string {\n const uuid = crypto.randomUUID();\n return `/tmp/.passwd-s3fs-${uuid}`;\n }\n\n /**\n * Create password file with s3fs credentials\n * Format: bucket:accessKeyId:secretAccessKey\n */\n private async createPasswordFile(\n passwordFilePath: string,\n bucket: string,\n credentials: BucketCredentials\n ): Promise<void> {\n const content = `${bucket}:${credentials.accessKeyId}:${credentials.secretAccessKey}`;\n\n await this.writeFile(passwordFilePath, content);\n\n await this.exec(`chmod 0600 ${shellEscape(passwordFilePath)}`);\n\n this.logger.debug(`Created password file: ${passwordFilePath}`);\n }\n\n /**\n * Delete password file\n */\n private async deletePasswordFile(passwordFilePath: string): Promise<void> {\n try {\n await this.exec(`rm -f ${shellEscape(passwordFilePath)}`);\n this.logger.debug(`Deleted password file: ${passwordFilePath}`);\n } catch (error) {\n this.logger.warn(`Failed to delete password file ${passwordFilePath}`, {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n\n /**\n * Execute S3FS mount command\n */\n private async executeS3FSMount(\n bucket: string,\n mountPath: string,\n options: MountBucketOptions,\n provider: BucketProvider | null,\n passwordFilePath: string\n ): Promise<void> {\n // Resolve s3fs options (provider defaults + user overrides)\n const resolvedOptions = resolveS3fsOptions(provider, options.s3fsOptions);\n\n // Build s3fs mount command\n const s3fsArgs: string[] = [];\n\n // Add password file option FIRST\n s3fsArgs.push(`passwd_file=${passwordFilePath}`);\n\n // Add resolved provider-specific and user options\n s3fsArgs.push(...resolvedOptions);\n\n // Add read-only flag if requested\n if (options.readOnly) {\n s3fsArgs.push('ro');\n }\n\n // Add endpoint URL\n s3fsArgs.push(`url=${options.endpoint}`);\n\n // Build final command with escaped options\n const optionsStr = shellEscape(s3fsArgs.join(','));\n const mountCmd = `s3fs ${shellEscape(bucket)} ${shellEscape(mountPath)} -o ${optionsStr}`;\n\n this.logger.debug('Executing s3fs mount', {\n bucket,\n mountPath,\n provider,\n resolvedOptions\n });\n\n // Execute mount command\n const result = await this.exec(mountCmd);\n\n if (result.exitCode !== 0) {\n throw new S3FSMountError(\n `S3FS mount failed: ${result.stderr || result.stdout || 'Unknown error'}`\n );\n }\n\n this.logger.debug('Mount command executed successfully');\n }\n\n /**\n * Cleanup and destroy the sandbox container\n */\n override async destroy(): Promise<void> {\n this.logger.info('Destroying sandbox container');\n\n // Disconnect WebSocket transport if active\n this.client.disconnect();\n\n // Unmount all mounted buckets and cleanup password files\n for (const [mountPath, mountInfo] of this.activeMounts.entries()) {\n if (mountInfo.mounted) {\n try {\n this.logger.info(\n `Unmounting bucket ${mountInfo.bucket} from ${mountPath}`\n );\n await this.exec(`fusermount -u ${shellEscape(mountPath)}`);\n mountInfo.mounted = false;\n } catch (error) {\n const errorMsg =\n error instanceof Error ? error.message : String(error);\n this.logger.warn(\n `Failed to unmount bucket ${mountInfo.bucket} from ${mountPath}: ${errorMsg}`\n );\n }\n }\n\n // Always cleanup password file\n await this.deletePasswordFile(mountInfo.passwordFilePath);\n }\n\n await super.destroy();\n }\n\n override onStart() {\n this.logger.debug('Sandbox started');\n\n // Check version compatibility asynchronously (don't block startup)\n this.checkVersionCompatibility().catch((error) => {\n this.logger.error(\n 'Version compatibility check failed',\n error instanceof Error ? error : new Error(String(error))\n );\n });\n }\n\n /**\n * Check if the container version matches the SDK version\n * Logs a warning if there's a mismatch\n */\n private async checkVersionCompatibility(): Promise<void> {\n try {\n // Get the SDK version (imported from version.ts)\n const sdkVersion = SDK_VERSION;\n\n // Get container version\n const containerVersion = await this.client.utils.getVersion();\n\n // If container version is unknown, it's likely an old container without the endpoint\n if (containerVersion === 'unknown') {\n this.logger.warn(\n 'Container version check: Container version could not be determined. ' +\n 'This may indicate an outdated container image. ' +\n 'Please update your container to match SDK version ' +\n sdkVersion\n );\n return;\n }\n\n // Check if versions match\n if (containerVersion !== sdkVersion) {\n const message =\n `Version mismatch detected! SDK version (${sdkVersion}) does not match ` +\n `container version (${containerVersion}). This may cause compatibility issues. ` +\n `Please update your container image to version ${sdkVersion}`;\n\n // Log warning - we can't reliably detect dev vs prod environment in Durable Objects\n // so we always use warning level as requested by the user\n this.logger.warn(message);\n } else {\n this.logger.debug('Version check passed', {\n sdkVersion,\n containerVersion\n });\n }\n } catch (error) {\n // Don't fail the sandbox initialization if version check fails\n this.logger.debug('Version compatibility check encountered an error', {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n\n override async onStop() {\n this.logger.debug('Sandbox stopped');\n\n // Clear in-memory state that references the old container\n // This prevents stale references after container restarts\n this.defaultSession = null;\n this.activeMounts.clear();\n\n // Persist cleanup to storage so state is clean on next container start\n await Promise.all([\n this.ctx.storage.delete('portTokens'),\n this.ctx.storage.delete('defaultSession')\n ]);\n }\n\n override onError(error: unknown) {\n this.logger.error(\n 'Sandbox error',\n error instanceof Error ? error : new Error(String(error))\n );\n }\n\n /**\n * Override Container.containerFetch to use production-friendly timeouts\n * Automatically starts container with longer timeouts if not running\n */\n override async containerFetch(\n requestOrUrl: Request | string | URL,\n portOrInit?: number | RequestInit,\n portParam?: number\n ): Promise<Response> {\n // Parse arguments to extract request and port\n const { request, port } = this.parseContainerFetchArgs(\n requestOrUrl,\n portOrInit,\n portParam\n );\n\n const state = await this.getState();\n\n // If container not healthy, start it with production timeouts\n if (state.status !== 'healthy') {\n try {\n this.logger.debug('Starting container with configured timeouts', {\n instanceTimeout: this.containerTimeouts.instanceGetTimeoutMS,\n portTimeout: this.containerTimeouts.portReadyTimeoutMS\n });\n\n await this.startAndWaitForPorts({\n ports: port,\n cancellationOptions: {\n instanceGetTimeoutMS: this.containerTimeouts.instanceGetTimeoutMS,\n portReadyTimeoutMS: this.containerTimeouts.portReadyTimeoutMS,\n waitInterval: this.containerTimeouts.waitIntervalMS,\n abort: request.signal\n }\n });\n } catch (e) {\n // 1. Provisioning: Container VM not yet available\n if (this.isNoInstanceError(e)) {\n return new Response(\n 'Container is currently provisioning. This can take several minutes on first deployment. Please retry in a moment.',\n {\n status: 503,\n headers: { 'Retry-After': '10' }\n }\n );\n }\n\n // 2. Transient startup errors: Container starting, port not ready yet\n if (this.isTransientStartupError(e)) {\n this.logger.debug(\n 'Transient container startup error, returning 503',\n {\n error: e instanceof Error ? e.message : String(e)\n }\n );\n return new Response(\n 'Container is starting. Please retry in a moment.',\n {\n status: 503,\n headers: { 'Retry-After': '3' }\n }\n );\n }\n\n // 3. Permanent errors: Configuration issues, missing images, etc.\n this.logger.error(\n 'Container startup failed with permanent error',\n e instanceof Error ? e : new Error(String(e))\n );\n return new Response(\n `Failed to start container: ${e instanceof Error ? e.message : String(e)}`,\n { status: 500 }\n );\n }\n }\n\n // Delegate to parent for the actual fetch (handles TCP port access internally)\n return await super.containerFetch(requestOrUrl, portOrInit, portParam);\n }\n\n /**\n * Helper: Check if error is \"no container instance available\"\n * This indicates the container VM is still being provisioned.\n */\n private isNoInstanceError(error: unknown): boolean {\n return (\n error instanceof Error &&\n error.message.toLowerCase().includes('no container instance')\n );\n }\n\n /**\n * Helper: Check if error is a transient startup error that should trigger retry\n *\n * These errors occur during normal container startup and are recoverable:\n * - Port not yet mapped (container starting, app not listening yet)\n * - Connection refused (port mapped but app not ready)\n * - Timeouts during startup (recoverable with retry)\n * - Network transients (temporary connectivity issues)\n *\n * Errors NOT included (permanent failures):\n * - \"no such image\" - missing Docker image\n * - \"container already exists\" - name collision\n * - Configuration errors\n */\n private isTransientStartupError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n\n const msg = error.message.toLowerCase();\n\n // Transient errors from workerd container-client.c++ and @cloudflare/containers\n const transientPatterns = [\n // Port mapping race conditions (workerd DockerPort::connect)\n 'container port not found',\n 'connection refused: container port',\n\n // Application startup delays (@cloudflare/containers)\n 'the container is not listening',\n 'failed to verify port',\n 'container did not start',\n\n // Network transients (workerd)\n 'network connection lost',\n 'container suddenly disconnected',\n\n // Monitor race conditions (workerd)\n 'monitor failed to find container',\n\n // Timeouts (various layers)\n 'timed out',\n 'timeout',\n 'the operation was aborted'\n ];\n\n return transientPatterns.some((pattern) => msg.includes(pattern));\n }\n\n /**\n * Helper: Parse containerFetch arguments (supports multiple signatures)\n */\n private parseContainerFetchArgs(\n requestOrUrl: Request | string | URL,\n portOrInit?: number | RequestInit,\n portParam?: number\n ): { request: Request; port: number } {\n let request: Request;\n let port: number | undefined;\n\n if (requestOrUrl instanceof Request) {\n request = requestOrUrl;\n port = typeof portOrInit === 'number' ? portOrInit : undefined;\n } else {\n const url =\n typeof requestOrUrl === 'string'\n ? requestOrUrl\n : requestOrUrl.toString();\n const init = typeof portOrInit === 'number' ? {} : portOrInit || {};\n port =\n typeof portOrInit === 'number'\n ? portOrInit\n : typeof portParam === 'number'\n ? portParam\n : undefined;\n request = new Request(url, init);\n }\n\n port ??= this.defaultPort;\n\n if (port === undefined) {\n throw new Error('No port specified for container fetch');\n }\n\n return { request, port };\n }\n\n /**\n * Override onActivityExpired to prevent automatic shutdown when keepAlive is enabled\n * When keepAlive is disabled, calls parent implementation which stops the container\n */\n override async onActivityExpired(): Promise<void> {\n if (this.keepAliveEnabled) {\n this.logger.debug(\n 'Activity expired but keepAlive is enabled - container will stay alive'\n );\n // Do nothing - don't call stop(), container stays alive\n } else {\n // Default behavior: stop the container\n this.logger.debug('Activity expired - stopping container');\n await super.onActivityExpired();\n }\n }\n\n // Override fetch to route internal container requests to appropriate ports\n override async fetch(request: Request): Promise<Response> {\n // Extract or generate trace ID from request\n const traceId =\n TraceContext.fromHeaders(request.headers) || TraceContext.generate();\n\n // Create request-specific logger with trace ID\n const requestLogger = this.logger.child({ traceId, operation: 'fetch' });\n\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 }\n\n // Detect WebSocket upgrade request (RFC 6455 compliant)\n const upgradeHeader = request.headers.get('Upgrade');\n const connectionHeader = request.headers.get('Connection');\n const isWebSocket =\n upgradeHeader?.toLowerCase() === 'websocket' &&\n connectionHeader?.toLowerCase().includes('upgrade');\n\n if (isWebSocket) {\n // WebSocket path: Let parent Container class handle WebSocket proxying\n // This bypasses containerFetch() which uses JSRPC and cannot handle WebSocket upgrades\n try {\n requestLogger.debug('WebSocket upgrade requested', {\n path: url.pathname,\n port: this.determinePort(url)\n });\n return await super.fetch(request);\n } catch (error) {\n requestLogger.error(\n 'WebSocket connection failed',\n error instanceof Error ? error : new Error(String(error)),\n { path: url.pathname }\n );\n throw error;\n }\n }\n\n // Non-WebSocket: Use existing port determination and HTTP routing logic\n const port = this.determinePort(url);\n\n // Route to the appropriate port\n return await this.containerFetch(request, port);\n }\n\n wsConnect(request: Request, port: number): Promise<Response> {\n // Stub - actual implementation is attached by getSandbox() on the stub object\n throw new Error(\n 'wsConnect must be called on the stub returned by getSandbox()'\n );\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], 10);\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 /**\n * Ensure default session exists - lazy initialization\n * This is called automatically by all public methods that need a session\n *\n * The session ID is persisted to DO storage. On container restart, if the\n * container already has this session (from a previous instance), we sync\n * our state rather than failing on duplicate creation.\n */\n private async ensureDefaultSession(): Promise<string> {\n const sessionId = `sandbox-${this.sandboxName || 'default'}`;\n\n // Fast path: session already initialized in this instance\n if (this.defaultSession === sessionId) {\n return this.defaultSession;\n }\n\n // Create session in container\n try {\n await this.client.utils.createSession({\n id: sessionId,\n env: this.envVars || {},\n cwd: '/workspace'\n });\n\n this.defaultSession = sessionId;\n await this.ctx.storage.put('defaultSession', sessionId);\n this.logger.debug('Default session initialized', { sessionId });\n } catch (error: unknown) {\n // Session may already exist (e.g., after hot reload or concurrent request)\n if (error instanceof SessionAlreadyExistsError) {\n this.logger.debug(\n 'Session exists in container but not in DO state, syncing',\n { sessionId }\n );\n this.defaultSession = sessionId;\n await this.ctx.storage.put('defaultSession', sessionId);\n } else {\n throw error;\n }\n }\n\n return this.defaultSession;\n }\n\n // Enhanced exec method - always returns ExecResult with optional streaming\n // This replaces the old exec method to match ISandbox interface\n async exec(command: string, options?: ExecOptions): Promise<ExecResult> {\n const session = await this.ensureDefaultSession();\n return this.execWithSession(command, session, options);\n }\n\n /**\n * Internal session-aware exec implementation\n * Used by both public exec() and session wrappers\n */\n private async execWithSession(\n command: string,\n sessionId: string,\n options?: ExecOptions\n ): Promise<ExecResult> {\n const startTime = Date.now();\n const timestamp = new Date().toISOString();\n\n let timeoutId: NodeJS.Timeout | undefined;\n\n try {\n // Handle cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n let result: ExecResult;\n\n if (options?.stream && options?.onOutput) {\n // Streaming with callbacks - we need to collect the final result\n result = await this.executeWithStreaming(\n command,\n sessionId,\n options,\n startTime,\n timestamp\n );\n } else {\n // Regular execution with session\n const commandOptions =\n options &&\n (options.timeout !== undefined ||\n options.env !== undefined ||\n options.cwd !== undefined)\n ? {\n timeoutMs: options.timeout,\n env: options.env,\n cwd: options.cwd\n }\n : undefined;\n\n const response = await this.client.commands.execute(\n command,\n sessionId,\n commandOptions\n );\n\n const duration = Date.now() - startTime;\n result = this.mapExecuteResponseToExecResult(\n response,\n duration,\n sessionId\n );\n }\n\n // Call completion callback if provided\n if (options?.onComplete) {\n options.onComplete(result);\n }\n\n return result;\n } catch (error) {\n if (options?.onError && error instanceof Error) {\n options.onError(error);\n }\n throw error;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n private async executeWithStreaming(\n command: string,\n sessionId: string,\n options: ExecOptions,\n startTime: number,\n timestamp: string\n ): Promise<ExecResult> {\n let stdout = '';\n let stderr = '';\n\n try {\n const stream = await this.client.commands.executeStream(\n command,\n sessionId,\n {\n timeoutMs: options.timeout,\n env: options.env,\n cwd: options.cwd\n }\n );\n\n for await (const event of parseSSEStream<ExecEvent>(stream)) {\n // Check for cancellation\n if (options.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n switch (event.type) {\n case 'stdout':\n case 'stderr':\n if (event.data) {\n // Update accumulated output\n if (event.type === 'stdout') stdout += event.data;\n if (event.type === 'stderr') stderr += event.data;\n\n // Call user's callback\n if (options.onOutput) {\n options.onOutput(event.type, event.data);\n }\n }\n break;\n\n case 'complete': {\n // Use result from complete event if available\n const duration = Date.now() - startTime;\n return {\n success: (event.exitCode ?? 0) === 0,\n exitCode: event.exitCode ?? 0,\n stdout,\n stderr,\n command,\n duration,\n timestamp,\n sessionId\n };\n }\n\n case 'error':\n throw new Error(event.data || 'Command execution failed');\n }\n }\n\n // If we get here without a complete event, something went wrong\n throw new Error('Stream ended without completion event');\n } catch (error) {\n if (options.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n throw error;\n }\n }\n\n private mapExecuteResponseToExecResult(\n response: ExecuteResponse,\n duration: number,\n sessionId?: string\n ): ExecResult {\n return {\n success: response.success,\n exitCode: response.exitCode,\n stdout: response.stdout,\n stderr: response.stderr,\n command: response.command,\n duration,\n timestamp: response.timestamp,\n sessionId\n };\n }\n\n /**\n * Create a Process domain object from HTTP client DTO\n * Centralizes process object creation with bound methods\n * This eliminates duplication across startProcess, listProcesses, getProcess, and session wrappers\n */\n private createProcessFromDTO(\n data: {\n id: string;\n pid?: number;\n command: string;\n status: ProcessStatus;\n startTime: string | Date;\n endTime?: string | Date;\n exitCode?: number;\n },\n sessionId: string\n ): Process {\n return {\n id: data.id,\n pid: data.pid,\n command: data.command,\n status: data.status,\n startTime:\n typeof data.startTime === 'string'\n ? new Date(data.startTime)\n : data.startTime,\n endTime: data.endTime\n ? typeof data.endTime === 'string'\n ? new Date(data.endTime)\n : data.endTime\n : undefined,\n exitCode: data.exitCode,\n sessionId,\n\n kill: async (signal?: string) => {\n await this.killProcess(data.id, signal);\n },\n\n getStatus: async () => {\n const current = await this.getProcess(data.id);\n return current?.status || 'error';\n },\n\n getLogs: async () => {\n const logs = await this.getProcessLogs(data.id);\n return { stdout: logs.stdout, stderr: logs.stderr };\n },\n\n waitForLog: async (\n pattern: string | RegExp,\n timeout?: number\n ): Promise<WaitForLogResult> => {\n return this.waitForLogPattern(data.id, data.command, pattern, timeout);\n },\n\n waitForPort: async (\n port: number,\n options?: WaitForPortOptions\n ): Promise<void> => {\n await this.waitForPortReady(data.id, data.command, port, options);\n },\n\n waitForExit: async (timeout?: number): Promise<WaitForExitResult> => {\n return this.waitForProcessExit(data.id, data.command, timeout);\n }\n };\n }\n\n /**\n * Wait for a log pattern to appear in process output\n */\n private async waitForLogPattern(\n processId: string,\n command: string,\n pattern: string | RegExp,\n timeout?: number\n ): Promise<WaitForLogResult> {\n const startTime = Date.now();\n const conditionStr = this.conditionToString(pattern);\n let collectedStdout = '';\n let collectedStderr = '';\n\n // First check existing logs\n try {\n const existingLogs = await this.getProcessLogs(processId);\n // Ensure existing logs end with newline for proper line separation from streamed output\n collectedStdout = existingLogs.stdout;\n if (collectedStdout && !collectedStdout.endsWith('\\n')) {\n collectedStdout += '\\n';\n }\n collectedStderr = existingLogs.stderr;\n if (collectedStderr && !collectedStderr.endsWith('\\n')) {\n collectedStderr += '\\n';\n }\n\n // Check stdout\n const stdoutResult = this.matchPattern(existingLogs.stdout, pattern);\n if (stdoutResult) {\n return stdoutResult;\n }\n\n // Check stderr\n const stderrResult = this.matchPattern(existingLogs.stderr, pattern);\n if (stderrResult) {\n return stderrResult;\n }\n } catch (error) {\n // Process might have already exited, continue to streaming\n this.logger.debug('Could not get existing logs, will stream', {\n processId,\n error: error instanceof Error ? error.message : String(error)\n });\n }\n\n // Stream new logs and check for pattern\n const stream = await this.streamProcessLogs(processId);\n\n // Set up timeout if specified\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutPromise: Promise<never> | undefined;\n\n if (timeout !== undefined) {\n const remainingTime = timeout - (Date.now() - startTime);\n if (remainingTime <= 0) {\n throw this.createReadyTimeoutError(\n processId,\n command,\n conditionStr,\n timeout\n );\n }\n\n timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n this.createReadyTimeoutError(\n processId,\n command,\n conditionStr,\n timeout\n )\n );\n }, remainingTime);\n });\n }\n\n try {\n // Process stream\n const streamProcessor = async (): Promise<WaitForLogResult> => {\n const DEBOUNCE_MS = 50;\n let lastCheckTime = 0;\n let pendingCheck = false;\n\n const checkPattern = (): WaitForLogResult | null => {\n // Check both stdout and stderr buffers\n const stdoutResult = this.matchPattern(collectedStdout, pattern);\n if (stdoutResult) return stdoutResult;\n const stderrResult = this.matchPattern(collectedStderr, pattern);\n if (stderrResult) return stderrResult;\n return null;\n };\n\n for await (const event of parseSSEStream<LogEvent>(stream)) {\n // Handle different event types\n if (event.type === 'stdout' || event.type === 'stderr') {\n const data = event.data || '';\n\n if (event.type === 'stdout') {\n collectedStdout += data;\n } else {\n collectedStderr += data;\n }\n pendingCheck = true;\n\n // Debounce pattern matching - check at most every 50ms\n const now = Date.now();\n if (now - lastCheckTime >= DEBOUNCE_MS) {\n lastCheckTime = now;\n pendingCheck = false;\n const result = checkPattern();\n if (result) return result;\n }\n }\n\n // Process exited - do final check before throwing\n if (event.type === 'exit') {\n if (pendingCheck) {\n const result = checkPattern();\n if (result) return result;\n }\n throw this.createExitedBeforeReadyError(\n processId,\n command,\n conditionStr,\n event.exitCode ?? 1\n );\n }\n }\n\n // Stream ended - do final check before throwing\n if (pendingCheck) {\n const result = checkPattern();\n if (result) return result;\n }\n // Stream ended without finding pattern - this indicates process exited\n throw this.createExitedBeforeReadyError(\n processId,\n command,\n conditionStr,\n 0\n );\n };\n\n // Race with timeout if specified, otherwise just run stream processor\n if (timeoutPromise) {\n return await Promise.race([streamProcessor(), timeoutPromise]);\n }\n return await streamProcessor();\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * Wait for a port to become available (for process readiness checking)\n */\n private async waitForPortReady(\n processId: string,\n command: string,\n port: number,\n options?: WaitForPortOptions\n ): Promise<void> {\n const {\n mode = 'http',\n path = '/',\n status = { min: 200, max: 399 },\n timeout,\n interval = 500\n } = options ?? {};\n\n const conditionStr =\n mode === 'http' ? `port ${port} (HTTP ${path})` : `port ${port} (TCP)`;\n\n // Normalize status to min/max\n const statusMin = typeof status === 'number' ? status : status.min;\n const statusMax = typeof status === 'number' ? status : status.max;\n\n // Open streaming watch - container handles internal polling\n const stream = await this.client.ports.watchPort({\n port,\n mode,\n path,\n statusMin,\n statusMax,\n processId,\n interval\n });\n\n // Set up timeout if specified\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutPromise: Promise<never> | undefined;\n\n if (timeout !== undefined) {\n timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n this.createReadyTimeoutError(\n processId,\n command,\n conditionStr,\n timeout\n )\n );\n }, timeout);\n });\n }\n\n try {\n const streamProcessor = async (): Promise<void> => {\n for await (const event of parseSSEStream<PortWatchEvent>(stream)) {\n switch (event.type) {\n case 'ready':\n return; // Success!\n case 'process_exited':\n throw this.createExitedBeforeReadyError(\n processId,\n command,\n conditionStr,\n event.exitCode ?? 1\n );\n case 'error':\n throw new Error(event.error || 'Port watch failed');\n // 'watching' - continue\n }\n }\n throw new Error('Port watch stream ended unexpectedly');\n };\n\n if (timeoutPromise) {\n await Promise.race([streamProcessor(), timeoutPromise]);\n } else {\n await streamProcessor();\n }\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n // Cancel the stream to stop container-side polling\n try {\n await stream.cancel();\n } catch {\n // Stream may already be closed\n }\n }\n }\n\n /**\n * Wait for a process to exit\n * Returns the exit code\n */\n private async waitForProcessExit(\n processId: string,\n command: string,\n timeout?: number\n ): Promise<WaitForExitResult> {\n const stream = await this.streamProcessLogs(processId);\n\n // Set up timeout if specified\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let timeoutPromise: Promise<never> | undefined;\n\n if (timeout !== undefined) {\n timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n this.createReadyTimeoutError(\n processId,\n command,\n 'process exit',\n timeout\n )\n );\n }, timeout);\n });\n }\n\n try {\n const streamProcessor = async (): Promise<WaitForExitResult> => {\n for await (const event of parseSSEStream<LogEvent>(stream)) {\n if (event.type === 'exit') {\n return {\n exitCode: event.exitCode ?? 1\n };\n }\n }\n\n // Stream ended without exit event - shouldn't happen, but handle gracefully\n throw new Error(\n `Process ${processId} stream ended unexpectedly without exit event`\n );\n };\n\n if (timeoutPromise) {\n return await Promise.race([streamProcessor(), timeoutPromise]);\n }\n return await streamProcessor();\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * Match a pattern against text\n */\n private matchPattern(\n text: string,\n pattern: string | RegExp\n ): WaitForLogResult | null {\n if (typeof pattern === 'string') {\n // Simple substring match\n if (text.includes(pattern)) {\n // Find the line containing the pattern\n const lines = text.split('\\n');\n for (const line of lines) {\n if (line.includes(pattern)) {\n return { line };\n }\n }\n return { line: pattern };\n }\n } else {\n const safePattern = new RegExp(\n pattern.source,\n pattern.flags.replace('g', '')\n );\n const match = text.match(safePattern);\n if (match) {\n // Find the full line containing the match\n const lines = text.split('\\n');\n for (const line of lines) {\n const lineMatch = line.match(safePattern);\n if (lineMatch) {\n return { line, match: lineMatch };\n }\n }\n return { line: match[0], match };\n }\n }\n return null;\n }\n\n /**\n * Convert a log pattern to a human-readable string\n */\n private conditionToString(pattern: string | RegExp): string {\n if (typeof pattern === 'string') {\n return `\"${pattern}\"`;\n }\n return pattern.toString();\n }\n\n /**\n * Create a ProcessReadyTimeoutError\n */\n private createReadyTimeoutError(\n processId: string,\n command: string,\n condition: string,\n timeout: number\n ): ProcessReadyTimeoutError {\n return new ProcessReadyTimeoutError({\n code: ErrorCode.PROCESS_READY_TIMEOUT,\n message: `Process did not become ready within ${timeout}ms. Waiting for: ${condition}`,\n context: {\n processId,\n command,\n condition,\n timeout\n },\n httpStatus: 408,\n timestamp: new Date().toISOString(),\n suggestion: `Check if your process outputs ${condition}. You can increase the timeout parameter.`\n });\n }\n\n /**\n * Create a ProcessExitedBeforeReadyError\n */\n private createExitedBeforeReadyError(\n processId: string,\n command: string,\n condition: string,\n exitCode: number\n ): ProcessExitedBeforeReadyError {\n return new ProcessExitedBeforeReadyError({\n code: ErrorCode.PROCESS_EXITED_BEFORE_READY,\n message: `Process exited with code ${exitCode} before becoming ready. Waiting for: ${condition}`,\n context: {\n processId,\n command,\n condition,\n exitCode\n },\n httpStatus: 500,\n timestamp: new Date().toISOString(),\n suggestion: 'Check process logs with getLogs() for error messages'\n });\n }\n\n // Background process management\n async startProcess(\n command: string,\n options?: ProcessOptions,\n sessionId?: string\n ): Promise<Process> {\n // Use the new HttpClient method to start the process\n try {\n const session = sessionId ?? (await this.ensureDefaultSession());\n const requestOptions = {\n ...(options?.processId !== undefined && {\n processId: options.processId\n }),\n ...(options?.timeout !== undefined && { timeoutMs: options.timeout }),\n ...(options?.env !== undefined && { env: options.env }),\n ...(options?.cwd !== undefined && { cwd: options.cwd }),\n ...(options?.encoding !== undefined && { encoding: options.encoding }),\n ...(options?.autoCleanup !== undefined && {\n autoCleanup: options.autoCleanup\n })\n };\n\n const response = await this.client.processes.startProcess(\n command,\n session,\n requestOptions\n );\n\n const processObj = this.createProcessFromDTO(\n {\n id: response.processId,\n pid: response.pid,\n command: response.command,\n status: 'running' as ProcessStatus,\n startTime: new Date(),\n endTime: undefined,\n exitCode: undefined\n },\n session\n );\n\n // Call onStart callback if provided\n if (options?.onStart) {\n options.onStart(processObj);\n }\n\n // Start background streaming if output/exit callbacks are provided\n if (options?.onOutput || options?.onExit) {\n // Fire and forget - don't await, let it run in background\n this.startProcessCallbackStream(response.processId, options).catch(\n () => {\n // Error already handled in startProcessCallbackStream\n }\n );\n }\n\n return processObj;\n } catch (error) {\n if (options?.onError && error instanceof Error) {\n options.onError(error);\n }\n\n throw error;\n }\n }\n\n /**\n * Start background streaming for process callbacks\n * Opens SSE stream to container and routes events to callbacks\n */\n private async startProcessCallbackStream(\n processId: string,\n options: ProcessOptions\n ): Promise<void> {\n try {\n const stream = await this.client.processes.streamProcessLogs(processId);\n\n for await (const event of parseSSEStream<{\n type: string;\n data?: string;\n exitCode?: number;\n processId?: string;\n }>(stream)) {\n switch (event.type) {\n case 'stdout':\n if (event.data && options.onOutput) {\n options.onOutput('stdout', event.data);\n }\n break;\n case 'stderr':\n if (event.data && options.onOutput) {\n options.onOutput('stderr', event.data);\n }\n break;\n case 'exit':\n case 'complete':\n if (options.onExit) {\n options.onExit(event.exitCode ?? null);\n }\n return; // Stream complete\n }\n }\n } catch (error) {\n // Call onError if streaming fails\n if (options.onError && error instanceof Error) {\n options.onError(error);\n }\n // Don't rethrow - background streaming failure shouldn't crash the caller\n this.logger.error(\n 'Background process streaming failed',\n error instanceof Error ? error : new Error(String(error)),\n { processId }\n );\n }\n }\n\n async listProcesses(sessionId?: string): Promise<Process[]> {\n const session = sessionId ?? (await this.ensureDefaultSession());\n const response = await this.client.processes.listProcesses();\n\n return response.processes.map((processData) =>\n this.createProcessFromDTO(\n {\n id: processData.id,\n pid: processData.pid,\n command: processData.command,\n status: processData.status,\n startTime: processData.startTime,\n endTime: processData.endTime,\n exitCode: processData.exitCode\n },\n session\n )\n );\n }\n\n async getProcess(id: string, sessionId?: string): Promise<Process | null> {\n const session = sessionId ?? (await this.ensureDefaultSession());\n const response = await this.client.processes.getProcess(id);\n if (!response.process) {\n return null;\n }\n\n const processData = response.process;\n return this.createProcessFromDTO(\n {\n id: processData.id,\n pid: processData.pid,\n command: processData.command,\n status: processData.status,\n startTime: processData.startTime,\n endTime: processData.endTime,\n exitCode: processData.exitCode\n },\n session\n );\n }\n\n async killProcess(\n id: string,\n signal?: string,\n sessionId?: string\n ): Promise<void> {\n // Note: signal parameter is not currently supported by the HTTP client\n await this.client.processes.killProcess(id);\n }\n\n async killAllProcesses(sessionId?: string): Promise<number> {\n const response = await this.client.processes.killAllProcesses();\n return response.cleanedCount;\n }\n\n async cleanupCompletedProcesses(sessionId?: string): Promise<number> {\n // Not yet implemented - requires container endpoint\n return 0;\n }\n\n async getProcessLogs(\n id: string,\n sessionId?: string\n ): Promise<{ stdout: string; stderr: string; processId: string }> {\n const response = await this.client.processes.getProcessLogs(id);\n return {\n stdout: response.stdout,\n stderr: response.stderr,\n processId: response.processId\n };\n }\n\n // Streaming methods - return ReadableStream for RPC compatibility\n async execStream(\n command: string,\n options?: StreamOptions\n ): Promise<ReadableStream<Uint8Array>> {\n // Check for cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n const session = await this.ensureDefaultSession();\n // Get the stream from CommandClient\n return this.client.commands.executeStream(command, session, {\n timeoutMs: options?.timeout,\n env: options?.env,\n cwd: options?.cwd\n });\n }\n\n /**\n * Internal session-aware execStream implementation\n */\n private async execStreamWithSession(\n command: string,\n sessionId: string,\n options?: StreamOptions\n ): Promise<ReadableStream<Uint8Array>> {\n // Check for cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n return this.client.commands.executeStream(command, sessionId, {\n timeoutMs: options?.timeout,\n env: options?.env,\n cwd: options?.cwd\n });\n }\n\n /**\n * Stream logs from a background process as a ReadableStream.\n */\n async streamProcessLogs(\n processId: string,\n options?: { signal?: AbortSignal }\n ): Promise<ReadableStream<Uint8Array>> {\n // Check for cancellation\n if (options?.signal?.aborted) {\n throw new Error('Operation was aborted');\n }\n\n return this.client.processes.streamProcessLogs(processId);\n }\n\n async gitCheckout(\n repoUrl: string,\n options?: { branch?: string; targetDir?: string; sessionId?: string }\n ) {\n const session = options?.sessionId ?? (await this.ensureDefaultSession());\n return this.client.git.checkout(repoUrl, session, {\n branch: options?.branch,\n targetDir: options?.targetDir\n });\n }\n\n async mkdir(\n path: string,\n options: { recursive?: boolean; sessionId?: string } = {}\n ) {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.mkdir(path, session, {\n recursive: options.recursive\n });\n }\n\n async writeFile(\n path: string,\n content: string,\n options: { encoding?: string; sessionId?: string } = {}\n ) {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.writeFile(path, content, session, {\n encoding: options.encoding\n });\n }\n\n async deleteFile(path: string, sessionId?: string) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.deleteFile(path, session);\n }\n\n async renameFile(oldPath: string, newPath: string, sessionId?: string) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.renameFile(oldPath, newPath, session);\n }\n\n async moveFile(\n sourcePath: string,\n destinationPath: string,\n sessionId?: string\n ) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.moveFile(sourcePath, destinationPath, session);\n }\n\n async readFile(\n path: string,\n options: { encoding?: string; sessionId?: string } = {}\n ) {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.readFile(path, session, {\n encoding: options.encoding\n });\n }\n\n /**\n * Stream a file from the sandbox using Server-Sent Events\n * Returns a ReadableStream that can be consumed with streamFile() or collectFile() utilities\n * @param path - Path to the file to stream\n * @param options - Optional session ID\n */\n async readFileStream(\n path: string,\n options: { sessionId?: string } = {}\n ): Promise<ReadableStream<Uint8Array>> {\n const session = options.sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.readFileStream(path, session);\n }\n\n async listFiles(\n path: string,\n options?: { recursive?: boolean; includeHidden?: boolean }\n ) {\n const session = await this.ensureDefaultSession();\n return this.client.files.listFiles(path, session, options);\n }\n\n async exists(path: string, sessionId?: string) {\n const session = sessionId ?? (await this.ensureDefaultSession());\n return this.client.files.exists(path, session);\n }\n\n async exposePort(port: number, options: { name?: string; hostname: string }) {\n // Check if hostname is workers.dev domain (doesn't support wildcard subdomains)\n if (options.hostname.endsWith('.workers.dev')) {\n const errorResponse: ErrorResponse = {\n code: ErrorCode.CUSTOM_DOMAIN_REQUIRED,\n message: `Port exposure requires a custom domain. .workers.dev domains do not support wildcard subdomains required for port proxying.`,\n context: { originalError: options.hostname },\n httpStatus: 400,\n timestamp: new Date().toISOString()\n };\n throw new CustomDomainRequiredError(errorResponse);\n }\n\n const sessionId = await this.ensureDefaultSession();\n await this.client.ports.exposePort(port, sessionId, 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 // Generate and store token for this port (storage is protected by input gates)\n const token = this.generatePortToken();\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n tokens[port.toString()] = token;\n await this.ctx.storage.put('portTokens', tokens);\n\n const url = this.constructPreviewUrl(\n port,\n this.sandboxName,\n options.hostname,\n token\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 throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n const sessionId = await this.ensureDefaultSession();\n await this.client.ports.unexposePort(port, sessionId);\n\n // Clean up token for this port (storage is protected by input gates)\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n if (tokens[port.toString()]) {\n delete tokens[port.toString()];\n await this.ctx.storage.put('portTokens', tokens);\n }\n }\n\n async getExposedPorts(hostname: string) {\n const sessionId = await this.ensureDefaultSession();\n const response = await this.client.ports.getExposedPorts(sessionId);\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 // Read all tokens from storage (protected by input gates)\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n\n return response.ports.map((port) => {\n const token = tokens[port.port.toString()];\n if (!token) {\n throw new Error(\n `Port ${port.port} is exposed but has no token. This should not happen.`\n );\n }\n\n return {\n url: this.constructPreviewUrl(\n port.port,\n this.sandboxName!,\n hostname,\n token\n ),\n port: port.port,\n status: port.status\n };\n });\n }\n\n async isPortExposed(port: number): Promise<boolean> {\n try {\n const sessionId = await this.ensureDefaultSession();\n const response = await this.client.ports.getExposedPorts(sessionId);\n return response.ports.some((exposedPort) => exposedPort.port === port);\n } catch (error) {\n this.logger.error(\n 'Error checking if port is exposed',\n error instanceof Error ? error : new Error(String(error)),\n { port }\n );\n return false;\n }\n }\n\n async validatePortToken(port: number, token: string): Promise<boolean> {\n // First check if port is exposed\n const isExposed = await this.isPortExposed(port);\n if (!isExposed) {\n return false;\n }\n\n // Read stored token from storage (protected by input gates)\n const tokens =\n (await this.ctx.storage.get<Record<string, string>>('portTokens')) || {};\n const storedToken = tokens[port.toString()];\n if (!storedToken) {\n // This should not happen - all exposed ports must have tokens\n this.logger.error(\n 'Port is exposed but has no token - bug detected',\n undefined,\n { port }\n );\n return false;\n }\n\n // Constant-time comparison to prevent timing attacks\n return storedToken === token;\n }\n\n private generatePortToken(): string {\n // Generate cryptographically secure 16-character token using Web Crypto API\n // Available in Cloudflare Workers runtime\n const array = new Uint8Array(12); // 12 bytes = 16 base64url chars (after padding removal)\n crypto.getRandomValues(array);\n\n // Convert to base64url format (URL-safe, no padding, lowercase)\n const base64 = btoa(String.fromCharCode(...array));\n return base64\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n .toLowerCase();\n }\n\n private constructPreviewUrl(\n port: number,\n sandboxId: string,\n hostname: string,\n token: string\n ): string {\n if (!validatePort(port)) {\n throw new SecurityError(\n `Invalid port number: ${port}. Must be between 1024-65535 and not reserved.`\n );\n }\n\n // Hostnames are case-insensitive, routing requests to wrong DO instance when keys contain uppercase letters\n const effectiveId = this.sandboxName || sandboxId;\n const hasUppercase = /[A-Z]/.test(effectiveId);\n if (!this.normalizeId && hasUppercase) {\n throw new SecurityError(\n `Preview URLs require lowercase sandbox IDs. Your ID \"${effectiveId}\" contains uppercase letters.\\n\\n` +\n `To fix this:\\n` +\n `1. Create a new sandbox with: getSandbox(ns, \"${effectiveId}\", { normalizeId: true })\\n` +\n `2. This will create a sandbox with ID: \"${effectiveId.toLowerCase()}\"\\n\\n` +\n `Note: Due to DNS case-insensitivity, IDs with uppercase letters cannot be used with preview URLs.`\n );\n }\n\n const sanitizedSandboxId = sanitizeSandboxId(sandboxId).toLowerCase();\n\n const isLocalhost = isLocalhostPattern(hostname);\n\n if (isLocalhost) {\n const [host, portStr] = hostname.split(':');\n const mainPort = portStr || '80';\n\n try {\n const baseUrl = new URL(`http://${host}:${mainPort}`);\n const subdomainHost = `${port}-${sanitizedSandboxId}-${token}.${host}`;\n baseUrl.hostname = subdomainHost;\n\n return baseUrl.toString();\n } catch (error) {\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n }\n }\n\n try {\n const baseUrl = new URL(`https://${hostname}`);\n const subdomainHost = `${port}-${sanitizedSandboxId}-${token}.${hostname}`;\n baseUrl.hostname = subdomainHost;\n\n return baseUrl.toString();\n } catch (error) {\n throw new SecurityError(\n `Failed to construct preview URL: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n }\n }\n\n // ============================================================================\n // Session Management - Advanced Use Cases\n // ============================================================================\n\n /**\n * Create isolated execution session for advanced use cases\n * Returns ExecutionSession with full sandbox API bound to specific session\n */\n async createSession(options?: SessionOptions): Promise<ExecutionSession> {\n const sessionId = options?.id || `session-${Date.now()}`;\n\n const mergedEnv = {\n ...this.envVars,\n ...(options?.env ?? {})\n };\n const envPayload =\n Object.keys(mergedEnv).length > 0 ? mergedEnv : undefined;\n\n // Create session in container\n await this.client.utils.createSession({\n id: sessionId,\n ...(envPayload && { env: envPayload }),\n ...(options?.cwd && { cwd: options.cwd })\n });\n\n // Return wrapper that binds sessionId to all operations\n return this.getSessionWrapper(sessionId);\n }\n\n /**\n * Get an existing session by ID\n * Returns ExecutionSession wrapper bound to the specified session\n *\n * This is useful for retrieving sessions across different requests/contexts\n * without storing the ExecutionSession object (which has RPC lifecycle limitations)\n *\n * @param sessionId - The ID of an existing session\n * @returns ExecutionSession wrapper bound to the session\n */\n async getSession(sessionId: string): Promise<ExecutionSession> {\n // No need to verify session exists in container - operations will fail naturally if it doesn't\n return this.getSessionWrapper(sessionId);\n }\n\n /**\n * Delete an execution session\n * Cleans up session resources and removes it from the container\n * Note: Cannot delete the default session. To reset the default session,\n * use sandbox.destroy() to terminate the entire sandbox.\n *\n * @param sessionId - The ID of the session to delete\n * @returns Result with success status, sessionId, and timestamp\n * @throws Error if attempting to delete the default session\n */\n async deleteSession(sessionId: string): Promise<SessionDeleteResult> {\n // Prevent deletion of default session\n if (this.defaultSession && sessionId === this.defaultSession) {\n throw new Error(\n `Cannot delete default session '${sessionId}'. Use sandbox.destroy() to terminate the sandbox.`\n );\n }\n\n const response = await this.client.utils.deleteSession(sessionId);\n\n // Map HTTP response to result type\n return {\n success: response.success,\n sessionId: response.sessionId,\n timestamp: response.timestamp\n };\n }\n\n /**\n * Internal helper to create ExecutionSession wrapper for a given sessionId\n * Used by both createSession and getSession\n */\n private getSessionWrapper(sessionId: string): ExecutionSession {\n return {\n id: sessionId,\n\n // Command execution - delegate to internal session-aware methods\n exec: (command, options) =>\n this.execWithSession(command, sessionId, options),\n execStream: (command, options) =>\n this.execStreamWithSession(command, sessionId, options),\n\n // Process management\n startProcess: (command, options) =>\n this.startProcess(command, options, sessionId),\n listProcesses: () => this.listProcesses(sessionId),\n getProcess: (id) => this.getProcess(id, sessionId),\n killProcess: (id, signal) => this.killProcess(id, signal),\n killAllProcesses: () => this.killAllProcesses(),\n cleanupCompletedProcesses: () => this.cleanupCompletedProcesses(),\n getProcessLogs: (id) => this.getProcessLogs(id),\n streamProcessLogs: (processId, options) =>\n this.streamProcessLogs(processId, options),\n\n // File operations - pass sessionId via options or parameter\n writeFile: (path, content, options) =>\n this.writeFile(path, content, { ...options, sessionId }),\n readFile: (path, options) =>\n this.readFile(path, { ...options, sessionId }),\n readFileStream: (path) => this.readFileStream(path, { sessionId }),\n mkdir: (path, options) => this.mkdir(path, { ...options, sessionId }),\n deleteFile: (path) => this.deleteFile(path, sessionId),\n renameFile: (oldPath, newPath) =>\n this.renameFile(oldPath, newPath, sessionId),\n moveFile: (sourcePath, destPath) =>\n this.moveFile(sourcePath, destPath, sessionId),\n listFiles: (path, options) =>\n this.client.files.listFiles(path, sessionId, options),\n exists: (path) => this.exists(path, sessionId),\n\n // Git operations\n gitCheckout: (repoUrl, options) =>\n this.gitCheckout(repoUrl, { ...options, sessionId }),\n\n // Environment management - needs special handling\n setEnvVars: async (envVars: Record<string, string>) => {\n try {\n // Set environment variables by executing export commands\n for (const [key, value] of Object.entries(envVars)) {\n const escapedValue = value.replace(/'/g, \"'\\\\''\");\n const exportCommand = `export ${key}='${escapedValue}'`;\n\n const result = await this.client.commands.execute(\n exportCommand,\n sessionId\n );\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to set ${key}: ${result.stderr || 'Unknown error'}`\n );\n }\n }\n } catch (error) {\n this.logger.error(\n 'Failed to set environment variables',\n error instanceof Error ? error : new Error(String(error)),\n { sessionId }\n );\n throw error;\n }\n },\n\n // Code interpreter methods - delegate to sandbox's code interpreter\n createCodeContext: (options) =>\n this.codeInterpreter.createCodeContext(options),\n runCode: async (code, options) => {\n const execution = await this.codeInterpreter.runCode(code, options);\n return execution.toJSON();\n },\n runCodeStream: (code, options) =>\n this.codeInterpreter.runCodeStream(code, options),\n listCodeContexts: () => this.codeInterpreter.listCodeContexts(),\n deleteCodeContext: (contextId) =>\n this.codeInterpreter.deleteCodeContext(contextId),\n\n // Bucket mounting - sandbox-level operations\n mountBucket: (bucket, mountPath, options) =>\n this.mountBucket(bucket, mountPath, options),\n unmountBucket: (mountPath) => this.unmountBucket(mountPath)\n };\n }\n\n // ============================================================================\n // Code interpreter methods - delegate to CodeInterpreter wrapper\n // ============================================================================\n\n async createCodeContext(\n options?: CreateContextOptions\n ): Promise<CodeContext> {\n return this.codeInterpreter.createCodeContext(options);\n }\n\n async runCode(\n code: string,\n options?: RunCodeOptions\n ): Promise<ExecutionResult> {\n const execution = await this.codeInterpreter.runCode(code, options);\n return execution.toJSON();\n }\n\n async runCodeStream(\n code: string,\n options?: RunCodeOptions\n ): Promise<ReadableStream> {\n return this.codeInterpreter.runCodeStream(code, options);\n }\n\n async listCodeContexts(): Promise<CodeContext[]> {\n return this.codeInterpreter.listCodeContexts();\n }\n\n async deleteCodeContext(contextId: string): Promise<void> {\n return this.codeInterpreter.deleteCodeContext(contextId);\n }\n}\n","import type { FileChunk, FileMetadata, FileStreamEvent } from '@repo/shared';\n\n/**\n * Parse SSE (Server-Sent Events) lines from a stream\n */\nasync function* parseSSE(\n stream: ReadableStream<Uint8Array>\n): AsyncGenerator<FileStreamEvent> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n\n // Keep the last incomplete line in the buffer\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6); // Remove 'data: ' prefix\n try {\n const event = JSON.parse(data) as FileStreamEvent;\n yield event;\n } catch {\n // Skip invalid JSON events and continue processing\n }\n }\n }\n }\n } finally {\n // Cancel the stream first to properly terminate HTTP connections when breaking early\n try {\n await reader.cancel();\n } catch {\n // Ignore cancel errors (stream may already be closed)\n }\n reader.releaseLock();\n }\n}\n\n/**\n * Stream a file from the sandbox with automatic base64 decoding for binary files\n *\n * @param stream - The ReadableStream from readFileStream()\n * @returns AsyncGenerator that yields FileChunk (string for text, Uint8Array for binary)\n *\n * @example\n * ```ts\n * const stream = await sandbox.readFileStream('/path/to/file.png');\n * for await (const chunk of streamFile(stream)) {\n * if (chunk instanceof Uint8Array) {\n * // Binary chunk\n * console.log('Binary chunk:', chunk.length, 'bytes');\n * } else {\n * // Text chunk\n * console.log('Text chunk:', chunk);\n * }\n * }\n * ```\n */\nexport async function* streamFile(\n stream: ReadableStream<Uint8Array>\n): AsyncGenerator<FileChunk, FileMetadata> {\n let metadata: FileMetadata | null = null;\n\n for await (const event of parseSSE(stream)) {\n switch (event.type) {\n case 'metadata':\n metadata = {\n mimeType: event.mimeType,\n size: event.size,\n isBinary: event.isBinary,\n encoding: event.encoding\n };\n break;\n\n case 'chunk':\n if (!metadata) {\n throw new Error('Received chunk before metadata');\n }\n\n if (metadata.isBinary && metadata.encoding === 'base64') {\n // Decode base64 to Uint8Array for binary files\n const binaryString = atob(event.data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n yield bytes;\n } else {\n // Text files - yield as-is\n yield event.data;\n }\n break;\n\n case 'complete':\n if (!metadata) {\n throw new Error('Stream completed without metadata');\n }\n return metadata;\n\n case 'error':\n throw new Error(`File streaming error: ${event.error}`);\n }\n }\n\n throw new Error('Stream ended unexpectedly');\n}\n\n/**\n * Collect an entire file into memory from a stream\n *\n * @param stream - The ReadableStream from readFileStream()\n * @returns Object containing the file content and metadata\n *\n * @example\n * ```ts\n * const stream = await sandbox.readFileStream('/path/to/file.txt');\n * const { content, metadata } = await collectFile(stream);\n * console.log('Content:', content);\n * console.log('MIME type:', metadata.mimeType);\n * ```\n */\nexport async function collectFile(stream: ReadableStream<Uint8Array>): Promise<{\n content: string | Uint8Array;\n metadata: FileMetadata;\n}> {\n const chunks: Array<string | Uint8Array> = [];\n\n // Iterate through the generator and get the return value (metadata)\n const generator = streamFile(stream);\n let result = await generator.next();\n\n while (!result.done) {\n chunks.push(result.value);\n result = await generator.next();\n }\n\n const metadata = result.value;\n\n if (!metadata) {\n throw new Error('Failed to get file metadata');\n }\n\n // Combine chunks based on type\n if (metadata.isBinary) {\n // Binary file - combine Uint8Arrays\n const totalLength = chunks.reduce(\n (sum, chunk) => sum + (chunk instanceof Uint8Array ? chunk.length : 0),\n 0\n );\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n if (chunk instanceof Uint8Array) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n }\n return { content: combined, metadata };\n } else {\n // Text file - combine strings\n const combined = chunks.filter((c) => typeof c === 'string').join('');\n return { content: combined, metadata };\n }\n}\n"],"mappings":"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"}
|