@volter/tabnode 0.5.5 → 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.
@@ -74067,7 +74067,7 @@ function transformDynamicImportsRegex(code2) {
74067
74067
  return code2.replace(new RegExp("(?<![.$\\w#])import\\s*\\(", "g"), "__dynamicImport(");
74068
74068
  }
74069
74069
  function __substrateRewriteDynamicImportsInScript(code2) {
74070
- if (!new RegExp("(?<![.$\\w#])import\\s*\\(").test(code2)) return code2;
74070
+ if (!new RegExp("(?<![.$\\w#])(?:import|eval)\\s*\\(").test(code2)) return code2;
74071
74071
  let ast;
74072
74072
  try {
74073
74073
  ast = parse3(code2, { ecmaVersion: "latest", sourceType: "script", allowReturnOutsideFunction: true, allowHashBang: true, allowAwaitOutsideFunction: true });
@@ -74076,14 +74076,30 @@ function __substrateRewriteDynamicImportsInScript(code2) {
74076
74076
  }
74077
74077
  const replacements = [];
74078
74078
  walkAst(ast, (node) => {
74079
- 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);
74080
74081
  });
74081
74082
  if (replacements.length === 0) return code2;
74082
- 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]);
74083
74095
  let out = code2;
74084
- 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);
74085
74097
  return out;
74086
74098
  }
74099
+ Object.defineProperty(globalThis, "__substrateEvalSource", {
74100
+ configurable: true,
74101
+ value: (source) => typeof source === "string" ? __substrateRewriteDynamicImportsInScript(source) : source
74102
+ });
74087
74103
  function transformEsmToCjs(code2, filename) {
74088
74104
  const maybeEsm = __substrateHasEsmSyntax(code2);
74089
74105
  if (!maybeEsm) return __substrateRewriteDynamicImportsInScript(code2);
@@ -74107,17 +74123,14 @@ function transformEsmToCjsAst(code2, filename) {
74107
74123
  if (node.type === "ImportExpression") {
74108
74124
  deepReplacements.push([node.start, node.start + 6, "__dynamicImport"]);
74109
74125
  }
74126
+ collectDirectEval(node, deepReplacements);
74110
74127
  });
74111
74128
  const hasImportDecl = ast.body.some((n8) => n8.type === "ImportDeclaration");
74112
74129
  const hasExportDecl = ast.body.some((n8) => {
74113
74130
  var _a3;
74114
74131
  return (_a3 = n8.type) == null ? void 0 : _a3.startsWith("Export");
74115
74132
  });
74116
- let transformed = code2;
74117
- deepReplacements.sort((a, b) => b[0] - a[0]);
74118
- for (const [start, end, replacement] of deepReplacements) {
74119
- transformed = transformed.slice(0, start) + replacement + transformed.slice(end);
74120
- }
74133
+ let transformed = applyReplacements(code2, deepReplacements);
74121
74134
  if (hasImportDecl || hasExportDecl) {
74122
74135
  transformed = transformEsmToCjsSimple(transformed);
74123
74136
  if (hasExportDecl) {
package/dist/index.mjs CHANGED
@@ -33760,7 +33760,7 @@ function transformDynamicImportsRegex(code2) {
33760
33760
  return code2.replace(new RegExp("(?<![.$\\w#])import\\s*\\(", "g"), "__dynamicImport(");
33761
33761
  }
33762
33762
  function __substrateRewriteDynamicImportsInScript(code2) {
33763
- if (!new RegExp("(?<![.$\\w#])import\\s*\\(").test(code2)) return code2;
33763
+ if (!new RegExp("(?<![.$\\w#])(?:import|eval)\\s*\\(").test(code2)) return code2;
33764
33764
  let ast;
33765
33765
  try {
33766
33766
  ast = parse3(code2, { ecmaVersion: "latest", sourceType: "script", allowReturnOutsideFunction: true, allowHashBang: true, allowAwaitOutsideFunction: true });
@@ -33769,14 +33769,30 @@ function __substrateRewriteDynamicImportsInScript(code2) {
33769
33769
  }
33770
33770
  const replacements = [];
33771
33771
  walkAst(ast, (node) => {
33772
- if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6]);
33772
+ if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6, "__dynamicImport"]);
33773
+ collectDirectEval(node, replacements);
33773
33774
  });
