/** * Host side of the connector isolate lane. * * `IsolateHost` owns one `isolated-vm` isolate: creation with a memory limit, * the context and its `global` self-reference, the named host capabilities the * guest may call, the wall-clock budget, termination and disposal. The * connector-specific contract (which capabilities exist and what the guest * runner does with them) lives in `executor/isolate.ts`; this module only * knows how to get a call across the boundary and back safely. * * Boundary rules, learned from probing isolated-vm 7 on Node 26: * - A host function that throws (sync or async) does reach the guest, but an * async rejection ALSO surfaces as an unhandled rejection in the host * process. Capabilities therefore never throw across the boundary: every * reply is an envelope `{ __lobu: 1, ok, value | error }` and the guest * prelude rethrows. * - Error names do not survive the boundary (`e.name = 'X'` arrives as * `Error`), another reason to carry `{ name, message }` in the envelope. * - `script.run({ timeout })` bounds only the synchronous part of the run; a * loop entered after an `await` is not interrupted. The wall clock here * disposes the isolate, which rejects the pending run. * - Exceeding `memoryLimit` disposes the isolate automatically; the run * rejects with "disposed during execution due to memory limit". * - `dispose()` on a disposed isolate throws; guard with `isDisposed`. */ import type { IsolatedVm } from './ivm-types.js'; export type HostSyncCapability = (...args: unknown[]) => unknown; export type HostAsyncCapability = (...args: unknown[]) => Promise; /** Terminal state the host imposed on the run (timeout, output cap, hook failure). */ export interface IsolateTerminalState { name: string; message: string; } export interface IsolateHostOptions { ivm: IsolatedVm; /** V8 heap limit for the isolate, in MB. */ memoryMb: number; /** Cap on any single string crossing from the guest; exceeding it terminates the run. */ messageBytes: number; /** `process.env` visible to the guest. */ env: Record; /** The run's own sync capabilities; a fresh set of the prelude's host halves (`createPreludeHostSync`) is always installed too. */ sync: Record; async: Record; } export interface IsolateRunOptions { /** Wall-clock budget in ms; `0` disables the timer (interactive auth). */ timeoutMs: number; /** Script name for stack traces. */ filename?: string; } export type IsolateFailureKind = 'timeout' | 'memory' | 'terminated' | 'crash'; /** A run that the host, not the guest, ended. */ export declare class IsolateHostError extends Error { readonly kind: IsolateFailureKind; readonly terminal: IsolateTerminalState | null; constructor(kind: IsolateFailureKind, message: string, terminal: IsolateTerminalState | null, options?: { cause?: unknown; }); } export declare class IsolateHost { private readonly isolate; private readonly context; private readonly options; private readonly sync; private terminalState; private timedOut; private constructor(); static create(options: IsolateHostOptions): Promise; /** The state the host imposed, if it ended the run. */ get terminal(): IsolateTerminalState | null; private install; private terminalEnvelope; /** True when every string argument fits the per-message cap; otherwise the run is terminated. */ private guardArgs; private dispatchSync; private dispatchAsync; /** * End the run from the host. Disposing the isolate is the only way to stop * a guest that is parked on an `await` (nothing is executing, so a * termination request would no-op) or looping after one (the run timeout * covers only the synchronous prefix). The pending `run()` rejects and is * reported as this terminal state. */ terminate(state: IsolateTerminalState): void; /** * Compile the prelude plus `source` and run it, resolving with the value of * the script's final expression (awaited when it is a promise, copied out). * Throws `IsolateHostError` when the host ended the run; any other rejection * is the guest's own uncaught throw during module init. */ run(source: string, options: IsolateRunOptions): Promise; private classifyRunFailure; dispose(): void; } //# sourceMappingURL=bridge.d.ts.map