sandboxedjs 0.1.28 → 0.1.29

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.
package/dist/index.d.cts CHANGED
@@ -27,7 +27,30 @@ interface ChildSpawnConfig {
27
27
  parentPid?: number;
28
28
  }
29
29
  type SpawnChild = (config: ChildSpawnConfig) => ChildHandle;
30
- declare function createChildProcessModule(spawnChild: SpawnChild, defaultCwd: () => string): Record<string, unknown>;
30
+ /**
31
+ * Run a child to completion without returning to the event loop.
32
+ *
33
+ * Supplied only by a pod that can actually block — one whose guest runs on its
34
+ * own thread. Where it is absent the synchronous entry points keep reporting
35
+ * that they are unavailable, which is the honest answer for an in-realm pod.
36
+ */
37
+ type SyncSpawn = (request: {
38
+ command: string;
39
+ args: string[];
40
+ cwd: string;
41
+ env?: Record<string, string>;
42
+ input?: string;
43
+ }) => {
44
+ status: number | null;
45
+ stdout: string;
46
+ stderr: string;
47
+ signal: string | null;
48
+ error?: {
49
+ code?: string;
50
+ message: string;
51
+ };
52
+ };
53
+ declare function createChildProcessModule(spawnChild: SpawnChild, defaultCwd: () => string, syncSpawn?: SyncSpawn): Record<string, unknown>;
31
54
 
32
55
  /**
33
56
  * Clean-room contracts between SandboxedJS and its JavaScript runtime.
@@ -1639,6 +1662,24 @@ interface ContainerOptions {
1639
1662
  * ```
1640
1663
  */
1641
1664
  pod?: RuntimePod;
1665
+ /**
1666
+ * Where guest programs run.
1667
+ *
1668
+ * `"worker"` (the default) gives each program its own thread, which is what
1669
+ * makes synchronous child processes work and keeps guest code out of the
1670
+ * host's realm; it falls back automatically where the host cannot support it.
1671
+ * `"realm"` forces the in-realm runtime.
1672
+ */
1673
+ isolation?: "worker" | "realm";
1674
+ /**
1675
+ * Where to load the guest worker bundle from.
1676
+ *
1677
+ * Defaults to the copy shipped beside the main bundle, which is what a
1678
+ * published package wants. Worth setting when a bundler has moved or
1679
+ * rewritten it — or when running from source, where the built file is the
1680
+ * only one a Worker can load.
1681
+ */
1682
+ workerUrl?: string | URL;
1642
1683
  /** Python runtime settings; a browser host uses this to locate the wasm. */
1643
1684
  python?: PythonOptions;
1644
1685
  }
@@ -2457,6 +2498,14 @@ interface CoreModulesOptions {
2457
2498
  };
2458
2499
  /** Backs `child_process`; without it the module reports as unavailable. */
2459
2500
  spawnChild?: SpawnChild;
2501
+ /**
2502
+ * Backs the `*Sync` half of `child_process`.
2503
+ *
2504
+ * Only a pod whose guest runs on its own thread can supply this — blocking
2505
+ * requires somewhere else for the child's work to happen. Without it the
2506
+ * synchronous entry points keep reporting that they are unavailable.
2507
+ */
2508
+ syncSpawn?: SyncSpawn;
2460
2509
  /** File holding the process's standard input, exposed as descriptor 0. */
2461
2510
  stdinPath?: string;
2462
2511
  /** Keep `process.stdin` open and fed by {@link writeStdin} rather than ending it. */
