@volter/tabnode 0.5.4 → 0.5.6

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.
@@ -6641,6 +6641,14 @@ var asyncHooksShim$1 = /* @__PURE__ */ Object.freeze({
6641
6641
  executionAsyncResource,
6642
6642
  triggerAsyncId
6643
6643
  });
6644
+ function describedIdentity(identity) {
6645
+ const { pid, ppid, argv, cwd, startedAt } = identity;
6646
+ const described = { pid, ppid };
6647
+ if (Array.isArray(argv) && argv.length <= 4096 && argv.every((arg) => typeof arg === "string")) described.argv = Object.freeze([...argv]);
6648
+ if (typeof cwd === "string" && cwd.startsWith("/")) described.cwd = cwd;
6649
+ if (typeof startedAt === "number" && Number.isFinite(startedAt)) described.startedAt = startedAt;
6650
+ return Object.freeze(described);
6651
+ }
6644
6652
  function createProcessRegistryOwner() {
6645
6653
  let nextPid2 = 1e3 + Math.floor(Math.random() * 3e4);
6646
6654
  const live = /* @__PURE__ */ new Map();
@@ -6697,7 +6705,7 @@ function createProcessRegistryOwner() {
6697
6705
  if (identity.ppid !== 0 && !Array.from(runs2.values()).some((parent) => parent.pid === identity.ppid)) {
6698
6706
  throw new Error("Parent process is not owned by this realm.");
6699
6707
  }
6700
- const entry = Object.freeze({ pid: identity.pid, ppid: identity.ppid });
6708
+ const entry = describedIdentity(identity);
6701
6709
  runs2.set(token, entry);
6702
6710
  live.set(entry.pid, entry);
6703
6711
  receivers.set(entry.pid, receiver);
@@ -6739,6 +6747,10 @@ function createProcessRegistryOwner() {
6739
6747
  };
6740
6748
  scopes.set(scope, { allocated, runs: runs2, active: active2 });
6741
6749
  return scope;
6750
+ },
6751
+ /** Every live process of the container, in pid order: what `/proc` lists. */
6752
+ table() {
6753
+ return [...live.values()].sort((a, b) => a.pid - b.pid);
6742
6754
  }
6743
6755
  };
6744
6756
  }
@@ -6779,8 +6791,8 @@ const pidsOfRuns = /* @__PURE__ */ new Map();
6779
6791
  function mintPid() {
6780
6792
  return processRegistry.allocate();
6781
6793
  }
