@cloudflare/sandbox 0.13.0-next.681.1 → 0.13.0-next.709.1
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/Dockerfile +6 -6
- package/README.md +49 -3
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +1364 -1072
- package/dist/bridge/index.js.map +1 -1
- package/dist/{contexts-DY1LHU1v.d.ts → contexts-1EsLHByO.d.ts} +156 -20
- package/dist/contexts-1EsLHByO.d.ts.map +1 -0
- package/dist/{dist-BStBkGIC.js → dist-Duor5GbS.js} +7 -56
- package/dist/dist-Duor5GbS.js.map +1 -0
- package/dist/errors/index.d.ts +4 -4
- package/dist/errors/index.js +3 -3
- package/dist/{errors-k3B8orjH.js → errors-CXR0xBpw.js} +42 -10
- package/dist/errors-CXR0xBpw.js.map +1 -0
- package/dist/{errors-ewgSNicb.js → errors-QYlSkVGz.js} +402 -250
- package/dist/errors-QYlSkVGz.js.map +1 -0
- package/dist/extensions/index.d.ts +4 -2
- package/dist/extensions/index.js +5 -3
- package/dist/extensions-CFB2xHqY.js +1023 -0
- package/dist/extensions-CFB2xHqY.js.map +1 -0
- package/dist/filesystem-BWAZCZER.d.ts +732 -0
- package/dist/filesystem-BWAZCZER.d.ts.map +1 -0
- package/dist/git/index.d.ts +8 -19
- package/dist/git/index.d.ts.map +1 -1
- package/dist/git/index.js +16 -23
- package/dist/git/index.js.map +1 -1
- package/dist/index-Bs4bqXDR.d.ts +438 -0
- package/dist/index-Bs4bqXDR.d.ts.map +1 -0
- package/dist/{index-Dy6u9r60.d.ts → index-HNYBk-az.d.ts} +233 -179
- package/dist/index-HNYBk-az.d.ts.map +1 -0
- package/dist/index.d.ts +480 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/interpreter/index.d.ts +3 -1
- package/dist/interpreter/index.d.ts.map +1 -1
- package/dist/interpreter/index.js +46 -18
- package/dist/interpreter/index.js.map +1 -1
- package/dist/openai/index.d.ts +5 -5
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +11 -6
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +7 -11
- package/dist/opencode/index.d.ts.map +1 -1
- package/dist/opencode/index.js +56 -85
- package/dist/opencode/index.js.map +1 -1
- package/dist/process-types-GStiZ8f8.d.ts +73 -0
- package/dist/process-types-GStiZ8f8.d.ts.map +1 -0
- package/dist/{sandbox-boKWPIcd.js → sandbox-Auuwfnur.js} +4152 -3359
- package/dist/sandbox-Auuwfnur.js.map +1 -0
- package/dist/sandbox-BbAabq93.d.ts +42 -0
- package/dist/sandbox-BbAabq93.d.ts.map +1 -0
- package/dist/xterm/index.d.ts +5 -1
- package/dist/xterm/index.d.ts.map +1 -1
- package/dist/xterm/index.js +55 -12
- package/dist/xterm/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/codes-y-U76vnQ.d.ts +0 -79
- package/dist/codes-y-U76vnQ.d.ts.map +0 -1
- package/dist/contexts-DY1LHU1v.d.ts.map +0 -1
- package/dist/dist-BStBkGIC.js.map +0 -1
- package/dist/errors-ewgSNicb.js.map +0 -1
- package/dist/errors-k3B8orjH.js.map +0 -1
- package/dist/extensions-CepYdzro.js +0 -191
- package/dist/extensions-CepYdzro.js.map +0 -1
- package/dist/index-B7QgIs0N.d.ts +0 -1841
- package/dist/index-B7QgIs0N.d.ts.map +0 -1
- package/dist/index-Dy6u9r60.d.ts.map +0 -1
- package/dist/sandbox-DHNO89IF.d.ts +0 -828
- package/dist/sandbox-DHNO89IF.d.ts.map +0 -1
- package/dist/sandbox-boKWPIcd.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-BWAZCZER.d.ts","names":["ProcessExit","ProcessLogCursor","ProcessLogEvent","ProcessStatus","WaitForLogResult","Disposable","ExecOptions","Record","ProcessLogsOptions","AbortSignal","WaitForExitOptions","WaitForLogOptions","ProcessOutput","T","ProcessOutputOptions","ProcessTextOutputOptions","SandboxProcess","Promise","ReadableStream","RegExp","Uint8Array","WaitForPortOptions","PortCheckRequest","PortCheckResponse","PortWatchRequest","PortWatchEvent","PortWatchRPCOptions","PortWatchSubscriptionAPI","SandboxOptions","ProcessExit","ProcessFailure","SandboxCommand","WaitForExitOptions","CreateTerminalOptions","Record","TerminalSnapshot","TerminalOutputCursor","TerminalOutputOptions","AbortSignal","TerminalOutputEvent","Uint8Array","TerminalOutputSubscriptionAPI","ReadableStream","Promise","Terminal","Request","Response","SandboxTerminalsAPI","Omit","PtyClientControlMessage","PtyServerControlMessage","BackupCompressionOptions","BackupOptions","DirectoryBackup","RestoreBackupResult","BucketProvider","BucketCredentials","RemoteMountBucketOptions","LocalMountBucketOptions","R2BindingMountBucketOptions","MountBucketOptions","MkdirResult","WriteFileResult","FileEncoding","ReadFileResult","ReadFileStreamResult","Uint8Array","ReadableStream","DeleteFileResult","RenameFileResult","MoveFileResult","FileExistsResult","FileInfo","ListFilesOptions","ListFilesResult","FileStreamEvent","FileMetadata","FileChunk","WatchOptions","CheckChangesOptions","FileWatchEventType","WatchRequest","CheckChangesRequest","FileWatchSSEEvent","CheckChangesResult","EnvSetResult","PortExposeResult","HealthCheckResult","ShutdownResult"],"sources":["../../shared/dist/types/core.d.ts","../../shared/dist/pty-types.d.ts","../../shared/dist/types/backup-mounts.d.ts","../../shared/dist/types/filesystem.d.ts"],"sourcesContent":["import type { ProcessExit, ProcessLogCursor, ProcessLogEvent, ProcessStatus, WaitForLogResult } from '../process-types.js';\n/**\n * Represents a disposable resource with a cleanup function.\n * Common pattern used by VS Code, xterm.js, RxJS, and others.\n */\nexport interface Disposable {\n dispose(): void;\n}\nexport interface ExecOptions {\n cwd?: string;\n env?: Record<string, string>;\n timeout?: number;\n}\nexport interface ProcessLogsOptions {\n since?: ProcessLogCursor;\n replay?: boolean;\n follow?: boolean;\n signal?: AbortSignal;\n}\nexport interface WaitForExitOptions {\n timeout?: number;\n signal?: AbortSignal;\n}\nexport interface WaitForLogOptions extends WaitForExitOptions {\n stream?: 'stdout' | 'stderr' | 'both';\n}\nexport interface ProcessOutput<T> {\n stdout: T;\n stderr: T;\n exitCode: number;\n signal?: number;\n timedOut: boolean;\n truncated: boolean;\n}\nexport interface ProcessOutputOptions extends WaitForExitOptions {\n maxBytes?: number;\n}\nexport interface ProcessTextOutputOptions extends ProcessOutputOptions {\n encoding: 'utf8';\n}\nexport interface SandboxProcess {\n readonly id: string;\n readonly pid: number;\n readonly exitCode: Promise<number>;\n status(): Promise<ProcessStatus>;\n logs(options?: ProcessLogsOptions): Promise<ReadableStream<ProcessLogEvent>>;\n waitForLog(pattern: string | RegExp, options?: WaitForLogOptions): Promise<WaitForLogResult>;\n waitForExit(options?: WaitForExitOptions): Promise<ProcessExit>;\n output(options: ProcessTextOutputOptions): Promise<ProcessOutput<string>>;\n output(options?: ProcessOutputOptions): Promise<ProcessOutput<Uint8Array>>;\n waitForPort(port: number, options?: WaitForPortOptions): Promise<void>;\n kill(signal?: number): Promise<void>;\n}\n/**\n * Options for waiting for a port to become ready\n */\nexport interface WaitForPortOptions {\n /**\n * Check mode\n * - 'http': Make an HTTP request and check for success status\n * - 'tcp': Just check if TCP connection succeeds (default)\n * @default 'tcp'\n */\n mode?: 'http' | 'tcp';\n /**\n * HTTP path to check (only used when mode is 'http')\n * @default '/'\n */\n path?: string;\n /**\n * Expected HTTP status code or range (only used when mode is 'http')\n * - Single number: exact match (e.g., 200)\n * - Object with min/max: range match (e.g., { min: 200, max: 399 })\n * @default { min: 200, max: 399 }\n */\n status?: number | {\n min: number;\n max: number;\n };\n /**\n * Maximum time to wait in milliseconds\n * @default no timeout\n */\n timeout?: number;\n /**\n * Signal used to cancel waiting locally.\n */\n signal?: AbortSignal;\n /**\n * Interval between checks in milliseconds\n * @default 500\n */\n interval?: number;\n}\n/**\n * Request body for port readiness check endpoint\n */\nexport interface PortCheckRequest {\n port: number;\n mode: 'http' | 'tcp';\n path?: string;\n statusMin?: number;\n statusMax?: number;\n}\n/**\n * Response from port readiness check endpoint\n */\nexport interface PortCheckResponse {\n ready: boolean;\n /** HTTP status code received (only for http mode) */\n statusCode?: number;\n /** Error message if check failed */\n error?: string;\n}\n/**\n * Request body for streaming port watch endpoint\n */\nexport interface PortWatchRequest extends PortCheckRequest {\n /** Process ID to monitor - stream closes if process exits */\n processId?: string;\n /** Internal polling interval in ms (default: 500) */\n interval?: number;\n}\n/**\n * SSE event emitted by port watch stream\n */\nexport type PortWatchEvent = {\n type: 'watching';\n port: number;\n} | {\n type: 'ready';\n port: number;\n statusCode?: number;\n} | {\n type: 'error';\n port: number;\n error: string;\n};\nexport interface PortWatchRPCOptions {\n mode?: 'http' | 'tcp';\n path?: string;\n status?: number | {\n min: number;\n max: number;\n };\n interval?: number;\n}\nexport interface PortWatchSubscriptionAPI {\n stream(): Promise<ReadableStream<PortWatchEvent>>;\n cancel(): Promise<void>;\n [Symbol.dispose](): void;\n}\nexport interface SandboxOptions {\n /**\n * Duration after which the sandbox instance will sleep if no requests are received\n * Can be:\n * - A string like \"30s\", \"3m\", \"5m\", \"1h\" (seconds, minutes, or hours)\n * - A number representing seconds (e.g., 180 for 3 minutes)\n * Default: \"10m\" (10 minutes)\n *\n * Note: Ignored when keepAlive is true\n */\n sleepAfter?: string | number;\n /**\n * Keep the container alive indefinitely by preventing automatic shutdown\n * When true, the container will never auto-timeout and must be explicitly destroyed\n * - Any scenario where activity can't be automatically detected\n *\n * Important: You MUST call sandbox.destroy() when done to avoid resource leaks\n *\n * Default: false\n */\n keepAlive?: boolean;\n /**\n * Normalize sandbox ID to lowercase for preview URL compatibility\n *\n * Required for preview URLs because hostnames are case-insensitive (RFC 3986), which\n * would route requests to a different Durable Object instance with IDs containing uppercase letters.\n *\n * **Important:** Different normalizeId values create different Durable Object instances:\n * - `getSandbox(ns, \"MyProject\")` → DO key: \"MyProject\"\n * - `getSandbox(ns, \"MyProject\", {normalizeId: true})` → DO key: \"myproject\"\n *\n * **Future change:** In a future version, this will default to `true` (automatically lowercase all IDs).\n * IDs with uppercase letters will trigger a warning. To prepare, use lowercase IDs or explicitly\n * pass `normalizeId: true`.\n *\n * @example\n * getSandbox(ns, \"my-project\") // Works with preview URLs (lowercase)\n * getSandbox(ns, \"MyProject\", {normalizeId: true}) // Normalized to \"myproject\"\n *\n * @default false\n */\n normalizeId?: boolean;\n /**\n * Container startup timeout configuration\n *\n * Tune timeouts based on your container's characteristics. SDK defaults (30s instance, 90s ports)\n * work for most use cases. Adjust for heavy containers or fail-fast applications.\n *\n * Can also be configured via environment variables:\n * - SANDBOX_INSTANCE_TIMEOUT_MS\n * - SANDBOX_PORT_TIMEOUT_MS\n * - SANDBOX_POLL_INTERVAL_MS\n *\n * Precedence: options > env vars > SDK defaults\n *\n * @example\n * // Heavy containers (ML models, large apps)\n * getSandbox(ns, id, {\n * containerTimeouts: { portReadyTimeoutMS: 180_000 }\n * })\n *\n * @example\n * // Fail-fast for latency-sensitive apps\n * getSandbox(ns, id, {\n * containerTimeouts: {\n * instanceGetTimeoutMS: 15_000,\n * portReadyTimeoutMS: 30_000\n * }\n * })\n */\n containerTimeouts?: {\n /**\n * Time to wait for container instance provisioning\n * @default 30000 (30s) - or SANDBOX_INSTANCE_TIMEOUT_MS env var\n */\n instanceGetTimeoutMS?: number;\n /**\n * Time to wait for application startup and ports to be ready\n * @default 90000 (90s) - or SANDBOX_PORT_TIMEOUT_MS env var\n */\n portReadyTimeoutMS?: number;\n /**\n * How often to poll for container readiness\n * @default 300 (300ms) - or SANDBOX_POLL_INTERVAL_MS env var\n */\n waitIntervalMS?: number;\n };\n}\n//# sourceMappingURL=core.d.ts.map","import type { ProcessExit, ProcessFailure, SandboxCommand } from './process-types.js';\nimport type { WaitForExitOptions } from './types/core.js';\nexport interface CreateTerminalOptions {\n command: SandboxCommand;\n cwd?: string;\n env?: Record<string, string>;\n cols?: number;\n rows?: number;\n bufferSize?: number;\n}\nexport interface TerminalSnapshot {\n id: string;\n pid?: number;\n command: SandboxCommand;\n cwd?: string;\n status: 'running' | 'exited' | 'error';\n exit?: ProcessExit;\n error?: ProcessFailure;\n}\nexport type TerminalOutputCursor = string;\nexport interface TerminalOutputOptions {\n since?: TerminalOutputCursor;\n replay?: boolean;\n follow?: boolean;\n signal?: AbortSignal;\n}\nexport type TerminalOutputEvent = {\n type: 'data';\n terminalId: string;\n cursor: TerminalOutputCursor;\n timestamp: string;\n data: Uint8Array;\n} | {\n type: 'terminal';\n terminalId: string;\n cursor: TerminalOutputCursor;\n timestamp: string;\n state: 'exited';\n exit: ProcessExit;\n} | {\n type: 'terminal';\n terminalId: string;\n cursor: TerminalOutputCursor;\n timestamp: string;\n state: 'error';\n error: ProcessFailure;\n} | {\n type: 'truncated';\n terminalId: string;\n cursor?: TerminalOutputCursor;\n timestamp: string;\n};\nexport interface TerminalOutputSubscriptionAPI {\n stream(): Promise<ReadableStream<TerminalOutputEvent>>;\n cancel(): Promise<void>;\n [Symbol.dispose](): void;\n}\nexport interface Terminal {\n readonly id: string;\n getSnapshot(): Promise<TerminalSnapshot>;\n write(data: Uint8Array): Promise<void>;\n resize(cols: number, rows: number): Promise<void>;\n output(options?: TerminalOutputOptions): Promise<ReadableStream<TerminalOutputEvent>>;\n waitForExit(options?: WaitForExitOptions): Promise<ProcessExit>;\n interrupt(): Promise<void>;\n terminate(): Promise<void>;\n connect(request: Request, options?: {\n cursor?: TerminalOutputCursor;\n cols?: number;\n rows?: number;\n }): Promise<Response>;\n}\nexport interface SandboxTerminalsAPI {\n create(options: CreateTerminalOptions): Promise<TerminalSnapshot>;\n get(id: string): Promise<TerminalSnapshot | null>;\n list(): Promise<TerminalSnapshot[]>;\n output(id: string, options?: Omit<TerminalOutputOptions, 'signal'>): Promise<TerminalOutputSubscriptionAPI>;\n write(id: string, data: Uint8Array): Promise<void>;\n resize(id: string, cols: number, rows: number): Promise<void>;\n interrupt(id: string): Promise<void>;\n terminate(id: string): Promise<void>;\n hasActive(): Promise<boolean>;\n}\nexport type PtyClientControlMessage = {\n type: 'resize';\n cols: number;\n rows: number;\n} | {\n type: 'interrupt';\n} | {\n type: 'terminate';\n};\nexport type PtyServerControlMessage = {\n type: 'ready';\n cursor?: TerminalOutputCursor;\n} | {\n type: 'chunk';\n cursor: TerminalOutputCursor;\n byteLength: number;\n} | {\n type: 'truncated';\n cursor?: TerminalOutputCursor;\n} | {\n type: 'exit';\n cursor: TerminalOutputCursor;\n exit: ProcessExit;\n} | {\n type: 'error';\n cursor?: TerminalOutputCursor;\n code?: string;\n message: string;\n};\n//# sourceMappingURL=pty-types.d.ts.map","/**\n * Options for creating a directory backup\n */\nexport interface BackupCompressionOptions {\n format?: 'gzip' | 'lz4' | 'zstd';\n threads?: number;\n}\nexport interface BackupOptions {\n /** Directory to back up. Must be absolute and under `/workspace`, `/home`, `/tmp`, `/var/tmp`, or `/app`. */\n dir: string;\n /** Human-readable name for this backup. Optional. */\n name?: string;\n /** Seconds until automatic garbage collection. Default: 259200 (3 days). No upper limit. */\n ttl?: number;\n /**\n * Respect git ignore rules for the backup directory when it is inside a git repository.\n *\n * Default: false.\n * If the directory is not inside a git repository, no git-based exclusions are applied.\n * If git is not installed in the container, a warning is logged and gitignore rules are skipped.\n */\n gitignore?: boolean;\n /**\n * Glob patterns to exclude from the backup.\n * These are passed directly to mksquashfs as wildcard exclude patterns.\n *\n * @example ['node_modules', '*.log', '.cache']\n */\n excludes?: string[];\n /**\n * Use local R2 binding for backup storage instead of presigned URLs.\n * Required for local development where presigned URLs and FUSE are unavailable.\n * When true, the DO resolves BACKUP_BUCKET from its own env as an R2 binding.\n */\n localBucket?: boolean;\n compression?: BackupCompressionOptions;\n /**\n * Use parallel multipart upload to R2 for large archives.\n * Significantly speeds up uploads for archives over 10 MiB.\n * Default: true.\n */\n multipart?: boolean;\n}\n/**\n * Handle representing a stored directory backup.\n * Serializable metadata returned by createBackup().\n * Store it anywhere and later pass it to restoreBackup().\n */\nexport interface DirectoryBackup {\n /** Unique backup identifier */\n readonly id: string;\n /** Directory to restore into. Must be under `/workspace`, `/home`, `/tmp`, `/var/tmp`, or `/app`. */\n readonly dir: string;\n /** Whether this backup was created with local R2 binding mode. */\n readonly localBucket?: boolean;\n}\n/**\n * Result returned from a successful restoreBackup() call\n */\nexport interface RestoreBackupResult {\n success: boolean;\n /** The directory that was restored */\n dir: string;\n /** Backup ID that was restored */\n id: string;\n}\n/**\n * Supported S3-compatible storage providers\n */\nexport type BucketProvider = 'r2' | 's3' | 'gcs';\n/**\n * Credentials for S3-compatible storage\n */\nexport interface BucketCredentials {\n accessKeyId: string;\n secretAccessKey: string;\n}\n/**\n * Options for mounting an S3-compatible bucket via s3fs-FUSE (production)\n */\nexport interface RemoteMountBucketOptions {\n /**\n * S3-compatible endpoint URL\n *\n * Examples:\n * - R2: 'https://abc123.r2.cloudflarestorage.com'\n * - AWS S3: 'https://s3.us-west-2.amazonaws.com'\n * - GCS: 'https://storage.googleapis.com'\n */\n endpoint: string;\n /**\n * Optional provider hint for automatic s3fs flag configuration\n * If not specified, will attempt to detect from endpoint URL.\n *\n * Examples:\n * - 'r2' - Cloudflare R2 (adds nomixupload)\n * - 's3' - Amazon S3 (standard configuration)\n * - 'gcs' - Google Cloud Storage (no special flags needed)\n */\n provider?: BucketProvider;\n /**\n * Explicit credentials (overrides env var auto-detection)\n */\n credentials?: BucketCredentials;\n /**\n * Mount filesystem as read-only\n * Default: false\n */\n readOnly?: boolean;\n /**\n * Advanced: Override or extend s3fs options\n *\n * These will be merged with provider-specific defaults.\n * To override defaults completely, specify all options here.\n *\n * Common options:\n * - 'use_path_request_style' - Use path-style URLs (bucket/path vs bucket.host/path)\n * - 'nomixupload' - Disable mixed multipart uploads (needed for some providers)\n * - 'nomultipart' - Disable all multipart operations\n * - 'sigv2' - Use signature version 2 instead of v4\n * - 'no_check_certificate' - Skip SSL certificate validation (dev/testing only)\n */\n s3fsOptions?: string[];\n /**\n * Optional prefix/subdirectory within the bucket to mount.\n *\n * When specified, only the contents under this prefix are visible at the\n * mount point, scoping the mount to a subdirectory of the bucket.\n *\n * Must start with '/' (e.g., '/workspaces/project123' or '/data/uploads/')\n */\n prefix?: string;\n /**\n * Keep real credentials in the Durable Object; write dummy credentials into\n * the container-side s3fs password file. Outbound s3fs requests are\n * intercepted by the DO, signed with real credentials, and forwarded to the\n * configured endpoint.\n *\n * Default: false (real credentials are written into the container)\n */\n credentialProxy?: boolean;\n}\n/**\n * Options for mounting a local R2 binding via bidirectional sync (local dev)\n *\n * Used during local development with `wrangler dev`. The Durable Object\n * resolves the R2 binding from its own env using the `bucket` parameter\n * and syncs files via polling instead of s3fs-FUSE.\n */\nexport interface LocalMountBucketOptions {\n /**\n * Must be true to indicate local R2 binding mode.\n */\n localBucket: true;\n /**\n * Optional prefix/subdirectory within the bucket to sync.\n *\n * When specified, only the contents under this prefix will be visible\n * at the mount point.\n */\n prefix?: string;\n /**\n * Mount filesystem as read-only\n * Default: false\n */\n readOnly?: boolean;\n}\n/**\n * Options for mounting an R2 binding via credential-less egress interception.\n */\nexport interface R2BindingMountBucketOptions {\n /**\n * Must not be set — distinguishes this variant from RemoteMountBucketOptions.\n */\n endpoint?: never;\n /**\n * Optional prefix/subdirectory within the bucket to mount.\n *\n * When specified, only the contents under this prefix will be visible\n * at the mount point.\n */\n prefix?: string;\n /**\n * Mount filesystem as read-only\n * Default: false\n */\n readOnly?: boolean;\n /**\n * Advanced: Override or extend s3fs options.\n * Provider defaults for R2 are still applied automatically.\n */\n s3fsOptions?: string[];\n}\n/**\n * Options for mounting a bucket — remote (s3fs-FUSE), local (R2 binding sync),\n * or R2 egress (credential-less s3fs via egress interception).\n */\nexport type MountBucketOptions = RemoteMountBucketOptions | LocalMountBucketOptions | R2BindingMountBucketOptions;\n//# sourceMappingURL=backup-mounts.d.ts.map","export interface MkdirResult {\n success: boolean;\n path: string;\n recursive: boolean;\n timestamp: string;\n exitCode?: number;\n}\nexport interface WriteFileResult {\n success: boolean;\n path: string;\n timestamp: string;\n exitCode?: number;\n}\n/**\n * Valid `encoding` values accepted by `readFile` / `writeFile` options.\n *\n * - `'utf-8'` / `'utf8'` — treat content as text.\n * - `'base64'` — treat content as base64-encoded binary.\n * - `'none'` — streaming variant of `readFile`, returns a\n * `ReadableStream<Uint8Array>` of raw bytes (see `ReadFileStreamResult`).\n */\nexport type FileEncoding = 'utf-8' | 'utf8' | 'base64' | 'none';\nexport interface ReadFileResult {\n success: boolean;\n path: string;\n content: string;\n timestamp: string;\n exitCode?: number;\n /**\n * Encoding used for content (utf-8 for text, base64 for binary)\n */\n encoding?: 'utf-8' | 'base64';\n /**\n * Whether the file is detected as binary\n */\n isBinary?: boolean;\n /**\n * MIME type of the file (e.g., 'image/png', 'text/plain')\n */\n mimeType?: string;\n /**\n * File size in bytes\n */\n size?: number;\n}\n/**\n * Result of `readFile()` with `encoding: 'none'`.\n *\n * `content` is a raw binary `ReadableStream<Uint8Array>` delivered directly\n * over the capnp channel — no base64 encoding, no SSE framing, no buffering.\n */\nexport interface ReadFileStreamResult {\n success: true;\n path: string;\n content: ReadableStream<Uint8Array>;\n size: number;\n mimeType: string;\n timestamp: string;\n}\nexport interface DeleteFileResult {\n success: boolean;\n path: string;\n timestamp: string;\n exitCode?: number;\n}\nexport interface RenameFileResult {\n success: boolean;\n path: string;\n newPath: string;\n timestamp: string;\n exitCode?: number;\n}\nexport interface MoveFileResult {\n success: boolean;\n path: string;\n newPath: string;\n timestamp: string;\n exitCode?: number;\n}\nexport interface FileExistsResult {\n success: boolean;\n path: string;\n exists: boolean;\n timestamp: string;\n}\nexport interface FileInfo {\n name: string;\n absolutePath: string;\n relativePath: string;\n type: 'file' | 'directory' | 'symlink' | 'other';\n size: number;\n modifiedAt: string;\n mode: string;\n permissions: {\n readable: boolean;\n writable: boolean;\n executable: boolean;\n };\n}\nexport interface ListFilesOptions {\n recursive?: boolean;\n includeHidden?: boolean;\n}\nexport interface ListFilesResult {\n success: boolean;\n path: string;\n files: FileInfo[];\n count: number;\n timestamp: string;\n exitCode?: number;\n}\n/**\n * SSE events for file streaming\n */\nexport type FileStreamEvent = {\n type: 'metadata';\n mimeType: string;\n size: number;\n isBinary: boolean;\n encoding: 'utf-8' | 'base64';\n} | {\n type: 'chunk';\n data: string;\n} | {\n type: 'complete';\n bytesRead: number;\n} | {\n type: 'error';\n error: string;\n};\n/**\n * File metadata from streaming\n */\nexport interface FileMetadata {\n mimeType: string;\n size: number;\n isBinary: boolean;\n encoding: 'utf-8' | 'base64';\n}\n/**\n * File stream chunk - either string (text) or Uint8Array (binary, auto-decoded)\n */\nexport type FileChunk = string | Uint8Array;\n/**\n * Options for watching a directory.\n *\n * `watch()` resolves only after the watcher is established on the filesystem.\n * The returned SSE stream can be consumed with `parseSSEStream()`.\n */\nexport interface WatchOptions {\n /**\n * Watch subdirectories recursively\n * @default true\n */\n recursive?: boolean;\n /**\n * Glob patterns to include (e.g., '*.ts', '*.js').\n * If not specified, all files are included.\n * Cannot be used together with `exclude`.\n */\n include?: string[];\n /**\n * Glob patterns to exclude (e.g., 'node_modules', '.git').\n * Cannot be used together with `include`.\n * @default ['.git', 'node_modules', '.DS_Store']\n */\n exclude?: string[];\n}\n/**\n * Options for checking whether a path changed while disconnected.\n *\n * Pass the `version` returned from a previous `checkChanges()` call to learn\n * whether the path is unchanged, changed, or needs a full resync because the\n * retained change state was reset. Change state lives only for the current\n * container lifetime and may expire while idle.\n */\nexport interface CheckChangesOptions extends WatchOptions {\n /**\n * Version returned by a previous `checkChanges()` call.\n */\n since?: string;\n}\n/**\n * @internal SSE event types for container communication\n */\nexport type FileWatchEventType = 'create' | 'modify' | 'delete' | 'move_from' | 'move_to' | 'attrib';\n/**\n * @internal Request body for starting a file watch\n */\nexport interface WatchRequest {\n path: string;\n recursive?: boolean;\n events?: FileWatchEventType[];\n include?: string[];\n exclude?: string[];\n}\n/**\n * @internal Request body for checking retained change state.\n */\nexport interface CheckChangesRequest extends WatchRequest {\n since?: string;\n}\n/**\n * SSE events emitted by `sandbox.watch()`.\n */\nexport type FileWatchSSEEvent = {\n type: 'watching';\n path: string;\n watchId: string;\n} | {\n type: 'event';\n eventType: FileWatchEventType;\n path: string;\n isDirectory: boolean;\n timestamp: string;\n} | {\n type: 'error';\n error: string;\n} | {\n type: 'stopped';\n reason: string;\n};\n/**\n * Result returned by `checkChanges()`.\n */\nexport type CheckChangesResult = {\n success: true;\n status: 'unchanged' | 'changed';\n version: string;\n timestamp: string;\n} | {\n success: true;\n status: 'resync';\n reason: 'expired' | 'restarted';\n version: string;\n timestamp: string;\n};\nexport interface EnvSetResult {\n success: boolean;\n timestamp: string;\n}\nexport interface PortExposeResult {\n url: string;\n port: number;\n name?: string;\n}\nexport interface HealthCheckResult {\n success: boolean;\n status: 'healthy' | 'unhealthy';\n timestamp: string;\n}\nexport interface ShutdownResult {\n success: boolean;\n message: string;\n timestamp: string;\n}\n//# sourceMappingURL=filesystem.d.ts.map"],"mappings":"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"}
|
package/dist/git/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../process-types-GStiZ8f8.js";
|
|
2
|
+
import "../filesystem-BWAZCZER.js";
|
|
3
|
+
import { c as SandboxExtension, l as SandboxLike, o as HTTPAuthHostConfig } from "../index-Bs4bqXDR.js";
|
|
2
4
|
|
|
3
5
|
//#region ../../extensions/git/src/types.d.ts
|
|
4
|
-
|
|
5
6
|
/** Result of a git clone (`checkout`) operation. */
|
|
6
7
|
interface GitCheckoutResult {
|
|
7
8
|
success: boolean;
|
|
@@ -21,20 +22,8 @@ interface GitAuthConfig {
|
|
|
21
22
|
interface GitExtensionOptions {
|
|
22
23
|
auth?: GitAuthConfig;
|
|
23
24
|
}
|
|
24
|
-
/** Options shared by every git extension method. */
|
|
25
|
-
interface GitSessionOptions {
|
|
26
|
-
/**
|
|
27
|
-
* Session to run the git command in. Omit to run sessionless (the command
|
|
28
|
-
* runs in a fresh, non-persistent shell). Sessionless commands still inherit
|
|
29
|
-
* the sandbox-level environment variables (e.g. tokens, proxy settings), so
|
|
30
|
-
* auth and egress configured on the sandbox keep working. Pass a session id
|
|
31
|
-
* to run inside an existing session so its working directory and environment
|
|
32
|
-
* carry over instead.
|
|
33
|
-
*/
|
|
34
|
-
sessionId?: string;
|
|
35
|
-
}
|
|
36
25
|
/** Options for cloning a repository. */
|
|
37
|
-
interface GitCheckoutOptions
|
|
26
|
+
interface GitCheckoutOptions {
|
|
38
27
|
/** Branch (or tag) to check out after cloning. */
|
|
39
28
|
branch?: string;
|
|
40
29
|
/** Directory to clone into. Defaults to `/workspace/<repoName>`. */
|
|
@@ -61,14 +50,14 @@ declare class Git extends SandboxExtension {
|
|
|
61
50
|
*/
|
|
62
51
|
checkout(repoUrl: string, options?: GitCheckoutOptions): Promise<GitCheckoutResult>;
|
|
63
52
|
/** Check out an existing branch in a cloned repository. */
|
|
64
|
-
checkoutBranch(repoPath: string, branch: string
|
|
53
|
+
checkoutBranch(repoPath: string, branch: string): Promise<void>;
|
|
65
54
|
/** Return the current branch of a cloned repository. */
|
|
66
|
-
getCurrentBranch(repoPath: string
|
|
55
|
+
getCurrentBranch(repoPath: string): Promise<string>;
|
|
67
56
|
/** List local and remote branches of a cloned repository. */
|
|
68
|
-
listBranches(repoPath: string
|
|
57
|
+
listBranches(repoPath: string): Promise<string[]>;
|
|
69
58
|
}
|
|
70
59
|
/** Factory — the consumer-facing API. */
|
|
71
60
|
declare function withGit(sandbox: SandboxLike, options?: GitExtensionOptions): Git;
|
|
72
61
|
//#endregion
|
|
73
|
-
export { Git, type GitAuthConfig, type GitCheckoutOptions, type GitCheckoutResult, type GitExtensionOptions, type GitHostAuth,
|
|
62
|
+
export { Git, type GitAuthConfig, type GitCheckoutOptions, type GitCheckoutResult, type GitExtensionOptions, type GitHostAuth, withGit as default, withGit };
|
|
74
63
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/git/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../../extensions/git/src/types.ts","../../../../extensions/git/src/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../../extensions/git/src/types.ts","../../../../extensions/git/src/index.ts"],"sourcesContent":[],"mappings":";;;;;;AAUiB,UAAA,iBAAA,CAAiB;EAStB,OAAA,EAAA,OAAW;EAEN,OAAA,EAAA,MAAA;EACN,MAAA,EAAA,MAAA;EACA,SAAA,EAAA,MAAA;EACG,SAAA,EAAA,MAAA;EACW,QAAA,CAAA,EAAA,MAAA;;AAAT,KANJ,WAAA,GAAc,kBAMV;AAKC,UATA,aAAA,CASmB;EAKnB,MAAA,CAAA,EAbN,WAaM;WAZN;cACG;UACJ,eAAe;ACyDzB;AAG6C,UDvD5B,mBAAA,CCuD4B;EAWhC,IAAA,CAAA,EDjEJ,aCiEI;;;AAiG6C,UD9JzC,kBAAA,CC8JyC;EA+Cd;EA8BJ,MAAA,CAAA,EAAA,MAAA;EA5Lf;EAAgB,SAAA,CAAA,EAAA,MAAA;EAqUzB;EACL,KAAA,CAAA,EAAA,MAAA;EACA;EACR,cAAA,CAAA,EAAA,MAAA;EAAG,IAAA,CAAA,ED9WG,aC8WH,GAAA,KAAA;;;;;;;;;cAxUO,GAAA,SAAY,gBAAA;;uBAGF,uBAAsB;;;;;sCAWhC,qBACR,QAAQ;;oDAgG6C;;sCA+Cd;;kCA8BJ;;;iBAyIxB,OAAA,UACL,uBACA,sBACR"}
|
package/dist/git/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as SandboxExtension } from "../extensions-
|
|
1
|
+
import { i as ErrorCode, r as getHttpStatus } from "../errors-CXR0xBpw.js";
|
|
2
|
+
import { t as createErrorFromResponse } from "../errors-QYlSkVGz.js";
|
|
3
|
+
import { c as extractRepoName, l as redactCommand, s as DEFAULT_GIT_CLONE_TIMEOUT_MS } from "../dist-Duor5GbS.js";
|
|
4
|
+
import { t as SandboxExtension } from "../extensions-CFB2xHqY.js";
|
|
5
5
|
|
|
6
6
|
//#region ../../extensions/git/src/manager.ts
|
|
7
7
|
/**
|
|
@@ -198,8 +198,7 @@ var Git = class extends SandboxExtension {
|
|
|
198
198
|
const pathValidation = validatePath(targetDir);
|
|
199
199
|
if (!pathValidation.isValid) this.#throwValidation("targetDir", pathValidation.errors, "INVALID_PATH");
|
|
200
200
|
await this.#configureAuth(repoUrl, options.auth);
|
|
201
|
-
const
|
|
202
|
-
const cloneResult = await this.#exec(buildCloneArgs(repoUrl, targetDir, options), sessionId, void 0, cloneTimeoutMs + CLONE_PROCESS_TIMEOUT_BUFFER_MS);
|
|
201
|
+
const cloneResult = await this.#exec(buildCloneArgs(repoUrl, targetDir, options), void 0, cloneTimeoutMs + CLONE_PROCESS_TIMEOUT_BUFFER_MS);
|
|
203
202
|
if (cloneResult.exitCode !== 0) {
|
|
204
203
|
if ([
|
|
205
204
|
124,
|
|
@@ -219,7 +218,7 @@ var Git = class extends SandboxExtension {
|
|
|
219
218
|
stderr: redactCommand(cloneResult.stderr || "")
|
|
220
219
|
});
|
|
221
220
|
}
|
|
222
|
-
const branchResult = await this.#exec(buildGetCurrentBranchArgs(),
|
|
221
|
+
const branchResult = await this.#exec(buildGetCurrentBranchArgs(), targetDir);
|
|
223
222
|
return {
|
|
224
223
|
success: true,
|
|
225
224
|
repoUrl,
|
|
@@ -229,7 +228,7 @@ var Git = class extends SandboxExtension {
|
|
|
229
228
|
};
|
|
230
229
|
}
|
|
231
230
|
/** Check out an existing branch in a cloned repository. */
|
|
232
|
-
async checkoutBranch(repoPath, branch
|
|
231
|
+
async checkoutBranch(repoPath, branch) {
|
|
233
232
|
const pathValidation = validatePath(repoPath);
|
|
234
233
|
if (!pathValidation.isValid) this.#throwValidation("repoPath", pathValidation.errors, "INVALID_PATH");
|
|
235
234
|
const branchValidation = validateBranchName(branch);
|
|
@@ -238,7 +237,7 @@ var Git = class extends SandboxExtension {
|
|
|
238
237
|
message: branchValidation.error || "Invalid branch name format",
|
|
239
238
|
code: "INVALID_BRANCH"
|
|
240
239
|
}] });
|
|
241
|
-
const result = await this.#exec(buildCheckoutArgs(branch),
|
|
240
|
+
const result = await this.#exec(buildCheckoutArgs(branch), repoPath);
|
|
242
241
|
if (result.exitCode !== 0) {
|
|
243
242
|
const code = determineErrorCode("checkout", result.stderr || "Unknown error", result.exitCode);
|
|
244
243
|
this.#throwError(code, `Failed to checkout branch '${branch}' in '${repoPath}': ${result.stderr || `exit code ${result.exitCode}`}`, {
|
|
@@ -250,10 +249,10 @@ var Git = class extends SandboxExtension {
|
|
|
250
249
|
}
|
|
251
250
|
}
|
|
252
251
|
/** Return the current branch of a cloned repository. */
|
|
253
|
-
async getCurrentBranch(repoPath
|
|
252
|
+
async getCurrentBranch(repoPath) {
|
|
254
253
|
const pathValidation = validatePath(repoPath);
|
|
255
254
|
if (!pathValidation.isValid) this.#throwValidation("repoPath", pathValidation.errors, "INVALID_PATH");
|
|
256
|
-
const result = await this.#exec(buildGetCurrentBranchArgs(),
|
|
255
|
+
const result = await this.#exec(buildGetCurrentBranchArgs(), repoPath);
|
|
257
256
|
if (result.exitCode !== 0) this.#throwError(determineErrorCode("getCurrentBranch", result.stderr || "Unknown error", result.exitCode), `Failed to get current branch in '${repoPath}': ${result.stderr || `exit code ${result.exitCode}`}`, {
|
|
258
257
|
targetDir: repoPath,
|
|
259
258
|
exitCode: result.exitCode,
|
|
@@ -262,10 +261,10 @@ var Git = class extends SandboxExtension {
|
|
|
262
261
|
return result.stdout.trim();
|
|
263
262
|
}
|
|
264
263
|
/** List local and remote branches of a cloned repository. */
|
|
265
|
-
async listBranches(repoPath
|
|
264
|
+
async listBranches(repoPath) {
|
|
266
265
|
const pathValidation = validatePath(repoPath);
|
|
267
266
|
if (!pathValidation.isValid) this.#throwValidation("repoPath", pathValidation.errors, "INVALID_PATH");
|
|
268
|
-
const result = await this.#exec(buildListBranchesArgs(),
|
|
267
|
+
const result = await this.#exec(buildListBranchesArgs(), repoPath);
|
|
269
268
|
if (result.exitCode !== 0) this.#throwError(determineErrorCode("listBranches", result.stderr || "Unknown error", result.exitCode), `Failed to list branches in '${repoPath}': ${result.stderr || `exit code ${result.exitCode}`}`, {
|
|
270
269
|
targetDir: repoPath,
|
|
271
270
|
exitCode: result.exitCode,
|
|
@@ -301,17 +300,11 @@ var Git = class extends SandboxExtension {
|
|
|
301
300
|
if (config.bitbucket) hosts["bitbucket.org"] = config.bitbucket;
|
|
302
301
|
return hosts;
|
|
303
302
|
}
|
|
304
|
-
#
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
async #exec(command, sessionId, cwd, timeout) {
|
|
308
|
-
const result = await this.exec(command, {
|
|
309
|
-
...sessionId !== void 0 && { sessionId },
|
|
303
|
+
async #exec(command, cwd, timeout) {
|
|
304
|
+
const result = await (await this.exec(command, {
|
|
310
305
|
...cwd !== void 0 && { cwd },
|
|
311
|
-
...timeout !== void 0 && { timeout }
|
|
312
|
-
|
|
313
|
-
stderr: "pipe"
|
|
314
|
-
}).output({ encoding: "utf8" });
|
|
306
|
+
...timeout !== void 0 && { timeout }
|
|
307
|
+
})).output({ encoding: "utf8" });
|
|
315
308
|
return {
|
|
316
309
|
stdout: result.stdout,
|
|
317
310
|
stderr: result.stderr,
|
package/dist/git/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["errors: string[]","#options","#throwValidation","#throwError","#configureAuth","#sessionId","#exec","#authHosts","#authHostname","hosts: Record<string, GitHostAuth>"],"sources":["../../../../extensions/git/src/manager.ts","../../../../extensions/git/src/index.ts"],"sourcesContent":["/**\n * Pure git business logic for the git extension.\n *\n * No I/O — just command-argument building, output parsing, validation, and\n * error-code classification. Ported from the former container-side\n * `GitManager` so the extension can drive everything through `exec`.\n */\n\nimport { DEFAULT_GIT_CLONE_TIMEOUT_MS, extractRepoName } from '@repo/shared';\nimport { ErrorCode } from '@repo/shared/errors';\nimport type { GitCheckoutOptions } from './types.js';\n\nexport { DEFAULT_GIT_CLONE_TIMEOUT_MS };\n\nconst GIT_CLONE_KILL_GRACE_SECONDS = 5;\n\n/** Format a millisecond timeout as a `timeout(1)`-friendly seconds string. */\nexport function gitCloneTimeoutSeconds(timeoutMs: number): string {\n const timeoutSeconds = timeoutMs / 1000;\n return Number.isInteger(timeoutSeconds)\n ? String(timeoutSeconds)\n : timeoutSeconds\n .toFixed(3)\n .replace(/\\.0+$/, '')\n .replace(/(\\.\\d*?)0+$/, '$1');\n}\n\n/**\n * Generate the default target directory for a clone: `/workspace/<repoName>`.\n */\nexport function generateTargetDirectory(repoUrl: string): string {\n return `/workspace/${extractRepoName(repoUrl)}`;\n}\n\n/**\n * Build git clone command arguments.\n *\n * Wraps the command with `timeout -k 5 <seconds>` to enforce a wall-clock\n * limit, and configures git's own stalled-transfer detection via\n * `http.lowSpeedLimit` and `http.lowSpeedTime`.\n */\nexport function buildCloneArgs(\n repoUrl: string,\n targetDir: string,\n options: GitCheckoutOptions = {}\n): string[] {\n const timeoutMs = options.cloneTimeoutMs ?? DEFAULT_GIT_CLONE_TIMEOUT_MS;\n const timeoutSeconds = gitCloneTimeoutSeconds(timeoutMs);\n const args = [\n 'timeout',\n '-k',\n String(GIT_CLONE_KILL_GRACE_SECONDS),\n String(timeoutSeconds),\n 'git',\n '-c',\n 'http.lowSpeedLimit=1024',\n '-c',\n 'http.lowSpeedTime=30',\n 'clone',\n '--filter=blob:none'\n ];\n\n if (options.branch) {\n args.push('--branch', options.branch);\n }\n\n if (options.depth !== undefined) {\n args.push('--depth', String(options.depth));\n }\n\n args.push(repoUrl, targetDir);\n\n return args;\n}\n\nexport function buildCheckoutArgs(branch: string): string[] {\n return ['git', 'checkout', branch];\n}\n\nexport function buildGetCurrentBranchArgs(): string[] {\n return ['git', 'branch', '--show-current'];\n}\n\nexport function buildListBranchesArgs(): string[] {\n return ['git', 'branch', '-a'];\n}\n\n/**\n * Parse `git branch -a` output into a deduplicated array of branch names.\n * Strips the current-branch marker, the `remotes/origin/` prefix, and the\n * `HEAD` reference.\n */\nexport function parseBranchList(stdout: string): string[] {\n return stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => line.replace(/^\\*\\s*/, ''))\n .map((line) => line.replace(/^remotes\\/origin\\//, ''))\n .filter((branch) => branch !== 'HEAD' && !branch.includes('->'))\n .filter((branch, index, array) => array.indexOf(branch) === index);\n}\n\n/** Validate a branch name (format only). */\nexport function validateBranchName(branch: string): {\n isValid: boolean;\n error?: string;\n} {\n if (!branch || branch.trim().length === 0) {\n return { isValid: false, error: 'Branch name cannot be empty' };\n }\n return { isValid: true };\n}\n\n/** Validate a git URL (format only — no allowlist). */\nexport function validateGitUrl(url: string): {\n isValid: boolean;\n errors: string[];\n} {\n const errors: string[] = [];\n\n if (!url || typeof url !== 'string') {\n return { isValid: false, errors: ['Git URL must be a non-empty string'] };\n }\n\n const trimmedUrl = url.trim();\n\n if (trimmedUrl.length === 0) {\n errors.push('Git URL cannot be empty');\n }\n if (trimmedUrl.length > 2048) {\n errors.push('Git URL too long (max 2048 characters)');\n }\n if (trimmedUrl.includes('\\0')) {\n errors.push('Git URL contains null bytes');\n }\n\n return { isValid: errors.length === 0, errors };\n}\n\n/** Validate a filesystem path (format only). */\nexport function validatePath(path: string): {\n isValid: boolean;\n errors: string[];\n} {\n const errors: string[] = [];\n\n if (!path || typeof path !== 'string') {\n return { isValid: false, errors: ['Path must be a non-empty string'] };\n }\n if (path.includes('\\0')) {\n errors.push('Path contains null bytes');\n }\n if (path.length > 4096) {\n errors.push('Path too long (max 4096 characters)');\n }\n\n return { isValid: errors.length === 0, errors };\n}\n\n/**\n * Determine the appropriate {@link ErrorCode} for a failed git operation,\n * based on the operation, the stderr/error text, and the process exit code.\n */\nexport function determineErrorCode(\n operation: string,\n error: Error | string,\n exitCode?: number\n): ErrorCode {\n const errorMessage = typeof error === 'string' ? error : error.message;\n const lowerMessage = errorMessage.toLowerCase();\n\n // Exit code 124: timeout command killed the process.\n if (exitCode === 124) {\n return ErrorCode.GIT_NETWORK_ERROR;\n }\n\n // Exit code 128: git-specific fatal errors.\n if (exitCode === 128) {\n if (lowerMessage.includes('not a git repository')) {\n return ErrorCode.GIT_OPERATION_FAILED;\n }\n if (lowerMessage.includes('repository not found')) {\n return ErrorCode.GIT_REPOSITORY_NOT_FOUND;\n }\n return ErrorCode.GIT_OPERATION_FAILED;\n }\n\n if (\n lowerMessage.includes('permission denied') ||\n lowerMessage.includes('access denied')\n ) {\n return ErrorCode.GIT_AUTH_FAILED;\n }\n if (\n lowerMessage.includes('not found') ||\n lowerMessage.includes('does not exist')\n ) {\n return ErrorCode.GIT_REPOSITORY_NOT_FOUND;\n }\n if (lowerMessage.includes('already exists')) {\n return ErrorCode.GIT_CLONE_FAILED;\n }\n if (\n lowerMessage.includes('did not match') ||\n lowerMessage.includes('pathspec')\n ) {\n return ErrorCode.GIT_BRANCH_NOT_FOUND;\n }\n if (\n lowerMessage.includes('authentication') ||\n lowerMessage.includes('credentials')\n ) {\n return ErrorCode.GIT_AUTH_FAILED;\n }\n\n switch (operation) {\n case 'clone':\n return ErrorCode.GIT_CLONE_FAILED;\n case 'checkout':\n return ErrorCode.GIT_CHECKOUT_FAILED;\n default:\n return ErrorCode.GIT_OPERATION_FAILED;\n }\n}\n","/**\n * Git extension for the Cloudflare Sandbox SDK.\n *\n * Git is just a sequence of shell commands, so this is an **SDK-only**\n * extension: it drives the owning sandbox's unified `exec()` process surface\n * over the existing control channel and needs no sidecar. All the git\n * business logic that used to live in the container (argument building,\n * branch parsing, error\n * classification) is ported into `./manager` and runs in the Worker; only the\n * `git` process itself runs in the container.\n *\n * Usage — attach it to a Sandbox subclass and expose delegate methods:\n *\n * ```ts\n * import { Sandbox as BaseSandbox } from '@cloudflare/sandbox';\n * import { withGit } from '@cloudflare/sandbox/git';\n *\n * export class Sandbox extends BaseSandbox<Env> {\n * git = withGit(this);\n * gitCheckout(repoUrl: string, options?: GitCheckoutOptions) {\n * return this.git.checkout(repoUrl, options);\n * }\n * }\n *\n * await sandbox.gitCheckout('https://github.com/owner/repo.git');\n * ```\n */\n\nimport { createErrorFromResponse } from '@cloudflare/sandbox/errors';\nimport {\n SandboxExtension,\n type SandboxLike\n} from '@cloudflare/sandbox/extensions';\nimport { redactCommand } from '@repo/shared';\nimport {\n ErrorCode,\n type ErrorResponse,\n getHttpStatus\n} from '@repo/shared/errors';\nimport {\n buildCheckoutArgs,\n buildCloneArgs,\n buildGetCurrentBranchArgs,\n buildListBranchesArgs,\n DEFAULT_GIT_CLONE_TIMEOUT_MS,\n determineErrorCode,\n generateTargetDirectory,\n gitCloneTimeoutSeconds,\n parseBranchList,\n validateBranchName,\n validateGitUrl,\n validatePath\n} from './manager.js';\nimport type {\n GitCheckoutOptions,\n GitCheckoutResult,\n GitExtensionOptions,\n GitHostAuth,\n GitSessionOptions\n} from './types.js';\n\nexport type {\n GitAuthConfig,\n GitCheckoutOptions,\n GitCheckoutResult,\n GitExtensionOptions,\n GitHostAuth,\n GitSessionOptions\n} from './types.js';\nexport { withGit as default };\n\nconst CLONE_PROCESS_TIMEOUT_BUFFER_MS = 10_000;\n\n/** Shape returned by a completed git process. */\ninterface ExecOutcome {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * The git extension. Drives `git` in the container through the commands\n * control sub-API and translates failures into the SDK's typed git errors.\n */\nexport class Git extends SandboxExtension {\n readonly #options: GitExtensionOptions;\n\n constructor(sandbox: SandboxLike, options: GitExtensionOptions = {}) {\n super(sandbox);\n this.#options = options;\n }\n\n /**\n * Clone a repository. Returns the resolved target directory and the branch\n * actually checked out (queried from git, not assumed).\n */\n async checkout(\n repoUrl: string,\n options: GitCheckoutOptions = {}\n ): Promise<GitCheckoutResult> {\n const urlValidation = validateGitUrl(repoUrl);\n if (!urlValidation.isValid) {\n this.#throwValidation('repoUrl', urlValidation.errors, 'INVALID_GIT_URL');\n }\n\n const targetDir = options.targetDir || generateTargetDirectory(repoUrl);\n const cloneTimeoutMs =\n options.cloneTimeoutMs ?? DEFAULT_GIT_CLONE_TIMEOUT_MS;\n\n if (!Number.isInteger(cloneTimeoutMs) || cloneTimeoutMs <= 0) {\n this.#throwError(\n ErrorCode.VALIDATION_FAILED,\n `Invalid clone timeout '${options.cloneTimeoutMs}'. Must be a positive integer representing milliseconds.`,\n {\n validationErrors: [\n {\n field: 'cloneTimeoutMs',\n message:\n 'Clone timeout must be a positive integer representing milliseconds',\n code: 'INVALID_TIMEOUT'\n }\n ]\n }\n );\n }\n\n const pathValidation = validatePath(targetDir);\n if (!pathValidation.isValid) {\n this.#throwValidation('targetDir', pathValidation.errors, 'INVALID_PATH');\n }\n\n await this.#configureAuth(repoUrl, options.auth);\n\n const sessionId = this.#sessionId(options);\n const cloneResult = await this.#exec(\n buildCloneArgs(repoUrl, targetDir, options),\n sessionId,\n undefined,\n cloneTimeoutMs + CLONE_PROCESS_TIMEOUT_BUFFER_MS\n );\n\n if (cloneResult.exitCode !== 0) {\n if ([124, 143, -15].includes(cloneResult.exitCode)) {\n this.#throwError(\n ErrorCode.GIT_NETWORK_ERROR,\n `Git clone timed out after ${gitCloneTimeoutSeconds(\n cloneTimeoutMs\n )} seconds for '${redactCommand(repoUrl)}'`,\n {\n repository: redactCommand(repoUrl),\n targetDir,\n exitCode: 124,\n stderr: 'Operation timed out'\n }\n );\n }\n\n const code = determineErrorCode(\n 'clone',\n cloneResult.stderr || 'Unknown error',\n cloneResult.exitCode\n );\n this.#throwError(\n code,\n `Failed to clone repository '${redactCommand(repoUrl)}': ${\n redactCommand(cloneResult.stderr || '') ||\n `exit code ${cloneResult.exitCode}`\n }`,\n {\n repository: redactCommand(repoUrl),\n targetDir,\n exitCode: cloneResult.exitCode,\n stderr: redactCommand(cloneResult.stderr || '')\n }\n );\n }\n\n // Query the branch actually checked out rather than assuming.\n const branchResult = await this.#exec(\n buildGetCurrentBranchArgs(),\n sessionId,\n targetDir\n );\n const branch =\n branchResult.exitCode === 0 && branchResult.stdout.trim()\n ? branchResult.stdout.trim()\n : options.branch || 'unknown';\n\n return {\n success: true,\n repoUrl,\n branch,\n targetDir,\n timestamp: new Date().toISOString()\n };\n }\n\n /** Check out an existing branch in a cloned repository. */\n async checkoutBranch(\n repoPath: string,\n branch: string,\n options: GitSessionOptions = {}\n ): Promise<void> {\n const pathValidation = validatePath(repoPath);\n if (!pathValidation.isValid) {\n this.#throwValidation('repoPath', pathValidation.errors, 'INVALID_PATH');\n }\n\n const branchValidation = validateBranchName(branch);\n if (!branchValidation.isValid) {\n this.#throwError(\n ErrorCode.VALIDATION_FAILED,\n `Invalid branch name '${branch}': ${branchValidation.error || 'Invalid format'}`,\n {\n validationErrors: [\n {\n field: 'branch',\n message: branchValidation.error || 'Invalid branch name format',\n code: 'INVALID_BRANCH'\n }\n ]\n }\n );\n }\n\n const result = await this.#exec(\n buildCheckoutArgs(branch),\n this.#sessionId(options),\n repoPath\n );\n\n if (result.exitCode !== 0) {\n const code = determineErrorCode(\n 'checkout',\n result.stderr || 'Unknown error',\n result.exitCode\n );\n this.#throwError(\n code,\n `Failed to checkout branch '${branch}' in '${repoPath}': ${\n result.stderr || `exit code ${result.exitCode}`\n }`,\n {\n branch,\n targetDir: repoPath,\n exitCode: result.exitCode,\n stderr: result.stderr\n }\n );\n }\n }\n\n /** Return the current branch of a cloned repository. */\n async getCurrentBranch(\n repoPath: string,\n options: GitSessionOptions = {}\n ): Promise<string> {\n const pathValidation = validatePath(repoPath);\n if (!pathValidation.isValid) {\n this.#throwValidation('repoPath', pathValidation.errors, 'INVALID_PATH');\n }\n\n const result = await this.#exec(\n buildGetCurrentBranchArgs(),\n this.#sessionId(options),\n repoPath\n );\n\n if (result.exitCode !== 0) {\n this.#throwError(\n determineErrorCode(\n 'getCurrentBranch',\n result.stderr || 'Unknown error',\n result.exitCode\n ),\n `Failed to get current branch in '${repoPath}': ${\n result.stderr || `exit code ${result.exitCode}`\n }`,\n {\n targetDir: repoPath,\n exitCode: result.exitCode,\n stderr: result.stderr\n }\n );\n }\n\n return result.stdout.trim();\n }\n\n /** List local and remote branches of a cloned repository. */\n async listBranches(\n repoPath: string,\n options: GitSessionOptions = {}\n ): Promise<string[]> {\n const pathValidation = validatePath(repoPath);\n if (!pathValidation.isValid) {\n this.#throwValidation('repoPath', pathValidation.errors, 'INVALID_PATH');\n }\n\n const result = await this.#exec(\n buildListBranchesArgs(),\n this.#sessionId(options),\n repoPath\n );\n\n if (result.exitCode !== 0) {\n this.#throwError(\n determineErrorCode(\n 'listBranches',\n result.stderr || 'Unknown error',\n result.exitCode\n ),\n `Failed to list branches in '${repoPath}': ${\n result.stderr || `exit code ${result.exitCode}`\n }`,\n {\n targetDir: repoPath,\n exitCode: result.exitCode,\n stderr: result.stderr\n }\n );\n }\n\n return parseBranchList(result.stdout);\n }\n\n // --- internals -----------------------------------------------------------\n\n async #configureAuth(\n repoUrl: string,\n authOverride: GitCheckoutOptions['auth']\n ): Promise<void> {\n const hosts = this.#authHosts(authOverride);\n if (Object.keys(hosts).length === 0) {\n return;\n }\n\n const hostname = this.#authHostname(repoUrl);\n if (hostname === undefined || !hosts[hostname]) {\n return;\n }\n\n if (!this.httpAuthInterceptor) {\n this.#throwError(\n ErrorCode.VALIDATION_FAILED,\n 'Git extension authentication requires exporting ContainerProxy from the Worker entrypoint. Import ContainerProxy from @cloudflare/sandbox and export it from your Worker to use git auth interception.',\n {\n repository: redactCommand(repoUrl),\n host: hostname\n }\n );\n }\n\n await this.httpAuthInterceptor({ hosts: { [hostname]: hosts[hostname] } });\n }\n\n #authHostname(repoUrl: string): string | undefined {\n try {\n return new URL(repoUrl).hostname;\n } catch {\n return undefined;\n }\n }\n\n #authHosts(\n authOverride: GitCheckoutOptions['auth']\n ): Record<string, GitHostAuth> {\n if (authOverride === false) {\n return {};\n }\n const config = authOverride ?? this.#options.auth;\n if (!config) {\n return {};\n }\n\n const hosts: Record<string, GitHostAuth> = { ...(config.hosts ?? {}) };\n if (config.github) {\n hosts['github.com'] = config.github;\n }\n if (config.gitlab) {\n hosts['gitlab.com'] = config.gitlab;\n }\n if (config.bitbucket) {\n hosts['bitbucket.org'] = config.bitbucket;\n }\n return hosts;\n }\n\n #sessionId(options: GitSessionOptions): string | undefined {\n return options.sessionId;\n }\n\n async #exec(\n command: string[],\n sessionId: string | undefined,\n cwd?: string,\n timeout?: number\n ): Promise<ExecOutcome> {\n const result = await this.exec(command, {\n ...(sessionId !== undefined && { sessionId }),\n ...(cwd !== undefined && { cwd }),\n ...(timeout !== undefined && { timeout }),\n stdout: 'pipe',\n stderr: 'pipe'\n }).output({ encoding: 'utf8' });\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode\n };\n }\n\n #throwValidation(field: string, errors: string[], code: string): never {\n this.#throwError(\n code === 'INVALID_GIT_URL'\n ? ErrorCode.INVALID_GIT_URL\n : ErrorCode.VALIDATION_FAILED,\n `Invalid ${field}: ${errors.join(', ')}`,\n {\n validationErrors: errors.map((message) => ({ field, message, code }))\n }\n );\n }\n\n #throwError(\n code: ErrorCode,\n message: string,\n context: Record<string, unknown>\n ): never {\n const response: ErrorResponse = {\n code,\n message,\n context,\n httpStatus: getHttpStatus(code),\n timestamp: new Date().toISOString()\n };\n throw createErrorFromResponse(response);\n }\n}\n\n/** Factory — the consumer-facing API. */\nexport function withGit(\n sandbox: SandboxLike,\n options: GitExtensionOptions = {}\n): Git {\n return new Git(sandbox, options);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["args: [string, ...string[]]","errors: string[]","#options","#throwValidation","#throwError","#configureAuth","#exec","#authHosts","#authHostname","hosts: Record<string, GitHostAuth>"],"sources":["../../../../extensions/git/src/manager.ts","../../../../extensions/git/src/index.ts"],"sourcesContent":["/**\n * Pure git business logic for the git extension.\n *\n * No I/O — just command-argument building, output parsing, validation, and\n * error-code classification. Ported from the former container-side\n * `GitManager` so the extension can drive everything through `exec`.\n */\n\nimport {\n DEFAULT_GIT_CLONE_TIMEOUT_MS,\n extractRepoName,\n type SandboxCommand\n} from '@repo/shared';\nimport { ErrorCode } from '@repo/shared/errors';\nimport type { GitCheckoutOptions } from './types.js';\n\nexport { DEFAULT_GIT_CLONE_TIMEOUT_MS };\n\nconst GIT_CLONE_KILL_GRACE_SECONDS = 5;\n\n/** Format a millisecond timeout as a `timeout(1)`-friendly seconds string. */\nexport function gitCloneTimeoutSeconds(timeoutMs: number): string {\n const timeoutSeconds = timeoutMs / 1000;\n return Number.isInteger(timeoutSeconds)\n ? String(timeoutSeconds)\n : timeoutSeconds\n .toFixed(3)\n .replace(/\\.0+$/, '')\n .replace(/(\\.\\d*?)0+$/, '$1');\n}\n\n/**\n * Generate the default target directory for a clone: `/workspace/<repoName>`.\n */\nexport function generateTargetDirectory(repoUrl: string): string {\n return `/workspace/${extractRepoName(repoUrl)}`;\n}\n\n/**\n * Build git clone command arguments.\n *\n * Wraps the command with `timeout -k 5 <seconds>` to enforce a wall-clock\n * limit, and configures git's own stalled-transfer detection via\n * `http.lowSpeedLimit` and `http.lowSpeedTime`.\n */\nexport function buildCloneArgs(\n repoUrl: string,\n targetDir: string,\n options: GitCheckoutOptions = {}\n): SandboxCommand {\n const timeoutMs = options.cloneTimeoutMs ?? DEFAULT_GIT_CLONE_TIMEOUT_MS;\n const timeoutSeconds = gitCloneTimeoutSeconds(timeoutMs);\n const args: [string, ...string[]] = [\n 'timeout',\n '-k',\n String(GIT_CLONE_KILL_GRACE_SECONDS),\n String(timeoutSeconds),\n 'git',\n '-c',\n 'http.lowSpeedLimit=1024',\n '-c',\n 'http.lowSpeedTime=30',\n 'clone',\n '--filter=blob:none'\n ];\n\n if (options.branch) {\n args.push('--branch', options.branch);\n }\n\n if (options.depth !== undefined) {\n args.push('--depth', String(options.depth));\n }\n\n args.push(repoUrl, targetDir);\n\n return args;\n}\n\nexport function buildCheckoutArgs(branch: string): SandboxCommand {\n return ['git', 'checkout', branch];\n}\n\nexport function buildGetCurrentBranchArgs(): SandboxCommand {\n return ['git', 'branch', '--show-current'];\n}\n\nexport function buildListBranchesArgs(): SandboxCommand {\n return ['git', 'branch', '-a'];\n}\n\n/**\n * Parse `git branch -a` output into a deduplicated array of branch names.\n * Strips the current-branch marker, the `remotes/origin/` prefix, and the\n * `HEAD` reference.\n */\nexport function parseBranchList(stdout: string): string[] {\n return stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => line.replace(/^\\*\\s*/, ''))\n .map((line) => line.replace(/^remotes\\/origin\\//, ''))\n .filter((branch) => branch !== 'HEAD' && !branch.includes('->'))\n .filter((branch, index, array) => array.indexOf(branch) === index);\n}\n\n/** Validate a branch name (format only). */\nexport function validateBranchName(branch: string): {\n isValid: boolean;\n error?: string;\n} {\n if (!branch || branch.trim().length === 0) {\n return { isValid: false, error: 'Branch name cannot be empty' };\n }\n return { isValid: true };\n}\n\n/** Validate a git URL (format only — no allowlist). */\nexport function validateGitUrl(url: string): {\n isValid: boolean;\n errors: string[];\n} {\n const errors: string[] = [];\n\n if (!url || typeof url !== 'string') {\n return { isValid: false, errors: ['Git URL must be a non-empty string'] };\n }\n\n const trimmedUrl = url.trim();\n\n if (trimmedUrl.length === 0) {\n errors.push('Git URL cannot be empty');\n }\n if (trimmedUrl.length > 2048) {\n errors.push('Git URL too long (max 2048 characters)');\n }\n if (trimmedUrl.includes('\\0')) {\n errors.push('Git URL contains null bytes');\n }\n\n return { isValid: errors.length === 0, errors };\n}\n\n/** Validate a filesystem path (format only). */\nexport function validatePath(path: string): {\n isValid: boolean;\n errors: string[];\n} {\n const errors: string[] = [];\n\n if (!path || typeof path !== 'string') {\n return { isValid: false, errors: ['Path must be a non-empty string'] };\n }\n if (path.includes('\\0')) {\n errors.push('Path contains null bytes');\n }\n if (path.length > 4096) {\n errors.push('Path too long (max 4096 characters)');\n }\n\n return { isValid: errors.length === 0, errors };\n}\n\n/**\n * Determine the appropriate {@link ErrorCode} for a failed git operation,\n * based on the operation, the stderr/error text, and the process exit code.\n */\nexport function determineErrorCode(\n operation: string,\n error: Error | string,\n exitCode?: number\n): ErrorCode {\n const errorMessage = typeof error === 'string' ? error : error.message;\n const lowerMessage = errorMessage.toLowerCase();\n\n // Exit code 124: timeout command killed the process.\n if (exitCode === 124) {\n return ErrorCode.GIT_NETWORK_ERROR;\n }\n\n // Exit code 128: git-specific fatal errors.\n if (exitCode === 128) {\n if (lowerMessage.includes('not a git repository')) {\n return ErrorCode.GIT_OPERATION_FAILED;\n }\n if (lowerMessage.includes('repository not found')) {\n return ErrorCode.GIT_REPOSITORY_NOT_FOUND;\n }\n return ErrorCode.GIT_OPERATION_FAILED;\n }\n\n if (\n lowerMessage.includes('permission denied') ||\n lowerMessage.includes('access denied')\n ) {\n return ErrorCode.GIT_AUTH_FAILED;\n }\n if (\n lowerMessage.includes('not found') ||\n lowerMessage.includes('does not exist')\n ) {\n return ErrorCode.GIT_REPOSITORY_NOT_FOUND;\n }\n if (lowerMessage.includes('already exists')) {\n return ErrorCode.GIT_CLONE_FAILED;\n }\n if (\n lowerMessage.includes('did not match') ||\n lowerMessage.includes('pathspec')\n ) {\n return ErrorCode.GIT_BRANCH_NOT_FOUND;\n }\n if (\n lowerMessage.includes('authentication') ||\n lowerMessage.includes('credentials')\n ) {\n return ErrorCode.GIT_AUTH_FAILED;\n }\n\n switch (operation) {\n case 'clone':\n return ErrorCode.GIT_CLONE_FAILED;\n case 'checkout':\n return ErrorCode.GIT_CHECKOUT_FAILED;\n default:\n return ErrorCode.GIT_OPERATION_FAILED;\n }\n}\n","/**\n * Git extension for the Cloudflare Sandbox SDK.\n *\n * Git is just a sequence of shell commands, so this is an **SDK-only**\n * extension: it drives the owning sandbox's unified `exec()` process surface\n * over the existing control channel and needs no sidecar. All the git\n * business logic that used to live in the container (argument building,\n * branch parsing, error\n * classification) is ported into `./manager` and runs in the Worker; only the\n * `git` process itself runs in the container.\n *\n * Usage — attach it to a Sandbox subclass and expose delegate methods:\n *\n * ```ts\n * import { Sandbox as BaseSandbox } from '@cloudflare/sandbox';\n * import { withGit } from '@cloudflare/sandbox/git';\n *\n * export class Sandbox extends BaseSandbox<Env> {\n * git = withGit(this);\n * gitCheckout(repoUrl: string, options?: GitCheckoutOptions) {\n * return this.git.checkout(repoUrl, options);\n * }\n * }\n *\n * await sandbox.gitCheckout('https://github.com/owner/repo.git');\n * ```\n */\n\nimport { createErrorFromResponse } from '@cloudflare/sandbox/errors';\nimport {\n SandboxExtension,\n type SandboxLike\n} from '@cloudflare/sandbox/extensions';\nimport { redactCommand, type SandboxCommand } from '@repo/shared';\nimport {\n ErrorCode,\n type ErrorResponse,\n getHttpStatus\n} from '@repo/shared/errors';\nimport {\n buildCheckoutArgs,\n buildCloneArgs,\n buildGetCurrentBranchArgs,\n buildListBranchesArgs,\n DEFAULT_GIT_CLONE_TIMEOUT_MS,\n determineErrorCode,\n generateTargetDirectory,\n gitCloneTimeoutSeconds,\n parseBranchList,\n validateBranchName,\n validateGitUrl,\n validatePath\n} from './manager.js';\nimport type {\n GitCheckoutOptions,\n GitCheckoutResult,\n GitExtensionOptions,\n GitHostAuth\n} from './types.js';\n\nexport type {\n GitAuthConfig,\n GitCheckoutOptions,\n GitCheckoutResult,\n GitExtensionOptions,\n GitHostAuth\n} from './types.js';\nexport { withGit as default };\n\nconst CLONE_PROCESS_TIMEOUT_BUFFER_MS = 10_000;\n\n/** Shape returned by a completed git process. */\ninterface ExecOutcome {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * The git extension. Drives `git` in the container through the commands\n * control sub-API and translates failures into the SDK's typed git errors.\n */\nexport class Git extends SandboxExtension {\n readonly #options: GitExtensionOptions;\n\n constructor(sandbox: SandboxLike, options: GitExtensionOptions = {}) {\n super(sandbox);\n this.#options = options;\n }\n\n /**\n * Clone a repository. Returns the resolved target directory and the branch\n * actually checked out (queried from git, not assumed).\n */\n async checkout(\n repoUrl: string,\n options: GitCheckoutOptions = {}\n ): Promise<GitCheckoutResult> {\n const urlValidation = validateGitUrl(repoUrl);\n if (!urlValidation.isValid) {\n this.#throwValidation('repoUrl', urlValidation.errors, 'INVALID_GIT_URL');\n }\n\n const targetDir = options.targetDir || generateTargetDirectory(repoUrl);\n const cloneTimeoutMs =\n options.cloneTimeoutMs ?? DEFAULT_GIT_CLONE_TIMEOUT_MS;\n\n if (!Number.isInteger(cloneTimeoutMs) || cloneTimeoutMs <= 0) {\n this.#throwError(\n ErrorCode.VALIDATION_FAILED,\n `Invalid clone timeout '${options.cloneTimeoutMs}'. Must be a positive integer representing milliseconds.`,\n {\n validationErrors: [\n {\n field: 'cloneTimeoutMs',\n message:\n 'Clone timeout must be a positive integer representing milliseconds',\n code: 'INVALID_TIMEOUT'\n }\n ]\n }\n );\n }\n\n const pathValidation = validatePath(targetDir);\n if (!pathValidation.isValid) {\n this.#throwValidation('targetDir', pathValidation.errors, 'INVALID_PATH');\n }\n\n await this.#configureAuth(repoUrl, options.auth);\n\n const cloneResult = await this.#exec(\n buildCloneArgs(repoUrl, targetDir, options),\n undefined,\n cloneTimeoutMs + CLONE_PROCESS_TIMEOUT_BUFFER_MS\n );\n\n if (cloneResult.exitCode !== 0) {\n if ([124, 143, -15].includes(cloneResult.exitCode)) {\n this.#throwError(\n ErrorCode.GIT_NETWORK_ERROR,\n `Git clone timed out after ${gitCloneTimeoutSeconds(\n cloneTimeoutMs\n )} seconds for '${redactCommand(repoUrl)}'`,\n {\n repository: redactCommand(repoUrl),\n targetDir,\n exitCode: 124,\n stderr: 'Operation timed out'\n }\n );\n }\n\n const code = determineErrorCode(\n 'clone',\n cloneResult.stderr || 'Unknown error',\n cloneResult.exitCode\n );\n this.#throwError(\n code,\n `Failed to clone repository '${redactCommand(repoUrl)}': ${\n redactCommand(cloneResult.stderr || '') ||\n `exit code ${cloneResult.exitCode}`\n }`,\n {\n repository: redactCommand(repoUrl),\n targetDir,\n exitCode: cloneResult.exitCode,\n stderr: redactCommand(cloneResult.stderr || '')\n }\n );\n }\n\n // Query the branch actually checked out rather than assuming.\n const branchResult = await this.#exec(\n buildGetCurrentBranchArgs(),\n targetDir\n );\n const branch =\n branchResult.exitCode === 0 && branchResult.stdout.trim()\n ? branchResult.stdout.trim()\n : options.branch || 'unknown';\n\n return {\n success: true,\n repoUrl,\n branch,\n targetDir,\n timestamp: new Date().toISOString()\n };\n }\n\n /** Check out an existing branch in a cloned repository. */\n async checkoutBranch(repoPath: string, branch: string): Promise<void> {\n const pathValidation = validatePath(repoPath);\n if (!pathValidation.isValid) {\n this.#throwValidation('repoPath', pathValidation.errors, 'INVALID_PATH');\n }\n\n const branchValidation = validateBranchName(branch);\n if (!branchValidation.isValid) {\n this.#throwError(\n ErrorCode.VALIDATION_FAILED,\n `Invalid branch name '${branch}': ${branchValidation.error || 'Invalid format'}`,\n {\n validationErrors: [\n {\n field: 'branch',\n message: branchValidation.error || 'Invalid branch name format',\n code: 'INVALID_BRANCH'\n }\n ]\n }\n );\n }\n\n const result = await this.#exec(buildCheckoutArgs(branch), repoPath);\n\n if (result.exitCode !== 0) {\n const code = determineErrorCode(\n 'checkout',\n result.stderr || 'Unknown error',\n result.exitCode\n );\n this.#throwError(\n code,\n `Failed to checkout branch '${branch}' in '${repoPath}': ${\n result.stderr || `exit code ${result.exitCode}`\n }`,\n {\n branch,\n targetDir: repoPath,\n exitCode: result.exitCode,\n stderr: result.stderr\n }\n );\n }\n }\n\n /** Return the current branch of a cloned repository. */\n async getCurrentBranch(repoPath: string): Promise<string> {\n const pathValidation = validatePath(repoPath);\n if (!pathValidation.isValid) {\n this.#throwValidation('repoPath', pathValidation.errors, 'INVALID_PATH');\n }\n\n const result = await this.#exec(buildGetCurrentBranchArgs(), repoPath);\n\n if (result.exitCode !== 0) {\n this.#throwError(\n determineErrorCode(\n 'getCurrentBranch',\n result.stderr || 'Unknown error',\n result.exitCode\n ),\n `Failed to get current branch in '${repoPath}': ${\n result.stderr || `exit code ${result.exitCode}`\n }`,\n {\n targetDir: repoPath,\n exitCode: result.exitCode,\n stderr: result.stderr\n }\n );\n }\n\n return result.stdout.trim();\n }\n\n /** List local and remote branches of a cloned repository. */\n async listBranches(repoPath: string): Promise<string[]> {\n const pathValidation = validatePath(repoPath);\n if (!pathValidation.isValid) {\n this.#throwValidation('repoPath', pathValidation.errors, 'INVALID_PATH');\n }\n\n const result = await this.#exec(buildListBranchesArgs(), repoPath);\n\n if (result.exitCode !== 0) {\n this.#throwError(\n determineErrorCode(\n 'listBranches',\n result.stderr || 'Unknown error',\n result.exitCode\n ),\n `Failed to list branches in '${repoPath}': ${\n result.stderr || `exit code ${result.exitCode}`\n }`,\n {\n targetDir: repoPath,\n exitCode: result.exitCode,\n stderr: result.stderr\n }\n );\n }\n\n return parseBranchList(result.stdout);\n }\n\n // --- internals -----------------------------------------------------------\n\n async #configureAuth(\n repoUrl: string,\n authOverride: GitCheckoutOptions['auth']\n ): Promise<void> {\n const hosts = this.#authHosts(authOverride);\n if (Object.keys(hosts).length === 0) {\n return;\n }\n\n const hostname = this.#authHostname(repoUrl);\n if (hostname === undefined || !hosts[hostname]) {\n return;\n }\n\n if (!this.httpAuthInterceptor) {\n this.#throwError(\n ErrorCode.VALIDATION_FAILED,\n 'Git extension authentication requires exporting ContainerProxy from the Worker entrypoint. Import ContainerProxy from @cloudflare/sandbox and export it from your Worker to use git auth interception.',\n {\n repository: redactCommand(repoUrl),\n host: hostname\n }\n );\n }\n\n await this.httpAuthInterceptor({ hosts: { [hostname]: hosts[hostname] } });\n }\n\n #authHostname(repoUrl: string): string | undefined {\n try {\n return new URL(repoUrl).hostname;\n } catch {\n return undefined;\n }\n }\n\n #authHosts(\n authOverride: GitCheckoutOptions['auth']\n ): Record<string, GitHostAuth> {\n if (authOverride === false) {\n return {};\n }\n const config = authOverride ?? this.#options.auth;\n if (!config) {\n return {};\n }\n\n const hosts: Record<string, GitHostAuth> = { ...(config.hosts ?? {}) };\n if (config.github) {\n hosts['github.com'] = config.github;\n }\n if (config.gitlab) {\n hosts['gitlab.com'] = config.gitlab;\n }\n if (config.bitbucket) {\n hosts['bitbucket.org'] = config.bitbucket;\n }\n return hosts;\n }\n\n async #exec(\n command: SandboxCommand,\n cwd?: string,\n timeout?: number\n ): Promise<ExecOutcome> {\n const process = await this.exec(command, {\n ...(cwd !== undefined && { cwd }),\n ...(timeout !== undefined && { timeout })\n });\n const result = await process.output({ encoding: 'utf8' });\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode\n };\n }\n\n #throwValidation(field: string, errors: string[], code: string): never {\n this.#throwError(\n code === 'INVALID_GIT_URL'\n ? ErrorCode.INVALID_GIT_URL\n : ErrorCode.VALIDATION_FAILED,\n `Invalid ${field}: ${errors.join(', ')}`,\n {\n validationErrors: errors.map((message) => ({ field, message, code }))\n }\n );\n }\n\n #throwError(\n code: ErrorCode,\n message: string,\n context: Record<string, unknown>\n ): never {\n const response: ErrorResponse = {\n code,\n message,\n context,\n httpStatus: getHttpStatus(code),\n timestamp: new Date().toISOString()\n };\n throw createErrorFromResponse(response);\n }\n}\n\n/** Factory — the consumer-facing API. */\nexport function withGit(\n sandbox: SandboxLike,\n options: GitExtensionOptions = {}\n): Git {\n return new Git(sandbox, options);\n}\n"],"mappings":"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"}
|