@ai-ecoverse/slicc-kernel 1.158.1 → 1.159.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 +9 -1
- package/dist/driver-worker.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +205 -17
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +22 -0
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +659 -376
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +207 -19
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +131 -34
- package/dist/process-worker.js.map +4 -4
- package/dist/types/kernel/fd-rights.d.ts +32 -0
- package/dist/types/kernel/net/tls-server.d.ts +6 -1
- package/dist/types/kernel/pipe.d.ts +19 -2
- package/dist/types/kernel/socket-syscalls.d.ts +12 -0
- package/dist/types/kernel/socket.d.ts +9 -1
- package/dist/types/process/js/js-context.d.ts +9 -0
- package/dist/types/process/js/js-net.d.ts +1 -0
- package/dist/types/process/js/js-rights.d.ts +46 -0
- package/dist/types/process/js/js-sync.d.ts +8 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -404,6 +404,13 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
404
404
|
- `sync.exit(status)`, which ends the process at once, as Node's `process.exit()` does: no `catch`, `finally`, microtask, timer or signal handler runs after it, because the call never returns. First the writes the program has made reach their descriptors, in order (a broken pipe drops the rest for that descriptor), and terminal modes the program set with `tty` are put back. Then the process ends the way any exit does: its descriptors are closed and written back, its parent gets `SIGCHLD`, and `wait` reports `status`. Children keep running. In the main thread it ends the process with all its threads (`Worker` itself is withheld; threads come from `thread.spawn`, below); in a thread it ends that thread only. `exit(status)` (below) unwinds instead, so the program's `catch` and `finally` blocks run;
|
|
405
405
|
- `select({ read?, write?, timeoutMs? }, { signal }?)` waits until a descriptor of either list is readable or writable, and answers `{ read, write }` with the ready ones; `timeoutMs` (default: no limit) bounds the wait, and `0` only checks. After a nonblock write's `EAGAIN`, `select({ write: [fd] })` says when room returns ([#1124](https://github.com/ai-ecoverse/slicc-kernel/issues/1124)).
|
|
406
406
|
- `socketpair()` (and `sync.socketpair()`) answers `[a, b]`, two descriptors of the program on a connected `AF_UNIX` stream pair, and `pipe()` (and `sync.pipe()`) answers `[readFd, writeFd]` ([#1093](https://github.com/ai-ecoverse/slicc-kernel/issues/1093)).
|
|
407
|
+
- `sendmsg(fd, data, { fds, nonblock })` and `recvmsg(fd, max?, { cloexec, nonblock })` (and their `sync` forms) pass descriptors over a kernel `AF_UNIX` stream socket, a `socketpair` or a connected unix-path stream, as `SCM_RIGHTS` does ([#1562](https://github.com/ai-ecoverse/slicc-kernel/issues/1562)). `sendmsg` answers the bytes written; `recvmsg` answers `{ bytes, fds, ctrunc }`. `net.adopt(fd)` turns a received socket into a connection, or a listener when it listens. The rules:
|
|
408
|
+
- **What crosses** is the open file description, as `dup()` gives across processes: the receiver shares its offset, and for a socket its connection or listener, which stays open while it is in flight even if the sender closes its copy. The sender's status flags (`O_APPEND`, `O_NONBLOCK`) come with it; `FD_CLOEXEC` comes only with `cloexec: true`.
|
|
409
|
+
- **No re-check:** the receiver gets the description as is, in every `users` mode, as on Linux. A received descriptor gives no new power, since the sender could already act on it for the receiver; that holds for protect writers and tag rules too.
|
|
410
|
+
- **Framing:** the descriptors ride on the first byte of the write (it needs at least one, else `EINVAL`), and a read never crosses such a byte. `recvmsg` installs them at the lowest free numbers; a plain `read` that takes those bytes closes them, as does the receiving end closing with them still queued.
|
|
411
|
+
- **Kinds:** files, directories, pipes and FIFOs, devices, eventfds and inet sockets (connected, listening or datagram) pass. `/dev/sealed`, `/dev/clipboard`, `/dev/embedder`, epoll instances, TLS contexts and any inet socket that carries a kernel TLS session or TLS server options (`secure()`d, a TLS `connect`, a TLS `listen`, anything sealed) are `EPERM`, as they are bound to the process that made them. `AF_UNIX` sockets are `EOPNOTSUPP`, so nothing in flight can carry more rights and no cycle can form. A carrier other than a kernel `AF_UNIX` stream is `EOPNOTSUPP`.
|
|
412
|
+
- **Limits:** 253 descriptors per message (`EINVAL` beyond), 1024 in flight per direction (`EMFILE`, as WASI has no `ETOOMANYREFS`). A receiver whose table is full gets the bytes and as many descriptors as fit, the rest closed, with `ctrunc: true`.
|
|
413
|
+
- WASI and Emscripten programs can't pass descriptors yet, as WASIX has no ancillary-data ABI.
|
|
407
414
|
- **The same descriptors either way:** the async and `sync` forms give the program's own kernel descriptors, which `read`, `write`, `close` and their `sync` forms all take, until the program closes them or ends.
|
|
408
415
|
- **Reading** a socket or pipe whose peer has closed gives an empty `Uint8Array` (end of file). A `read` still pending when the program `close`s that descriptor rejects with `EBADF` instead of waiting. A `read` and a `write` on one socket can be pending at the same time, as a socket is full duplex.
|
|
409
416
|
- **Writing to a socket whose peer is gone** fails with `EPIPE` and raises no `SIGPIPE`, at the default disposition too, as for WASIX and Emscripten programs (as if `MSG_NOSIGNAL` were set). A pipe's broken write follows `SIGPIPE` as described below.
|
|
@@ -414,6 +421,7 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
414
421
|
- **Why a `Record`:** it can't name a child fd twice, and it reads like Node's `stdio` index, so it's this rather than a list of `{ fd, from }`.
|
|
415
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.
|
|
416
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
|
+
- `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).
|
|
417
425
|
- `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`.
|
|
418
426
|
- **`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() }`.
|
|
419
427
|
- **What a thread is:** a new process worker in the **same process**. It has the same pid, descriptor table, cwd, umask, credentials and lockdown, and a sync lane of its own, so `sync` calls in one thread don't hold another.
|
|
@@ -499,7 +507,7 @@ The module's default export (or its `main` export) is called with a context and
|
|
|
499
507
|
It's never `ERR_TLS_CERT_ALTNAME_INVALID`; that's `hostnameMatches: false`. `authorized` and `authorizationError` are as before.
|
|
500
508
|
- **A client certificate** ([#1004](https://github.com/ai-ecoverse/slicc-kernel/issues/1004)): `cert` (PEM text, DER bytes or a list: the leaf first, then its intermediates) and `key` (PEM, PKCS#1, SEC1 or PKCS#8, or DER), with `passphrase` for an encrypted key, as in Node.
|
|
501
509
|
- The key goes to the engine before anything is dialled, and the kernel keeps no copy of it (nor of the passphrase) once the engine has it.
|
|
502
|
-
- Before dialling, `cert` without `key` (or the reverse) is `EINVAL`. A key that doesn't match the leaf is `ERR_OSSL_X509_KEY_VALUES_MISMATCH`, a wrong passphrase `ERR_OSSL_BAD_DECRYPT`, a missing one `ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED`, and a key the engine can't read `ERR_OSSL_UNSUPPORTED`.
|
|
510
|
+
- Before dialling, `cert` without `key` (or the reverse) is `EINVAL`. A key that doesn't match the leaf is `ERR_OSSL_X509_KEY_VALUES_MISMATCH`, a wrong passphrase `ERR_OSSL_BAD_DECRYPT`, a missing one `ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED`, and a key the engine can't read `ERR_OSSL_UNSUPPORTED`. An encrypted PKCS#8 key may use PBES2 with AES, Camellia or ARIA (tls-engine 4.2.0-12, [#1564](https://github.com/ai-ecoverse/slicc-kernel/issues/1564)). 3DES (`-v2 des3`), PBES1 (`-v1`) and traditional encrypted PEM are `ERR_OSSL_UNSUPPORTED` whatever the passphrase, as Mbed TLS 4 has no DES; these are differences from Node.
|
|
503
511
|
- `pfx` is `ENOTSUP`: pass `cert` and `key`.
|
|
504
512
|
- A server that requires a certificate and gets none refuses with an alert. On TLS 1.2 that fails the connect (`ERR_SSL_HANDSHAKE_FAILURE`). On TLS 1.3 the client's side of the handshake is already done, so the next read or write fails with `ERR_SSL_FATAL_ALERT`, as Node's fails after `secureConnect`.
|
|
505
513
|
- **A reply that isn't TLS** ([#1548](https://github.com/ai-ecoverse/slicc-kernel/issues/1548)) is told apart by its first record's header, in OpenSSL's order, so a program gets Node's code: an SSLv2 version is `ERR_SSL_WRONG_VERSION_NUMBER`; a length over 16704 bytes `ERR_SSL_PACKET_LENGTH_TOO_LONG` (most plain-text replies, `HTTP/1.1 …` among them); a major version other than 3 `ERR_SSL_HTTP_REQUEST` for `GET ` or `PUT ` and `ERR_SSL_WRONG_VERSION_NUMBER` otherwise (`220 …`, `SSH-2.0…`, `+OK …`); a record over 16384 bytes `ERR_SSL_DATA_LENGTH_TOO_LONG`; and a handshake record that isn't a ServerHello `ERR_SSL_UNEXPECTED_MESSAGE`. Anything else stays `ERR_SSL_HANDSHAKE_FAILURE`, or `ECONNRESET` for a server that closes.
|