@ai-ecoverse/slicc-kernel 1.59.1 → 1.60.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 +21 -2
- package/dist/index.js +12 -1
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +159 -24
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node.js +157 -27
- package/dist/node.js.map +3 -3
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -1774,6 +1774,29 @@ function userEnv(account, system) {
|
|
|
1774
1774
|
PATH: `${pnpm}/bin:/usr/local/bin:/usr/bin:/bin`
|
|
1775
1775
|
};
|
|
1776
1776
|
}
|
|
1777
|
+
function groupsOf(groups, names) {
|
|
1778
|
+
return names.map((g) => {
|
|
1779
|
+
const row = groups.find((r) => r.name === g);
|
|
1780
|
+
if (!row) throw fsError("ENOENT", `no group ${g}`);
|
|
1781
|
+
return row;
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
function homeModeOf(mode) {
|
|
1785
|
+
if (mode === void 0) return void 0;
|
|
1786
|
+
if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
|
|
1787
|
+
throw fsError("EINVAL", `not a mode: ${String(mode)}`);
|
|
1788
|
+
}
|
|
1789
|
+
return mode;
|
|
1790
|
+
}
|
|
1791
|
+
function joined(name2, rows) {
|
|
1792
|
+
let changed = false;
|
|
1793
|
+
for (const g of rows) {
|
|
1794
|
+
if (g.members.includes(name2)) continue;
|
|
1795
|
+
g.members.push(name2);
|
|
1796
|
+
changed = true;
|
|
1797
|
+
}
|
|
1798
|
+
return changed;
|
|
1799
|
+
}
|
|
1777
1800
|
function homeGroupOf(groups, name2) {
|
|
1778
1801
|
if (name2 === void 0) return void 0;
|
|
1779
1802
|
const found = groups.find((g) => g.name === name2);
|
|
@@ -1789,14 +1812,14 @@ var UserDb = class {
|
|
|
1789
1812
|
this.fs = fs;
|
|
1790
1813
|
this.owners = owners;
|
|
1791
1814
|
}
|
|
1792
|
-
async stampHome(row, shared) {
|
|
1815
|
+
async stampHome(row, shared, homeMode) {
|
|
1793
1816
|
const home = this.fs.resolvePath("/", row.home);
|
|
1794
1817
|
if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
|
|
1795
1818
|
if (!await this.realDir(home)) return;
|
|
1796
1819
|
const gid = shared?.gid ?? row.gid;
|
|
1797
1820
|
await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
|
|
1798
1821
|
const scoop = row.name.startsWith("scoop-");
|
|
1799
|
-
await this.fs.chmod(home, shared ? 1512 : scoop ? 488 : 448);
|
|
1822
|
+
await this.fs.chmod(home, homeMode ?? (shared ? 1512 : scoop ? 488 : 448));
|
|
1800
1823
|
const pnpm = `${home}/.local/share/pnpm`;
|
|
1801
1824
|
if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
|
|
1802
1825
|
}
|
|
@@ -1910,31 +1933,33 @@ var UserDb = class {
|
|
|
1910
1933
|
const groups = parsed(group);
|
|
1911
1934
|
const found = users.find((r) => r.name === name2);
|
|
1912
1935
|
const shared = homeGroupOf(groups, options.homeGroup);
|
|
1936
|
+
const homeMode = homeModeOf(options.homeMode);
|
|
1913
1937
|
if (found) {
|
|
1938
|
+
const more = groupsOf(groups, options.groups ?? []);
|
|
1939
|
+
if (more.some((g) => g.gid === found.gid)) {
|
|
1940
|
+
throw fsError("EINVAL", `a user is no member of its own group ${name2}`);
|
|
1941
|
+
}
|
|
1914
1942
|
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
|
|
1915
1943
|
await this.provision(found);
|
|
1916
|
-
await this.stampHome(found, shared);
|
|
1944
|
+
await this.stampHome(found, shared, homeMode);
|
|
1917
1945
|
}
|
|
1946
|
+
if (joined(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
1918
1947
|
remember();
|
|
1919
1948
|
return this.account(found, groups);
|
|
1920
1949
|
}
|
|
1921
1950
|
const home = homeOf(options.home ?? `/home/${name2}`);
|
|
1922
|
-
const extra = [USERS_GROUP, ...options.groups ?? []]
|
|
1923
|
-
const row2 = groups.find((r) => r.name === g);
|
|
1924
|
-
if (!row2) throw fsError("ENOENT", `no group ${g}`);
|
|
1925
|
-
return row2;
|
|
1926
|
-
});
|
|
1951
|
+
const extra = groupsOf(groups, [USERS_GROUP, ...options.groups ?? []]);
|
|
1927
1952
|
if (groups.some((r) => r.name === name2)) throw fsError("EEXIST", `group ${name2} exists`);
|
|
1928
1953
|
const uid = freeId(users, groups);
|
|
1929
1954
|
const row = { name: name2, uid, gid: uid, gecos: name2, home, shell: "/bin/bash" };
|
|
1930
|
-
|
|
1955
|
+
joined(name2, extra);
|
|
1931
1956
|
group.push({ name: name2, gid: uid, members: [] });
|
|
1932
1957
|
passwd.push(row);
|
|
1933
1958
|
const fresh = !await this.fs.exists(home);
|
|
1934
1959
|
await this.fs.mkdir(home, { recursive: true });
|
|
1935
1960
|
try {
|
|
1936
1961
|
await this.provision(row);
|
|
1937
|
-
await this.stampHome(row, shared);
|
|
1962
|
+
await this.stampHome(row, shared, homeMode);
|
|
1938
1963
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
1939
1964
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
1940
1965
|
} catch (err) {
|
|
@@ -1945,6 +1970,31 @@ var UserDb = class {
|
|
|
1945
1970
|
return this.account(row, parsed(group));
|
|
1946
1971
|
});
|
|
1947
1972
|
}
|
|
1973
|
+
async groups() {
|
|
1974
|
+
const { group } = await this.tables();
|
|
1975
|
+
return parsed(group).map(({ name: name2, gid, members }) => ({ name: name2, gid, members: [...members] }));
|
|
1976
|
+
}
|
|
1977
|
+
addMember(group, user) {
|
|
1978
|
+
return this.member(group, user, true);
|
|
1979
|
+
}
|
|
1980
|
+
removeMember(group, user) {
|
|
1981
|
+
return this.member(group, user, false);
|
|
1982
|
+
}
|
|
1983
|
+
member(name2, user, on) {
|
|
1984
|
+
return this.serial(async () => {
|
|
1985
|
+
const { passwd, group } = await this.tables();
|
|
1986
|
+
const row = parsed(group).find((g) => g.name === name2);
|
|
1987
|
+
if (!row) throw fsError("ENOENT", `no group ${String(name2)}`);
|
|
1988
|
+
const who = parsed(passwd).find((u) => u.name === user);
|
|
1989
|
+
if (!who) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
1990
|
+
if (who.gid === row.gid) throw fsError("EINVAL", `${name2} is the own group of ${user}`);
|
|
1991
|
+
if (row.members.includes(user) !== on) {
|
|
1992
|
+
row.members = on ? [...row.members, user] : row.members.filter((m) => m !== user);
|
|
1993
|
+
await this.fs.writeFile(GROUP, formatGroup(group));
|
|
1994
|
+
}
|
|
1995
|
+
return { name: row.name, gid: row.gid, members: [...row.members] };
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1948
1998
|
remove(name2, options = {}) {
|
|
1949
1999
|
return this.serial(async () => {
|
|
1950
2000
|
const { passwd, group } = await this.tables();
|
|
@@ -2470,10 +2520,31 @@ var ERRNO_BY_DOM_ERROR = {
|
|
|
2470
2520
|
TypeError: "EINVAL",
|
|
2471
2521
|
NotAllowedError: "EACCES"
|
|
2472
2522
|
};
|
|
2473
|
-
|
|
2523
|
+
var reported = /* @__PURE__ */ new Set();
|
|
2524
|
+
function translate(err, path, op = "lookup", mapped = true) {
|
|
2474
2525
|
if (typeof err?.code === "string") return err;
|
|
2475
|
-
const
|
|
2476
|
-
|
|
2526
|
+
const raw = err?.name;
|
|
2527
|
+
const name2 = typeof raw === "string" ? raw : "Error";
|
|
2528
|
+
const code = mapped && ERRNO_BY_DOM_ERROR[name2] || "EIO";
|
|
2529
|
+
const error = Object.assign(fsError(code, path), { domName: name2, op, cause: err });
|
|
2530
|
+
if (code !== "EIO") return error;
|
|
2531
|
+
const detail = err?.message;
|
|
2532
|
+
error.message += ` (OPFS ${op}: ${name2}${typeof detail === "string" && detail ? `: ${detail}` : ""})`;
|
|
2533
|
+
if (!reported.has(`${name2}/${op}`)) {
|
|
2534
|
+
reported.add(`${name2}/${op}`);
|
|
2535
|
+
console.warn(
|
|
2536
|
+
`slicc-kernel: ${error.message}, reported as EIO; logged once per error and operation`
|
|
2537
|
+
);
|
|
2538
|
+
}
|
|
2539
|
+
return error;
|
|
2540
|
+
}
|
|
2541
|
+
var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
|
|
2542
|
+
function sidecar(meta) {
|
|
2543
|
+
const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
|
|
2544
|
+
const guarded = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
2545
|
+
throw translate(err, pathOf(args), "sidecar", false);
|
|
2546
|
+
});
|
|
2547
|
+
return Object.fromEntries(META_OPS.map((op) => [op, guarded(op)]));
|
|
2477
2548
|
}
|
|
2478
2549
|
function missing(err) {
|
|
2479
2550
|
const code = err?.code;
|
|
@@ -2558,7 +2629,7 @@ var OpfsFs = class {
|
|
|
2558
2629
|
owners = false;
|
|
2559
2630
|
constructor(root, meta = new MemoryMeta(), channel, options = {}) {
|
|
2560
2631
|
this.root = root;
|
|
2561
|
-
this.meta = meta;
|
|
2632
|
+
this.meta = sidecar(meta);
|
|
2562
2633
|
this.ranged = options.ranged === true;
|
|
2563
2634
|
this.channel = channel === void 0 ? void 0 : new BroadcastChannel(channel);
|
|
2564
2635
|
if (this.channel) {
|
|
@@ -2863,7 +2934,8 @@ var OpfsFs = class {
|
|
|
2863
2934
|
} catch (err) {
|
|
2864
2935
|
const name2 = err?.name;
|
|
2865
2936
|
const again = name2 === "NotReadableError" || locks && LOCKED.has(name2);
|
|
2866
|
-
if (!again || attempt >= READ_ATTEMPTS)
|
|
2937
|
+
if (!again || attempt >= READ_ATTEMPTS)
|
|
2938
|
+
throw translate(err, path, locks ? "write" : "read");
|
|
2867
2939
|
await new Promise((resolve) => setTimeout(resolve, attempt * 10));
|
|
2868
2940
|
}
|
|
2869
2941
|
}
|
|
@@ -2905,9 +2977,15 @@ var OpfsFs = class {
|
|
|
2905
2977
|
true
|
|
2906
2978
|
);
|
|
2907
2979
|
return {
|
|
2908
|
-
write: (at, bytes) => writable.write({ type: "write", position: at, data: bytes })
|
|
2909
|
-
|
|
2910
|
-
|
|
2980
|
+
write: (at, bytes) => writable.write({ type: "write", position: at, data: bytes }).catch((err) => {
|
|
2981
|
+
throw translate(err, path, "write", false);
|
|
2982
|
+
}),
|
|
2983
|
+
truncate: (size) => writable.truncate(size).catch((err) => {
|
|
2984
|
+
throw translate(err, path, "write", false);
|
|
2985
|
+
}),
|
|
2986
|
+
close: () => writable.close().catch((err) => {
|
|
2987
|
+
throw translate(err, path, "commit", false);
|
|
2988
|
+
})
|
|
2911
2989
|
};
|
|
2912
2990
|
}
|
|
2913
2991
|
async readFile(path) {
|
|
@@ -2942,9 +3020,13 @@ var OpfsFs = class {
|
|
|
2942
3020
|
const [file, existed, target] = await this.fileFor(path);
|
|
2943
3021
|
if (!existed) await this.stampNew(target, owner, false);
|
|
2944
3022
|
if (!existed && content.length === 0) return;
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
3023
|
+
try {
|
|
3024
|
+
const writable = await file.createWritable();
|
|
3025
|
+
await writable.write(content);
|
|
3026
|
+
await writable.close();
|
|
3027
|
+
} catch (err) {
|
|
3028
|
+
throw translate(err, path, "commit", false);
|
|
3029
|
+
}
|
|
2948
3030
|
}
|
|
2949
3031
|
async listing(path) {
|
|
2950
3032
|
const found = await this.locate(path, true);
|
|
@@ -3220,6 +3302,49 @@ var OpfsFs = class {
|
|
|
3220
3302
|
return removed;
|
|
3221
3303
|
}
|
|
3222
3304
|
};
|
|
3305
|
+
var READS = [
|
|
3306
|
+
"stat",
|
|
3307
|
+
"lstat",
|
|
3308
|
+
"exists",
|
|
3309
|
+
"readFile",
|
|
3310
|
+
"readFileBuffer",
|
|
3311
|
+
"pread",
|
|
3312
|
+
"readdir",
|
|
3313
|
+
"readdirStat",
|
|
3314
|
+
"readlink",
|
|
3315
|
+
"realpath"
|
|
3316
|
+
];
|
|
3317
|
+
var WRITES = [
|
|
3318
|
+
"writeFile",
|
|
3319
|
+
"pwrite",
|
|
3320
|
+
"truncate",
|
|
3321
|
+
"writeSession",
|
|
3322
|
+
"mkdir",
|
|
3323
|
+
"rm",
|
|
3324
|
+
"link",
|
|
3325
|
+
"rename",
|
|
3326
|
+
"symlink",
|
|
3327
|
+
"chmod",
|
|
3328
|
+
"utimes",
|
|
3329
|
+
"lutimes",
|
|
3330
|
+
"chown"
|
|
3331
|
+
];
|
|
3332
|
+
for (const [names, op] of [
|
|
3333
|
+
[READS, "read"],
|
|
3334
|
+
[WRITES, "write"]
|
|
3335
|
+
]) {
|
|
3336
|
+
for (const name2 of names) {
|
|
3337
|
+
const proto = OpfsFs.prototype;
|
|
3338
|
+
const inner = proto[name2];
|
|
3339
|
+
proto[name2] = async function(...args) {
|
|
3340
|
+
try {
|
|
3341
|
+
return await inner.apply(this, args);
|
|
3342
|
+
} catch (err) {
|
|
3343
|
+
throw translate(err, String(args[0]), op, false);
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3223
3348
|
|
|
3224
3349
|
// src/fs/unlinked.ts
|
|
3225
3350
|
var UNLINKED_DIR = ".slicc-unlinked";
|
|
@@ -11041,9 +11166,9 @@ var Dying = class {
|
|
|
11041
11166
|
clear() {
|
|
11042
11167
|
clearTimeout(this.timer);
|
|
11043
11168
|
}
|
|
11044
|
-
status(
|
|
11169
|
+
status(reported2) {
|
|
11045
11170
|
if (this.ending) return [this.ending.code, this.ending.sig];
|
|
11046
|
-
return [typeof
|
|
11171
|
+
return [typeof reported2 === "number" ? reported2 : CRASHED, void 0];
|
|
11047
11172
|
}
|
|
11048
11173
|
};
|
|
11049
11174
|
function killThread(thread, caught, sig) {
|
|
@@ -14831,10 +14956,10 @@ var ByteSource = class {
|
|
|
14831
14956
|
async more() {
|
|
14832
14957
|
const { done: done4, value } = await this.reader.read();
|
|
14833
14958
|
if (done4) return false;
|
|
14834
|
-
const
|
|
14835
|
-
|
|
14836
|
-
|
|
14837
|
-
this.buffered =
|
|
14959
|
+
const joined2 = new Uint8Array(this.buffered.length + value.length);
|
|
14960
|
+
joined2.set(this.buffered);
|
|
14961
|
+
joined2.set(value, this.buffered.length);
|
|
14962
|
+
this.buffered = joined2;
|
|
14838
14963
|
return true;
|
|
14839
14964
|
}
|
|
14840
14965
|
async until(marker) {
|
|
@@ -15522,6 +15647,11 @@ async function createNodeKernel(options = {}) {
|
|
|
15522
15647
|
remove: (name2, options2) => guard(() => launcher.users.remove(name2, options2)),
|
|
15523
15648
|
list: () => guard(() => launcher.users.list())
|
|
15524
15649
|
},
|
|
15650
|
+
groups: {
|
|
15651
|
+
list: () => guard(() => launcher.users.groups()),
|
|
15652
|
+
addMember: (group, user) => guard(() => launcher.users.addMember(group, user)),
|
|
15653
|
+
removeMember: (group, user) => guard(() => launcher.users.removeMember(group, user))
|
|
15654
|
+
},
|
|
15525
15655
|
async connect({ user } = {}) {
|
|
15526
15656
|
if (terminated) throw new Error(TERMINATED);
|
|
15527
15657
|
if (user !== void 0 && !await launcher.users.lookup(user)) {
|