@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.
- package/dist/assets/{runtime-worker-DBtzjAkn.js → runtime-worker-Bt4uLPDa.js} +105 -22
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +155 -28
- package/dist/native-stream-owner.d.ts +8 -1
- package/dist/process-registry.d.ts +7 -0
- package/dist/process-tokens.d.ts +15 -2
- package/dist/virtual-fs.d.ts +25 -1
- package/package.json +1 -1
- package/src/index.ts +21 -4
- package/src/native-stream-owner.ts +10 -1
- package/src/node-lib/binding/fs.ts +1 -1
- package/src/process-registry.ts +22 -2
- package/src/process-tokens.ts +30 -3
- package/src/runtime.ts +33 -10
- package/src/shims/child_process.ts +4 -3
- package/src/virtual-fs.ts +77 -5
package/dist/index.mjs
CHANGED
|
@@ -6350,6 +6350,14 @@ const asyncHooksShim$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
6350
6350
|
executionAsyncResource,
|
|
6351
6351
|
triggerAsyncId
|
|
6352
6352
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
6353
|
+
function describedIdentity(identity) {
|
|
6354
|
+
const { pid, ppid, argv, cwd, startedAt } = identity;
|
|
6355
|
+
const described = { pid, ppid };
|
|
6356
|
+
if (Array.isArray(argv) && argv.length <= 4096 && argv.every((arg) => typeof arg === "string")) described.argv = Object.freeze([...argv]);
|
|
6357
|
+
if (typeof cwd === "string" && cwd.startsWith("/")) described.cwd = cwd;
|
|
6358
|
+
if (typeof startedAt === "number" && Number.isFinite(startedAt)) described.startedAt = startedAt;
|
|
6359
|
+
return Object.freeze(described);
|
|
6360
|
+
}
|
|
6353
6361
|
function createProcessRegistryOwner() {
|
|
6354
6362
|
let nextPid2 = 1e3 + Math.floor(Math.random() * 3e4);
|
|
6355
6363
|
const live = /* @__PURE__ */ new Map();
|
|
@@ -6406,7 +6414,7 @@ function createProcessRegistryOwner() {
|
|
|
6406
6414
|
if (identity.ppid !== 0 && !Array.from(runs2.values()).some((parent) => parent.pid === identity.ppid)) {
|
|
6407
6415
|
throw new Error("Parent process is not owned by this realm.");
|
|
6408
6416
|
}
|
|
6409
|
-
const entry =
|
|
6417
|
+
const entry = describedIdentity(identity);
|
|
6410
6418
|
runs2.set(token, entry);
|
|
6411
6419
|
live.set(entry.pid, entry);
|
|
6412
6420
|
receivers.set(entry.pid, receiver);
|
|
@@ -6448,6 +6456,10 @@ function createProcessRegistryOwner() {
|
|
|
6448
6456
|
};
|
|
6449
6457
|
scopes2.set(scope, { allocated: allocated2, runs: runs2, active: active2 });
|
|
6450
6458
|
return scope;
|
|
6459
|
+
},
|
|
6460
|
+
/** Every live process of the container, in pid order: what `/proc` lists. */
|
|
6461
|
+
table() {
|
|
6462
|
+
return [...live.values()].sort((a, b) => a.pid - b.pid);
|
|
6451
6463
|
}
|
|
6452
6464
|
};
|
|
6453
6465
|
}
|
|
@@ -6485,6 +6497,18 @@ function __stopOwnedProcess(token) {
|
|
|
6485
6497
|
var _a2;
|
|
6486
6498
|
(_a2 = runs.get(token)) == null ? void 0 : _a2.stopTimers();
|
|
6487
6499
|
}
|
|
6500
|
+
function __signalOwnedProcess(token, signal) {
|
|
6501
|
+
const run = runs.get(token);
|
|
6502
|
+
if (!run) return false;
|
|
6503
|
+
const guest = run.process;
|
|
6504
|
+
try {
|
|
6505
|
+
enterRun(token, () => guest.kill(guest.pid, signal));
|
|
6506
|
+
} catch (error) {
|
|
6507
|
+
if (error instanceof Error && error.message.startsWith("Process exited with code")) return true;
|
|
6508
|
+
return false;
|
|
6509
|
+
}
|
|
6510
|
+
return true;
|
|
6511
|
+
}
|
|
6488
6512
|
const processRegistryOwner = createProcessRegistryOwner();
|
|
6489
6513
|
let processRegistry = processRegistryOwner.createScope();
|
|
6490
6514
|
let registryInstalled = false;
|
|
@@ -6494,6 +6518,10 @@ function createProcessRegistryScope() {
|
|
|
6494
6518
|
if (registryInstalled) throw new Error("Only the container owner can create process registry scopes.");
|
|
6495
6519
|
return processRegistryOwner.createScope();
|
|
6496
6520
|
}
|
|
6521
|
+
function ownerProcessTable() {
|
|
6522
|
+
if (registryInstalled) throw new Error("This realm is a process registry client, not the container owner.");
|
|
6523
|
+
return processRegistryOwner.table();
|
|
6524
|
+
}
|
|
6497
6525
|
function ownerProcessRegistryScope() {
|
|
6498
6526
|
if (registryInstalled) throw new Error("This realm is a process registry client, not the container owner.");
|
|
6499
6527
|
return processRegistry;
|
|
@@ -6513,9 +6541,9 @@ function mintPid() {
|
|
|
6513
6541
|
registryUsed = true;
|
|
6514
6542
|
return processRegistry.allocate();
|
|
6515
6543
|
}
|
|
6516
|
-
function setRunPid(token, pid, ppid) {
|
|
6544
|
+
function setRunPid(token, pid, ppid, started2) {
|
|
6517
6545
|
registryUsed = true;
|
|
6518
|
-
processRegistry.publish(token, { pid, ppid });
|
|
6546
|
+
processRegistry.publish(token, { pid, ppid, ...started2, startedAt: Date.now() });
|
|
6519
6547
|
pidsOfRuns.set(token, { pid, ppid });
|
|
6520
6548
|
}
|
|
6521
6549
|
function runPid(token) {
|
|
@@ -9804,7 +9832,7 @@ function createUtilBinding(require2) {
|
|
|
9804
9832
|
const bufferModule = lazyModule("buffer");
|
|
9805
9833
|
const Buffer$9 = lazyExport("buffer", "Buffer");
|
|
9806
9834
|
function createNodeError$1(code2, syscall, path2) {
|
|
9807
|
-
const known = ["EEXIST", "EINVAL", "EISDIR", "ENOENT", "ENOTDIR", "ENOTEMPTY", "ELOOP"];
|
|
9835
|
+
const known = ["EEXIST", "EINVAL", "EISDIR", "ENOENT", "ENOTDIR", "ENOTEMPTY", "ELOOP", "EROFS"];
|
|
9808
9836
|
if (known.includes(code2)) return createNodeError(code2, syscall, path2);
|
|
9809
9837
|
return Object.assign(new Error(`${code2}: ${syscall} '${path2}'`), { code: code2, syscall, path: path2, errno: -9 });
|
|
9810
9838
|
}
|
|
@@ -17762,10 +17790,17 @@ var implementation$1 = function bind2(that) {
|
|
|
17762
17790
|
var implementation = implementation$1;
|
|
17763
17791
|
var functionBind = Function.prototype.bind || implementation;
|
|
17764
17792
|
var functionCall = Function.prototype.call;
|
|
17765
|
-
var functionApply
|
|
17793
|
+
var functionApply;
|
|
17794
|
+
var hasRequiredFunctionApply;
|
|
17795
|
+
function requireFunctionApply() {
|
|
17796
|
+
if (hasRequiredFunctionApply) return functionApply;
|
|
17797
|
+
hasRequiredFunctionApply = 1;
|
|
17798
|
+
functionApply = Function.prototype.apply;
|
|
17799
|
+
return functionApply;
|
|
17800
|
+
}
|
|
17766
17801
|
var reflectApply = typeof Reflect !== "undefined" && Reflect && Reflect.apply;
|
|
17767
17802
|
var bind$2 = functionBind;
|
|
17768
|
-
var $apply$1 =
|
|
17803
|
+
var $apply$1 = requireFunctionApply();
|
|
17769
17804
|
var $call$2 = functionCall;
|
|
17770
17805
|
var $reflectApply = reflectApply;
|
|
17771
17806
|
var actualApply = $reflectApply || bind$2.call($call$2, $apply$1);
|
|
@@ -17885,7 +17920,7 @@ var hasSymbols = requireHasSymbols()();
|
|
|
17885
17920
|
var getProto = requireGetProto();
|
|
17886
17921
|
var $ObjectGPO = requireObject_getPrototypeOf();
|
|
17887
17922
|
var $ReflectGPO = requireReflect_getPrototypeOf();
|
|
17888
|
-
var $apply =
|
|
17923
|
+
var $apply = requireFunctionApply();
|
|
17889
17924
|
var $call = functionCall;
|
|
17890
17925
|
var needsEval = {};
|
|
17891
17926
|
var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined$1 : getProto(Uint8Array);
|
|
@@ -18526,7 +18561,7 @@ function requireApplyBind() {
|
|
|
18526
18561
|
if (hasRequiredApplyBind) return applyBind;
|
|
18527
18562
|
hasRequiredApplyBind = 1;
|
|
18528
18563
|
var bind3 = functionBind;
|
|
18529
|
-
var $apply2 =
|
|
18564
|
+
var $apply2 = requireFunctionApply();
|
|
18530
18565
|
var actualApply$1 = actualApply;
|
|
18531
18566
|
applyBind = function applyBind2() {
|
|
18532
18567
|
return actualApply$1(bind3, $apply2, arguments);
|
|
@@ -27737,14 +27772,16 @@ function createNodeError(code2, syscall, path2, message) {
|
|
|
27737
27772
|
ENOTDIR: -20,
|
|
27738
27773
|
EISDIR: -21,
|
|
27739
27774
|
EEXIST: -17,
|
|
27740
|
-
ENOTEMPTY: -39
|
|
27775
|
+
ENOTEMPTY: -39,
|
|
27776
|
+
EROFS: -30
|
|
27741
27777
|
};
|
|
27742
27778
|
const messages2 = {
|
|
27743
27779
|
ENOENT: "no such file or directory",
|
|
27744
27780
|
ENOTDIR: "not a directory",
|
|
27745
27781
|
EISDIR: "is a directory",
|
|
27746
27782
|
EEXIST: "file already exists",
|
|
27747
|
-
ENOTEMPTY: "directory not empty"
|
|
27783
|
+
ENOTEMPTY: "directory not empty",
|
|
27784
|
+
EROFS: "read-only file system"
|
|
27748
27785
|
};
|
|
27749
27786
|
const err2 = new Error(
|
|
27750
27787
|
`${code2}: ${messages2[code2]}, ${syscall} '${path2}'`
|
|
@@ -27803,6 +27840,7 @@ class VirtualFS {
|
|
|
27803
27840
|
return { files };
|
|
27804
27841
|
}
|
|
27805
27842
|
serializeNode(path2, node, files) {
|
|
27843
|
+
if (node.mount) return;
|
|
27806
27844
|
if (node.type === "file") {
|
|
27807
27845
|
let content = "";
|
|
27808
27846
|
if (node.content && node.content.length > 0) {
|
|
@@ -27858,6 +27896,7 @@ class VirtualFS {
|
|
|
27858
27896
|
*/
|
|
27859
27897
|
writeFileSyncInternal(path2, data2, emitEvent) {
|
|
27860
27898
|
const normalized = this.normalizePath(path2);
|
|
27899
|
+
this.assertWritable(normalized, "open");
|
|
27861
27900
|
const parentPath = this.getParentPath(normalized);
|
|
27862
27901
|
const basename2 = this.getBasename(normalized);
|
|
27863
27902
|
if (!basename2) {
|
|
@@ -27933,11 +27972,12 @@ class VirtualFS {
|
|
|
27933
27972
|
if (depth > 40) throw createNodeError("ELOOP", "stat", path2);
|
|
27934
27973
|
const segments = this.getPathSegments(path2);
|
|
27935
27974
|
let current3 = this.root;
|
|
27975
|
+
let mounted;
|
|
27936
27976
|
for (let index2 = 0; index2 < segments.length; index2 += 1) {
|
|
27937
|
-
if (current3.type !== "directory" || !current3.children) {
|
|
27977
|
+
if (current3.type !== "directory" || !mounted && !current3.children) {
|
|
27938
27978
|
return void 0;
|
|
27939
27979
|
}
|
|
27940
|
-
const child = current3.children.get(segments[index2]);
|
|
27980
|
+
const child = mounted ? mounted.tree.node("/" + segments.slice(mounted.at + 1, index2 + 1).join("/")) : current3.children.get(segments[index2]);
|
|
27941
27981
|
if (!child) {
|
|
27942
27982
|
return void 0;
|
|
27943
27983
|
}
|
|
@@ -27947,16 +27987,53 @@ class VirtualFS {
|
|
|
27947
27987
|
const target = this.__substrateLinkTarget(linkPath, child.target);
|
|
27948
27988
|
return this.__substrateNode(rest ? target + "/" + rest : target, follow, depth + 1);
|
|
27949
27989
|
}
|
|
27950
|
-
|
|
27990
|
+
if (!mounted && child.mount) {
|
|
27991
|
+
mounted = { tree: child.mount, at: index2 };
|
|
27992
|
+
current3 = child.mount.node("/") ?? child;
|
|
27993
|
+
} else {
|
|
27994
|
+
current3 = child;
|
|
27995
|
+
}
|
|
27951
27996
|
}
|
|
27952
27997
|
return current3;
|
|
27953
27998
|
}
|
|
27999
|
+
/**
|
|
28000
|
+
* Mount a read-only tree at a directory, as Linux mounts `/proc`: reads
|
|
28001
|
+
* below it are the tree's answers, writes fail with `EROFS`, and a snapshot
|
|
28002
|
+
* leaves it out. Answers the unmount.
|
|
28003
|
+
*/
|
|
28004
|
+
mount(path2, tree2) {
|
|
28005
|
+
var _a2;
|
|
28006
|
+
const normalized = this.normalizePath(path2);
|
|
28007
|
+
const basename2 = this.getBasename(normalized);
|
|
28008
|
+
if (!basename2) throw createNodeError("EINVAL", "mount", path2);
|
|
28009
|
+
const parent = this.ensureDirectory(this.getParentPath(normalized));
|
|
28010
|
+
const existing = parent.children.get(basename2);
|
|
28011
|
+
if (existing && (existing.type !== "directory" || existing.mount || ((_a2 = existing.children) == null ? void 0 : _a2.size))) {
|
|
28012
|
+
throw createNodeError("EEXIST", "mount", path2);
|
|
28013
|
+
}
|
|
28014
|
+
const node = { type: "directory", children: /* @__PURE__ */ new Map(), mtime: Date.now(), mode: 365, mount: tree2 };
|
|
28015
|
+
parent.children.set(basename2, node);
|
|
28016
|
+
return () => {
|
|
28017
|
+
if (parent.children.get(basename2) === node) parent.children.delete(basename2);
|
|
28018
|
+
};
|
|
28019
|
+
}
|
|
28020
|
+
/** A write at or below a mount point is refused, as a read-only filesystem refuses it. */
|
|
28021
|
+
assertWritable(path2, syscall) {
|
|
28022
|
+
var _a2;
|
|
28023
|
+
let current3 = this.root;
|
|
28024
|
+
for (const segment of this.getPathSegments(path2)) {
|
|
28025
|
+
current3 = (_a2 = current3 == null ? void 0 : current3.children) == null ? void 0 : _a2.get(segment);
|
|
28026
|
+
if (!current3) return;
|
|
28027
|
+
if (current3.mount) throw createNodeError("EROFS", syscall, path2);
|
|
28028
|
+
}
|
|
28029
|
+
}
|
|
27954
28030
|
/** A link's target as an absolute path: absolute as written, or relative to the link's directory. */
|
|
27955
28031
|
__substrateLinkTarget(linkPath, target) {
|
|
27956
28032
|
return this.normalizePath(target.startsWith("/") ? target : this.getParentPath(linkPath) + "/" + target);
|
|
27957
28033
|
}
|
|
27958
28034
|
symlinkSync(target, path2) {
|
|
27959
28035
|
const normalized = this.normalizePath(path2);
|
|
28036
|
+
this.assertWritable(normalized, "symlink");
|
|
27960
28037
|
const parentPath = this.getParentPath(normalized);
|
|
27961
28038
|
const basename2 = this.getBasename(normalized);
|
|
27962
28039
|
const parent = this.getNode(parentPath);
|
|
@@ -28017,11 +28094,13 @@ class VirtualFS {
|
|
|
28017
28094
|
* Get stats for path
|
|
28018
28095
|
*/
|
|
28019
28096
|
chmodSync(path2, mode) {
|
|
28097
|
+
this.assertWritable(path2, "chmod");
|
|
28020
28098
|
const node = this.getNode(path2);
|
|
28021
28099
|
if (!node) throw createNodeError("ENOENT", "chmod", path2);
|
|
28022
28100
|
node.mode = mode & 4095;
|
|
28023
28101
|
}
|
|
28024
28102
|
utimesSync(path2, atime, mtime) {
|
|
28103
|
+
this.assertWritable(path2, "utime");
|
|
28025
28104
|
const node = this.getNode(path2);
|
|
28026
28105
|
if (!node) throw createNodeError("ENOENT", "utimes", path2);
|
|
28027
28106
|
node.atime = atime instanceof Date ? atime.getTime() : atime * 1e3;
|
|
@@ -28127,7 +28206,10 @@ class VirtualFS {
|
|
|
28127
28206
|
* Create directory, optionally with recursive parent creation
|
|
28128
28207
|
*/
|
|
28129
28208
|
mkdirSync(path2, options) {
|
|
28209
|
+
var _a2;
|
|
28130
28210
|
const normalized = this.normalizePath(path2);
|
|
28211
|
+
if ((options == null ? void 0 : options.recursive) && ((_a2 = this.getNode(normalized)) == null ? void 0 : _a2.type) === "directory") return;
|
|
28212
|
+
this.assertWritable(normalized, "mkdir");
|
|
28131
28213
|
if (options == null ? void 0 : options.recursive) {
|
|
28132
28214
|
this.ensureDirectory(normalized);
|
|
28133
28215
|
return;
|
|
@@ -28172,6 +28254,7 @@ class VirtualFS {
|
|
|
28172
28254
|
*/
|
|
28173
28255
|
unlinkSync(path2) {
|
|
28174
28256
|
const normalized = this.normalizePath(path2);
|
|
28257
|
+
this.assertWritable(normalized, "unlink");
|
|
28175
28258
|
const parentPath = this.getParentPath(normalized);
|
|
28176
28259
|
const basename2 = this.getBasename(normalized);
|
|
28177
28260
|
const parent = this.getNode(parentPath);
|
|
@@ -28194,6 +28277,7 @@ class VirtualFS {
|
|
|
28194
28277
|
*/
|
|
28195
28278
|
rmdirSync(path2) {
|
|
28196
28279
|
const normalized = this.normalizePath(path2);
|
|
28280
|
+
this.assertWritable(normalized, "rmdir");
|
|
28197
28281
|
const parentPath = this.getParentPath(normalized);
|
|
28198
28282
|
const basename2 = this.getBasename(normalized);
|
|
28199
28283
|
if (!basename2) {
|
|
@@ -28222,6 +28306,8 @@ class VirtualFS {
|
|
|
28222
28306
|
renameSync(oldPath, newPath) {
|
|
28223
28307
|
const normalizedOld = this.normalizePath(oldPath);
|
|
28224
28308
|
const normalizedNew = this.normalizePath(newPath);
|
|
28309
|
+
this.assertWritable(normalizedOld, "rename");
|
|
28310
|
+
this.assertWritable(normalizedNew, "rename");
|
|
28225
28311
|
const oldParentPath = this.getParentPath(normalizedOld);
|
|
28226
28312
|
const oldBasename = this.getBasename(normalizedOld);
|
|
28227
28313
|
const newParentPath = this.getParentPath(normalizedNew);
|
|
@@ -28320,10 +28406,12 @@ class VirtualFS {
|
|
|
28320
28406
|
for (let hops = 0; hops <= 40; hops += 1) {
|
|
28321
28407
|
const segments = resolved.split("/").filter(Boolean);
|
|
28322
28408
|
let current3 = this.root;
|
|
28409
|
+
let mounted;
|
|
28323
28410
|
let linked = false;
|
|
28324
28411
|
for (let index2 = 0; index2 < segments.length; index2 += 1) {
|
|
28325
|
-
const child = current3 && current3.children ? current3.children.get(segments[index2]) : void 0;
|
|
28412
|
+
const child = mounted ? mounted.tree.node("/" + segments.slice(mounted.at + 1, index2 + 1).join("/")) : current3 && current3.children ? current3.children.get(segments[index2]) : void 0;
|
|
28326
28413
|
if (!child) throw createNodeError("ENOENT", "realpath", path2);
|
|
28414
|
+
if (!mounted && child.mount) mounted = { tree: child.mount, at: index2 };
|
|
28327
28415
|
if (child.type === "symlink") {
|
|
28328
28416
|
const linkPath = "/" + segments.slice(0, index2 + 1).join("/");
|
|
28329
28417
|
const rest = segments.slice(index2 + 1).join("/");
|
|
@@ -29379,7 +29467,7 @@ const _runStreams = /* @__PURE__ */ new Map();
|
|
|
29379
29467
|
async function runHostedNode(host2, launch) {
|
|
29380
29468
|
var _a2;
|
|
29381
29469
|
const { token, streams } = launch;
|
|
29382
|
-
if (!runPid(token)) setRunPid(token, mintPid(), 0);
|
|
29470
|
+
if (!runPid(token)) setRunPid(token, mintPid(), 0, { argv: ["node", ...launch.argv], cwd: launch.cwd });
|
|
29383
29471
|
let input;
|
|
29384
29472
|
try {
|
|
29385
29473
|
(_a2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _a2.throwIfAborted();
|
|
@@ -29638,7 +29726,7 @@ function initChildProcess(vfs2) {
|
|
|
29638
29726
|
...runPid(runToken) ? { pid: runPid(runToken).pid, ppid: runPid(runToken).ppid } : {}
|
|
29639
29727
|
});
|
|
29640
29728
|
const proc = runtime.getProcess();
|
|
29641
|
-
if (runToken !== null) setRunPid(runToken, proc.pid, proc.ppid);
|
|
29729
|
+
if (runToken !== null) setRunPid(runToken, proc.pid, proc.ppid, { argv: ["node", ...args], cwd: ctx.cwd });
|
|
29642
29730
|
const releaseRun = runToken === null ? null : __recordRun(runToken, {
|
|
29643
29731
|
process: proc,
|
|
29644
29732
|
stdout: appendStdout,
|
|
@@ -30384,7 +30472,12 @@ function startChildRun(request) {
|
|
|
30384
30472
|
var _a2;
|
|
30385
30473
|
const token = `child-${__nextChildRun++}`;
|
|
30386
30474
|
const pid = mintPid();
|
|
30387
|
-
setRunPid(
|
|
30475
|
+
setRunPid(
|
|
30476
|
+
token,
|
|
30477
|
+
pid,
|
|
30478
|
+
((_a2 = runPid(nodeProcessRealmToken() ?? __currentProcessToken() ?? __lastLaunchedToken)) == null ? void 0 : _a2.pid) ?? 0,
|
|
30479
|
+
{ argv: request.args.length ? request.args : [request.file], ...request.cwd ? { cwd: request.cwd } : {} }
|
|
30480
|
+
);
|
|
30388
30481
|
const controller = new AbortController();
|
|
30389
30482
|
const pendingStdin = [];
|
|
30390
30483
|
const admittedNode = nodeProcessHostInstalled() && engineProgramFor(request.file, request.cwd) === "node";
|
|
@@ -33667,7 +33760,7 @@ function transformDynamicImportsRegex(code2) {
|
|
|
33667
33760
|
return code2.replace(new RegExp("(?<![.$\\w#])import\\s*\\(", "g"), "__dynamicImport(");
|
|
33668
33761
|
}
|
|
33669
33762
|
function __substrateRewriteDynamicImportsInScript(code2) {
|
|
33670
|
-
if (!new RegExp("(?<![.$\\w#])import\\s*\\(").test(code2)) return code2;
|
|
33763
|
+
if (!new RegExp("(?<![.$\\w#])(?:import|eval)\\s*\\(").test(code2)) return code2;
|
|
33671
33764
|
let ast;
|
|
33672
33765
|
try {
|
|
33673
33766
|
ast = parse3(code2, { ecmaVersion: "latest", sourceType: "script", allowReturnOutsideFunction: true, allowHashBang: true, allowAwaitOutsideFunction: true });
|
|
@@ -33676,14 +33769,30 @@ function __substrateRewriteDynamicImportsInScript(code2) {
|
|
|
33676
33769
|
}
|
|
33677
33770
|
const replacements = [];
|
|
33678
33771
|
walkAst(ast, (node) => {
|
|
33679
|
-
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);
|
|
33680
33774
|
});
|
|
33681
33775
|
if (replacements.length === 0) return code2;
|
|
33682
|
-
|
|
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]);
|
|
33683
33788
|
let out = code2;
|
|
33684
|
-
for (const [start, end] of replacements) out = out.slice(0, start) +
|
|
33789
|
+
for (const [start, end, text] of replacements) out = out.slice(0, start) + text + out.slice(end);
|
|
33685
33790
|
return out;
|
|
33686
33791
|
}
|
|
33792
|
+
Object.defineProperty(globalThis, "__substrateEvalSource", {
|
|
33793
|
+
configurable: true,
|
|
33794
|
+
value: (source) => typeof source === "string" ? __substrateRewriteDynamicImportsInScript(source) : source
|
|
33795
|
+
});
|
|
33687
33796
|
function transformEsmToCjs(code2, filename) {
|
|
33688
33797
|
const maybeEsm = __substrateHasEsmSyntax(code2);
|
|
33689
33798
|
if (!maybeEsm) return __substrateRewriteDynamicImportsInScript(code2);
|
|
@@ -33707,17 +33816,14 @@ function transformEsmToCjsAst(code2, filename) {
|
|
|
33707
33816
|
if (node.type === "ImportExpression") {
|
|
33708
33817
|
deepReplacements.push([node.start, node.start + 6, "__dynamicImport"]);
|
|
33709
33818
|
}
|
|
33819
|
+
collectDirectEval(node, deepReplacements);
|
|
33710
33820
|
});
|
|
33711
33821
|
const hasImportDecl = ast.body.some((n) => n.type === "ImportDeclaration");
|
|
33712
33822
|
const hasExportDecl = ast.body.some((n) => {
|
|
33713
33823
|
var _a2;
|
|
33714
33824
|
return (_a2 = n.type) == null ? void 0 : _a2.startsWith("Export");
|
|
33715
33825
|
});
|
|
33716
|
-
let transformed = code2;
|
|
33717
|
-
deepReplacements.sort((a, b) => b[0] - a[0]);
|
|
33718
|
-
for (const [start, end, replacement] of deepReplacements) {
|
|
33719
|
-
transformed = transformed.slice(0, start) + replacement + transformed.slice(end);
|
|
33720
|
-
}
|
|
33826
|
+
let transformed = applyReplacements(code2, deepReplacements);
|
|
33721
33827
|
if (hasImportDecl || hasExportDecl) {
|
|
33722
33828
|
transformed = transformEsmToCjsSimple(transformed);
|
|
33723
33829
|
if (hasExportDecl) {
|
|
@@ -35562,7 +35668,7 @@ class WorkerRuntime {
|
|
|
35562
35668
|
this.worker = new Worker(
|
|
35563
35669
|
new URL(
|
|
35564
35670
|
/* @vite-ignore */
|
|
35565
|
-
"/assets/runtime-worker-
|
|
35671
|
+
"/assets/runtime-worker-Bt4uLPDa.js",
|
|
35566
35672
|
import.meta.url
|
|
35567
35673
|
),
|
|
35568
35674
|
{ type: "module" }
|
|
@@ -37930,7 +38036,11 @@ function resetServerBridge() {
|
|
|
37930
38036
|
}
|
|
37931
38037
|
const scopes = /* @__PURE__ */ new WeakMap();
|
|
37932
38038
|
class NativeStreamScope {
|
|
37933
|
-
|
|
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) {
|
|
37934
38044
|
__publicField(this, "entries", /* @__PURE__ */ new Map());
|
|
37935
38045
|
__publicField(this, "descriptors", /* @__PURE__ */ new Map());
|
|
37936
38046
|
__publicField(this, "writes", /* @__PURE__ */ new Map());
|
|
@@ -37940,6 +38050,7 @@ class NativeStreamScope {
|
|
|
37940
38050
|
__publicField(this, "disposed", false);
|
|
37941
38051
|
__publicField(this, "limits");
|
|
37942
38052
|
this.emit = emit2;
|
|
38053
|
+
this.ownerPid = ownerPid;
|
|
37943
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.");
|
|
37944
38055
|
this.limits = Object.freeze({ ...limits });
|
|
37945
38056
|
}
|
|
@@ -38224,6 +38335,10 @@ class NativeStreamScope {
|
|
|
38224
38335
|
if (failures.length) throw new AggregateError(failures, "Native stream scope cleanup failed.");
|
|
38225
38336
|
}
|
|
38226
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
|
+
}
|
|
38227
38342
|
let __nextRunName = 1;
|
|
38228
38343
|
function createContainer(options) {
|
|
38229
38344
|
const vfs2 = options && options.vfs || new VirtualFS();
|
|
@@ -38278,6 +38393,17 @@ function createContainer(options) {
|
|
|
38278
38393
|
},
|
|
38279
38394
|
/** The ports the servers the named run opened are listening on. */
|
|
38280
38395
|
processPorts: (token) => __ownedServerPorts(token),
|
|
38396
|
+
portPid: (port) => {
|
|
38397
|
+
var _a2;
|
|
38398
|
+
const listener = listenerOnPort(port);
|
|
38399
|
+
if (!listener) return void 0;
|
|
38400
|
+
return ((_a2 = runPid(ownerOf(listener))) == null ? void 0 : _a2.pid) ?? nativeStreamOwnerPid(listener);
|
|
38401
|
+
},
|
|
38402
|
+
/**
|
|
38403
|
+
* Deliver a signal to the named run as another process's `kill(pid)` does:
|
|
38404
|
+
* the guest's listeners for it run, else its default action ends the run.
|
|
38405
|
+
*/
|
|
38406
|
+
signalProcess: (token, signal) => __signalOwnedProcess(token, signal),
|
|
38281
38407
|
/** End the named run: its timers stop and its servers are released. */
|
|
38282
38408
|
stopProcess: (token) => {
|
|
38283
38409
|
const known = __runFor(token) !== void 0 || __ownedServerPorts(token).length > 0;
|
|
@@ -38350,6 +38476,7 @@ export {
|
|
|
38350
38476
|
nodeProcessHostInstalled,
|
|
38351
38477
|
index as npm,
|
|
38352
38478
|
ownerProcessRegistryScope,
|
|
38479
|
+
ownerProcessTable,
|
|
38353
38480
|
path,
|
|
38354
38481
|
perfHooksShim as perf_hooks,
|
|
38355
38482
|
processByPid,
|
|
@@ -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
|
-
|
|
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;
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
export interface ProcessIdentity {
|
|
3
3
|
readonly pid: number;
|
|
4
4
|
readonly ppid: number;
|
|
5
|
+
/** What the process was started as, where its starter said: `/proc/<pid>/cmdline`. */
|
|
6
|
+
readonly argv?: readonly string[];
|
|
7
|
+
/** The directory it was started in: `/proc/<pid>/cwd`. */
|
|
8
|
+
readonly cwd?: string;
|
|
9
|
+
/** When it started, in milliseconds since the epoch. */
|
|
10
|
+
readonly startedAt?: number;
|
|
5
11
|
}
|
|
6
12
|
/** A run already admitted by the container owner into this realm's scope. */
|
|
7
13
|
export interface InitialProcessRegistration {
|
|
@@ -36,4 +42,5 @@ export interface ProcessRegistryScope extends ProcessRegistry {
|
|
|
36
42
|
*/
|
|
37
43
|
export declare function createProcessRegistryOwner(): {
|
|
38
44
|
createScope(): ProcessRegistryScope;
|
|
45
|
+
table(): ProcessIdentity[];
|
|
39
46
|
};
|
package/dist/process-tokens.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* command gives its process has it removed.
|
|
16
16
|
*/
|
|
17
17
|
import type { Process } from './shims/process';
|
|
18
|
-
import { type ProcessRegistry, type ProcessRegistryScope, type InitialProcessRegistration } from './process-registry';
|
|
18
|
+
import { type ProcessIdentity, type ProcessRegistry, type ProcessRegistryScope, type InitialProcessRegistration } from './process-registry';
|
|
19
19
|
/** Whatever the embedding runtime uses to name one guest process. */
|
|
20
20
|
export type ProcessToken = string;
|
|
21
21
|
/** The environment variable a run's name travels in, from `exec` to `node`. */
|
|
@@ -64,8 +64,18 @@ export declare function __currentProcessToken(): ProcessToken | null;
|
|
|
64
64
|
* half, `__releaseOwnedServers`, which calls this for the timers.
|
|
65
65
|
*/
|
|
66
66
|
export declare function __stopOwnedProcess(token: ProcessToken): void;
|
|
67
|
+
/**
|
|
68
|
+
* Another process's `kill(pid, signal)`, delivered to a named run's guest.
|
|
69
|
+
* On a machine the target's handlers run, or its default action ends it; the
|
|
70
|
+
* guest's own `process.kill(process.pid, signal)` is exactly that, so the
|
|
71
|
+
* signal is raised through it, as the run. False when the run is gone or the
|
|
72
|
+
* signal is not one Node names.
|
|
73
|
+
*/
|
|
74
|
+
export declare function __signalOwnedProcess(token: ProcessToken, signal: string): boolean;
|
|
67
75
|
/** Each child realm gets its own registration authority in this container. */
|
|
68
76
|
export declare function createProcessRegistryScope(): ProcessRegistryScope;
|
|
77
|
+
/** Trusted container owner only: every live process of the container, from every realm. */
|
|
78
|
+
export declare function ownerProcessTable(): ProcessIdentity[];
|
|
69
79
|
/** Trusted container owner only; worker clients cannot expose their authority. */
|
|
70
80
|
export declare function ownerProcessRegistryScope(): ProcessRegistryScope;
|
|
71
81
|
/** Startup-only host seam; never swap identity authorities under live runs. */
|
|
@@ -73,7 +83,10 @@ export declare function installProcessRegistry(registry: ProcessRegistry, initia
|
|
|
73
83
|
/** The next process number this engine hands out. */
|
|
74
84
|
export declare function mintPid(): number;
|
|
75
85
|
/** Record the numbers a named run was started with, for the run to read back. */
|
|
76
|
-
export declare function setRunPid(token: ProcessToken, pid: number, ppid: number
|
|
86
|
+
export declare function setRunPid(token: ProcessToken, pid: number, ppid: number, started?: {
|
|
87
|
+
argv?: readonly string[];
|
|
88
|
+
cwd?: string;
|
|
89
|
+
}): void;
|
|
77
90
|
/** The numbers a named run was started with, where one was recorded. */
|
|
78
91
|
export declare function runPid(token: ProcessToken | null | undefined): {
|
|
79
92
|
pid: number;
|
package/dist/virtual-fs.d.ts
CHANGED
|
@@ -37,6 +37,22 @@ export interface FSNode {
|
|
|
37
37
|
* apart). Absent until something sets it, which is the write time.
|
|
38
38
|
*/
|
|
39
39
|
atime?: number;
|
|
40
|
+
/**
|
|
41
|
+
* A tree mounted here: the paths below this node are the tree's, answered
|
|
42
|
+
* when they are read, and never this filesystem's to write. Linux's
|
|
43
|
+
* `/proc` is one.
|
|
44
|
+
*/
|
|
45
|
+
mount?: MountedTree;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A read-only tree another party answers, mounted at a directory: `node`
|
|
49
|
+
* returns what is at a path relative to the mount point (`/` is the mount
|
|
50
|
+
* point itself), computed when it is asked, or undefined where nothing is.
|
|
51
|
+
* A directory's `children` names what a listing shows; a link's `target` is
|
|
52
|
+
* followed as any link is.
|
|
53
|
+
*/
|
|
54
|
+
export interface MountedTree {
|
|
55
|
+
node(path: string): FSNode | undefined;
|
|
40
56
|
}
|
|
41
57
|
type VFSChangeListener = (path: string, content: string) => void;
|
|
42
58
|
type VFSDeleteListener = (path: string) => void;
|
|
@@ -83,7 +99,7 @@ export interface NodeError extends Error {
|
|
|
83
99
|
syscall: string;
|
|
84
100
|
path?: string;
|
|
85
101
|
}
|
|
86
|
-
export declare function createNodeError(code: 'ENOENT' | 'ENOTDIR' | 'EISDIR' | 'EEXIST' | 'ENOTEMPTY' | 'ELOOP' | 'EINVAL', syscall: string, path: string, message?: string): NodeError;
|
|
102
|
+
export declare function createNodeError(code: 'ENOENT' | 'ENOTDIR' | 'EISDIR' | 'EEXIST' | 'ENOTEMPTY' | 'ELOOP' | 'EINVAL' | 'EROFS', syscall: string, path: string, message?: string): NodeError;
|
|
87
103
|
export declare class VirtualFS {
|
|
88
104
|
private root;
|
|
89
105
|
private encoder;
|
|
@@ -140,6 +156,14 @@ export declare class VirtualFS {
|
|
|
140
156
|
getNode(path: string): FSNode | undefined;
|
|
141
157
|
/** The node at a path, following every link on the way and, when `follow`, the last one too. */
|
|
142
158
|
__substrateNode(path: string, follow: boolean, depth: number): FSNode | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Mount a read-only tree at a directory, as Linux mounts `/proc`: reads
|
|
161
|
+
* below it are the tree's answers, writes fail with `EROFS`, and a snapshot
|
|
162
|
+
* leaves it out. Answers the unmount.
|
|
163
|
+
*/
|
|
164
|
+
mount(path: string, tree: MountedTree): () => void;
|
|
165
|
+
/** A write at or below a mount point is refused, as a read-only filesystem refuses it. */
|
|
166
|
+
private assertWritable;
|
|
143
167
|
/** A link's target as an absolute path: absolute as written, or relative to the link's directory. */
|
|
144
168
|
__substrateLinkTarget(linkPath: string, target: string): string;
|
|
145
169
|
symlinkSync(target: string, path: string): void;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// hands the host's own globals back. See `host-globals.ts`.
|
|
14
14
|
export { restoreHostGlobals, guestRealmInstalled } from './host-globals';
|
|
15
15
|
export { VirtualFS } from './virtual-fs';
|
|
16
|
-
export type { FSNode, Stats, FSWatcher, WatchListener, WatchEventType } from './virtual-fs';
|
|
16
|
+
export type { FSNode, MountedTree, Stats, FSWatcher, WatchListener, WatchEventType } from './virtual-fs';
|
|
17
17
|
export { Runtime, execute } from './runtime';
|
|
18
18
|
export type { Module, RuntimeOptions, RequireFunction } from './runtime';
|
|
19
19
|
export { createRuntime, WorkerRuntime } from './create-runtime';
|
|
@@ -54,11 +54,13 @@ import { PackageManager } from './npm';
|
|
|
54
54
|
import { ServerBridge, getServerBridge } from './server-bridge';
|
|
55
55
|
import { runCommand, registerRunStreams, releaseRunStreams, sendStdin } from './shims/child_process';
|
|
56
56
|
import { Server as NetServer, __releaseOwnedHandles, type Socket as NetSocket } from './node-lib/net-module';
|
|
57
|
-
import { __adoptHandle, type OwnedHandle } from './node-lib/binding/handles';
|
|
57
|
+
import { __adoptHandle, ownerOf, type OwnedHandle } from './node-lib/binding/handles';
|
|
58
|
+
import { listenerOnPort } from './node-lib/binding/tcp_wrap';
|
|
59
|
+
import { nativeStreamOwnerPid } from './native-stream-owner';
|
|
58
60
|
|
|
59
|
-
import { __currentProcessToken, __runFor, __stopOwnedProcess, runPid, processByPid } from './process-tokens';
|
|
61
|
+
import { __currentProcessToken, __runFor, __signalOwnedProcess, __stopOwnedProcess, runPid, processByPid } from './process-tokens';
|
|
60
62
|
export { runPid, processByPid };
|
|
61
|
-
export { createProcessRegistryScope, installProcessRegistry, ownerProcessRegistryScope } from './process-tokens';
|
|
63
|
+
export { createProcessRegistryScope, installProcessRegistry, ownerProcessRegistryScope, ownerProcessTable } from './process-tokens';
|
|
62
64
|
export { installNodeProcessHost, nodeProcessHostInstalled } from './node-process-host';
|
|
63
65
|
export type { NodeProcessLaunch, NodeProcessHost } from './node-process-host';
|
|
64
66
|
export type { ProcessIdentity, ProcessRegistry, ProcessRegistryScope, InitialProcessRegistration } from './process-registry';
|
|
@@ -123,6 +125,10 @@ export function createContainer(options?: ContainerOptions): {
|
|
|
123
125
|
run: (command: string, options?: RunOptions) => Promise<RunResult>;
|
|
124
126
|
pendingTimers: (token: string) => number;
|
|
125
127
|
processPorts: (token: string) => number[];
|
|
128
|
+
/** The pid of the process listening on a port of this engine, where a guest process is: `/proc`'s socket owner. */
|
|
129
|
+
portPid: (port: number) => number | undefined;
|
|
130
|
+
/** Deliver a signal to the named run as another process's `kill(pid)` does; false when the run is gone. */
|
|
131
|
+
signalProcess: (token: string, signal: string) => boolean;
|
|
126
132
|
stopProcess: (token: string) => boolean;
|
|
127
133
|
/**
|
|
128
134
|
* Input for one run's guest, by its process token; without a token, the most
|
|
@@ -208,6 +214,17 @@ export function createContainer(options?: ContainerOptions): {
|
|
|
208
214
|
pendingTimers: (token: string): number => __runFor(token)?.pendingTimers() ?? 0,
|
|
209
215
|
/** The ports the servers the named run opened are listening on. */
|
|
210
216
|
processPorts: (token: string): number[] => __ownedServerPorts(token),
|
|
217
|
+
portPid: (port: number): number | undefined => {
|
|
218
|
+
const listener = listenerOnPort(port);
|
|
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);
|
|
222
|
+
},
|
|
223
|
+
/**
|
|
224
|
+
* Deliver a signal to the named run as another process's `kill(pid)` does:
|
|
225
|
+
* the guest's listeners for it run, else its default action ends the run.
|
|
226
|
+
*/
|
|
227
|
+
signalProcess: (token: string, signal: string): boolean => __signalOwnedProcess(token, signal),
|
|
211
228
|
/** End the named run: its timers stop and its servers are released. */
|
|
212
229
|
stopProcess: (token: string): boolean => {
|
|
213
230
|
const known = __runFor(token) !== undefined || __ownedServerPorts(token).length > 0;
|
|
@@ -56,7 +56,11 @@ export class NativeStreamScope {
|
|
|
56
56
|
private disposed = false;
|
|
57
57
|
private readonly limits: Readonly<NativeStreamLimits>;
|
|
58
58
|
|
|
59
|
-
|
|
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
|
+
}
|