@computesdk/provider
Advanced tools
+236
-0
@@ -33,2 +33,124 @@ "use strict"; | ||
| // src/factory.ts | ||
| var import_daemond = require("daemond"); | ||
| var DEFAULT_DAEMON_SSE_PORT = 38989; | ||
| function createDaemonRequestId() { | ||
| if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { | ||
| return crypto.randomUUID(); | ||
| } | ||
| return `req_${Date.now()}_${Math.random().toString(16).slice(2)}`; | ||
| } | ||
| function emitMissingOutput(emitted, finalOutput, emit) { | ||
| if (!finalOutput) return; | ||
| if (!emitted) { | ||
| emit(finalOutput); | ||
| return; | ||
| } | ||
| if (finalOutput.startsWith(emitted)) { | ||
| const missing = finalOutput.slice(emitted.length); | ||
| if (missing) emit(missing); | ||
| return; | ||
| } | ||
| if (finalOutput.includes(emitted)) { | ||
| return; | ||
| } | ||
| if (emitted.includes(finalOutput)) { | ||
| return; | ||
| } | ||
| if (!emitted.includes(finalOutput)) { | ||
| emit(finalOutput); | ||
| } | ||
| } | ||
| function parseSseDataLines(raw) { | ||
| const chunks = raw.split(/\n\n+/); | ||
| const out = []; | ||
| for (const chunk of chunks) { | ||
| const lines = chunk.split("\n"); | ||
| for (const line of lines) { | ||
| if (line.startsWith("data:")) { | ||
| out.push(line.slice(5).trim()); | ||
| } | ||
| } | ||
| } | ||
| return out; | ||
| } | ||
| function pickString(source, keys) { | ||
| if (!source) return void 0; | ||
| for (const key of keys) { | ||
| const value = source[key]; | ||
| if (typeof value === "string") return value; | ||
| } | ||
| return void 0; | ||
| } | ||
| function normalizeDaemonStreamEvent(payload) { | ||
| if (!payload || typeof payload !== "object") return {}; | ||
| const record = payload; | ||
| const data = record.data && typeof record.data === "object" ? record.data : void 0; | ||
| const type = pickString(record, ["type", "event"]); | ||
| const requestId = pickString(record, ["requestId"]) ?? pickString(data, ["requestId"]); | ||
| const stdout = pickString(record, ["stdout", "output", "chunk"]) ?? pickString(data, ["stdout", "output", "chunk"]); | ||
| const stderr = pickString(record, ["stderr"]) ?? pickString(data, ["stderr"]); | ||
| return { type, requestId, stdout, stderr }; | ||
| } | ||
| function isExpectedDaemonStreamError(error) { | ||
| if (!error) return false; | ||
| if (error instanceof DOMException && error.name === "AbortError") { | ||
| return true; | ||
| } | ||
| if (error instanceof TypeError) { | ||
| return true; | ||
| } | ||
| if (error instanceof Error) { | ||
| if (error.name === "AbortError") { | ||
| return true; | ||
| } | ||
| const message = error.message.toLowerCase(); | ||
| if (message.includes("failed to open daemon event stream")) { | ||
| return true; | ||
| } | ||
| if (message.includes("fetch") || message.includes("network")) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| async function streamDaemonEvents(sseUrl, requestIdFilter, callbacks, signal) { | ||
| const response = await fetch(sseUrl, { signal }); | ||
| if (!response.ok || !response.body) { | ||
| throw new Error(`Failed to open daemon event stream: ${response.status}`); | ||
| } | ||
| const reader = response.body.getReader(); | ||
| const decoder = new TextDecoder(); | ||
| let buffer = ""; | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (done) break; | ||
| buffer += decoder.decode(value, { stream: true }); | ||
| const frames = buffer.split("\n\n"); | ||
| buffer = frames.pop() ?? ""; | ||
| for (const frame of frames) { | ||
| const dataLines = parseSseDataLines(frame); | ||
| for (const dataLine of dataLines) { | ||
| let parsed; | ||
| try { | ||
| parsed = JSON.parse(dataLine); | ||
| } catch { | ||
| continue; | ||
| } | ||
| const event = normalizeDaemonStreamEvent(parsed); | ||
| if (requestIdFilter.current && event.requestId !== requestIdFilter.current) { | ||
| continue; | ||
| } | ||
| if ((event.type === "command.stdout" || !event.type) && event.stdout && callbacks.onStdout) { | ||
| callbacks.markStdout(event.stdout); | ||
| callbacks.onStdout(event.stdout); | ||
| } | ||
| const stderrChunk = event.stderr ?? (event.type === "command.stderr" ? event.stdout : void 0); | ||
| if ((event.type === "command.stderr" || !event.type) && stderrChunk && callbacks.onStderr) { | ||
| callbacks.markStderr(stderrChunk); | ||
| callbacks.onStderr(stderrChunk); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| var UnsupportedFileSystem = class { | ||
@@ -103,3 +225,117 @@ constructor(providerName) { | ||
| } | ||
| async resolveDaemonSseUrl(rawUrl, expectedToken) { | ||
| let parsed; | ||
| try { | ||
| parsed = new URL(rawUrl); | ||
| } catch { | ||
| throw new Error("Invalid daemon SSE URL returned by command invocation."); | ||
| } | ||
| if (parsed.protocol !== "http:" && parsed.protocol !== "https:") { | ||
| throw new Error(`Unsupported daemon SSE URL protocol: ${parsed.protocol}`); | ||
| } | ||
| const urlToken = parsed.searchParams.get("token"); | ||
| if (!urlToken || urlToken !== expectedToken) { | ||
| throw new Error("Daemon SSE URL token mismatch."); | ||
| } | ||
| const parsedPort = parsed.port ? Number(parsed.port) : NaN; | ||
| if (!Number.isFinite(parsedPort) || parsedPort <= 0) { | ||
| throw new Error("Daemon SSE URL must include a valid port."); | ||
| } | ||
| const providerBaseUrl = await this.methods.getUrl(this.sandbox, { port: parsedPort }); | ||
| const providerUrl = new URL(providerBaseUrl); | ||
| parsed = new URL(providerUrl.toString()); | ||
| parsed.pathname = "/events"; | ||
| parsed.search = `?token=${encodeURIComponent(expectedToken)}`; | ||
| parsed.hash = ""; | ||
| return parsed.toString(); | ||
| } | ||
| async runCommand(command, options) { | ||
| if (options?.daemon) { | ||
| if (options.background) { | ||
| throw new Error("runCommand({ daemon: true }) does not support background mode."); | ||
| } | ||
| const daemonPayload = { | ||
| command: "sh", | ||
| args: ["-lc", command], | ||
| cwd: options.cwd, | ||
| env: options.env, | ||
| timeoutMs: options.timeout, | ||
| requestId: createDaemonRequestId() | ||
| }; | ||
| const daemonConfig = typeof options.daemon === "object" ? options.daemon : {}; | ||
| const normalizedDaemonConfig = { | ||
| ...daemonConfig, | ||
| ssePort: daemonConfig.ssePort ?? DEFAULT_DAEMON_SSE_PORT | ||
| }; | ||
| const daemonCommand = (0, import_daemond.daemonSeedScriptCommand)( | ||
| normalizedDaemonConfig, | ||
| daemonPayload | ||
| ); | ||
| const forwardedOptions = { ...options }; | ||
| delete forwardedOptions.daemon; | ||
| delete forwardedOptions.onStdout; | ||
| delete forwardedOptions.onStderr; | ||
| const requestIdFilter = { current: daemonPayload.requestId }; | ||
| let streamStdout = ""; | ||
| let streamStderr = ""; | ||
| const streamController = new AbortController(); | ||
| let streamPromise; | ||
| let streamFinalized = false; | ||
| const finalizeStream = async () => { | ||
| if (streamFinalized) return; | ||
| streamFinalized = true; | ||
| streamController.abort(); | ||
| if (streamPromise) { | ||
| await streamPromise; | ||
| } | ||
| }; | ||
| if ((options.onStdout || options.onStderr) && this.daemonStreamState?.rawSseUrl) { | ||
| streamPromise = this.resolveDaemonSseUrl( | ||
| this.daemonStreamState.rawSseUrl, | ||
| this.daemonStreamState.token | ||
| ).then((sseUrl) => streamDaemonEvents( | ||
| sseUrl, | ||
| requestIdFilter, | ||
| { | ||
| onStdout: options.onStdout, | ||
| onStderr: options.onStderr, | ||
| markStdout: (chunk) => { | ||
| if (chunk) streamStdout += chunk; | ||
| }, | ||
| markStderr: (chunk) => { | ||
| if (chunk) streamStderr += chunk; | ||
| } | ||
| }, | ||
| streamController.signal | ||
| )).then(() => void 0).catch((error) => { | ||
| if (isExpectedDaemonStreamError(error)) { | ||
| return; | ||
| } | ||
| throw error; | ||
| }); | ||
| } | ||
| try { | ||
| const daemonResult = await this.methods.runCommand(this.sandbox, daemonCommand, forwardedOptions); | ||
| const invocation = (0, import_daemond.parseSeedInvocationOutput)(daemonResult.stdout); | ||
| this.daemonStreamState = { | ||
| token: invocation.token, | ||
| rawSseUrl: invocation.daemon.sseUrl | ||
| }; | ||
| await finalizeStream(); | ||
| if (options.onStdout) { | ||
| emitMissingOutput(streamStdout, invocation.command.stdout, options.onStdout); | ||
| } | ||
| if (options.onStderr) { | ||
| emitMissingOutput(streamStderr, invocation.command.stderr, options.onStderr); | ||
| } | ||
| return { | ||
| stdout: invocation.command.stdout, | ||
| stderr: invocation.command.stderr, | ||
| exitCode: invocation.command.exitCode ?? -1, | ||
| durationMs: daemonResult.durationMs | ||
| }; | ||
| } finally { | ||
| await finalizeStream(); | ||
| } | ||
| } | ||
| return await this.methods.runCommand(this.sandbox, command, options); | ||
@@ -106,0 +342,0 @@ } |
+239
-0
| // src/factory.ts | ||
| import { | ||
| daemonSeedScriptCommand, | ||
| parseSeedInvocationOutput | ||
| } from "daemond"; | ||
| var DEFAULT_DAEMON_SSE_PORT = 38989; | ||
| function createDaemonRequestId() { | ||
| if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { | ||
| return crypto.randomUUID(); | ||
| } | ||
| return `req_${Date.now()}_${Math.random().toString(16).slice(2)}`; | ||
| } | ||
| function emitMissingOutput(emitted, finalOutput, emit) { | ||
| if (!finalOutput) return; | ||
| if (!emitted) { | ||
| emit(finalOutput); | ||
| return; | ||
| } | ||
| if (finalOutput.startsWith(emitted)) { | ||
| const missing = finalOutput.slice(emitted.length); | ||
| if (missing) emit(missing); | ||
| return; | ||
| } | ||
| if (finalOutput.includes(emitted)) { | ||
| return; | ||
| } | ||
| if (emitted.includes(finalOutput)) { | ||
| return; | ||
| } | ||
| if (!emitted.includes(finalOutput)) { | ||
| emit(finalOutput); | ||
| } | ||
| } | ||
| function parseSseDataLines(raw) { | ||
| const chunks = raw.split(/\n\n+/); | ||
| const out = []; | ||
| for (const chunk of chunks) { | ||
| const lines = chunk.split("\n"); | ||
| for (const line of lines) { | ||
| if (line.startsWith("data:")) { | ||
| out.push(line.slice(5).trim()); | ||
| } | ||
| } | ||
| } | ||
| return out; | ||
| } | ||
| function pickString(source, keys) { | ||
| if (!source) return void 0; | ||
| for (const key of keys) { | ||
| const value = source[key]; | ||
| if (typeof value === "string") return value; | ||
| } | ||
| return void 0; | ||
| } | ||
| function normalizeDaemonStreamEvent(payload) { | ||
| if (!payload || typeof payload !== "object") return {}; | ||
| const record = payload; | ||
| const data = record.data && typeof record.data === "object" ? record.data : void 0; | ||
| const type = pickString(record, ["type", "event"]); | ||
| const requestId = pickString(record, ["requestId"]) ?? pickString(data, ["requestId"]); | ||
| const stdout = pickString(record, ["stdout", "output", "chunk"]) ?? pickString(data, ["stdout", "output", "chunk"]); | ||
| const stderr = pickString(record, ["stderr"]) ?? pickString(data, ["stderr"]); | ||
| return { type, requestId, stdout, stderr }; | ||
| } | ||
| function isExpectedDaemonStreamError(error) { | ||
| if (!error) return false; | ||
| if (error instanceof DOMException && error.name === "AbortError") { | ||
| return true; | ||
| } | ||
| if (error instanceof TypeError) { | ||
| return true; | ||
| } | ||
| if (error instanceof Error) { | ||
| if (error.name === "AbortError") { | ||
| return true; | ||
| } | ||
| const message = error.message.toLowerCase(); | ||
| if (message.includes("failed to open daemon event stream")) { | ||
| return true; | ||
| } | ||
| if (message.includes("fetch") || message.includes("network")) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| async function streamDaemonEvents(sseUrl, requestIdFilter, callbacks, signal) { | ||
| const response = await fetch(sseUrl, { signal }); | ||
| if (!response.ok || !response.body) { | ||
| throw new Error(`Failed to open daemon event stream: ${response.status}`); | ||
| } | ||
| const reader = response.body.getReader(); | ||
| const decoder = new TextDecoder(); | ||
| let buffer = ""; | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (done) break; | ||
| buffer += decoder.decode(value, { stream: true }); | ||
| const frames = buffer.split("\n\n"); | ||
| buffer = frames.pop() ?? ""; | ||
| for (const frame of frames) { | ||
| const dataLines = parseSseDataLines(frame); | ||
| for (const dataLine of dataLines) { | ||
| let parsed; | ||
| try { | ||
| parsed = JSON.parse(dataLine); | ||
| } catch { | ||
| continue; | ||
| } | ||
| const event = normalizeDaemonStreamEvent(parsed); | ||
| if (requestIdFilter.current && event.requestId !== requestIdFilter.current) { | ||
| continue; | ||
| } | ||
| if ((event.type === "command.stdout" || !event.type) && event.stdout && callbacks.onStdout) { | ||
| callbacks.markStdout(event.stdout); | ||
| callbacks.onStdout(event.stdout); | ||
| } | ||
| const stderrChunk = event.stderr ?? (event.type === "command.stderr" ? event.stdout : void 0); | ||
| if ((event.type === "command.stderr" || !event.type) && stderrChunk && callbacks.onStderr) { | ||
| callbacks.markStderr(stderrChunk); | ||
| callbacks.onStderr(stderrChunk); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| var UnsupportedFileSystem = class { | ||
@@ -71,3 +196,117 @@ constructor(providerName) { | ||
| } | ||
| async resolveDaemonSseUrl(rawUrl, expectedToken) { | ||
| let parsed; | ||
| try { | ||
| parsed = new URL(rawUrl); | ||
| } catch { | ||
| throw new Error("Invalid daemon SSE URL returned by command invocation."); | ||
| } | ||
| if (parsed.protocol !== "http:" && parsed.protocol !== "https:") { | ||
| throw new Error(`Unsupported daemon SSE URL protocol: ${parsed.protocol}`); | ||
| } | ||
| const urlToken = parsed.searchParams.get("token"); | ||
| if (!urlToken || urlToken !== expectedToken) { | ||
| throw new Error("Daemon SSE URL token mismatch."); | ||
| } | ||
| const parsedPort = parsed.port ? Number(parsed.port) : NaN; | ||
| if (!Number.isFinite(parsedPort) || parsedPort <= 0) { | ||
| throw new Error("Daemon SSE URL must include a valid port."); | ||
| } | ||
| const providerBaseUrl = await this.methods.getUrl(this.sandbox, { port: parsedPort }); | ||
| const providerUrl = new URL(providerBaseUrl); | ||
| parsed = new URL(providerUrl.toString()); | ||
| parsed.pathname = "/events"; | ||
| parsed.search = `?token=${encodeURIComponent(expectedToken)}`; | ||
| parsed.hash = ""; | ||
| return parsed.toString(); | ||
| } | ||
| async runCommand(command, options) { | ||
| if (options?.daemon) { | ||
| if (options.background) { | ||
| throw new Error("runCommand({ daemon: true }) does not support background mode."); | ||
| } | ||
| const daemonPayload = { | ||
| command: "sh", | ||
| args: ["-lc", command], | ||
| cwd: options.cwd, | ||
| env: options.env, | ||
| timeoutMs: options.timeout, | ||
| requestId: createDaemonRequestId() | ||
| }; | ||
| const daemonConfig = typeof options.daemon === "object" ? options.daemon : {}; | ||
| const normalizedDaemonConfig = { | ||
| ...daemonConfig, | ||
| ssePort: daemonConfig.ssePort ?? DEFAULT_DAEMON_SSE_PORT | ||
| }; | ||
| const daemonCommand = daemonSeedScriptCommand( | ||
| normalizedDaemonConfig, | ||
| daemonPayload | ||
| ); | ||
| const forwardedOptions = { ...options }; | ||
| delete forwardedOptions.daemon; | ||
| delete forwardedOptions.onStdout; | ||
| delete forwardedOptions.onStderr; | ||
| const requestIdFilter = { current: daemonPayload.requestId }; | ||
| let streamStdout = ""; | ||
| let streamStderr = ""; | ||
| const streamController = new AbortController(); | ||
| let streamPromise; | ||
| let streamFinalized = false; | ||
| const finalizeStream = async () => { | ||
| if (streamFinalized) return; | ||
| streamFinalized = true; | ||
| streamController.abort(); | ||
| if (streamPromise) { | ||
| await streamPromise; | ||
| } | ||
| }; | ||
| if ((options.onStdout || options.onStderr) && this.daemonStreamState?.rawSseUrl) { | ||
| streamPromise = this.resolveDaemonSseUrl( | ||
| this.daemonStreamState.rawSseUrl, | ||
| this.daemonStreamState.token | ||
| ).then((sseUrl) => streamDaemonEvents( | ||
| sseUrl, | ||
| requestIdFilter, | ||
| { | ||
| onStdout: options.onStdout, | ||
| onStderr: options.onStderr, | ||
| markStdout: (chunk) => { | ||
| if (chunk) streamStdout += chunk; | ||
| }, | ||
| markStderr: (chunk) => { | ||
| if (chunk) streamStderr += chunk; | ||
| } | ||
| }, | ||
| streamController.signal | ||
| )).then(() => void 0).catch((error) => { | ||
| if (isExpectedDaemonStreamError(error)) { | ||
| return; | ||
| } | ||
| throw error; | ||
| }); | ||
| } | ||
| try { | ||
| const daemonResult = await this.methods.runCommand(this.sandbox, daemonCommand, forwardedOptions); | ||
| const invocation = parseSeedInvocationOutput(daemonResult.stdout); | ||
| this.daemonStreamState = { | ||
| token: invocation.token, | ||
| rawSseUrl: invocation.daemon.sseUrl | ||
| }; | ||
| await finalizeStream(); | ||
| if (options.onStdout) { | ||
| emitMissingOutput(streamStdout, invocation.command.stdout, options.onStdout); | ||
| } | ||
| if (options.onStderr) { | ||
| emitMissingOutput(streamStderr, invocation.command.stderr, options.onStderr); | ||
| } | ||
| return { | ||
| stdout: invocation.command.stdout, | ||
| stderr: invocation.command.stderr, | ||
| exitCode: invocation.command.exitCode ?? -1, | ||
| durationMs: daemonResult.durationMs | ||
| }; | ||
| } finally { | ||
| await finalizeStream(); | ||
| } | ||
| } | ||
| return await this.methods.runCommand(this.sandbox, command, options); | ||
@@ -74,0 +313,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/factory.ts","../src/infra-factory.ts","../src/compute.ts","../src/browser-factory.ts","../src/utils.ts"],"sourcesContent":["/**\n * Provider Factory - Creates providers from method definitions\n * \n * Eliminates boilerplate by auto-generating Provider/Sandbox classes\n * from simple method definitions with automatic feature detection.\n */\n\n// Import all types from local types\nimport type {\n CreateSandboxOptions,\n FileEntry,\n RunCommandOptions,\n SandboxFileSystem,\n Provider,\n ProviderSandboxManager,\n ProviderTemplateManager,\n ProviderSnapshotManager,\n ProviderSandbox,\n SandboxInfo,\n CommandResult,\n CreateSnapshotOptions,\n ListSnapshotsOptions,\n CreateTemplateOptions,\n ListTemplatesOptions,\n} from './types/index.js';\n\n/**\n * Flat sandbox method implementations - all operations in one place\n */\nexport interface SandboxMethods<TSandbox = any, TConfig = any> {\n // Collection operations (map to compute.sandbox.*)\n create: (config: TConfig, options?: CreateSandboxOptions) => Promise<{ sandbox: TSandbox; sandboxId: string }>;\n getById: (config: TConfig, sandboxId: string) => Promise<{ sandbox: TSandbox; sandboxId: string } | null>;\n list: (config: TConfig) => Promise<Array<{ sandbox: TSandbox; sandboxId: string }>>;\n destroy: (config: TConfig, sandboxId: string) => Promise<void>;\n\n // Instance operations\n runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>;\n getInfo: (sandbox: TSandbox) => Promise<SandboxInfo>;\n getUrl: (sandbox: TSandbox, options: { port: number; protocol?: string }) => Promise<string>;\n\n // Optional provider-specific typed getInstance method\n getInstance?: (sandbox: TSandbox) => TSandbox;\n\n // Optional filesystem methods\n filesystem?: {\n readFile: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<string>;\n writeFile: (sandbox: TSandbox, path: string, content: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<void>;\n mkdir: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<void>;\n readdir: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<FileEntry[]>;\n exists: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<boolean>;\n remove: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<void>;\n };\n}\n\n/**\n * Template method implementations\n */\nexport interface TemplateMethods<TTemplate = any, TConfig = any, TCreateOptions extends CreateTemplateOptions = CreateTemplateOptions> {\n create: (config: TConfig, options: TCreateOptions) => Promise<TTemplate>;\n list: (config: TConfig, options?: ListTemplatesOptions) => Promise<TTemplate[]>;\n delete: (config: TConfig, templateId: string) => Promise<void>;\n}\n\n/**\n * Snapshot method implementations \n */\nexport interface SnapshotMethods<TSnapshot = any, TConfig = any> {\n create: (config: TConfig, sandboxId: string, options?: CreateSnapshotOptions) => Promise<TSnapshot>;\n list: (config: TConfig, options?: ListSnapshotsOptions) => Promise<TSnapshot[]>;\n delete: (config: TConfig, snapshotId: string) => Promise<void>;\n}\n\n/**\n * Provider configuration for defineProvider()\n */\nexport interface ProviderConfig<TSandbox = any, TConfig = any, TTemplate = any, TSnapshot = any> {\n name: string;\n methods: {\n sandbox: SandboxMethods<TSandbox, TConfig>;\n template?: TemplateMethods<TTemplate, TConfig>;\n snapshot?: SnapshotMethods<TSnapshot, TConfig>;\n };\n}\n\n/**\n * Auto-generated filesystem implementation that throws \"not supported\" errors\n */\nclass UnsupportedFileSystem implements SandboxFileSystem {\n private readonly providerName: string;\n\n constructor(providerName: string) {\n this.providerName = providerName;\n }\n\n async readFile(_path: string): Promise<string> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async writeFile(_path: string, _content: string): Promise<void> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async mkdir(_path: string): Promise<void> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async readdir(_path: string): Promise<FileEntry[]> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async exists(_path: string): Promise<boolean> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async remove(_path: string): Promise<void> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n}\n\n\n\n/**\n * Auto-generated filesystem implementation that wraps provider methods\n */\nclass SupportedFileSystem<TSandbox> implements SandboxFileSystem {\n constructor(\n private sandbox: TSandbox,\n private methods: NonNullable<SandboxMethods<TSandbox>['filesystem']>,\n private allMethods: SandboxMethods<TSandbox>\n ) {}\n\n async readFile(path: string): Promise<string> {\n return this.methods.readFile(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n return this.methods.writeFile(this.sandbox, path, content, this.allMethods.runCommand);\n }\n\n async mkdir(path: string): Promise<void> {\n return this.methods.mkdir(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async readdir(path: string): Promise<FileEntry[]> {\n return this.methods.readdir(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async exists(path: string): Promise<boolean> {\n return this.methods.exists(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async remove(path: string): Promise<void> {\n return this.methods.remove(this.sandbox, path, this.allMethods.runCommand);\n }\n}\n\n\n\n\n\n/**\n * Generated sandbox class - implements the ProviderSandbox interface\n */\nclass GeneratedSandbox<TSandbox = any> implements ProviderSandbox<TSandbox> {\n readonly sandboxId: string;\n readonly provider: string;\n readonly filesystem: SandboxFileSystem;\n constructor(\n private sandbox: TSandbox,\n sandboxId: string,\n providerName: string,\n private methods: SandboxMethods<TSandbox>,\n private config: any,\n private destroyMethod: (config: any, sandboxId: string) => Promise<void>,\n private providerInstance: Provider\n ) {\n this.sandboxId = sandboxId;\n this.provider = providerName;\n\n // Auto-detect filesystem support\n if (methods.filesystem) {\n this.filesystem = new SupportedFileSystem(sandbox, methods.filesystem, methods);\n } else {\n this.filesystem = new UnsupportedFileSystem(providerName);\n }\n }\n\n getInstance(): TSandbox {\n // Use provider-specific typed getInstance if available\n if (this.methods.getInstance) {\n return this.methods.getInstance(this.sandbox);\n }\n // Fallback to returning the sandbox directly\n return this.sandbox;\n }\n\n async runCommand(\n command: string,\n options?: RunCommandOptions\n ): Promise<CommandResult> {\n // Pass command and options directly to provider - no preprocessing\n // Provider is responsible for handling cwd, env, background, etc.\n return await this.methods.runCommand(this.sandbox, command, options);\n }\n\n async getInfo(): Promise<SandboxInfo> {\n return await this.methods.getInfo(this.sandbox);\n }\n\n async getUrl(options: { port: number; protocol?: string }): Promise<string> {\n return await this.methods.getUrl(this.sandbox, options);\n }\n\n getProvider(): Provider<TSandbox> {\n return this.providerInstance;\n }\n\n async destroy(): Promise<void> {\n // Destroy via the provider's destroy method using our sandboxId\n await this.destroyMethod(this.config, this.sandboxId);\n }\n}\n\n/**\n * Auto-generated Sandbox Manager implementation\n */\nclass GeneratedSandboxManager<TSandbox, TConfig> implements ProviderSandboxManager<TSandbox> {\n constructor(\n private config: TConfig,\n private providerName: string,\n private methods: SandboxMethods<TSandbox, TConfig>,\n private providerInstance: Provider\n ) {}\n\n async create(options?: CreateSandboxOptions): Promise<ProviderSandbox<TSandbox>> {\n const result = await this.methods.create(this.config, options);\n\n return new GeneratedSandbox<TSandbox>(\n result.sandbox,\n result.sandboxId,\n this.providerName,\n this.methods,\n this.config,\n this.methods.destroy,\n this.providerInstance\n );\n }\n\n async getById(sandboxId: string): Promise<ProviderSandbox<TSandbox> | null> {\n const result = await this.methods.getById(this.config, sandboxId);\n if (!result) {\n return null;\n }\n\n return new GeneratedSandbox<TSandbox>(\n result.sandbox,\n result.sandboxId,\n this.providerName,\n this.methods,\n this.config,\n this.methods.destroy,\n this.providerInstance\n );\n }\n\n async list(): Promise<ProviderSandbox<TSandbox>[]> {\n const results = await this.methods.list(this.config);\n \n return results.map(result => new GeneratedSandbox<TSandbox>(\n result.sandbox,\n result.sandboxId,\n this.providerName,\n this.methods,\n this.config,\n this.methods.destroy,\n this.providerInstance\n ));\n }\n\n async destroy(sandboxId: string): Promise<void> {\n await this.methods.destroy(this.config, sandboxId);\n }\n}\n\n/**\n * Auto-generated Template Manager implementation\n */\nclass GeneratedTemplateManager<TTemplate, TConfig, TCreateOptions extends CreateTemplateOptions = CreateTemplateOptions> implements ProviderTemplateManager<TTemplate, TCreateOptions> {\n constructor(\n private config: TConfig,\n private methods: TemplateMethods<TTemplate, TConfig, TCreateOptions>\n ) {}\n\n async create(options: TCreateOptions): Promise<TTemplate> {\n return await this.methods.create(this.config, options);\n }\n\n async list(options?: ListTemplatesOptions): Promise<TTemplate[]> {\n return await this.methods.list(this.config, options);\n }\n\n async delete(templateId: string): Promise<void> {\n return await this.methods.delete(this.config, templateId);\n }\n}\n\n/**\n * Auto-generated Snapshot Manager implementation\n */\nclass GeneratedSnapshotManager<TSnapshot, TConfig> implements ProviderSnapshotManager<TSnapshot> {\n constructor(\n private config: TConfig,\n private methods: SnapshotMethods<TSnapshot, TConfig>\n ) {}\n\n async create(sandboxId: string, options?: CreateSnapshotOptions): Promise<TSnapshot> {\n return await this.methods.create(this.config, sandboxId, options);\n }\n\n async list(options?: ListSnapshotsOptions): Promise<TSnapshot[]> {\n return await this.methods.list(this.config, options);\n }\n\n async delete(snapshotId: string): Promise<void> {\n return await this.methods.delete(this.config, snapshotId);\n }\n}\n\n/**\n * Auto-generated Provider implementation\n */\nclass GeneratedProvider<TSandbox, TConfig, TTemplate, TSnapshot> implements Provider<TSandbox, TTemplate, TSnapshot> {\n readonly name: string;\n readonly sandbox: ProviderSandboxManager<TSandbox>;\n readonly template?: ProviderTemplateManager<TTemplate>;\n readonly snapshot?: ProviderSnapshotManager<TSnapshot>;\n\n constructor(config: TConfig, providerConfig: ProviderConfig<TSandbox, TConfig, TTemplate, TSnapshot>) {\n this.name = providerConfig.name;\n this.sandbox = new GeneratedSandboxManager(\n config,\n providerConfig.name,\n providerConfig.methods.sandbox,\n this\n );\n\n // Initialize optional managers if methods are provided\n if (providerConfig.methods.template) {\n this.template = new GeneratedTemplateManager(config, providerConfig.methods.template);\n }\n \n if (providerConfig.methods.snapshot) {\n this.snapshot = new GeneratedSnapshotManager(config, providerConfig.methods.snapshot);\n }\n }\n}\n\n/**\n * Create a provider from method definitions\n *\n * Auto-generates all boilerplate classes and provides feature detection\n * based on which methods are implemented.\n */\nexport function defineProvider<TSandbox, TConfig = any, TTemplate = any, TSnapshot = any>(\n providerConfig: ProviderConfig<TSandbox, TConfig, TTemplate, TSnapshot>\n): (config: TConfig) => Provider<TSandbox, TTemplate, TSnapshot> {\n return (config: TConfig) => {\n return new GeneratedProvider(config, providerConfig);\n };\n}\n","/**\n * Infrastructure Provider Factory\n * \n * Creates infrastructure-only providers that provision compute resources\n * but don't have native sandbox capabilities. Used by gateway server.\n */\n\nimport type { CreateSandboxOptions } from './types/index.js';\n\n/**\n * Infrastructure provider methods - only resource provisioning\n */\nexport interface InfraProviderMethods<TInstance = any, TConfig = any> {\n /** Create a new compute instance */\n create: (config: TConfig, options?: CreateSandboxOptions & { daemonConfig?: DaemonConfig }) => Promise<{ instance: TInstance; instanceId: string }>;\n \n /** Get an existing instance by ID */\n getById: (config: TConfig, instanceId: string) => Promise<{ instance: TInstance; instanceId: string } | null>;\n \n /** List all instances */\n list: (config: TConfig) => Promise<Array<{ instance: TInstance; instanceId: string }>>;\n \n /** Destroy an instance */\n destroy: (config: TConfig, instanceId: string) => Promise<void>;\n}\n\n/**\n * Daemon configuration passed to infrastructure providers\n */\nexport interface DaemonConfig {\n /** Access token for daemon authentication */\n accessToken: string;\n /** Gateway URL for daemon to connect to */\n gatewayUrl?: string;\n /** Additional daemon environment variables */\n env?: Record<string, string>;\n}\n\n/**\n * Infrastructure provider configuration\n */\nexport interface InfraProviderConfig<TInstance = any, TConfig = any> {\n name: string;\n methods: InfraProviderMethods<TInstance, TConfig>;\n}\n\n/**\n * Infrastructure provider interface returned by defineInfraProvider\n */\nexport interface InfraProvider<TInstance = any> {\n name: string;\n create: (options?: CreateSandboxOptions & { daemonConfig?: DaemonConfig }) => Promise<{ instance: TInstance; instanceId: string }>;\n getById: (instanceId: string) => Promise<{ instance: TInstance; instanceId: string } | null>;\n list: () => Promise<Array<{ instance: TInstance; instanceId: string }>>;\n destroy: (instanceId: string) => Promise<void>;\n}\n\n/**\n * Create an infrastructure provider from method definitions\n * \n * Infrastructure providers only handle resource provisioning.\n * The gateway server uses these to create VMs/containers with the ComputeSDK daemon pre-installed.\n * \n * @example\n * ```typescript\n * export const railway = defineInfraProvider<RailwayInstance, RailwayConfig>({\n * name: 'railway',\n * methods: {\n * create: async (config, options) => {\n * // Create Railway service with daemon docker image\n * const service = await railwayAPI.createService({\n * ...config,\n * image: 'computesdk/daemon:latest',\n * env: options?.daemonConfig ? {\n * COMPUTESDK_ACCESS_TOKEN: options.daemonConfig.accessToken,\n * COMPUTESDK_GATEWAY_URL: options.daemonConfig.gatewayUrl,\n * } : {}\n * });\n * return { instance: service, instanceId: service.id };\n * },\n * destroy: async (config, instanceId) => {\n * await railwayAPI.deleteService(config, instanceId);\n * },\n * getById: async (config, instanceId) => {\n * const service = await railwayAPI.getService(config, instanceId);\n * return service ? { instance: service, instanceId: service.id } : null;\n * },\n * list: async (config) => {\n * const services = await railwayAPI.listServices(config);\n * return services.map(s => ({ instance: s, instanceId: s.id }));\n * }\n * }\n * });\n * \n * // Gateway server usage:\n * const provider = railway({ apiKey, projectId, environmentId });\n * const { instance, instanceId } = await provider.create({\n * daemonConfig: { accessToken: 'token_xxx' }\n * });\n * ```\n */\nexport function defineInfraProvider<TInstance, TConfig = any>(\n config: InfraProviderConfig<TInstance, TConfig>\n): (providerConfig: TConfig) => InfraProvider<TInstance> {\n return (providerConfig: TConfig) => {\n return {\n name: config.name,\n \n create: async (options) => {\n return await config.methods.create(providerConfig, options);\n },\n \n getById: async (instanceId) => {\n return await config.methods.getById(providerConfig, instanceId);\n },\n \n list: async () => {\n return await config.methods.list(providerConfig);\n },\n \n destroy: async (instanceId) => {\n await config.methods.destroy(providerConfig, instanceId);\n }\n };\n };\n}\n","/**\n * Direct Mode Compute API\n * \n * Use this when you want to use providers directly without the gateway.\n * This is the \"mother\" talking directly to \"children\" providers.\n */\n\nimport type { Provider } from './types';\n\n/**\n * Configuration for creating a compute instance with a provider\n */\nexport interface CreateComputeConfig<TInstance = any> {\n /** The provider instance to use */\n defaultProvider?: Provider<TInstance>;\n /** Legacy alias for defaultProvider */\n provider?: Provider<TInstance>;\n}\n\n/**\n * Compute API for direct provider usage\n */\nexport interface ComputeAPI<TInstance = any> {\n /** Sandbox management methods */\n sandbox: Provider<TInstance>['sandbox'];\n /** Get current configuration */\n getConfig(): CreateComputeConfig<TInstance> | null;\n /** Update configuration and return new compute instance */\n setConfig<TNewInstance = any>(config: CreateComputeConfig<TNewInstance>): ComputeAPI<TNewInstance>;\n /** Clear configuration */\n clearConfig(): void;\n}\n\n/**\n * Create a compute instance with a provider for direct mode\n * \n * @example\n * ```typescript\n * import { createCompute } from '@computesdk/provider';\n * import { e2bProvider } from '@computesdk/e2b';\n * \n * const provider = e2bProvider({ apiKey: 'your-key' });\n * const compute = createCompute({ defaultProvider: provider });\n * \n * const sandbox = await compute.sandbox.create();\n * ```\n */\nexport function createCompute<TInstance = any>(\n config: CreateComputeConfig<TInstance>\n): ComputeAPI<TInstance> {\n const provider = config.defaultProvider || config.provider;\n \n if (!provider) {\n throw new Error(\n 'createCompute requires a provider for direct mode. ' +\n 'Pass a provider via the defaultProvider or provider config property. ' +\n 'For gateway mode, do not use createCompute; use the compute singleton from computesdk instead.'\n );\n }\n\n let currentConfig: CreateComputeConfig<TInstance> | null = config;\n\n return {\n sandbox: provider.sandbox,\n \n getConfig() {\n return currentConfig;\n },\n \n setConfig<TNewInstance = any>(newConfig: CreateComputeConfig<TNewInstance>): ComputeAPI<TNewInstance> {\n return createCompute(newConfig);\n },\n \n clearConfig() {\n currentConfig = null;\n }\n };\n}\n","/**\n * Browser Provider Factory - Creates browser providers from method definitions\n *\n * Eliminates boilerplate by auto-generating BrowserProvider/Session classes\n * from simple method definitions with automatic feature detection.\n * Mirrors the sandbox provider factory pattern.\n */\n\nimport type {\n BrowserProvider,\n BrowserSessionManager,\n BrowserProfileManager,\n BrowserExtensionManager,\n BrowserPoolManager,\n BrowserLogManager,\n BrowserRecordingManager,\n BrowserPageOperations,\n ProviderBrowserSession,\n BrowserSession,\n BrowserProfile,\n BrowserExtension,\n BrowserPool,\n BrowserLog,\n BrowserRecording,\n CreateBrowserSessionOptions,\n CreateBrowserProfileOptions,\n CreateBrowserExtensionOptions,\n CreateBrowserPoolOptions,\n ScreenshotOptions,\n PdfOptions,\n} from './types/browser.js';\n\n// ─── Method Definitions ──────────────────────────────────────────────────────\n\n/**\n * Session method implementations that provider authors supply\n */\nexport interface BrowserSessionMethods<TSession = any, TConfig = any> {\n create: (config: TConfig, options?: CreateBrowserSessionOptions) => Promise<{ session: TSession; sessionId: string; connectUrl: string; status?: BrowserSession['status'] }>;\n getById: (config: TConfig, sessionId: string) => Promise<{ session: TSession; sessionId: string; connectUrl: string; status?: BrowserSession['status'] } | null>;\n /**\n * List sessions. `connectUrl` may be omitted on entries when the provider's\n * list endpoint doesn't include it — callers needing a connectable URL\n * should use `provider.getConnectUrl(sessionId)`.\n */\n list: (config: TConfig) => Promise<Array<{ session: TSession; sessionId: string; connectUrl?: string; status?: BrowserSession['status'] }>>;\n destroy: (config: TConfig, sessionId: string) => Promise<void>;\n getConnectUrl: (config: TConfig, sessionId: string) => Promise<string>;\n}\n\n/**\n * Profile method implementations\n */\nexport interface BrowserProfileMethods<TConfig = any> {\n create: (config: TConfig, options?: CreateBrowserProfileOptions) => Promise<BrowserProfile>;\n get: (config: TConfig, profileId: string) => Promise<BrowserProfile | null>;\n list: (config: TConfig) => Promise<BrowserProfile[]>;\n delete: (config: TConfig, profileId: string) => Promise<void>;\n}\n\n/**\n * Extension method implementations\n */\nexport interface BrowserExtensionMethods<TConfig = any> {\n create: (config: TConfig, options: CreateBrowserExtensionOptions) => Promise<BrowserExtension>;\n get: (config: TConfig, extensionId: string) => Promise<BrowserExtension | null>;\n delete: (config: TConfig, extensionId: string) => Promise<void>;\n}\n\n/**\n * Pool method implementations\n */\nexport interface BrowserPoolMethods<TSession = any, TConfig = any> {\n create: (config: TConfig, options: CreateBrowserPoolOptions) => Promise<BrowserPool>;\n get: (config: TConfig, poolId: string) => Promise<BrowserPool | null>;\n list: (config: TConfig) => Promise<BrowserPool[]>;\n acquire: (config: TConfig, poolId: string) => Promise<{ session: TSession; sessionId: string; connectUrl: string }>;\n release: (config: TConfig, poolId: string, sessionId: string) => Promise<void>;\n delete: (config: TConfig, poolId: string) => Promise<void>;\n}\n\n/**\n * Log method implementations\n */\nexport interface BrowserLogMethods<TConfig = any> {\n list: (config: TConfig, sessionId: string) => Promise<BrowserLog[]>;\n}\n\n/**\n * Recording method implementations\n */\nexport interface BrowserRecordingMethods<TConfig = any> {\n get: (config: TConfig, sessionId: string) => Promise<BrowserRecording | null>;\n}\n\n/**\n * Page operation method implementations\n */\nexport interface BrowserPageMethods<TSession = any> {\n navigate: (session: TSession, url: string) => Promise<void>;\n screenshot: (session: TSession, options?: ScreenshotOptions) => Promise<Uint8Array>;\n pdf?: (session: TSession, options?: PdfOptions) => Promise<Uint8Array>;\n evaluate: (session: TSession, script: string) => Promise<unknown>;\n getContent: (session: TSession) => Promise<string>;\n}\n\n/**\n * Full browser provider configuration for defineBrowserProvider()\n */\nexport interface BrowserProviderConfig<TSession = any, TConfig = any> {\n name: string;\n methods: {\n session: BrowserSessionMethods<TSession, TConfig>;\n profile?: BrowserProfileMethods<TConfig>;\n extension?: BrowserExtensionMethods<TConfig>;\n pool?: BrowserPoolMethods<TSession, TConfig>;\n logs?: BrowserLogMethods<TConfig>;\n recording?: BrowserRecordingMethods<TConfig>;\n page?: BrowserPageMethods<TSession>;\n };\n}\n\n// ─── Generated Classes ───────────────────────────────────────────────────────\n\n/**\n * Generated browser session — implements ProviderBrowserSession\n */\nclass GeneratedBrowserSession<TSession = any> implements ProviderBrowserSession<TSession> {\n readonly sessionId: string;\n readonly connectUrl?: string;\n readonly status: BrowserSession['status'];\n readonly createdAt?: Date;\n readonly metadata?: Record<string, unknown>;\n\n constructor(\n private session: TSession,\n sessionId: string,\n connectUrl: string | undefined,\n status: BrowserSession['status'] | undefined,\n private providerInstance: BrowserProvider<TSession>,\n private config: any,\n private sessionMethods: BrowserSessionMethods<TSession>,\n private logMethods?: BrowserLogMethods,\n private recordingMethods?: BrowserRecordingMethods,\n private pageMethods?: BrowserPageMethods<TSession>,\n ) {\n this.sessionId = sessionId;\n this.connectUrl = connectUrl;\n this.status = status ?? 'running';\n }\n\n getInstance(): TSession {\n return this.session;\n }\n\n getProvider(): BrowserProvider<TSession> {\n return this.providerInstance;\n }\n\n async destroy(): Promise<void> {\n await this.sessionMethods.destroy(this.config, this.sessionId);\n }\n\n async screenshot(options?: ScreenshotOptions): Promise<Uint8Array> {\n if (!this.pageMethods) {\n throw new Error(\n `Provider '${this.providerInstance.name}' does not support native page operations. ` +\n `Use the connectUrl to control the browser via Playwright/Puppeteer instead.`\n );\n }\n return this.pageMethods.screenshot(this.session, options);\n }\n\n async getLogs(): Promise<BrowserLog[]> {\n if (!this.logMethods) {\n throw new Error(`Provider '${this.providerInstance.name}' does not support log retrieval.`);\n }\n return this.logMethods.list(this.config, this.sessionId);\n }\n\n async getRecording(): Promise<BrowserRecording | null> {\n if (!this.recordingMethods) {\n throw new Error(`Provider '${this.providerInstance.name}' does not support recordings.`);\n }\n return this.recordingMethods.get(this.config, this.sessionId);\n }\n}\n\n/**\n * Generated session manager\n */\nclass GeneratedSessionManager<TSession, TConfig> implements BrowserSessionManager<TSession> {\n constructor(\n private config: TConfig,\n private methods: BrowserSessionMethods<TSession, TConfig>,\n private providerInstance: BrowserProvider<TSession>,\n private logMethods?: BrowserLogMethods<TConfig>,\n private recordingMethods?: BrowserRecordingMethods<TConfig>,\n private pageMethods?: BrowserPageMethods<TSession>,\n ) {}\n\n async create(options?: CreateBrowserSessionOptions): Promise<ProviderBrowserSession<TSession>> {\n const result = await this.methods.create(this.config, options);\n return new GeneratedBrowserSession(\n result.session, result.sessionId, result.connectUrl, result.status,\n this.providerInstance, this.config, this.methods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n );\n }\n\n async getById(sessionId: string): Promise<ProviderBrowserSession<TSession> | null> {\n const result = await this.methods.getById(this.config, sessionId);\n if (!result) return null;\n return new GeneratedBrowserSession(\n result.session, result.sessionId, result.connectUrl, result.status,\n this.providerInstance, this.config, this.methods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n );\n }\n\n async list(): Promise<ProviderBrowserSession<TSession>[]> {\n const results = await this.methods.list(this.config);\n return results.map(r => new GeneratedBrowserSession(\n r.session, r.sessionId, r.connectUrl, r.status,\n this.providerInstance, this.config, this.methods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n ));\n }\n\n async destroy(sessionId: string): Promise<void> {\n await this.methods.destroy(this.config, sessionId);\n }\n}\n\n/**\n * Generated profile manager\n */\nclass GeneratedProfileManager<TConfig> implements BrowserProfileManager {\n constructor(private config: TConfig, private methods: BrowserProfileMethods<TConfig>) {}\n\n async create(options?: CreateBrowserProfileOptions): Promise<BrowserProfile> {\n return this.methods.create(this.config, options);\n }\n async get(profileId: string): Promise<BrowserProfile | null> {\n return this.methods.get(this.config, profileId);\n }\n async list(): Promise<BrowserProfile[]> {\n return this.methods.list(this.config);\n }\n async delete(profileId: string): Promise<void> {\n return this.methods.delete(this.config, profileId);\n }\n}\n\n/**\n * Generated extension manager\n */\nclass GeneratedExtensionManager<TConfig> implements BrowserExtensionManager {\n constructor(private config: TConfig, private methods: BrowserExtensionMethods<TConfig>) {}\n\n async create(options: CreateBrowserExtensionOptions): Promise<BrowserExtension> {\n return this.methods.create(this.config, options);\n }\n async get(extensionId: string): Promise<BrowserExtension | null> {\n return this.methods.get(this.config, extensionId);\n }\n async delete(extensionId: string): Promise<void> {\n return this.methods.delete(this.config, extensionId);\n }\n}\n\n/**\n * Generated pool manager\n */\nclass GeneratedPoolManager<TSession, TConfig> implements BrowserPoolManager<TSession> {\n constructor(\n private config: TConfig,\n private methods: BrowserPoolMethods<TSession, TConfig>,\n private providerInstance: BrowserProvider<TSession>,\n private sessionMethods: BrowserSessionMethods<TSession, TConfig>,\n private logMethods?: BrowserLogMethods<TConfig>,\n private recordingMethods?: BrowserRecordingMethods<TConfig>,\n private pageMethods?: BrowserPageMethods<TSession>,\n ) {}\n\n async create(options: CreateBrowserPoolOptions): Promise<BrowserPool> {\n return this.methods.create(this.config, options);\n }\n async get(poolId: string): Promise<BrowserPool | null> {\n return this.methods.get(this.config, poolId);\n }\n async list(): Promise<BrowserPool[]> {\n return this.methods.list(this.config);\n }\n async acquire(poolId: string): Promise<ProviderBrowserSession<TSession>> {\n const result = await this.methods.acquire(this.config, poolId);\n return new GeneratedBrowserSession(\n result.session, result.sessionId, result.connectUrl, 'running',\n this.providerInstance, this.config, this.sessionMethods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n );\n }\n async release(poolId: string, sessionId: string): Promise<void> {\n return this.methods.release(this.config, poolId, sessionId);\n }\n async delete(poolId: string): Promise<void> {\n return this.methods.delete(this.config, poolId);\n }\n}\n\n/**\n * Generated page operations\n */\nclass GeneratedPageOperations<TSession> implements BrowserPageOperations<TSession> {\n pdf?: (session: TSession, options?: PdfOptions) => Promise<Uint8Array>;\n\n constructor(private methods: BrowserPageMethods<TSession>) {\n if (methods.pdf) {\n const pdfMethod = methods.pdf;\n this.pdf = (session: TSession, options?: PdfOptions) => pdfMethod(session, options);\n }\n }\n\n async navigate(session: TSession, url: string): Promise<void> {\n return this.methods.navigate(session, url);\n }\n async screenshot(session: TSession, options?: ScreenshotOptions): Promise<Uint8Array> {\n return this.methods.screenshot(session, options);\n }\n async evaluate(session: TSession, script: string): Promise<unknown> {\n return this.methods.evaluate(session, script);\n }\n async getContent(session: TSession): Promise<string> {\n return this.methods.getContent(session);\n }\n}\n\n/**\n * Generated browser provider\n */\nclass GeneratedBrowserProvider<TSession, TConfig> implements BrowserProvider<TSession> {\n readonly name: string;\n readonly session: BrowserSessionManager<TSession>;\n readonly profile?: BrowserProfileManager;\n readonly extension?: BrowserExtensionManager;\n readonly pool?: BrowserPoolManager;\n readonly logs?: BrowserLogManager;\n readonly recording?: BrowserRecordingManager;\n readonly page?: BrowserPageOperations<TSession>;\n\n private config: TConfig;\n private sessionMethods: BrowserSessionMethods<TSession, TConfig>;\n\n constructor(config: TConfig, providerConfig: BrowserProviderConfig<TSession, TConfig>) {\n this.name = providerConfig.name;\n this.config = config;\n this.sessionMethods = providerConfig.methods.session;\n\n const logMethods = providerConfig.methods.logs;\n const recordingMethods = providerConfig.methods.recording;\n const pageMethods = providerConfig.methods.page;\n\n // Session manager (always present)\n this.session = new GeneratedSessionManager(\n config, providerConfig.methods.session, this,\n logMethods, recordingMethods, pageMethods,\n );\n\n // Optional managers — auto-detected from provided methods\n if (providerConfig.methods.profile) {\n this.profile = new GeneratedProfileManager(config, providerConfig.methods.profile);\n }\n if (providerConfig.methods.extension) {\n this.extension = new GeneratedExtensionManager(config, providerConfig.methods.extension);\n }\n if (providerConfig.methods.pool) {\n this.pool = new GeneratedPoolManager(\n config, providerConfig.methods.pool, this,\n providerConfig.methods.session, logMethods, recordingMethods, pageMethods,\n );\n }\n if (logMethods) {\n this.logs = { list: (sessionId: string) => logMethods.list(config, sessionId) };\n }\n if (recordingMethods) {\n this.recording = { get: (sessionId: string) => recordingMethods.get(config, sessionId) };\n }\n if (pageMethods) {\n this.page = new GeneratedPageOperations(pageMethods);\n }\n }\n\n async getConnectUrl(sessionId: string): Promise<string> {\n return this.sessionMethods.getConnectUrl(this.config, sessionId);\n }\n}\n\n// ─── Public Factory ──────────────────────────────────────────────────────────\n\n/**\n * Create a browser provider from method definitions\n *\n * Auto-generates all boilerplate classes and provides feature detection\n * based on which methods are implemented.\n *\n * @example\n * ```ts\n * export const browserbase = defineBrowserProvider<BrowserbaseSession, BrowserbaseConfig>({\n * name: 'browserbase',\n * methods: {\n * session: { create, getById, list, destroy, getConnectUrl },\n * profile: { create, get, list, delete },\n * logs: { list: getLogs },\n * recording: { get: getRecording },\n * },\n * });\n *\n * // Usage:\n * const provider = browserbase({ apiKey: 'bb_...' });\n * const session = await provider.session.create({ stealth: true });\n * console.log(session.connectUrl);\n * ```\n */\nexport function defineBrowserProvider<TSession, TConfig = any>(\n providerConfig: BrowserProviderConfig<TSession, TConfig>\n): (config: TConfig) => BrowserProvider<TSession> {\n return (config: TConfig) => {\n return new GeneratedBrowserProvider(config, providerConfig);\n };\n}\n","/**\n * Utility functions for ComputeSDK\n */\n\n/**\n * Calculate exponential backoff delay with jitter\n * \n * Uses exponential backoff (2^attempt) multiplied by base delay,\n * plus random jitter to prevent thundering herd.\n * \n * @param attempt - Current retry attempt (0-indexed)\n * @param baseDelay - Base delay in milliseconds (default: 1000)\n * @param jitterMax - Maximum random jitter in milliseconds (default: 100)\n * @returns Delay in milliseconds\n * \n * @example\n * ```typescript\n * // First retry: 1000-1100ms\n * calculateBackoff(0);\n * \n * // Second retry: 2000-2100ms\n * calculateBackoff(1);\n * \n * // Third retry: 4000-4100ms\n * calculateBackoff(2);\n * ```\n */\nexport function calculateBackoff(\n attempt: number,\n baseDelay: number = 1000,\n jitterMax: number = 100\n): number {\n return baseDelay * Math.pow(2, attempt) + Math.random() * jitterMax;\n}\n\n/**\n * Escapes a string for safe use in shell commands\n * \n * Escapes special shell characters to prevent command injection.\n * Use this when interpolating user-controlled values into shell commands.\n * \n * @param arg - The string to escape\n * @returns Escaped string safe for shell interpolation\n * \n * @example\n * ```typescript\n * const path = '/path/with spaces';\n * const command = `cd \"${escapeShellArg(path)}\" && ls`;\n * // Result: cd \"/path/with\\ spaces\" && ls\n * \n * const env = { KEY: 'value with $pecial chars' };\n * const command = `KEY=\"${escapeShellArg(env.KEY)}\" npm run build`;\n * // Result: KEY=\"value with \\$pecial chars\" npm run build\n * ```\n */\nexport function escapeShellArg(arg: string): string {\n return arg\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/\"/g, '\\\\\"') // Escape double quotes\n .replace(/\\$/g, '\\\\$') // Escape dollar signs (variable expansion)\n .replace(/`/g, '\\\\`'); // Escape backticks (command substitution)\n}\n"],"mappings":"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","names":[]} | ||
| {"version":3,"sources":["../src/factory.ts","../src/infra-factory.ts","../src/compute.ts","../src/browser-factory.ts","../src/utils.ts"],"sourcesContent":["/**\n * Provider Factory - Creates providers from method definitions\n * \n * Eliminates boilerplate by auto-generating Provider/Sandbox classes\n * from simple method definitions with automatic feature detection.\n */\n\n// Import all types from local types\nimport type {\n CreateSandboxOptions,\n FileEntry,\n RunCommandOptions,\n SandboxFileSystem,\n Provider,\n ProviderSandboxManager,\n ProviderTemplateManager,\n ProviderSnapshotManager,\n ProviderSandbox,\n SandboxInfo,\n CommandResult,\n CreateSnapshotOptions,\n ListSnapshotsOptions,\n CreateTemplateOptions,\n ListTemplatesOptions,\n} from './types/index.js';\nimport {\n daemonSeedScriptCommand,\n parseSeedInvocationOutput,\n type SeedCommandInput,\n} from 'daemond';\n\ntype DaemonStreamState = {\n token: string;\n rawSseUrl: string;\n};\n\nconst DEFAULT_DAEMON_SSE_PORT = 38989;\n\nfunction createDaemonRequestId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `req_${Date.now()}_${Math.random().toString(16).slice(2)}`;\n}\n\nfunction emitMissingOutput(\n emitted: string,\n finalOutput: string,\n emit: (data: string) => void\n): void {\n if (!finalOutput) return;\n if (!emitted) {\n emit(finalOutput);\n return;\n }\n if (finalOutput.startsWith(emitted)) {\n const missing = finalOutput.slice(emitted.length);\n if (missing) emit(missing);\n return;\n }\n if (finalOutput.includes(emitted)) {\n return;\n }\n if (emitted.includes(finalOutput)) {\n return;\n }\n if (!emitted.includes(finalOutput)) {\n emit(finalOutput);\n }\n}\n\nfunction parseSseDataLines(raw: string): string[] {\n const chunks = raw.split(/\\n\\n+/);\n const out: string[] = [];\n for (const chunk of chunks) {\n const lines = chunk.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data:')) {\n out.push(line.slice(5).trim());\n }\n }\n }\n return out;\n}\n\nfunction pickString(source: Record<string, unknown> | undefined, keys: string[]): string | undefined {\n if (!source) return undefined;\n for (const key of keys) {\n const value = source[key];\n if (typeof value === 'string') return value;\n }\n return undefined;\n}\n\nfunction normalizeDaemonStreamEvent(payload: unknown): { type?: string; requestId?: string; stdout?: string; stderr?: string } {\n if (!payload || typeof payload !== 'object') return {};\n const record = payload as Record<string, unknown>;\n const data = (record.data && typeof record.data === 'object')\n ? (record.data as Record<string, unknown>)\n : undefined;\n const type = pickString(record, ['type', 'event']);\n const requestId = pickString(record, ['requestId']) ?? pickString(data, ['requestId']);\n const stdout = pickString(record, ['stdout', 'output', 'chunk']) ?? pickString(data, ['stdout', 'output', 'chunk']);\n const stderr = pickString(record, ['stderr']) ?? pickString(data, ['stderr']);\n return { type, requestId, stdout, stderr };\n}\n\nfunction isExpectedDaemonStreamError(error: unknown): boolean {\n if (!error) return false;\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n return true;\n }\n\n if (error instanceof TypeError) {\n return true;\n }\n\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n return true;\n }\n\n const message = error.message.toLowerCase();\n if (message.includes('failed to open daemon event stream')) {\n return true;\n }\n\n if (message.includes('fetch') || message.includes('network')) {\n return true;\n }\n }\n\n return false;\n}\n\nasync function streamDaemonEvents(\n sseUrl: string,\n requestIdFilter: { current?: string },\n callbacks: { onStdout?: (data: string) => void; onStderr?: (data: string) => void; markStdout: (chunk?: string) => void; markStderr: (chunk?: string) => void },\n signal: AbortSignal\n): Promise<void> {\n const response = await fetch(sseUrl, { signal });\n if (!response.ok || !response.body) {\n throw new Error(`Failed to open daemon event stream: ${response.status}`);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop() ?? '';\n\n for (const frame of frames) {\n const dataLines = parseSseDataLines(frame);\n for (const dataLine of dataLines) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(dataLine);\n } catch {\n continue;\n }\n const event = normalizeDaemonStreamEvent(parsed);\n if (requestIdFilter.current && event.requestId !== requestIdFilter.current) {\n continue;\n }\n if ((event.type === 'command.stdout' || !event.type) && event.stdout && callbacks.onStdout) {\n callbacks.markStdout(event.stdout);\n callbacks.onStdout(event.stdout);\n }\n const stderrChunk = event.stderr ?? (event.type === 'command.stderr' ? event.stdout : undefined);\n if ((event.type === 'command.stderr' || !event.type) && stderrChunk && callbacks.onStderr) {\n callbacks.markStderr(stderrChunk);\n callbacks.onStderr(stderrChunk);\n }\n }\n }\n }\n}\n\n/**\n * Flat sandbox method implementations - all operations in one place\n */\nexport interface SandboxMethods<TSandbox = any, TConfig = any> {\n // Collection operations (map to compute.sandbox.*)\n create: (config: TConfig, options?: CreateSandboxOptions) => Promise<{ sandbox: TSandbox; sandboxId: string }>;\n getById: (config: TConfig, sandboxId: string) => Promise<{ sandbox: TSandbox; sandboxId: string } | null>;\n list: (config: TConfig) => Promise<Array<{ sandbox: TSandbox; sandboxId: string }>>;\n destroy: (config: TConfig, sandboxId: string) => Promise<void>;\n\n // Instance operations\n runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>;\n getInfo: (sandbox: TSandbox) => Promise<SandboxInfo>;\n getUrl: (sandbox: TSandbox, options: { port: number; protocol?: string }) => Promise<string>;\n\n // Optional provider-specific typed getInstance method\n getInstance?: (sandbox: TSandbox) => TSandbox;\n\n // Optional filesystem methods\n filesystem?: {\n readFile: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<string>;\n writeFile: (sandbox: TSandbox, path: string, content: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<void>;\n mkdir: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<void>;\n readdir: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<FileEntry[]>;\n exists: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<boolean>;\n remove: (sandbox: TSandbox, path: string, runCommand: (sandbox: TSandbox, command: string, options?: RunCommandOptions) => Promise<CommandResult>) => Promise<void>;\n };\n}\n\n/**\n * Template method implementations\n */\nexport interface TemplateMethods<TTemplate = any, TConfig = any, TCreateOptions extends CreateTemplateOptions = CreateTemplateOptions> {\n create: (config: TConfig, options: TCreateOptions) => Promise<TTemplate>;\n list: (config: TConfig, options?: ListTemplatesOptions) => Promise<TTemplate[]>;\n delete: (config: TConfig, templateId: string) => Promise<void>;\n}\n\n/**\n * Snapshot method implementations \n */\nexport interface SnapshotMethods<TSnapshot = any, TConfig = any> {\n create: (config: TConfig, sandboxId: string, options?: CreateSnapshotOptions) => Promise<TSnapshot>;\n list: (config: TConfig, options?: ListSnapshotsOptions) => Promise<TSnapshot[]>;\n delete: (config: TConfig, snapshotId: string) => Promise<void>;\n}\n\n/**\n * Provider configuration for defineProvider()\n */\nexport interface ProviderConfig<TSandbox = any, TConfig = any, TTemplate = any, TSnapshot = any> {\n name: string;\n methods: {\n sandbox: SandboxMethods<TSandbox, TConfig>;\n template?: TemplateMethods<TTemplate, TConfig>;\n snapshot?: SnapshotMethods<TSnapshot, TConfig>;\n };\n}\n\n/**\n * Auto-generated filesystem implementation that throws \"not supported\" errors\n */\nclass UnsupportedFileSystem implements SandboxFileSystem {\n private readonly providerName: string;\n\n constructor(providerName: string) {\n this.providerName = providerName;\n }\n\n async readFile(_path: string): Promise<string> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async writeFile(_path: string, _content: string): Promise<void> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async mkdir(_path: string): Promise<void> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async readdir(_path: string): Promise<FileEntry[]> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async exists(_path: string): Promise<boolean> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n\n async remove(_path: string): Promise<void> {\n throw new Error(`Filesystem operations are not supported by ${this.providerName}'s sandbox environment. ${this.providerName} sandboxes are designed for code execution only.`);\n }\n}\n\n\n\n/**\n * Auto-generated filesystem implementation that wraps provider methods\n */\nclass SupportedFileSystem<TSandbox> implements SandboxFileSystem {\n constructor(\n private sandbox: TSandbox,\n private methods: NonNullable<SandboxMethods<TSandbox>['filesystem']>,\n private allMethods: SandboxMethods<TSandbox>\n ) {}\n\n async readFile(path: string): Promise<string> {\n return this.methods.readFile(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n return this.methods.writeFile(this.sandbox, path, content, this.allMethods.runCommand);\n }\n\n async mkdir(path: string): Promise<void> {\n return this.methods.mkdir(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async readdir(path: string): Promise<FileEntry[]> {\n return this.methods.readdir(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async exists(path: string): Promise<boolean> {\n return this.methods.exists(this.sandbox, path, this.allMethods.runCommand);\n }\n\n async remove(path: string): Promise<void> {\n return this.methods.remove(this.sandbox, path, this.allMethods.runCommand);\n }\n}\n\n\n\n\n\n/**\n * Generated sandbox class - implements the ProviderSandbox interface\n */\nclass GeneratedSandbox<TSandbox = any> implements ProviderSandbox<TSandbox> {\n readonly sandboxId: string;\n readonly provider: string;\n readonly filesystem: SandboxFileSystem;\n private daemonStreamState?: DaemonStreamState;\n constructor(\n private sandbox: TSandbox,\n sandboxId: string,\n providerName: string,\n private methods: SandboxMethods<TSandbox>,\n private config: any,\n private destroyMethod: (config: any, sandboxId: string) => Promise<void>,\n private providerInstance: Provider\n ) {\n this.sandboxId = sandboxId;\n this.provider = providerName;\n\n // Auto-detect filesystem support\n if (methods.filesystem) {\n this.filesystem = new SupportedFileSystem(sandbox, methods.filesystem, methods);\n } else {\n this.filesystem = new UnsupportedFileSystem(providerName);\n }\n }\n\n getInstance(): TSandbox {\n // Use provider-specific typed getInstance if available\n if (this.methods.getInstance) {\n return this.methods.getInstance(this.sandbox);\n }\n // Fallback to returning the sandbox directly\n return this.sandbox;\n }\n\n private async resolveDaemonSseUrl(\n rawUrl: string,\n expectedToken: string\n ): Promise<string> {\n let parsed: URL;\n try {\n parsed = new URL(rawUrl);\n } catch {\n throw new Error('Invalid daemon SSE URL returned by command invocation.');\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Unsupported daemon SSE URL protocol: ${parsed.protocol}`);\n }\n\n const urlToken = parsed.searchParams.get('token');\n if (!urlToken || urlToken !== expectedToken) {\n throw new Error('Daemon SSE URL token mismatch.');\n }\n\n const parsedPort = parsed.port ? Number(parsed.port) : NaN;\n if (!Number.isFinite(parsedPort) || parsedPort <= 0) {\n throw new Error('Daemon SSE URL must include a valid port.');\n }\n\n const providerBaseUrl = await this.methods.getUrl(this.sandbox, { port: parsedPort });\n const providerUrl = new URL(providerBaseUrl);\n\n parsed = new URL(providerUrl.toString());\n parsed.pathname = '/events';\n parsed.search = `?token=${encodeURIComponent(expectedToken)}`;\n parsed.hash = '';\n\n return parsed.toString();\n }\n\n async runCommand(\n command: string,\n options?: RunCommandOptions\n ): Promise<CommandResult> {\n if (options?.daemon) {\n if (options.background) {\n throw new Error('runCommand({ daemon: true }) does not support background mode.');\n }\n\n const daemonPayload: SeedCommandInput = {\n command: 'sh',\n args: ['-lc', command],\n cwd: options.cwd,\n env: options.env,\n timeoutMs: options.timeout,\n requestId: createDaemonRequestId(),\n };\n\n const daemonConfig = typeof options.daemon === 'object' ? options.daemon : {};\n const normalizedDaemonConfig = {\n ...daemonConfig,\n ssePort: daemonConfig.ssePort ?? DEFAULT_DAEMON_SSE_PORT,\n };\n\n const daemonCommand = daemonSeedScriptCommand(\n normalizedDaemonConfig,\n daemonPayload\n );\n\n const forwardedOptions: RunCommandOptions = { ...options };\n delete forwardedOptions.daemon;\n delete forwardedOptions.onStdout;\n delete forwardedOptions.onStderr;\n\n const requestIdFilter: { current?: string } = { current: daemonPayload.requestId };\n let streamStdout = '';\n let streamStderr = '';\n\n const streamController = new AbortController();\n let streamPromise: Promise<void> | undefined;\n let streamFinalized = false;\n const finalizeStream = async () => {\n if (streamFinalized) return;\n streamFinalized = true;\n streamController.abort();\n if (streamPromise) {\n await streamPromise;\n }\n };\n\n if ((options.onStdout || options.onStderr) && this.daemonStreamState?.rawSseUrl) {\n streamPromise = this.resolveDaemonSseUrl(\n this.daemonStreamState.rawSseUrl,\n this.daemonStreamState.token\n )\n .then((sseUrl) => streamDaemonEvents(\n sseUrl,\n requestIdFilter,\n {\n onStdout: options.onStdout,\n onStderr: options.onStderr,\n markStdout: (chunk?: string) => {\n if (chunk) streamStdout += chunk;\n },\n markStderr: (chunk?: string) => {\n if (chunk) streamStderr += chunk;\n },\n },\n streamController.signal\n ))\n .then(() => undefined)\n .catch((error) => {\n if (isExpectedDaemonStreamError(error)) {\n return;\n }\n throw error;\n });\n }\n try {\n const daemonResult = await this.methods.runCommand(this.sandbox, daemonCommand, forwardedOptions);\n const invocation = parseSeedInvocationOutput(daemonResult.stdout);\n this.daemonStreamState = {\n token: invocation.token,\n rawSseUrl: invocation.daemon.sseUrl,\n };\n\n await finalizeStream();\n\n if (options.onStdout) {\n emitMissingOutput(streamStdout, invocation.command.stdout, options.onStdout);\n }\n if (options.onStderr) {\n emitMissingOutput(streamStderr, invocation.command.stderr, options.onStderr);\n }\n\n return {\n stdout: invocation.command.stdout,\n stderr: invocation.command.stderr,\n exitCode: invocation.command.exitCode ?? -1,\n durationMs: daemonResult.durationMs,\n };\n } finally {\n await finalizeStream();\n }\n }\n\n // Pass command and options directly to provider - no preprocessing\n // Provider is responsible for handling cwd, env, background, etc.\n return await this.methods.runCommand(this.sandbox, command, options);\n }\n\n async getInfo(): Promise<SandboxInfo> {\n return await this.methods.getInfo(this.sandbox);\n }\n\n async getUrl(options: { port: number; protocol?: string }): Promise<string> {\n return await this.methods.getUrl(this.sandbox, options);\n }\n\n getProvider(): Provider<TSandbox> {\n return this.providerInstance;\n }\n\n async destroy(): Promise<void> {\n // Destroy via the provider's destroy method using our sandboxId\n await this.destroyMethod(this.config, this.sandboxId);\n }\n}\n\n/**\n * Auto-generated Sandbox Manager implementation\n */\nclass GeneratedSandboxManager<TSandbox, TConfig> implements ProviderSandboxManager<TSandbox> {\n constructor(\n private config: TConfig,\n private providerName: string,\n private methods: SandboxMethods<TSandbox, TConfig>,\n private providerInstance: Provider\n ) {}\n\n async create(options?: CreateSandboxOptions): Promise<ProviderSandbox<TSandbox>> {\n const result = await this.methods.create(this.config, options);\n\n return new GeneratedSandbox<TSandbox>(\n result.sandbox,\n result.sandboxId,\n this.providerName,\n this.methods,\n this.config,\n this.methods.destroy,\n this.providerInstance\n );\n }\n\n async getById(sandboxId: string): Promise<ProviderSandbox<TSandbox> | null> {\n const result = await this.methods.getById(this.config, sandboxId);\n if (!result) {\n return null;\n }\n\n return new GeneratedSandbox<TSandbox>(\n result.sandbox,\n result.sandboxId,\n this.providerName,\n this.methods,\n this.config,\n this.methods.destroy,\n this.providerInstance\n );\n }\n\n async list(): Promise<ProviderSandbox<TSandbox>[]> {\n const results = await this.methods.list(this.config);\n \n return results.map(result => new GeneratedSandbox<TSandbox>(\n result.sandbox,\n result.sandboxId,\n this.providerName,\n this.methods,\n this.config,\n this.methods.destroy,\n this.providerInstance\n ));\n }\n\n async destroy(sandboxId: string): Promise<void> {\n await this.methods.destroy(this.config, sandboxId);\n }\n}\n\n/**\n * Auto-generated Template Manager implementation\n */\nclass GeneratedTemplateManager<TTemplate, TConfig, TCreateOptions extends CreateTemplateOptions = CreateTemplateOptions> implements ProviderTemplateManager<TTemplate, TCreateOptions> {\n constructor(\n private config: TConfig,\n private methods: TemplateMethods<TTemplate, TConfig, TCreateOptions>\n ) {}\n\n async create(options: TCreateOptions): Promise<TTemplate> {\n return await this.methods.create(this.config, options);\n }\n\n async list(options?: ListTemplatesOptions): Promise<TTemplate[]> {\n return await this.methods.list(this.config, options);\n }\n\n async delete(templateId: string): Promise<void> {\n return await this.methods.delete(this.config, templateId);\n }\n}\n\n/**\n * Auto-generated Snapshot Manager implementation\n */\nclass GeneratedSnapshotManager<TSnapshot, TConfig> implements ProviderSnapshotManager<TSnapshot> {\n constructor(\n private config: TConfig,\n private methods: SnapshotMethods<TSnapshot, TConfig>\n ) {}\n\n async create(sandboxId: string, options?: CreateSnapshotOptions): Promise<TSnapshot> {\n return await this.methods.create(this.config, sandboxId, options);\n }\n\n async list(options?: ListSnapshotsOptions): Promise<TSnapshot[]> {\n return await this.methods.list(this.config, options);\n }\n\n async delete(snapshotId: string): Promise<void> {\n return await this.methods.delete(this.config, snapshotId);\n }\n}\n\n/**\n * Auto-generated Provider implementation\n */\nclass GeneratedProvider<TSandbox, TConfig, TTemplate, TSnapshot> implements Provider<TSandbox, TTemplate, TSnapshot> {\n readonly name: string;\n readonly sandbox: ProviderSandboxManager<TSandbox>;\n readonly template?: ProviderTemplateManager<TTemplate>;\n readonly snapshot?: ProviderSnapshotManager<TSnapshot>;\n\n constructor(config: TConfig, providerConfig: ProviderConfig<TSandbox, TConfig, TTemplate, TSnapshot>) {\n this.name = providerConfig.name;\n this.sandbox = new GeneratedSandboxManager(\n config,\n providerConfig.name,\n providerConfig.methods.sandbox,\n this\n );\n\n // Initialize optional managers if methods are provided\n if (providerConfig.methods.template) {\n this.template = new GeneratedTemplateManager(config, providerConfig.methods.template);\n }\n \n if (providerConfig.methods.snapshot) {\n this.snapshot = new GeneratedSnapshotManager(config, providerConfig.methods.snapshot);\n }\n }\n}\n\n/**\n * Create a provider from method definitions\n *\n * Auto-generates all boilerplate classes and provides feature detection\n * based on which methods are implemented.\n */\nexport function defineProvider<TSandbox, TConfig = any, TTemplate = any, TSnapshot = any>(\n providerConfig: ProviderConfig<TSandbox, TConfig, TTemplate, TSnapshot>\n): (config: TConfig) => Provider<TSandbox, TTemplate, TSnapshot> {\n return (config: TConfig) => {\n return new GeneratedProvider(config, providerConfig);\n };\n}\n","/**\n * Infrastructure Provider Factory\n * \n * Creates infrastructure-only providers that provision compute resources\n * but don't have native sandbox capabilities. Used by gateway server.\n */\n\nimport type { CreateSandboxOptions } from './types/index.js';\n\n/**\n * Infrastructure provider methods - only resource provisioning\n */\nexport interface InfraProviderMethods<TInstance = any, TConfig = any> {\n /** Create a new compute instance */\n create: (config: TConfig, options?: CreateSandboxOptions & { daemonConfig?: DaemonConfig }) => Promise<{ instance: TInstance; instanceId: string }>;\n \n /** Get an existing instance by ID */\n getById: (config: TConfig, instanceId: string) => Promise<{ instance: TInstance; instanceId: string } | null>;\n \n /** List all instances */\n list: (config: TConfig) => Promise<Array<{ instance: TInstance; instanceId: string }>>;\n \n /** Destroy an instance */\n destroy: (config: TConfig, instanceId: string) => Promise<void>;\n}\n\n/**\n * Daemon configuration passed to infrastructure providers\n */\nexport interface DaemonConfig {\n /** Access token for daemon authentication */\n accessToken: string;\n /** Gateway URL for daemon to connect to */\n gatewayUrl?: string;\n /** Additional daemon environment variables */\n env?: Record<string, string>;\n}\n\n/**\n * Infrastructure provider configuration\n */\nexport interface InfraProviderConfig<TInstance = any, TConfig = any> {\n name: string;\n methods: InfraProviderMethods<TInstance, TConfig>;\n}\n\n/**\n * Infrastructure provider interface returned by defineInfraProvider\n */\nexport interface InfraProvider<TInstance = any> {\n name: string;\n create: (options?: CreateSandboxOptions & { daemonConfig?: DaemonConfig }) => Promise<{ instance: TInstance; instanceId: string }>;\n getById: (instanceId: string) => Promise<{ instance: TInstance; instanceId: string } | null>;\n list: () => Promise<Array<{ instance: TInstance; instanceId: string }>>;\n destroy: (instanceId: string) => Promise<void>;\n}\n\n/**\n * Create an infrastructure provider from method definitions\n * \n * Infrastructure providers only handle resource provisioning.\n * The gateway server uses these to create VMs/containers with the ComputeSDK daemon pre-installed.\n * \n * @example\n * ```typescript\n * export const railway = defineInfraProvider<RailwayInstance, RailwayConfig>({\n * name: 'railway',\n * methods: {\n * create: async (config, options) => {\n * // Create Railway service with daemon docker image\n * const service = await railwayAPI.createService({\n * ...config,\n * image: 'computesdk/daemon:latest',\n * env: options?.daemonConfig ? {\n * COMPUTESDK_ACCESS_TOKEN: options.daemonConfig.accessToken,\n * COMPUTESDK_GATEWAY_URL: options.daemonConfig.gatewayUrl,\n * } : {}\n * });\n * return { instance: service, instanceId: service.id };\n * },\n * destroy: async (config, instanceId) => {\n * await railwayAPI.deleteService(config, instanceId);\n * },\n * getById: async (config, instanceId) => {\n * const service = await railwayAPI.getService(config, instanceId);\n * return service ? { instance: service, instanceId: service.id } : null;\n * },\n * list: async (config) => {\n * const services = await railwayAPI.listServices(config);\n * return services.map(s => ({ instance: s, instanceId: s.id }));\n * }\n * }\n * });\n * \n * // Gateway server usage:\n * const provider = railway({ apiKey, projectId, environmentId });\n * const { instance, instanceId } = await provider.create({\n * daemonConfig: { accessToken: 'token_xxx' }\n * });\n * ```\n */\nexport function defineInfraProvider<TInstance, TConfig = any>(\n config: InfraProviderConfig<TInstance, TConfig>\n): (providerConfig: TConfig) => InfraProvider<TInstance> {\n return (providerConfig: TConfig) => {\n return {\n name: config.name,\n \n create: async (options) => {\n return await config.methods.create(providerConfig, options);\n },\n \n getById: async (instanceId) => {\n return await config.methods.getById(providerConfig, instanceId);\n },\n \n list: async () => {\n return await config.methods.list(providerConfig);\n },\n \n destroy: async (instanceId) => {\n await config.methods.destroy(providerConfig, instanceId);\n }\n };\n };\n}\n","/**\n * Direct Mode Compute API\n * \n * Use this when you want to use providers directly without the gateway.\n * This is the \"mother\" talking directly to \"children\" providers.\n */\n\nimport type { Provider } from './types';\n\n/**\n * Configuration for creating a compute instance with a provider\n */\nexport interface CreateComputeConfig<TInstance = any> {\n /** The provider instance to use */\n defaultProvider?: Provider<TInstance>;\n /** Legacy alias for defaultProvider */\n provider?: Provider<TInstance>;\n}\n\n/**\n * Compute API for direct provider usage\n */\nexport interface ComputeAPI<TInstance = any> {\n /** Sandbox management methods */\n sandbox: Provider<TInstance>['sandbox'];\n /** Get current configuration */\n getConfig(): CreateComputeConfig<TInstance> | null;\n /** Update configuration and return new compute instance */\n setConfig<TNewInstance = any>(config: CreateComputeConfig<TNewInstance>): ComputeAPI<TNewInstance>;\n /** Clear configuration */\n clearConfig(): void;\n}\n\n/**\n * Create a compute instance with a provider for direct mode\n * \n * @example\n * ```typescript\n * import { createCompute } from '@computesdk/provider';\n * import { e2bProvider } from '@computesdk/e2b';\n * \n * const provider = e2bProvider({ apiKey: 'your-key' });\n * const compute = createCompute({ defaultProvider: provider });\n * \n * const sandbox = await compute.sandbox.create();\n * ```\n */\nexport function createCompute<TInstance = any>(\n config: CreateComputeConfig<TInstance>\n): ComputeAPI<TInstance> {\n const provider = config.defaultProvider || config.provider;\n \n if (!provider) {\n throw new Error(\n 'createCompute requires a provider for direct mode. ' +\n 'Pass a provider via the defaultProvider or provider config property. ' +\n 'For gateway mode, do not use createCompute; use the compute singleton from computesdk instead.'\n );\n }\n\n let currentConfig: CreateComputeConfig<TInstance> | null = config;\n\n return {\n sandbox: provider.sandbox,\n \n getConfig() {\n return currentConfig;\n },\n \n setConfig<TNewInstance = any>(newConfig: CreateComputeConfig<TNewInstance>): ComputeAPI<TNewInstance> {\n return createCompute(newConfig);\n },\n \n clearConfig() {\n currentConfig = null;\n }\n };\n}\n","/**\n * Browser Provider Factory - Creates browser providers from method definitions\n *\n * Eliminates boilerplate by auto-generating BrowserProvider/Session classes\n * from simple method definitions with automatic feature detection.\n * Mirrors the sandbox provider factory pattern.\n */\n\nimport type {\n BrowserProvider,\n BrowserSessionManager,\n BrowserProfileManager,\n BrowserExtensionManager,\n BrowserPoolManager,\n BrowserLogManager,\n BrowserRecordingManager,\n BrowserPageOperations,\n ProviderBrowserSession,\n BrowserSession,\n BrowserProfile,\n BrowserExtension,\n BrowserPool,\n BrowserLog,\n BrowserRecording,\n CreateBrowserSessionOptions,\n CreateBrowserProfileOptions,\n CreateBrowserExtensionOptions,\n CreateBrowserPoolOptions,\n ScreenshotOptions,\n PdfOptions,\n} from './types/browser.js';\n\n// ─── Method Definitions ──────────────────────────────────────────────────────\n\n/**\n * Session method implementations that provider authors supply\n */\nexport interface BrowserSessionMethods<TSession = any, TConfig = any> {\n create: (config: TConfig, options?: CreateBrowserSessionOptions) => Promise<{ session: TSession; sessionId: string; connectUrl: string; status?: BrowserSession['status'] }>;\n getById: (config: TConfig, sessionId: string) => Promise<{ session: TSession; sessionId: string; connectUrl: string; status?: BrowserSession['status'] } | null>;\n /**\n * List sessions. `connectUrl` may be omitted on entries when the provider's\n * list endpoint doesn't include it — callers needing a connectable URL\n * should use `provider.getConnectUrl(sessionId)`.\n */\n list: (config: TConfig) => Promise<Array<{ session: TSession; sessionId: string; connectUrl?: string; status?: BrowserSession['status'] }>>;\n destroy: (config: TConfig, sessionId: string) => Promise<void>;\n getConnectUrl: (config: TConfig, sessionId: string) => Promise<string>;\n}\n\n/**\n * Profile method implementations\n */\nexport interface BrowserProfileMethods<TConfig = any> {\n create: (config: TConfig, options?: CreateBrowserProfileOptions) => Promise<BrowserProfile>;\n get: (config: TConfig, profileId: string) => Promise<BrowserProfile | null>;\n list: (config: TConfig) => Promise<BrowserProfile[]>;\n delete: (config: TConfig, profileId: string) => Promise<void>;\n}\n\n/**\n * Extension method implementations\n */\nexport interface BrowserExtensionMethods<TConfig = any> {\n create: (config: TConfig, options: CreateBrowserExtensionOptions) => Promise<BrowserExtension>;\n get: (config: TConfig, extensionId: string) => Promise<BrowserExtension | null>;\n delete: (config: TConfig, extensionId: string) => Promise<void>;\n}\n\n/**\n * Pool method implementations\n */\nexport interface BrowserPoolMethods<TSession = any, TConfig = any> {\n create: (config: TConfig, options: CreateBrowserPoolOptions) => Promise<BrowserPool>;\n get: (config: TConfig, poolId: string) => Promise<BrowserPool | null>;\n list: (config: TConfig) => Promise<BrowserPool[]>;\n acquire: (config: TConfig, poolId: string) => Promise<{ session: TSession; sessionId: string; connectUrl: string }>;\n release: (config: TConfig, poolId: string, sessionId: string) => Promise<void>;\n delete: (config: TConfig, poolId: string) => Promise<void>;\n}\n\n/**\n * Log method implementations\n */\nexport interface BrowserLogMethods<TConfig = any> {\n list: (config: TConfig, sessionId: string) => Promise<BrowserLog[]>;\n}\n\n/**\n * Recording method implementations\n */\nexport interface BrowserRecordingMethods<TConfig = any> {\n get: (config: TConfig, sessionId: string) => Promise<BrowserRecording | null>;\n}\n\n/**\n * Page operation method implementations\n */\nexport interface BrowserPageMethods<TSession = any> {\n navigate: (session: TSession, url: string) => Promise<void>;\n screenshot: (session: TSession, options?: ScreenshotOptions) => Promise<Uint8Array>;\n pdf?: (session: TSession, options?: PdfOptions) => Promise<Uint8Array>;\n evaluate: (session: TSession, script: string) => Promise<unknown>;\n getContent: (session: TSession) => Promise<string>;\n}\n\n/**\n * Full browser provider configuration for defineBrowserProvider()\n */\nexport interface BrowserProviderConfig<TSession = any, TConfig = any> {\n name: string;\n methods: {\n session: BrowserSessionMethods<TSession, TConfig>;\n profile?: BrowserProfileMethods<TConfig>;\n extension?: BrowserExtensionMethods<TConfig>;\n pool?: BrowserPoolMethods<TSession, TConfig>;\n logs?: BrowserLogMethods<TConfig>;\n recording?: BrowserRecordingMethods<TConfig>;\n page?: BrowserPageMethods<TSession>;\n };\n}\n\n// ─── Generated Classes ───────────────────────────────────────────────────────\n\n/**\n * Generated browser session — implements ProviderBrowserSession\n */\nclass GeneratedBrowserSession<TSession = any> implements ProviderBrowserSession<TSession> {\n readonly sessionId: string;\n readonly connectUrl?: string;\n readonly status: BrowserSession['status'];\n readonly createdAt?: Date;\n readonly metadata?: Record<string, unknown>;\n\n constructor(\n private session: TSession,\n sessionId: string,\n connectUrl: string | undefined,\n status: BrowserSession['status'] | undefined,\n private providerInstance: BrowserProvider<TSession>,\n private config: any,\n private sessionMethods: BrowserSessionMethods<TSession>,\n private logMethods?: BrowserLogMethods,\n private recordingMethods?: BrowserRecordingMethods,\n private pageMethods?: BrowserPageMethods<TSession>,\n ) {\n this.sessionId = sessionId;\n this.connectUrl = connectUrl;\n this.status = status ?? 'running';\n }\n\n getInstance(): TSession {\n return this.session;\n }\n\n getProvider(): BrowserProvider<TSession> {\n return this.providerInstance;\n }\n\n async destroy(): Promise<void> {\n await this.sessionMethods.destroy(this.config, this.sessionId);\n }\n\n async screenshot(options?: ScreenshotOptions): Promise<Uint8Array> {\n if (!this.pageMethods) {\n throw new Error(\n `Provider '${this.providerInstance.name}' does not support native page operations. ` +\n `Use the connectUrl to control the browser via Playwright/Puppeteer instead.`\n );\n }\n return this.pageMethods.screenshot(this.session, options);\n }\n\n async getLogs(): Promise<BrowserLog[]> {\n if (!this.logMethods) {\n throw new Error(`Provider '${this.providerInstance.name}' does not support log retrieval.`);\n }\n return this.logMethods.list(this.config, this.sessionId);\n }\n\n async getRecording(): Promise<BrowserRecording | null> {\n if (!this.recordingMethods) {\n throw new Error(`Provider '${this.providerInstance.name}' does not support recordings.`);\n }\n return this.recordingMethods.get(this.config, this.sessionId);\n }\n}\n\n/**\n * Generated session manager\n */\nclass GeneratedSessionManager<TSession, TConfig> implements BrowserSessionManager<TSession> {\n constructor(\n private config: TConfig,\n private methods: BrowserSessionMethods<TSession, TConfig>,\n private providerInstance: BrowserProvider<TSession>,\n private logMethods?: BrowserLogMethods<TConfig>,\n private recordingMethods?: BrowserRecordingMethods<TConfig>,\n private pageMethods?: BrowserPageMethods<TSession>,\n ) {}\n\n async create(options?: CreateBrowserSessionOptions): Promise<ProviderBrowserSession<TSession>> {\n const result = await this.methods.create(this.config, options);\n return new GeneratedBrowserSession(\n result.session, result.sessionId, result.connectUrl, result.status,\n this.providerInstance, this.config, this.methods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n );\n }\n\n async getById(sessionId: string): Promise<ProviderBrowserSession<TSession> | null> {\n const result = await this.methods.getById(this.config, sessionId);\n if (!result) return null;\n return new GeneratedBrowserSession(\n result.session, result.sessionId, result.connectUrl, result.status,\n this.providerInstance, this.config, this.methods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n );\n }\n\n async list(): Promise<ProviderBrowserSession<TSession>[]> {\n const results = await this.methods.list(this.config);\n return results.map(r => new GeneratedBrowserSession(\n r.session, r.sessionId, r.connectUrl, r.status,\n this.providerInstance, this.config, this.methods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n ));\n }\n\n async destroy(sessionId: string): Promise<void> {\n await this.methods.destroy(this.config, sessionId);\n }\n}\n\n/**\n * Generated profile manager\n */\nclass GeneratedProfileManager<TConfig> implements BrowserProfileManager {\n constructor(private config: TConfig, private methods: BrowserProfileMethods<TConfig>) {}\n\n async create(options?: CreateBrowserProfileOptions): Promise<BrowserProfile> {\n return this.methods.create(this.config, options);\n }\n async get(profileId: string): Promise<BrowserProfile | null> {\n return this.methods.get(this.config, profileId);\n }\n async list(): Promise<BrowserProfile[]> {\n return this.methods.list(this.config);\n }\n async delete(profileId: string): Promise<void> {\n return this.methods.delete(this.config, profileId);\n }\n}\n\n/**\n * Generated extension manager\n */\nclass GeneratedExtensionManager<TConfig> implements BrowserExtensionManager {\n constructor(private config: TConfig, private methods: BrowserExtensionMethods<TConfig>) {}\n\n async create(options: CreateBrowserExtensionOptions): Promise<BrowserExtension> {\n return this.methods.create(this.config, options);\n }\n async get(extensionId: string): Promise<BrowserExtension | null> {\n return this.methods.get(this.config, extensionId);\n }\n async delete(extensionId: string): Promise<void> {\n return this.methods.delete(this.config, extensionId);\n }\n}\n\n/**\n * Generated pool manager\n */\nclass GeneratedPoolManager<TSession, TConfig> implements BrowserPoolManager<TSession> {\n constructor(\n private config: TConfig,\n private methods: BrowserPoolMethods<TSession, TConfig>,\n private providerInstance: BrowserProvider<TSession>,\n private sessionMethods: BrowserSessionMethods<TSession, TConfig>,\n private logMethods?: BrowserLogMethods<TConfig>,\n private recordingMethods?: BrowserRecordingMethods<TConfig>,\n private pageMethods?: BrowserPageMethods<TSession>,\n ) {}\n\n async create(options: CreateBrowserPoolOptions): Promise<BrowserPool> {\n return this.methods.create(this.config, options);\n }\n async get(poolId: string): Promise<BrowserPool | null> {\n return this.methods.get(this.config, poolId);\n }\n async list(): Promise<BrowserPool[]> {\n return this.methods.list(this.config);\n }\n async acquire(poolId: string): Promise<ProviderBrowserSession<TSession>> {\n const result = await this.methods.acquire(this.config, poolId);\n return new GeneratedBrowserSession(\n result.session, result.sessionId, result.connectUrl, 'running',\n this.providerInstance, this.config, this.sessionMethods,\n this.logMethods, this.recordingMethods, this.pageMethods,\n );\n }\n async release(poolId: string, sessionId: string): Promise<void> {\n return this.methods.release(this.config, poolId, sessionId);\n }\n async delete(poolId: string): Promise<void> {\n return this.methods.delete(this.config, poolId);\n }\n}\n\n/**\n * Generated page operations\n */\nclass GeneratedPageOperations<TSession> implements BrowserPageOperations<TSession> {\n pdf?: (session: TSession, options?: PdfOptions) => Promise<Uint8Array>;\n\n constructor(private methods: BrowserPageMethods<TSession>) {\n if (methods.pdf) {\n const pdfMethod = methods.pdf;\n this.pdf = (session: TSession, options?: PdfOptions) => pdfMethod(session, options);\n }\n }\n\n async navigate(session: TSession, url: string): Promise<void> {\n return this.methods.navigate(session, url);\n }\n async screenshot(session: TSession, options?: ScreenshotOptions): Promise<Uint8Array> {\n return this.methods.screenshot(session, options);\n }\n async evaluate(session: TSession, script: string): Promise<unknown> {\n return this.methods.evaluate(session, script);\n }\n async getContent(session: TSession): Promise<string> {\n return this.methods.getContent(session);\n }\n}\n\n/**\n * Generated browser provider\n */\nclass GeneratedBrowserProvider<TSession, TConfig> implements BrowserProvider<TSession> {\n readonly name: string;\n readonly session: BrowserSessionManager<TSession>;\n readonly profile?: BrowserProfileManager;\n readonly extension?: BrowserExtensionManager;\n readonly pool?: BrowserPoolManager;\n readonly logs?: BrowserLogManager;\n readonly recording?: BrowserRecordingManager;\n readonly page?: BrowserPageOperations<TSession>;\n\n private config: TConfig;\n private sessionMethods: BrowserSessionMethods<TSession, TConfig>;\n\n constructor(config: TConfig, providerConfig: BrowserProviderConfig<TSession, TConfig>) {\n this.name = providerConfig.name;\n this.config = config;\n this.sessionMethods = providerConfig.methods.session;\n\n const logMethods = providerConfig.methods.logs;\n const recordingMethods = providerConfig.methods.recording;\n const pageMethods = providerConfig.methods.page;\n\n // Session manager (always present)\n this.session = new GeneratedSessionManager(\n config, providerConfig.methods.session, this,\n logMethods, recordingMethods, pageMethods,\n );\n\n // Optional managers — auto-detected from provided methods\n if (providerConfig.methods.profile) {\n this.profile = new GeneratedProfileManager(config, providerConfig.methods.profile);\n }\n if (providerConfig.methods.extension) {\n this.extension = new GeneratedExtensionManager(config, providerConfig.methods.extension);\n }\n if (providerConfig.methods.pool) {\n this.pool = new GeneratedPoolManager(\n config, providerConfig.methods.pool, this,\n providerConfig.methods.session, logMethods, recordingMethods, pageMethods,\n );\n }\n if (logMethods) {\n this.logs = { list: (sessionId: string) => logMethods.list(config, sessionId) };\n }\n if (recordingMethods) {\n this.recording = { get: (sessionId: string) => recordingMethods.get(config, sessionId) };\n }\n if (pageMethods) {\n this.page = new GeneratedPageOperations(pageMethods);\n }\n }\n\n async getConnectUrl(sessionId: string): Promise<string> {\n return this.sessionMethods.getConnectUrl(this.config, sessionId);\n }\n}\n\n// ─── Public Factory ──────────────────────────────────────────────────────────\n\n/**\n * Create a browser provider from method definitions\n *\n * Auto-generates all boilerplate classes and provides feature detection\n * based on which methods are implemented.\n *\n * @example\n * ```ts\n * export const browserbase = defineBrowserProvider<BrowserbaseSession, BrowserbaseConfig>({\n * name: 'browserbase',\n * methods: {\n * session: { create, getById, list, destroy, getConnectUrl },\n * profile: { create, get, list, delete },\n * logs: { list: getLogs },\n * recording: { get: getRecording },\n * },\n * });\n *\n * // Usage:\n * const provider = browserbase({ apiKey: 'bb_...' });\n * const session = await provider.session.create({ stealth: true });\n * console.log(session.connectUrl);\n * ```\n */\nexport function defineBrowserProvider<TSession, TConfig = any>(\n providerConfig: BrowserProviderConfig<TSession, TConfig>\n): (config: TConfig) => BrowserProvider<TSession> {\n return (config: TConfig) => {\n return new GeneratedBrowserProvider(config, providerConfig);\n };\n}\n","/**\n * Utility functions for ComputeSDK\n */\n\n/**\n * Calculate exponential backoff delay with jitter\n * \n * Uses exponential backoff (2^attempt) multiplied by base delay,\n * plus random jitter to prevent thundering herd.\n * \n * @param attempt - Current retry attempt (0-indexed)\n * @param baseDelay - Base delay in milliseconds (default: 1000)\n * @param jitterMax - Maximum random jitter in milliseconds (default: 100)\n * @returns Delay in milliseconds\n * \n * @example\n * ```typescript\n * // First retry: 1000-1100ms\n * calculateBackoff(0);\n * \n * // Second retry: 2000-2100ms\n * calculateBackoff(1);\n * \n * // Third retry: 4000-4100ms\n * calculateBackoff(2);\n * ```\n */\nexport function calculateBackoff(\n attempt: number,\n baseDelay: number = 1000,\n jitterMax: number = 100\n): number {\n return baseDelay * Math.pow(2, attempt) + Math.random() * jitterMax;\n}\n\n/**\n * Escapes a string for safe use in shell commands\n * \n * Escapes special shell characters to prevent command injection.\n * Use this when interpolating user-controlled values into shell commands.\n * \n * @param arg - The string to escape\n * @returns Escaped string safe for shell interpolation\n * \n * @example\n * ```typescript\n * const path = '/path/with spaces';\n * const command = `cd \"${escapeShellArg(path)}\" && ls`;\n * // Result: cd \"/path/with\\ spaces\" && ls\n * \n * const env = { KEY: 'value with $pecial chars' };\n * const command = `KEY=\"${escapeShellArg(env.KEY)}\" npm run build`;\n * // Result: KEY=\"value with \\$pecial chars\" npm run build\n * ```\n */\nexport function escapeShellArg(arg: string): string {\n return arg\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/\"/g, '\\\\\"') // Escape double quotes\n .replace(/\\$/g, '\\\\$') // Escape dollar signs (variable expansion)\n .replace(/`/g, '\\\\`'); // Escape backticks (command substitution)\n}\n"],"mappings":"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","names":[]} |
+4
-3
| { | ||
| "name": "@computesdk/provider", | ||
| "version": "2.0.0", | ||
| "version": "2.1.0", | ||
| "description": "Provider framework for ComputeSDK - define custom sandbox providers", | ||
@@ -38,4 +38,5 @@ "author": "Garrison", | ||
| "dependencies": { | ||
| "computesdk": "4.0.0", | ||
| "@computesdk/cmd": "0.4.1" | ||
| "daemond": "^0.1.3", | ||
| "@computesdk/cmd": "0.4.1", | ||
| "computesdk": "4.1.0" | ||
| }, | ||
@@ -42,0 +43,0 @@ "devDependencies": { |
+14
-11
@@ -235,5 +235,9 @@ # @computesdk/provider | ||
| Add filesystem support by implementing the `filesystem` methods: | ||
| Add filesystem support by implementing the `filesystem` methods. Import `escapeShellArg` from `@computesdk/provider` and always interpolate it inside double quotes — the helper escapes `\`, `"`, `$`, and backticks but not spaces or shell metacharacters like `;` and `|`, so unquoted usage will break on paths with spaces and is unsafe for user-controlled input. | ||
| ```typescript | ||
| import { defineProvider, escapeShellArg } from '@computesdk/provider'; | ||
| // ... | ||
| methods: { | ||
@@ -245,3 +249,3 @@ sandbox: { | ||
| readFile: async (sandbox, path, runCommand) => { | ||
| const result = await runCommand(sandbox, 'cat', [path]); | ||
| const result = await runCommand(sandbox, `cat "${escapeShellArg(path)}"`); | ||
| return result.stdout; | ||
@@ -251,12 +255,11 @@ }, | ||
| writeFile: async (sandbox, path, content, runCommand) => { | ||
| const escaped = content.replace(/'/g, "'\\''"); | ||
| await runCommand(sandbox, 'sh', ['-c', `cat > '${path}' << 'EOF'\n${content}\nEOF`]); | ||
| await runCommand(sandbox, `cat > "${escapeShellArg(path)}" << 'EOF'\n${content}\nEOF`); | ||
| }, | ||
| mkdir: async (sandbox, path, runCommand) => { | ||
| await runCommand(sandbox, 'mkdir', ['-p', path]); | ||
| await runCommand(sandbox, `mkdir -p "${escapeShellArg(path)}"`); | ||
| }, | ||
| readdir: async (sandbox, path, runCommand) => { | ||
| const result = await runCommand(sandbox, 'ls', ['-la', path]); | ||
| const result = await runCommand(sandbox, `ls -la "${escapeShellArg(path)}"`); | ||
| // Parse ls output and return FileEntry[] | ||
@@ -267,3 +270,3 @@ return parseFileList(result.stdout); | ||
| exists: async (sandbox, path, runCommand) => { | ||
| const result = await runCommand(sandbox, 'test', ['-e', path]); | ||
| const result = await runCommand(sandbox, `test -e "${escapeShellArg(path)}"`); | ||
| return result.exitCode === 0; | ||
@@ -273,3 +276,3 @@ }, | ||
| remove: async (sandbox, path, runCommand) => { | ||
| await runCommand(sandbox, 'rm', ['-rf', path]); | ||
| await runCommand(sandbox, `rm -rf "${escapeShellArg(path)}"`); | ||
| } | ||
@@ -319,3 +322,3 @@ } | ||
| - **`direct`** - Provider has native sandbox capabilities (e.g., E2B, Modal) | ||
| - **`gateway`** - Provider only has infrastructure (e.g., Railway) - routes through gateway | ||
| - **`gateway`** - Provider only has infrastructure - routes through gateway | ||
@@ -524,5 +527,5 @@ Set the default mode in your provider config: | ||
| - **[@computesdk/e2b](../e2b)** - Full-featured provider with filesystem and terminals | ||
| - **[@computesdk/e2b](../e2b)** - Full-featured provider with filesystem operations | ||
| - **[@computesdk/modal](../modal)** - GPU-accelerated Python provider | ||
| - **[@computesdk/railway](../railway)** - Infrastructure provider using gateway mode | ||
| - **[@computesdk/daytona](../daytona)** - Workspace-based development sandboxes | ||
@@ -529,0 +532,0 @@ ## Related Packages |
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
270152
20.68%2585
22.51%534
0.56%3
50%4
Infinity%+ Added
+ Added
+ Added
- Removed
Updated