@ai-ecoverse/slicc-kernel 1.161.0 → 1.162.0
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/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +365 -34
- package/dist/kernel-worker.js.map +3 -3
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +1 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +365 -34
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/opfs.d.ts +6 -2
- package/dist/types/fs/remote.d.ts +56 -0
- package/dist/types/fs/types.d.ts +36 -0
- package/dist/types/fs/unlinked.d.ts +21 -1
- package/dist/types/kernel/host.d.ts +1 -1
- package/dist/types/launcher.d.ts +5 -0
- package/dist/types/mount/mount-fs.d.ts +5 -2
- package/dist/types/realm/sync-fs-token-registry.d.ts +1 -1
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -3675,7 +3675,7 @@ function satisfies(version, range2) {
|
|
|
3675
3675
|
}
|
|
3676
3676
|
|
|
3677
3677
|
// src/version.ts
|
|
3678
|
-
var KERNEL_VERSION = true ? "1.
|
|
3678
|
+
var KERNEL_VERSION = true ? "1.162.0" : "0.0.0-dev";
|
|
3679
3679
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3680
3680
|
function procVersion() {
|
|
3681
3681
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -4638,6 +4638,9 @@ var LOOKUP_OPS = [
|
|
|
4638
4638
|
var within2 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
4639
4639
|
var TOUCHED_MAX = 4096;
|
|
4640
4640
|
var parentOf2 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
4641
|
+
var PEER_RM_MS = 1e3;
|
|
4642
|
+
var PEER_RENAME_MS = 1e4;
|
|
4643
|
+
var PEER_GATE_MS = PEER_RENAME_MS + 5e3;
|
|
4641
4644
|
var lockName = (instance) => `slicc-unlinked:${instance}`;
|
|
4642
4645
|
var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
|
|
4643
4646
|
var PathGate = class {
|
|
@@ -4680,7 +4683,9 @@ var UnlinkedKeeper = class {
|
|
|
4680
4683
|
links = /* @__PURE__ */ new Map();
|
|
4681
4684
|
linked = /* @__PURE__ */ new Map();
|
|
4682
4685
|
dirOwner;
|
|
4686
|
+
peers;
|
|
4683
4687
|
constructor(fs, holders, rootOf, options = {}) {
|
|
4688
|
+
this.peers = options.peers;
|
|
4684
4689
|
this.marks = options.marks ?? new PathMarks();
|
|
4685
4690
|
const { locks, owner } = options;
|
|
4686
4691
|
this.dirOwner = options.dirOwner;
|
|
@@ -4756,22 +4761,29 @@ var UnlinkedKeeper = class {
|
|
|
4756
4761
|
lstat: (path) => unreplaced(path, async () => counted3(await fs.lstat(path))),
|
|
4757
4762
|
async rm(path, options) {
|
|
4758
4763
|
const target = fs.resolvePath("/", path);
|
|
4759
|
-
await
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
+
const kept = await keeper.peerKeep(target, false, () => keeper.removable(target, options));
|
|
4765
|
+
if (kept.whole) return;
|
|
4766
|
+
await kept.undoing(
|
|
4767
|
+
() => replace(target, async (gated, sealed) => {
|
|
4768
|
+
const pinned = await keeper.pin(target, gated, sealed);
|
|
4769
|
+
if (pinned.moved.has(target)) pinned.commit();
|
|
4770
|
+
else await keeper.settle(pinned, () => fs.rm(path, options));
|
|
4771
|
+
})
|
|
4772
|
+
);
|
|
4764
4773
|
},
|
|
4765
4774
|
async rename(from, to) {
|
|
4766
4775
|
const target = fs.resolvePath("/", to);
|
|
4767
4776
|
const source = fs.resolvePath("/", from);
|
|
4768
4777
|
if (target === source) return fs.rename(from, to);
|
|
4769
|
-
await keeper.
|
|
4770
|
-
|
|
4771
|
-
() =>
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4778
|
+
const kept = await keeper.peerKeep(target, true, () => keeper.renamable(source, target));
|
|
4779
|
+
await kept.undoing(
|
|
4780
|
+
() => keeper.marks.around(
|
|
4781
|
+
[source],
|
|
4782
|
+
() => replace(target, async (gated, sealed) => {
|
|
4783
|
+
const pinned = await keeper.pin(target, gated, sealed);
|
|
4784
|
+
await keeper.settle(pinned, () => fs.rename(from, to));
|
|
4785
|
+
})
|
|
4786
|
+
)
|
|
4775
4787
|
);
|
|
4776
4788
|
},
|
|
4777
4789
|
symlink: (target, path, owner) => keeper.marks.around([fs.resolvePath("/", path)], () => fs.symlink(target, path, owner)),
|
|
@@ -4916,6 +4928,114 @@ var UnlinkedKeeper = class {
|
|
|
4916
4928
|
(err) => err?.code !== "ENOENT" && err?.code !== "ENOTDIR"
|
|
4917
4929
|
);
|
|
4918
4930
|
}
|
|
4931
|
+
get id() {
|
|
4932
|
+
return this.instance;
|
|
4933
|
+
}
|
|
4934
|
+
adopt(hidden, refs) {
|
|
4935
|
+
return this.keptFile(hidden, { refs });
|
|
4936
|
+
}
|
|
4937
|
+
async peerKeep(target, over, valid2 = async () => true) {
|
|
4938
|
+
const none = { whole: false, undoing: (op) => op() };
|
|
4939
|
+
const peers = this.peers;
|
|
4940
|
+
if (!peers?.shared() || this.rootOf(target) !== "/") return none;
|
|
4941
|
+
const held = peers.heldWithin(target).filter((holder) => holder.instance !== void 0);
|
|
4942
|
+
if (held.length === 0 || !await valid2()) return none;
|
|
4943
|
+
const tabs = /* @__PURE__ */ new Map();
|
|
4944
|
+
for (const holder of held) tabs.set(holder.tab, [...tabs.get(holder.tab) ?? [], holder]);
|
|
4945
|
+
const asked = [...tabs].map(([tab, holders]) => {
|
|
4946
|
+
const paths = holders.map((holder) => holder.path);
|
|
4947
|
+
return { tab, holders, paths };
|
|
4948
|
+
});
|
|
4949
|
+
const heard = await Promise.all(
|
|
4950
|
+
asked.map(
|
|
4951
|
+
({ tab, paths }) => peers.ask(tab, { keeping: { paths } }, over ? PEER_RENAME_MS : PEER_RM_MS)
|
|
4952
|
+
)
|
|
4953
|
+
);
|
|
4954
|
+
if (over && heard.includes(false)) {
|
|
4955
|
+
for (const { tab, paths } of asked)
|
|
4956
|
+
void peers.ask(tab, { kept: { items: [], paths } }, PEER_RM_MS);
|
|
4957
|
+
throw fsError("EBUSY", `${target}: open in another tab that did not answer`);
|
|
4958
|
+
}
|
|
4959
|
+
const { whole, moved: moved2 } = await this.setAside(peers, target, asked, heard);
|
|
4960
|
+
return { whole, undoing: (op) => this.undoing(op, moved2) };
|
|
4961
|
+
}
|
|
4962
|
+
async setAside(peers, target, asked, heard) {
|
|
4963
|
+
const mine = this.heldWithin(target);
|
|
4964
|
+
const taken = /* @__PURE__ */ new Set();
|
|
4965
|
+
let whole = false;
|
|
4966
|
+
const told = [];
|
|
4967
|
+
const moved2 = [];
|
|
4968
|
+
for (const [i, { tab, holders, paths }] of asked.entries()) {
|
|
4969
|
+
const items = [];
|
|
4970
|
+
for (const holder of holders) {
|
|
4971
|
+
const free = !mine.has(holder.path) && !taken.has(holder.path);
|
|
4972
|
+
const hidden = free ? await this.asideFor(holder.path, holder.instance) : void 0;
|
|
4973
|
+
if (hidden !== void 0) {
|
|
4974
|
+
taken.add(holder.path);
|
|
4975
|
+
moved2.push({ tab, path: holder.path, hidden, fid: holder.fid });
|
|
4976
|
+
if (holder.path === target) whole = true;
|
|
4977
|
+
}
|
|
4978
|
+
items.push({ path: holder.path, hidden, fid: holder.fid });
|
|
4979
|
+
}
|
|
4980
|
+
const answer2 = peers.ask(tab, { kept: { items, paths } }, PEER_RM_MS);
|
|
4981
|
+
if (heard[i]) told.push(answer2);
|
|
4982
|
+
}
|
|
4983
|
+
await Promise.all(told);
|
|
4984
|
+
return { whole, moved: moved2 };
|
|
4985
|
+
}
|
|
4986
|
+
async undoing(op, moved2) {
|
|
4987
|
+
try {
|
|
4988
|
+
return await op();
|
|
4989
|
+
} catch (err) {
|
|
4990
|
+
for (const { tab, path, hidden, fid } of moved2) {
|
|
4991
|
+
const back = await this.serial(async () => {
|
|
4992
|
+
if (await this.present(path)) return false;
|
|
4993
|
+
return this.fs.rename(hidden, path).then(
|
|
4994
|
+
() => true,
|
|
4995
|
+
() => false
|
|
4996
|
+
);
|
|
4997
|
+
});
|
|
4998
|
+
if (!back) continue;
|
|
4999
|
+
void this.peers?.ask(
|
|
5000
|
+
tab,
|
|
5001
|
+
{ kept: { items: [{ path, hidden: void 0, fid, undo: hidden }], paths: [] } },
|
|
5002
|
+
PEER_RM_MS
|
|
5003
|
+
);
|
|
5004
|
+
}
|
|
5005
|
+
throw err;
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
async removable(target, options) {
|
|
5009
|
+
const st = await this.fs.lstat(target).catch(() => void 0);
|
|
5010
|
+
return st !== void 0 && (!st.isDirectory || options?.recursive === true);
|
|
5011
|
+
}
|
|
5012
|
+
async renamable(source, target) {
|
|
5013
|
+
const from = await this.fs.lstat(source);
|
|
5014
|
+
const to = await this.fs.lstat(target).catch(() => void 0);
|
|
5015
|
+
if (!to) return true;
|
|
5016
|
+
if (to.isDirectory && !from.isDirectory) throw fsError("EISDIR", target);
|
|
5017
|
+
if (!to.isDirectory && from.isDirectory) throw fsError("ENOTDIR", target);
|
|
5018
|
+
if (to.isDirectory && (await this.fs.readdir(target)).length > 0)
|
|
5019
|
+
throw fsError("ENOTEMPTY", target);
|
|
5020
|
+
return true;
|
|
5021
|
+
}
|
|
5022
|
+
async asideFor(path, instance) {
|
|
5023
|
+
return await this.hideFor(path, instance) ?? this.hideFor(path, instance);
|
|
5024
|
+
}
|
|
5025
|
+
hideFor(path, instance) {
|
|
5026
|
+
return this.serial(async () => {
|
|
5027
|
+
const dir = dirOf("/");
|
|
5028
|
+
const hidden = `${dir}/${instance}.p${crypto.randomUUID().replaceAll("-", "")}`;
|
|
5029
|
+
try {
|
|
5030
|
+
const owner = this.dirOwner;
|
|
5031
|
+
await this.fs.mkdir(dir, { recursive: true, ...owner ? { owner } : {} });
|
|
5032
|
+
await this.fs.rename(path, hidden);
|
|
5033
|
+
return hidden;
|
|
5034
|
+
} catch {
|
|
5035
|
+
return void 0;
|
|
5036
|
+
}
|
|
5037
|
+
});
|
|
5038
|
+
}
|
|
4919
5039
|
keptFile(hidden, entry) {
|
|
4920
5040
|
return {
|
|
4921
5041
|
hidden,
|
|
@@ -4970,7 +5090,7 @@ var UnlinkedKeeper = class {
|
|
|
4970
5090
|
}
|
|
4971
5091
|
async tidy(dir) {
|
|
4972
5092
|
const left = await this.fs.readdir(dir).catch(() => [UNLINKED_DIR]);
|
|
4973
|
-
if (left.length === 0) await this.fs.rm(dir
|
|
5093
|
+
if (left.length === 0) await this.fs.rm(dir).catch(() => void 0);
|
|
4974
5094
|
}
|
|
4975
5095
|
sweep(root) {
|
|
4976
5096
|
const query = this.locks?.query?.bind(this.locks);
|
|
@@ -6380,6 +6500,11 @@ async function shownTarget(fs, target) {
|
|
|
6380
6500
|
const st = await quiet2(fs.stat(target));
|
|
6381
6501
|
return st?.isFile && await readsAs2(fs, NOBODY, target) ? st : void 0;
|
|
6382
6502
|
}
|
|
6503
|
+
async function madeFor(owner, virtual) {
|
|
6504
|
+
if (!owner?.existing || await virtual() === void 0) return owner;
|
|
6505
|
+
const { existing: _, ...made2 } = owner;
|
|
6506
|
+
return made2;
|
|
6507
|
+
}
|
|
6383
6508
|
function withCommandDirs(fs, names2, userDir = async () => void 0, owners = false, targetOf2 = async () => void 0) {
|
|
6384
6509
|
async function nearest(path) {
|
|
6385
6510
|
const st = await fs.stat(path).catch(() => void 0);
|
|
@@ -6477,7 +6602,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6477
6602
|
}),
|
|
6478
6603
|
readFileBuffer: (path) => fs.readFileBuffer(path).catch((err) => content(path, err)),
|
|
6479
6604
|
commandTarget: async (path) => (await entryTarget(path))?.path,
|
|
6480
|
-
writeFile: (path, content2, owner) => fs.writeFile(path, content2, owner),
|
|
6605
|
+
writeFile: async (path, content2, owner) => fs.writeFile(path, content2, await madeFor(owner, () => entryTarget(path))),
|
|
6481
6606
|
link: (from, to, follow2) => fs.link(from, to, follow2),
|
|
6482
6607
|
links: (path) => mayLink(fs, path),
|
|
6483
6608
|
async exists(path) {
|
|
@@ -6642,6 +6767,10 @@ function withEtcFiles(fs, files) {
|
|
|
6642
6767
|
}
|
|
6643
6768
|
} : {},
|
|
6644
6769
|
readFile: (path) => fs.readFile(path).catch(fallback(path, (b) => new TextDecoder().decode(b))),
|
|
6770
|
+
writeFile: async (path, content, owner) => {
|
|
6771
|
+
if (owner?.existing && files.has(path)) await materialize(path);
|
|
6772
|
+
return fs.writeFile(path, content, owner);
|
|
6773
|
+
},
|
|
6645
6774
|
...fs.append ? {
|
|
6646
6775
|
append: async (path, bytes, options) => {
|
|
6647
6776
|
if (files.has(path)) await materialize(path);
|
|
@@ -9022,12 +9151,25 @@ var HeldPaths = class extends Map {
|
|
|
9022
9151
|
for (const file of this.unlinked.values()) if (file.hidden === hidden) return true;
|
|
9023
9152
|
return false;
|
|
9024
9153
|
}
|
|
9154
|
+
boundAt(path, fid) {
|
|
9155
|
+
return this.handlesAt(path).filter(
|
|
9156
|
+
(id2) => !this.keptHandles.has(id2) && this.bound.get(id2)?.fid === fid
|
|
9157
|
+
);
|
|
9158
|
+
}
|
|
9159
|
+
keepBound(ids, path, file) {
|
|
9160
|
+
for (const id2 of ids) this.keptHandles.set(id2, file);
|
|
9161
|
+
this.uses.set(file, ids.length);
|
|
9162
|
+
this.unlinked.set(path, file);
|
|
9163
|
+
}
|
|
9025
9164
|
keep(path, file) {
|
|
9026
9165
|
const fresh3 = this.handlesAt(path).filter((id2) => !this.keptHandles.has(id2));
|
|
9027
9166
|
for (const id2 of fresh3) this.keptHandles.set(id2, file);
|
|
9028
9167
|
this.uses.set(file, Math.max(fresh3.length, 1));
|
|
9029
9168
|
this.unlinked.set(path, file);
|
|
9030
9169
|
}
|
|
9170
|
+
unkeepAt(path, hidden) {
|
|
9171
|
+
for (const file of [...this.uses.keys()]) if (file.hidden === hidden) this.unkeep(path, file);
|
|
9172
|
+
}
|
|
9031
9173
|
unkeep(path, file) {
|
|
9032
9174
|
for (const [id2, kept] of this.keptHandles) if (kept === file) this.keptHandles.delete(id2);
|
|
9033
9175
|
this.uses.delete(file);
|
|
@@ -9596,12 +9738,12 @@ var MountFs = class _MountFs {
|
|
|
9596
9738
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
9597
9739
|
return this.follow(this.base.resolvePath(parentOf5(real), target), hops + 1, create);
|
|
9598
9740
|
}
|
|
9599
|
-
async open(mount, rel2, write, owner) {
|
|
9741
|
+
async open(mount, rel2, write, owner, create = write) {
|
|
9600
9742
|
return await mount.conn.call({
|
|
9601
9743
|
op: "open",
|
|
9602
9744
|
path: rel2,
|
|
9603
9745
|
write,
|
|
9604
|
-
create
|
|
9746
|
+
create,
|
|
9605
9747
|
truncate: write,
|
|
9606
9748
|
exclusive: false,
|
|
9607
9749
|
...owner
|
|
@@ -9698,10 +9840,10 @@ var MountFs = class _MountFs {
|
|
|
9698
9840
|
`${real} would be larger than this mount's maxfile (${mount.maxFile})`
|
|
9699
9841
|
);
|
|
9700
9842
|
}
|
|
9701
|
-
const made2 = await this.driverOwner(found, real, owner, false);
|
|
9843
|
+
const made2 = owner?.existing ? void 0 : await this.driverOwner(found, real, owner, false);
|
|
9702
9844
|
for (let attempt = 1; ; attempt++) {
|
|
9703
9845
|
try {
|
|
9704
|
-
return await this.writeWhole(mount, real, rel2, bytes, made2);
|
|
9846
|
+
return await this.writeWhole(mount, real, rel2, bytes, made2, owner?.existing !== true);
|
|
9705
9847
|
} catch (err) {
|
|
9706
9848
|
if (err.code !== "ESTALE" || attempt >= STALE_RETRIES) throw err;
|
|
9707
9849
|
}
|
|
@@ -9719,10 +9861,10 @@ var MountFs = class _MountFs {
|
|
|
9719
9861
|
this.table.forget(mount, real);
|
|
9720
9862
|
}
|
|
9721
9863
|
}
|
|
9722
|
-
async writeWhole(mount, real, rel2, bytes, owner) {
|
|
9864
|
+
async writeWhole(mount, real, rel2, bytes, owner, create = true) {
|
|
9723
9865
|
await this.table.commit(real);
|
|
9724
9866
|
this.table.forget(mount, real);
|
|
9725
|
-
const fh = await this.open(mount, rel2, true, owner);
|
|
9867
|
+
const fh = await this.open(mount, rel2, true, owner, create);
|
|
9726
9868
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
9727
9869
|
try {
|
|
9728
9870
|
for (let offset = 0; offset < bytes.length; offset += chunk2) {
|
|
@@ -10459,6 +10601,11 @@ function ownerFor(entry, mode) {
|
|
|
10459
10601
|
if (!cred) return void 0;
|
|
10460
10602
|
return ownerOf(cred, mode === void 0 ? void 0 : mode & ~(entry.umask?.() ?? 18));
|
|
10461
10603
|
}
|
|
10604
|
+
function writeOwner(entry, req) {
|
|
10605
|
+
const owner = ownerFor(entry, 438);
|
|
10606
|
+
if (req.handle === void 0 || req.mode !== 1) return owner;
|
|
10607
|
+
return { ...owner ?? {}, existing: true };
|
|
10608
|
+
}
|
|
10462
10609
|
function plainDirMode(entry, mode) {
|
|
10463
10610
|
if (entry.cred || mode === void 0) return void 0;
|
|
10464
10611
|
const wanted = mode & 4095 & ~(entry.umask?.() ?? 18);
|
|
@@ -10529,7 +10676,7 @@ async function run(entry, path, req) {
|
|
|
10529
10676
|
case "read":
|
|
10530
10677
|
return { ok: true, kind: "bytes", bytes: await readSource(entry, path) };
|
|
10531
10678
|
case "write":
|
|
10532
|
-
await fs.writeFile(path, req.body ?? new Uint8Array(0),
|
|
10679
|
+
await fs.writeFile(path, req.body ?? new Uint8Array(0), writeOwner(entry, req));
|
|
10533
10680
|
return done;
|
|
10534
10681
|
case "exists":
|
|
10535
10682
|
return json2(await fs.exists(path));
|
|
@@ -23425,6 +23572,9 @@ var RemoteWatch = class {
|
|
|
23425
23572
|
holdsSent = 0;
|
|
23426
23573
|
silent = /* @__PURE__ */ new Set();
|
|
23427
23574
|
holders = /* @__PURE__ */ new Set();
|
|
23575
|
+
instances = /* @__PURE__ */ new Map();
|
|
23576
|
+
instance;
|
|
23577
|
+
keeps;
|
|
23428
23578
|
listeners = /* @__PURE__ */ new Set();
|
|
23429
23579
|
waiting = /* @__PURE__ */ new Map();
|
|
23430
23580
|
locks;
|
|
@@ -23544,8 +23694,9 @@ var RemoteWatch = class {
|
|
|
23544
23694
|
this.met?.();
|
|
23545
23695
|
}
|
|
23546
23696
|
if (data.tab !== void 0 && data.paths !== void 0) this.announced(data);
|
|
23547
|
-
|
|
23697
|
+
this.holdsHeard(data);
|
|
23548
23698
|
if (data.ack !== void 0 && data.to === this.tab && data.from !== void 0) {
|
|
23699
|
+
if (data.instance !== void 0) this.instances.set(data.from, data.instance);
|
|
23549
23700
|
this.acked(data.ack, data.from);
|
|
23550
23701
|
}
|
|
23551
23702
|
if (data.changed !== void 0) this.emit({ paths: data.changed, trees: [], content: true });
|
|
@@ -23572,6 +23723,7 @@ var RemoteWatch = class {
|
|
|
23572
23723
|
this.mourned.delete(peer);
|
|
23573
23724
|
this.others.delete(peer);
|
|
23574
23725
|
this.peerHolds.delete(peer);
|
|
23726
|
+
this.keeps?.left(peer);
|
|
23575
23727
|
this.peers.delete(peer);
|
|
23576
23728
|
this.ackers.delete(peer);
|
|
23577
23729
|
this.holders.delete(peer);
|
|
@@ -23612,9 +23764,38 @@ var RemoteWatch = class {
|
|
|
23612
23764
|
this.rebuild();
|
|
23613
23765
|
this.channel.postMessage({ ack: seq2, from: this.tab, to: from });
|
|
23614
23766
|
}
|
|
23767
|
+
holdsHeard(data) {
|
|
23768
|
+
if (data.tab === void 0) return;
|
|
23769
|
+
if (data.holds !== void 0) this.heldBy(data);
|
|
23770
|
+
if (data.to === this.tab && (data.keeping || data.kept)) void this.keepAsked(data);
|
|
23771
|
+
}
|
|
23772
|
+
keepChains = /* @__PURE__ */ new Map();
|
|
23773
|
+
keepAsked(data) {
|
|
23774
|
+
const from = data.tab;
|
|
23775
|
+
const next3 = (this.keepChains.get(from) ?? Promise.resolve()).then(() => this.keepOne(data));
|
|
23776
|
+
this.keepChains.set(from, next3);
|
|
23777
|
+
return next3;
|
|
23778
|
+
}
|
|
23779
|
+
async keepOne({ tab, seq: seq2, keeping, kept }) {
|
|
23780
|
+
const from = tab;
|
|
23781
|
+
const keeps = this.keeps;
|
|
23782
|
+
try {
|
|
23783
|
+
if (keeping) await keeps?.keeping(from, keeping.paths);
|
|
23784
|
+
if (kept)
|
|
23785
|
+
await keeps?.kept(from, kept.items, kept.paths ?? kept.items.map((item) => item.path));
|
|
23786
|
+
} finally {
|
|
23787
|
+
this.channel.postMessage({
|
|
23788
|
+
ack: seq2,
|
|
23789
|
+
from: this.tab,
|
|
23790
|
+
to: from,
|
|
23791
|
+
...this.instance === void 0 ? {} : { instance: this.instance }
|
|
23792
|
+
});
|
|
23793
|
+
}
|
|
23794
|
+
}
|
|
23615
23795
|
heldBy({ tab, holds: holds2, seq: seq2 }) {
|
|
23616
23796
|
const from = tab;
|
|
23617
23797
|
const { add, drop } = holds2;
|
|
23798
|
+
if (holds2?.instance !== void 0) this.instances.set(from, holds2.instance);
|
|
23618
23799
|
const held = this.peerHolds.get(from) ?? /* @__PURE__ */ new Map();
|
|
23619
23800
|
for (const path of drop) held.delete(path);
|
|
23620
23801
|
for (const [path, fid] of add) held.set(path, fid);
|
|
@@ -23656,9 +23837,38 @@ var RemoteWatch = class {
|
|
|
23656
23837
|
sendHolds(add, drop) {
|
|
23657
23838
|
const seq2 = ++this.seq;
|
|
23658
23839
|
this.holdsSent++;
|
|
23659
|
-
|
|
23840
|
+
const instance = this.instance === void 0 ? {} : { instance: this.instance };
|
|
23841
|
+
this.channel.postMessage({
|
|
23842
|
+
tab: this.tab,
|
|
23843
|
+
holds: { add: [...add], drop: [...drop], ...instance },
|
|
23844
|
+
seq: seq2
|
|
23845
|
+
});
|
|
23660
23846
|
return seq2;
|
|
23661
23847
|
}
|
|
23848
|
+
heldWithin(target) {
|
|
23849
|
+
const out = [];
|
|
23850
|
+
for (const [tab, held] of this.peerHolds) {
|
|
23851
|
+
for (const [path, fid] of held) {
|
|
23852
|
+
if (path !== target && !path.startsWith(`${target}/`)) continue;
|
|
23853
|
+
out.push({ tab, path, fid, instance: this.instances.get(tab) });
|
|
23854
|
+
}
|
|
23855
|
+
}
|
|
23856
|
+
return out;
|
|
23857
|
+
}
|
|
23858
|
+
ask(to, body, cap) {
|
|
23859
|
+
const seq2 = ++this.seq;
|
|
23860
|
+
this.channel.postMessage({ tab: this.tab, to, seq: seq2, ...body });
|
|
23861
|
+
return new Promise((resolve2) => {
|
|
23862
|
+
const done4 = () => {
|
|
23863
|
+
clearTimeout(timer);
|
|
23864
|
+
this.waiting.delete(seq2);
|
|
23865
|
+
resolve2(left.size === 0);
|
|
23866
|
+
};
|
|
23867
|
+
const left = /* @__PURE__ */ new Set([to]);
|
|
23868
|
+
const timer = setTimeout(done4, cap);
|
|
23869
|
+
this.waiting.set(seq2, { left, done: done4 });
|
|
23870
|
+
});
|
|
23871
|
+
}
|
|
23662
23872
|
peerHeld(path) {
|
|
23663
23873
|
const out = [];
|
|
23664
23874
|
for (const [tab, held] of this.peerHolds)
|
|
@@ -23694,6 +23904,7 @@ var RemoteWatch = class {
|
|
|
23694
23904
|
if (this.peers.delete(tab)) left = true;
|
|
23695
23905
|
this.others.delete(tab);
|
|
23696
23906
|
this.peerHolds.delete(tab);
|
|
23907
|
+
this.keeps?.left(tab);
|
|
23697
23908
|
this.ackers.delete(tab);
|
|
23698
23909
|
this.holders.delete(tab);
|
|
23699
23910
|
}
|
|
@@ -25169,6 +25380,7 @@ function translate(err, path, op = "lookup", mapped = true) {
|
|
|
25169
25380
|
return error;
|
|
25170
25381
|
}
|
|
25171
25382
|
var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
|
|
25383
|
+
var FILE_ID_TRIES = 3;
|
|
25172
25384
|
function sidecar(meta) {
|
|
25173
25385
|
const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
|
|
25174
25386
|
const guarded3 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
@@ -25408,18 +25620,48 @@ var OpfsFs = class {
|
|
|
25408
25620
|
this.channel?.postMessage(paths);
|
|
25409
25621
|
}
|
|
25410
25622
|
async fileId(path) {
|
|
25623
|
+
for (let tries = 0; tries < FILE_ID_TRIES; tries++) {
|
|
25624
|
+
const fid = await this.assignId(path);
|
|
25625
|
+
if (fid !== void 0) return fid;
|
|
25626
|
+
}
|
|
25627
|
+
throw fsError("EAGAIN", `${path}: moved while its file id was assigned`);
|
|
25628
|
+
}
|
|
25629
|
+
bindId(path) {
|
|
25630
|
+
return this.assignId(path);
|
|
25631
|
+
}
|
|
25632
|
+
async assignId(path) {
|
|
25411
25633
|
const found = await this.locate(path, true);
|
|
25412
25634
|
const [entry] = await (this.meta.fresh ?? this.meta.get).call(this.meta, [found.path]);
|
|
25413
25635
|
if (entry?.fid !== void 0) return entry.fid;
|
|
25414
25636
|
const fid = crypto.randomUUID();
|
|
25637
|
+
let moved2 = false;
|
|
25638
|
+
await this.meta.update(found.path, (now) => {
|
|
25639
|
+
const vacatedSince = now?.vacated && (!entry?.vacated || now.ino !== entry.ino);
|
|
25640
|
+
if (vacatedSince || entry !== void 0 && now === void 0) {
|
|
25641
|
+
moved2 = true;
|
|
25642
|
+
return now;
|
|
25643
|
+
}
|
|
25644
|
+
return { ...occupied(now), path: found.path, fid: now?.fid ?? fid };
|
|
25645
|
+
});
|
|
25646
|
+
if (moved2) return void 0;
|
|
25415
25647
|
this.idWrites++;
|
|
25416
|
-
await this.
|
|
25417
|
-
|
|
25418
|
-
|
|
25419
|
-
|
|
25420
|
-
|
|
25421
|
-
const
|
|
25422
|
-
|
|
25648
|
+
const there = await this.locate(path, true).then(
|
|
25649
|
+
(at) => at.path === found.path,
|
|
25650
|
+
() => false
|
|
25651
|
+
);
|
|
25652
|
+
if (there) return (await this.meta.get([found.path]))[0]?.fid ?? fid;
|
|
25653
|
+
const gone = await this.locate(found.path, true).then(
|
|
25654
|
+
() => false,
|
|
25655
|
+
(err) => missing4(err)
|
|
25656
|
+
);
|
|
25657
|
+
if (gone) {
|
|
25658
|
+
await this.meta.update(found.path, (now) => {
|
|
25659
|
+
if (now?.fid !== fid || now.vacated) return now;
|
|
25660
|
+
const { fid: _, ...rest2 } = now;
|
|
25661
|
+
return rest2;
|
|
25662
|
+
});
|
|
25663
|
+
}
|
|
25664
|
+
return void 0;
|
|
25423
25665
|
}
|
|
25424
25666
|
heldUnder = () => [];
|
|
25425
25667
|
heldBy(held) {
|
|
@@ -25445,6 +25687,20 @@ var OpfsFs = class {
|
|
|
25445
25687
|
const remote = this.remote;
|
|
25446
25688
|
return remote && { ...remote.holdCounts(), held: remote.peerHeldPaths() };
|
|
25447
25689
|
}
|
|
25690
|
+
peerKeeps() {
|
|
25691
|
+
const remote = this.remote;
|
|
25692
|
+
if (!remote) return void 0;
|
|
25693
|
+
return {
|
|
25694
|
+
shared: () => this.shared(),
|
|
25695
|
+
heldWithin: (path) => remote.heldWithin(path),
|
|
25696
|
+
ask: (to, body, cap) => remote.ask(to, body, cap)
|
|
25697
|
+
};
|
|
25698
|
+
}
|
|
25699
|
+
servePeerKeeps(instance, handlers) {
|
|
25700
|
+
if (!this.remote) return;
|
|
25701
|
+
this.remote.instance = instance;
|
|
25702
|
+
this.remote.keeps = handlers;
|
|
25703
|
+
}
|
|
25448
25704
|
rehold(from, to) {
|
|
25449
25705
|
this.remote?.rehold(from, to);
|
|
25450
25706
|
}
|
|
@@ -26392,7 +26648,7 @@ var OpfsFs = class {
|
|
|
26392
26648
|
}
|
|
26393
26649
|
}
|
|
26394
26650
|
async writeFile(path, content, owner) {
|
|
26395
|
-
const [file, existed, target] = await this.fileFor(path);
|
|
26651
|
+
const [file, existed, target] = await this.fileFor(path, owner?.existing !== true);
|
|
26396
26652
|
if (!existed) await this.stampNew(target, owner, false);
|
|
26397
26653
|
if (!existed && content.length === 0) return;
|
|
26398
26654
|
let writable2;
|
|
@@ -30283,7 +30539,7 @@ var Launcher = class {
|
|
|
30283
30539
|
busy: (path) => [...this.openFiles].some((nodes) => nodes.holds(path)),
|
|
30284
30540
|
owner: options.unlinkOwner,
|
|
30285
30541
|
marks: this.pathMarks,
|
|
30286
|
-
...this.
|
|
30542
|
+
...this.peerOptions(options.fs)
|
|
30287
30543
|
}
|
|
30288
30544
|
);
|
|
30289
30545
|
this.fs = this.processChain(fs, this.nodes, this.unlinked);
|
|
@@ -31117,7 +31373,7 @@ var Launcher = class {
|
|
|
31117
31373
|
const assign = this.mounts.locate(target.wasm) === void 0 ? this.rootFs.fileId : void 0;
|
|
31118
31374
|
return this.base.stat(target.wasm).then(
|
|
31119
31375
|
async (st) => {
|
|
31120
|
-
const fid = st.fid ?? await assign?.call(this.rootFs, target.wasm);
|
|
31376
|
+
const fid = st.fid ?? await assign?.call(this.rootFs, target.wasm)?.catch(() => void 0);
|
|
31121
31377
|
if (fid === void 0) return exeIdOf(fileIdentity(st.ino, st.mtime.getTime()));
|
|
31122
31378
|
return { exeId: `fid:${fid}:${st.mtime.getTime()}` };
|
|
31123
31379
|
},
|
|
@@ -32279,8 +32535,82 @@ var Launcher = class {
|
|
|
32279
32535
|
this.writers ??= this.writerStack();
|
|
32280
32536
|
return this.writers;
|
|
32281
32537
|
}
|
|
32538
|
+
peerGates = /* @__PURE__ */ new Map();
|
|
32539
|
+
peerOptions(fs) {
|
|
32540
|
+
const peers = fs.peerKeeps?.();
|
|
32541
|
+
queueMicrotask(() => fs.servePeerKeeps?.(this.unlinked.id, this.peerKept()));
|
|
32542
|
+
return {
|
|
32543
|
+
...peers ? { peers } : {},
|
|
32544
|
+
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
32545
|
+
};
|
|
32546
|
+
}
|
|
32547
|
+
peerKept() {
|
|
32548
|
+
const gates = this.peerGates;
|
|
32549
|
+
const gone = /* @__PURE__ */ new Set();
|
|
32550
|
+
const instance = this.unlinked.id;
|
|
32551
|
+
const ours = (hidden) => hidden.startsWith(`/${UNLINKED_DIR}/${instance}.p`) && /^[0-9a-f]+$/.test(hidden.slice(`/${UNLINKED_DIR}/${instance}.p`.length));
|
|
32552
|
+
const open = (tab, paths) => {
|
|
32553
|
+
for (const [key, release] of [...gates]) {
|
|
32554
|
+
const [owner, path] = key.split("\0");
|
|
32555
|
+
if (owner !== tab || paths && !paths.includes(path)) continue;
|
|
32556
|
+
gates.delete(key);
|
|
32557
|
+
release();
|
|
32558
|
+
}
|
|
32559
|
+
};
|
|
32560
|
+
return {
|
|
32561
|
+
keeping: async (tab, paths) => {
|
|
32562
|
+
for (const path of paths) {
|
|
32563
|
+
if (gone.has(tab)) return;
|
|
32564
|
+
const release = await this.unlinked.gate.acquire(path);
|
|
32565
|
+
const key = `${tab}\0${path}`;
|
|
32566
|
+
let done4 = false;
|
|
32567
|
+
const once2 = () => {
|
|
32568
|
+
if (done4) return;
|
|
32569
|
+
done4 = true;
|
|
32570
|
+
clearTimeout(timer);
|
|
32571
|
+
release();
|
|
32572
|
+
};
|
|
32573
|
+
const timer = setTimeout(() => {
|
|
32574
|
+
if (gates.get(key) === once2) gates.delete(key);
|
|
32575
|
+
once2();
|
|
32576
|
+
}, PEER_GATE_MS);
|
|
32577
|
+
if (gone.has(tab)) once2();
|
|
32578
|
+
else gates.set(key, once2);
|
|
32579
|
+
}
|
|
32580
|
+
},
|
|
32581
|
+
kept: async (tab, items, paths) => {
|
|
32582
|
+
for (const { path, hidden, fid, undo } of items) {
|
|
32583
|
+
if (undo !== void 0) this.unadopt(path, undo, fid);
|
|
32584
|
+
else this.adoptKept(path, hidden, fid, ours);
|
|
32585
|
+
}
|
|
32586
|
+
open(tab, paths);
|
|
32587
|
+
},
|
|
32588
|
+
left: (tab) => {
|
|
32589
|
+
gone.add(tab);
|
|
32590
|
+
open(tab);
|
|
32591
|
+
}
|
|
32592
|
+
};
|
|
32593
|
+
}
|
|
32594
|
+
unadopt(path, undo, fid) {
|
|
32595
|
+
for (const holds2 of this.held) holds2.unkeepAt(path, undo);
|
|
32596
|
+
void this.rootFs.announceHolds?.([[path, fid]], [], false);
|
|
32597
|
+
}
|
|
32598
|
+
adoptKept(path, hidden, fid, ours) {
|
|
32599
|
+
if (hidden === void 0 || !ours(hidden)) {
|
|
32600
|
+
this.held.doubt([path]);
|
|
32601
|
+
return;
|
|
32602
|
+
}
|
|
32603
|
+
const bound3 = [...this.held].map(
|
|
32604
|
+
(holds2) => [holds2, [...holds2.boundAt(path, fid), ...holds2.boundAt(hidden, fid)]]
|
|
32605
|
+
);
|
|
32606
|
+
const keeping = bound3.filter(([, ids]) => ids.length > 0);
|
|
32607
|
+
const file = this.unlinked.adopt(hidden, Math.max(keeping.length, 1));
|
|
32608
|
+
if (keeping.length === 0) file.release();
|
|
32609
|
+
for (const [holds2, ids] of keeping) holds2.keepBound(ids, path, file);
|
|
32610
|
+
void this.rootFs.announceHolds?.([], [path, hidden], false);
|
|
32611
|
+
}
|
|
32282
32612
|
rootFileId(path) {
|
|
32283
|
-
return this.mounts.locate(path) === void 0 ? this.rootFs.
|
|
32613
|
+
return this.mounts.locate(path) === void 0 ? this.rootFs.bindId?.(path) : void 0;
|
|
32284
32614
|
}
|
|
32285
32615
|
flushingPeers(fs) {
|
|
32286
32616
|
const peers = fs.peers?.();
|
|
@@ -32326,6 +32656,7 @@ var Launcher = class {
|
|
|
32326
32656
|
busy: (path) => [...this.openFiles].some((open) => open.holds(path)),
|
|
32327
32657
|
owner: this.unlinkOwnerOption,
|
|
32328
32658
|
marks: this.pathMarks,
|
|
32659
|
+
peers: this.rootFs.peerKeeps?.(),
|
|
32329
32660
|
...this.owners ? { dirOwner: { uid: 0, gid: 0, mode: 448 } } : {}
|
|
32330
32661
|
}
|
|
32331
32662
|
);
|