33774
33775
  if (replacements.length === 0) return code2;
33775
- replacements.sort((a, b) => b[0] - a[0]);
33776
+ return applyReplacements(code2, replacements);
33777
+ }
33778
+ function collectDirectEval(node, replacements) {
33779
+ var _a2, _b2;
33780
+ if (node.type !== "CallExpression" || node.optional || ((_a2 = node.callee) == null ? void 0 : _a2.type) !== "Identifier" || node.callee.name !== "eval") return;
33781
+ const source = (_b2 = node.arguments) == null ? void 0 : _b2[0];
33782
+ if (!source || source.type === "SpreadElement") return;
33783
+ replacements.push([source.start, source.start, "__substrateEvalSource("]);
33784
+ replacements.push([source.end, source.end, ")"]);
33785
+ }
33786
+ function applyReplacements(code2, replacements) {
33787
+ replacements.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
33776
33788
  let out = code2;
33777
- for (const [start, end] of replacements) out = out.slice(0, start) + "__dynamicImport" + out.slice(end);
33789
+ for (const [start, end, text] of replacements) out = out.slice(0, start) + text + out.slice(end);
33778
33790
  return out;
33779
33791
  }
33792
+ Object.defineProperty(globalThis, "__substrateEvalSource", {
33793
+ configurable: true,
33794
+ value: (source) => typeof source === "string" ? __substrateRewriteDynamicImportsInScript(source) : source
33795
+ });
33780
33796
  function transformEsmToCjs(code2, filename) {
33781
33797
  const maybeEsm = __substrateHasEsmSyntax(code2);
33782
33798
  if (!maybeEsm) return __substrateRewriteDynamicImportsInScript(code2);
@@ -33800,17 +33816,14 @@ function transformEsmToCjsAst(code2, filename) {
33800
33816
  if (node.type === "ImportExpression") {
33801
33817
  deepReplacements.push([node.start, node.start + 6, "__dynamicImport"]);
33802
33818
  }
33819
+ collectDirectEval(node, deepReplacements);
33803
33820
  });
33804
33821
  const hasImportDecl = ast.body.some((n) => n.type === "ImportDeclaration");
33805
33822
  const hasExportDecl = ast.body.some((n) => {
33806
33823
  var _a2;
33807
33824
  return (_a2 = n.type) == null ? void 0 : _a2.startsWith("Export");
33808
33825
  });
