sandboxedjs 0.1.26 → 0.1.28

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
@@ -9,6 +9,14 @@ interface ChildHandle {
9
9
  on(event: "stdout" | "stderr" | "exit", listener: (...args: any[]) => void): unknown;
10
10
  exec(): void;
11
11
  sendStdin(data: string): void;
12
+ /**
13
+ * Close the child's input.
14
+ *
15
+ * Without this a child that reads stdin to EOF — every filter, and every
16
+ * tool a library pipes into, `xsel` and `base64` alike — waits forever for
17
+ * an end that never comes, and the parent waits on its exit.
18
+ */
19
+ endStdin?(): void;
12
20
  kill(signal?: string): void;
13
21
  }
14
22
  interface ChildSpawnConfig {
@@ -196,7 +204,7 @@ interface DirEntry {
196
204
  /**
197
205
  * The container's virtual filesystem.
198
206
  *
199
- * Real file content lives in a Nodepod `MemoryVolume`, which is deliberately the
207
+ * Real file content lives in the RuntimePod's `MemoryVolume`, deliberately the
200
208
  * *same* volume the Node.js worker processes see — so a file written by `echo`
201
209
  * is readable by `require('fs')` inside a spawned script, and vice versa.
202
210
  *
@@ -746,7 +754,7 @@ declare function createContext(init: ContextInit): ExecContext;
746
754
  * The container's network stack.
747
755
  *
748
756
  * There is no real socket layer: HTTP servers started inside the container are
749
- * registered with Nodepod's request proxy, and this module is the routing and
757
+ * registered with the RuntimePod's request proxy, and this module is the routing and
750
758
  * name-resolution layer on top — interfaces for `ip`/`ifconfig`, a hosts file
751
759
  * resolver, a listening-port table for `ss`/`netstat`, and an outbound policy
752
760
  * that decides whether `curl https://example.com` is allowed to touch the real
@@ -805,7 +813,7 @@ declare class NetworkStack {
805
813
  registerListener(port: number, info: Omit<ListeningPort, "port" | "since">): void;
806
814
  unregisterListener(port: number): void;
807
815
  listening(): ListeningPort[];
808
- /** Ports Nodepod's proxy has registered for this instance. */
816
+ /** Ports the pod's proxy has registered for this instance. */
809
817
  private knownPodPorts;
810
818
  /** True when something inside the container answers on `port`. */
811
819
  isPortOpen(port: number, timeoutMs?: number): Promise<boolean>;
@@ -1732,7 +1740,7 @@ declare class Container {
1732
1740
  /**
1733
1741
  * Deliver a request whose body is bytes, without letting them become text.
1734
1742
  *
1735
- * Nodepod's public `request()` runs the body through `toString("utf8")` on
1743
+ * A RuntimePod's public `request()` may run the body through `toString("utf8")` on
1736
1744
  * its way in, so anything above `0x7f` is replaced: a five-byte payload
1737
1745
  * containing `0x89` and `0xff` arrives as nine. That silently destroys every
1738
1746
  * upload — an image or a video reaches the server the wrong size and no
@@ -1772,7 +1780,7 @@ declare class Container {
1772
1780
  get cwd(): string;
1773
1781
  get env(): Record<string, string>;
1774
1782
  private assertActive;
1775
- /** Tear down every process and release the Nodepod instance. */
1783
+ /** Tear down every process and release the runtime pod. */
1776
1784
  dispose(): void;
1777
1785
  get isDisposed(): boolean;
1778
1786
  }
@@ -2114,17 +2122,16 @@ interface RootfsOptions {
2114
2122
  declare function buildRootfs(vfs: Vfs, opts?: RootfsOptions): void;
2115
2123
 
2116
2124
  /**
2117
- * The Node.js runtime, backed by Nodepod.
2125
+ * The Node.js command adapter, backed by the clean-room RuntimePod.
2118
2126
  *
2119
- * Nodepod runs the script in an isolated worker over the *same* memory volume
2127
+ * The pod runs the script over the *same* memory volume
2120
2128
  * the container's filesystem uses, so `require('fs')` inside a script sees the
2121
2129
  * files `echo` and `tar` created, and anything the script writes is visible to
2122
2130
  * the shell afterwards.
2123
2131
  *
2124
- * Two gaps in the underlying `spawn` are papered over here:
2132
+ * Two details of the underlying `spawn` are handled here:
2125
2133
  * - only `node` resolves as a command, so everything else is dispatched by our
2126
- * own kernel rather than being handed to Nodepod's shell (which hangs on an
2127
- * unknown command);
2134
+ * own kernel rather than being handed to the Node process runner;
2128
2135
  * - the worker's stdin has no end-of-stream signal, so when a pipeline feeds
2129
2136
  * a script we materialise stdin as a file and install a real stdin stream
2130
2137
  * over it before the script loads.
@@ -2427,6 +2434,8 @@ declare class VirtualHttpRouter {
2427
2434
  onListen: ((port: number) => void) | undefined;
2428
2435
  register(port: number, server: VirtualHttpServer, owner: string): void;
2429
2436
  unregister(port: number, server: VirtualHttpServer): void;
2437
+ /** Whether anything in this container is listening on `port`. */
2438
+ activePortsIncludes(port: number): boolean;
2430
2439
  activePorts(owner?: string): number[];
2431
2440
  closeOwner(owner: string): void;
2432
2441
  closeAll(): void;
@@ -2444,6 +2453,7 @@ interface CoreModulesOptions {
2444
2453
  http?: {
2445
2454
  router: VirtualHttpRouter;
2446
2455
  owner: string;
2456
+ fetch?: typeof globalThis.fetch;
2447
2457
  };
2448
2458
  /** Backs `child_process`; without it the module reports as unavailable. */
2449
2459
  spawnChild?: SpawnChild;
@@ -2484,6 +2494,16 @@ declare function createCoreModules(options: CoreModulesOptions): {
2484
2494
  * script that has simply finished.
2485
2495
  */
2486
2496
  pendingHandles(): number;
2497
+ /** Active timers which called `unref()` and therefore only merit startup grace. */
2498
+ pendingUnrefed(): number;
2499
+ /**
2500
+ * Client requests sent but not yet read to completion.
2501
+ *
2502
+ * An outbound request is event-loop work in exactly the way a timer is, and
2503
+ * it schedules no timer of its own. Counting it is what stops a program from
2504
+ * exiting in the gap between `http.get` and its response callback.
2505
+ */
2506
+ pendingRequests(): number;
2487
2507
  };
2488
2508
 
2489
2509
  interface EsmTransformResult {
@@ -2570,9 +2590,20 @@ declare class LocalRuntimePod implements RuntimePod {
2570
2590
  private readonly aliases;
2571
2591
  private readonly modules;
2572
2592
  private readonly esbuild;
2593
+ private rolldownBinding;
2594
+ /** Backs outbound `http`/`https` client requests from inside the sandbox. */
2595
+ private readonly fetch;
2573
2596
  private constructor();
2574
2597
  static boot(options?: LocalRuntimeOptions): Promise<LocalRuntimePod>;
2575
2598
  spawn(command: string, args?: string[], options?: Record<string, unknown>): Promise<RuntimeProcess>;
2599
+ /**
2600
+ * Rolldown's JavaScript API synchronously requires its compiled binding.
2601
+ * When a project contains Rolldown, preload the official WASI build in the
2602
+ * host and expose it through the module override table before evaluation.
2603
+ * Keeping this demand-driven avoids adding WASM startup cost to ordinary
2604
+ * shells and Node programs.
2605
+ */
2606
+ private prepareRolldown;
2576
2607
  /**
2577
2608
  * Wait until the process has either started serving or genuinely run out of
2578
2609
  * work.
@@ -2607,6 +2638,10 @@ interface RegistryManifest {
2607
2638
  };
2608
2639
  dependencies?: Record<string, string>;
2609
2640
  optionalDependencies?: Record<string, string>;
2641
+ os?: string[];
2642
+ cpu?: string[];
2643
+ libc?: string[];
2644
+ main?: string;
2610
2645
  bin?: string | Record<string, string>;
2611
2646
  }
2612
2647
  interface CleanInstallerOptions {
package/dist/index.d.ts CHANGED
@@ -9,6 +9,14 @@ interface ChildHandle {
9
9
  on(event: "stdout" | "stderr" | "exit", listener: (...args: any[]) => void): unknown;
10
10
  exec(): void;
11
11
  sendStdin(data: string): void;
12
+ /**
13
+ * Close the child's input.
14
+ *
15
+ * Without this a child that reads stdin to EOF — every filter, and every
16
+ * tool a library pipes into, `xsel` and `base64` alike — waits forever for
17
+ * an end that never comes, and the parent waits on its exit.
18
+ */
19
+ endStdin?(): void;
12
20
  kill(signal?: string): void;
13
21
  }
14
22
  interface ChildSpawnConfig {
@@ -196,7 +204,7 @@ interface DirEntry {
196
204
  /**
197
205
  * The container's virtual filesystem.
198
206
  *
199
- * Real file content lives in a Nodepod `MemoryVolume`, which is deliberately the
207
+ * Real file content lives in the RuntimePod's `MemoryVolume`, deliberately the
200
208
  * *same* volume the Node.js worker processes see — so a file written by `echo`
201
209
  * is readable by `require('fs')` inside a spawned script, and vice versa.
202
210
  *
@@ -746,7 +754,7 @@ declare function createContext(init: ContextInit): ExecContext;
746
754
  * The container's network stack.
747
755
  *
748
756
  * There is no real socket layer: HTTP servers started inside the container are
749
- * registered with Nodepod's request proxy, and this module is the routing and
757
+ * registered with the RuntimePod's request proxy, and this module is the routing and
750
758
  * name-resolution layer on top — interfaces for `ip`/`ifconfig`, a hosts file
751
759
  * resolver, a listening-port table for `ss`/`netstat`, and an outbound policy
752
760
  * that decides whether `curl https://example.com` is allowed to touch the real
@@ -805,7 +813,7 @@ declare class NetworkStack {
805
813
  registerListener(port: number, info: Omit<ListeningPort, "port" | "since">): void;
806
814
  unregisterListener(port: number): void;
807
815
  listening(): ListeningPort[];
808
- /** Ports Nodepod's proxy has registered for this instance. */
816
+ /** Ports the pod's proxy has registered for this instance. */
809
817
  private knownPodPorts;
810
818
  /** True when something inside the container answers on `port`. */
811
819
  isPortOpen(port: number, timeoutMs?: number): Promise<boolean>;
@@ -1732,7 +1740,7 @@ declare class Container {
1732
1740
  /**
1733
1741
  * Deliver a request whose body is bytes, without letting them become text.
1734
1742
  *
1735
- * Nodepod's public `request()` runs the body through `toString("utf8")` on
1743
+ * A RuntimePod's public `request()` may run the body through `toString("utf8")` on
1736
1744
  * its way in, so anything above `0x7f` is replaced: a five-byte payload
1737
1745
  * containing `0x89` and `0xff` arrives as nine. That silently destroys every
1738
1746
  * upload — an image or a video reaches the server the wrong size and no
@@ -1772,7 +1780,7 @@ declare class Container {
1772
1780
  get cwd(): string;
1773
1781
  get env(): Record<string, string>;
1774
1782
  private assertActive;
1775
- /** Tear down every process and release the Nodepod instance. */
1783
+ /** Tear down every process and release the runtime pod. */
1776
1784
  dispose(): void;
1777
1785
  get isDisposed(): boolean;
1778
1786
  }
@@ -2114,17 +2122,16 @@ interface RootfsOptions {
2114
2122
  declare function buildRootfs(vfs: Vfs, opts?: RootfsOptions): void;
2115
2123
 
2116
2124
  /**
2117
- * The Node.js runtime, backed by Nodepod.
2125
+ * The Node.js command adapter, backed by the clean-room RuntimePod.
2118
2126
  *
2119
- * Nodepod runs the script in an isolated worker over the *same* memory volume
2127
+ * The pod runs the script over the *same* memory volume
2120
2128
  * the container's filesystem uses, so `require('fs')` inside a script sees the
2121
2129
  * files `echo` and `tar` created, and anything the script writes is visible to
2122
2130
  * the shell afterwards.
2123
2131
  *
2124
- * Two gaps in the underlying `spawn` are papered over here:
2132
+ * Two details of the underlying `spawn` are handled here:
2125
2133
  * - only `node` resolves as a command, so everything else is dispatched by our
2126
- * own kernel rather than being handed to Nodepod's shell (which hangs on an
2127
- * unknown command);
2134
+ * own kernel rather than being handed to the Node process runner;
2128
2135
  * - the worker's stdin has no end-of-stream signal, so when a pipeline feeds
2129
2136
  * a script we materialise stdin as a file and install a real stdin stream
2130
2137
  * over it before the script loads.
@@ -2427,6 +2434,8 @@ declare class VirtualHttpRouter {
2427
2434
  onListen: ((port: number) => void) | undefined;
2428
2435
  register(port: number, server: VirtualHttpServer, owner: string): void;
2429
2436
  unregister(port: number, server: VirtualHttpServer): void;
2437
+ /** Whether anything in this container is listening on `port`. */
2438
+ activePortsIncludes(port: number): boolean;
2430
2439
  activePorts(owner?: string): number[];
2431
2440
  closeOwner(owner: string): void;
2432
2441
  closeAll(): void;
@@ -2444,6 +2453,7 @@ interface CoreModulesOptions {
2444
2453
  http?: {
2445
2454
  router: VirtualHttpRouter;
2446
2455
  owner: string;
2456
+ fetch?: typeof globalThis.fetch;
2447
2457
  };
2448
2458
  /** Backs `child_process`; without it the module reports as unavailable. */
2449
2459
  spawnChild?: SpawnChild;
@@ -2484,6 +2494,16 @@ declare function createCoreModules(options: CoreModulesOptions): {
2484
2494
  * script that has simply finished.
2485
2495
  */
2486
2496
  pendingHandles(): number;
2497
+ /** Active timers which called `unref()` and therefore only merit startup grace. */
2498
+ pendingUnrefed(): number;
2499
+ /**
2500
+ * Client requests sent but not yet read to completion.
2501
+ *
2502
+ * An outbound request is event-loop work in exactly the way a timer is, and
2503
+ * it schedules no timer of its own. Counting it is what stops a program from
2504
+ * exiting in the gap between `http.get` and its response callback.
2505
+ */
2506
+ pendingRequests(): number;
2487
2507
  };
2488
2508
 
2489
2509
  interface EsmTransformResult {
@@ -2570,9 +2590,20 @@ declare class LocalRuntimePod implements RuntimePod {
2570
2590
  private readonly aliases;
2571
2591
  private readonly modules;
2572
2592
  private readonly esbuild;
2593
+ private rolldownBinding;
2594
+ /** Backs outbound `http`/`https` client requests from inside the sandbox. */
2595
+ private readonly fetch;
2573
2596
  private constructor();
2574
2597
  static boot(options?: LocalRuntimeOptions): Promise<LocalRuntimePod>;
2575
2598
  spawn(command: string, args?: string[], options?: Record<string, unknown>): Promise<RuntimeProcess>;
2599
+ /**
2600
+ * Rolldown's JavaScript API synchronously requires its compiled binding.
2601
+ * When a project contains Rolldown, preload the official WASI build in the
2602
+ * host and expose it through the module override table before evaluation.
2603
+ * Keeping this demand-driven avoids adding WASM startup cost to ordinary
2604
+ * shells and Node programs.
2605
+ */
2606
+ private prepareRolldown;
2576
2607
  /**
2577
2608
  * Wait until the process has either started serving or genuinely run out of
2578
2609
  * work.
@@ -2607,6 +2638,10 @@ interface RegistryManifest {
2607
2638
  };
2608
2639
  dependencies?: Record<string, string>;
2609
2640
  optionalDependencies?: Record<string, string>;
2641
+ os?: string[];
2642
+ cpu?: string[];
2643
+ libc?: string[];
2644
+ main?: string;
2610
2645
  bin?: string | Record<string, string>;
2611
2646
  }
2612
2647
  interface CleanInstallerOptions {