6782
- function setRunPid(token, pid, ppid) {
6783
- processRegistry.publish(token, { pid, ppid });
6794
+ function setRunPid(token, pid, ppid, started) {
6795
+ processRegistry.publish(token, { pid, ppid, ...started, startedAt: Date.now() });
6784
6796
  pidsOfRuns.set(token, { pid, ppid });
6785
6797
  }
6786
6798
  function runPid(token) {
@@ -9657,7 +9669,7 @@ function createUtilBinding(require2) {
9657
9669
  const bufferModule = lazyModule("buffer");
9658
9670
  const Buffer$9 = lazyExport("buffer", "Buffer");
9659
9671
  function createNodeError$1(code2, syscall, path2) {
9660
- const known = ["EEXIST", "EINVAL", "EISDIR", "ENOENT", "ENOTDIR", "ENOTEMPTY", "ELOOP"];
9672
+ const known = ["EEXIST", "EINVAL", "EISDIR", "ENOENT", "ENOTDIR", "ENOTEMPTY", "ELOOP", "EROFS"];
9661
9673
  if (known.includes(code2)) return createNodeError(code2, syscall, path2);
9662
9674
  return Object.assign(new Error(`${code2}: ${syscall} '${path2}'`), { code: code2, syscall, path: path2, errno: -9 });
9663
9675
  }
@@ -27571,14 +27583,16 @@ function createNodeError(code2, syscall, path2, message) {
27571
27583
  ENOTDIR: -20,
27572
27584
  EISDIR: -21,
27573
27585
  EEXIST: -17,
27574
- ENOTEMPTY: -39
27586
+ ENOTEMPTY: -39,
27587
+ EROFS: -30
27575
27588
  };
27576
27589
  const messages2 = {
27577
27590
  ENOENT: "no such file or directory",
27578
27591
  ENOTDIR: "not a directory",
27579
27592
  EISDIR: "is a directory",
27580
27593
  EEXIST: "file already exists",
27581
- ENOTEMPTY: "directory not empty"
27594
+ ENOTEMPTY: "directory not empty",
27595
+ EROFS: "read-only file system"
27582
27596
  };
27583
27597
  const err2 = new Error(
27584
27598
  `${code2}: ${messages2[code2]}, ${syscall} '${path2}'`
@@ -27637,6 +27651,7 @@ class VirtualFS {
27637
27651
  return { files };
27638
27652
  }
27639
27653
  serializeNode(path2, node, files) {
27654
+ if (node.mount) return;
27640
27655
  if (node.type === "file") {
27641
27656
  let content = "";
27642
27657
  if (node.content && node.content.length > 0) {
@@ -27692,6 +27707,7 @@ class VirtualFS {
27692
27707
  */
27693
27708
  writeFileSyncInternal(path2, data2, emitEvent) {
27694
27709
  const normalized = this.normalizePath(path2);
27710
+ this.assertWritable(normalized, "open");
27695
27711
  const parentPath = this.getParentPath(normalized);
27696
27712
  const basename = this.getBasename(normalized);
27697
27713
  if (!basename) {
@@ -27767,11 +27783,12 @@ class VirtualFS {
27767
27783
  if (depth > 40) throw createNodeError("ELOOP", "stat", path2);
27768
27784
  const segments = this.getPathSegments(path2);
27769
27785
  let current3 = this.root;
27786
+ let mounted;
27770
27787
  for (let index2 = 0; index2 < segments.length; index2 += 1) {
27771
- if (current3.type !== "directory" || !current3.children) {
27788
+ if (current3.type !== "directory" || !mounted && !current3.children) {
27772
27789
  return void 0;
27773
27790
  }
27774
- const child = current3.children.get(segments[index2]);
27791
+ const child = mounted ? mounted.tree.node("/" + segments.slice(mounted.at + 1, index2 + 1).join("/")) : current3.children.get(segments[index2]);
27775
27792
  if (!child) {
27776
27793
  return void 0;
27777
27794
  }
@@ -27781,16 +27798,53 @@ class VirtualFS {
27781
27798
  const target = this.__substrateLinkTarget(linkPath, child.target);
27782
27799
  return this.__substrateNode(rest ? target + "/" + rest : target, follow, depth + 1);
27783
27800
  }
27784
- current3 = child;
27801
+ if (!mounted && child.mount) {
27802
+ mounted = { tree: child.mount, at: index2 };
27803
+ current3 = child.mount.node("/") ?? child;
27804
+ } else {
27805
+ current3 = child;
27806
+ }
27785
27807
  }
27786
27808
  return current3;
27787
27809
  }
27810
+ /**
27811
+ * Mount a read-only tree at a directory, as Linux mounts `/proc`: reads
27812
+ * below it are the tree's answers, writes fail with `EROFS`, and a snapshot
27813
+ * leaves it out. Answers the unmount.
27814
+ */
27815
+ mount(path2, tree2) {
27816
+ var _a3;
27817
+ const normalized = this.normalizePath(path2);
27818
+ const basename = this.getBasename(normalized);
27819
+ if (!basename) throw createNodeError("EINVAL", "mount", path2);
27820
+ const parent = this.ensureDirectory(this.getParentPath(normalized));
27821
+ const existing = parent.children.get(basename);
27822
+ if (existing && (existing.type !== "directory" || existing.mount || ((_a3 = existing.children) == null ? void 0 : _a3.size))) {
27823
+ throw createNodeError("EEXIST", "mount", path2);
27824
+ }
27825
+ const node = { type: "directory", children: /* @__PURE__ */ new Map(), mtime: Date.now(), mode: 365, mount: tree2 };
27826
+ parent.children.set(basename, node);
27827
+ return () => {
27828
+ if (parent.children.get(basename) === node) parent.children.delete(basename);
27829
+ };
27830
+ }
27831
+ /** A write at or below a mount point is refused, as a read-only filesystem refuses it. */
27832
+ assertWritable(path2, syscall) {
27833
+ var _a3;
27834
+ let current3 = this.root;
27835
+ for (const segment of this.getPathSegments(path2)) {
27836
+ current3 = (_a3 = current3 == null ? void 0 : current3.children) == null ? void 0 : _a3.get(segment);
27837
+ if (!current3) return;
27838
+ if (current3.mount) throw createNodeError("EROFS", syscall, path2);
27839
+ }
27840
+ }
27788
27841
  /** A link's target as an absolute path: absolute as written, or relative to the link's directory. */
27789
27842
  __substrateLinkTarget(linkPath, target) {
27790
27843
  return this.normalizePath(target.startsWith("/") ? target : this.getParentPath(linkPath) + "/" + target);
27791
27844
  }
27792
27845
  symlinkSync(target, path2) {
27793
27846
  const normalized = this.normalizePath(path2);
27847
+ this.assertWritable(normalized, "symlink");
27794
27848
  const parentPath = this.getParentPath(normalized);
27795
27849
  const basename = this.getBasename(normalized);
27796
27850
  const parent = this.getNode(parentPath);
@@ -27851,11 +27905,13 @@ class VirtualFS {
27851
27905
  * Get stats for path
27852
27906
  */
27853
27907
  chmodSync(path2, mode) {
27908
+ this.assertWritable(path2, "chmod");
27854
27909
  const node = this.getNode(path2);
27855
27910
  if (!node) throw createNodeError("ENOENT", "chmod", path2);
27856
27911
  node.mode = mode & 4095;
27857
27912
  }
27858
27913
  utimesSync(path2, atime, mtime) {
27914
+ this.assertWritable(path2, "utime");
27859
27915
  const node = this.getNode(path2);
27860
27916
  if (!node) throw createNodeError("ENOENT", "utimes", path2);
27861
27917
  node.atime = atime instanceof Date ? atime.getTime() : atime * 1e3;
@@ -27961,7 +28017,10 @@ class VirtualFS {
27961
28017
  * Create directory, optionally with recursive parent creation
27962
28018
  */
27963
28019
  mkdirSync(path2, options) {
28020
+ var _a3;
27964
28021
  const normalized = this.normalizePath(path2);
28022
+ if ((options == null ? void 0 : options.recursive) && ((_a3 = this.getNode(normalized)) == null ? void 0 : _a3.type) === "directory") return;
28023
+ this.assertWritable(normalized, "mkdir");
27965
28024
  if (options == null ? void 0 : options.recursive) {
27966
28025
  this.ensureDirectory(normalized);
27967
28026
  return;
@@ -28006,6 +28065,7 @@ class VirtualFS {
28006
28065
  */
28007
28066
  unlinkSync(path2) {
28008
28067
  const normalized = this.normalizePath(path2);
28068
+ this.assertWritable(normalized, "unlink");
28009
28069
  const parentPath = this.getParentPath(normalized);
28010
28070
  const basename = this.getBasename(normalized);
28011
28071
  const parent = this.getNode(parentPath);
@@ -28028,6 +28088,7 @@ class VirtualFS {
28028
28088
  */
28029
28089
  rmdirSync(path2) {
28030
28090
  const normalized = this.normalizePath(path2);
28091
+ this.assertWritable(normalized, "rmdir");
28031
28092
  const parentPath = this.getParentPath(normalized);
28032
28093
  const basename = this.getBasename(normalized);
28033
28094
  if (!basename) {
@@ -28056,6 +28117,8 @@ class VirtualFS {
28056
28117
  renameSync(oldPath, newPath) {
28057
28118
  const normalizedOld = this.normalizePath(oldPath);
28058
28119
  const normalizedNew = this.normalizePath(newPath);
28120
+ this.assertWritable(normalizedOld, "rename");
28121
+ this.assertWritable(normalizedNew, "rename");
28059
28122
  const oldParentPath = this.getParentPath(normalizedOld);
28060
28123
  const oldBasename = this.getBasename(normalizedOld);
28061
28124
  const newParentPath = this.getParentPath(normalizedNew);
@@ -28154,10 +28217,12 @@ class VirtualFS {
28154
28217
  for (let hops = 0; hops <= 40; hops += 1) {
28155
28218
  const segments = resolved.split("/").filter(Boolean);
28156
28219
  let current3 = this.root;
28220
+ let mounted;
28157
28221
  let linked = false;
28158
28222
  for (let index2 = 0; index2 < segments.length; index2 += 1) {
28159
- const child = current3 && current3.children ? current3.children.get(segments[index2]) : void 0;
28223
+ const child = mounted ? mounted.tree.node("/" + segments.slice(mounted.at + 1, index2 + 1).join("/")) : current3 && current3.children ? current3.children.get(segments[index2]) : void 0;
28160
28224
  if (!child) throw createNodeError("ENOENT", "realpath", path2);
28225
+ if (!mounted && child.mount) mounted = { tree: child.mount, at: index2 };
28161
28226
  if (child.type === "symlink") {
28162
28227
  const linkPath = "/" + segments.slice(0, index2 + 1).join("/");
28163
28228
  const rest = segments.slice(index2 + 1).join("/");
@@ -69753,7 +69818,7 @@ const _runStreams = /* @__PURE__ */ new Map();
69753
69818
  async function runHostedNode(host, launch) {
69754
69819
  var _a3;
69755
69820
  const { token, streams } = launch;
69756
- if (!runPid(token)) setRunPid(token, mintPid(), 0);
69821
+ if (!runPid(token)) setRunPid(token, mintPid(), 0, { argv: ["node", ...launch.argv], cwd: launch.cwd });
69757
69822
  let input;
69758
69823
  try {
69759
69824
  (_a3 = streams == null ? void 0 : streams.signal) == null ? void 0 : _a3.throwIfAborted();
@@ -69989,7 +70054,7 @@ function initChildProcess(vfs2) {
69989
70054
  ...runPid(runToken) ? { pid: runPid(runToken).pid, ppid: runPid(runToken).ppid } : {}
69990
70055
  });
69991
70056
  const proc = runtime2.getProcess();
69992
- if (runToken !== null) setRunPid(runToken, proc.pid, proc.ppid);
70057
+ if (runToken !== null) setRunPid(runToken, proc.pid, proc.ppid, { argv: ["node", ...args], cwd: ctx.cwd });
69993
70058
  const releaseRun = runToken === null ? null : __recordRun(runToken, {
69994
70059
  process: proc,
69995
70060
  stdout: appendStdout,
@@ -70715,7 +70780,12 @@ function startChildRun(request) {
70715
70780
  var _a3;
70716
70781
  const token = `child-${__nextChildRun++}`;
70717
70782
  const pid = mintPid();
70718
- setRunPid(token, pid, ((_a3 = runPid(__currentProcessToken() ?? __lastLaunchedToken)) == null ? void 0 : _a3.pid) ?? 0);
70783
+ setRunPid(
70784
+ token,
70785
+ pid,
70786
+ ((_a3 = runPid(__currentProcessToken() ?? __lastLaunchedToken)) == null ? void 0 : _a3.pid) ?? 0,
70787
+ { argv: request.args.length ? request.args : [request.file], ...request.cwd ? { cwd: request.cwd } : {} }
70788
+ );
70719
70789
  const controller = new AbortController();
70720
70790
  const pendingStdin = [];
70721
70791
  const admittedNode = nodeProcessHostInstalled();
@@ -73997,7 +74067,7 @@ function transformDynamicImportsRegex(code2) {
73997
74067
  return code2.replace(new RegExp("(?<![.$\\w#])import\\s*\\(", "g"), "__dynamicImport(");
73998
74068
  }
73999
74069
  function __substrateRewriteDynamicImportsInScript(code2) {
74000
- if (!new RegExp("(?<![.$\\w#])import\\s*\\(").test(code2)) return code2;
74070
+ if (!new RegExp("(?<![.$\\w#])(?:import|eval)\\s*\\(").test(code2)) return code2;
74001
74071
  let ast;
74002
74072
  try {
74003
74073
  ast = parse3(code2, { ecmaVersion: "latest", sourceType: "script", allowReturnOutsideFunction: true, allowHashBang: true, allowAwaitOutsideFunction: true });
@@ -74006,14 +74076,30 @@ function __substrateRewriteDynamicImportsInScript(code2) {
74006
74076
  }
74007
74077
  const replacements = [];
74008
74078
  walkAst(ast, (node) => {
74009
- if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6]);
74079
+ if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6, "__dynamicImport"]);
74080
+ collectDirectEval(node, replacements);
74010
74081
  });
74011
74082
  if (replacements.length === 0) return code2;
74012
- replacements.sort((a, b) => b[0] - a[0]);
74083
+ return applyReplacements(code2, replacements);
74084
+ }
74085
+ function collectDirectEval(node, replacements) {
74086
+ var _a3, _b3;
74087
+ if (node.type !== "CallExpression" || node.optional || ((_a3 = node.callee) == null ? void 0 : _a3.type) !== "Identifier" || node.callee.name !== "eval") return;
74088
+ const source = (_b3 = node.arguments) == null ? void 0 : _b3[0];
74089
+ if (!source || source.type === "SpreadElement") return;
74090
+ replacements.push([source.start, source.start, "__substrateEvalSource("]);
74091
+ replacements.push([source.end, source.end, ")"]);
74092
+ }
74093
+ function applyReplacements(code2, replacements) {
74094
+ replacements.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
74013
74095
  let out = code2;
74014
- for (const [start, end] of replacements) out = out.slice(0, start) + "__dynamicImport" + out.slice(end);
74096
+ for (const [start, end, text] of replacements) out = out.slice(0, start) + text + out.slice(end);
74015
74097
  return out;
74016
74098
  }
74099
+ Object.defineProperty(globalThis, "__substrateEvalSource", {
74100
+ configurable: true,
74101
+ value: (source) => typeof source === "string" ? __substrateRewriteDynamicImportsInScript(source) : source
74102
+ });
74017
74103
  function transformEsmToCjs(code2, filename) {
74018
74104
  const maybeEsm = __substrateHasEsmSyntax(code2);
74019
74105
  if (!maybeEsm) return __substrateRewriteDynamicImportsInScript(code2);
@@ -74037,17 +74123,14 @@ function transformEsmToCjsAst(code2, filename) {
74037
74123
  if (node.type === "ImportExpression") {
74038
74124
  deepReplacements.push([node.start, node.start + 6, "__dynamicImport"]);
74039
74125
  }
74126
+ collectDirectEval(node, deepReplacements);
74040
74127
  });
74041
74128
  const hasImportDecl = ast.body.some((n8) => n8.type === "ImportDeclaration");
74042
74129
  const hasExportDecl = ast.body.some((n8) => {
74043
74130
  var _a3;
74044
74131
  return (_a3 = n8.type) == null ? void 0 : _a3.startsWith("Export");
74045
74132
  });
74046
- let transformed = code2;
74047
- deepReplacements.sort((a, b) => b[0] - a[0]);
74048
- for (const [start, end, replacement] of deepReplacements) {
74049
- transformed = transformed.slice(0, start) + replacement + transformed.slice(end);
74050
- }
74133
+ let transformed = applyReplacements(code2, deepReplacements);
74051
74134
  if (hasImportDecl || hasExportDecl) {
74052
74135
  transformed = transformEsmToCjsSimple(transformed);
74053
74136
  if (hasExportDecl) {
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  */
10
10
  export { restoreHostGlobals, guestRealmInstalled } from './host-globals';
11
11
  export { VirtualFS } from './virtual-fs';
12
- export type { FSNode, Stats, FSWatcher, WatchListener, WatchEventType } from './virtual-fs';
12
+ export type { FSNode, MountedTree, Stats, FSWatcher, WatchListener, WatchEventType } from './virtual-fs';
13
13
  export { Runtime, execute } from './runtime';
14
14
  export type { Module, RuntimeOptions, RequireFunction } from './runtime';
15
15
  export { createRuntime, WorkerRuntime } from './create-runtime';
@@ -46,7 +46,7 @@ import { ServerBridge } from './server-bridge';
46
46
  import { type Socket as NetSocket } from './node-lib/net-module';
47
47
  import { runPid, processByPid } from './process-tokens';
48
48
  export { runPid, processByPid };
49
- export { createProcessRegistryScope, installProcessRegistry, ownerProcessRegistryScope } from './process-tokens';
49
+ export { createProcessRegistryScope, installProcessRegistry, ownerProcessRegistryScope, ownerProcessTable } from './process-tokens';
50
50
  export { installNodeProcessHost, nodeProcessHostInstalled } from './node-process-host';
51
51
  export type { NodeProcessLaunch, NodeProcessHost } from './node-process-host';
52
52
  export type { ProcessIdentity, ProcessRegistry, ProcessRegistryScope, InitialProcessRegistration } from './process-registry';
@@ -112,6 +112,10 @@ export declare function createContainer(options?: ContainerOptions): {
112
112
  run: (command: string, options?: RunOptions) => Promise<RunResult>;
113
113
  pendingTimers: (token: string) => number;
114
114
  processPorts: (token: string) => number[];
115
+ /** The pid of the process listening on a port of this engine, where a guest process is: `/proc`'s socket owner. */
116
+ portPid: (port: number) => number | undefined;
117
+ /** Deliver a signal to the named run as another process's `kill(pid)` does; false when the run is gone. */
118
+ signalProcess: (token: string, signal: string) => boolean;
115
119
  stopProcess: (token: string) => boolean;
116
120
  /**
117
121
  * Input for one run's guest, by its process token; without a token, the most