33809
- let transformed = code2;
33810
- deepReplacements.sort((a, b) => b[0] - a[0]);
33811
- for (const [start, end, replacement] of deepReplacements) {
33812
- transformed = transformed.slice(0, start) + replacement + transformed.slice(end);
33813
- }
33826
+ let transformed = applyReplacements(code2, deepReplacements);
33814
33827
  if (hasImportDecl || hasExportDecl) {
33815
33828
  transformed = transformEsmToCjsSimple(transformed);
33816
33829
  if (hasExportDecl) {
@@ -35655,7 +35668,7 @@ class WorkerRuntime {
35655
35668
  this.worker = new Worker(
35656
35669
  new URL(
35657
35670
  /* @vite-ignore */
35658
- "/assets/runtime-worker-iInsmIAS.js",
35671
+ "/assets/runtime-worker-Bt4uLPDa.js",
35659
35672
  import.meta.url
35660
35673
  ),
35661
35674
  { type: "module" }
@@ -38023,7 +38036,11 @@ function resetServerBridge() {
38023
38036
  }
38024
38037
  const scopes = /* @__PURE__ */ new WeakMap();
38025
38038
  class NativeStreamScope {
38026
- constructor(limits, emit2) {
38039
+ /**
38040
+ * `ownerPid` names the process whose worker this scope serves: a listener
38041
+ * it opens is that process's socket, as the container's /proc shows it.
38042
+ */
38043
+ constructor(limits, emit2, ownerPid) {
38027
38044
  __publicField(this, "entries", /* @__PURE__ */ new Map());
38028
38045
  __publicField(this, "descriptors", /* @__PURE__ */ new Map());
38029
38046
  __publicField(this, "writes", /* @__PURE__ */ new Map());
@@ -38033,6 +38050,7 @@ class NativeStreamScope {
38033
38050
  __publicField(this, "disposed", false);
38034
38051
  __publicField(this, "limits");
38035
38052
  this.emit = emit2;
38053
+ this.ownerPid = ownerPid;
38036
38054
  if ([limits.maxHandles, limits.maxReadChunkBytes, limits.maxQueuedBytes, limits.maxQueuedHandles, limits.maxPendingWriteBytes].some((value) => !Number.isSafeInteger(value) || value < 1) || limits.maxReadChunkBytes > 2147483647 || limits.maxReadChunkBytes > limits.maxQueuedBytes || limits.maxReadChunkBytes > limits.maxPendingWriteBytes) throw new Error("Invalid native stream resource limits.");
38037
38055
  this.limits = Object.freeze({ ...limits });
38038
38056
  }
@@ -38317,6 +38335,10 @@ class NativeStreamScope {
38317
38335
  if (failures.length) throw new AggregateError(failures, "Native stream scope cleanup failed.");
38318
38336
  }
38319
38337
  }
38338
+ function nativeStreamOwnerPid(handle) {
38339
+ var _a2, _b2;
38340
+ return (_b2 = (_a2 = scopes.get(handle)) == null ? void 0 : _a2.ownerPid) == null ? void 0 : _b2.call(_a2);
38341
+ }
38320
38342
  let __nextRunName = 1;
38321
38343
  function createContainer(options) {
38322
38344
  const vfs2 = options && options.vfs || new VirtualFS();
@@ -38374,7 +38396,8 @@ function createContainer(options) {
38374
38396
  portPid: (port) => {
38375
38397
  var _a2;
38376
38398
  const listener = listenerOnPort(port);
38377
- return listener ? (_a2 = runPid(ownerOf(listener))) == null ? void 0 : _a2.pid : void 0;
38399
+ if (!listener) return void 0;
38400
+ return ((_a2 = runPid(ownerOf(listener))) == null ? void 0 : _a2.pid) ?? nativeStreamOwnerPid(listener);
38378
38401
  },
38379
38402
  /**
38380
38403
  * Deliver a signal to the named run as another process's `kill(pid)` does:
@@ -94,6 +94,7 @@ export interface NativeStreamTransport {
94
94
  */
95
95
  export declare class NativeStreamScope {
96
96
  private readonly emit;
97
+ readonly ownerPid?: (() => number | undefined) | undefined;
97
98
  private readonly entries;
98
99
  private readonly descriptors;
99
100
  private readonly writes;
@@ -102,7 +103,11 @@ export declare class NativeStreamScope {
102
103
  private pendingWriteBytes;
103
104
  private disposed;
104
105
  private readonly limits;
105
- constructor(limits: NativeStreamLimits, emit: (event: NativeStreamEvent) => void);
106
+ /**
107
+ * `ownerPid` names the process whose worker this scope serves: a listener
108
+ * it opens is that process's socket, as the container's /proc shows it.
109
+ */
110
+ constructor(limits: NativeStreamLimits, emit: (event: NativeStreamEvent) => void, ownerPid?: (() => number | undefined) | undefined);
106
111
  private entry;
107
112
  private publish;
108
113
  private claim;
@@ -119,3 +124,5 @@ export declare class NativeStreamScope {
119
124
  private close;
120
125
  dispose(): void;
121
126
  }
127
+ /** The process a handle opened for another worker's process belongs to, where a scope holds it. */
128
+ export declare function nativeStreamOwnerPid(handle: object): number | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/tabnode",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "Node's own library, in a browser tab.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -56,6 +56,7 @@ import { runCommand, registerRunStreams, releaseRunStreams, sendStdin } from './
56
56
  import { Server as NetServer, __releaseOwnedHandles, type Socket as NetSocket } from './node-lib/net-module';
57
57
  import { __adoptHandle, ownerOf, type OwnedHandle } from './node-lib/binding/handles';
58
58
  import { listenerOnPort } from './node-lib/binding/tcp_wrap';
59
+ import { nativeStreamOwnerPid } from './native-stream-owner';
59
60
 
60
61
  import { __currentProcessToken, __runFor, __signalOwnedProcess, __stopOwnedProcess, runPid, processByPid } from './process-tokens';
61
62
  export { runPid, processByPid };
@@ -215,7 +216,9 @@ export function createContainer(options?: ContainerOptions): {
215
216
  processPorts: (token: string): number[] => __ownedServerPorts(token),
216
217
  portPid: (port: number): number | undefined => {
217
218
  const listener = listenerOnPort(port);
218
- return listener ? runPid(ownerOf(listener as unknown as OwnedHandle))?.pid : undefined;
219
+ if (!listener) return undefined;
220
+ // a guest's own listener, or one this engine holds for another worker's process
221
+ return runPid(ownerOf(listener as unknown as OwnedHandle))?.pid ?? nativeStreamOwnerPid(listener);
219
222
  },
220
223
  /**
221
224
  * Deliver a signal to the named run as another process's `kill(pid)` does:
@@ -56,7 +56,11 @@ export class NativeStreamScope {
56
56
  private disposed = false;
57
57
  private readonly limits: Readonly<NativeStreamLimits>;
58
58
 
59
- constructor(limits: NativeStreamLimits, private readonly emit: (event: NativeStreamEvent) => void) {
59
+ /**
60
+ * `ownerPid` names the process whose worker this scope serves: a listener
61
+ * it opens is that process's socket, as the container's /proc shows it.
62
+ */
63
+ constructor(limits: NativeStreamLimits, private readonly emit: (event: NativeStreamEvent) => void, readonly ownerPid?: () => number | undefined) {
60
64
  if ([limits.maxHandles, limits.maxReadChunkBytes, limits.maxQueuedBytes, limits.maxQueuedHandles, limits.maxPendingWriteBytes].some(value => !Number.isSafeInteger(value) || value < 1)
61
65
  || limits.maxReadChunkBytes > 0x7fffffff
62
66
  || limits.maxReadChunkBytes > limits.maxQueuedBytes
@@ -315,3 +319,8 @@ export class NativeStreamScope {
315
319
  if (failures.length) throw new AggregateError(failures, 'Native stream scope cleanup failed.');
316
320
  }
317
321
  }
322
+
323
+ /** The process a handle opened for another worker's process belongs to, where a scope holds it. */
324
+ export function nativeStreamOwnerPid(handle: object): number | undefined {
325
+ return scopes.get(handle as NativeHandle)?.ownerPid?.();
326
+ }
package/src/runtime.ts CHANGED
@@ -343,23 +343,49 @@ function transformDynamicImportsRegex(code: string): string {
343
343
  * saw no import at all.
344
344
  */
345
345
  function __substrateRewriteDynamicImportsInScript(code: string): string {
346
- if (!/(?<![.$\w#])import\s*\(/.test(code)) return code;
346
+ if (!/(?<![.$\w#])(?:import|eval)\s*\(/.test(code)) return code;
347
347
  let ast;
348
348
  try {
349
349
  ast = acorn.parse(code, { ecmaVersion: "latest", sourceType: "script", allowReturnOutsideFunction: true, allowHashBang: true, allowAwaitOutsideFunction: true });
350
350
  } catch {
351
351
  return code;
352
352
  }
353
- const replacements: Array<[number, number]> = [];
353
+ const replacements: Array<[number, number, string]> = [];
354
354
  walkAst(ast, (node: any) => {
355
- if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6]);
355
+ if (node.type === "ImportExpression") replacements.push([node.start, node.start + 6, "__dynamicImport"]);
356
+ collectDirectEval(node, replacements);
356
357
  });
357
358
  if (replacements.length === 0) return code;
358
- replacements.sort((a, b) => b[0] - a[0]);
359
+ return applyReplacements(code, replacements);
360
+ }
361
+
362
+ /**
363
+ * A direct `eval` runs source the module builds at run time, and Node runs an
364
+ * `import()` in it through the module's loader: Playwright loads an ES config
365
+ * with ``eval(`import(${url})`)``. The call stays a direct eval, so the
366
+ * source keeps the module's scope, `__dynamicImport` included; only the
367
+ * source it is given is rewritten the way the module's own was.
368
+ */
369
+ function collectDirectEval(node: any, replacements: Array<[number, number, string]>): void {
370
+ if (node.type !== "CallExpression" || node.optional || node.callee?.type !== "Identifier" || node.callee.name !== "eval") return;
371
+ const source = node.arguments?.[0];
372
+ if (!source || source.type === "SpreadElement") return;
373
+ replacements.push([source.start, source.start, "__substrateEvalSource("]);
374
+ replacements.push([source.end, source.end, ")"]);
375
+ }
376
+
377
+ /** Applies insertions and replacements from the end, so earlier offsets hold. */
378
+ function applyReplacements(code: string, replacements: Array<[number, number, string]>): string {
379
+ replacements.sort((a, b) => b[0] - a[0] || b[1] - a[1]);
359
380
  let out = code;
360
- for (const [start, end] of replacements) out = out.slice(0, start) + "__dynamicImport" + out.slice(end);
381
+ for (const [start, end, text] of replacements) out = out.slice(0, start) + text + out.slice(end);
361
382
  return out;
362
383
  }
384
+
385
+ Object.defineProperty(globalThis, "__substrateEvalSource", {
386
+ configurable: true,
387
+ value: (source: unknown): unknown => typeof source === "string" ? __substrateRewriteDynamicImportsInScript(source) : source,
388
+ });
363
389
  function transformEsmToCjs(code: string, filename: string): string {
364
390
  // Quick check: does the code have any ESM-like patterns?
365
391
  const maybeEsm = __substrateHasEsmSyntax(code);
@@ -401,6 +427,7 @@ function transformEsmToCjsAst(code: string, filename: string): string {
401
427
  // Replace just the 'import' keyword, preserving the (...) part
402
428
  deepReplacements.push([node.start, node.start + 6, '__dynamicImport']);
403
429
  }
430
+ collectDirectEval(node, deepReplacements);
404
431
  });
405
432
 
406
433
  // Check for actual import/export declarations
@@ -408,11 +435,7 @@ function transformEsmToCjsAst(code: string, filename: string): string {
408
435
  const hasExportDecl = ast.body.some((n: any) => n.type?.startsWith('Export'));
409
436
 
410
437
  // Apply deep replacements from end to start (preserves earlier positions)
411
- let transformed = code;
412
- deepReplacements.sort((a, b) => b[0] - a[0]);
413
- for (const [start, end, replacement] of deepReplacements) {
414
- transformed = transformed.slice(0, start) + replacement + transformed.slice(end);
415
- }
438
+ let transformed = applyReplacements(code, deepReplacements);
416
439
 
417
440
  // Transform import/export declarations (re-parses the modified code)
418
441
  if (hasImportDecl || hasExportDecl) {