@ai-ecoverse/slicc-kernel 1.162.1 → 1.163.0
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 +5 -0
- package/dist/kernel-worker.js +1 -1
- package/dist/node-driver-worker.js +117 -0
- package/dist/node-driver-worker.js.map +4 -4
- package/dist/node-process-worker.js +232 -88
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +37 -7
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +5 -2
- package/dist/process-worker.js.map +2 -2
- package/dist/types/node.d.ts +3 -0
- package/dist/types/process/js/js-context.d.ts +3 -0
- package/dist/types/process/js/js-sync.d.ts +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -422,6 +422,11 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
422
422
|
- `asyncContext` (the Node entry only; absent in a browser, so a runtime feature-detects it; #1350, slicc-jsh#375) is `{ run(store, fn, ...args), getStore(), enterWith(store) }`, backed by one host `AsyncLocalStorage` the process worker makes for each program, since a program can't import `node:async_hooks` and the realm has no promise hooks of its own. A store follows the program's native `await` continuations and promise jobs, as an `AsyncLocalStorage` does in Node, so Next.js, OpenTelemetry and request-context loggers keep their context. Each process and each thread has its own. Only these three frozen functions on a frozen null-prototype object reach the program: they hold the host storage in a closure, `run` calls the program's function with its own arguments, and nothing they return or expose is a host object.
|
|
423
423
|
- `sync.runScript(source, { filename })` (#1541, slicc-jsh#977) runs `source` as a classic script in the program's own global scope, synchronously, as Node's `vm.runInThisContext` does: `let`, `const` and `class` land in the global lexical scope, `var` (in strict code too) on the global object, and stack frames are named `filename` (default `[eval]`). On the Node entry it returns `{ value, completion: true }` with the completion value, and an error the script throws is thrown as it is. In a browser, where process workers are module workers with no synchronous classic-script path, it returns `undefined`, so a runtime feature-detects it with `ctx.sync.runScript('1') !== undefined`. A non-string `source` or `filename` is a `TypeError` everywhere. The script sees exactly the globals the program sees, `import()` inside it is refused, and a `var`, function or `let` declaration can't replace a global the program can't assign: a non-configurable one stays as it is, and the only configurable, non-assignable ones (`crypto`, `navigator`) are ones the program can already redefine with `Object.defineProperty`.
|
|
424
424
|
- `sync.promiseState(promise)` (#1531, slicc-jsh#974) tells a native promise's state synchronously, as Node's `util.inspect` does: `{ state: 'pending' | 'fulfilled' | 'rejected', value }`. `value` is the very fulfillment value or rejection reason (`undefined` while pending), and probing doesn't handle a rejection. On the Node entry it reads the promise through an inspector session the process worker opens on first use, one per process and per thread; the probe runs no program code. Anything that isn't a native promise (a thenable, a proxy) is a `TypeError`. It answers `undefined` in a browser, where a worker has no inspector, on a Node built without one, once a program has changed `Object.prototype` or put a `toJSON` on a built-in prototype, and when the global object can't take a new property (`Object.preventExtensions(globalThis)`, or a frozen global).
|
|
425
|
+
- `sync.setStackFormatter(fn | null)` (#1612, slicc-jsh#1091) is Node only, so check it with `typeof ctx.sync.setStackFormatter === 'function'`. It returns the previous formatter, and `null` removes it.
|
|
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
|
+
- **What `fn` gets:** a fresh array of V8 CallSites holding only the program's own frames (its modules, `data:` imports, `sync.runScript` scripts and code they `eval`), `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
|
+
- **Fallback:** if `fn` throws or returns a non-string, or an error is formatted while `fn` runs, the default stack is used.
|
|
429
|
+
- **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`.
|
|
425
430
|
- **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 same holds in `CallSite.toString()` and `getScriptNameOrSourceURL()`, which a program's own `Error.prepareStackTrace` gets; `getFileName()` still returns the bundle's file URL. 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.
|
|
426
431
|
- `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.
|
|
427
432
|
- `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`.
|
package/dist/kernel-worker.js
CHANGED
|
@@ -8437,7 +8437,7 @@ function satisfies(version, range2) {
|
|
|
8437
8437
|
}
|
|
8438
8438
|
|
|
8439
8439
|
// src/version.ts
|
|
8440
|
-
var KERNEL_VERSION = true ? "1.
|
|
8440
|
+
var KERNEL_VERSION = true ? "1.163.0" : "0.0.0-dev";
|
|
8441
8441
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8442
8442
|
function procVersion() {
|
|
8443
8443
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -1420,6 +1420,123 @@ async function hostDriver(start, load) {
|
|
|
1420
1420
|
import { isBuiltin, registerHooks } from "node:module";
|
|
1421
1421
|
import { types } from "node:util";
|
|
1422
1422
|
|
|
1423
|
+
// src/node-stack.ts
|
|
1424
|
+
import { createRequire } from "node:module";
|
|
1425
|
+
var apply = Reflect.apply;
|
|
1426
|
+
var push = Array.prototype.push;
|
|
1427
|
+
var startsWith = String.prototype.startsWith;
|
|
1428
|
+
var slice = String.prototype.slice;
|
|
1429
|
+
var lastIndexOf = String.prototype.lastIndexOf;
|
|
1430
|
+
var indexOf2 = String.prototype.indexOf;
|
|
1431
|
+
var setHas = Set.prototype.has;
|
|
1432
|
+
var setAdd = Set.prototype.add;
|
|
1433
|
+
function internals() {
|
|
1434
|
+
try {
|
|
1435
|
+
const load = createRequire(import.meta.url);
|
|
1436
|
+
const errors = load("internal/errors");
|
|
1437
|
+
const set = errors.setInternalPrepareStackTrace;
|
|
1438
|
+
let fallback = errors.defaultPrepareStackTrace;
|
|
1439
|
+
if (process.sourceMapsEnabled) {
|
|
1440
|
+
fallback = load("internal/source_map/prepare_stack_trace").prepareStackTraceWithSourceMaps;
|
|
1441
|
+
}
|
|
1442
|
+
if (typeof set !== "function" || typeof fallback !== "function") return void 0;
|
|
1443
|
+
return {
|
|
1444
|
+
setInternalPrepareStackTrace: set,
|
|
1445
|
+
fallback
|
|
1446
|
+
};
|
|
1447
|
+
} catch {
|
|
1448
|
+
return void 0;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
function ownSite() {
|
|
1452
|
+
const saved = Object.getOwnPropertyDescriptor(Error, "prepareStackTrace");
|
|
1453
|
+
try {
|
|
1454
|
+
Object.defineProperty(Error, "prepareStackTrace", {
|
|
1455
|
+
value: (_, sites) => sites[0],
|
|
1456
|
+
configurable: true,
|
|
1457
|
+
writable: true
|
|
1458
|
+
});
|
|
1459
|
+
return new Error().stack;
|
|
1460
|
+
} finally {
|
|
1461
|
+
delete Error.prepareStackTrace;
|
|
1462
|
+
Object.defineProperties(Error, saved ? { prepareStackTrace: saved } : {});
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
var self = ownSite();
|
|
1466
|
+
var proto = Object.getPrototypeOf(self);
|
|
1467
|
+
var fileOf = proto.getFileName;
|
|
1468
|
+
var hashOf = proto.getScriptHash;
|
|
1469
|
+
var isEval = proto.isEval;
|
|
1470
|
+
var originOf = proto.getEvalOrigin;
|
|
1471
|
+
var ownHash = apply(hashOf, self, []);
|
|
1472
|
+
var programHashes = /* @__PURE__ */ new Set();
|
|
1473
|
+
var programNames = /* @__PURE__ */ new Set();
|
|
1474
|
+
function programName(name) {
|
|
1475
|
+
return apply(startsWith, name, ["data:"]) === true || apply(setHas, programNames, [name]) === true;
|
|
1476
|
+
}
|
|
1477
|
+
function rootOrigin(origin) {
|
|
1478
|
+
let at = origin;
|
|
1479
|
+
while (apply(startsWith, at, ["eval at "]) === true) {
|
|
1480
|
+
const open = apply(indexOf2, at, [" ("]);
|
|
1481
|
+
if (open < 0) return "";
|
|
1482
|
+
let depth = 1;
|
|
1483
|
+
let i = open + 2;
|
|
1484
|
+
for (; i < at.length && depth > 0; i++) {
|
|
1485
|
+
const c = at[i];
|
|
1486
|
+
if (c === "(") depth++;
|
|
1487
|
+
else if (c === ")") depth--;
|
|
1488
|
+
}
|
|
1489
|
+
if (depth !== 0) return "";
|
|
1490
|
+
at = apply(slice, at, [open + 2, i - 1]);
|
|
1491
|
+
}
|
|
1492
|
+
let end = at.length;
|
|
1493
|
+
for (let n = 0; n < 2; n++) {
|
|
1494
|
+
const colon = apply(lastIndexOf, at, [":", end - 1]);
|
|
1495
|
+
if (colon <= 0) break;
|
|
1496
|
+
end = colon;
|
|
1497
|
+
}
|
|
1498
|
+
return apply(slice, at, [0, end]);
|
|
1499
|
+
}
|
|
1500
|
+
function keptFrame(site) {
|
|
1501
|
+
const hash = apply(hashOf, site, []);
|
|
1502
|
+
if (hash === ownHash) return false;
|
|
1503
|
+
if (apply(isEval, site, []) === true) {
|
|
1504
|
+
const origin = apply(originOf, site, []);
|
|
1505
|
+
return typeof origin === "string" && programName(rootOrigin(origin));
|
|
1506
|
+
}
|
|
1507
|
+
const file = apply(fileOf, site, []);
|
|
1508
|
+
if (typeof file !== "string") return true;
|
|
1509
|
+
if (apply(setHas, programHashes, [hash]) === true) return true;
|
|
1510
|
+
return apply(startsWith, file, ["node:"]) === true || programName(file);
|
|
1511
|
+
}
|
|
1512
|
+
function keptFrames(trace) {
|
|
1513
|
+
const out = [];
|
|
1514
|
+
for (let i = 0; i < trace.length; i++) {
|
|
1515
|
+
const site = trace[i];
|
|
1516
|
+
if (keptFrame(site)) apply(push, out, [site]);
|
|
1517
|
+
}
|
|
1518
|
+
return out;
|
|
1519
|
+
}
|
|
1520
|
+
var formatter = null;
|
|
1521
|
+
var formatting = false;
|
|
1522
|
+
function stackDispatcher(fallback) {
|
|
1523
|
+
return (error, trace) => {
|
|
1524
|
+
const fn = formatter;
|
|
1525
|
+
if (fn === null || formatting) return apply(fallback, void 0, [error, trace]);
|
|
1526
|
+
formatting = true;
|
|
1527
|
+
try {
|
|
1528
|
+
const out = apply(fn, void 0, [error, keptFrames(trace)]);
|
|
1529
|
+
if (typeof out === "string") return out;
|
|
1530
|
+
} catch {
|
|
1531
|
+
} finally {
|
|
1532
|
+
formatting = false;
|
|
1533
|
+
}
|
|
1534
|
+
return apply(fallback, void 0, [error, trace]);
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
var found = internals();
|
|
1538
|
+
if (found) found.setInternalPrepareStackTrace(stackDispatcher(found.fallback));
|
|
1539
|
+
|
|
1423
1540
|
// src/process/js/lockdown.ts
|
|
1424
1541
|
var BLOCKED_GLOBALS = [
|
|
1425
1542
|
"XMLHttpRequest",
|