@@ -2496,6 +2545,13 @@ declare function createCoreModules(options: CoreModulesOptions): {
2496
2545
  pendingHandles(): number;
2497
2546
  /** Active timers which called `unref()` and therefore only merit startup grace. */
2498
2547
  pendingUnrefed(): number;
2548
+ /**
2549
+ * Cancel every timer this process still holds.
2550
+ *
2551
+ * Called when a process is killed: the process is finished, but its
2552
+ * scheduled work would otherwise keep running on the host's event loop.
2553
+ */
2554
+ cancelTimers(): void;
2499
2555
  /**
2500
2556
  * Client requests sent but not yet read to completion.
2501
2557
  *
@@ -2533,6 +2589,99 @@ declare function looksLikeEsm(source: string): boolean;
2533
2589
  */
2534
2590
  declare function transformEsm(source: string, filename?: string): EsmTransformResult | null;
2535
2591
 
2592
+ /**
2593
+ * A volume that keeps a second, foreign filesystem in step with itself.
2594
+ *
2595
+ * Rolldown's browser WebAssembly binding owns a `memfs` volume of its own —
2596
+ * its Rust resolver reads through WASI, not through anything JavaScript can
2597
+ * hand it. So the sandbox project has to exist in two places at once, and the
2598
+ * copy has to stay current: a dev server reads `index.html` when the request
2599
+ * arrives, not when the process started.
2600
+ *
2601
+ * Mirroring on write rather than copying up-front is what makes that true. The
2602
+ * previous approach took one deep snapshot per spawn, which was both expensive
2603
+ * — every `npm run dev` re-copied `node_modules` — and already stale by the
2604
+ * time it mattered, so an edit during a session was served from the old tree.
2605
+ *
2606
+ * The mirror is deliberately one-way and best-effort. It is a cache for a
2607
+ * consumer that only reads; a write that fails to reach it must never fail the
2608
+ * write that the container itself made.
2609
+ */
2610
+
2611
+ /** The slice of a `memfs`-style filesystem the mirror writes through. */
2612
+ interface MirrorFs {
2613
+ mkdirSync(path: string, options?: {
2614
+ recursive?: boolean;
2615
+ }): void;
2616
+ writeFileSync(path: string, data: Uint8Array): void;
2617
+ symlinkSync(target: string, path: string): void;
2618
+ rmSync?(path: string, options?: {
2619
+ recursive?: boolean;
2620
+ force?: boolean;
2621
+ }): void;
2622
+ unlinkSync?(path: string): void;
2623
+ rmdirSync?(path: string): void;
2624
+ }
2625
+ /**
2626
+ * A `RuntimeVolume` that forwards every mutation to an optional mirror.
2627
+ *
2628
+ * Wrapping rather than modifying `MemoryVolume` keeps the mirroring concern out
2629
+ * of the filesystem, and keeps this transparent to the kernel, whose `Vfs`
2630
+ * takes any `RuntimeVolume`.
2631
+ */
2632
+ declare class MirroringVolume implements RuntimeVolume {
2633
+ private readonly inner;
2634
+ private mirror;
2635
+ private root;
2636
+ constructor(inner?: MemoryVolume);
2637
+ /**
2638
+ * Start mirroring the tree under `root`, seeding it with what is there now.
2639
+ *
2640
+ * Called once the Rolldown binding is known to be in play; before that a
2641
+ * container pays nothing for this.
2642
+ */
2643
+ attach(mirror: MirrorFs, root: string): void;
2644
+ detach(): void;
2645
+ /** Copy the whole subtree across. The only bulk operation that remains. */
2646
+ private seed;
2647
+ /** Is this path inside the mirrored subtree? */
2648
+ private mirrored;
2649
+ /**
2650
+ * Run a mirror update, swallowing failure.
2651
+ *
2652
+ * The mirror is a read-only cache for another engine. If it rejects
2653
+ * something — an unsupported operation, a path it has not seen — the
2654
+ * container's own write has still happened and must still succeed.
2655
+ */
2656
+ private safely;
2657
+ /** Push a path's current state across, whatever it is now. */
2658
+ private sync;
2659
+ readFileSync(path: string): Uint8Array;
2660
+ readdirSync(path: string): string[];
2661
+ lstatSync(path: string): VolumeStat;
2662
+ readlinkSync(path: string): string;
2663
+ getStats(): VolumeStats;
2664
+ writeFileSync(path: string, data: string | Uint8Array): void;
2665
+ appendFileSync(path: string, data: string | Uint8Array): void;
2666
+ mkdirSync(path: string, options?: {
2667
+ mode?: number;
2668
+ }): void;
2669
+ rmdirSync(path: string): void;
2670
+ unlinkSync(path: string): void;
2671
+ renameSync(from: string, to: string): void;
2672
+ symlinkSync(target: string, path: string): void;
2673
+ linkSync(existing: string, path: string): void;
2674
+ truncateSync(path: string, length?: number): void;
2675
+ chmodSync(path: string, mode: number): void;
2676
+ lchmodSync(path: string, mode: number): void;
2677
+ chownSync(path: string, uid: number, gid: number): void;
2678
+ lchownSync(path: string, uid: number, gid: number): void;
2679
+ utimesSync(path: string, atime: Date, mtime: Date): void;
2680
+ snapshot(): MemoryVolumeSnapshotEntry[];
2681
+ /** A restore replaces everything, so the mirror is rebuilt rather than patched. */
2682
+ restore(entries: MemoryVolumeSnapshotEntry[]): void;
2683
+ }
2684
+
2536
2685
  interface LocalRuntimeOptions {
2537
2686
  workdir?: string;
2538
2687
  env?: Record<string, string>;
@@ -2569,10 +2718,10 @@ declare const WASM_ALIASES: Record<string, string>;
2569
2718
  * dedicated Worker before this becomes the default untrusted-code path.
2570
2719
  */
2571
2720
  declare class LocalRuntimePod implements RuntimePod {
2572
- readonly volume: MemoryVolume;
2721
+ readonly volume: MirroringVolume;
2573
2722
  readonly packages: RuntimePackageInstaller;
2574
2723
  readonly instanceId: string;
2575
- private readonly router;
2724
+ protected readonly router: VirtualHttpRouter;
2576
2725
  readonly proxy: {
2577
2726
  activePorts: (_instanceId?: string) => number[];
2578
2727
  };
@@ -2585,15 +2734,15 @@ declare class LocalRuntimePod implements RuntimePod {
2585
2734
  spawn(config: ChildSpawnConfig): ChildHandle;
2586
2735
  };
2587
2736
  private disposed;
2588
- private readonly workdir;
2589
- private readonly env;
2590
- private readonly aliases;
2737
+ protected readonly workdir: string;
2738
+ protected readonly env: Record<string, string>;
2739
+ protected readonly aliases: Record<string, string>;
2591
2740
  private readonly modules;
2592
2741
  private readonly esbuild;
2593
2742
  private rolldownBinding;
2594
2743
  /** Backs outbound `http`/`https` client requests from inside the sandbox. */
2595
2744
  private readonly fetch;
2596
- private constructor();
2745
+ protected constructor(options: LocalRuntimeOptions);
2597
2746
  static boot(options?: LocalRuntimeOptions): Promise<LocalRuntimePod>;
2598
2747
  spawn(command: string, args?: string[], options?: Record<string, unknown>): Promise<RuntimeProcess>;
2599
2748
  /**
@@ -2678,6 +2827,47 @@ declare class CleanPackageInstaller implements RuntimePackageInstaller {
2678
2827
  }
2679
2828
  declare function extractNpmTarball(volume: RuntimeVolume, compressed: Uint8Array, destination: string): void;
2680
2829
 
2830
+ /**
2831
+ * Starting the guest Worker, in whichever environment the host happens to be.
2832
+ *
2833
+ * The awkward part of shipping a Worker from a library is not creating it, but
2834
+ * naming it. `new URL("./worker-entry.js", import.meta.url)` is the form every
2835
+ * bundler recognises, and it resolves correctly from `dist/` — but a bundler
2836
+ * that *pre-bundles* this package rewrites `import.meta.url` to point into its
2837
+ * own dependency cache, where no such file exists. That is the same trap
2838
+ * Rolldown's WASI binding falls into, and it surfaces just as obliquely.
2839
+ *
2840
+ * So this never assumes it worked. The caller treats a failure to start as
2841
+ * "this host cannot run the Worker pod" and uses the in-realm pod instead.
2842
+ */
2843
+ interface RuntimeWorker {
2844
+ postMessage(message: unknown): void;
2845
+ onMessage(listener: (message: unknown) => void): void;
2846
+ onError(listener: (error: unknown) => void): void;
2847
+ terminate(): unknown;
2848
+ }
2849
+ /**
2850
+ * Start the guest Worker and wait for it to say it is alive.
2851
+ *
2852
+ * Rejects rather than hanging when the script cannot be loaded: a Worker whose
2853
+ * script 404s reports an `error` event and would otherwise leave the caller
2854
+ * waiting for a ready message that can never arrive.
2855
+ */
2856
+ declare function startRuntimeWorker(options?: {
2857
+ url?: string | URL;
2858
+ workerData?: Record<string, unknown>;
2859
+ timeoutMs?: number;
2860
+ }): Promise<RuntimeWorker>;
2861
+
2862
+ /**
2863
+ * Can this environment support a blocking client at all?
2864
+ *
2865
+ * `SharedArrayBuffer` needs cross-origin isolation in a browser, and
2866
+ * `Atomics.wait` is forbidden on a browser's main thread — which is why the
2867
+ * client is always the Worker.
2868
+ */
2869
+ declare function syncChannelSupported(): boolean;
2870
+
2681
2871
  /**
2682
2872
  * sandboxedjs — a Linux-like container that runs entirely inside Node.js.
2683
2873
  *
@@ -2696,4 +2886,4 @@ declare function extractNpmTarball(volume: RuntimeVolume, compressed: Uint8Array
2696
2886
  * ```
2697
2887
  */
2698
2888
 
2699
- export { ArithError, BufferSink, type CPythonOptions, CallbackSink, type ChildHandle, type ChildSpawnConfig, type CleanInstallerOptions, CleanPackageInstaller, type Command, CommandRegistry, CommonJsEngine, type CommonJsEngineOptions, type CommonJsModule, Container, ContainerFs, type ContainerOptions, type ContextInit, type CoreModulesOptions, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type EsmTransformResult, type ExecContext, type ExecOptions, type ExecResult, type FileData, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type InstallOptions, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, type LocalRuntimeOptions, LocalRuntimePod, MemoryVolume, type MountEntry, NODE_VERSION, NPM_VERSION, type NetInterface, type NetworkOptions, NetworkStack, NullInput, NullOutput, OS_RELEASE, type OutputStream, PYTHON_VERSION, type PasswdEntry, Pipe, Process, type ProcessKind, type ProcessOptions, type ProcessState, ProcessTable, type PythonOptions, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, type RuntimePackageInstaller, type RuntimePod, type RuntimeProcess, type RuntimeProcessManager, type RuntimeProcessResult, type RuntimeVolume, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnChild, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, VirtualHttpRouter, VirtualHttpServer, VirtualIncomingMessage, type VirtualNode, type VirtualProvider, VirtualServerResponse, WASM_ALIASES, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, configureCPython, configurePython, createChildProcessModule, createContainer, createContext, createCoreModules, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, extractNpmTarball, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isCPythonAvailable, isPythonAvailable, isSysError, looksLikeEsm, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, strerror, transformEsm, unameInfo };
2889
+ export { ArithError, BufferSink, type CPythonOptions, CallbackSink, type ChildHandle, type ChildSpawnConfig, type CleanInstallerOptions, CleanPackageInstaller, type Command, CommandRegistry, CommonJsEngine, type CommonJsEngineOptions, type CommonJsModule, Container, ContainerFs, type ContainerOptions, type ContextInit, type CoreModulesOptions, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type EsmTransformResult, type ExecContext, type ExecOptions, type ExecResult, type FileData, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type InstallOptions, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, type LocalRuntimeOptions, LocalRuntimePod, MemoryVolume, type MountEntry, NODE_VERSION, NPM_VERSION, type NetInterface, type NetworkOptions, NetworkStack, NullInput, NullOutput, OS_RELEASE, type OutputStream, PYTHON_VERSION, type PasswdEntry, Pipe, Process, type ProcessKind, type ProcessOptions, type ProcessState, ProcessTable, type PythonOptions, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, type RuntimePackageInstaller, type RuntimePod, type RuntimeProcess, type RuntimeProcessManager, type RuntimeProcessResult, type RuntimeVolume, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnChild, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, VirtualHttpRouter, VirtualHttpServer, VirtualIncomingMessage, type VirtualNode, type VirtualProvider, VirtualServerResponse, WASM_ALIASES, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, configureCPython, configurePython, createChildProcessModule, createContainer, createContext, createCoreModules, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, extractNpmTarball, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isCPythonAvailable, isPythonAvailable, isSysError, looksLikeEsm, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, startRuntimeWorker, strerror, syncChannelSupported, transformEsm, unameInfo };
package/dist/index.d.ts CHANGED
@@ -27,7 +27,30 @@ interface ChildSpawnConfig {
27
27
  parentPid?: number;
28
28
  }
29
29
  type SpawnChild = (config: ChildSpawnConfig) => ChildHandle;
30
- declare function createChildProcessModule(spawnChild: SpawnChild, defaultCwd: () => string): Record<string, unknown>;
30
+ /**
31
+ * Run a child to completion without returning to the event loop.
32
+ *
33
+ * Supplied only by a pod that can actually block — one whose guest runs on its
34
+ * own thread. Where it is absent the synchronous entry points keep reporting
35
+ * that they are unavailable, which is the honest answer for an in-realm pod.
36
+ */
37
+ type SyncSpawn = (request: {
38
+ command: string;
39
+ args: string[];
40
+ cwd: string;
41
+ env?: Record<string, string>;
42
+ input?: string;
43
+ }) => {
44
+ status: number | null;
45
+ stdout: string;
46
+ stderr: string;
47
+ signal: string | null;
48
+ error?: {
49
+ code?: string;
50
+ message: string;
51
+ };
52
+ };
53
+ declare function createChildProcessModule(spawnChild: SpawnChild, defaultCwd: () => string, syncSpawn?: SyncSpawn): Record<string, unknown>;
31
54
 
32
55
  /**
33
56
  * Clean-room contracts between SandboxedJS and its JavaScript runtime.
@@ -1639,6 +1662,24 @@ interface ContainerOptions {
1639
1662
  * ```
1640
1663
  */
1641
1664
  pod?: RuntimePod;
1665
+ /**
1666
+ * Where guest programs run.
1667
+ *
1668
+ * `"worker"` (the default) gives each program its own thread, which is what
1669
+ * makes synchronous child processes work and keeps guest code out of the
1670
+ * host's realm; it falls back automatically where the host cannot support it.
1671
+ * `"realm"` forces the in-realm runtime.
1672
+ */
1673
+ isolation?: "worker" | "realm";
1674
+ /**
1675
+ * Where to load the guest worker bundle from.
1676
+ *
1677
+ * Defaults to the copy shipped beside the main bundle, which is what a
1678
+ * published package wants. Worth setting when a bundler has moved or
1679
+ * rewritten it — or when running from source, where the built file is the
1680
+ * only one a Worker can load.
1681
+ */
1682
+ workerUrl?: string | URL;
1642
1683
  /** Python runtime settings; a browser host uses this to locate the wasm. */
1643
1684
  python?: PythonOptions;
1644
1685
  }
@@ -2457,6 +2498,14 @@ interface CoreModulesOptions {
2457
2498
  };
2458
2499
  /** Backs `child_process`; without it the module reports as unavailable. */
2459
2500
  spawnChild?: SpawnChild;
2501
+ /**
2502
+ * Backs the `*Sync` half of `child_process`.
2503
+ *
2504
+ * Only a pod whose guest runs on its own thread can supply this — blocking
2505
+ * requires somewhere else for the child's work to happen. Without it the
2506
+ * synchronous entry points keep reporting that they are unavailable.
2507
+ */
2508
+ syncSpawn?: SyncSpawn;
2460
2509
  /** File holding the process's standard input, exposed as descriptor 0. */
2461
2510
  stdinPath?: string;
2462
2511
  /** Keep `process.stdin` open and fed by {@link writeStdin} rather than ending it. */
@@ -2496,6 +2545,13 @@ declare function createCoreModules(options: CoreModulesOptions): {
2496
2545
  pendingHandles(): number;
2497
2546
  /** Active timers which called `unref()` and therefore only merit startup grace. */
2498
2547
  pendingUnrefed(): number;
2548
+ /**
2549
+ * Cancel every timer this process still holds.
2550
+ *
2551
+ * Called when a process is killed: the process is finished, but its
2552
+ * scheduled work would otherwise keep running on the host's event loop.
2553
+ */
2554
+ cancelTimers(): void;
2499
2555
  /**
2500
2556
  * Client requests sent but not yet read to completion.
2501
2557
  *
@@ -2533,6 +2589,99 @@ declare function looksLikeEsm(source: string): boolean;
2533
2589
  */
2534
2590
  declare function transformEsm(source: string, filename?: string): EsmTransformResult | null;
2535
2591
 
2592
+ /**
2593
+ * A volume that keeps a second, foreign filesystem in step with itself.
2594
+ *
2595
+ * Rolldown's browser WebAssembly binding owns a `memfs` volume of its own —
2596
+ * its Rust resolver reads through WASI, not through anything JavaScript can
2597
+ * hand it. So the sandbox project has to exist in two places at once, and the
2598
+ * copy has to stay current: a dev server reads `index.html` when the request
2599
+ * arrives, not when the process started.
2600
+ *
2601
+ * Mirroring on write rather than copying up-front is what makes that true. The
2602
+ * previous approach took one deep snapshot per spawn, which was both expensive
2603
+ * — every `npm run dev` re-copied `node_modules` — and already stale by the
2604
+ * time it mattered, so an edit during a session was served from the old tree.
2605
+ *
2606
+ * The mirror is deliberately one-way and best-effort. It is a cache for a
2607
+ * consumer that only reads; a write that fails to reach it must never fail the
2608
+ * write that the container itself made.
2609
+ */
2610
+
2611
+ /** The slice of a `memfs`-style filesystem the mirror writes through. */
2612
+ interface MirrorFs {
2613
+ mkdirSync(path: string, options?: {
2614
+ recursive?: boolean;
2615
+ }): void;
2616
+ writeFileSync(path: string, data: Uint8Array): void;
2617
+ symlinkSync(target: string, path: string): void;
2618
+ rmSync?(path: string, options?: {
2619
+ recursive?: boolean;
2620
+ force?: boolean;
2621
+ }): void;
2622
+ unlinkSync?(path: string): void;
2623
+ rmdirSync?(path: string): void;
2624
+ }
2625
+ /**
2626
+ * A `RuntimeVolume` that forwards every mutation to an optional mirror.
2627
+ *
2628
+ * Wrapping rather than modifying `MemoryVolume` keeps the mirroring concern out
2629
+ * of the filesystem, and keeps this transparent to the kernel, whose `Vfs`
2630
+ * takes any `RuntimeVolume`.
2631
+ */
2632
+ declare class MirroringVolume implements RuntimeVolume {
2633
+ private readonly inner;
2634
+ private mirror;
2635
+ private root;
2636
+ constructor(inner?: MemoryVolume);
2637
+ /**
2638
+ * Start mirroring the tree under `root`, seeding it with what is there now.
2639
+ *
2640
+ * Called once the Rolldown binding is known to be in play; before that a
2641
+ * container pays nothing for this.
2642
+ */
2643
+ attach(mirror: MirrorFs, root: string): void;
2644
+ detach(): void;
2645
+ /** Copy the whole subtree across. The only bulk operation that remains. */
2646
+ private seed;
2647
+ /** Is this path inside the mirrored subtree? */
2648
+ private mirrored;
2649
+ /**
2650
+ * Run a mirror update, swallowing failure.
2651
+ *
2652
+ * The mirror is a read-only cache for another engine. If it rejects
2653
+ * something — an unsupported operation, a path it has not seen — the
2654
+ * container's own write has still happened and must still succeed.
2655
+ */
2656
+ private safely;
2657
+ /** Push a path's current state across, whatever it is now. */
2658
+ private sync;
2659
+ readFileSync(path: string): Uint8Array;
2660
+ readdirSync(path: string): string[];
2661
+ lstatSync(path: string): VolumeStat;
2662
+ readlinkSync(path: string): string;
2663
+ getStats(): VolumeStats;
2664
+ writeFileSync(path: string, data: string | Uint8Array): void;
2665
+ appendFileSync(path: string, data: string | Uint8Array): void;
2666
+ mkdirSync(path: string, options?: {
2667
+ mode?: number;
2668
+ }): void;
2669
+ rmdirSync(path: string): void;
2670
+ unlinkSync(path: string): void;
2671
+ renameSync(from: string, to: string): void;
2672
+ symlinkSync(target: string, path: string): void;
2673
+ linkSync(existing: string, path: string): void;
2674
+ truncateSync(path: string, length?: number): void;
2675
+ chmodSync(path: string, mode: number): void;
2676
+ lchmodSync(path: string, mode: number): void;
2677
+ chownSync(path: string, uid: number, gid: number): void;
2678
+ lchownSync(path: string, uid: number, gid: number): void;
2679
+ utimesSync(path: string, atime: Date, mtime: Date): void;
2680
+ snapshot(): MemoryVolumeSnapshotEntry[];
2681
+ /** A restore replaces everything, so the mirror is rebuilt rather than patched. */
2682
+ restore(entries: MemoryVolumeSnapshotEntry[]): void;
2683
+ }
2684
+
2536
2685
  interface LocalRuntimeOptions {
2537
2686
  workdir?: string;
2538
2687
  env?: Record<string, string>;
@@ -2569,10 +2718,10 @@ declare const WASM_ALIASES: Record<string, string>;
2569
2718
  * dedicated Worker before this becomes the default untrusted-code path.
2570
2719
  */
2571
2720
  declare class LocalRuntimePod implements RuntimePod {
2572
- readonly volume: MemoryVolume;
2721
+ readonly volume: MirroringVolume;
2573
2722
  readonly packages: RuntimePackageInstaller;
2574
2723
  readonly instanceId: string;
2575
- private readonly router;
2724
+ protected readonly router: VirtualHttpRouter;
2576
2725
  readonly proxy: {
2577
2726
  activePorts: (_instanceId?: string) => number[];
2578
2727
  };
@@ -2585,15 +2734,15 @@ declare class LocalRuntimePod implements RuntimePod {
2585
2734
  spawn(config: ChildSpawnConfig): ChildHandle;
2586
2735
  };
2587
2736
  private disposed;
2588
- private readonly workdir;
2589
- private readonly env;
2590
- private readonly aliases;
2737
+ protected readonly workdir: string;
2738
+ protected readonly env: Record<string, string>;
2739
+ protected readonly aliases: Record<string, string>;
2591
2740
  private readonly modules;
2592
2741
  private readonly esbuild;
2593
2742
  private rolldownBinding;
2594
2743
  /** Backs outbound `http`/`https` client requests from inside the sandbox. */
2595
2744
  private readonly fetch;
2596
- private constructor();
2745
+ protected constructor(options: LocalRuntimeOptions);
2597
2746
  static boot(options?: LocalRuntimeOptions): Promise<LocalRuntimePod>;
2598
2747
  spawn(command: string, args?: string[], options?: Record<string, unknown>): Promise<RuntimeProcess>;
2599
2748
  /**
@@ -2678,6 +2827,47 @@ declare class CleanPackageInstaller implements RuntimePackageInstaller {
2678
2827
  }
2679
2828
  declare function extractNpmTarball(volume: RuntimeVolume, compressed: Uint8Array, destination: string): void;
2680
2829
 
2830
+ /**
2831
+ * Starting the guest Worker, in whichever environment the host happens to be.
2832
+ *
2833
+ * The awkward part of shipping a Worker from a library is not creating it, but
2834
+ * naming it. `new URL("./worker-entry.js", import.meta.url)` is the form every
2835
+ * bundler recognises, and it resolves correctly from `dist/` — but a bundler
2836
+ * that *pre-bundles* this package rewrites `import.meta.url` to point into its
2837
+ * own dependency cache, where no such file exists. That is the same trap
2838
+ * Rolldown's WASI binding falls into, and it surfaces just as obliquely.
2839
+ *
2840
+ * So this never assumes it worked. The caller treats a failure to start as
2841
+ * "this host cannot run the Worker pod" and uses the in-realm pod instead.
2842
+ */
2843
+ interface RuntimeWorker {
2844
+ postMessage(message: unknown): void;
2845
+ onMessage(listener: (message: unknown) => void): void;
2846
+ onError(listener: (error: unknown) => void): void;
2847
+ terminate(): unknown;
2848
+ }
2849
+ /**
2850
+ * Start the guest Worker and wait for it to say it is alive.
2851
+ *
2852
+ * Rejects rather than hanging when the script cannot be loaded: a Worker whose
2853
+ * script 404s reports an `error` event and would otherwise leave the caller
2854
+ * waiting for a ready message that can never arrive.
2855
+ */
2856
+ declare function startRuntimeWorker(options?: {
2857
+ url?: string | URL;
2858
+ workerData?: Record<string, unknown>;
2859
+ timeoutMs?: number;
2860
+ }): Promise<RuntimeWorker>;
2861
+
2862
+ /**
2863
+ * Can this environment support a blocking client at all?
2864
+ *
2865
+ * `SharedArrayBuffer` needs cross-origin isolation in a browser, and
2866
+ * `Atomics.wait` is forbidden on a browser's main thread — which is why the
2867
+ * client is always the Worker.
2868
+ */
2869
+ declare function syncChannelSupported(): boolean;
2870
+
2681
2871
  /**
2682
2872
  * sandboxedjs — a Linux-like container that runs entirely inside Node.js.
2683
2873
  *
@@ -2696,4 +2886,4 @@ declare function extractNpmTarball(volume: RuntimeVolume, compressed: Uint8Array
2696
2886
  * ```
2697
2887
  */
2698
2888
 
2699
- export { ArithError, BufferSink, type CPythonOptions, CallbackSink, type ChildHandle, type ChildSpawnConfig, type CleanInstallerOptions, CleanPackageInstaller, type Command, CommandRegistry, CommonJsEngine, type CommonJsEngineOptions, type CommonJsModule, Container, ContainerFs, type ContainerOptions, type ContextInit, type CoreModulesOptions, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type EsmTransformResult, type ExecContext, type ExecOptions, type ExecResult, type FileData, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type InstallOptions, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, type LocalRuntimeOptions, LocalRuntimePod, MemoryVolume, type MountEntry, NODE_VERSION, NPM_VERSION, type NetInterface, type NetworkOptions, NetworkStack, NullInput, NullOutput, OS_RELEASE, type OutputStream, PYTHON_VERSION, type PasswdEntry, Pipe, Process, type ProcessKind, type ProcessOptions, type ProcessState, ProcessTable, type PythonOptions, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, type RuntimePackageInstaller, type RuntimePod, type RuntimeProcess, type RuntimeProcessManager, type RuntimeProcessResult, type RuntimeVolume, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnChild, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, VirtualHttpRouter, VirtualHttpServer, VirtualIncomingMessage, type VirtualNode, type VirtualProvider, VirtualServerResponse, WASM_ALIASES, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, configureCPython, configurePython, createChildProcessModule, createContainer, createContext, createCoreModules, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, extractNpmTarball, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isCPythonAvailable, isPythonAvailable, isSysError, looksLikeEsm, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, strerror, transformEsm, unameInfo };
2889
+ export { ArithError, BufferSink, type CPythonOptions, CallbackSink, type ChildHandle, type ChildSpawnConfig, type CleanInstallerOptions, CleanPackageInstaller, type Command, CommandRegistry, CommonJsEngine, type CommonJsEngineOptions, type CommonJsModule, Container, ContainerFs, type ContainerOptions, type ContextInit, type CoreModulesOptions, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type EsmTransformResult, type ExecContext, type ExecOptions, type ExecResult, type FileData, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type InstallOptions, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, type LocalRuntimeOptions, LocalRuntimePod, MemoryVolume, type MountEntry, NODE_VERSION, NPM_VERSION, type NetInterface, type NetworkOptions, NetworkStack, NullInput, NullOutput, OS_RELEASE, type OutputStream, PYTHON_VERSION, type PasswdEntry, Pipe, Process, type ProcessKind, type ProcessOptions, type ProcessState, ProcessTable, type PythonOptions, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, type RuntimePackageInstaller, type RuntimePod, type RuntimeProcess, type RuntimeProcessManager, type RuntimeProcessResult, type RuntimeVolume, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnChild, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, VirtualHttpRouter, VirtualHttpServer, VirtualIncomingMessage, type VirtualNode, type VirtualProvider, VirtualServerResponse, WASM_ALIASES, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, configureCPython, configurePython, createChildProcessModule, createContainer, createContext, createCoreModules, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, extractNpmTarball, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isCPythonAvailable, isPythonAvailable, isSysError, looksLikeEsm, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, startRuntimeWorker, strerror, syncChannelSupported, transformEsm, unameInfo };