@ai-ecoverse/slicc-kernel 1.31.2 → 1.32.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 +3 -2
- package/dist/kernel-worker.js +8 -3
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +361 -262
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +20 -3
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +361 -262
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ const { status, stdout } = await kernel.run(['bash', '-c', 'echo hi'], { cwd: '/
|
|
|
125
125
|
kernel.terminate();
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
`createNodeKernel({ root, modules, env, network, worker, processMounts, fstabRetries, cdp, hostfs })` 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`, `setRoutes` and `terminate` as above, plus `root`, `writeFile(path, data)` (creating the parent directories) and `readFile(path)` to put files in place and read results. `nodeTransport()` is `fetchTransport()` with Node's `fetch`, which no CORS binds (`crossOrigin: 'any'`). `connect()` 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.
|
|
128
|
+
`createNodeKernel({ root, modules, env, network, worker, processMounts, fstabRetries, cdp, hostfs, hostfsOrigin, hostfsFetch })` 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`, `setRoutes` and `terminate` as above, plus `root`, `writeFile(path, data)` (creating the parent directories) and `readFile(path)` to put files in place and read results. `nodeTransport()` is `fetchTransport()` with Node's `fetch`, which no CORS binds (`crossOrigin: 'any'`). `connect()` 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.
|
|
129
129
|
|
|
130
130
|
## Commands
|
|
131
131
|
|
|
@@ -373,7 +373,8 @@ A `hostfs` mount is a folder exported by the local proxy ([slicc-node](https://g
|
|
|
373
373
|
- **Options:** `ro` mounts read-only, and `maxfile` caps file size as on any mount. There is no other size limit: reads and writes go in `maxIo` pieces (16 MiB unless the proxy says otherwise), so a file of any size the host can hold works. A proxy that advertises `ranges` in its grant (slicc-node 2.4, slicc-swift 1.4) makes the mount ranged, so programs read and write its files in pages and truncate through `setattr` `size`. With an older proxy files go whole, and a truncate on a ranged mount whose proxy was replaced by an older one is done by rewriting the file.
|
|
374
374
|
- **Changes on the host** arrive as invalidations on a watch stream (`POST /api/hostfs/watch`), so an edit made outside shows up on the next access without a remount.
|
|
375
375
|
- **Proxy loss:** when the watch stream ends, or is silent for 45 s, the kernel reconnects once at once. If that fails, the mount is `nomedium`, as with [removable media](#removable-media-fsa): operations fail with `ENOMEDIUM` (`ENODEV` for WASI), and the kernel keeps reconnecting with backoff (1 s to 30 s), so the folder comes back by itself when the proxy does. A mount made while the proxy is down starts as `nomedium`, and so does one whose grant or first watch takes more than 15 s; it comes up by itself when they arrive.
|
|
376
|
-
- **Consistency:** a file that changes on the host while a program reads it fails with `ESTALE`, and the kernel restarts the whole read (up to 3 times) instead of stitching two versions together. On a ranged mount an open file keeps the version it was opened at (its ETag) until it writes, also when it is handed to a child process: a page fetched after the host changed the file fails the program's read with `ESTALE` ("Stale file handle") instead of mixing versions.
|
|
376
|
+
- **Consistency:** a file that changes on the host while a program reads it fails with `ESTALE`, and the kernel restarts the whole read (up to 3 times) instead of stitching two versions together. On a ranged mount an open file keeps the version it was opened at (its ETag) until it writes, also when it is handed to a child process: a page fetched after the host changed the file fails the program's read with `ESTALE` ("Stale file handle") instead of mixing versions. A file deleted on the host while a program holds it open fails the next read that goes to the host with `ENOENT`, not with NFS's `ESTALE`.
|
|
377
|
+
- **Node:** a page's requests carry its `Origin`, and slicc-node grants a token to that origin only. Node's `fetch` sends none, so a Node embedder passes `createNodeKernel` the origin its `hostfs` hook asked for the grant with, as `hostfsOrigin`, and the kernel adds it to every hostfs request. Without it the mount stays `nomedium`. `hostfsFetch(url, init)` replaces the `fetch` those requests use (for an agent or a test proxy), and gets the `Origin` too when both are given.
|
|
377
378
|
|
|
378
379
|
### Mounting from a program
|
|
379
380
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -1152,6 +1152,10 @@ function nullFile() {
|
|
|
1152
1152
|
}
|
|
1153
1153
|
});
|
|
1154
1154
|
}
|
|
1155
|
+
function written(device, bytes) {
|
|
1156
|
+
if (device === "full" && bytes.length > 0) throw new KernelError("ENOSPC");
|
|
1157
|
+
return bytes.length;
|
|
1158
|
+
}
|
|
1155
1159
|
function deviceFile(device, access) {
|
|
1156
1160
|
const read = async (max) => {
|
|
1157
1161
|
if (device === "null") return new Uint8Array(0);
|
|
@@ -1165,7 +1169,7 @@ function deviceFile(device, access) {
|
|
|
1165
1169
|
};
|
|
1166
1170
|
return new OpenFile({
|
|
1167
1171
|
...access !== "write" ? { read } : {},
|
|
1168
|
-
...access !== "read" ? { write: async (bytes) => bytes
|
|
1172
|
+
...access !== "read" ? { write: async (bytes) => written(device, bytes) } : {},
|
|
1169
1173
|
seek: async () => 0,
|
|
1170
1174
|
heldMeta: { device, ...access ? { access } : {} },
|
|
1171
1175
|
close: () => {
|
|
@@ -4979,6 +4983,7 @@ var ChildTable = class {
|
|
|
4979
4983
|
openSlot(slot, n, captured) {
|
|
4980
4984
|
if ("fd" in slot) return this.parentFds.get(slot.fd).retain();
|
|
4981
4985
|
if ("input" in slot) return bytesSource(slot.input);
|
|
4986
|
+
if ("device" in slot) return deviceFile(slot.device, slot.access);
|
|
4982
4987
|
if ("capture" in slot) {
|
|
4983
4988
|
const chunks = [];
|
|
4984
4989
|
captured.set(n, chunks);
|
|
@@ -7210,11 +7215,11 @@ var Pages = class {
|
|
|
7210
7215
|
runs.push({ offset: start, bytes });
|
|
7211
7216
|
i = j;
|
|
7212
7217
|
}
|
|
7213
|
-
const
|
|
7218
|
+
const written2 = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
|
|
7214
7219
|
return {
|
|
7215
7220
|
...this.shrink !== void 0 ? { shrink: this.shrink } : {},
|
|
7216
7221
|
runs,
|
|
7217
|
-
...this.length >
|
|
7222
|
+
...this.length > written2 ? { extend: this.length } : {}
|
|
7218
7223
|
};
|
|
7219
7224
|
}
|
|
7220
7225
|
flushed() {
|