@ai-ecoverse/slicc-kernel 1.83.0 → 1.84.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 +10 -3
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +208 -45
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +27 -5
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +289 -68
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +27 -5
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -448,8 +448,8 @@ async function inParent(g, op, path, old = false) {
|
|
|
448
448
|
if (!old) return void await need(g, op, parentOf(path), W_OK | X_OK, DIR, path);
|
|
449
449
|
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, DIR);
|
|
450
450
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
451
|
-
const
|
|
452
|
-
if (!
|
|
451
|
+
const lookup3 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
452
|
+
if (!lookup3 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
453
453
|
}
|
|
454
454
|
async function makeIn(g, op, path) {
|
|
455
455
|
for (let dir = parentOf(path); ; dir = parentOf(dir)) {
|
|
@@ -3022,6 +3022,9 @@ var MemoryMeta = class {
|
|
|
3022
3022
|
async remove(paths) {
|
|
3023
3023
|
for (const path of paths) this.entries.deleteTree(path);
|
|
3024
3024
|
}
|
|
3025
|
+
absent(path) {
|
|
3026
|
+
return !this.entries.has(path);
|
|
3027
|
+
}
|
|
3025
3028
|
async links(dir) {
|
|
3026
3029
|
return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);
|
|
3027
3030
|
}
|
|
@@ -3467,10 +3470,17 @@ function translate(err, path, op = "lookup", mapped = true) {
|
|
|
3467
3470
|
var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
|
|
3468
3471
|
function sidecar(meta) {
|
|
3469
3472
|
const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
|
|
3470
|
-
const
|
|
3473
|
+
const guarded3 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
3471
3474
|
throw translate(err, pathOf(args), "sidecar", false);
|
|
3472
3475
|
});
|
|
3473
|
-
|
|
3476
|
+
const ops = Object.fromEntries(META_OPS.map((op) => [op, guarded3(op)]));
|
|
3477
|
+
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
3478
|
+
const { removeFile } = meta;
|
|
3479
|
+
if (removeFile)
|
|
3480
|
+
ops.removeFile = (path) => removeFile.call(meta, path).catch((err) => {
|
|
3481
|
+
throw translate(err, path, "sidecar", false);
|
|
3482
|
+
});
|
|
3483
|
+
return ops;
|
|
3474
3484
|
}
|
|
3475
3485
|
function missing2(err) {
|
|
3476
3486
|
const code = err?.code;
|
|
@@ -4163,6 +4173,7 @@ var OpfsFs = class {
|
|
|
4163
4173
|
throw error;
|
|
4164
4174
|
}
|
|
4165
4175
|
this.refuse(found.path, true);
|
|
4176
|
+
if (options.file && found.handle?.kind === "directory") throw fsError("EISDIR", path);
|
|
4166
4177
|
if (found.handle) {
|
|
4167
4178
|
const [dir, name2] = await this.parent(found.path);
|
|
4168
4179
|
try {
|
|
@@ -4173,8 +4184,19 @@ var OpfsFs = class {
|
|
|
4173
4184
|
} catch (err) {
|
|
4174
4185
|
throw translate(err, path);
|
|
4175
4186
|
}
|
|
4176
|
-
|
|
4187
|
+
const file = found.handle.kind === "file";
|
|
4188
|
+
if (!file || this.remote?.watched()) this.changed(found.path);
|
|
4189
|
+
else this.forget(found.path);
|
|
4177
4190
|
this.movePending(found.path);
|
|
4191
|
+
if (file && this.meta.absent?.(found.path)) {
|
|
4192
|
+
this.touch(parentOf4(found.path));
|
|
4193
|
+
return;
|
|
4194
|
+
}
|
|
4195
|
+
if (file && this.meta.removeFile) {
|
|
4196
|
+
await this.meta.removeFile(found.path);
|
|
4197
|
+
this.touch(parentOf4(found.path));
|
|
4198
|
+
return;
|
|
4199
|
+
}
|
|
4178
4200
|
}
|
|
4179
4201
|
await this.meta.remove([found.path]);
|
|
4180
4202
|
this.touch(parentOf4(found.path));
|
|
@@ -5907,9 +5929,13 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
5907
5929
|
// src/fs/fresh-modules.ts
|
|
5908
5930
|
var MAGIC = [0, 97, 115, 109];
|
|
5909
5931
|
var MAX_FRESH = 65536;
|
|
5932
|
+
var DEFAULT_UMASK = 18;
|
|
5910
5933
|
function isModule(bytes) {
|
|
5911
5934
|
return MAGIC.every((b, i) => bytes[i] === b);
|
|
5912
5935
|
}
|
|
5936
|
+
function within4(path, dir) {
|
|
5937
|
+
return path.startsWith(dir === "/" ? "/" : `${dir}/`);
|
|
5938
|
+
}
|
|
5913
5939
|
var FreshModules = class {
|
|
5914
5940
|
fresh = /* @__PURE__ */ new Map();
|
|
5915
5941
|
add(path, umask, pid) {
|
|
@@ -5917,17 +5943,40 @@ var FreshModules = class {
|
|
|
5917
5943
|
this.fresh.delete(key);
|
|
5918
5944
|
const oldest = this.fresh.size >= MAX_FRESH ? this.fresh.keys().next().value : void 0;
|
|
5919
5945
|
if (oldest !== void 0) this.fresh.delete(oldest);
|
|
5920
|
-
|
|
5946
|
+
const mask = umask & 511;
|
|
5947
|
+
this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
|
|
5921
5948
|
}
|
|
5922
5949
|
forget(pid) {
|
|
5923
5950
|
for (const [path, fresh2] of this.fresh) if (fresh2.pid === pid) this.fresh.delete(path);
|
|
5924
5951
|
}
|
|
5952
|
+
drop(fresh2) {
|
|
5953
|
+
for (const [key, note] of [...this.fresh]) if (note === fresh2) this.fresh.delete(key);
|
|
5954
|
+
}
|
|
5955
|
+
moved(from, to) {
|
|
5956
|
+
const source = normalizePath(from);
|
|
5957
|
+
const target = normalizePath(to);
|
|
5958
|
+
if (source === target) return;
|
|
5959
|
+
for (const key of [...this.fresh.keys()]) {
|
|
5960
|
+
if (key === target || within4(key, target)) this.fresh.delete(key);
|
|
5961
|
+
}
|
|
5962
|
+
for (const [key, fresh2] of [...this.fresh]) {
|
|
5963
|
+
if (key !== source && !within4(key, source)) continue;
|
|
5964
|
+
this.fresh.delete(key);
|
|
5965
|
+
this.fresh.set(target + key.slice(source.length), fresh2);
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5925
5968
|
wrap(fs) {
|
|
5926
|
-
const
|
|
5969
|
+
const head = async (path) => {
|
|
5970
|
+
if (fs.pread) return fs.pread(path, 0, MAGIC.length);
|
|
5971
|
+
return (await fs.readFileBuffer(path)).subarray(0, MAGIC.length);
|
|
5972
|
+
};
|
|
5973
|
+
const decide = async (given, known) => {
|
|
5927
5974
|
const path = normalizePath(given);
|
|
5928
5975
|
const fresh2 = this.fresh.get(path);
|
|
5929
|
-
if (!fresh2
|
|
5976
|
+
if (!fresh2) return;
|
|
5977
|
+
const bytes = known && known.length >= MAGIC.length ? known : await head(path);
|
|
5930
5978
|
const want = isModule(bytes) ? 73 & ~fresh2.umask : 0;
|
|
5979
|
+
fresh2.setup = false;
|
|
5931
5980
|
if (want === fresh2.added) return;
|
|
5932
5981
|
const mode = (await fs.stat(path)).mode & 4095;
|
|
5933
5982
|
await fs.chmod(path, mode & ~fresh2.added | want);
|
|
@@ -5936,32 +5985,47 @@ var FreshModules = class {
|
|
|
5936
5985
|
const overrides = {
|
|
5937
5986
|
writeFile: async (path, content, owner) => {
|
|
5938
5987
|
await fs.writeFile(path, content, owner);
|
|
5939
|
-
|
|
5988
|
+
if (this.fresh.has(normalizePath(path))) {
|
|
5989
|
+
await decide(
|
|
5990
|
+
path,
|
|
5991
|
+
typeof content === "string" ? new TextEncoder().encode(content) : content
|
|
5992
|
+
);
|
|
5993
|
+
}
|
|
5940
5994
|
},
|
|
5941
5995
|
chmod: async (path, mode) => {
|
|
5942
5996
|
const fresh2 = this.fresh.get(normalizePath(path));
|
|
5943
|
-
|
|
5944
|
-
if (
|
|
5997
|
+
if (fresh2?.setup && (mode & 4095) === (438 & ~fresh2.umask)) fresh2.setup = false;
|
|
5998
|
+
else if (fresh2) this.drop(fresh2);
|
|
5945
5999
|
await fs.chmod(path, mode);
|
|
5946
6000
|
},
|
|
5947
6001
|
rm: async (path, options) => {
|
|
5948
|
-
this.fresh.delete(normalizePath(path));
|
|
5949
6002
|
await fs.rm(path, options);
|
|
6003
|
+
const at = normalizePath(path);
|
|
6004
|
+
for (const key of [...this.fresh.keys()]) {
|
|
6005
|
+
if (key === at || within4(key, at)) this.fresh.delete(key);
|
|
6006
|
+
}
|
|
5950
6007
|
},
|
|
5951
6008
|
rename: async (from, to) => {
|
|
5952
6009
|
await fs.rename(from, to);
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
6010
|
+
this.moved(from, to);
|
|
6011
|
+
},
|
|
6012
|
+
link: async (from, to, follow2) => {
|
|
6013
|
+
await fs.link(from, to, follow2);
|
|
6014
|
+
const source = follow2 && fs.realpath ? await fs.realpath(from, true) : from;
|
|
6015
|
+
const fresh2 = this.fresh.get(normalizePath(source));
|
|
5956
6016
|
if (fresh2) this.fresh.set(normalizePath(to), fresh2);
|
|
5957
6017
|
}
|
|
5958
6018
|
};
|
|
5959
6019
|
const ranged2 = rangedOps(fs);
|
|
5960
6020
|
if (ranged2) {
|
|
5961
6021
|
overrides.pwrite = async (path, at, bytes, transfer) => {
|
|
5962
|
-
const
|
|
6022
|
+
const touches2 = at < MAGIC.length && this.fresh.has(normalizePath(path));
|
|
5963
6023
|
await ranged2.pwrite(path, at, bytes, transfer);
|
|
5964
|
-
if (
|
|
6024
|
+
if (touches2) await decide(path);
|
|
6025
|
+
};
|
|
6026
|
+
overrides.truncate = async (path, size) => {
|
|
6027
|
+
await ranged2.truncate(path, size);
|
|
6028
|
+
if (size < MAGIC.length && this.fresh.has(normalizePath(path))) await decide(path);
|
|
5965
6029
|
};
|
|
5966
6030
|
}
|
|
5967
6031
|
const bound2 = /* @__PURE__ */ new WeakMap();
|
|
@@ -6701,7 +6765,7 @@ function parseSize(text) {
|
|
|
6701
6765
|
if (!match) throw errnoError("EINVAL", `not a size: ${text}`);
|
|
6702
6766
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
6703
6767
|
}
|
|
6704
|
-
var
|
|
6768
|
+
var within5 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
6705
6769
|
var HeldSet = class extends Set {
|
|
6706
6770
|
idle;
|
|
6707
6771
|
constructor(idle) {
|
|
@@ -6720,7 +6784,7 @@ var HeldSet = class extends Set {
|
|
|
6720
6784
|
}
|
|
6721
6785
|
};
|
|
6722
6786
|
function heldUnder(held, target) {
|
|
6723
|
-
for (const paths of held) for (const path of paths.keys()) if (
|
|
6787
|
+
for (const paths of held) for (const path of paths.keys()) if (within5(path, target)) return true;
|
|
6724
6788
|
return false;
|
|
6725
6789
|
}
|
|
6726
6790
|
var HeldPaths = class extends Map {
|
|
@@ -6836,24 +6900,24 @@ var HeldPaths = class extends Map {
|
|
|
6836
6900
|
return this.owning === path;
|
|
6837
6901
|
}
|
|
6838
6902
|
revoke(prefix) {
|
|
6839
|
-
for (const path of this.keys()) if (
|
|
6903
|
+
for (const path of this.keys()) if (within5(path, prefix)) this.revoked.add(path);
|
|
6840
6904
|
}
|
|
6841
6905
|
renamed(from, to) {
|
|
6842
6906
|
for (const [path, count2] of [...this]) {
|
|
6843
|
-
if (!
|
|
6907
|
+
if (!within5(path, from)) continue;
|
|
6844
6908
|
const moved2 = to + path.slice(from.length);
|
|
6845
6909
|
this.delete(path);
|
|
6846
6910
|
this.set(moved2, (this.get(moved2) ?? 0) + count2);
|
|
6847
6911
|
if (this.revoked.delete(path)) this.revoked.add(moved2);
|
|
6848
6912
|
}
|
|
6849
6913
|
for (const [path, count2] of [...this.opens]) {
|
|
6850
|
-
if (!
|
|
6914
|
+
if (!within5(path, from)) continue;
|
|
6851
6915
|
const moved2 = to + path.slice(from.length);
|
|
6852
6916
|
this.opens.delete(path);
|
|
6853
6917
|
this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count2);
|
|
6854
6918
|
}
|
|
6855
6919
|
for (const [id2, key] of this.handles) {
|
|
6856
|
-
if (
|
|
6920
|
+
if (within5(key, from)) this.handles.set(id2, to + key.slice(from.length));
|
|
6857
6921
|
}
|
|
6858
6922
|
}
|
|
6859
6923
|
isRevoked(path) {
|
|
@@ -6957,10 +7021,14 @@ var MountTable = class {
|
|
|
6957
7021
|
...error ? { error } : {}
|
|
6958
7022
|
});
|
|
6959
7023
|
}
|
|
7024
|
+
under(path) {
|
|
7025
|
+
for (const mount of this.mounts.values()) if (within5(mount.target, path)) return true;
|
|
7026
|
+
return false;
|
|
7027
|
+
}
|
|
6960
7028
|
locate(path) {
|
|
6961
7029
|
let best;
|
|
6962
7030
|
for (const mount of this.mounts.values()) {
|
|
6963
|
-
if (
|
|
7031
|
+
if (within5(path, mount.target) && (!best || mount.target.length > best.target.length))
|
|
6964
7032
|
best = mount;
|
|
6965
7033
|
}
|
|
6966
7034
|
if (!best) return void 0;
|
|
@@ -7103,7 +7171,7 @@ var MountTable = class {
|
|
|
7103
7171
|
async commitUnder(prefix) {
|
|
7104
7172
|
const at = normalizePath(prefix);
|
|
7105
7173
|
await Promise.all(
|
|
7106
|
-
[...this.sessions.keys()].filter((p) =>
|
|
7174
|
+
[...this.sessions.keys()].filter((p) => within5(p, at)).map((p) => this.commit(p))
|
|
7107
7175
|
);
|
|
7108
7176
|
}
|
|
7109
7177
|
async commitOverlapping(real, offset, length2) {
|
|
@@ -7138,10 +7206,10 @@ var MountTable = class {
|
|
|
7138
7206
|
}
|
|
7139
7207
|
forget(mount, path) {
|
|
7140
7208
|
mount.epoch++;
|
|
7141
|
-
for (const key of [...mount.attrs.keys()]) if (
|
|
7209
|
+
for (const key of [...mount.attrs.keys()]) if (within5(key, path)) mount.attrs.delete(key);
|
|
7142
7210
|
mount.lists.delete(path);
|
|
7143
7211
|
mount.lists.delete(parentOf7(path));
|
|
7144
|
-
for (const key of [...mount.lists.keys()]) if (
|
|
7212
|
+
for (const key of [...mount.lists.keys()]) if (within5(key, path)) mount.lists.delete(key);
|
|
7145
7213
|
}
|
|
7146
7214
|
async getattr(mount, path, rel2, settled = false) {
|
|
7147
7215
|
for (let round = 1; ; round++) {
|
|
@@ -7526,9 +7594,12 @@ var MountFs = class {
|
|
|
7526
7594
|
}
|
|
7527
7595
|
async rm(path, options = {}) {
|
|
7528
7596
|
const found = this.at(path);
|
|
7597
|
+
if (!found && options.recursive && this.table.under(normalizePath(path)))
|
|
7598
|
+
return this.rmAround(normalizePath(path), options);
|
|
7529
7599
|
if (!found) return this.base.rm(path, options);
|
|
7530
7600
|
const { mount, rel: rel2 } = found;
|
|
7531
7601
|
const real = normalizePath(path);
|
|
7602
|
+
if (rel2 === "/" && options.recursive) await this.rmEach(real, mount, rel2, options);
|
|
7532
7603
|
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
7533
7604
|
this.writable(mount, real);
|
|
7534
7605
|
await this.table.commitUnder(real);
|
|
@@ -7539,16 +7610,33 @@ var MountFs = class {
|
|
|
7539
7610
|
if (options.force && err.code === "ENOENT") return;
|
|
7540
7611
|
throw err;
|
|
7541
7612
|
}
|
|
7613
|
+
if (options.file && attr2.kind === "directory") throw errnoError("EISDIR", real);
|
|
7542
7614
|
this.table.forget(mount, real);
|
|
7543
7615
|
if (attr2.kind === "directory" && options.recursive) {
|
|
7544
|
-
|
|
7545
|
-
await this.rm(`${real}/${entry.name}`, { recursive: true, force: options.force ?? false });
|
|
7546
|
-
}
|
|
7616
|
+
await this.rmEach(real, mount, rel2, { recursive: true, force: options.force ?? false });
|
|
7547
7617
|
this.table.forget(mount, real);
|
|
7548
7618
|
}
|
|
7549
7619
|
await mount.conn.call({ op: attr2.kind === "directory" ? "rmdir" : "unlink", path: rel2 });
|
|
7550
7620
|
this.table.forget(mount, real);
|
|
7551
7621
|
}
|
|
7622
|
+
async rmEach(real, mount, rel2, options) {
|
|
7623
|
+
let first;
|
|
7624
|
+
for (const entry of await this.table.readdir(mount, real, rel2)) {
|
|
7625
|
+
await this.rm(joinName(real, entry.name), options).catch((err) => {
|
|
7626
|
+
first ??= err;
|
|
7627
|
+
});
|
|
7628
|
+
}
|
|
7629
|
+
if (first) throw first;
|
|
7630
|
+
}
|
|
7631
|
+
async rmAround(path, options) {
|
|
7632
|
+
let first;
|
|
7633
|
+
for (const name2 of await this.base.readdir(path)) {
|
|
7634
|
+
await this.rm(joinName(path, name2), options).catch((err) => {
|
|
7635
|
+
first ??= err;
|
|
7636
|
+
});
|
|
7637
|
+
}
|
|
7638
|
+
throw first ?? errnoError("EBUSY", `${path} holds a mount point`);
|
|
7639
|
+
}
|
|
7552
7640
|
async rename(from, to) {
|
|
7553
7641
|
const a = this.at(from);
|
|
7554
7642
|
const b = this.at(to);
|
|
@@ -7776,6 +7864,11 @@ function statJson(s) {
|
|
|
7776
7864
|
async function readdirStat(fs, dir) {
|
|
7777
7865
|
return (await fs.readdirStat(dir)).map(([name2, stat]) => [name2, stat && statJson(stat)]);
|
|
7778
7866
|
}
|
|
7867
|
+
async function usageAt(entry, path) {
|
|
7868
|
+
if (!entry.statfs) return void 0;
|
|
7869
|
+
const real = await realTarget(entry.fs, path).catch(() => path);
|
|
7870
|
+
return entry.statfs(real);
|
|
7871
|
+
}
|
|
7779
7872
|
async function storageUsage() {
|
|
7780
7873
|
const estimate = await globalThis.navigator?.storage?.estimate?.();
|
|
7781
7874
|
if (typeof estimate?.quota !== "number") return null;
|
|
@@ -7847,8 +7940,7 @@ async function run(entry, path, req) {
|
|
|
7847
7940
|
await fs.link(path, fs.resolvePath(cwd, req.arg2 ?? ""), req.mode === 1);
|
|
7848
7941
|
return done;
|
|
7849
7942
|
case "unlink":
|
|
7850
|
-
|
|
7851
|
-
await fs.rm(path);
|
|
7943
|
+
await fs.rm(path, { file: true });
|
|
7852
7944
|
return done;
|
|
7853
7945
|
case "rmdir":
|
|
7854
7946
|
if (!(await fs.lstat(path)).isDirectory) throw syncError("ENOTDIR", path);
|
|
@@ -7996,8 +8088,8 @@ async function guarded(entry, path, req) {
|
|
|
7996
8088
|
await guard(g, path, req, entry.cwd);
|
|
7997
8089
|
return void 0;
|
|
7998
8090
|
} catch (err) {
|
|
7999
|
-
const
|
|
8000
|
-
return req.op === "exists" &&
|
|
8091
|
+
const refusal2 = err.code === "EACCES";
|
|
8092
|
+
return req.op === "exists" && refusal2 ? json2(false) : toErrno(err);
|
|
8001
8093
|
}
|
|
8002
8094
|
}
|
|
8003
8095
|
async function createExclusive(fs, path, owner) {
|
|
@@ -8082,6 +8174,26 @@ async function dispatchSyncFs(req) {
|
|
|
8082
8174
|
return toErrno(err);
|
|
8083
8175
|
}
|
|
8084
8176
|
}
|
|
8177
|
+
var DENIED = /* @__PURE__ */ new Set(["EACCES", "EPERM"]);
|
|
8178
|
+
async function rmPermitted(entry, path, req, refused2) {
|
|
8179
|
+
const st = await entry.fs.lstat(path).catch(() => void 0);
|
|
8180
|
+
if (!st?.isDirectory) return refused2;
|
|
8181
|
+
const unlisted = await guarded(entry, path, { ...req, op: "readdir" });
|
|
8182
|
+
if (unlisted) return unlisted;
|
|
8183
|
+
const names = await entry.fs.readdir(path).catch(() => void 0);
|
|
8184
|
+
if (!names) return refused2;
|
|
8185
|
+
let first;
|
|
8186
|
+
for (const name2 of names) {
|
|
8187
|
+
const child = await dispatchOne(entry, {
|
|
8188
|
+
...req,
|
|
8189
|
+
path: joinName(path, name2)
|
|
8190
|
+
});
|
|
8191
|
+
if (!child.ok) first ??= child;
|
|
8192
|
+
}
|
|
8193
|
+
if (first) return first;
|
|
8194
|
+
const again = await guarded(entry, path, req);
|
|
8195
|
+
return again ?? await run(entry, path, req);
|
|
8196
|
+
}
|
|
8085
8197
|
async function dispatchOne(entry, req) {
|
|
8086
8198
|
const { fs, cwd } = entry;
|
|
8087
8199
|
try {
|
|
@@ -8091,8 +8203,11 @@ async function dispatchOne(entry, req) {
|
|
|
8091
8203
|
if (req.op === "access") return await accessOp(entry, path, req);
|
|
8092
8204
|
if (req.op === "hold") return await holdOp(entry, path, req);
|
|
8093
8205
|
const refused2 = await guarded(entry, path, req);
|
|
8206
|
+
if (refused2 && req.op === "rm" && !refused2.ok && DENIED.has(refused2.errno)) {
|
|
8207
|
+
return await rmPermitted(entry, path, req, refused2);
|
|
8208
|
+
}
|
|
8094
8209
|
if (refused2) return refused2;
|
|
8095
|
-
if (req.op === "statfs") return json2(await entry
|
|
8210
|
+
if (req.op === "statfs") return json2(await usageAt(entry, path) ?? await storageUsage());
|
|
8096
8211
|
if (entry.revoked?.(path)) return { ok: false, errno: "EIO", message: `${path} was unmounted` };
|
|
8097
8212
|
if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
|
|
8098
8213
|
const serve = async () => run(entry, await keptOr(entry, path, req.handle), req);
|
|
@@ -10776,7 +10891,7 @@ function parsePrefix(text) {
|
|
|
10776
10891
|
if (length2 < 0 || length2 > max) return void 0;
|
|
10777
10892
|
return { ...parsed2, length: length2 };
|
|
10778
10893
|
}
|
|
10779
|
-
function
|
|
10894
|
+
function within6(prefix, addr) {
|
|
10780
10895
|
if (prefix.v6 !== addr.v6) return false;
|
|
10781
10896
|
const shift = BigInt((prefix.v6 ? 128 : 32) - prefix.length);
|
|
10782
10897
|
return addr.bits >> shift === prefix.bits >> shift;
|
|
@@ -10816,9 +10931,9 @@ var Routes = class {
|
|
|
10816
10931
|
if (!addr) return "unreachable";
|
|
10817
10932
|
if (addr.v6 && addr.bits === 1n) return "loopback";
|
|
10818
10933
|
if (!addr.v6 && addr.bits >> 24n === 127n) return "loopback";
|
|
10819
|
-
if (RESERVED.some((p) =>
|
|
10934
|
+
if (RESERVED.some((p) => within6(p, addr))) return "reserved";
|
|
10820
10935
|
if (addr.v6 && !this.ipv6) return "unreachable";
|
|
10821
|
-
if (this.exit || this.table.some((p) =>
|
|
10936
|
+
if (this.exit || this.table.some((p) => within6(p, addr))) return "uplink";
|
|
10822
10937
|
return "unreachable";
|
|
10823
10938
|
}
|
|
10824
10939
|
};
|
|
@@ -10884,14 +10999,14 @@ var Resolver = class {
|
|
|
10884
10999
|
if (hit && hit.expires > this.now()) return hit.addresses;
|
|
10885
11000
|
const signal = blocking?.();
|
|
10886
11001
|
if (signal?.aborted) throw new KernelError("EINTR");
|
|
10887
|
-
let
|
|
10888
|
-
if (!
|
|
11002
|
+
let lookup3 = this.pending.get(id2);
|
|
11003
|
+
if (!lookup3) {
|
|
10889
11004
|
const abort = new AbortController();
|
|
10890
|
-
|
|
10891
|
-
this.pending.set(id2,
|
|
10892
|
-
void
|
|
11005
|
+
lookup3 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
|
|
11006
|
+
this.pending.set(id2, lookup3);
|
|
11007
|
+
void lookup3.work.then(() => this.pending.delete(id2));
|
|
10893
11008
|
}
|
|
10894
|
-
return waitFor(
|
|
11009
|
+
return waitFor(lookup3, signal);
|
|
10895
11010
|
}
|
|
10896
11011
|
async lookup(name2, family, id2, abandoned) {
|
|
10897
11012
|
const uplink = this.uplink;
|
|
@@ -10932,17 +11047,17 @@ var Resolver = class {
|
|
|
10932
11047
|
}
|
|
10933
11048
|
}
|
|
10934
11049
|
};
|
|
10935
|
-
function waitFor(
|
|
10936
|
-
|
|
11050
|
+
function waitFor(lookup3, signal) {
|
|
11051
|
+
lookup3.waiters++;
|
|
10937
11052
|
return new Promise((resolve2, reject) => {
|
|
10938
11053
|
const abort = () => {
|
|
10939
|
-
if (--
|
|
11054
|
+
if (--lookup3.waiters === 0) lookup3.abort.abort(new KernelError("EINTR"));
|
|
10940
11055
|
reject(new KernelError("EINTR"));
|
|
10941
11056
|
};
|
|
10942
11057
|
signal?.addEventListener("abort", abort, { once: true });
|
|
10943
|
-
void
|
|
11058
|
+
void lookup3.work.then((value) => {
|
|
10944
11059
|
if (signal?.aborted) return;
|
|
10945
|
-
|
|
11060
|
+
lookup3.waiters--;
|
|
10946
11061
|
signal?.removeEventListener("abort", abort);
|
|
10947
11062
|
resolve2(value);
|
|
10948
11063
|
});
|
|
@@ -11674,7 +11789,7 @@ function isMissing(err) {
|
|
|
11674
11789
|
if (err?.code === "ENOENT") return true;
|
|
11675
11790
|
return err instanceof Error && err.message.startsWith("ENOENT");
|
|
11676
11791
|
}
|
|
11677
|
-
function
|
|
11792
|
+
function within7(path, root) {
|
|
11678
11793
|
return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
|
|
11679
11794
|
}
|
|
11680
11795
|
var VfsNode = class {
|
|
@@ -11995,12 +12110,12 @@ var VfsNodes = class {
|
|
|
11995
12110
|
return node;
|
|
11996
12111
|
}
|
|
11997
12112
|
holds(prefix) {
|
|
11998
|
-
for (const path of this.byPath.keys()) if (
|
|
12113
|
+
for (const path of this.byPath.keys()) if (within7(path, prefix)) return true;
|
|
11999
12114
|
return false;
|
|
12000
12115
|
}
|
|
12001
12116
|
writes(prefix) {
|
|
12002
12117
|
for (const [path, node] of this.byPath)
|
|
12003
|
-
if (node.writers > 0 &&
|
|
12118
|
+
if (node.writers > 0 && within7(path, prefix)) return true;
|
|
12004
12119
|
return false;
|
|
12005
12120
|
}
|
|
12006
12121
|
closed(node, writable2 = false) {
|
|
@@ -12044,11 +12159,11 @@ var VfsNodes = class {
|
|
|
12044
12159
|
this.kept.delete(node);
|
|
12045
12160
|
}
|
|
12046
12161
|
async flush(path) {
|
|
12047
|
-
for (const [p, node] of this.byPath) if (
|
|
12162
|
+
for (const [p, node] of this.byPath) if (within7(p, path)) await node.serial(() => node.flush());
|
|
12048
12163
|
}
|
|
12049
12164
|
async unlinking(path) {
|
|
12050
12165
|
for (const [held, node] of [...this.byPath]) {
|
|
12051
|
-
if (!
|
|
12166
|
+
if (!within7(held, path)) continue;
|
|
12052
12167
|
await node.serial(async () => {
|
|
12053
12168
|
await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
|
|
12054
12169
|
});
|
|
@@ -12056,14 +12171,14 @@ var VfsNodes = class {
|
|
|
12056
12171
|
}
|
|
12057
12172
|
revoke(prefix) {
|
|
12058
12173
|
for (const [path, node] of [...this.byPath]) {
|
|
12059
|
-
if (!
|
|
12174
|
+
if (!within7(path, prefix)) continue;
|
|
12060
12175
|
node.revoke();
|
|
12061
12176
|
this.forget(node);
|
|
12062
12177
|
}
|
|
12063
12178
|
}
|
|
12064
12179
|
unlinked(path) {
|
|
12065
12180
|
for (const [held, node] of [...this.byPath]) {
|
|
12066
|
-
if (!
|
|
12181
|
+
if (!within7(held, path) || this.byPath.get(held) !== node) continue;
|
|
12067
12182
|
if (!this.dropName(held, node)) this.orphan(node);
|
|
12068
12183
|
}
|
|
12069
12184
|
}
|
|
@@ -12071,8 +12186,8 @@ var VfsNodes = class {
|
|
|
12071
12186
|
if (from === to) return;
|
|
12072
12187
|
const moved2 = [];
|
|
12073
12188
|
for (const [p, node] of [...this.byPath]) {
|
|
12074
|
-
if (
|
|
12075
|
-
else if (
|
|
12189
|
+
if (within7(p, from)) moved2.push([p, node]);
|
|
12190
|
+
else if (within7(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
|
|
12076
12191
|
this.orphan(node);
|
|
12077
12192
|
}
|
|
12078
12193
|
}
|
|
@@ -12351,7 +12466,7 @@ function isWasmSyscall(req) {
|
|
|
12351
12466
|
var MAX_READ = 1024 * 1024;
|
|
12352
12467
|
var WRITE_ACCESS = 3;
|
|
12353
12468
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
12354
|
-
var
|
|
12469
|
+
var DEFAULT_UMASK2 = 18;
|
|
12355
12470
|
function words(value) {
|
|
12356
12471
|
if (!Array.isArray(value) || !value.every((w) => typeof w === "string")) {
|
|
12357
12472
|
throw new KernelError("EINVAL");
|
|
@@ -12379,7 +12494,7 @@ var WasmProcess = class {
|
|
|
12379
12494
|
interrupt = new AbortController();
|
|
12380
12495
|
gone = new AbortController();
|
|
12381
12496
|
dying = false;
|
|
12382
|
-
umask =
|
|
12497
|
+
umask = DEFAULT_UMASK2;
|
|
12383
12498
|
cred;
|
|
12384
12499
|
execChild;
|
|
12385
12500
|
killed = false;
|
|
@@ -12401,7 +12516,7 @@ var WasmProcess = class {
|
|
|
12401
12516
|
this.fds = fds;
|
|
12402
12517
|
this.options = options;
|
|
12403
12518
|
this.inherited = options.ignored ?? 0;
|
|
12404
|
-
this.umask = options.umask ??
|
|
12519
|
+
this.umask = options.umask ?? DEFAULT_UMASK2;
|
|
12405
12520
|
this.cred = copyCred(options.cred ?? ROOT);
|
|
12406
12521
|
this.children = new ChildTable(fds, options.spawner, options.forker);
|
|
12407
12522
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
@@ -18087,7 +18202,7 @@ var Launcher = class {
|
|
|
18087
18202
|
}
|
|
18088
18203
|
}
|
|
18089
18204
|
umaskOf(pid) {
|
|
18090
|
-
return this.processes.get(pid)?.umask?.() ??
|
|
18205
|
+
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK2;
|
|
18091
18206
|
}
|
|
18092
18207
|
imageOf(pid) {
|
|
18093
18208
|
const members = this.jobs.list();
|
|
@@ -18597,6 +18712,111 @@ var Launcher = class {
|
|
|
18597
18712
|
}
|
|
18598
18713
|
};
|
|
18599
18714
|
|
|
18715
|
+
// src/node/loopback.ts
|
|
18716
|
+
import { lookup } from "node:dns/promises";
|
|
18717
|
+
import { isIP } from "node:net";
|
|
18718
|
+
var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
|
|
18719
|
+
var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
|
|
18720
|
+
var resolveHost = async (host) => (await lookup(host, { all: true, verbatim: true })).map((a) => a.address);
|
|
18721
|
+
function ipv4Place(address) {
|
|
18722
|
+
const [a, b] = address.split(".").map(Number);
|
|
18723
|
+
if (a === 127 || a === 0) return "loopback";
|
|
18724
|
+
if (a === 169 && b === 254) return "link-local";
|
|
18725
|
+
return void 0;
|
|
18726
|
+
}
|
|
18727
|
+
function placeOf(address) {
|
|
18728
|
+
const plain = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
|
|
18729
|
+
const kind = isIP(plain);
|
|
18730
|
+
if (kind === 4) return ipv4Place(plain);
|
|
18731
|
+
if (kind !== 6) return void 0;
|
|
18732
|
+
const words2 = hextets2(plain);
|
|
18733
|
+
const embedded2 = words2.slice(0, 5).every((w) => w === 0) && (words2[5] === 65535 || words2[5] === 0);
|
|
18734
|
+
if (embedded2 && (words2[5] === 65535 || words2[6] !== 0)) return ipv4Place(ipv4Of(words2));
|
|
18735
|
+
if (words2.slice(0, 7).every((w) => w === 0) && (words2[7] ?? 0) <= 1) return "loopback";
|
|
18736
|
+
if (((words2[0] ?? 0) & 65472) === 65152) return "link-local";
|
|
18737
|
+
if (words2.join(":") === METADATA_V6) return "link-local";
|
|
18738
|
+
return void 0;
|
|
18739
|
+
}
|
|
18740
|
+
function ipv4Of(words2) {
|
|
18741
|
+
const [high = 0, low = 0] = words2.slice(6);
|
|
18742
|
+
return [high >> 8, high & 255, low >> 8, low & 255].join(".");
|
|
18743
|
+
}
|
|
18744
|
+
function hextets2(address) {
|
|
18745
|
+
const dotted = /(\d+\.\d+\.\d+\.\d+)$/.exec(address)?.[1];
|
|
18746
|
+
let text = address;
|
|
18747
|
+
if (dotted) {
|
|
18748
|
+
const [a, b, c, d] = dotted.split(".").map(Number);
|
|
18749
|
+
text = `${address.slice(0, -dotted.length)}${(a << 8 | b).toString(16)}:${(c << 8 | d).toString(16)}`;
|
|
18750
|
+
}
|
|
18751
|
+
const [head = "", tail] = text.split("::");
|
|
18752
|
+
const part = (side) => side ? side.split(":").map((w) => Number.parseInt(w, 16)) : [];
|
|
18753
|
+
const left = part(head);
|
|
18754
|
+
const right = tail === void 0 ? [] : part(tail);
|
|
18755
|
+
const gap = Array(8 - left.length - right.length).fill(0);
|
|
18756
|
+
return [...left, ...gap, ...right];
|
|
18757
|
+
}
|
|
18758
|
+
function loopbackName2(host) {
|
|
18759
|
+
const name2 = host.toLowerCase().replace(/\.$/, "");
|
|
18760
|
+
return name2 === "localhost" || name2.endsWith(".localhost");
|
|
18761
|
+
}
|
|
18762
|
+
function portOf(url) {
|
|
18763
|
+
if (url.port) return Number(url.port);
|
|
18764
|
+
return url.protocol === "https:" || url.protocol === "wss:" ? 443 : 80;
|
|
18765
|
+
}
|
|
18766
|
+
function allows(policy, port) {
|
|
18767
|
+
if (Array.isArray(policy)) return policy.includes(port);
|
|
18768
|
+
return policy === true && !DEVTOOLS_PORTS.includes(port);
|
|
18769
|
+
}
|
|
18770
|
+
function refusal(url, address, place) {
|
|
18771
|
+
const where = `${address}:${portOf(url)}`;
|
|
18772
|
+
const why = place === "link-local" ? `nodeTransport refuses link-local ${where}` : `nodeTransport refuses the host's loopback ${where} (see nodeTransport({ hostLoopback }))`;
|
|
18773
|
+
return Object.assign(new Error(why), { status: 403, code: "EACCES" });
|
|
18774
|
+
}
|
|
18775
|
+
async function addressesOf(host, resolve2) {
|
|
18776
|
+
const plain = host.replace(/^\[(.*)\]$/, "$1");
|
|
18777
|
+
if (isIP(plain)) return [plain];
|
|
18778
|
+
if (loopbackName2(plain)) return ["127.0.0.1"];
|
|
18779
|
+
return resolve2(plain).catch(() => []);
|
|
18780
|
+
}
|
|
18781
|
+
async function checkDestination(target, policy, resolve2 = resolveHost) {
|
|
18782
|
+
const url = new URL(target);
|
|
18783
|
+
for (const address of await addressesOf(url.hostname, resolve2)) {
|
|
18784
|
+
const place = placeOf(address);
|
|
18785
|
+
if (!place) continue;
|
|
18786
|
+
if (place === "loopback" && allows(policy, portOf(url))) continue;
|
|
18787
|
+
throw refusal(url, address, place);
|
|
18788
|
+
}
|
|
18789
|
+
}
|
|
18790
|
+
function guarded2(check, signal) {
|
|
18791
|
+
if (!signal) return check;
|
|
18792
|
+
signal.throwIfAborted();
|
|
18793
|
+
let stop = () => {
|
|
18794
|
+
};
|
|
18795
|
+
const aborted2 = new Promise((_, reject) => {
|
|
18796
|
+
stop = () => reject(signal.reason);
|
|
18797
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
18798
|
+
});
|
|
18799
|
+
return Promise.race([check, aborted2]).finally(() => signal.removeEventListener("abort", stop));
|
|
18800
|
+
}
|
|
18801
|
+
function guardedLoopback(transport, policy, resolve2) {
|
|
18802
|
+
const open = transport.websocket?.bind(transport);
|
|
18803
|
+
return {
|
|
18804
|
+
get traits() {
|
|
18805
|
+
return transport.traits;
|
|
18806
|
+
},
|
|
18807
|
+
fetch: async (request, owner) => {
|
|
18808
|
+
await guarded2(checkDestination(request.url, policy, resolve2), request.signal);
|
|
18809
|
+
return transport.fetch(request, owner);
|
|
18810
|
+
},
|
|
18811
|
+
...open ? {
|
|
18812
|
+
websocket: async (request) => {
|
|
18813
|
+
await guarded2(checkDestination(request.url, policy, resolve2), request.signal);
|
|
18814
|
+
return open(request);
|
|
18815
|
+
}
|
|
18816
|
+
} : {}
|
|
18817
|
+
};
|
|
18818
|
+
}
|
|
18819
|
+
|
|
18600
18820
|
// src/node/memory-root.ts
|
|
18601
18821
|
var fail2 = (name2) => {
|
|
18602
18822
|
throw new DOMException(name2, name2);
|
|
@@ -18803,8 +19023,8 @@ function isMemoryRoot(handle) {
|
|
|
18803
19023
|
}
|
|
18804
19024
|
|
|
18805
19025
|
// src/node/ws-diagnose.ts
|
|
18806
|
-
import { lookup } from "node:dns/promises";
|
|
18807
|
-
import { isIP, connect as tcp } from "node:net";
|
|
19026
|
+
import { lookup as lookup2 } from "node:dns/promises";
|
|
19027
|
+
import { isIP as isIP2, connect as tcp } from "node:net";
|
|
18808
19028
|
import { connect as tls } from "node:tls";
|
|
18809
19029
|
var PROBE_MS = 3e3;
|
|
18810
19030
|
var PASSED = /* @__PURE__ */ new Set(["ECONNREFUSED", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT", "ECONNRESET"]);
|
|
@@ -18815,7 +19035,7 @@ function codeOf5(e) {
|
|
|
18815
19035
|
}
|
|
18816
19036
|
function probe(secure, host, port, ms) {
|
|
18817
19037
|
return new Promise((resolve2) => {
|
|
18818
|
-
const socket = secure ? tls({ host, port, ...
|
|
19038
|
+
const socket = secure ? tls({ host, port, ...isIP2(host) ? {} : { servername: host } }) : tcp({ host, port });
|
|
18819
19039
|
const done4 = (code) => {
|
|
18820
19040
|
clearTimeout(timer);
|
|
18821
19041
|
socket.destroy();
|
|
@@ -18835,7 +19055,7 @@ async function diagnose(url, ms = PROBE_MS) {
|
|
|
18835
19055
|
const secure = at.protocol === "wss:";
|
|
18836
19056
|
const port = Number(at.port) || (secure ? 443 : 80);
|
|
18837
19057
|
try {
|
|
18838
|
-
await
|
|
19058
|
+
await lookup2(host);
|
|
18839
19059
|
} catch (e) {
|
|
18840
19060
|
return NO_NAME.has(codeOf5(e) ?? "") ? "EAI_NONAME" : void 0;
|
|
18841
19061
|
}
|
|
@@ -19684,9 +19904,10 @@ function hostfsFetchOf(options) {
|
|
|
19684
19904
|
}
|
|
19685
19905
|
};
|
|
19686
19906
|
}
|
|
19687
|
-
function nodeTransport() {
|
|
19907
|
+
function nodeTransport(options = {}) {
|
|
19688
19908
|
const transport = fetchTransport({ webSocket: true, webSocketHeaders: true, redirect: "manual" });
|
|
19689
|
-
|
|
19909
|
+
const open = { ...transport, traits: { ...transport.traits, crossOrigin: "any" } };
|
|
19910
|
+
return diagnosing(guardedLoopback(open, options.hostLoopback ?? false));
|
|
19690
19911
|
}
|
|
19691
19912
|
var TERMINATED = "the kernel is terminated";
|
|
19692
19913
|
var EXIT_GRACE_MS = 50;
|