/** * The `run` sandbox: a TypeScript snippet executes inside QuickJS compiled to * WebAssembly (the asyncify build of `quickjs-emscripten`), never inside Node. * * A QuickJS runtime can touch the host only through functions the host binds * into it, so `require`, `process`, `fetch`, `import()`, timers, and every Node * builtin are absent by construction: there is nothing to deny. What the * snippet does see is the global inventory below (`SANDBOX_GLOBALS`, pinned by * `sandbox.test.ts`): the ECMAScript builtins QuickJS ships, the web builtins * this module adds in plain JavaScript (`URL`, `TextEncoder`, `TextDecoder`, * `structuredClone`, `crypto.randomUUID`), a captured `console`, and whatever * an extension installs (the `r` recorder from `./sandbox-proxy.ts`). * * Each run gets its own WebAssembly module instance, runtime, and context, so * nothing survives from one run to the next and a run that ends badly cannot * poison another. Bounds: a memory limit on the runtime, a stack limit, and a * deadline enforced two ways — the interrupt handler stops JavaScript that is * running past it, and the event loop stops waiting on the host past it. An * async host call already in flight at the deadline is allowed to settle * before the run returns, because its side effect is real either way. * * The source is TypeScript or JavaScript. It is wrapped as the body of an * async function (so top-level `await` and `return` both work), types are * stripped on the host with `node:module`'s `stripTypeScriptTypes` (strip-only: * `enum` and parameter properties are syntax errors, as in Node), the result is * parsed, and when the body ends in an expression statement that statement is * rewritten into a `return` from the parse tree, never by string search. */ /** 64 MB: the runtime's allocation ceiling. */ export declare const SANDBOX_MEMORY_LIMIT_BYTES: number; /** The interpreter's own stack ceiling, well inside the WebAssembly stack. */ export declare const SANDBOX_STACK_LIMIT_BYTES: number; /** The serialized (compact JSON) value a run may return. */ export declare const SANDBOX_MAX_VALUE_BYTES: number; /** Console lines retained per run. */ export declare const SANDBOX_MAX_LOG_LINES = 500; /** Characters retained per console line. */ export declare const SANDBOX_MAX_LOG_LINE_CHARS = 2048; /** * The snippet's global inventory, sorted. `r` is present when the chain proxy * is installed (always, in the `run` tool). A new global is a deliberate diff * of this list and of the snapshot test. */ export declare const SANDBOX_GLOBALS: readonly ["AggregateError", "Array", "ArrayBuffer", "BigInt", "BigInt64Array", "BigUint64Array", "Boolean", "DataView", "Date", "Error", "EvalError", "FinalizationRegistry", "Float16Array", "Float32Array", "Float64Array", "Function", "Infinity", "Int16Array", "Int32Array", "Int8Array", "InternalError", "Iterator", "JSON", "Map", "Math", "NaN", "Number", "Object", "Promise", "Proxy", "RangeError", "ReferenceError", "Reflect", "RegExp", "Set", "SharedArrayBuffer", "String", "Symbol", "SyntaxError", "TextDecoder", "TextEncoder", "TypeError", "URIError", "URL", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray", "WeakMap", "WeakRef", "WeakSet", "console", "crypto", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "escape", "eval", "globalThis", "isFinite", "isNaN", "parseFloat", "parseInt", "r", "structuredClone", "undefined", "unescape"]; export type SandboxErrorCode = "RUN_SYNTAX_ERROR" | "RUN_TIMEOUT" | "RUN_MEMORY_EXCEEDED" | "RUN_VALUE_NOT_SERIALIZABLE" | "RUN_VALUE_TOO_LARGE" | "RUN_EXCEPTION"; export interface SandboxLogLine { level: "log" | "info" | "warn" | "error"; line: string; } /** What the snippet threw, as far as the sandbox can describe it without trusting it. */ export interface SandboxThrown { name: string; message: string; /** A string `code` property on the thrown value, when it had one. */ code?: string; /** A string `error_ref` property on the thrown value (set by the chain proxy on host errors). */ error_ref?: string; } export interface SandboxError { code: SandboxErrorCode; message: string; line?: number; column?: number; thrown?: SandboxThrown; } export interface SandboxOutcome { status: "ok" | "error"; /** Compact JSON of the value, when `status` is `ok` and the value was not `undefined`. */ value_json?: string; /** `"undefined"` when the snippet produced `undefined` (reported as `null` data). */ value_kind?: "undefined"; error?: SandboxError; logs: SandboxLogLine[]; /** Console lines past {@link SANDBOX_MAX_LOG_LINES} that were not retained. */ logs_dropped: number; /** True when the deadline passed (the run was stopped or stopped waiting). */ timed_out: boolean; duration_ms: number; } /** * Something the host installs into the sandbox before the snippet runs. * `install` is the source of a function expression `(host) => { … }` evaluated * inside the sandbox and called once with an object carrying the bound host * functions; it may define globals and keeps the host functions in its closure, * so no host function is ever a global. */ export interface SandboxExtension { install: string; /** Synchronous host functions: string (or undefined) arguments, string (or undefined) result. */ sync?: Record) => string | undefined>; /** * Asynchronous host functions: string arguments, resolve to a string. They * should not reject; encode failures in the string. A rejection becomes a * plain `Error` inside the sandbox. */ async?: Record) => Promise>; } export interface SandboxRunOptions { code: string; timeoutMs: number; memoryLimitBytes?: number; maxValueBytes?: number; extensions?: SandboxExtension[]; } export type PreparedSnippet = { ok: true; source: string; } | { ok: false; error: SandboxError; }; /** * Wrap, strip types, parse, and rewrite the final expression statement into a * `return`. The result is the source of one async function expression. */ export declare function prepareSnippet(code: string): PreparedSnippet; /** Run one snippet to completion (or to its bound) and describe how it ended. */ export declare function runInSandbox(opts: SandboxRunOptions): Promise; //# sourceMappingURL=sandbox.d.ts.map