@ai-ecoverse/slicc-kernel 1.162.0 → 1.162.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 +2 -2
- package/dist/kernel-worker.js +4 -2
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +26 -11
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +1 -1
- package/dist/types/node.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -207,7 +207,7 @@ kernel.terminate();
|
|
|
207
207
|
|
|
208
208
|
`createNodeKernel({ root, modules, commands, env, network, worker, facades, processMounts, fstabRetries, cdp, hostfs, hostfsOrigin, hostfsFetch, users, onDenial, approve, compileCache, warmWorker, warmWorkers })` takes the options of `createKernel` except `metadata`, and `fstabRetries`, the delays in ms between tries of a failing `/etc/fstab` line (default `[1000, 4000, 16000]`). `root` is an in-memory directory by default (`memoryRoot()` makes another), which keeps each file in 1 MiB chunks, and POSIX metadata stays in memory. Processes and threads run on `worker_threads`. The kernel has `run`, `openTerminal`, `users`, `setRoutes`, `updateTransportTraits` and `terminate` as above, plus `integrity.revoke(path?)`, `root`, `writeFile(path, data, { mode }?)` (creating the parent directories; `mode` sets the permission bits, `0` to `0o7777`, before the data is written), `chmod(path, mode)` and `readFile(path)` to put files in place and read results; like the `fs` of an attached client, they go through the mounts, as the processes see them. `nodeTransport()` is `fetchTransport()` with Node's `fetch`, which no CORS binds (`crossOrigin: 'any'`). `connect({ user })` and `attachKernel` work as in the browser: the port is a `worker_threads` `MessagePort`, which a worker thread can attach with, and `terminate()` ends every attached client.
|
|
209
209
|
|
|
210
|
-
`compileCache` (#1285, slicc-jsh#566) is where each process worker keeps the compiled code of the JS programs it imports (`module.enableCompileCache`), so the next spawn of the same program skips V8's compile. **By default a Node kernel writes a private directory of its own** (#1597): `slicc-kernel-cc
|
|
210
|
+
`compileCache` (#1285, slicc-jsh#566) is where each process worker keeps the compiled code of the JS programs it imports (`module.enableCompileCache`), so the next spawn of the same program skips V8's compile. **By default a Node kernel writes a private directory of its own** (#1597): `<pid>-<random>` in a per-user parent `slicc-kernel-cc-u<uid>` under the host's temp directory (`os.tmpdir()`), both mode 0700, removed by `terminate()`. A parent that isn't a real directory of this user closed to others (a symlink, another user's, or group- or world-accessible) isn't used, and the kernel runs without a cache. The first kernel in a host process also removes the parent's directories whose process is gone, so a crashed host leaves none behind for good; it lists only that parent, never the temp directory itself, which can hold tens of thousands of entries (1.160.3 listed it, costing a host about 15 MB of RSS and 30 ms at start, slicc-jsh#566). Measured on Node 26 with a 2 MB module, the default takes a spawn from about 21 to 8 ms and adds no measurable RSS per process. `compileCache: false` turns it off, and an absolute host directory uses that one instead, shared by every kernel given it. It stores V8's code cache, keyed and checksummed by the module's source, one file per program (about 7 MB for a 2.4 MB bundle), shared by every kernel given the same directory; programs can't reach or write it (the worker hands it to Node before the lockdown, and `node:worker_threads` stays refused). Measured on a 2.4 MB bundle, a spawn went from about 54 to 39 ms; a trivial program costs about 1 ms more. **The directory must be private to the embedder:** V8's code cache is trusted bytecode that Node only checksums, so whoever can write it can plant code that runs inside a process worker past the lockdown. Never make it reachable from inside the kernel (no `hostfs` mount of it or of a parent), and don't share one between kernels of different trust. A host's own `NODE_COMPILE_CACHE` is never handed to the process workers, with or without the option, so programs never land in a host-wide cache. If a host preload (`--import` or `--require`) has already enabled another compile cache in the workers, a kernel given a `compileCache` directory refuses to run programs there instead of caching them in the host's directory; a kernel on its default private directory leaves it to the host's, as it did before the default.
|
|
211
211
|
|
|
212
212
|
`warmWorker` (on by default; `false` turns it off; #1341, slicc-jsh#566) keeps one process worker booted ahead of the next spawn, fork or thread on the Node entry, so the spawn skips the worker's boot: it has loaded the process worker module and nothing else, no pid, credentials, environment, cwd, descriptors, lockdown or program, all of which arrive with its init message, and every worker still serves exactly one process or thread and is then terminated. Its own `process.env` is a snapshot taken when the spare is created rather than at the spawn, but a program never sees it (`process` is withheld, and a program's environment is the one its spawn gives it). The spare never keeps the host alive, is replaced after each spawn off the critical path, is dropped if it errors or exits while idle, and is released after 30 s without a spawn; `terminate()` ends it. It costs about 11 MB of host RSS while it waits. `warmWorkers: n` (opt-in; #1361, slicc-jsh#566) keeps up to `n` spares instead of one (an integer from 0 to 64; `warmWorker: false` still means none), so a burst of starts, as worker pools make, finds a spare for each: all are refilled after each take off the critical path, and all are released together after 30 s without a spawn and ended by `terminate()`. Each costs about 7–11 MB of host RSS while it waits. It pays off for bursts of `Worker` threads (jsh measured about 13 ms less per start in a burst of 8); for bursts of child processes that boot a large runtime of their own, the refills compete for CPU with the children and the gain is small or none.
|
|
213
213
|
|
|
@@ -529,7 +529,7 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
529
529
|
- A connection's `tls` is `{ path: 'kernel', protocol, cipher ({ name, standardName, version }, as a client's; [#1500](https://github.com/ai-ecoverse/slicc-kernel/issues/1500)), alpnProtocol, servername (the SNI the client sent, or ''), authorized (whether a client certificate verified), authorizationError?, peerCertificates (the client's chain) }`.
|
|
530
530
|
- On a `listen({ tls })` listener, the kernel handshakes accepted connections concurrently, from the first `accept` on, and `accept` (and `for await`) yields each as its handshake finishes, so a client that connects and stays silent doesn't hold up the next. It holds at most `backlog` (up to 64) connections in a handshake or handshaken but not yet taken; beyond that it stops accepting, leaving the rest in the kernel's backlog, until one finishes or is taken. A connection whose handshake fails is closed and never yielded. `secure()` rejects instead.
|
|
531
531
|
- `handshakeTimeout` (milliseconds, 120000 by default, as Node's) ends a handshake that hasn't finished with `ERR_TLS_HANDSHAKE_TIMEOUT`. A listener closes that connection. After `secure()` rejects, the connection stays open and is the program's to answer or close, as with Node's `tlsClientError` ([#1504](https://github.com/ai-ecoverse/slicc-kernel/issues/1504)).
|
|
532
|
-
- A client that sends a plain HTTP request instead of a ClientHello fails the handshake with `ERR_SSL_HTTP_REQUEST`, as in Node. A client that resets during the handshake fails it with `ECONNRESET` and `read ECONNRESET`, as Node's server reports it, and one that closes with `ECONNRESET` and `the client closed the connection during the TLS handshake` ([#1578](https://github.com/ai-ecoverse/slicc-kernel/issues/1578)). A handshake, server or loopback client, waits without holding the program's other calls, and an aborted `accept({ signal })` or `connect({ signal })` ends it. A signal delivered to the program doesn't interrupt a handshake, as with `SA_RESTART`.
|
|
532
|
+
- A client that sends a plain HTTP request instead of a ClientHello fails the handshake with `ERR_SSL_HTTP_REQUEST`, as in Node. A client that resets during the handshake fails it with `ECONNRESET` and `read ECONNRESET`, as Node's server reports it, and one that closes with `ECONNRESET` and `the client closed the connection during the TLS handshake` ([#1578](https://github.com/ai-ecoverse/slicc-kernel/issues/1578)). A loopback TLS client whose server resets before or during the handshake fails the same way, with `read ECONNRESET`, not `EPIPE` ([#1611](https://github.com/ai-ecoverse/slicc-kernel/issues/1611)). A handshake, server or loopback client, waits without holding the program's other calls, and an aborted `accept({ signal })` or `connect({ signal })` ends it. A signal delivered to the program doesn't interrupt a handshake, as with `SA_RESTART`.
|
|
533
533
|
- **Choosing per connection** ([#1501](https://github.com/ai-ecoverse/slicc-kernel/issues/1501), [#1502](https://github.com/ai-ecoverse/slicc-kernel/issues/1502), tls-engine 4.2.0-9's `TLS_SERVER_SELECT`), for Node's `SNICallback`, `addContext` and `ALPNCallback`: `tls.select({ servername, protocols })` on `listen` or `secure` is called once the client's ClientHello is in, with the SNI (or `''`) and the protocols the client offers. It returns (or resolves with) `{ context, alpn }` or `{ refuse }`:
|
|
534
534
|
- `context` is a certificate from `net.tlsContext({ cert, key, passphrase })` (or its `fd`); without it the listener's own `cert` serves, and with `select` that one is optional. `alpn` is one of `protocols`, or none; another is `EINVAL` and refuses the handshake. `select` and a fixed `alpn` list together are `EINVAL` (`ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS`), as in Node.
|
|
535
535
|
- `refuse` sends a fatal alert and ends the handshake: `'unrecognized_name'` (112), `'no_application_protocol'` (120), `'handshake_failure'` (40), `'access_denied'` (49) or `'internal_error'` (80), or the number. A `select` that throws refuses with 40, and one that doesn't answer within `handshakeTimeout` times the handshake out. On a listener the connection is dropped and the listener keeps accepting; `secure()` rejects with the error.
|
package/dist/kernel-worker.js
CHANGED
|
@@ -6650,7 +6650,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
6650
6650
|
throw new KernelError("ECONNRESET", "read ECONNRESET");
|
|
6651
6651
|
return bytes.length > 0 ? bytes : null;
|
|
6652
6652
|
},
|
|
6653
|
-
write: (bytes) => raw2.tx.write(bytes)
|
|
6653
|
+
write: (bytes) => raw2.tx.write(bytes).catch((err) => {
|
|
6654
|
+
throw this.refused ? new KernelError("ECONNRESET", "read ECONNRESET") : err;
|
|
6655
|
+
}),
|
|
6654
6656
|
closeWrite: () => raw2.tx.closeWrite(),
|
|
6655
6657
|
close: () => {
|
|
6656
6658
|
raw2.rx.closeRead();
|
|
@@ -8435,7 +8437,7 @@ function satisfies(version, range2) {
|
|
|
8435
8437
|
}
|
|
8436
8438
|
|
|
8437
8439
|
// src/version.ts
|
|
8438
|
-
var KERNEL_VERSION = true ? "1.162.
|
|
8440
|
+
var KERNEL_VERSION = true ? "1.162.1" : "0.0.0-dev";
|
|
8439
8441
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8440
8442
|
function procVersion() {
|
|
8441
8443
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|