sandboxedjs 0.1.11 → 0.1.13

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
@@ -1293,16 +1293,23 @@ declare class Shell {
1293
1293
  * so it reads naturally from the outside.
1294
1294
  */
1295
1295
 
1296
+ /** Data accepted by the host-facing filesystem API.
1297
+ *
1298
+ * `Blob` includes browser `File` objects, which is what an `<input
1299
+ * type="file">` returns. The bytes are copied into the container; no host
1300
+ * filesystem path is ever resolved by the sandbox.
1301
+ */
1302
+ type FileData = string | Uint8Array | ArrayBuffer | ArrayBufferView | Blob;
1296
1303
  declare class ContainerFs {
1297
1304
  private readonly kernel;
1298
1305
  constructor(kernel: Kernel);
1299
1306
  private get vfs();
1300
1307
  readFile(path: string): Promise<Uint8Array>;
1301
1308
  readFile(path: string, encoding: "utf8" | "utf-8"): Promise<string>;
1302
- writeFile(path: string, data: string | Uint8Array, opts?: {
1309
+ writeFile(path: string, data: FileData, opts?: {
1303
1310
  mode?: number;
1304
1311
  }): Promise<void>;
1305
- appendFile(path: string, data: string | Uint8Array): Promise<void>;
1312
+ appendFile(path: string, data: FileData): Promise<void>;
1306
1313
  readdir(path: string): Promise<string[]>;
1307
1314
  readdir(path: string, opts: {
1308
1315
  withFileTypes: true;
@@ -1336,7 +1343,7 @@ declare class ContainerFs {
1336
1343
  /** Read many files at once, keyed by path. */
1337
1344
  readAll(paths: string[]): Promise<Record<string, string>>;
1338
1345
  /** Write a whole map of files, creating parents. */
1339
- writeAll(files: Record<string, string | Uint8Array>, opts?: {
1346
+ writeAll(files: Record<string, FileData>, opts?: {
1340
1347
  cwd?: string;
1341
1348
  }): Promise<void>;
1342
1349
  }
@@ -1502,6 +1509,7 @@ declare class Container {
1502
1509
  private readonly hooks;
1503
1510
  private disposed;
1504
1511
  private defaultSession;
1512
+ private readonly restoreNodeChildProcessBridge;
1505
1513
  private constructor();
1506
1514
  static create(opts?: ContainerOptions): Promise<Container>;
1507
1515
  /**
@@ -1986,4 +1994,4 @@ declare const NPM_VERSION = "10.9.0";
1986
1994
  * ```
1987
1995
  */
1988
1996
 
1989
- export { ArithError, BufferSink, CallbackSink, type Command, CommandRegistry, Container, ContainerFs, type ContainerOptions, type ContextInit, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type ExecContext, type ExecOptions, type ExecResult, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, 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, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, type VirtualNode, type VirtualProvider, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, createContainer, createContext, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isPythonAvailable, isSysError, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, strerror, unameInfo };
1997
+ export { ArithError, BufferSink, CallbackSink, type Command, CommandRegistry, Container, ContainerFs, type ContainerOptions, type ContextInit, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type ExecContext, type ExecOptions, type ExecResult, type FileData, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, 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, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, type VirtualNode, type VirtualProvider, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, createContainer, createContext, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isPythonAvailable, isSysError, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, strerror, unameInfo };
package/dist/index.d.ts CHANGED
@@ -1293,16 +1293,23 @@ declare class Shell {
1293
1293
  * so it reads naturally from the outside.
1294
1294
  */
1295
1295
 
1296
+ /** Data accepted by the host-facing filesystem API.
1297
+ *
1298
+ * `Blob` includes browser `File` objects, which is what an `<input
1299
+ * type="file">` returns. The bytes are copied into the container; no host
1300
+ * filesystem path is ever resolved by the sandbox.
1301
+ */
1302
+ type FileData = string | Uint8Array | ArrayBuffer | ArrayBufferView | Blob;
1296
1303
  declare class ContainerFs {
1297
1304
  private readonly kernel;
1298
1305
  constructor(kernel: Kernel);
1299
1306
  private get vfs();
1300
1307
  readFile(path: string): Promise<Uint8Array>;
1301
1308
  readFile(path: string, encoding: "utf8" | "utf-8"): Promise<string>;
1302
- writeFile(path: string, data: string | Uint8Array, opts?: {
1309
+ writeFile(path: string, data: FileData, opts?: {
1303
1310
  mode?: number;
1304
1311
  }): Promise<void>;
1305
- appendFile(path: string, data: string | Uint8Array): Promise<void>;
1312
+ appendFile(path: string, data: FileData): Promise<void>;
1306
1313
  readdir(path: string): Promise<string[]>;
1307
1314
  readdir(path: string, opts: {
1308
1315
  withFileTypes: true;
@@ -1336,7 +1343,7 @@ declare class ContainerFs {
1336
1343
  /** Read many files at once, keyed by path. */
1337
1344
  readAll(paths: string[]): Promise<Record<string, string>>;
1338
1345
  /** Write a whole map of files, creating parents. */
1339
- writeAll(files: Record<string, string | Uint8Array>, opts?: {
1346
+ writeAll(files: Record<string, FileData>, opts?: {
1340
1347
  cwd?: string;
1341
1348
  }): Promise<void>;
1342
1349
  }
@@ -1502,6 +1509,7 @@ declare class Container {
1502
1509
  private readonly hooks;
1503
1510
  private disposed;
1504
1511
  private defaultSession;
1512
+ private readonly restoreNodeChildProcessBridge;
1505
1513
  private constructor();
1506
1514
  static create(opts?: ContainerOptions): Promise<Container>;
1507
1515
  /**
@@ -1986,4 +1994,4 @@ declare const NPM_VERSION = "10.9.0";
1986
1994
  * ```
1987
1995
  */
1988
1996
 
1989
- export { ArithError, BufferSink, CallbackSink, type Command, CommandRegistry, Container, ContainerFs, type ContainerOptions, type ContextInit, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type ExecContext, type ExecOptions, type ExecResult, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, 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, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, type VirtualNode, type VirtualProvider, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, createContainer, createContext, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isPythonAvailable, isSysError, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, strerror, unameInfo };
1997
+ export { ArithError, BufferSink, CallbackSink, type Command, CommandRegistry, Container, ContainerFs, type ContainerOptions, type ContextInit, type Cred, type DirEntry, ERRNO, type Env, type ErrnoCode, type ExecContext, type ExecOptions, type ExecResult, type FileData, FileInput, FileOutput, type GroupEntry, type HttpResponse, IncompleteInputError, type InputStream, type Job, KERNEL_NAME, KERNEL_RELEASE, Kernel, type KernelOptions, type ListeningPort, 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, ROOT_CRED, type ResolvedExecutable, type RootfsOptions, type RunOptions, type RunResult, SIGNALS, SIGNAL_NAMES, Session, type SessionInit, type SessionResult, type SessionRunOptions, Shell, ShellExit, type ShellIO, type ShellInit, Lexer as ShellLexer, type ShellOptions, ShellSyntaxError, type SpawnHandle, Stats, type Stdio, SysError, TeeOutput, Terminal, type TerminalOptions, UserDatabase, Variables, Vfs, type VirtualNode, type VirtualProvider, type WriteOptions, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, createContainer, createContext, createContainer as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isPythonAvailable, isSysError, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path as posixPath, resetPidCounter, shellQuote, strerror, unameInfo };
package/dist/index.js CHANGED
@@ -23475,6 +23475,14 @@ function installUserland(kernel) {
23475
23475
 
23476
23476
  // src/container/fs.ts
23477
23477
  init_path();
23478
+ async function bytesFor(data) {
23479
+ if (data instanceof Uint8Array) return data;
23480
+ if (data instanceof ArrayBuffer) return new Uint8Array(data);
23481
+ if (ArrayBuffer.isView(data)) {
23482
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
23483
+ }
23484
+ return new Uint8Array(await data.arrayBuffer());
23485
+ }
23478
23486
  var ContainerFs = class {
23479
23487
  constructor(kernel) {
23480
23488
  this.kernel = kernel;
@@ -23491,10 +23499,12 @@ var ContainerFs = class {
23491
23499
  const abs = clean(path);
23492
23500
  const parent = dirname(abs);
23493
23501
  if (!this.vfs.lexists(parent)) this.vfs.mkdir(parent, { recursive: true, mode: 493 });
23494
- this.vfs.writeFile(abs, data, { privileged: true, mode: opts.mode ?? 420 });
23502
+ const content = typeof data === "string" ? data : await bytesFor(data);
23503
+ this.vfs.writeFile(abs, content, { privileged: true, mode: opts.mode ?? 420 });
23495
23504
  }
23496
23505
  async appendFile(path, data) {
23497
- this.vfs.appendFile(clean(path), data, { privileged: true });
23506
+ const content = typeof data === "string" ? data : await bytesFor(data);
23507
+ this.vfs.appendFile(clean(path), content, { privileged: true });
23498
23508
  }
23499
23509
  async readdir(path, opts) {
23500
23510
  if (opts?.withFileTypes) return this.vfs.readdirWithTypes(clean(path));
@@ -23660,6 +23670,146 @@ var Session = class {
23660
23670
  }
23661
23671
  };
23662
23672
 
23673
+ // src/runtime/node-child-process-bridge.ts
23674
+ var KernelChildProcess = class {
23675
+ pid;
23676
+ command;
23677
+ args;
23678
+ parentPid;
23679
+ state = "running";
23680
+ exitCode;
23681
+ stdout = "";
23682
+ stderr = "";
23683
+ listeners = /* @__PURE__ */ new Map();
23684
+ kernel;
23685
+ cred;
23686
+ cwd;
23687
+ env;
23688
+ stdin = new Pipe();
23689
+ process;
23690
+ started = false;
23691
+ cancelled = false;
23692
+ constructor(kernel, cred, config, pid) {
23693
+ this.kernel = kernel;
23694
+ this.cred = cred;
23695
+ this.pid = pid;
23696
+ this.command = config.command;
23697
+ this.args = config.args?.slice() ?? [];
23698
+ this.parentPid = config.parentPid;
23699
+ this.cwd = config.cwd ?? "/";
23700
+ this.env = { ...config.env };
23701
+ }
23702
+ on(event, listener) {
23703
+ let listeners = this.listeners.get(event);
23704
+ if (!listeners) {
23705
+ listeners = /* @__PURE__ */ new Set();
23706
+ this.listeners.set(event, listeners);
23707
+ }
23708
+ listeners.add(listener);
23709
+ return this;
23710
+ }
23711
+ emit(event, ...args) {
23712
+ for (const listener of this.listeners.get(event) ?? []) listener(...args);
23713
+ }
23714
+ exec() {
23715
+ if (this.started) return;
23716
+ this.started = true;
23717
+ queueMicrotask(() => {
23718
+ if (this.cancelled) {
23719
+ this.finish(143);
23720
+ return;
23721
+ }
23722
+ const stdout = new ChildOutput(this, "stdout");
23723
+ const stderr = new ChildOutput(this, "stderr");
23724
+ try {
23725
+ this.process = this.kernel.spawn([this.command, ...this.args], {
23726
+ cwd: this.cwd,
23727
+ env: this.env,
23728
+ cred: this.cred,
23729
+ stdin: this.stdin,
23730
+ stdout,
23731
+ stderr,
23732
+ ppid: 1
23733
+ });
23734
+ void this.process.wait().then((code) => {
23735
+ stdout.end();
23736
+ stderr.end();
23737
+ this.finish(code);
23738
+ });
23739
+ } catch (error) {
23740
+ stderr.write(error instanceof Error ? error.message : String(error));
23741
+ stderr.end();
23742
+ stdout.end();
23743
+ this.finish(1);
23744
+ }
23745
+ });
23746
+ }
23747
+ sendStdin(data) {
23748
+ try {
23749
+ this.stdin.write(data);
23750
+ } catch {
23751
+ }
23752
+ }
23753
+ kill(signal = "SIGTERM") {
23754
+ if (this.process) {
23755
+ this.process.deliver(signal);
23756
+ return;
23757
+ }
23758
+ this.cancelled = true;
23759
+ }
23760
+ finish(code) {
23761
+ if (this.state === "exited") return;
23762
+ this.state = "exited";
23763
+ this.exitCode = code;
23764
+ this.emit("exit", code);
23765
+ }
23766
+ append(stream, text) {
23767
+ this[stream] += text;
23768
+ this.emit(stream, text);
23769
+ }
23770
+ };
23771
+ var ChildOutput = class {
23772
+ constructor(child, stream) {
23773
+ this.child = child;
23774
+ this.stream = stream;
23775
+ }
23776
+ child;
23777
+ stream;
23778
+ isTTY = false;
23779
+ closedState = false;
23780
+ decoder = new TextDecoder();
23781
+ get closed() {
23782
+ return this.closedState;
23783
+ }
23784
+ write(data) {
23785
+ if (this.closedState) return;
23786
+ const text = typeof data === "string" ? data : this.decoder.decode(data, { stream: true });
23787
+ if (text) this.child.append(this.stream, text);
23788
+ }
23789
+ end() {
23790
+ if (this.closedState) return;
23791
+ this.closedState = true;
23792
+ const tail2 = this.decoder.decode();
23793
+ if (tail2) this.child.append(this.stream, tail2);
23794
+ }
23795
+ };
23796
+ var nextBridgePid = 1073741824;
23797
+ function installNodeChildProcessBridge(pod, kernel, cred) {
23798
+ const manager = pod.processManager;
23799
+ const originalSpawn = manager.spawn;
23800
+ manager.spawn = (config) => {
23801
+ const resolved = kernel.resolveExecutable(config.command, config.cwd ?? "/", config.env ?? {}, cred);
23802
+ if (resolved?.kind === "builtin" && resolved.command?.name !== "node" && resolved.command?.name !== "nodejs") {
23803
+ return new KernelChildProcess(kernel, cred, config, nextBridgePid++);
23804
+ }
23805
+ return originalSpawn.call(manager, config);
23806
+ };
23807
+ return () => {
23808
+ if (manager.spawn === originalSpawn) return;
23809
+ manager.spawn = originalSpawn;
23810
+ };
23811
+ }
23812
+
23663
23813
  // src/container/container.ts
23664
23814
  var Container = class _Container {
23665
23815
  kernel;
@@ -23670,6 +23820,7 @@ var Container = class _Container {
23670
23820
  hooks;
23671
23821
  disposed = false;
23672
23822
  defaultSession = null;
23823
+ restoreNodeChildProcessBridge;
23673
23824
  constructor(kernel, pod, opts) {
23674
23825
  this.kernel = kernel;
23675
23826
  this.pod = pod;
@@ -23698,6 +23849,7 @@ var Container = class _Container {
23698
23849
  };
23699
23850
  if (opts.timeoutMs !== void 0) this.defaults.timeoutMs = opts.timeoutMs;
23700
23851
  this.hooks = { onStdout: opts.onStdout, onStderr: opts.onStderr };
23852
+ this.restoreNodeChildProcessBridge = installNodeChildProcessBridge(pod, kernel, cred);
23701
23853
  }
23702
23854
  // ── boot ──────────────────────────────────────────────────────────────────
23703
23855
  static async create(opts = {}) {
@@ -24108,6 +24260,7 @@ var Container = class _Container {
24108
24260
  dispose() {
24109
24261
  if (this.disposed) return;
24110
24262
  this.disposed = true;
24263
+ this.restoreNodeChildProcessBridge();
24111
24264
  this.kernel.dispose();
24112
24265
  try {
24113
24266
  this.pod.teardown();