unfazed 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/eve-sandbox/daemon.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The eve sandbox daemon: runs as root inside an unfazed box and gives the\n * apps it trusts sandboxes, one Unix user per eve session.\n *\n * It serves the box's :3000, which unfazed publishes at the box's URL, and\n * accepts only workload identity tokens (OIDC, issuer\n * `https://unfazed.dev/oidc`) whose audience is that URL and whose app is on\n * its allow list. A session's commands and file operations run as that\n * session's user, so the kernel keeps sessions apart; the daemon itself only\n * creates and removes users and relays bytes.\n *\n * Started by a box boot hook (`/data/boot.d/50-eve-sandbox`, see setup.ts):\n *\n * node|bun <this file> serve [--config /data/eve-sandbox/config.json]\n *\n * and invoked as the session user for file operations:\n *\n * setpriv --reuid U --regid G --init-groups -- node|bun <this file> fileop\n */\n\nimport { spawn, spawnSync, type ChildProcess } from \"node:child_process\";\nimport { createHash, randomUUID, webcrypto } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, rmSync, statSync, utimesSync, writeFileSync } from \"node:fs\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n API_PREFIX,\n DAEMON_VERSION,\n TEMPLATE_HOME,\n TEMPLATE_WORKSPACE,\n type EnsureSessionRequest,\n type ProcessEvent,\n type RemoveRequest,\n type SessionInfo,\n type SpawnRequest,\n type WireFile,\n} from \"./protocol.js\";\n\n// ---------------------------------------------------------------------------\n// Configuration\n\nexport interface DaemonConfig {\n /** The audience every token must carry: the box's URL. */\n readonly audience: string;\n /** App ids (`app_id` claim) allowed to use this box; `owner:<id>` allows every app of an owner. */\n readonly allow: readonly string[];\n readonly issuer: string;\n readonly port: number;\n /** Where session homes live. */\n readonly homeRoot: string;\n /** Kill a session's processes after this long without a call; 0 never. */\n readonly idleMinutes: number;\n /** Delete a session (user, home, files) after this many days without a call; 0 never. */\n readonly retentionDays: number;\n /** Extra environment for every command (e.g. PLAYWRIGHT_BROWSERS_PATH). */\n readonly env: Readonly<Record<string, string>>;\n}\n\nconst DEFAULT_CONFIG_PATH = \"/data/eve-sandbox/config.json\";\nconst PATH_ENV = \"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\";\n/** Output kept per process for a client that reads late or reconnects. */\nconst MAX_PROCESS_OUTPUT = 64 * 1024 * 1024;\n/** A finished process is forgotten this long after it exited. */\nconst PROCESS_RETENTION_MS = 10 * 60 * 1000;\nconst MAX_BODY = 128 * 1024 * 1024;\n/** Root-owned file in a session's home whose mtime is the session's last call. */\nconst LAST_USED = \".eve-sandbox-last-used\";\nconst SESSION_USER = /^eve[0-9a-f]{12}$/;\n\nexport function loadConfig(path = DEFAULT_CONFIG_PATH): DaemonConfig {\n const raw = existsSync(path) ? (JSON.parse(readFileSync(path, \"utf8\")) as Partial<DaemonConfig>) : {};\n const audience = raw.audience ?? process.env.UNFZ_PUBLIC_URL ?? \"\";\n if (!audience) throw new Error(`eve sandbox: no audience (set \"audience\" in ${path} or UNFZ_PUBLIC_URL)`);\n const envAllow = (process.env.EVE_SANDBOX_ALLOW ?? \"\").split(\",\").map((s) => s.trim()).filter(Boolean);\n const allow = [...(raw.allow ?? []), ...envAllow];\n if (allow.length === 0) throw new Error(`eve sandbox: nothing is allowed (set \"allow\" in ${path} or EVE_SANDBOX_ALLOW)`);\n return {\n audience: audience.replace(/\\/+$/, \"\"),\n allow,\n issuer: raw.issuer ?? \"https://unfazed.dev/oidc\",\n port: raw.port ?? 3000,\n homeRoot: raw.homeRoot ?? \"/home\",\n idleMinutes: raw.idleMinutes ?? 20,\n retentionDays: raw.retentionDays ?? 14,\n env: raw.env ?? {},\n };\n}\n\n// ---------------------------------------------------------------------------\n// Workload identity tokens (ES256 JWTs from the unfazed issuer)\n\ninterface Claims {\n readonly iss: string;\n readonly aud: string | readonly string[];\n readonly exp: number;\n readonly nbf?: number;\n readonly app_id?: string;\n readonly owner_id?: string;\n readonly alias?: string;\n}\n\nclass HttpError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message?: string,\n ) {\n super(message ?? code);\n }\n}\n\nfunction b64urlDecode(part: string): Uint8Array {\n return new Uint8Array(Buffer.from(part.replace(/-/g, \"+\").replace(/_/g, \"/\"), \"base64\"));\n}\n\nexport class TokenVerifier {\n private keys = new Map<string, CryptoKey>();\n private fetchedAt = 0;\n private refreshing: Promise<void> | undefined;\n\n constructor(\n private readonly config: Pick<DaemonConfig, \"audience\" | \"issuer\" | \"allow\">,\n private readonly fetchJson: (url: string) => Promise<unknown> = async (url) => {\n const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });\n if (!res.ok) throw new Error(`${url}: ${res.status}`);\n return await res.json();\n },\n private readonly now: () => number = () => Date.now(),\n ) {}\n\n /** The calling app's namespace (its app id) for a valid, allowed token. */\n async verify(authorization: string | undefined): Promise<string> {\n const match = /^Bearer ([A-Za-z0-9_-]+)\\.([A-Za-z0-9_-]+)\\.([A-Za-z0-9_-]+)$/.exec(authorization ?? \"\");\n if (!match) throw new HttpError(401, \"invalid_token\", \"a workload identity bearer token is required\");\n const [, h, p, s] = match as unknown as [string, string, string, string];\n let header: { alg?: string; kid?: string };\n let claims: Claims;\n try {\n header = JSON.parse(Buffer.from(b64urlDecode(h)).toString(\"utf8\"));\n claims = JSON.parse(Buffer.from(b64urlDecode(p)).toString(\"utf8\"));\n } catch {\n throw new HttpError(401, \"invalid_token\", \"malformed token\");\n }\n if (header.alg !== \"ES256\" || !header.kid) throw new HttpError(401, \"invalid_token\", \"unsupported token algorithm\");\n const key = await this.key(header.kid);\n const ok = await webcrypto.subtle.verify(\n { name: \"ECDSA\", hash: \"SHA-256\" },\n key,\n b64urlDecode(s),\n new TextEncoder().encode(`${h}.${p}`),\n );\n if (!ok) throw new HttpError(401, \"invalid_token\", \"bad signature\");\n const nowS = Math.floor(this.now() / 1000);\n const audiences = Array.isArray(claims.aud) ? claims.aud : [claims.aud];\n if (claims.iss !== this.config.issuer) throw new HttpError(401, \"invalid_token\", \"wrong issuer\");\n if (!audiences.some((a) => a.replace(/\\/+$/, \"\") === this.config.audience)) throw new HttpError(401, \"invalid_token\", \"wrong audience\");\n if (typeof claims.exp !== \"number\" || claims.exp < nowS - 30) throw new HttpError(401, \"invalid_token\", \"token expired\");\n if (typeof claims.nbf === \"number\" && claims.nbf > nowS + 30) throw new HttpError(401, \"invalid_token\", \"token not yet valid\");\n const app = claims.app_id ?? \"\";\n if (!app) throw new HttpError(403, \"forbidden\", \"the token names no app\");\n const allowed = this.config.allow.some((entry) =>\n entry.startsWith(\"owner:\") ? entry.slice(6) === claims.owner_id : entry === app,\n );\n if (!allowed) throw new HttpError(403, \"forbidden\", `app ${app} may not use this box`);\n return app;\n }\n\n private async key(kid: string): Promise<CryptoKey> {\n const cached = this.keys.get(kid);\n if (cached && this.now() - this.fetchedAt < 10 * 60 * 1000) return cached;\n // Unknown kid: refetch, but at most every 30 s.\n if (!cached || this.now() - this.fetchedAt >= 30_000) await this.refresh();\n const key = this.keys.get(kid);\n if (!key) throw new HttpError(401, \"invalid_token\", \"unknown signing key\");\n return key;\n }\n\n private async refresh(): Promise<void> {\n this.refreshing ??= (async () => {\n try {\n const discovery = (await this.fetchJson(`${this.config.issuer}/.well-known/openid-configuration`)) as { jwks_uri?: string };\n const jwks = (await this.fetchJson(discovery.jwks_uri ?? `${this.config.issuer}/jwks`)) as { keys?: JsonWebKey[] };\n const next = new Map<string, CryptoKey>();\n for (const jwk of jwks.keys ?? []) {\n const kid = (jwk as { kid?: string }).kid;\n if (!kid || jwk.kty !== \"EC\" || jwk.crv !== \"P-256\") continue;\n next.set(kid, await webcrypto.subtle.importKey(\"jwk\", jwk, { name: \"ECDSA\", namedCurve: \"P-256\" }, false, [\"verify\"]));\n }\n this.keys = next;\n this.fetchedAt = this.now();\n } finally {\n this.refreshing = undefined;\n }\n })();\n await this.refreshing;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Sessions: one Unix user each\n\ninterface Session extends SessionInfo {\n readonly uid: number;\n readonly gid: number;\n}\n\n/** The Unix name of an app's session: bounded, derived from the ids only. */\nexport function sessionName(app: string, sessionId: string): string {\n return `eve${createHash(\"sha256\").update(`${app}\\n${sessionId}`).digest(\"hex\").slice(0, 12)}`;\n}\n\nfunction run(argv: readonly string[], input?: string | Uint8Array): { status: number; stdout: string; stderr: string } {\n const result = spawnSync(argv[0]!, argv.slice(1), { input, encoding: \"utf8\", env: { PATH: PATH_ENV } });\n return { status: result.status ?? 1, stdout: result.stdout ?? \"\", stderr: result.stderr ?? \"\" };\n}\n\nclass Sessions {\n private lastUsed = new Map<string, number>();\n\n constructor(private readonly config: DaemonConfig) {}\n\n private describe(name: string): Session | undefined {\n const entry = run([\"getent\", \"passwd\", name]);\n if (entry.status !== 0) return undefined;\n const [, , uid, gid, , home] = entry.stdout.trim().split(\":\");\n return { name, uid: Number(uid), gid: Number(gid), home: home!, workspace: `${home}/workspace` };\n }\n\n get(app: string, sessionId: string): Session | undefined {\n const session = this.describe(sessionName(app, sessionId));\n if (session) this.touch(session.name);\n return session;\n }\n\n ensure(app: string, sessionId: string, template: readonly WireFile[]): Session & { created: boolean } {\n const name = sessionName(app, sessionId);\n const existing = this.describe(name);\n if (existing) {\n this.touch(name);\n return { ...existing, created: false };\n }\n const home = `${this.config.homeRoot}/${name}`;\n const added = run([\"useradd\", \"--create-home\", \"--home-dir\", home, \"--shell\", \"/bin/bash\", \"--user-group\", \"--comment\", \"eve sandbox\", name]);\n const session = this.describe(name);\n if (!session) throw new HttpError(500, \"session_create_failed\", added.stderr.trim() || \"useradd failed\");\n run([\"chmod\", \"0700\", home]);\n const files = [\n { path: `${session.workspace}/.keep`, b64: \"\" },\n ...template.map((file) => ({ path: mapTemplatePath(file.path, session), b64: file.b64 })),\n ];\n fileop(session, { op: \"write\", files });\n this.touch(name);\n return { ...session, created: true };\n }\n\n stop(name: string): void {\n run([\"pkill\", \"-KILL\", \"-u\", name]);\n }\n\n delete(app: string, sessionId: string): void {\n const name = sessionName(app, sessionId);\n if (!this.describe(name)) return;\n this.stop(name);\n for (let attempt = 0; attempt < 5; attempt++) {\n if (run([\"userdel\", \"--remove\", name]).status === 0) break;\n this.stop(name);\n spawnSync(\"sleep\", [\"0.2\"]);\n }\n rmSync(`${this.config.homeRoot}/${name}`, { recursive: true, force: true });\n this.lastUsed.delete(name);\n }\n\n touch(name: string): void {\n const now = Date.now();\n const previous = this.lastUsed.get(name) ?? 0;\n this.lastUsed.set(name, now);\n if (now - previous < 60_000) return;\n const marker = `${this.config.homeRoot}/${name}/${LAST_USED}`;\n try {\n if (!existsSync(marker)) writeFileSync(marker, \"\");\n utimesSync(marker, now / 1000, now / 1000);\n } catch {\n // the home may be gone mid-delete\n }\n }\n\n /** Deletes sessions without a call for longer than the retention, users and homes included. */\n expireOld(): void {\n if (this.config.retentionDays <= 0) return;\n const limit = this.config.retentionDays * 24 * 60 * 60 * 1000;\n const passwd = run([\"getent\", \"passwd\"]).stdout.split(\"\\n\");\n for (const line of passwd) {\n const [name, , , , , home] = line.split(\":\");\n if (!name || !SESSION_USER.test(name) || home !== `${this.config.homeRoot}/${name}`) continue;\n let at: number;\n try {\n at = statSync(`${home}/${LAST_USED}`).mtimeMs;\n } catch {\n try {\n at = statSync(home).mtimeMs;\n } catch {\n at = 0;\n }\n }\n if (Date.now() - at > limit) {\n this.stop(name);\n run([\"userdel\", \"--remove\", name]);\n rmSync(home, { recursive: true, force: true });\n this.lastUsed.delete(name);\n }\n }\n }\n\n /** Kills the processes of sessions idle for longer than the limit. */\n reapIdle(): void {\n if (this.config.idleMinutes <= 0) return;\n const limit = this.config.idleMinutes * 60 * 1000;\n for (const [name, at] of this.lastUsed) {\n if (Date.now() - at > limit) {\n this.stop(name);\n this.lastUsed.delete(name);\n }\n }\n }\n}\n\nfunction mapTemplatePath(path: string, session: SessionInfo): string {\n if (path === TEMPLATE_WORKSPACE || path.startsWith(`${TEMPLATE_WORKSPACE}/`)) return session.workspace + path.slice(TEMPLATE_WORKSPACE.length);\n if (path === TEMPLATE_HOME || path.startsWith(`${TEMPLATE_HOME}/`)) return session.home + path.slice(TEMPLATE_HOME.length);\n return path;\n}\n\nfunction sessionEnv(session: Session, extra: Readonly<Record<string, string>>): Record<string, string> {\n return {\n PATH: PATH_ENV,\n HOME: session.home,\n USER: session.name,\n LOGNAME: session.name,\n SHELL: \"/bin/bash\",\n LANG: \"C.UTF-8\",\n ...extra,\n };\n}\n\nfunction asUser(session: Session, argv: readonly string[]): string[] {\n return [\"setpriv\", `--reuid=${session.uid}`, `--regid=${session.gid}`, \"--init-groups\", \"--\", ...argv];\n}\n\n// ---------------------------------------------------------------------------\n// File operations, run as the session user\n\ntype FileOp =\n | { op: \"read\"; path: string }\n | { op: \"write\"; files: readonly WireFile[] }\n | { op: \"remove\"; path: string; force: boolean; recursive: boolean };\n\nconst FILEOP_MISSING = 3;\nconst FILEOP_DIRECTORY = 4;\nconst FILEOP_FAILED = 5;\n\nfunction fileop(session: Session, request: FileOp): Buffer {\n // This module itself, whoever loaded it (its own entry or `unfazed eve-sandbox serve`).\n const argv = asUser(session, [process.execPath, fileURLToPath(import.meta.url), \"fileop\"]);\n const result = spawnSync(argv[0]!, argv.slice(1), {\n input: JSON.stringify(request),\n env: { PATH: PATH_ENV, HOME: session.home },\n maxBuffer: MAX_BODY,\n });\n const status = result.status ?? FILEOP_FAILED;\n if (status === 0) return result.stdout as Buffer;\n const message = (result.stderr?.toString() ?? \"\").trim().slice(0, 500);\n if (status === FILEOP_MISSING) throw new HttpError(404, \"not_found\", message || \"no such file\");\n if (status === FILEOP_DIRECTORY) throw new HttpError(409, \"is_directory\", message || \"the path is a directory\");\n throw new HttpError(422, \"file_operation_failed\", message || \"the file operation failed\");\n}\n\n/** The `fileop` subcommand: one request on stdin, run with the caller's own permissions. */\nexport function runFileOp(): never {\n try {\n const request = JSON.parse(readFileSync(0, \"utf8\")) as FileOp;\n if (request.op === \"read\") {\n let st;\n try {\n st = statSync(request.path);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") process.exit(FILEOP_MISSING);\n throw error;\n }\n if (st.isDirectory()) process.exit(FILEOP_DIRECTORY);\n process.stdout.write(readFileSync(request.path), () => process.exit(0));\n return undefined as never;\n }\n if (request.op === \"write\") {\n for (const file of request.files) {\n if (!file.path.startsWith(\"/\")) throw new Error(`not an absolute path: ${file.path}`);\n mkdirSync(dirname(file.path), { recursive: true });\n writeFileSync(file.path, Buffer.from(file.b64, \"base64\"));\n }\n process.exit(0);\n }\n if (request.op === \"remove\") {\n if (!existsSync(request.path)) process.exit(request.force ? 0 : FILEOP_MISSING);\n rmSync(request.path, { recursive: request.recursive, force: request.force });\n process.exit(0);\n }\n throw new Error(\"unknown operation\");\n } catch (error) {\n process.stderr.write(String((error as Error).message ?? error));\n process.exit(FILEOP_FAILED);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Processes\n\ninterface Proc {\n readonly id: string;\n readonly app: string;\n readonly session: string;\n readonly child: ChildProcess;\n readonly events: ProcessEvent[];\n bytes: number;\n exit: number | undefined;\n exitedAt: number | undefined;\n readonly listeners: Set<() => void>;\n}\n\nconst SIGNALS: Record<string, number> = { SIGHUP: 1, SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGSEGV: 11, SIGPIPE: 13, SIGTERM: 15 };\n\nclass Processes {\n readonly all = new Map<string, Proc>();\n\n start(app: string, session: Session, request: SpawnRequest, baseEnv: Readonly<Record<string, string>>): Proc {\n if (!existsSync(request.cwd)) throw new HttpError(400, \"invalid_cwd\", `working directory does not exist: ${request.cwd}`);\n const argv = asUser(session, [\"bash\", \"-lc\", request.command]);\n const child = spawn(argv[0]!, argv.slice(1), {\n cwd: request.cwd,\n env: { ...sessionEnv(session, { AI_AGENT: \"eve\", ...baseEnv }), ...request.env },\n stdio: [request.stdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n // Its own process group, so a kill reaches the whole tree.\n detached: true,\n });\n const proc: Proc = {\n id: randomUUID(),\n app,\n session: session.name,\n child,\n events: [],\n bytes: 0,\n exit: undefined,\n exitedAt: undefined,\n listeners: new Set(),\n };\n const push = (event: ProcessEvent) => {\n proc.events.push(event);\n for (const listener of proc.listeners) listener();\n };\n const pipe = (fd: 1 | 2) => (chunk: Buffer) => {\n if (proc.bytes + chunk.length > MAX_PROCESS_OUTPUT) return;\n proc.bytes += chunk.length;\n push({ s: proc.events.length + 1, f: fd, d: chunk.toString(\"base64\") });\n };\n child.stdout?.on(\"data\", pipe(1));\n child.stderr?.on(\"data\", pipe(2));\n child.on(\"error\", (error) => {\n push({ s: proc.events.length + 1, f: 2, d: Buffer.from(`eve sandbox: ${error.message}\\n`).toString(\"base64\") });\n });\n child.on(\"close\", (code, signal) => {\n proc.exit = code ?? 128 + (signal ? (SIGNALS[signal] ?? 1) : 1);\n proc.exitedAt = Date.now();\n push({ s: proc.events.length + 1, x: proc.exit });\n });\n this.all.set(proc.id, proc);\n return proc;\n }\n\n kill(proc: Proc): void {\n if (proc.exit !== undefined || proc.child.pid === undefined) return;\n try {\n process.kill(-proc.child.pid, \"SIGKILL\");\n } catch {\n proc.child.kill(\"SIGKILL\");\n }\n }\n\n killSession(name: string): void {\n for (const proc of this.all.values()) if (proc.session === name) this.kill(proc);\n }\n\n prune(): void {\n for (const [id, proc] of this.all) {\n if (proc.exitedAt !== undefined && Date.now() - proc.exitedAt > PROCESS_RETENTION_MS) this.all.delete(id);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// HTTP\n\nasync function readBody(req: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n size += (chunk as Buffer).length;\n if (size > MAX_BODY) throw new HttpError(413, \"too_large\");\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks);\n}\n\nasync function readJson<T>(req: IncomingMessage): Promise<T> {\n const body = await readBody(req);\n try {\n return JSON.parse(body.toString(\"utf8\") || \"{}\") as T;\n } catch {\n throw new HttpError(400, \"invalid_json\");\n }\n}\n\nfunction sendJson(res: ServerResponse, status: number, value: unknown): void {\n const body = JSON.stringify(value);\n res.writeHead(status, { \"content-type\": \"application/json\", \"content-length\": Buffer.byteLength(body), \"cache-control\": \"no-store\" });\n res.end(body);\n}\n\nexport function createDaemon(config: DaemonConfig, verifier = new TokenVerifier(config)) {\n const sessions = new Sessions(config);\n const processes = new Processes();\n\n const sessionOf = (app: string, id: string): Session => {\n const session = sessions.get(app, decodeURIComponent(id));\n if (!session) throw new HttpError(410, \"session_gone\", \"no such sandbox session\");\n return session;\n };\n const procOf = (app: string, id: string): Proc => {\n const proc = processes.all.get(id);\n if (!proc || proc.app !== app) throw new HttpError(404, \"no_such_process\");\n sessions.touch(proc.session);\n return proc;\n };\n\n async function route(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = new URL(req.url ?? \"/\", \"http://box\");\n const path = url.pathname;\n const method = req.method ?? \"GET\";\n if (method === \"GET\" && path === `${API_PREFIX}/health`) return sendJson(res, 200, { ok: true, version: DAEMON_VERSION });\n if (!path.startsWith(`${API_PREFIX}/`)) throw new HttpError(404, \"not_found\");\n const app = await verifier.verify(req.headers.authorization);\n const parts = path.slice(API_PREFIX.length + 1).split(\"/\");\n\n if (parts[0] === \"sessions\" && parts[1]) {\n const sessionId = decodeURIComponent(parts[1]);\n const sub = parts[2];\n if (!sub && method === \"PUT\") {\n const body = await readJson<EnsureSessionRequest>(req);\n const session = sessions.ensure(app, sessionId, body.template ?? []);\n return sendJson(res, 200, { name: session.name, home: session.home, workspace: session.workspace, created: session.created });\n }\n if (!sub && method === \"GET\") {\n const session = sessionOf(app, parts[1]);\n return sendJson(res, 200, { name: session.name, home: session.home, workspace: session.workspace });\n }\n if (!sub && method === \"DELETE\") {\n processes.killSession(sessionName(app, sessionId));\n sessions.delete(app, sessionId);\n return sendJson(res, 200, { deleted: true });\n }\n const session = sessionOf(app, parts[1]);\n if (sub === \"stop\" && method === \"POST\") {\n processes.killSession(session.name);\n sessions.stop(session.name);\n return sendJson(res, 200, { stopped: true });\n }\n if (sub === \"processes\" && method === \"POST\") {\n const body = await readJson<SpawnRequest>(req);\n if (typeof body.command !== \"string\" || typeof body.cwd !== \"string\" || !body.cwd.startsWith(\"/\")) throw new HttpError(400, \"invalid_request\");\n const env: Record<string, string> = {};\n for (const [key, value] of Object.entries(body.env ?? {})) if (typeof value === \"string\") env[key] = value;\n const proc = processes.start(app, session, { command: body.command, cwd: body.cwd, env, stdin: body.stdin === true }, config.env);\n return sendJson(res, 200, { id: proc.id, pid: proc.child.pid });\n }\n if (sub === \"file\" && method === \"GET\") {\n const target = url.searchParams.get(\"path\") ?? \"\";\n if (!target.startsWith(\"/\")) throw new HttpError(400, \"invalid_path\");\n const bytes = fileop(session, { op: \"read\", path: target });\n res.writeHead(200, { \"content-type\": \"application/octet-stream\", \"content-length\": bytes.length, \"cache-control\": \"no-store\" });\n res.end(bytes);\n return;\n }\n if (sub === \"files\" && method === \"POST\") {\n const body = await readJson<{ files?: WireFile[] }>(req);\n const files = (body.files ?? []).filter((f) => typeof f.path === \"string\" && typeof f.b64 === \"string\");\n if (files.some((f) => !f.path.startsWith(\"/\"))) throw new HttpError(400, \"invalid_path\");\n if (files.length > 0) fileop(session, { op: \"write\", files });\n return sendJson(res, 200, { written: files.length });\n }\n if (sub === \"remove\" && method === \"POST\") {\n const body = await readJson<RemoveRequest>(req);\n if (typeof body.path !== \"string\" || !body.path.startsWith(\"/\")) throw new HttpError(400, \"invalid_path\");\n fileop(session, { op: \"remove\", path: body.path, force: body.force === true, recursive: body.recursive === true });\n return sendJson(res, 200, { removed: true });\n }\n }\n\n if (parts[0] === \"processes\" && parts[1]) {\n const proc = procOf(app, parts[1]);\n const sub = parts[2];\n if (sub === \"events\" && method === \"GET\") return streamEvents(req, res, proc, Number(url.searchParams.get(\"after\") ?? \"0\") || 0);\n if (sub === \"stdin\" && method === \"POST\") {\n const body = await readBody(req);\n const stdin = proc.child.stdin;\n if (!stdin) throw new HttpError(409, \"no_stdin\");\n if (body.length > 0) await new Promise<void>((resolve, reject) => stdin.write(body, (e) => (e ? reject(e) : resolve())));\n if (url.searchParams.get(\"eof\") === \"1\") stdin.end();\n return sendJson(res, 200, { written: body.length });\n }\n if (sub === \"kill\" && method === \"POST\") {\n processes.kill(proc);\n return sendJson(res, 200, { killed: true });\n }\n }\n throw new HttpError(404, \"not_found\");\n }\n\n function streamEvents(req: IncomingMessage, res: ServerResponse, proc: Proc, after: number): void {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store, no-transform\",\n \"x-accel-buffering\": \"no\",\n connection: \"keep-alive\",\n });\n let sent = after;\n const flush = () => {\n while (sent < proc.events.length) {\n const event = proc.events[sent]!;\n sent = event.s;\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n if (\"x\" in event) {\n finish();\n return;\n }\n }\n };\n const heartbeat = setInterval(() => res.write(\": keep-alive\\n\\n\"), 15_000);\n const finish = () => {\n clearInterval(heartbeat);\n proc.listeners.delete(flush);\n res.end();\n };\n req.on(\"close\", () => {\n clearInterval(heartbeat);\n proc.listeners.delete(flush);\n });\n proc.listeners.add(flush);\n flush();\n }\n\n const server = createServer((req, res) => {\n route(req, res).catch((error: unknown) => {\n if (res.headersSent) {\n res.end();\n return;\n }\n if (error instanceof HttpError) return sendJson(res, error.status, { error: error.code, message: error.message });\n sendJson(res, 500, { error: \"internal\", message: String((error as Error)?.message ?? error).slice(0, 300) });\n });\n });\n server.requestTimeout = 0;\n server.headersTimeout = 60_000;\n const timers = [\n setInterval(() => processes.prune(), 60_000),\n setInterval(() => sessions.reapIdle(), 60_000),\n setInterval(() => sessions.expireOld(), 60 * 60 * 1000),\n ];\n return {\n server,\n listen(port = config.port) {\n return new Promise<void>((resolve) => server.listen(port, \"0.0.0.0\", () => resolve()));\n },\n close() {\n for (const timer of timers) clearInterval(timer);\n server.close();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n\nfunction argValue(flag: string): string | undefined {\n const index = process.argv.indexOf(flag);\n return index >= 0 ? process.argv[index + 1] : undefined;\n}\n\nconst isMain = (() => {\n try {\n return import.meta.url === `file://${process.argv[1]}` || (process.argv[1] ?? \"\").endsWith(\"eve-sandbox-daemon.js\");\n } catch {\n return false;\n }\n})();\n\nif (isMain) {\n const command = process.argv[2];\n if (command === \"fileop\") runFileOp();\n if (command === \"serve\") {\n const config = loadConfig(argValue(\"--config\"));\n const daemon = createDaemon(config);\n await daemon.listen();\n process.stdout.write(`eve sandbox daemon ${DAEMON_VERSION} on :${config.port} for ${config.audience}, ${config.allow.length} allowed\\n`);\n } else if (command !== \"fileop\") {\n process.stderr.write(\"usage: eve-sandbox-daemon serve [--config <path>] | fileop\\n\");\n process.exit(2);\n }\n}\n"]}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `unfazed/eve-sandbox` — eve sandboxes backed by an unfazed box.
3
+ *
4
+ * ```ts title="agent/sandbox.ts"
5
+ * import { defineSandbox } from "eve/sandbox";
6
+ * import { UnfazedSandbox } from "unfazed/eve-sandbox";
7
+ *
8
+ * export const environment = UnfazedSandbox.environment({ box: "my-sandbox-box" });
9
+ * export default defineSandbox(() => environment.open());
10
+ * ```
11
+ *
12
+ * The box runs the sandbox daemon (`unfazed eve-sandbox setup` inside it).
13
+ * Each eve session gets its own Unix user, home and workspace on the box; the
14
+ * box keeps them across restarts and redeploys until the session ends. The
15
+ * app authenticates with its workload identity token (audience: the box's
16
+ * URL), so it needs no stored secret; the box's allow list names the apps it
17
+ * serves.
18
+ *
19
+ * Requires the optional peer `eve` (0.90 or newer).
20
+ */
21
+ import type { SandboxSession } from "eve/sandbox";
22
+ import { type SandboxProvider, type SandboxProviderDefinition, type WithPrepareOption } from "eve/sandbox/provider";
23
+ import { type SessionInfo, type WireFile } from "./protocol.js";
24
+ export { TEMPLATE_HOME, TEMPLATE_WORKSPACE } from "./protocol.js";
25
+ /** Options of `UnfazedSandbox.environment()`. */
26
+ export interface UnfazedSandboxOptions {
27
+ /** The box's alias; its URL is `https://<box>.unfz.to`. */
28
+ readonly box?: string;
29
+ /** The box's URL, instead of `box`. */
30
+ readonly url?: string;
31
+ /** Token audience; the box's URL by default. */
32
+ readonly audience?: string;
33
+ /** Supplies the bearer token; the app's workload identity token by default. */
34
+ readonly token?: (audience: string) => Promise<string>;
35
+ /** `fetch` used for every call (tests). */
36
+ readonly fetch?: FetchLike;
37
+ }
38
+ /** The subset of `fetch` the client uses. */
39
+ export type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
40
+ /** The artifact `prepare()` ships with the deployment: the template files. */
41
+ export type UnfazedSandboxArtifact = {
42
+ readonly v: 1;
43
+ readonly files: readonly WireFile[];
44
+ };
45
+ /** What eve checkpoints for a session. */
46
+ export type UnfazedSandboxState = {
47
+ readonly v: 1;
48
+ readonly sessionId: string;
49
+ readonly workspace: string;
50
+ };
51
+ export declare class UnfazedSandboxError extends Error {
52
+ readonly status: number;
53
+ readonly code: string;
54
+ constructor(status: number, code: string, message: string);
55
+ }
56
+ /** The daemon's HTTP API, one per environment. */
57
+ export declare class SandboxClient {
58
+ readonly base: string;
59
+ private readonly bearer;
60
+ private readonly doFetch;
61
+ constructor(base: string, bearer: () => Promise<string>, doFetch?: FetchLike);
62
+ request(method: string, path: string, init?: {
63
+ body?: BodyInit;
64
+ json?: unknown;
65
+ signal?: AbortSignal;
66
+ timeoutMs?: number;
67
+ }): Promise<Response>;
68
+ ok(response: Response, what: string): Promise<Response>;
69
+ ensure(sessionId: string, template: readonly WireFile[]): Promise<SessionInfo>;
70
+ /** The session, or `null` when the box no longer has it. */
71
+ get(sessionId: string): Promise<SessionInfo | null>;
72
+ delete(sessionId: string, signal?: AbortSignal): Promise<void>;
73
+ }
74
+ /** The provider's implementation (for tests); eve apps use {@link UnfazedSandbox}. */
75
+ export declare const unfazedSandboxDefinition: SandboxProviderDefinition<UnfazedSandboxOptions, undefined, UnfazedSandboxArtifact, UnfazedSandboxState, {}>;
76
+ /** The eve sandbox provider backed by an unfazed box. */
77
+ export declare const UnfazedSandbox: SandboxProvider<WithPrepareOption<UnfazedSandboxOptions, SandboxSession>, undefined, SandboxSession>;
@@ -0,0 +1,352 @@
1
+ /**
2
+ * `unfazed/eve-sandbox` — eve sandboxes backed by an unfazed box.
3
+ *
4
+ * ```ts title="agent/sandbox.ts"
5
+ * import { defineSandbox } from "eve/sandbox";
6
+ * import { UnfazedSandbox } from "unfazed/eve-sandbox";
7
+ *
8
+ * export const environment = UnfazedSandbox.environment({ box: "my-sandbox-box" });
9
+ * export default defineSandbox(() => environment.open());
10
+ * ```
11
+ *
12
+ * The box runs the sandbox daemon (`unfazed eve-sandbox setup` inside it).
13
+ * Each eve session gets its own Unix user, home and workspace on the box; the
14
+ * box keeps them across restarts and redeploys until the session ends. The
15
+ * app authenticates with its workload identity token (audience: the box's
16
+ * URL), so it needs no stored secret; the box's allow list names the apps it
17
+ * serves.
18
+ *
19
+ * Requires the optional peer `eve` (0.90 or newer).
20
+ */
21
+ import { defineSandboxProvider, SandboxSessionGoneError, } from "eve/sandbox/provider";
22
+ import { oidcToken } from "../oidc.js";
23
+ import { API_PREFIX, TEMPLATE_HOME, TEMPLATE_WORKSPACE, } from "./protocol.js";
24
+ export { TEMPLATE_HOME, TEMPLATE_WORKSPACE } from "./protocol.js";
25
+ /** Template files larger than this in total belong on the box, not in the artifact. */
26
+ const MAX_TEMPLATE_BYTES = 8 * 1024 * 1024;
27
+ /** One `writeFiles` request carries at most this much content. */
28
+ const MAX_WRITE_BATCH = 16 * 1024 * 1024;
29
+ const CONTROL_TIMEOUT_MS = 60_000;
30
+ export class UnfazedSandboxError extends Error {
31
+ status;
32
+ code;
33
+ constructor(status, code, message) {
34
+ super(message);
35
+ this.status = status;
36
+ this.code = code;
37
+ this.name = "UnfazedSandboxError";
38
+ }
39
+ }
40
+ function boxUrl(options) {
41
+ if (options.url)
42
+ return options.url.replace(/\/+$/, "");
43
+ if (options.box) {
44
+ if (!/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/.test(options.box))
45
+ throw new Error(`unfazed eve sandbox: invalid box alias "${options.box}"`);
46
+ return `https://${options.box}.unfz.to`;
47
+ }
48
+ throw new Error("unfazed eve sandbox: pass { box } or { url }");
49
+ }
50
+ const toB64 = (bytes) => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
51
+ /** The daemon's HTTP API, one per environment. */
52
+ export class SandboxClient {
53
+ base;
54
+ bearer;
55
+ doFetch;
56
+ constructor(base, bearer, doFetch) {
57
+ this.base = base;
58
+ this.bearer = bearer;
59
+ this.doFetch = doFetch ?? ((input, init) => fetch(input, init));
60
+ }
61
+ async request(method, path, init = {}) {
62
+ const headers = { authorization: `Bearer ${await this.bearer()}` };
63
+ let body = init.body;
64
+ if (init.json !== undefined) {
65
+ headers["content-type"] = "application/json";
66
+ body = JSON.stringify(init.json);
67
+ }
68
+ const signals = [AbortSignal.timeout(init.timeoutMs ?? CONTROL_TIMEOUT_MS), ...(init.signal ? [init.signal] : [])];
69
+ return await this.doFetch(`${this.base}${API_PREFIX}${path}`, { method, headers, body, signal: AbortSignal.any(signals) });
70
+ }
71
+ async ok(response, what) {
72
+ if (response.ok)
73
+ return response;
74
+ let code = "http_" + response.status;
75
+ let message = "";
76
+ try {
77
+ const body = (await response.json());
78
+ code = body.error ?? code;
79
+ message = body.message ?? "";
80
+ }
81
+ catch {
82
+ // not JSON
83
+ }
84
+ throw new UnfazedSandboxError(response.status, code, `unfazed eve sandbox: ${what}: ${response.status} ${code}${message ? `: ${message}` : ""}`);
85
+ }
86
+ async ensure(sessionId, template) {
87
+ const res = await this.request("PUT", `/sessions/${encodeURIComponent(sessionId)}`, { json: { template } });
88
+ return (await (await this.ok(res, "start the sandbox")).json());
89
+ }
90
+ /** The session, or `null` when the box no longer has it. */
91
+ async get(sessionId) {
92
+ const res = await this.request("GET", `/sessions/${encodeURIComponent(sessionId)}`);
93
+ if (res.status === 410)
94
+ return null;
95
+ return (await (await this.ok(res, "resume the sandbox")).json());
96
+ }
97
+ async delete(sessionId, signal) {
98
+ const res = await this.request("DELETE", `/sessions/${encodeURIComponent(sessionId)}`, { signal });
99
+ await this.ok(res, "delete the sandbox");
100
+ }
101
+ }
102
+ /** A sandbox session that is gone answers 410: eve then starts a fresh one. */
103
+ function gone(error, sessionId) {
104
+ if (error instanceof UnfazedSandboxError && error.status === 410) {
105
+ throw new SandboxSessionGoneError(`unfazed sandbox for session ${sessionId} is gone`);
106
+ }
107
+ throw error;
108
+ }
109
+ /** Reads a process's event stream, reconnecting after a dropped connection. */
110
+ async function followProcess(client, id, onEvent, signal) {
111
+ let after = 0;
112
+ let failures = 0;
113
+ for (;;) {
114
+ try {
115
+ const res = await client.ok(await client.request("GET", `/processes/${id}/events?after=${after}`, { signal, timeoutMs: 24 * 60 * 60 * 1000 }), "read process output");
116
+ const reader = res.body.getReader();
117
+ const decoder = new TextDecoder();
118
+ let buffer = "";
119
+ for (;;) {
120
+ const { value, done } = await reader.read();
121
+ if (done)
122
+ break;
123
+ buffer += decoder.decode(value, { stream: true });
124
+ let cut;
125
+ while ((cut = buffer.indexOf("\n\n")) >= 0) {
126
+ const frame = buffer.slice(0, cut);
127
+ buffer = buffer.slice(cut + 2);
128
+ for (const line of frame.split("\n")) {
129
+ if (!line.startsWith("data: "))
130
+ continue;
131
+ const event = JSON.parse(line.slice(6));
132
+ after = event.s;
133
+ failures = 0;
134
+ onEvent(event);
135
+ if ("x" in event)
136
+ return event.x;
137
+ }
138
+ }
139
+ }
140
+ }
141
+ catch (error) {
142
+ if (signal.aborted)
143
+ throw error;
144
+ if (error instanceof UnfazedSandboxError && error.status < 500)
145
+ throw error;
146
+ if (++failures > 8)
147
+ throw error;
148
+ }
149
+ await new Promise((resolve) => setTimeout(resolve, Math.min(250 * 2 ** failures, 5000)));
150
+ }
151
+ }
152
+ function connect(client, sessionId, session) {
153
+ const sid = encodeURIComponent(sessionId);
154
+ return {
155
+ workspaceRoot: session.workspace,
156
+ async spawn({ command, env, workingDirectory, stdin, signal }) {
157
+ const res = await client
158
+ .request("POST", `/sessions/${sid}/processes`, { json: { command, cwd: workingDirectory, env, stdin: stdin === true }, signal })
159
+ .then((r) => client.ok(r, "start a command"))
160
+ .catch((error) => gone(error, sessionId));
161
+ const { id, pid } = (await res.json());
162
+ const kill = async () => {
163
+ await client.request("POST", `/processes/${id}/kill`).catch(() => undefined);
164
+ };
165
+ const follow = new AbortController();
166
+ let out;
167
+ let err;
168
+ const stdout = new ReadableStream({ start: (c) => void (out = c) });
169
+ const stderr = new ReadableStream({ start: (c) => void (err = c) });
170
+ const closeStreams = (error) => {
171
+ for (const c of [out, err]) {
172
+ try {
173
+ error === undefined ? c.close() : c.error(error);
174
+ }
175
+ catch {
176
+ // already closed
177
+ }
178
+ }
179
+ };
180
+ const exited = followProcess(client, id, (event) => {
181
+ if ("d" in event)
182
+ (event.f === 1 ? out : err).enqueue(new Uint8Array(Buffer.from(event.d, "base64")));
183
+ }, follow.signal).then((exitCode) => {
184
+ closeStreams();
185
+ return { exitCode };
186
+ }, (error) => {
187
+ closeStreams(error);
188
+ throw error;
189
+ });
190
+ if (signal) {
191
+ const onAbort = () => void kill();
192
+ if (signal.aborted)
193
+ onAbort();
194
+ else
195
+ signal.addEventListener("abort", onAbort, { once: true });
196
+ void exited.finally(() => signal.removeEventListener("abort", onAbort)).catch(() => undefined);
197
+ }
198
+ let pending = Promise.resolve();
199
+ const input = stdin
200
+ ? new WritableStream({
201
+ write: (chunk) => (pending = pending.then(async () => {
202
+ await client.ok(await client.request("POST", `/processes/${id}/stdin`, { body: new Uint8Array(chunk) }), "write stdin");
203
+ })),
204
+ close: () => (pending = pending.then(async () => {
205
+ await client.ok(await client.request("POST", `/processes/${id}/stdin?eof=1`, { body: new Uint8Array() }), "close stdin");
206
+ })),
207
+ })
208
+ : undefined;
209
+ return {
210
+ pid,
211
+ stdin: input,
212
+ stdout,
213
+ stderr,
214
+ wait: () => exited,
215
+ kill,
216
+ };
217
+ },
218
+ async readFile({ path, signal }) {
219
+ const res = await client.request("GET", `/sessions/${sid}/file?path=${encodeURIComponent(path)}`, { signal }).catch((e) => gone(e, sessionId));
220
+ if (res.status === 404)
221
+ return null;
222
+ await client.ok(res, `read ${path}`).catch((e) => gone(e, sessionId));
223
+ return new Uint8Array(await res.arrayBuffer());
224
+ },
225
+ async writeFiles({ files, signal }) {
226
+ let batch = [];
227
+ let size = 0;
228
+ const send = async () => {
229
+ if (batch.length === 0)
230
+ return;
231
+ await client
232
+ .ok(await client.request("POST", `/sessions/${sid}/files`, { json: { files: batch }, signal }), "write files")
233
+ .catch((e) => gone(e, sessionId));
234
+ batch = [];
235
+ size = 0;
236
+ };
237
+ for (const file of files) {
238
+ if (size + file.content.byteLength > MAX_WRITE_BATCH)
239
+ await send();
240
+ batch.push({ path: file.path, b64: toB64(file.content) });
241
+ size += file.content.byteLength;
242
+ }
243
+ await send();
244
+ },
245
+ async removePath({ path, force, recursive, signal }) {
246
+ await client
247
+ .ok(await client.request("POST", `/sessions/${sid}/remove`, { json: { path, force: force === true, recursive: recursive === true }, signal }), `remove ${path}`)
248
+ .catch((e) => gone(e, sessionId));
249
+ },
250
+ async stop() {
251
+ const res = await client.request("POST", `/sessions/${sid}/stop`);
252
+ if (res.status === 410)
253
+ return;
254
+ await client.ok(res, "stop the sandbox");
255
+ },
256
+ // The box keeps the session's processes (an open browser) between steps;
257
+ // its daemon stops a session's processes after it has been idle.
258
+ async close() { },
259
+ };
260
+ }
261
+ /**
262
+ * Captures the workspace and skill files `ctx.populate()` writes at build
263
+ * time, so every new session starts from them. A build-time command other
264
+ * than eve's `$HOME` probe is refused: install tools on the box instead.
265
+ */
266
+ async function captureTemplate(ctx) {
267
+ const files = new Map();
268
+ const empty = () => new ReadableStream({ start: (c) => c.close() });
269
+ const capture = {
270
+ workspaceRoot: TEMPLATE_WORKSPACE,
271
+ async spawn({ command }) {
272
+ if (command.trim() !== `printf '%s\\n' "$HOME"`) {
273
+ throw new Error("unfazed eve sandbox: commands in prepare() do not run at build time; install tools on the box itself (see `unfazed eve-sandbox setup`)");
274
+ }
275
+ return {
276
+ stdout: new ReadableStream({
277
+ start(c) {
278
+ c.enqueue(new TextEncoder().encode(`${TEMPLATE_HOME}\n`));
279
+ c.close();
280
+ },
281
+ }),
282
+ stderr: empty(),
283
+ wait: async () => ({ exitCode: 0 }),
284
+ kill: async () => { },
285
+ };
286
+ },
287
+ async readFile({ path }) {
288
+ return files.get(path) ?? null;
289
+ },
290
+ async writeFiles({ files: written }) {
291
+ for (const file of written)
292
+ files.set(file.path, file.content);
293
+ },
294
+ async removePath({ path, recursive }) {
295
+ files.delete(path);
296
+ if (recursive)
297
+ for (const key of [...files.keys()])
298
+ if (key.startsWith(`${path}/`))
299
+ files.delete(key);
300
+ },
301
+ async stop() { },
302
+ };
303
+ await ctx.populate(capture);
304
+ let total = 0;
305
+ const out = [];
306
+ for (const [path, content] of files) {
307
+ total += content.byteLength;
308
+ out.push({ path, b64: toB64(content) });
309
+ }
310
+ if (total > MAX_TEMPLATE_BYTES) {
311
+ throw new Error(`unfazed eve sandbox: the workspace and skill files are ${total} bytes; at most ${MAX_TEMPLATE_BYTES} fit in a template`);
312
+ }
313
+ return out.sort((a, b) => a.path.localeCompare(b.path));
314
+ }
315
+ /** The provider's implementation (for tests); eve apps use {@link UnfazedSandbox}. */
316
+ export const unfazedSandboxDefinition = {
317
+ name: "unfazed",
318
+ stateProtocolVersion: 1,
319
+ environment(options) {
320
+ const base = boxUrl(options);
321
+ const audience = options.audience ?? base;
322
+ const token = options.token ?? ((aud) => oidcToken(aud));
323
+ const client = new SandboxClient(base, () => token(audience), options.fetch);
324
+ return {
325
+ async prepare(ctx) {
326
+ return { v: 1, files: ctx.isEmpty ? [] : await captureTemplate(ctx) };
327
+ },
328
+ async start(ctx, _open, artifact) {
329
+ const session = await client.ensure(ctx.session.id, artifact?.files ?? []);
330
+ const state = { v: 1, sessionId: ctx.session.id, workspace: session.workspace };
331
+ return { connection: connect(client, ctx.session.id, session), state };
332
+ },
333
+ async resume(ctx, _artifact, state) {
334
+ const sessionId = typeof state?.sessionId === "string" ? state.sessionId : ctx.session.id;
335
+ const session = await client.get(sessionId);
336
+ if (session === null)
337
+ throw new SandboxSessionGoneError(`unfazed sandbox for session ${sessionId} is gone`);
338
+ return connect(client, sessionId, session);
339
+ },
340
+ async onSessionEnd(ctx, state, { signal }) {
341
+ const sessionId = typeof state?.sessionId === "string" ? state.sessionId : ctx.session.id;
342
+ await client.delete(sessionId, signal);
343
+ },
344
+ // Keyed MCP tool sessions keep their sandbox between calls; the box
345
+ // deletes a sandbox nobody used for its retention period.
346
+ toolSessions: true,
347
+ };
348
+ },
349
+ };
350
+ /** The eve sandbox provider backed by an unfazed box. */
351
+ export const UnfazedSandbox = defineSandboxProvider(unfazedSandboxDefinition);
352
+ //# sourceMappingURL=index.js.map