@ai-ecoverse/slicc-kernel 1.164.5 → 1.165.1
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/README.md +4 -2
- package/dist/kernel-worker.js +1 -1
- package/dist/node-driver-worker.js +107 -22
- package/dist/node-driver-worker.js.map +4 -4
- package/dist/node-process-worker.js +234 -130
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +1 -1
- package/dist/process-worker.js +33 -15
- package/dist/process-worker.js.map +4 -4
- package/dist/types/process/js/js-context.d.ts +4 -2
- package/dist/types/process/js/js-sync.d.ts +4 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -426,12 +426,14 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
426
426
|
- **When `fn` runs:** it formats an error's `.stack` the way V8's prepare-stack-trace callback does, as `fn(error, callSites)` returning the string. It runs only when no own `Error.prepareStackTrace` function is set, as in Node, so `Error.prepareStackTrace` stays an ordinary property: after `delete` it's `undefined`, `Object.getPrototypeOf(Error)` stays `Function.prototype`, and an assignment to a frozen subclass throws in strict mode.
|
|
427
427
|
- **What `fn` gets:** a fresh array of V8 CallSites holding only the program's own frames (its modules, `data:` imports, `sync.runScript` scripts, code they `eval`, and `new Function` or `eval` code named by `//# sourceURL`, #1632), `node:` frames and native frames. Kernel frames are dropped by script identity, so a script named like a kernel file doesn't let them through, and so are host files. A program's strict frames give `getFunction()` and `getThis()` as `undefined`.
|
|
428
428
|
- **Fallback:** if `fn` throws or returns a non-string, or an error is formatted while `fn` runs, the default stack is used.
|
|
429
|
+
- **`{ own: true }`** (#1631): `setStackFormatter(fn, { own: true })` calls `fn(error, callSites, own)` for every stack. `own` is the program's own `Error.prepareStackTrace` (the realm's `Error`, then the main one, read as Node 26 reads it), or `undefined` when none is set or it's Node's default. `fn`'s result is the stack whatever its type, and a throw propagates out of the `.stack` read, as with Node's own callback.
|
|
430
|
+
- **An own `Error.prepareStackTrace` on the Node entry** (#1631): the process worker replaces Node's stack callback with a copy of Node 26's order. A program's own `Error.prepareStackTrace`, and a host preload's, still gets V8's CallSites as in Node, kernel frames included (named `slicc-kernel:/node-process-worker.js`), with its `Error` as receiver; its result and throws are the stack. To hand it the filtered CallSites instead (no kernel frame, no host path), use `setStackFormatter(fn, { own: true })` and call `own` from `fn`. 1.165.0 filtered by default, which broke runtimes that read their own frames through an own `prepareStackTrace`; the release after it went back to V8's CallSites. Node's own internal overrides still come first with raw frames, and so do the kernel's own diagnostics: a crash report and a WASI trap backtrace still show kernel and wasm frames.
|
|
429
431
|
- **How it works:** process workers start with `--expose-internals`, so the worker can install the formatter before the lockdown. Host flags a worker refuses are dropped. If the worker still can't start with the flag, the method is absent. Every `internal/*` and `node:internal/*` module stays refused to programs, as do `node:module` and `node:worker_threads`.
|
|
430
432
|
- `sync.errorSource(error)` (#1610, slicc-jsh#1082) is Node only, so check it with `typeof ctx.sync.errorSource === 'function'`. It gives `{ sourceLine, lineNumber, startColumn }` (null-prototype and frozen), the source line Node prints over an uncaught error, for an error in the program's own code. The kernel takes V8's position while the stack is formatted (#1633), so this also works after `.stack` was read, and for a call of a non-function, a ReferenceError, a TDZ error or a thrown `Error`. For code named by `//# sourceURL` it matches on that name (#1632). That includes a direct `eval` of a value that isn't a string literal (`const s = 'null.d'; eval(s)` gives `null.d` and line 1) and a `sync.runScript` script.
|
|
431
433
|
- **Only the program's own code:** it answers only when the error's top frame is a program frame and the position V8 kept is in that same script and line.
|
|
432
|
-
- **`undefined` cases:** kernel-made errors; values that aren't native errors; a script that borrows the kernel worker's name
|
|
434
|
+
- **`undefined` cases:** kernel-made errors; values that aren't native errors; and a script that borrows the kernel worker's name. An error an own `Error.prepareStackTrace` formats answers too (#1631).
|
|
433
435
|
- **How it works:** it reads V8's message through Node's internal errors binding, which the worker loads at start-up through the same `--expose-internals` as `setStackFormatter`. It prints no warning and needs no inspector.
|
|
434
|
-
- **Kernel frames in a program's stacks** (#1583): on the Node entry, the process worker's bundle names itself `slicc-kernel:/node-process-worker.js` (a `sourceURL`), so the kernel's own frames in an error a program sees (its own errors, a failed `ctx` call, `runScript`) show that name and not the host directory the kernel is installed in. The
|
|
436
|
+
- **Kernel frames in a program's stacks** (#1583): on the Node entry, the process worker's bundle names itself `slicc-kernel:/node-process-worker.js` (a `sourceURL`), so the kernel's own frames in an error a program sees (its own errors, a failed `ctx` call, `runScript`) show that name and not the host directory the kernel is installed in. The stack formatter, and an own `Error.prepareStackTrace` called through `{ own: true }`, get no kernel CallSites at all (#1612, #1631). Line and column numbers are unchanged, so they still point into `dist/node-process-worker.js`. Don't run an embedder with `--enable-source-maps` if program-visible paths matter: Node then maps the kernel's frames back to the absolute paths of its sources. In a browser the frames keep the bundle's URL, because Chrome ignores `sourceURL` in a module worker loaded by URL.
|
|
435
437
|
- `module` (#1598, slicc-jsh#566) is a frozen `{ path }` with the command module's own path in the kernel's file system (e.g. `/usr/lib/node_modules/jsh/dist/jsh.mjs`), so a program can read its package's other files through `ctx.fs` on first use. It's the path the kernel found the package under, with symlinks left as they are (a pnpm-style `node_modules/<name>` link stays in it), and reads the same files through `ctx.fs`. It's a kernel path, never a host one, and a thread gets the same. It's absent for the kernel's built-in programs (`sudo`, `crontab`) and for a program run from inline source with no file.
|
|
436
438
|
- `memory()`, synchronous and without a kernel call, measures the calling isolate: each `thread` answers for its own (#1240, slicc-jsh#397). It returns a fresh plain object of numbers in bytes, each field only where it's measured: `heapUsed`, `heapTotal`, `heapLimit` (V8's heap size limit), `external`, `arrayBuffers` and `rss`. On the Node entry they come from V8's heap statistics and Node's memory usage, through functions the worker captured before its lockdown, so nothing reachable from the program leads back to `process` or `v8`. `rss` is the host process's resident set size, as a Node worker thread reports it in `process.memoryUsage().rss`: it isn't per process, but shared by every process and thread of the kernel, and by any other kernel in that host process (#1563, slicc-jsh#539). In a browser `memory()` answers `{}` for now, with no `rss`.
|
|
437
439
|
- **`thread`, kernel threads of the same process** ([#1094](https://github.com/ai-ecoverse/slicc-kernel/issues/1094)), the base for Node's `worker_threads` (tinypool, piscina, vitest's and jest's thread pools, eslint's concurrency). `thread.spawn({ data, transfer })` resolves with `{ tid, port, exited, terminate() }`.
|
package/dist/kernel-worker.js
CHANGED
|
@@ -8440,7 +8440,7 @@ function satisfies(version, range2) {
|
|
|
8440
8440
|
}
|
|
8441
8441
|
|
|
8442
8442
|
// src/version.ts
|
|
8443
|
-
var KERNEL_VERSION = true ? "1.
|
|
8443
|
+
var KERNEL_VERSION = true ? "1.165.1" : "0.0.0-dev";
|
|
8444
8444
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8445
8445
|
function procVersion() {
|
|
8446
8446
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -564,23 +564,23 @@ function errorWithCode(message) {
|
|
|
564
564
|
}
|
|
565
565
|
function dialStream(port, onClose) {
|
|
566
566
|
let closed = false;
|
|
567
|
-
let
|
|
567
|
+
let reader2;
|
|
568
568
|
const acks = [];
|
|
569
569
|
const readable = new ReadableStream({
|
|
570
570
|
start(controller) {
|
|
571
|
-
|
|
571
|
+
reader2 = controller;
|
|
572
572
|
},
|
|
573
573
|
pull() {
|
|
574
574
|
if (!closed) port.postMessage({ more: true });
|
|
575
575
|
},
|
|
576
576
|
cancel() {
|
|
577
|
-
|
|
577
|
+
reader2 = void 0;
|
|
578
578
|
close();
|
|
579
579
|
}
|
|
580
580
|
});
|
|
581
581
|
const finish = (fail2) => {
|
|
582
|
-
const controller =
|
|
583
|
-
|
|
582
|
+
const controller = reader2;
|
|
583
|
+
reader2 = void 0;
|
|
584
584
|
for (const ack of acks.splice(0)) {
|
|
585
585
|
if (fail2) ack.reject(fail2);
|
|
586
586
|
else ack.resolve();
|
|
@@ -601,7 +601,7 @@ function dialStream(port, onClose) {
|
|
|
601
601
|
finish();
|
|
602
602
|
}
|
|
603
603
|
port.addEventListener("message", ({ data }) => {
|
|
604
|
-
if (data instanceof Uint8Array)
|
|
604
|
+
if (data instanceof Uint8Array) reader2?.enqueue(data);
|
|
605
605
|
else if ("ack" in data) acks.shift()?.resolve();
|
|
606
606
|
else if ("end" in data) finish();
|
|
607
607
|
else finish(errorWithCode(data.error));
|
|
@@ -636,8 +636,8 @@ var latin1 = new TextDecoder("latin1");
|
|
|
636
636
|
var ByteSource = class {
|
|
637
637
|
buffered = new Uint8Array(0);
|
|
638
638
|
reader;
|
|
639
|
-
constructor(
|
|
640
|
-
this.reader =
|
|
639
|
+
constructor(reader2) {
|
|
640
|
+
this.reader = reader2;
|
|
641
641
|
}
|
|
642
642
|
async more() {
|
|
643
643
|
const { done, value } = await this.reader.read();
|
|
@@ -1423,6 +1423,14 @@ import { types as types2 } from "node:util";
|
|
|
1423
1423
|
// src/node-stack.ts
|
|
1424
1424
|
import { createRequire } from "node:module";
|
|
1425
1425
|
import { types } from "node:util";
|
|
1426
|
+
|
|
1427
|
+
// src/process/raw-stack.ts
|
|
1428
|
+
var reader = (error) => error.stack;
|
|
1429
|
+
function setRawStack(read) {
|
|
1430
|
+
reader = read;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// src/node-stack.ts
|
|
1426
1434
|
function quietly(target, run) {
|
|
1427
1435
|
const emit = target.emitWarning;
|
|
1428
1436
|
target.emitWarning = () => {
|
|
@@ -1433,18 +1441,20 @@ function quietly(target, run) {
|
|
|
1433
1441
|
target.emitWarning = emit;
|
|
1434
1442
|
}
|
|
1435
1443
|
}
|
|
1436
|
-
function
|
|
1444
|
+
function bindingOf(load) {
|
|
1437
1445
|
try {
|
|
1438
1446
|
const { internalBinding } = quietly(
|
|
1439
1447
|
process,
|
|
1440
1448
|
() => load("internal/test/binding")
|
|
1441
1449
|
);
|
|
1442
|
-
|
|
1443
|
-
return typeof get === "function" ? get : void 0;
|
|
1450
|
+
return internalBinding("errors");
|
|
1444
1451
|
} catch {
|
|
1445
|
-
return
|
|
1452
|
+
return {};
|
|
1446
1453
|
}
|
|
1447
1454
|
}
|
|
1455
|
+
function fn(value) {
|
|
1456
|
+
return typeof value === "function" ? value : void 0;
|
|
1457
|
+
}
|
|
1448
1458
|
var apply = Reflect.apply;
|
|
1449
1459
|
var push = Array.prototype.push;
|
|
1450
1460
|
var startsWith = String.prototype.startsWith;
|
|
@@ -1455,6 +1465,9 @@ var setHas = Set.prototype.has;
|
|
|
1455
1465
|
var setAdd = Set.prototype.add;
|
|
1456
1466
|
var mapGet = WeakMap.prototype.get;
|
|
1457
1467
|
var mapSet = WeakMap.prototype.set;
|
|
1468
|
+
var mapHas = WeakMap.prototype.has;
|
|
1469
|
+
var mapDelete = WeakMap.prototype.delete;
|
|
1470
|
+
var MainError = Error;
|
|
1458
1471
|
var isNativeError = types.isNativeError;
|
|
1459
1472
|
var freeze = Object.freeze;
|
|
1460
1473
|
var blank = Object.create;
|
|
@@ -1467,11 +1480,17 @@ function internals() {
|
|
|
1467
1480
|
if (process.sourceMapsEnabled) {
|
|
1468
1481
|
fallback = load("internal/source_map/prepare_stack_trace").prepareStackTraceWithSourceMaps;
|
|
1469
1482
|
}
|
|
1470
|
-
|
|
1483
|
+
const overrides = errors.overrideStackTrace;
|
|
1484
|
+
const usable = typeof set === "function" && typeof fallback === "function";
|
|
1485
|
+
if (!usable || !types.isWeakMap(overrides)) return void 0;
|
|
1486
|
+
const binding = bindingOf(load);
|
|
1471
1487
|
return {
|
|
1472
1488
|
setInternalPrepareStackTrace: set,
|
|
1473
1489
|
fallback,
|
|
1474
|
-
positions:
|
|
1490
|
+
positions: fn(binding.getErrorSourcePositions),
|
|
1491
|
+
setCallback: fn(binding.setPrepareStackTraceCallback),
|
|
1492
|
+
overrides,
|
|
1493
|
+
nodeDefault: errors.ErrorPrepareStackTrace
|
|
1475
1494
|
};
|
|
1476
1495
|
} catch {
|
|
1477
1496
|
return void 0;
|
|
@@ -1563,6 +1582,7 @@ function keptFrames(trace) {
|
|
|
1563
1582
|
return out;
|
|
1564
1583
|
}
|
|
1565
1584
|
var formatter = null;
|
|
1585
|
+
var withOwn = false;
|
|
1566
1586
|
var formatting = false;
|
|
1567
1587
|
var seen = /* @__PURE__ */ new WeakMap();
|
|
1568
1588
|
function positionsAt(positions, error, site) {
|
|
@@ -1573,17 +1593,20 @@ function positionsAt(positions, error, site) {
|
|
|
1573
1593
|
return void 0;
|
|
1574
1594
|
}
|
|
1575
1595
|
}
|
|
1596
|
+
function record(positions, error, trace) {
|
|
1597
|
+
if (typeof error === "object" && error !== null && trace.length > 0) {
|
|
1598
|
+
const site = trace[0];
|
|
1599
|
+
apply(mapSet, seen, [error, { site, at: positionsAt(positions, error, site) }]);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1576
1602
|
function stackDispatcher(fallback, positions) {
|
|
1577
1603
|
return (error, trace) => {
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
}
|
|
1582
|
-
const fn = formatter;
|
|
1583
|
-
if (fn === null || formatting) return apply(fallback, void 0, [error, trace]);
|
|
1604
|
+
record(positions, error, trace);
|
|
1605
|
+
const fn2 = formatter;
|
|
1606
|
+
if (fn2 === null || formatting) return apply(fallback, void 0, [error, trace]);
|
|
1584
1607
|
formatting = true;
|
|
1585
1608
|
try {
|
|
1586
|
-
const out = apply(
|
|
1609
|
+
const out = apply(fn2, void 0, [error, keptFrames(trace)]);
|
|
1587
1610
|
if (typeof out === "string") return out;
|
|
1588
1611
|
} catch {
|
|
1589
1612
|
} finally {
|
|
@@ -1592,8 +1615,70 @@ function stackDispatcher(fallback, positions) {
|
|
|
1592
1615
|
return apply(fallback, void 0, [error, trace]);
|
|
1593
1616
|
};
|
|
1594
1617
|
}
|
|
1618
|
+
function errorOf2(realm) {
|
|
1619
|
+
return realm === null || realm === void 0 ? void 0 : realm.Error;
|
|
1620
|
+
}
|
|
1621
|
+
function prepareOf(holder) {
|
|
1622
|
+
return holder === null || holder === void 0 ? void 0 : holder.prepareStackTrace;
|
|
1623
|
+
}
|
|
1624
|
+
function ownPrepare(realm, nodeDefault) {
|
|
1625
|
+
let self2;
|
|
1626
|
+
if (typeof prepareOf(errorOf2(realm)) === "function") self2 = errorOf2(realm);
|
|
1627
|
+
else if (typeof prepareOf(MainError) === "function") self2 = MainError;
|
|
1628
|
+
else return void 0;
|
|
1629
|
+
const value = prepareOf(self2);
|
|
1630
|
+
return value === nodeDefault ? void 0 : { fn: value, self: self2 };
|
|
1631
|
+
}
|
|
1632
|
+
function calling(run) {
|
|
1633
|
+
formatting = true;
|
|
1634
|
+
try {
|
|
1635
|
+
return run();
|
|
1636
|
+
} finally {
|
|
1637
|
+
formatting = false;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
function kernelCallback(internal, dispatch2) {
|
|
1641
|
+
const { fallback, positions, overrides, nodeDefault } = internal;
|
|
1642
|
+
return (realm, error, trace) => {
|
|
1643
|
+
if (apply(mapHas, overrides, [error]) === true) {
|
|
1644
|
+
const override = apply(mapGet, overrides, [error]);
|
|
1645
|
+
apply(mapDelete, overrides, [error]);
|
|
1646
|
+
return apply(override, void 0, [error, trace]);
|
|
1647
|
+
}
|
|
1648
|
+
const own = ownPrepare(realm, nodeDefault);
|
|
1649
|
+
if (formatting) return apply(fallback, void 0, [error, keptFrames(trace)]);
|
|
1650
|
+
const fmt = formatter;
|
|
1651
|
+
if (fmt !== null && withOwn) {
|
|
1652
|
+
record(positions, error, trace);
|
|
1653
|
+
return calling(() => apply(fmt, void 0, [error, keptFrames(trace), own?.fn]));
|
|
1654
|
+
}
|
|
1655
|
+
if (own === void 0) return apply(dispatch2, void 0, [error, trace]);
|
|
1656
|
+
record(positions, error, trace);
|
|
1657
|
+
return apply(own.fn, own.self, [error, trace]);
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
function rawReader(overrides, fallback) {
|
|
1661
|
+
return (error) => {
|
|
1662
|
+
apply(mapSet, overrides, [
|
|
1663
|
+
error,
|
|
1664
|
+
(e, trace) => apply(fallback, void 0, [e, trace])
|
|
1665
|
+
]);
|
|
1666
|
+
try {
|
|
1667
|
+
return error.stack;
|
|
1668
|
+
} finally {
|
|
1669
|
+
apply(mapDelete, overrides, [error]);
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1595
1673
|
var found = internals();
|
|
1596
|
-
if (found)
|
|
1674
|
+
if (found) {
|
|
1675
|
+
const dispatch2 = stackDispatcher(found.fallback, found.positions);
|
|
1676
|
+
found.setInternalPrepareStackTrace(dispatch2);
|
|
1677
|
+
if (found.setCallback) {
|
|
1678
|
+
found.setCallback(kernelCallback(found, dispatch2));
|
|
1679
|
+
setRawStack(rawReader(found.overrides, found.fallback));
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1597
1682
|
function errorSourceOf(error) {
|
|
1598
1683
|
if (typeof error !== "object" || error === null || !isNativeError(error)) return void 0;
|
|
1599
1684
|
try {
|