import { S as Shell, a as ShellIO, b as Session, N as Node, c as Command, K as Kernel, E as ExecContext, O as OutputStream, C as Container, B as BinaryBackend, d as createContainer } from './container-BQx27_d-.cjs'; export { e as BinaryExecutionRegistry, f as BinaryInfo, g as BinaryRequest, h as BufferSink, i as CallbackSink, j as CommandRegistry, k as ContainerFs, l as ContainerOptions, m as ContextInit, n as Env, o as ExecOptions, p as ExecResult, q as ExecutionDecision, r as ExecutionTier, F as FileData, s as FileInput, t as FileOutput, G as GroupEntry, H as HttpResponse, I as InputStream, J as Job, u as KernelOptions, L as ListeningPort, M as MANIFEST_FORMAT, v as MANIFEST_SCHEMA_VERSION, w as MountEntry, x as NetInterface, y as NetworkOptions, z as NetworkStack, A as NullInput, D as NullOutput, P as PYTHON_VERSION, Q as PasswdEntry, R as Pipe, T as Preparation, U as PreparedBinary, V as Process, W as ProcessKind, X as ProcessOptions, Y as ProcessState, Z as ProcessTable, _ as PythonCapabilities, $ as PythonOptions, a0 as PythonProfile, a1 as PythonRuntimeManifest, a2 as ResolvedExecutable, a3 as RunOptions, a4 as RunResult, a5 as SessionInit, a6 as SessionResult, a7 as SessionRunOptions, a8 as ShellExit, a9 as ShellInit, aa as ShellOptions, ab as SpawnHandle, ac as Stdio, ad as TeeOutput, ae as UserDatabase, af as Variables, ag as WasmCommandArtifact, ah as WasmTranslator, ai as binaryDigest, aj as braceExpand, ak as captureStdio, al as configurePython, am as createContext, an as createTranslationBackend, ao as createWasmCompatibilityBackend, ap as defineCommand, aq as expandWord, ar as expandWords, as as inspectElf, at as installWasmCommands, au as isElfBinary, av as isPythonAvailable, aw as resetPidCounter, ax as shellQuote, ay as validateManifest } from './container-BQx27_d-.cjs'; import { V as Vfs, C as Cred, R as RuntimeVolume, a as VirtualTcpNetwork, b as RuntimeHttpResponse, O as OutboundPolicy, S as SpawnChild, c as SyncSpawn, I as IpcTransport, d as VolumeStat, e as VolumeStats, f as RuntimePod, g as RuntimePackageInstaller, h as ChildSpawnConfig, i as ChildHandle, j as RuntimeProcess, k as RuntimeSocketPeer, l as RuntimeConnection } from './contracts-BHo4LdY2.cjs'; export { D as DirEntry, m as ROOT_CRED, n as RuntimeProcessManager, o as RuntimeProcessResult, p as Stats, q as VirtualNode, r as VirtualProvider, W as WriteOptions, s as applyChmod, t as createChildProcessModule, u as formatMode, v as makeCred, w as octalMode, x as parseUmask } from './contracts-BHo4LdY2.cjs'; import { M as MemoryVolume, a as MemoryVolumeSnapshotEntry } from './memory-volume-e-uJFRnG.cjs'; import EventEmitter from 'events/events.js'; import streamModule from 'stream-browserify'; /** * POSIX path helpers. Deliberately independent of `node:path` so container * paths behave identically no matter what platform the host runs on. */ declare const SEP = "/"; declare function isAbsolute(p: string): boolean; /** Split into non-empty segments, dropping the leading/trailing slashes. */ declare function segments(p: string): string[]; /** * Lexical normalisation: collapse `//`, resolve `.` and `..` without touching * the filesystem. Symlinks are *not* followed — that is `Vfs.realpath`'s job. */ declare function normalize(p: string): string; /** Join fragments then normalise, like `path.posix.join`. */ declare function join(...parts: string[]): string; /** Resolve `p` against `base` (usually a process cwd) to an absolute path. */ declare function resolve(base: string, ...parts: string[]): string; declare function dirname(p: string): string; declare function basename(p: string, ext?: string): string; declare function extname(p: string): string; /** Relative path from `from` to `to`, both assumed absolute + normalised. */ declare function relative(from: string, to: string): string; /** True when `child` is `parent` or lives beneath it. */ declare function contains(parent: string, child: string): boolean; /** Drop a trailing slash except on the root, for display and map keys. */ declare function clean(p: string): string; declare const path_SEP: typeof SEP; declare const path_basename: typeof basename; declare const path_clean: typeof clean; declare const path_contains: typeof contains; declare const path_dirname: typeof dirname; declare const path_extname: typeof extname; declare const path_isAbsolute: typeof isAbsolute; declare const path_join: typeof join; declare const path_normalize: typeof normalize; declare const path_relative: typeof relative; declare const path_resolve: typeof resolve; declare const path_segments: typeof segments; declare namespace path { export { path_SEP as SEP, path_basename as basename, path_clean as clean, path_contains as contains, path_dirname as dirname, path_extname as extname, path_isAbsolute as isAbsolute, path_join as join, path_normalize as normalize, path_relative as relative, path_resolve as resolve, path_segments as segments }; } /** Registry of shell builtins. Lookup order in the interpreter is: function, builtin, then `$PATH`. */ interface BuiltinContext { shell: Shell; /** Full argv, including argv[0]. */ argv: string[]; io: ShellIO; } type Builtin = (ctx: BuiltinContext) => Promise | number; declare function getBuiltin(name: string): Builtin | undefined; declare function isBuiltinName(name: string): boolean; declare function builtinNames(): string[]; /** * An interactive terminal on top of a `Session`. * * Deliberately transport-agnostic: feed it keystrokes with `input()` and it * calls `write()` with what should appear on screen. That works equally well * for a real TTY (the `sandboxedjs` CLI) and for xterm.js in a browser app. * * Provides line editing, history, tab completion over commands and paths, * multi-line continuation for unfinished commands, and the usual control keys. */ interface TerminalOptions { /** Called with text to display. */ write(data: string): void; columns?: number; rows?: number; /** Overrides `$PS1` when provided. */ prompt?: (session: Session) => string; /** Print `/etc/motd` when the terminal starts. Default true. */ motd?: boolean; /** Invoked after the shell exits. */ onExit?: (code: number) => void; } declare class Terminal { private readonly session; private readonly opts; private buffer; private cursor; private pending; private historyIndex; private savedLine; private running; private closed; private escapeBuffer; private currentStdin; private exitCode; columns: number; rows: number; constructor(session: Session, opts: TerminalOptions); /** Print the banner and the first prompt. */ start(): void; resize(columns: number, rows: number): void; /** Feed raw keystrokes. */ input(data: string): void; close(): void; get isClosed(): boolean; private write; private promptText; private writePrompt; /** Repaint the current line after an edit. */ private redraw; private key; private handleEscape; private recallHistory; private complete; private completeCommand; private completePath; private submit; private execute; } /** Expand a `PS1`-style prompt string. */ declare function expandPrompt(format: string, session: Session): string; /** POSIX signal numbers, names and default dispositions. */ declare const SIGNALS: Record; declare const SIGNAL_NAMES: Record; /** * Normalise anything `kill` might be handed — `9`, `TERM`, `SIGTERM`, `-9` — * into a canonical `SIGxxx` name. Returns null when unrecognised. */ declare function normalizeSignal(spec: string | number): string | null; /** The `$?` value a shell reports for a process killed by `sig`. */ declare function exitCodeForSignal(sig: string): number; /** * The identity the container reports for itself. * * The runtime's `os.release()` is built from these same constants, so `uname -r` * and `node -p "os.release()"` agree inside the container — a program that * checks the platform gets one answer whichever way it asks. */ declare const KERNEL_NAME = "Linux"; declare const KERNEL_RELEASE = "5.10.0"; declare const OS_RELEASE = "PRETTY_NAME=\"SandboxedJS 1.0 (sandbox)\"\nNAME=\"SandboxedJS\"\nVERSION_ID=\"1.0\"\nVERSION=\"1.0 (sandbox)\"\nVERSION_CODENAME=sandbox\nID=sandboxedjs\nID_LIKE=debian\nHOME_URL=\"https://www.npmjs.com/package/sandboxedjs\"\nSUPPORT_URL=\"https://www.npmjs.com/package/sandboxedjs\"\n"; interface UnameInfo { sysname: string; nodename: string; release: string; version: string; machine: string; processor: string; hardwarePlatform: string; operatingSystem: string; } declare function unameInfo(hostname: string): UnameInfo; /** * Linux errno numbers and the `SysError` type every syscall-ish helper throws. * * The numbers match Linux x86-64 so that programs which print `err.errno` * (or read `$?` after a failed syscall) see the values they would on a real box. */ declare const ERRNO: { readonly EPERM: 1; readonly ENOENT: 2; readonly ESRCH: 3; readonly EINTR: 4; readonly EIO: 5; readonly ENXIO: 6; readonly E2BIG: 7; readonly ENOEXEC: 8; readonly EBADF: 9; readonly ECHILD: 10; readonly EAGAIN: 11; readonly ENOMEM: 12; readonly EACCES: 13; readonly EFAULT: 14; readonly ENOTBLK: 15; readonly EBUSY: 16; readonly EEXIST: 17; readonly EXDEV: 18; readonly ENODEV: 19; readonly ENOTDIR: 20; readonly EISDIR: 21; readonly EINVAL: 22; readonly ENFILE: 23; readonly EMFILE: 24; readonly ENOTTY: 25; readonly ETXTBSY: 26; readonly EFBIG: 27; readonly ENOSPC: 28; readonly ESPIPE: 29; readonly EROFS: 30; readonly EMLINK: 31; readonly EPIPE: 32; readonly EDOM: 33; readonly ERANGE: 34; readonly EDEADLK: 35; readonly ENAMETOOLONG: 36; readonly ENOLCK: 37; readonly ENOSYS: 38; readonly ENOTEMPTY: 39; readonly ELOOP: 40; readonly ENOMSG: 42; readonly ENOTSOCK: 88; readonly EADDRINUSE: 98; readonly EADDRNOTAVAIL: 99; readonly ENETDOWN: 100; readonly ECONNRESET: 104; readonly ENOTCONN: 107; readonly ETIMEDOUT: 110; readonly ENETUNREACH: 101; readonly ECONNREFUSED: 111; readonly EHOSTUNREACH: 113; readonly ENOTSUP: 95; }; type ErrnoCode = keyof typeof ERRNO; /** An error carrying the same shape Node uses for `fs` failures. */ declare class SysError extends Error { readonly code: ErrnoCode; readonly errno: number; readonly syscall: string; readonly path?: string; readonly dest?: string; constructor(code: ErrnoCode, syscall: string, path?: string, dest?: string); /** The message a coreutil prints: `ls: /nope: No such file or directory`. */ toUserMessage(program: string, subject?: string | undefined): string; } declare function isSysError(e: unknown): e is SysError; declare function strerror(code: ErrnoCode): string; /** * Pattern matching: `fnmatch(3)` semantics for `case`/`find -name`, plus the * pathname expansion the shell performs on unquoted words. */ interface MatchOptions { /** `*` and `?` stop at `/` (shell pathname expansion). */ pathname?: boolean; /** Match leading dots with wildcards (shell `dotglob`). */ dot?: boolean; /** Case-insensitive comparison. */ nocase?: boolean; /** Enable ksh-style `?(a|b)`, `*(a|b)`, `+(...)`, `@(...)`, `!(...)`. */ extglob?: boolean; } declare function globToRegex(pattern: string, opts?: MatchOptions): RegExp; /** `fnmatch(3)`. */ declare function fnmatch(pattern: string, str: string, opts?: MatchOptions): boolean; /** True when the word contains an unescaped glob metacharacter. */ declare function hasMagic(word: string, extglob?: boolean): boolean; interface GlobOptions extends MatchOptions { cwd?: string; cred?: Cred; /** Only return paths that are directories (trailing `/` in the pattern). */ onlyDirs?: boolean; /** Cap on results, to keep a runaway `/**` from exhausting memory. */ limit?: number; } /** * Pathname expansion against the container filesystem. Returns absolute paths * when the pattern is absolute, otherwise paths relative to `cwd` — matching * how the shell substitutes the results back into the command line. */ declare function glob(vfs: Vfs, pattern: string, opts?: GlobOptions): string[]; /** * Shell tokenizer. * * Words are kept as *raw* text with their quotes intact — expansion happens * later, in `expand.ts`, which is the only stage that needs to distinguish * `"$x"` from `$x`. The lexer's job is to find word boundaries correctly in the * presence of quoting, `$(...)`, backticks and `${...}`, and to pull here-doc * bodies out of the stream at the right moment. */ type TokenType = "word" | "op" | "newline" | "eof" | "io_number"; interface HeredocInfo { tag: string; /** `<<-` strips leading tabs from the body and the delimiter line. */ stripTabs: boolean; /** A quoted tag disables expansion inside the body. */ quoted: boolean; body: string; } interface Token { type: TokenType; value: string; pos: number; /** Attached to the `<<` operator token once the body has been collected. */ heredoc?: HeredocInfo; } declare class ShellSyntaxError extends Error { readonly pos: number; constructor(message: string, pos: number); } /** Thrown when input ends mid-construct, so a REPL can ask for another line. */ declare class IncompleteInputError extends ShellSyntaxError { constructor(message: string, pos: number); } declare class Lexer { private readonly src; private pos; private readonly tokens; /** Here-docs whose bodies are collected when the current line ends. */ private pendingHeredocs; constructor(src: string); static tokenize(src: string): Token[]; run(): Token[]; private push; /** True when `prev` ends exactly where the current operator begins. */ private adjacent; private skipBlanks; private matchOperator; private readWord; private readDoubleQuoted; /** * Consume a balanced `$( ... )` or `${ ... }`, honouring nesting and quotes * inside. `prefix` is emitted before the opening delimiter. */ private readBalanced; private skipDoubleQuoted; private findBacktickEnd; /** * Called right after a newline: read the bodies of every here-doc whose * operator appeared on the line just finished. */ private collectHeredocs; } /** * Recursive-descent parser for the shell grammar. * * Covers the POSIX command language plus the bash extensions that scripts in * the wild actually depend on: `[[ ]]`, `(( ))`, `function name { }`, * `for ((;;))`, `select`, `|&`, `&>`, `<<<`, and `;&`/`;;&` in `case`. */ declare function parse(source: string): Node; /** * Arithmetic expansion — the `$(( ... ))` and `(( ... ))` evaluator. * * Implements the C-like operator set bash supports, including assignment, * pre/post increment, the ternary, comma, and `base#digits` literals. Values * are integers; division by zero is an error, as it is in bash. */ interface ArithScope { get(name: string): string | undefined; set(name: string, value: string): void; } declare class ArithError extends Error { constructor(message: string); } declare function evalArith(expression: string, scope: ArithScope): number; /** * The userland: every program installed into `$PATH` at boot. * * Each command is a real file under `/bin`, `/sbin` or `/usr/bin`, so `which`, * `ls -l /usr/bin` and shebang dispatch all behave the way they do on a real * system. */ /** Every command, in installation order. */ declare function allCommands(): Command[]; /** * Install the userland into a kernel. Commands declaring their own `path` land * there; everything else goes to `/usr/bin`, with `/bin` and `/sbin` symlinked * the way merged-`/usr` distributions do. */ declare function installUserland(kernel: Kernel): void; /** * The root filesystem image. * * Everything here is a real file in the volume, not a special case in code — * `/etc/passwd` is what `id` reads, `/etc/profile` is what a login shell * sources, and `/etc/os-release` is what `lsb_release` parses. Editing them * inside the container changes behaviour, exactly as it would on a real box. */ interface RootfsOptions { hostname?: string; /** Non-root login user created at boot. Pass null for a root-only image. */ user?: { name: string; uid?: number; gid?: number; home?: string; shell?: string; } | null; timezone?: string; } declare function buildRootfs(vfs: Vfs, opts?: RootfsOptions): void; /** * The Node.js command adapter, backed by the clean-room RuntimePod. * * The pod runs the script over the *same* memory volume * the container's filesystem uses, so `require('fs')` inside a script sees the * files `echo` and `tar` created, and anything the script writes is visible to * the shell afterwards. * * Two details of the underlying `spawn` are handled here: * - only `node` resolves as a command, so everything else is dispatched by our * own kernel rather than being handed to the Node process runner; * - the worker's stdin has no end-of-stream signal, so when a pipeline feeds * a script we materialise stdin as a file and install a real stdin stream * over it before the script loads. */ declare const NODE_VERSION = "v22.12.0"; /** * Package managers: `npm`/`npx`/`yarn`/`pnpm` on top of the runtime's package * installer, and an `apt`-shaped front end for the things a container image * would ship. */ declare const NPM_VERSION = "10.9.0"; /** * How a specifier was requested. Node resolves the same package differently * for the two, and a dual package depends on that: `is-promise` exports a * callable function under "require" and a namespace under "import", so * `require("is-promise")` served the ESM build is not merely suboptimal, it is * a `TypeError` at the first call site. */ type RequestKind = "import" | "require"; interface CommonJsModule { id: string; filename: string; exports: any; loaded: boolean; parent: CommonJsModule | null; children: CommonJsModule[]; /** * Set for an ES module whose body contains a top-level `await`: the promise * for its completion. A synchronous `require` of such a module cannot * succeed, and this is what lets the engine say so precisely. */ pending?: Promise; } interface CommonJsEngineOptions { volume: RuntimeVolume; cwd?: string; builtins?: Record; globals?: Record; /** * Package-name substitutions, applied to bare specifiers before resolution. * * Several cornerstone build tools ship a compiled addon on the platforms * they support and a WebAssembly build for everywhere else — `rollup` and * `@rollup/wasm-node`, `esbuild` and `esbuild-wasm`. This runtime is always * the "everywhere else" case, but the packages select their binding by * reading `process.platform`, which reports a platform whose addon exists * and cannot be loaded. Redirecting the name is how the WebAssembly build * gets chosen instead. * * A substitution that is not installed falls back to the original name, so * an alias is a preference rather than a requirement. */ aliases?: Record; /** * Modules supplied by the runtime instead of resolved from the filesystem. * * The case this exists for is a toolchain component that cannot execute * inside the sandbox at all. `esbuild` is the example: every build of it * either dlopens a compiled addon or drives a Go/WebAssembly process through * facilities the runtime does not have, so the copy installed in * `node_modules` is unusable no matter which one is chosen. Handing over a * working implementation is what lets the tools built on it run. * * These take precedence over an installed package of the same name but not * over a Node built-in, so an override can never shadow `fs`. */ overrides?: Record; } /** * CommonJS loader for a runtime worker. The worker is the security boundary; * this class intentionally has no dependency on Node's module implementation. */ declare class CommonJsEngine { readonly volume: RuntimeVolume; readonly cache: Map; readonly builtins: Record; readonly globals: Record; readonly aliases: Record; readonly overrides: Record; cwd: string; main: CommonJsModule | null; /** `package.json` per directory; resolution reads them constantly. */ private readonly manifests; private evaluationDepth; private readonly moduleApi; /** * Is a module body running synchronously right now? * * `process.exit` unwinds by throwing, and that is only safe while one of * this engine's own frames is on the stack to catch it. Thrown from a later * callback — a stream handler, a timer — it would escape into whichever * library called that callback and surface as an unrelated crash. */ get isEvaluating(): boolean; constructor(volume: RuntimeVolume, options?: Omit); /** * Evaluate an entry point. * * Returns the module's exports, or a promise for them when the entry is an * ES module with a top-level `await` — the caller has to await that before * treating the program as finished. */ run(entry: string): unknown | Promise; require(specifier: string, importer?: string): unknown; resolve(specifier: string, importer: string, kind?: RequestKind): string; private load; private evaluate; /** The `require` a module sees, complete with `resolve`, `cache` and `main`. */ private makeRequire; /** * Load `specifier` and present it as an ES module namespace. * * A static `import` is synchronous here, exactly as the CommonJS `require` * it compiles down to. That is the one place this engine knowingly differs * from Node's real ESM semantics, and it is the trade that lets both module * systems share a single cache and resolver. */ private importNamespace; /** `import(...)`: the same load, but able to await a top-level `await`. */ private dynamicImport; /** `import.meta` for a module. */ private importMeta; /** * The substituted specifier for `specifier`, or null when none applies. * * An alias names a package, so a subpath rides along: aliasing `rollup` also * redirects `rollup/dist/native.js` into the substitute. */ private aliasFor; /** * Resolve a bare specifier (`pkg`, `@scope/pkg`, `pkg/sub`) by walking * `node_modules` up from the importer, exactly as Node does. */ private resolvePackage; /** * Resolve `subpath` ("" for the package root) inside an installed package. * * An `exports` map, when present, is authoritative: Node refuses paths it * does not name, and packages rely on that to keep their internals private. * Only a package without one falls back to `main`/`module` and to treating * the subpath as a plain file path. */ private resolveInPackage; /** * Resolve a `#private` specifier through the importing package's `imports` * map, which is scoped to the nearest enclosing package rather than to * `node_modules`. */ private resolveImports; /** Resolve a path to a file, trying Node's extension and index fallbacks. */ private resolvePath; private resolveIndex; /** The nearest ancestor directory holding a `package.json`. */ private packageRoot; private readManifest; private builtin; private exists; private isFile; private isDirectory; private readText; private moduleNotFound; } interface VirtualRequestInit { method?: string; path?: string; headers?: Record; body?: string | Uint8Array | ArrayBuffer | null; } declare class VirtualIncomingMessage extends streamModule.Readable { readonly method: string; readonly url: string; readonly headers: Record; readonly rawHeaders: string[]; readonly httpVersion = "1.1"; readonly httpVersionMajor = 1; readonly httpVersionMinor = 1; readonly complete = true; socket: Record | VirtualSocket; get connection(): Record | VirtualSocket; constructor(init: VirtualRequestInit); _read(): void; setTimeout(_milliseconds: number, callback?: () => void): this; } declare class VirtualServerResponse extends streamModule.Writable { statusCode: number; statusMessage: string; headersSent: boolean; sendDate: boolean; readonly req: VirtualIncomingMessage; readonly socket: Record; readonly connection: Record; private readonly headers; private readonly chunks; private resolve; readonly completed: Promise; constructor(request: VirtualIncomingMessage); _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; _final(callback: (error?: Error | null) => void): void; _destroy(error: Error | null, callback: (error?: Error | null) => void): void; private settled; private settle; setHeader(name: string, value: string | number | readonly string[]): this; appendHeader(name: string, value: string | readonly string[]): this; getHeader(name: string): string | string[] | undefined; getHeaders(): Record; getHeaderNames(): string[]; hasHeader(name: string): boolean; removeHeader(name: string): void; writeHead(statusCode: number, statusMessage?: string | Record, headers?: Record): this; flushHeaders(): void; _implicitHeader(): void; get _header(): string | null; get finished(): boolean; chunkedEncoding: boolean; useChunkedEncodingByDefault: boolean; strictContentLength: boolean; writeContinue(): void; writeProcessing(): void; addTrailers(_headers: Record): void; setTimeout(_milliseconds: number, callback?: () => void): this; } /** Where a {@link VirtualSocket} puts the bytes the server writes. */ interface VirtualSocketPeer { /** The server sent these. */ data(bytes: Uint8Array): void; /** The server hung up. */ close(): void; } /** * The server half of a connection that has stopped being HTTP. * * Everything else in this file models one request and one response, because * that is all a container's servers were ever asked for. A protocol upgrade is * the case that does not fit: after the `101` there is no request and no * response, only two peers writing bytes at each other for as long as they * both stay interested. * * So this is a real `Duplex` rather than another stub. It has to be — the * libraries that speak WebSocket do not merely read `req.headers` and reply, * they take the socket and run a framing protocol over it, and a stub that * accepts `write()` and drops it produces a server that completes its * handshake and is then silent forever, which looks exactly like a network * problem and is the hardest possible thing to attribute. * * Writes go out through {@link VirtualSocketPeer}; {@link deliver} pushes what * comes back. Nothing here knows what the bytes mean, which is the point: `ws`, * `socket.io` and Vite's HMR server all work over it unmodified. */ declare class VirtualSocket extends streamModule.Duplex { readonly remoteAddress = "127.0.0.1"; readonly remotePort = 0; readonly localAddress = "127.0.0.1"; readonly localPort = 0; readonly encrypted = false; readonly bufferSize = 0; private peer; /** Set once the peer is told, so `end()` then `destroy()` reports once. */ private hungUp; constructor(peer: VirtualSocketPeer); _read(): void; _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void; _final(callback: (error?: Error | null) => void): void; _destroy(error: Error | null, callback: (error?: Error | null) => void): void; private hangUp; /** Bytes arriving from the far end. */ deliver(bytes: Uint8Array): void; /** The far end went away; let the server's stream end cleanly. */ peerClosed(): void; setNoDelay(): this; setKeepAlive(): this; setTimeout(_milliseconds: number, callback?: () => void): this; destroySoon(): void; ref(): this; unref(): this; } declare class VirtualHttpServer extends EventEmitter { private readonly router; readonly owner: string; listening: boolean; private portValue; private referenced; constructor(router: VirtualHttpRouter, owner: string, listener?: (req: VirtualIncomingMessage, res: VirtualServerResponse) => void); listen(...args: any[]): this; close(callback?: (error?: Error) => void): this; address(): { address: string; family: string; port: number; } | null; ref(): this; unref(): this; hasRef(): boolean; setTimeout(_milliseconds: number, callback?: () => void): this; } declare class VirtualHttpRouter { private readonly sockets?; private readonly servers; /** Notified when a server begins listening, for `onServerReady`. */ onListen: ((port: number) => void) | undefined; onClose: ((port: number) => void) | undefined; constructor(sockets?: VirtualTcpNetwork | undefined); register(port: number, server: VirtualHttpServer, owner: string): void; unregister(port: number, server: VirtualHttpServer): void; /** Whether anything in this container is listening on `port`. */ activePortsIncludes(port: number): boolean; activePorts(owner?: string): number[]; referencedPorts(owner: string): number[]; closeOwner(owner: string): void; closeAll(): void; request(port: number, init?: VirtualRequestInit): Promise; /** * Open a connection that leaves HTTP behind — a WebSocket, in practice. * * The counterpart to {@link request}, and the thing whose absence made a dev * server look broken. Every Node WebSocket library is built the same way: it * hands `http.Server` an `upgrade` listener and waits. Nothing here ever * emitted one, so `ws` sat holding a server that could not receive a single * connection, and Vite lost the channel it uses to tell a page to reload — * which is the only way it can recover after re-optimizing dependencies. * * Null means there is nothing to connect to: no server on the port, or a * server that never asked for upgrades. Both are refusals the caller should * report rather than wait out. */ connect(port: number, init: VirtualRequestInit, peer: VirtualSocketPeer): VirtualConnection | null; } /** A connection handed back by {@link VirtualHttpRouter.connect}. */ interface VirtualConnection { /** Bytes from the far end, into the container. */ send(bytes: Uint8Array): void; /** The far end went away. */ close(): void; } /** A loopback request, as it crosses from a program to whoever holds the port. */ interface LoopbackRequest { method: string; path: string; headers: Record; body: Uint8Array | null; } interface LoopbackResponse { statusCode?: number; statusMessage?: string; headers?: Record; body?: string | ArrayBuffer | Uint8Array | null; } /** * Reaches a server in this container that is not on this thread's router. * Resolves `null` when nothing in the container listens on the port. */ type LoopbackTransport = (port: number, request: LoopbackRequest) => Promise; interface CoreModulesOptions { volume: RuntimeVolume; cwd?: string; env?: Record; argv?: string[]; /** A `Buffer` written to the stream arrives as bytes, a string as a string. */ stdout?: (chunk: string | Uint8Array) => void; stderr?: (chunk: string | Uint8Array) => void; onExit?: (code: number) => void; http?: { router: VirtualHttpRouter; owner: string; fetch?: typeof globalThis.fetch; /** Servers in other processes, for a router that holds only this thread's. */ loopback?: LoopbackTransport; /** * The container's outbound policy, applied to `fetch`, `http`, `https` and * `WebSocket`. Omitted, requests leave the way the host's own would. */ policy?: OutboundPolicy; }; /** Backs `child_process`; without it the module reports as unavailable. */ spawnChild?: SpawnChild; /** * Backs the `*Sync` half of `child_process`. * * Only a pod whose guest runs on its own thread can supply this — blocking * requires somewhere else for the child's work to happen. Without it the * synchronous entry points keep reporting that they are unavailable. */ syncSpawn?: SyncSpawn; /** File holding the process's standard input, exposed as descriptor 0. */ stdinPath?: string; /** Keep `process.stdin` open and fed by {@link writeStdin} rather than ending it. */ interactiveStdin?: boolean; /** Report the standard streams as a terminal, which is what makes CLIs prompt. */ tty?: boolean; /** Called when the program turns raw mode on or off. */ onRawMode?: (enabled: boolean) => void; /** The host's `fork` channels: how a parent opens one and a forked child finds its own. */ ipc?: IpcTransport; } /** Build the core-module table injected into each isolated JS worker. */ declare function createCoreModules(options: CoreModulesOptions): { builtins: Record; globals: Record; process: Record; /** Deliver a chunk of input to an interactive `process.stdin`; bytes stay bytes. */ writeStdin(data: string | Uint8Array): void; /** Signal end-of-input to an interactive `process.stdin`. */ endStdin(): void; /** * Is the program waiting on input? * * Node keeps a process alive for an open stdin only while something is * actually reading it, and that distinction matters here: a CLI sitting on a * prompt has no timers pending and would otherwise look finished, while a * program that never touches stdin must still be allowed to exit. */ readingStdin(): boolean; /** * How many timers this process still has outstanding. * * Node keeps a process alive while its event loop has work, and exits when * it does not. Tracking the timers a program schedules is what lets this * runtime make the same decision — without it a server that binds its port * one turn after its entry module settles looks indistinguishable from a * script that has simply finished. */ pendingHandles(): number; /** Active timers which called `unref()` and therefore only merit startup grace. */ pendingUnrefed(): number; /** * Cancel every timer this process still holds. * * Called when a process is killed: the process is finished, but its * scheduled work would otherwise keep running on the host's event loop. */ cancelTimers(): void; /** * Client requests sent but not yet read to completion. * * An outbound request is event-loop work in exactly the way a timer is, and * it schedules no timer of its own. Counting it is what stops a program from * exiting in the gap between `http.get` and its response callback. */ pendingRequests(): number; /** An error that escaped the program's callbacks: listeners, or print and exit 1. */ reportUncaught(error: unknown): void; /** A rejection nobody handled, under the same rule. */ reportUnhandledRejection(reason: unknown): void; /** The status a program ends with: `process.exit`'s code, else `process.exitCode`. */ exitStatus(): number; /** Run `process.on("exit")` listeners once, for a program that ended by itself. */ emitExit(status: number): void; /** * Drain the `process.nextTick` queue now. * * Node drains it whenever a callback from the event loop returns — the entry * module included — before any promise callback that code queued. The runtime * calls this at those same points. */ runTicks(): void; /** Emit `beforeExit` for a loop that ran out of work; false when nothing listens or the process is exiting. */ emitBeforeExit(status: number): boolean; /** Increases whenever the program schedules event-loop work (timers, immediates, requests). */ loopActivity(): number; }; interface EsmTransformResult { /** The rewritten source. */ code: string; /** * True when the file is an ES module, and so must be evaluated in a wrapper * that does not inject `require`, `module`, `__filename` or `__dirname`. * * False for a CommonJS file that was rewritten only because it contains a * dynamic `import(...)`, which is legal there and still has to be routed * through the engine rather than to the host realm. */ esm: boolean; /** True when the module body contains a top-level `await`. */ topLevelAwait: boolean; } declare function looksLikeEsm(source: string): boolean; /** * Rewrite `source` from ESM to the engine's CommonJS wrapper shape, or return * `null` when it is not an ES module and should be evaluated as-is. * * `null` is also returned when the source does not parse as a module: that is * not this function's error to raise. Letting it through means the engine * evaluates the original text and the runtime reports the real syntax error at * the real position. */ declare function transformEsm(source: string, filename?: string): EsmTransformResult | null; /** * A volume that keeps a second, foreign filesystem in step with itself. * * Rolldown's browser WebAssembly binding owns a `memfs` volume of its own — * its Rust resolver reads through WASI, not through anything JavaScript can * hand it. So the sandbox project has to exist in two places at once, and the * copy has to stay current: a dev server reads `index.html` when the request * arrives, not when the process started. * * Mirroring on write rather than copying up-front is what makes that true. The * previous approach took one deep snapshot per spawn, which was both expensive * — every `npm run dev` re-copied `node_modules` — and already stale by the * time it mattered, so an edit during a session was served from the old tree. * * The mirror is deliberately one-way and best-effort. It is a cache for a * consumer that only reads; a write that fails to reach it must never fail the * write that the container itself made. */ /** The slice of a `memfs`-style filesystem the mirror writes through. */ interface MirrorFs { mkdirSync(path: string, options?: { recursive?: boolean; }): void; writeFileSync(path: string, data: Uint8Array): void; symlinkSync(target: string, path: string): void; rmSync?(path: string, options?: { recursive?: boolean; force?: boolean; }): void; unlinkSync?(path: string): void; rmdirSync?(path: string): void; readdirSync?(path: string): string[]; readFileSync?(path: string): Uint8Array; lstatSync?(path: string): { isDirectory(): boolean; isSymbolicLink(): boolean; size?: number; }; } /** * A `RuntimeVolume` that forwards every mutation to an optional mirror. * * Wrapping rather than modifying `MemoryVolume` keeps the mirroring concern out * of the filesystem, and keeps this transparent to the kernel, whose `Vfs` * takes any `RuntimeVolume`. */ declare class MirroringVolume implements RuntimeVolume { private readonly inner; private mirror; private root; constructor(inner?: MemoryVolume); /** * Start mirroring the tree under `root`, seeding it with what is there now. * * Called once the Rolldown binding is known to be in play; before that a * container pays nothing for this. */ attach(mirror: MirrorFs, root: string): void; detach(): void; /** Copy the whole subtree across. The only bulk operation that remains. */ private seed; /** * Bring back what the mirrored engine wrote. * * The mirror exists because Rolldown's resolver reads through WASI rather * than through anything JavaScript can hand it — but Rolldown also *writes* * through WASI, so `vite build` leaves its output in the mirror and the * container sees an empty `dist/`. This is the return leg, and it is why the * mirror is no longer strictly one-way. * * Called when a process ends rather than on a timer: that is the moment a * build's output is complete, and a dev server — which serves from memory * and writes nothing — pays for it only once, at exit. */ absorb(): void; /** `mkdir -p`, which the volume does not offer directly. */ private ensureDirectory; /** Is this path inside the mirrored subtree? */ private mirrored; /** * Run a mirror update, swallowing failure. * * The mirror is a read-only cache for another engine. If it rejects * something — an unsupported operation, a path it has not seen — the * container's own write has still happened and must still succeed. */ private safely; /** Push a path's current state across, whatever it is now. */ private sync; readFileSync(path: string): Uint8Array; readdirSync(path: string): string[]; lstatSync(path: string): VolumeStat; /** The mirror's copy of a file, if it has one and we are allowed to look. */ private fromMirror; /** The mirror's entries for a directory, for merging into a listing. */ private mirrorNames; readlinkSync(path: string): string; getStats(): VolumeStats; writeFileSync(path: string, data: string | Uint8Array): void; appendFileSync(path: string, data: string | Uint8Array): void; mkdirSync(path: string, options?: { mode?: number; }): void; rmdirSync(path: string): void; unlinkSync(path: string): void; /** * Rename, carrying anything the mirrored engine put there. * * This is the operation the dependency optimizer is built on, and the one * that used to destroy its output. Vite bundles into a temporary directory * and renames it into place when it is complete — but only half of that * directory is ever on this volume. Vite writes `_metadata.json` and * `package.json` through here; Rolldown writes the actual bundles through * WASI into the mirror. Renaming moved the half that was here and then * `sync(from)` deleted the half that was not, because from this side the * source directory had simply gone. * * What survived was a `deps` directory holding metadata that described five * optimized dependencies and contained none of them — which Vite reports, on * the failed read, as `504 Outdated Optimize Dep`. Nothing in that message is * true, and following it leads to hashes rather than to a missing file. * * So the mirror's side of the move is collected first, and lands here as * part of the rename. */ renameSync(from: string, to: string): void; /** * Copy whatever the mirror holds under `from` into this volume under `to`. * * Deliberately not filtered the way {@link absorb} is: this walks one * directory that is being renamed, not the whole project, so the subtree is * small and `node_modules` is exactly where the interesting case lives. */ private collect; symlinkSync(target: string, path: string): void; linkSync(existing: string, path: string): void; truncateSync(path: string, length?: number): void; chmodSync(path: string, mode: number): void; lchmodSync(path: string, mode: number): void; chownSync(path: string, uid: number, gid: number): void; lchownSync(path: string, uid: number, gid: number): void; utimesSync(path: string, atime: Date, mtime: Date): void; snapshot(): MemoryVolumeSnapshotEntry[]; /** A restore replaces everything, so the mirror is rebuilt rather than patched. */ restore(entries: MemoryVolumeSnapshotEntry[]): void; } interface LocalRuntimeOptions { workdir?: string; env?: Record; files?: Record; registry?: string; fetch?: typeof globalThis.fetch; /** * The outbound policy for guest `fetch`, `http`, `https` and `WebSocket`. * Omitted, guest requests leave the way the host's would; `createContainer` * always supplies one, closed unless the caller opens it. */ network?: OutboundPolicy; /** Invoked when a program inside the runtime starts listening on a port. */ onServerReady?: (port: number, url: string) => void; /** Extra package substitutions, merged over {@link WASM_ALIASES}. */ aliases?: Record; /** Modules supplied by the host rather than resolved from the volume. */ modules?: Record; /** * Supply `esbuild` from the host when it can be loaded. On by default: no * build of esbuild runs inside the sandbox, so without this every toolchain * that depends on it — Vite included — starts and then fails on the first * transform. */ hostEsbuild?: boolean; } /** * Default substitutions for packages that would otherwise load a compiled * addon. * * Each of these ships a WebAssembly build under a second package name for * exactly this situation — a host with no prebuilt binary for its platform. * The substitute is only used when it is actually installed, so a project that * has neither is unaffected and one that has both gets the runnable one. */ declare const WASM_ALIASES: Record; /** * First complete clean-room RuntimePod composition. Execution currently uses * the caller's JS realm; BrowserRuntimePod will place the same engine in a * dedicated Worker before this becomes the default untrusted-code path. */ declare class LocalRuntimePod implements RuntimePod { readonly volume: MirroringVolume; readonly packages: RuntimePackageInstaller; readonly instanceId: string; protected readonly router: VirtualHttpRouter; readonly sockets: VirtualTcpNetwork; readonly proxy: { activePorts: (_instanceId?: string) => number[]; }; /** * Bind a port to a server that is not a JavaScript one. * * The request is flattened to bytes and headers before it crosses the * boundary, because the far side is a different language and a Node stream * object cannot go there. What comes back is a complete response; streaming * is a later protocol, and pretending to stream over a buffered path would * only move the surprise. */ serveExternal(port: number, owner: string, handler: (request: { method: string; path: string; headers: Record; body: Uint8Array; }) => Promise): () => void; /** * Mutable on purpose: a container replaces `spawn` so that children resolve * against the kernel's PATH. Left alone, it runs `node` and reports anything * else as not found, which is the correct answer for a bare pod. */ readonly processManager: { spawn(config: ChildSpawnConfig): ChildHandle; }; private disposed; private readonly running; protected readonly workdir: string; protected readonly env: Record; protected readonly aliases: Record; private readonly modules; private readonly esbuild; private rolldownBinding; /** Backs outbound `http`/`https` client requests from inside the sandbox. */ private readonly fetch; /** What guest programs may reach outside the container. */ protected networkPolicy: OutboundPolicy | undefined; protected constructor(options: LocalRuntimeOptions); static boot(options?: LocalRuntimeOptions): Promise; /** Apply a container's outbound policy to programs started from now on. */ setNetworkPolicy(policy: OutboundPolicy): void; spawn(command: string, args?: string[], options?: Record): Promise; /** * Rolldown's JavaScript API synchronously requires its compiled binding. * When a project contains Rolldown, preload the official WASI build in the * host and expose it through the module override table before evaluation. * Keeping this demand-driven avoids adding WASM startup cost to ordinary * shells and Node programs. */ private prepareRolldown; /** * Wait until the process has either started serving or genuinely run out of * work. * * Two different kinds of pending work have to be waited on. Callbacks queued * as microtasks or `nextTick` — which is most of what streams and promise * chains are built from — need only for the current turn to end, so a few * turns of the macrotask queue are yielded first. Without that, a script * whose last act is `process.stdin.on("data", …)` exits before its own * handler runs and produces no output at all. Timers are the part that can * outlive any number of turns, so those are then polled until none remain. * * A plain script that has genuinely finished falls straight through both, * costing a handful of empty turns. */ private settle; request(port: number, init?: Record): Promise; connect(port: number, init: Record, peer: RuntimeSocketPeer): RuntimeConnection | null; snapshot(): MemoryVolumeSnapshotEntry[]; restore(snapshot: unknown): Promise; teardown(): void; /** HTTP/1.1 client path for a server implemented outside the JS runtime. */ private requestTcp; private seed; private assertActive; } /** * A pod that evaluates each guest program on its own thread. * * Everything shared stays here: the volume, the HTTP router, the package * installer and the process table. Only the program's own evaluation moves, * and it reaches back for the rest through a {@link SyncChannelServer}. * * That arrangement is forced rather than chosen. A synchronous call has to * block the caller while the work it is waiting on still makes progress, so * the blocking side cannot be the side that owns the resources — otherwise a * child process needing the filesystem would have to call into a thread that * is frozen waiting for that child. The guest blocks; the host never does. * * It inherits from {@link LocalRuntimePod} because every other part of the * contract is identical, and overriding one method is a smaller and more * honest claim than reimplementing nine. Both are held to the same contract * suite (`test/pod-contract.ts`). */ interface WorkerRuntimeOptions extends LocalRuntimeOptions { /** Where the guest bundle lives; defaults to the copy shipped beside this one. */ workerUrl?: string | URL; } declare class WorkerRuntimePod extends LocalRuntimePod { private readonly workerUrl; /** Live workers, so teardown can stop them all. */ private readonly live; protected constructor(options: WorkerRuntimeOptions); /** Boot without silently dropping synchronous child-process support. */ static boot(options?: WorkerRuntimeOptions): Promise; /** Compatibility mode, with an observable explanation for every fallback. */ static tryBoot(options?: WorkerRuntimeOptions, onFallback?: (error: Error) => void): Promise; spawn(command: string, args?: string[], options?: Record): Promise; private spawnInWorker; /** Start an asynchronous child on the host's behalf and relay its events. */ private startChild; /** Run a child to completion and collect it, for the guest's `spawnSync`. */ private runChildToCompletion; private readonly proxies; private readonly waiting; /** Upgraded connections, by the id the Worker knows them as. */ private readonly upgraded; private nextRequestId; /** * Register a stand-in for a server that is actually running in the Worker. * * The router only knows how to reach servers on this thread, so each bound * port gets a local server whose whole job is to forward and wait. */ private proxyPort; private forward; /** * Tunnel one upgraded connection to the server that actually holds the port. * * Unlike {@link forward} there is no reply to wait for: both ends write * whenever they have something, until one of them stops. The id is what ties * the two directions together across the Worker boundary. */ private upgrade; /** * Answer a program that is calling a server in this container. * * A guest's router holds only the servers on its own thread, so a request to * a port some other process opened comes here, where every server in the * container is registered. `null` means nothing listens, which the guest * reports as a refused connection. */ private answerLoopback; private settleProxied; private closeProxies; teardown(): void; /** Does anything under `cwd` need a module only the host can supply? */ private needsHostModules; } interface RegistryManifest { name: string; version: string; dist: { tarball: string; integrity?: string; shasum?: string; }; dependencies?: Record; optionalDependencies?: Record; os?: string[]; cpu?: string[]; libc?: string[]; main?: string; bin?: string | Record; } interface CleanInstallerOptions { cwd?: string; registry?: string; fetch?: typeof globalThis.fetch; } interface InstallOptions extends Record { onProgress?: (message: string) => void; persist?: boolean; persistDev?: boolean; withDevDeps?: boolean; } /** npm-registry installer independent of npm CLI and Node host APIs. */ declare class CleanPackageInstaller implements RuntimePackageInstaller { readonly volume: RuntimeVolume; readonly options: CleanInstallerOptions; private readonly registry; private readonly fetcher; private metadata; private tarballs; /** Single-version manifests, for the fields the packument omits. */ private details; constructor(volume: RuntimeVolume, options?: CleanInstallerOptions); forCwd(cwd: string): CleanPackageInstaller; install(name: string, version?: string, options?: InstallOptions): Promise; installFromManifest(path: string, options?: InstallOptions): Promise; private installAt; /** * The `libc` and `main` fields, which the abbreviated packument leaves out. * * Fetched per version rather than as a full packument: the single-version * document is a few kilobytes, while the full one for a popular package runs * to megabytes. Only packages that already declare `os` or `cpu` ask for it, * so an ordinary install of pure-JavaScript dependencies makes no extra * requests at all — it is the prebuilt binaries, a handful per project, that * need the answer. * * A failure here is not fatal. Being unable to read `libc` puts the check * back where it was before this existed, which is worth strictly less than * being right and strictly more than refusing to install. */ private platformDetail; /** Overlap up to six sibling downloads; filesystem writes remain ordered. */ private prefetch; private getMetadata; private getTarball; private createBinLinks; private persist; private removeIfPresent; private readJson; private tryReadJson; } declare function extractNpmTarball(volume: RuntimeVolume, compressed: Uint8Array, destination: string): void; /** * Running a `wasm32-wasi` binary as an ordinary container process. * * Everything a guest sees is taken from the `ExecContext` it was dispatched * with — argv, environment, cwd, credentials, the three streams — so a wasm * binary is pipelineable, redirectable and killable exactly like `grep` is. * That is the whole point: `./tool.wasm < input | sort` has to work, or this * is a demo rather than a runtime. */ interface RunWasiOptions { /** Guest argv. Defaults to the context's own. */ argv?: string[]; /** Guest directory name → container path. */ preopens?: Record; /** Extra imports, for a module linked against more than WASI. */ imports?: WebAssembly.Imports; } /** Load, instantiate and run a WebAssembly binary; returns its exit code. */ declare function runWasi(ctx: ExecContext, bytes: Uint8Array, options?: RunWasiOptions): Promise; /** * A `wasi_snapshot_preview1` host, implemented against this container's kernel. * * The point of this file is that "run a native app" stops being a special * case. A program compiled to `wasm32-wasi` — by clang, Rust, Zig, Go's * `GOOS=wasip1`, TinyGo — asks for files, arguments, environment, clocks and * standard I/O through this one interface. Implement it against the VFS, the * process table and the container's streams, and those programs run beside the * coreutils with the same paths, the same permissions and the same pipes. * * Three constraints shape everything here. * * **Imports must be synchronous.** A WebAssembly import cannot await, but the * kernel's stdin is a promise. So stdin is drained *before* the module starts * (see `run.ts`) and served from a buffer; output streams are already * synchronous. This is the same trade the Python bridge makes, for the same * reason, and it is why an interactive `wasm` REPL reading a live terminal is * out of scope until stack-switching is available here. * * **The VFS has no file descriptors.** It reads and writes whole files. So an * open file is held as a buffer with a cursor, and written back on close, on * sync, and before any path-based call that could otherwise observe a stale * version of the file being written. * * **Capabilities are the VFS's, not a second model.** WASI's rights bitmask is * carried and reported, but enforcement is the kernel's own uid/gid check * running underneath every call. Preopens are enforced, because those *are* * meaningful here: a descriptor cannot escape the directory it was derived * from, so a caller that preopens only `/workspace` gets a program confined to * it. */ /** Standard input, already reduced to something readable without waiting. */ interface WasiStdin { /** Up to `size` bytes; empty means end-of-file. Never blocks. */ read(size: number): Uint8Array; /** Bytes that could be produced right now, for `poll_oneoff`. */ readonly available: number; readonly isTTY: boolean; } interface WasiHostOptions { /** Full guest argv, `argv[0]` included. */ argv: string[]; env: Record; vfs: Vfs; cred: Cred; /** Where relative guest paths resolve; published to the guest as `PWD`. */ cwd: string; stdin: WasiStdin; stdout: OutputStream; stderr: OutputStream; /** * Guest path → container path. Defaults to the whole filesystem. * * Names are guest-visible *paths*, not labels: wasi-libc matches an open * against the longest preopen prefix, so a preopen called `.` claims every * absolute path as well and quietly turns `/work/out.txt` into * `work/out.txt` under whatever `.` points at. Relative paths need no * preopen of their own — libc joins them to `PWD` before it asks. */ preopens?: Record; now?: () => number; /** Monotonic nanosecond source, for `clock_time_get(MONOTONIC)`. */ hrtime?: () => bigint; random?: (into: Uint8Array) => void; /** Blocking sleep. Returning early is allowed; the guest re-polls. */ sleep?: (ms: number) => void; /** Consulted between sleep slices so a killed process stops waiting. */ aborted?: () => boolean; } /** Thrown by `proc_exit` to unwind the guest's stack out to the runner. */ declare class WasiExit extends Error { readonly code: number; constructor(code: number); } declare class WasiHost { private memory; private readonly fds; private nextFd; private readonly opts; private readonly startTime; /** Set once `proc_exit` has run, so the runner reports the guest's code. */ exitCode: number | null; constructor(options: WasiHostOptions); /** Attach the instance's memory. Called before `_start`. */ bind(instance: WebAssembly.Instance): void; /** Flush every buffered write. Called by the runner when the guest ends. */ flushAll(): void; /** * `wasi_snapshot_preview1`. * * Every entry returns an errno rather than throwing: a JavaScript exception * crossing back into WebAssembly traps the instance, which turns a missing * file into an unrecoverable crash instead of the `ENOENT` the guest is * written to handle. `guard` is what enforces that. */ get wasiImport(): Record unknown>; /** * `wasi_unstable`, the preview0 name older toolchains still emit. * * Identical but for `fd_seek`, whose `whence` values were reordered before * preview1 was frozen. Aliasing the table without this correction is a * popular bug: every seek in an old binary lands somewhere plausible and * wrong. */ get wasiUnstableImport(): Record unknown>; private get view(); private get bytes(); private readString; /** The scatter/gather list `fd_read` and `fd_write` are given. */ private iovecs; /** * Turn anything thrown inside a syscall into an errno. * * `WasiExit` is re-thrown on purpose: it is the guest unwinding its own * stack, not a failure to be reported through a return value. */ private guard; private get; private dir; private file; /** * Resolve a guest path against a directory descriptor. * * The confinement check is the one place preopens are enforced: a path that * climbs out of the directory the descriptor was derived from is * `ENOTCAPABLE`, which is exactly the error a capability-oriented guest * expects and knows how to report. */ private resolveAt; private allocate; /** * Push a buffered file back to the VFS. * * Called before every path-based call as well as on close, so a guest that * writes a file and then stats or reopens it by name sees what it wrote — * the alternative is a stale read that looks like data loss. */ private writeBack; private syncPaths; private args_get; private args_sizes_get; private get envStrings(); private environ_get; private environ_sizes_get; private writeStringVector; private writeVectorSizes; private clock_res_get; private clock_time_get; private clockNow; private random_get; private fd_read; private fd_pread; private fd_write; private fd_pwrite; private fd_seek; private fd_tell; private fd_close; private fd_sync; private fd_renumber; private fd_allocate; private fd_filestat_set_size; private fd_fdstat_get; private fd_fdstat_set_flags; private fd_filestat_get; private fd_filestat_set_times; private path_filestat_get; private path_filestat_set_times; private setTimes; private writeFilestat; private fd_prestat_get; private fd_prestat_dir_name; private path_open; private fd_readdir; private path_create_directory; private path_remove_directory; private path_unlink_file; private path_rename; private path_symlink; private path_link; private path_readlink; /** * `poll_oneoff`, which is how a WASI guest sleeps and how it waits on I/O. * * Files and the standard streams are always ready here — nothing in this * container can leave a read pending, since stdin was drained before the * guest started. That leaves the clock, which is the case that matters: * `sleep()` compiles to a lone clock subscription, and it is honoured by * actually waiting, in slices, so that killing the process interrupts it. */ private poll_oneoff; private bytesLeft; /** Wait in slices so that a `SIGKILL` does not have to outlast the sleep. */ private sleepInterruptibly; } /** An errno on its way back to the guest, rather than a JavaScript failure. */ declare class WasiError extends Error { readonly errno: number; constructor(errno: number); } /** Whether `bytes` begins with the WebAssembly magic number. */ declare function isWasmBinary(bytes: Uint8Array): boolean; /** * `wasi` — the interpreter that stands behind every `.wasm` file in `$PATH`. * * It is invoked two ways, and they are the same code path. A user can run * `wasi build/tool.wasm --flag`, or they can `chmod +x tool.wasm && ./tool.wasm * --flag` and let the kernel dispatch it here the way it dispatches a `#!` * script. The second is the one that matters: it is what makes a compiled * binary indistinguishable from any other program on the system. */ declare const wasi: Command; /** * Starting the guest Worker, in whichever environment the host happens to be. * * The awkward part of shipping a Worker from a library is not creating it, but * naming it. `new URL("./worker-entry.js", import.meta.url)` is the form every * bundler recognises, and it resolves correctly from `dist/` — but a bundler * that *pre-bundles* this package rewrites `import.meta.url` to point into its * own dependency cache, where no such file exists. That is the same trap * Rolldown's WASI binding falls into, and it surfaces just as obliquely. * * So this never assumes it worked. Strict boot surfaces the failure; automatic mode reports * the cause before choosing the in-realm pod. */ interface RuntimeWorker { postMessage(message: unknown): void; onMessage(listener: (message: unknown) => void): void; onError(listener: (error: unknown) => void): void; terminate(): unknown; } /** * Start the guest Worker and wait for it to say it is alive. * * Rejects rather than hanging when the script cannot be loaded: a Worker whose * script 404s reports an `error` event and would otherwise leave the caller * waiting for a ready message that can never arrive. */ declare function startRuntimeWorker(options?: { url?: string | URL; workerData?: Record; timeoutMs?: number; }): Promise; declare function syncChannelSupported(): boolean; /** * The routing a preview service worker does, separated from the worker itself. * * A service worker is awkward to test — it needs a browser, a registration and * a secure context — but almost none of what makes this correct is about being * a service worker. The interesting part is the bookkeeping: which client is * previewing which port, which requests belong to a preview at all, and how a * response is rebuilt on the way back. That lives here, where it can be * exercised directly. * * The rule this implements, and the reason it exists: requests are routed by * **who is asking**, not by what the path looks like. An iframe navigates once * to `/__sbx__//`; every later request from that client — however * absolute its path — is recognised by its client id. Nothing has to rewrite * `/src/main.js` or `/@vite/client`, which is what makes a real dev server * work rather than only a single page. */ /** A container-local server, named by port rather than by an address. */ interface ContainerTarget { port: number; /** Path and query, so a deep link does not collapse to the root. */ path: string; } /** * The container-local server a URL names, or null if it names anything else. * * A program inside the container prints the only address it can see — * `http://localhost:3000` — and that address is worse than useless once it * leaves: in the page it resolves to the *user's own machine*, where nothing * is listening, so a frame pointed at it fails with "refused to connect" * rather than failing visibly as a routing mistake. * * The same translation serves two callers. A host reading an address out of a * build log needs it to point a frame somewhere (`Preview.resolve`), and the * service worker needs it for the other direction: a page *inside* a preview * asking its own backend for `http://localhost:8000/api` means the container's * port 8000, not the reader's machine. * * Kept pure, and kept here rather than beside the host half, because the * worker bundles this module and not that one. */ declare function containerTarget(value: string): ContainerTarget | null; /** * Wiring a container's HTTP servers up to real URLs in the page. * * The service worker does the routing; this is the half that lives in the page * and actually knows about the container. * * **Read the origin note before using this.** A preview served this way runs on * *your* origin, so scripts inside it can reach `window.parent`, your cookies * and your `localStorage` — the sandbox contains the program's *filesystem and * process table*, not the page it serves. For code you did not write, either * host the preview on a separate origin, or use {@link renderInto}, which puts * the response in an iframe with no origin at all. */ interface PreviewOptions { /** Where the worker script lives; defaults to the copy shipped beside the bundle. */ scriptUrl?: string | URL; /** Registration scope. Must be able to see the paths a preview will request. */ scope?: string; /** * The dev server has invalidated what the frame is holding; reload it. * * Vite serves `504 Outdated Optimize Dep` once the hash in a dependency URL * no longer matches — after its optimizer re-runs, or after the server is * restarted. Its own client recovers by reloading, and hears about it over * the HMR WebSocket, which this bridge does not carry. Without a reload the * frame keeps asking for a hash the server has forgotten and the app never * mounts. * * Reloading is the host's call because the host owns the frame: it can pick * the moment, and it can stop after a few attempts rather than looping. */ onStale?: () => void; /** * Let pages inside the preview open WebSockets to the container. * * On by default. A service worker cannot answer a WebSocket handshake, so * previewed documents are given a `WebSocket` that tunnels through this page * instead — which means the HTML they are served is modified on the way * through, one `