@ai-ecoverse/slicc-kernel 1.60.0 → 1.60.2
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 +1 -1
- package/dist/kernel-worker.js +102 -14
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +1 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +102 -14
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/process-worker.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -384,7 +384,7 @@ The proxy answers `200` with `Content-Type: application/vnd.slicc.raw-fetch`: a
|
|
|
384
384
|
|
|
385
385
|
## Filesystem
|
|
386
386
|
|
|
387
|
-
`/` is the OPFS root. Each process mounts the top-level directories that exist when it starts (plus `/usr` and `/bin`), so files in them are shared by all processes and visible through the OPFS API as soon as the process that wrote them has closed them; `run` resolves only after that. `createKernel` creates `/tmp` and `/home` in OPFS, so they are shared too. Files directly in `/`, and directories created there after a process started, are OPFS as well, the same for Emscripten and WASI programs; only `/dev` and `/proc` live in each process's memory. File contents are buffered per open file and written back on close, `fsync` and exit; metadata operations (`mkdir`, `rename`, `rm`, …) go straight to OPFS. The kernel worker is the only writer.
|
|
387
|
+
`/` is the OPFS root. Each process mounts the top-level directories that exist when it starts (plus `/usr` and `/bin`), so files in them are shared by all processes and visible through the OPFS API as soon as the process that wrote them has closed them; `run` resolves only after that. `createKernel` creates `/tmp` and `/home` in OPFS, so they are shared too. Files directly in `/`, and directories created there after a process started, are OPFS as well, the same for Emscripten and WASI programs; only `/dev` and `/proc` live in each process's memory. A program's `mkdir` (WASI `path_create_directory`, Emscripten's `mkdir`) is exclusive, as on Linux: it fails with `EEXIST` when the name exists, and of several processes or threads making one name at once exactly one succeeds, so a directory works as a lock. Unlike Linux, a WASI program's `mkdir` under a missing directory makes the missing parents rather than failing with `ENOENT` (#380); a JS program's `ctx.fs.mkdir` makes parents too. An OPFS or IndexedDB failure that has no POSIX counterpart is `EIO`; its message names the DOM error and the operation (`lookup`, `read`, `write`, `commit` or `sidecar`), and the kernel worker logs the first of each kind to its console. File contents are buffered per open file and written back on close, `fsync` and exit; metadata operations (`mkdir`, `rename`, `rm`, …) go straight to OPFS. The kernel worker is the only writer.
|
|
388
388
|
|
|
389
389
|
Directories are renamed with `FileSystemHandle.move()` where available, else by copy and delete.
|
|
390
390
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -294,10 +294,31 @@ var ERRNO_BY_DOM_ERROR = {
|
|
|
294
294
|
TypeError: "EINVAL",
|
|
295
295
|
NotAllowedError: "EACCES"
|
|
296
296
|
};
|
|
297
|
-
|
|
297
|
+
var reported = /* @__PURE__ */ new Set();
|
|
298
|
+
function translate(err, path, op = "lookup", mapped = true) {
|
|
298
299
|
if (typeof err?.code === "string") return err;
|
|
299
|
-
const
|
|
300
|
-
|
|
300
|
+
const raw = err?.name;
|
|
301
|
+
const name2 = typeof raw === "string" ? raw : "Error";
|
|
302
|
+
const code = mapped && ERRNO_BY_DOM_ERROR[name2] || "EIO";
|
|
303
|
+
const error = Object.assign(fsError(code, path), { domName: name2, op, cause: err });
|
|
304
|
+
if (code !== "EIO") return error;
|
|
305
|
+
const detail = err?.message;
|
|
306
|
+
error.message += ` (OPFS ${op}: ${name2}${typeof detail === "string" && detail ? `: ${detail}` : ""})`;
|
|
307
|
+
if (!reported.has(`${name2}/${op}`)) {
|
|
308
|
+
reported.add(`${name2}/${op}`);
|
|
309
|
+
console.warn(
|
|
310
|
+
`slicc-kernel: ${error.message}, reported as EIO; logged once per error and operation`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
return error;
|
|
314
|
+
}
|
|
315
|
+
var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
|
|
316
|
+
function sidecar(meta) {
|
|
317
|
+
const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
|
|
318
|
+
const guarded = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
319
|
+
throw translate(err, pathOf(args), "sidecar", false);
|
|
320
|
+
});
|
|
321
|
+
return Object.fromEntries(META_OPS.map((op) => [op, guarded(op)]));
|
|
301
322
|
}
|
|
302
323
|
function missing(err) {
|
|
303
324
|
const code = err?.code;
|
|
@@ -386,7 +407,7 @@ var OpfsFs = class {
|
|
|
386
407
|
owners = false;
|
|
387
408
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
388
409
|
this.root = root;
|
|
389
|
-
this.meta = meta;
|
|
410
|
+
this.meta = sidecar(meta);
|
|
390
411
|
this.ranged = options.ranged === true;
|
|
391
412
|
this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
|
|
392
413
|
if (this.channel) {
|
|
@@ -691,7 +712,8 @@ var OpfsFs = class {
|
|
|
691
712
|
} catch (err) {
|
|
692
713
|
const name2 = err?.name;
|
|
693
714
|
const again = name2 === "NotReadableError" || locks && LOCKED.has(name2);
|
|
694
|
-
if (!again || attempt >= READ_ATTEMPTS)
|
|
715
|
+
if (!again || attempt >= READ_ATTEMPTS)
|
|
716
|
+
throw translate(err, path, locks ? "write" : "read");
|
|
695
717
|
await new Promise((resolve) => setTimeout(resolve, attempt * 10));
|
|
696
718
|
}
|
|
697
719
|
}
|
|
@@ -733,9 +755,15 @@ var OpfsFs = class {
|
|
|
733
755
|
true
|
|
734
756
|
);
|
|
735
757
|
return {
|
|
736
|
-
write: (at, bytes) => writable.write({ type: "write", position: at, data: bytes })
|
|
737
|
-
|
|
738
|
-
|
|
758
|
+
write: (at, bytes) => writable.write({ type: "write", position: at, data: bytes }).catch((err) => {
|
|
759
|
+
throw translate(err, path, "write", false);
|
|
760
|
+
}),
|
|
761
|
+
truncate: (size) => writable.truncate(size).catch((err) => {
|
|
762
|
+
throw translate(err, path, "write", false);
|
|
763
|
+
}),
|
|
764
|
+
close: () => writable.close().catch((err) => {
|
|
765
|
+
throw translate(err, path, "commit", false);
|
|
766
|
+
})
|
|
739
767
|
};
|
|
740
768
|
}
|
|
741
769
|
async readFile(path) {
|
|
@@ -770,9 +798,13 @@ var OpfsFs = class {
|
|
|
770
798
|
const [file, existed, target] = await this.fileFor(path);
|
|
771
799
|
if (!existed) await this.stampNew(target, owner, false);
|
|
772
800
|
if (!existed && content.length === 0) return;
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
801
|
+
try {
|
|
802
|
+
const writable = await file.createWritable();
|
|
803
|
+
await writable.write(content);
|
|
804
|
+
await writable.close();
|
|
805
|
+
} catch (err) {
|
|
806
|
+
throw translate(err, path, "commit", false);
|
|
807
|
+
}
|
|
776
808
|
}
|
|
777
809
|
async listing(path) {
|
|
778
810
|
const found = await this.locate(path, true);
|
|
@@ -1048,6 +1080,49 @@ var OpfsFs = class {
|
|
|
1048
1080
|
return removed;
|
|
1049
1081
|
}
|
|
1050
1082
|
};
|
|
1083
|
+
var READS = [
|
|
1084
|
+
"stat",
|
|
1085
|
+
"lstat",
|
|
1086
|
+
"exists",
|
|
1087
|
+
"readFile",
|
|
1088
|
+
"readFileBuffer",
|
|
1089
|
+
"pread",
|
|
1090
|
+
"readdir",
|
|
1091
|
+
"readdirStat",
|
|
1092
|
+
"readlink",
|
|
1093
|
+
"realpath"
|
|
1094
|
+
];
|
|
1095
|
+
var WRITES = [
|
|
1096
|
+
"writeFile",
|
|
1097
|
+
"pwrite",
|
|
1098
|
+
"truncate",
|
|
1099
|
+
"writeSession",
|
|
1100
|
+
"mkdir",
|
|
1101
|
+
"rm",
|
|
1102
|
+
"link",
|
|
1103
|
+
"rename",
|
|
1104
|
+
"symlink",
|
|
1105
|
+
"chmod",
|
|
1106
|
+
"utimes",
|
|
1107
|
+
"lutimes",
|
|
1108
|
+
"chown"
|
|
1109
|
+
];
|
|
1110
|
+
for (const [names, op] of [
|
|
1111
|
+
[READS, "read"],
|
|
1112
|
+
[WRITES, "write"]
|
|
1113
|
+
]) {
|
|
1114
|
+
for (const name2 of names) {
|
|
1115
|
+
const proto = OpfsFs.prototype;
|
|
1116
|
+
const inner = proto[name2];
|
|
1117
|
+
proto[name2] = async function(...args) {
|
|
1118
|
+
try {
|
|
1119
|
+
return await inner.apply(this, args);
|
|
1120
|
+
} catch (err) {
|
|
1121
|
+
throw translate(err, String(args[0]), op, false);
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1051
1126
|
|
|
1052
1127
|
// src/mount/media.ts
|
|
1053
1128
|
var MEDIA_STORE = "handles";
|
|
@@ -7734,6 +7809,19 @@ function mkdirOptions(entry, mode = 511) {
|
|
|
7734
7809
|
const parents = 511 & ~(entry.umask?.() ?? 18) | 192;
|
|
7735
7810
|
return { recursive: true, owner: { ...owner, parents } };
|
|
7736
7811
|
}
|
|
7812
|
+
async function mkdirExclusive(entry, path, mode) {
|
|
7813
|
+
const { fs } = entry;
|
|
7814
|
+
const { owner } = mkdirOptions(entry, mode);
|
|
7815
|
+
const own = owner ? { owner } : {};
|
|
7816
|
+
try {
|
|
7817
|
+
await fs.mkdir(path, own);
|
|
7818
|
+
} catch (err) {
|
|
7819
|
+
if (err?.code !== "ENOENT") throw err;
|
|
7820
|
+
const above = owner ? { owner: { ...owner, mode: owner.parents } } : {};
|
|
7821
|
+
await fs.mkdir(path.slice(0, path.lastIndexOf("/")) || "/", { recursive: true, ...above });
|
|
7822
|
+
await fs.mkdir(path, own);
|
|
7823
|
+
}
|
|
7824
|
+
}
|
|
7737
7825
|
async function chown(entry, path, req) {
|
|
7738
7826
|
const cred = entry.cred?.();
|
|
7739
7827
|
if (!cred) {
|
|
@@ -7766,7 +7854,7 @@ async function run(entry, path, req) {
|
|
|
7766
7854
|
case "readdir-stat":
|
|
7767
7855
|
return json2(await readdirStat(fs, path));
|
|
7768
7856
|
case "mkdir":
|
|
7769
|
-
await fs.mkdir(path, mkdirOptions(entry, req.mode));
|
|
7857
|
+
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
7770
7858
|
return done;
|
|
7771
7859
|
case "rm":
|
|
7772
7860
|
await fs.rm(path, { recursive: true });
|
|
@@ -11318,9 +11406,9 @@ var Dying = class {
|
|
|
11318
11406
|
clear() {
|
|
11319
11407
|
clearTimeout(this.timer);
|
|
11320
11408
|
}
|
|
11321
|
-
status(
|
|
11409
|
+
status(reported2) {
|
|
11322
11410
|
if (this.ending) return [this.ending.code, this.ending.sig];
|
|
11323
|
-
return [typeof
|
|
11411
|
+
return [typeof reported2 === "number" ? reported2 : CRASHED, void 0];
|
|
11324
11412
|
}
|
|
11325
11413
|
};
|
|
11326
11414
|
function killThread(thread, caught, sig) {
|