@ai-ecoverse/slicc-kernel 1.141.3 → 1.142.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 +17 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +492 -107
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +3 -0
- package/dist/meta.js.map +2 -2
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.js +113 -85
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +505 -110
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +14 -2
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/meta.d.ts +2 -0
- package/dist/types/fs/opfs.d.ts +30 -0
- package/dist/types/fs/remote.d.ts +15 -0
- package/dist/types/fs/types.d.ts +7 -0
- package/dist/types/kernel/proc-info.d.ts +7 -0
- package/dist/types/node.d.ts +1 -0
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/node.ts
|
|
2
|
+
import { isAbsolute } from "node:path";
|
|
2
3
|
import { MessageChannel as MessageChannel2, Worker } from "node:worker_threads";
|
|
3
4
|
|
|
4
5
|
// src/bytes.ts
|
|
@@ -3623,6 +3624,90 @@ function serveClient(port, host) {
|
|
|
3623
3624
|
return { detach, closed: ended.promise };
|
|
3624
3625
|
}
|
|
3625
3626
|
|
|
3627
|
+
// src/fs/changes.ts
|
|
3628
|
+
var GEN = 0;
|
|
3629
|
+
var RING = 1;
|
|
3630
|
+
var RING_SIZE = 4096;
|
|
3631
|
+
var SLOT = 2;
|
|
3632
|
+
var SHARED_TTL_MS = 100;
|
|
3633
|
+
var DIRTY = RING + RING_SIZE * SLOT;
|
|
3634
|
+
var FOREIGN = DIRTY + 1;
|
|
3635
|
+
var CHANGES_BYTES = (FOREIGN + 1) * 4;
|
|
3636
|
+
function changeHash(path) {
|
|
3637
|
+
let h = 2166136261;
|
|
3638
|
+
for (let i = 0; i < path.length; i++) {
|
|
3639
|
+
h ^= path.charCodeAt(i);
|
|
3640
|
+
h = Math.imul(h, 16777619);
|
|
3641
|
+
}
|
|
3642
|
+
return h === 0 ? 1 : h;
|
|
3643
|
+
}
|
|
3644
|
+
function normal(path) {
|
|
3645
|
+
const parts2 = [];
|
|
3646
|
+
for (const part of path.split("/")) {
|
|
3647
|
+
if (part === "" || part === ".") continue;
|
|
3648
|
+
if (part === "..") parts2.pop();
|
|
3649
|
+
else parts2.push(part);
|
|
3650
|
+
}
|
|
3651
|
+
return `/${parts2.join("/")}`;
|
|
3652
|
+
}
|
|
3653
|
+
var FileChanges = class {
|
|
3654
|
+
sab;
|
|
3655
|
+
view;
|
|
3656
|
+
constructor(sab = new SharedArrayBuffer(CHANGES_BYTES)) {
|
|
3657
|
+
this.sab = sab;
|
|
3658
|
+
this.view = new Int32Array(sab);
|
|
3659
|
+
}
|
|
3660
|
+
dirtied(delta) {
|
|
3661
|
+
Atomics.add(this.view, DIRTY, delta);
|
|
3662
|
+
}
|
|
3663
|
+
foreign(on) {
|
|
3664
|
+
Atomics.store(this.view, FOREIGN, on ? 1 : 0);
|
|
3665
|
+
}
|
|
3666
|
+
flush() {
|
|
3667
|
+
Atomics.add(this.view, GEN, RING_SIZE + 1);
|
|
3668
|
+
}
|
|
3669
|
+
publish(...paths) {
|
|
3670
|
+
for (const path of paths) {
|
|
3671
|
+
const g = Atomics.add(this.view, GEN, 1) + 1 | 0;
|
|
3672
|
+
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
3673
|
+
Atomics.store(this.view, at, 0);
|
|
3674
|
+
Atomics.store(this.view, at + 1, changeHash(normal(path)));
|
|
3675
|
+
Atomics.store(this.view, at, g);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
};
|
|
3679
|
+
var ChangeView = class {
|
|
3680
|
+
view;
|
|
3681
|
+
constructor(sab) {
|
|
3682
|
+
this.view = new Int32Array(sab);
|
|
3683
|
+
}
|
|
3684
|
+
now() {
|
|
3685
|
+
return Atomics.load(this.view, GEN);
|
|
3686
|
+
}
|
|
3687
|
+
clean() {
|
|
3688
|
+
return this.view.length > DIRTY && Atomics.load(this.view, DIRTY) === 0;
|
|
3689
|
+
}
|
|
3690
|
+
foreign() {
|
|
3691
|
+
return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
|
|
3692
|
+
}
|
|
3693
|
+
changedSince(seen, path) {
|
|
3694
|
+
const now = Atomics.load(this.view, GEN);
|
|
3695
|
+
const distance = now - seen >>> 0;
|
|
3696
|
+
if (distance === 0) return { now, changed: false };
|
|
3697
|
+
if (distance > RING_SIZE) return { now, changed: true };
|
|
3698
|
+
const hash = changeHash(normal(path));
|
|
3699
|
+
for (let i = 1; i <= distance; i++) {
|
|
3700
|
+
const g = seen + i | 0;
|
|
3701
|
+
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
3702
|
+
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
3703
|
+
const hit = Atomics.load(this.view, at + 1) === hash;
|
|
3704
|
+
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
3705
|
+
if (hit) return { now, changed: true };
|
|
3706
|
+
}
|
|
3707
|
+
return { now, changed: false };
|
|
3708
|
+
}
|
|
3709
|
+
};
|
|
3710
|
+
|
|
3626
3711
|
// src/fs/path-map.ts
|
|
3627
3712
|
function parentOf2(path) {
|
|
3628
3713
|
if (path === "/" || path === "") return void 0;
|
|
@@ -4157,6 +4242,8 @@ var ANNOUNCE_WAIT_MS = 500;
|
|
|
4157
4242
|
var PRUNE_EVERY_MS = 3e4;
|
|
4158
4243
|
var MOURN_TRIES = 5;
|
|
4159
4244
|
var MOURN_RETRY_MS = 100;
|
|
4245
|
+
var RENAME_ACK_MAX_MS = 1e4;
|
|
4246
|
+
var ANNOUNCE_POLL_MS = 20;
|
|
4160
4247
|
function lockManager() {
|
|
4161
4248
|
return globalThis.navigator?.locks;
|
|
4162
4249
|
}
|
|
@@ -4180,6 +4267,9 @@ var RemoteWatch = class {
|
|
|
4180
4267
|
quiet;
|
|
4181
4268
|
crowd;
|
|
4182
4269
|
gone;
|
|
4270
|
+
renaming;
|
|
4271
|
+
renamed;
|
|
4272
|
+
ackers = /* @__PURE__ */ new Set();
|
|
4183
4273
|
told;
|
|
4184
4274
|
counted = 0;
|
|
4185
4275
|
recount() {
|
|
@@ -4207,7 +4297,7 @@ var RemoteWatch = class {
|
|
|
4207
4297
|
this.settled = true;
|
|
4208
4298
|
this.recount();
|
|
4209
4299
|
});
|
|
4210
|
-
this.channel.postMessage({ hello: this.tab });
|
|
4300
|
+
this.channel.postMessage({ hello: this.tab, renames: true });
|
|
4211
4301
|
}
|
|
4212
4302
|
async join() {
|
|
4213
4303
|
if (!this.locks) return;
|
|
@@ -4228,6 +4318,20 @@ var RemoteWatch = class {
|
|
|
4228
4318
|
await this.joined;
|
|
4229
4319
|
return this.peers.size > 0;
|
|
4230
4320
|
}
|
|
4321
|
+
async joinedAll(cap) {
|
|
4322
|
+
if (!this.locks) return true;
|
|
4323
|
+
const prefix = `${this.name}:`;
|
|
4324
|
+
const began = performance.now();
|
|
4325
|
+
for (; ; ) {
|
|
4326
|
+
const held = ((await this.locks.query()).held ?? []).map((lock) => lock.name ?? "");
|
|
4327
|
+
const silent = held.some(
|
|
4328
|
+
(name2) => name2.startsWith(prefix) && name2 !== this.lockOf(this.tab) && !this.peers.has(name2.slice(prefix.length))
|
|
4329
|
+
);
|
|
4330
|
+
if (!silent) return true;
|
|
4331
|
+
if (performance.now() - began >= cap) return false;
|
|
4332
|
+
await new Promise((resolve2) => setTimeout(resolve2, ANNOUNCE_POLL_MS));
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4231
4335
|
crowded() {
|
|
4232
4336
|
return !this.settled || this.peers.size > 0;
|
|
4233
4337
|
}
|
|
@@ -4235,7 +4339,11 @@ var RemoteWatch = class {
|
|
|
4235
4339
|
return `${this.name}:${tab}`;
|
|
4236
4340
|
}
|
|
4237
4341
|
receive(data) {
|
|
4342
|
+
const sender = data.hello ?? data.here;
|
|
4343
|
+
if (sender !== void 0 && data.renames) this.ackers.add(sender);
|
|
4238
4344
|
if (data.hello !== void 0) this.greeted(data.hello);
|
|
4345
|
+
if (data.renaming !== void 0 && data.tab !== void 0) this.heard(data);
|
|
4346
|
+
if (data.renamed !== void 0) this.renamed?.(data.renamed);
|
|
4239
4347
|
if (data.here !== void 0 && data.to === this.tab) {
|
|
4240
4348
|
this.arrived(data.here);
|
|
4241
4349
|
this.met?.();
|
|
@@ -4267,6 +4375,7 @@ var RemoteWatch = class {
|
|
|
4267
4375
|
this.mourned.delete(peer);
|
|
4268
4376
|
this.others.delete(peer);
|
|
4269
4377
|
this.peers.delete(peer);
|
|
4378
|
+
this.ackers.delete(peer);
|
|
4270
4379
|
this.rebuild();
|
|
4271
4380
|
this.recount();
|
|
4272
4381
|
this.gone?.();
|
|
@@ -4278,12 +4387,18 @@ var RemoteWatch = class {
|
|
|
4278
4387
|
greeted(peer) {
|
|
4279
4388
|
this.arrived(peer);
|
|
4280
4389
|
const answer2 = () => {
|
|
4281
|
-
this.channel.postMessage({ here: this.tab, to: peer });
|
|
4390
|
+
this.channel.postMessage({ here: this.tab, to: peer, renames: true });
|
|
4282
4391
|
if (this.mine.length > 0) void this.announce(this.mine);
|
|
4283
4392
|
};
|
|
4284
4393
|
if (this.quiet) void this.quiet().then(answer2, answer2);
|
|
4285
4394
|
else answer2();
|
|
4286
4395
|
}
|
|
4396
|
+
heard({ tab, renaming, seq: seq2 }) {
|
|
4397
|
+
const ack = () => this.channel.postMessage({ ack: seq2, from: this.tab, to: tab });
|
|
4398
|
+
const heard = this.renaming?.(renaming);
|
|
4399
|
+
if (heard !== void 0) void heard.then(ack, ack);
|
|
4400
|
+
else ack();
|
|
4401
|
+
}
|
|
4287
4402
|
announced({ tab, paths, seq: seq2 }) {
|
|
4288
4403
|
const from = tab;
|
|
4289
4404
|
this.arrived(from);
|
|
@@ -4310,6 +4425,7 @@ var RemoteWatch = class {
|
|
|
4310
4425
|
if (!held.has(this.lockOf(tab))) {
|
|
4311
4426
|
if (this.peers.delete(tab)) left = true;
|
|
4312
4427
|
this.others.delete(tab);
|
|
4428
|
+
this.ackers.delete(tab);
|
|
4313
4429
|
}
|
|
4314
4430
|
}
|
|
4315
4431
|
this.rebuild();
|
|
@@ -4331,7 +4447,34 @@ var RemoteWatch = class {
|
|
|
4331
4447
|
this.mine = [...paths];
|
|
4332
4448
|
const seq2 = ++this.seq;
|
|
4333
4449
|
this.channel.postMessage({ tab: this.tab, paths: this.mine, seq: seq2 });
|
|
4334
|
-
|
|
4450
|
+
return this.acks(seq2, this.peers);
|
|
4451
|
+
}
|
|
4452
|
+
renamingTree(rename, cap = RENAME_ACK_MAX_MS) {
|
|
4453
|
+
const seq2 = ++this.seq;
|
|
4454
|
+
this.channel.postMessage({ tab: this.tab, renaming: rename, seq: seq2 });
|
|
4455
|
+
const left = new Set(this.ackers);
|
|
4456
|
+
if (left.size === 0) return Promise.resolve([]);
|
|
4457
|
+
const began = performance.now();
|
|
4458
|
+
return new Promise((resolve2) => {
|
|
4459
|
+
const done4 = () => {
|
|
4460
|
+
clearInterval(timer);
|
|
4461
|
+
this.waiting.delete(seq2);
|
|
4462
|
+
resolve2([...left]);
|
|
4463
|
+
};
|
|
4464
|
+
const timer = setInterval(() => {
|
|
4465
|
+
void this.prune().then(() => {
|
|
4466
|
+
for (const peer of left) if (!this.ackers.has(peer)) left.delete(peer);
|
|
4467
|
+
if (left.size === 0 || performance.now() - began >= cap) done4();
|
|
4468
|
+
});
|
|
4469
|
+
}, ANNOUNCE_WAIT_MS);
|
|
4470
|
+
this.waiting.set(seq2, { left, done: done4 });
|
|
4471
|
+
});
|
|
4472
|
+
}
|
|
4473
|
+
renamedTree(lock) {
|
|
4474
|
+
this.channel.postMessage({ renamed: lock });
|
|
4475
|
+
}
|
|
4476
|
+
acks(seq2, from) {
|
|
4477
|
+
if (from.size === 0) return Promise.resolve();
|
|
4335
4478
|
return new Promise((resolve2) => {
|
|
4336
4479
|
const done4 = () => {
|
|
4337
4480
|
clearTimeout(timer);
|
|
@@ -4342,7 +4485,7 @@ var RemoteWatch = class {
|
|
|
4342
4485
|
done4();
|
|
4343
4486
|
void this.prune();
|
|
4344
4487
|
}, ANNOUNCE_WAIT_MS);
|
|
4345
|
-
this.waiting.set(seq2, { left: new Set(
|
|
4488
|
+
this.waiting.set(seq2, { left: new Set(from), done: done4 });
|
|
4346
4489
|
});
|
|
4347
4490
|
}
|
|
4348
4491
|
emit(change) {
|
|
@@ -4405,6 +4548,12 @@ var RECONCILE_LISTINGS = 8;
|
|
|
4405
4548
|
var EXECUTABLE = /\/node_modules\/(?:@[^/]+\/)?[^/]+\/bin\//;
|
|
4406
4549
|
var RENAMES = "/.slicc-renames";
|
|
4407
4550
|
var RENAME_LOCK = "slicc-rename:";
|
|
4551
|
+
var RENAME_ADMIT = "slicc-rename-admit:";
|
|
4552
|
+
var PAIRED = /* @__PURE__ */ new Set(["rename", "link", "copyFile"]);
|
|
4553
|
+
var LISTINGS = /* @__PURE__ */ new Set(["readdir", "readdirStat"]);
|
|
4554
|
+
var RETRY = /* @__PURE__ */ Symbol("retry");
|
|
4555
|
+
var ACK_SAMPLES = 4096;
|
|
4556
|
+
var INTENT_POLL_MS = 5;
|
|
4408
4557
|
function movable(handle) {
|
|
4409
4558
|
return typeof handle.move === "function";
|
|
4410
4559
|
}
|
|
@@ -4449,6 +4598,7 @@ function sidecar(meta) {
|
|
|
4449
4598
|
for (const { path, change } of changes) await ops.update(path, change);
|
|
4450
4599
|
};
|
|
4451
4600
|
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
4601
|
+
if (meta.forgetTrees) ops.forgetTrees = meta.forgetTrees.bind(meta);
|
|
4452
4602
|
const { removeFile } = meta;
|
|
4453
4603
|
if (removeFile)
|
|
4454
4604
|
ops.removeFile = (path) => removeFile.call(meta, path).catch((err) => {
|
|
@@ -4570,7 +4720,17 @@ var OpfsFs = class {
|
|
|
4570
4720
|
this.remote = channel === void 0 ? void 0 : new RemoteWatch(`${channel}:watch`, { locks: this.locks ?? null });
|
|
4571
4721
|
if (this.remote) {
|
|
4572
4722
|
this.remote.quiet = () => this.quiet().then(() => this.settle?.());
|
|
4573
|
-
this.remote.gone = () =>
|
|
4723
|
+
this.remote.gone = () => {
|
|
4724
|
+
void this.orphans();
|
|
4725
|
+
for (const move of [...this.peerMoves.values()]) void this.peerMoved(move);
|
|
4726
|
+
};
|
|
4727
|
+
this.remote.renaming = (rename) => this.heardRename(rename);
|
|
4728
|
+
this.remote.renamed = (lock) => {
|
|
4729
|
+
const move = this.peerMoves.get(lock);
|
|
4730
|
+
if (!move) return;
|
|
4731
|
+
move.done = true;
|
|
4732
|
+
void this.peerMoved(move);
|
|
4733
|
+
};
|
|
4574
4734
|
}
|
|
4575
4735
|
if (this.channel) {
|
|
4576
4736
|
const remote = this.remote;
|
|
@@ -5614,16 +5774,27 @@ var OpfsFs = class {
|
|
|
5614
5774
|
throw fsError("EPERM", `${from}: this file system has no hard links`);
|
|
5615
5775
|
}
|
|
5616
5776
|
async rename(from, to) {
|
|
5777
|
+
const call = this.renameCall;
|
|
5778
|
+
this.renameCall = void 0;
|
|
5617
5779
|
if (from === to) return;
|
|
5780
|
+
for (; ; ) {
|
|
5781
|
+
try {
|
|
5782
|
+
return await this.renameOnce(from, to, call);
|
|
5783
|
+
} catch (err) {
|
|
5784
|
+
if (err !== RETRY) throw err;
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
}
|
|
5788
|
+
async renameOnce(from, to, call) {
|
|
5618
5789
|
const source = await this.locate(from, false);
|
|
5619
5790
|
this.refuse(source.path, true);
|
|
5620
5791
|
this.forget(source.path);
|
|
5621
5792
|
const parent = await this.locate(parentOf4(to), true);
|
|
5622
5793
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
5623
5794
|
this.refuse(destination, true);
|
|
5624
|
-
await this.entering(destination, () => this.moveTo(source, parent, destination, to));
|
|
5795
|
+
await this.entering(destination, () => this.moveTo(source, parent, destination, to, call));
|
|
5625
5796
|
}
|
|
5626
|
-
async moveTo(source, parent, destination, to) {
|
|
5797
|
+
async moveTo(source, parent, destination, to, call) {
|
|
5627
5798
|
const sourceStat = await this.describe(source);
|
|
5628
5799
|
if (sourceStat.isDirectory && within3(destination, source.path)) throw fsError("EINVAL", to);
|
|
5629
5800
|
const target = await this.exactly(() => this.locate(destination, false)).catch((err) => {
|
|
@@ -5658,6 +5829,7 @@ var OpfsFs = class {
|
|
|
5658
5829
|
const name2 = baseOf(destination);
|
|
5659
5830
|
const swap = targetStat?.isDirectory === true;
|
|
5660
5831
|
let lock;
|
|
5832
|
+
const hooks = {};
|
|
5661
5833
|
const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
|
|
5662
5834
|
const copying = sourceStat.isDirectory && !movable(source.handle);
|
|
5663
5835
|
const staged = resolvePath(parent.path, staging);
|
|
@@ -5666,8 +5838,15 @@ var OpfsFs = class {
|
|
|
5666
5838
|
const copies = /* @__PURE__ */ new Map();
|
|
5667
5839
|
const root = { ino: inodeOf(source.path), ...moving };
|
|
5668
5840
|
const owned4 = lock ? { lock } : {};
|
|
5841
|
+
hooks.notify?.();
|
|
5669
5842
|
const first = copying ? await this.intend({ from: source.path, to: staged, root, ...owned4 }) : void 0;
|
|
5670
5843
|
const second = copying && swap ? await this.intend({ from: staged, to: destination, replace: true, root, ...owned4 }) : void 0;
|
|
5844
|
+
await hooks.started?.().catch(async (err) => {
|
|
5845
|
+
for (const intent of [first, second]) {
|
|
5846
|
+
if (intent) await this.meta.update(intent, () => void 0);
|
|
5847
|
+
}
|
|
5848
|
+
throw err;
|
|
5849
|
+
});
|
|
5671
5850
|
const moved2 = await this.replacingTarget(
|
|
5672
5851
|
targetStat !== null,
|
|
5673
5852
|
() => this.place(source.handle, dir, staging, copies)
|
|
@@ -5702,13 +5881,262 @@ var OpfsFs = class {
|
|
|
5702
5881
|
const locks = this.locks;
|
|
5703
5882
|
if (locks) {
|
|
5704
5883
|
lock = `${RENAME_LOCK}${crypto.randomUUID()}`;
|
|
5705
|
-
|
|
5884
|
+
this.ownLocks.add(lock);
|
|
5885
|
+
call?.release();
|
|
5886
|
+
await this.admitted(locks, lock, source.path, destination, place, hooks);
|
|
5706
5887
|
} else await place();
|
|
5707
5888
|
} finally {
|
|
5889
|
+
if (lock) this.ownLocks.delete(lock);
|
|
5708
5890
|
this.renamingDirs.delete(entry);
|
|
5709
5891
|
resolve2();
|
|
5710
5892
|
}
|
|
5711
5893
|
}
|
|
5894
|
+
async admitted(locks, lock, from, to, place, hooks) {
|
|
5895
|
+
const remote = this.remote;
|
|
5896
|
+
if (remote && !this.shared() && !await remote.joinedAll(RENAME_ACK_MAX_MS)) {
|
|
5897
|
+
this.ackBusy++;
|
|
5898
|
+
console.warn(
|
|
5899
|
+
`slicc-kernel: renaming ${from} to ${to} gave up (EBUSY): a tab sharing the root did not finish joining in ${RENAME_ACK_MAX_MS} ms (#1140)`
|
|
5900
|
+
);
|
|
5901
|
+
throw fsError("EBUSY", from);
|
|
5902
|
+
}
|
|
5903
|
+
if (!remote || !this.shared()) {
|
|
5904
|
+
await locks.request(lock, place);
|
|
5905
|
+
return;
|
|
5906
|
+
}
|
|
5907
|
+
let clash;
|
|
5908
|
+
let run2;
|
|
5909
|
+
await locks.request(`${RENAME_ADMIT}${this.rootName ?? ""}`, async () => {
|
|
5910
|
+
if (await this.renamingElsewhere()) await this.learnRenames();
|
|
5911
|
+
clash = this.clashing(from, to);
|
|
5912
|
+
if (clash) return;
|
|
5913
|
+
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
5914
|
+
let told;
|
|
5915
|
+
hooks.notify = () => {
|
|
5916
|
+
told = remote.renamingTree({ from, to, lock });
|
|
5917
|
+
};
|
|
5918
|
+
hooks.started = async () => {
|
|
5919
|
+
resolve2();
|
|
5920
|
+
this.renameAcks++;
|
|
5921
|
+
const at = performance.now();
|
|
5922
|
+
const stuck = await told;
|
|
5923
|
+
this.ackMs.push(performance.now() - at);
|
|
5924
|
+
if (this.ackMs.length > ACK_SAMPLES) this.ackMs.shift();
|
|
5925
|
+
if (stuck.length === 0) return;
|
|
5926
|
+
this.ackBusy++;
|
|
5927
|
+
console.warn(
|
|
5928
|
+
`slicc-kernel: renaming ${from} to ${to} gave up (EBUSY): peer tab ${stuck.join(", ")} is alive but did not answer in ${RENAME_ACK_MAX_MS} ms (#1140)`
|
|
5929
|
+
);
|
|
5930
|
+
throw fsError("EBUSY", from);
|
|
5931
|
+
};
|
|
5932
|
+
run2 = locks.request(lock, async () => {
|
|
5933
|
+
await place();
|
|
5934
|
+
remote.renamedTree(lock);
|
|
5935
|
+
});
|
|
5936
|
+
await Promise.race([promise, run2.then(nothing, nothing)]);
|
|
5937
|
+
});
|
|
5938
|
+
if (clash) {
|
|
5939
|
+
this.peerWaited++;
|
|
5940
|
+
await this.peerMoved(clash);
|
|
5941
|
+
throw RETRY;
|
|
5942
|
+
}
|
|
5943
|
+
await run2;
|
|
5944
|
+
}
|
|
5945
|
+
renameAcks = 0;
|
|
5946
|
+
ackBusy = 0;
|
|
5947
|
+
ackMs = [];
|
|
5948
|
+
ownLocks = /* @__PURE__ */ new Set();
|
|
5949
|
+
peerMoves = /* @__PURE__ */ new Map();
|
|
5950
|
+
peerWaits = /* @__PURE__ */ new Map();
|
|
5951
|
+
inflight = /* @__PURE__ */ new Set();
|
|
5952
|
+
renameCall;
|
|
5953
|
+
looking;
|
|
5954
|
+
lookedAt = Number.NEGATIVE_INFINITY;
|
|
5955
|
+
peerWaited = 0;
|
|
5956
|
+
queries = 0;
|
|
5957
|
+
renameWaits() {
|
|
5958
|
+
return {
|
|
5959
|
+
acks: this.renameAcks,
|
|
5960
|
+
busy: this.ackBusy,
|
|
5961
|
+
waits: this.peerWaited,
|
|
5962
|
+
queries: this.queries,
|
|
5963
|
+
ackMs: this.ackMs
|
|
5964
|
+
};
|
|
5965
|
+
}
|
|
5966
|
+
notePeer(lock, tree2) {
|
|
5967
|
+
let known = this.peerMoves.get(lock);
|
|
5968
|
+
if (!known) {
|
|
5969
|
+
known = { lock, trees: [] };
|
|
5970
|
+
this.peerMoves.set(lock, known);
|
|
5971
|
+
}
|
|
5972
|
+
if (!known.trees.some(([a, b]) => a === tree2[0] && b === tree2[1])) known.trees.push(tree2);
|
|
5973
|
+
return known;
|
|
5974
|
+
}
|
|
5975
|
+
async learnRenames() {
|
|
5976
|
+
for (const { rename } of await this.meta.under(RENAMES)) {
|
|
5977
|
+
if (rename?.lock === void 0 || this.ownLocks.has(rename.lock)) continue;
|
|
5978
|
+
this.notePeer(rename.lock, [rename.from, rename.to]);
|
|
5979
|
+
}
|
|
5980
|
+
}
|
|
5981
|
+
async renamingElsewhere() {
|
|
5982
|
+
const { held = [] } = await this.locks.query();
|
|
5983
|
+
return held.some(({ name: name2 }) => name2?.startsWith(RENAME_LOCK) && !this.ownLocks.has(name2));
|
|
5984
|
+
}
|
|
5985
|
+
lookForRenames() {
|
|
5986
|
+
const locks = this.locks;
|
|
5987
|
+
const age = performance.now() - this.lookedAt;
|
|
5988
|
+
if (!locks || age < SHARED_TTL_MS / 2) return Promise.resolve();
|
|
5989
|
+
this.looking ??= (async () => {
|
|
5990
|
+
for (; ; ) {
|
|
5991
|
+
const asked = performance.now();
|
|
5992
|
+
this.queries++;
|
|
5993
|
+
const { held = [] } = await locks.query();
|
|
5994
|
+
const unknown = () => held.some(
|
|
5995
|
+
({ name: name2 }) => name2?.startsWith(RENAME_LOCK) && !this.ownLocks.has(name2) && !this.peerMoves.has(name2)
|
|
5996
|
+
);
|
|
5997
|
+
if (unknown()) await this.learnRenames();
|
|
5998
|
+
if (!unknown()) {
|
|
5999
|
+
this.lookedAt = asked;
|
|
6000
|
+
return;
|
|
6001
|
+
}
|
|
6002
|
+
await new Promise((resolve2) => setTimeout(resolve2, INTENT_POLL_MS));
|
|
6003
|
+
}
|
|
6004
|
+
})().finally(() => {
|
|
6005
|
+
this.looking = void 0;
|
|
6006
|
+
});
|
|
6007
|
+
if (age >= SHARED_TTL_MS) return this.looking;
|
|
6008
|
+
this.looking.catch(nothing);
|
|
6009
|
+
return Promise.resolve();
|
|
6010
|
+
}
|
|
6011
|
+
async heardRename({ from, to, lock }) {
|
|
6012
|
+
if (this.ownLocks.has(lock)) return;
|
|
6013
|
+
this.notePeer(lock, [from, to]);
|
|
6014
|
+
this.lookedAt = performance.now();
|
|
6015
|
+
const trees = [[from, to]];
|
|
6016
|
+
const running = [...this.inflight];
|
|
6017
|
+
const reached = await Promise.all(
|
|
6018
|
+
running.map(async (op) => {
|
|
6019
|
+
if (op.paths.some((at) => touches(at, trees))) return true;
|
|
6020
|
+
for (const at of op.paths) {
|
|
6021
|
+
const forms = await this.resolvedForms(at);
|
|
6022
|
+
if (forms.some((form) => touches(form, trees))) return true;
|
|
6023
|
+
}
|
|
6024
|
+
return false;
|
|
6025
|
+
})
|
|
6026
|
+
);
|
|
6027
|
+
const busy = running.filter((op, i) => reached[i] && this.inflight.has(op));
|
|
6028
|
+
if (this.aloneCalls > 0) {
|
|
6029
|
+
this.aloneDrain ??= Promise.withResolvers();
|
|
6030
|
+
busy.push({ paths: [], waiting: this.aloneDrain, release: nothing });
|
|
6031
|
+
}
|
|
6032
|
+
await Promise.all(
|
|
6033
|
+
busy.map((op) => {
|
|
6034
|
+
op.waiting ??= Promise.withResolvers();
|
|
6035
|
+
return op.waiting.promise;
|
|
6036
|
+
})
|
|
6037
|
+
);
|
|
6038
|
+
}
|
|
6039
|
+
peerAt(at, listing) {
|
|
6040
|
+
for (const move of this.peerMoves.values()) {
|
|
6041
|
+
if (this.ownLocks.has(move.lock)) continue;
|
|
6042
|
+
if (touches(at, move.trees, listing)) return move;
|
|
6043
|
+
}
|
|
6044
|
+
return void 0;
|
|
6045
|
+
}
|
|
6046
|
+
clashing(from, to) {
|
|
6047
|
+
for (const move of this.peerMoves.values()) {
|
|
6048
|
+
for (const tree2 of move.trees) {
|
|
6049
|
+
for (const mine of [from, to]) {
|
|
6050
|
+
if (tree2.some((theirs) => within3(mine, theirs) || within3(theirs, mine))) return move;
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
return void 0;
|
|
6055
|
+
}
|
|
6056
|
+
peerMoved(move) {
|
|
6057
|
+
const locks = this.locks;
|
|
6058
|
+
let wait2 = this.peerWaits.get(move.lock);
|
|
6059
|
+
if (wait2 !== void 0) return wait2;
|
|
6060
|
+
wait2 = (async () => {
|
|
6061
|
+
if (!move.done)
|
|
6062
|
+
await locks.request(move.lock, async () => {
|
|
6063
|
+
if (move.done) return;
|
|
6064
|
+
const left = (await this.meta.under(RENAMES)).filter((entry) => entry.rename?.lock === move.lock).sort(byIntent);
|
|
6065
|
+
for (const entry of left) await this.finishRename(entry);
|
|
6066
|
+
});
|
|
6067
|
+
this.peerMoves.delete(move.lock);
|
|
6068
|
+
for (const [from, to] of move.trees) {
|
|
6069
|
+
this.forget(from);
|
|
6070
|
+
this.forget(to);
|
|
6071
|
+
this.meta.forgetTrees?.([from, to]);
|
|
6072
|
+
}
|
|
6073
|
+
})().finally(() => this.peerWaits.delete(move.lock));
|
|
6074
|
+
this.peerWaits.set(move.lock, wait2);
|
|
6075
|
+
return wait2;
|
|
6076
|
+
}
|
|
6077
|
+
async peerSettled(at, listing) {
|
|
6078
|
+
await this.lookForRenames();
|
|
6079
|
+
for (let reals; ; ) {
|
|
6080
|
+
const forms = [at, ...reals ?? []];
|
|
6081
|
+
const move = forms.map((form) => this.peerAt(form, listing)).find(Boolean);
|
|
6082
|
+
if (move) {
|
|
6083
|
+
this.peerWaited++;
|
|
6084
|
+
await this.peerMoved(move);
|
|
6085
|
+
continue;
|
|
6086
|
+
}
|
|
6087
|
+
if (reals !== void 0 || at === "/" || this.peerMoves.size === 0) return forms;
|
|
6088
|
+
reals = await this.resolvedForms(at);
|
|
6089
|
+
if (reals.length === 0) return forms;
|
|
6090
|
+
}
|
|
6091
|
+
}
|
|
6092
|
+
aloneCalls = 0;
|
|
6093
|
+
aloneDrain;
|
|
6094
|
+
async alonePlain(inner, args) {
|
|
6095
|
+
this.aloneCalls++;
|
|
6096
|
+
try {
|
|
6097
|
+
return await inner.apply(this, args);
|
|
6098
|
+
} finally {
|
|
6099
|
+
this.aloneCalls--;
|
|
6100
|
+
if (this.aloneCalls === 0 && this.aloneDrain) {
|
|
6101
|
+
this.aloneDrain.resolve();
|
|
6102
|
+
this.aloneDrain = void 0;
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
}
|
|
6106
|
+
async resolvedForms(at) {
|
|
6107
|
+
if (at === "/") return [];
|
|
6108
|
+
const parent = await PLAIN.realpath.call(this, parentOf4(at), true).catch(() => parentOf4(at));
|
|
6109
|
+
const named = resolvePath(parent, baseOf(at));
|
|
6110
|
+
const target = await PLAIN.realpath.call(this, at, true).catch(() => named);
|
|
6111
|
+
return [.../* @__PURE__ */ new Set([named, target])].filter((form) => form !== at);
|
|
6112
|
+
}
|
|
6113
|
+
amongPeers() {
|
|
6114
|
+
return this.remote !== void 0 && this.locks !== void 0 && this.shared();
|
|
6115
|
+
}
|
|
6116
|
+
async peerOp(name2, args, inner) {
|
|
6117
|
+
const paths = (name2 === "symlink" ? args.slice(1, 2) : PAIRED.has(name2) ? args.slice(0, 2) : args.slice(0, 1)).filter((path) => typeof path === "string").map(normalizePath);
|
|
6118
|
+
const listing = LISTINGS.has(name2);
|
|
6119
|
+
const checked = [...paths];
|
|
6120
|
+
while (this.amongPeers()) {
|
|
6121
|
+
checked.length = 0;
|
|
6122
|
+
for (const at of paths) checked.push(...await this.peerSettled(at, listing));
|
|
6123
|
+
if (!checked.some((at) => this.peerAt(at, listing))) break;
|
|
6124
|
+
}
|
|
6125
|
+
const busy = { paths: checked, release: () => void 0 };
|
|
6126
|
+
const done4 = () => {
|
|
6127
|
+
this.inflight.delete(busy);
|
|
6128
|
+
busy.waiting?.resolve();
|
|
6129
|
+
};
|
|
6130
|
+
busy.release = done4;
|
|
6131
|
+
this.inflight.add(busy);
|
|
6132
|
+
if (name2 === "rename") this.renameCall = busy;
|
|
6133
|
+
if (name2 !== "writeSession") return await inner.apply(this, args).finally(done4);
|
|
6134
|
+
const session = await inner.apply(this, args).catch((err) => {
|
|
6135
|
+
done4();
|
|
6136
|
+
throw err;
|
|
6137
|
+
});
|
|
6138
|
+
return { ...session, close: () => session.close().finally(done4) };
|
|
6139
|
+
}
|
|
5712
6140
|
renamingDirs = /* @__PURE__ */ new Set();
|
|
5713
6141
|
intents = 0;
|
|
5714
6142
|
async intend(rename, at = `${RENAMES}/${crypto.randomUUID()}`) {
|
|
@@ -5754,7 +6182,7 @@ var OpfsFs = class {
|
|
|
5754
6182
|
);
|
|
5755
6183
|
for (const entry of intents) {
|
|
5756
6184
|
const lock = entry.rename.lock;
|
|
5757
|
-
if (!
|
|
6185
|
+
if (!locks || !lock) await this.finishRename(entry);
|
|
5758
6186
|
else await locks.request(lock, () => this.finishRename(entry));
|
|
5759
6187
|
}
|
|
5760
6188
|
return intents.length;
|
|
@@ -5770,7 +6198,8 @@ var OpfsFs = class {
|
|
|
5770
6198
|
this.forget(to);
|
|
5771
6199
|
try {
|
|
5772
6200
|
const left = await this.real(from);
|
|
5773
|
-
if (left && replace && await this.real(to))
|
|
6201
|
+
if (left && replace && await this.real(to))
|
|
6202
|
+
await PLAIN.rm.call(this, to, { recursive: true });
|
|
5774
6203
|
if (left) {
|
|
5775
6204
|
const source = await this.locate(from, false);
|
|
5776
6205
|
const target = await this.locate(parentOf4(to), true);
|
|
@@ -5784,7 +6213,7 @@ var OpfsFs = class {
|
|
|
5784
6213
|
this.forget(from);
|
|
5785
6214
|
this.forget(to);
|
|
5786
6215
|
}
|
|
5787
|
-
if ((await this.meta.under(from)).
|
|
6216
|
+
if ((await this.meta.under(from)).some((entry2) => !entry2.vacated)) {
|
|
5788
6217
|
await this.meta.move(
|
|
5789
6218
|
from,
|
|
5790
6219
|
to,
|
|
@@ -6115,6 +6544,21 @@ var OpfsFs = class {
|
|
|
6115
6544
|
return removed;
|
|
6116
6545
|
}
|
|
6117
6546
|
};
|
|
6547
|
+
function nothing() {
|
|
6548
|
+
return void 0;
|
|
6549
|
+
}
|
|
6550
|
+
function touches(at, trees, listing = true) {
|
|
6551
|
+
return trees.some(
|
|
6552
|
+
([from, to]) => within3(at, from) || within3(at, to) || listing && (at === parentOf4(from) || at === parentOf4(to))
|
|
6553
|
+
);
|
|
6554
|
+
}
|
|
6555
|
+
function byIntent(a, b) {
|
|
6556
|
+
return a.rename.at - b.rename.at;
|
|
6557
|
+
}
|
|
6558
|
+
var PLAIN = {
|
|
6559
|
+
rm: OpfsFs.prototype.rm,
|
|
6560
|
+
realpath: OpfsFs.prototype.realpath
|
|
6561
|
+
};
|
|
6118
6562
|
var READS = [
|
|
6119
6563
|
"stat",
|
|
6120
6564
|
"lstat",
|
|
@@ -6145,6 +6589,14 @@ var WRITES = [
|
|
|
6145
6589
|
"lutimes",
|
|
6146
6590
|
"chown"
|
|
6147
6591
|
];
|
|
6592
|
+
{
|
|
6593
|
+
const proto = OpfsFs.prototype;
|
|
6594
|
+
const inner = proto.createExclusive;
|
|
6595
|
+
proto.createExclusive = function(...args) {
|
|
6596
|
+
if (this.amongPeers()) return this.peerOp("createExclusive", args, inner);
|
|
6597
|
+
return this.alonePlain(inner, args);
|
|
6598
|
+
};
|
|
6599
|
+
}
|
|
6148
6600
|
for (const [names2, op] of [
|
|
6149
6601
|
[READS, "read"],
|
|
6150
6602
|
[WRITES, "write"]
|
|
@@ -6155,7 +6607,9 @@ for (const [names2, op] of [
|
|
|
6155
6607
|
proto[name2] = async function(...args) {
|
|
6156
6608
|
try {
|
|
6157
6609
|
if (op === "read") await this.settledRename(args[0]);
|
|
6158
|
-
|
|
6610
|
+
if (this.amongPeers() || name2 === "writeSession")
|
|
6611
|
+
return await this.peerOp(name2, args, inner);
|
|
6612
|
+
return await this.alonePlain(inner, args);
|
|
6159
6613
|
} catch (err) {
|
|
6160
6614
|
throw translate(err, String(args[0]), op, false);
|
|
6161
6615
|
}
|
|
@@ -7514,7 +7968,7 @@ function satisfies(version, range2) {
|
|
|
7514
7968
|
}
|
|
7515
7969
|
|
|
7516
7970
|
// src/version.ts
|
|
7517
|
-
var KERNEL_VERSION = true ? "1.
|
|
7971
|
+
var KERNEL_VERSION = true ? "1.142.1" : "0.0.0-dev";
|
|
7518
7972
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7519
7973
|
function procVersion() {
|
|
7520
7974
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9513,89 +9967,6 @@ var FileWatches = class {
|
|
|
9513
9967
|
}
|
|
9514
9968
|
};
|
|
9515
9969
|
|
|
9516
|
-
// src/fs/changes.ts
|
|
9517
|
-
var GEN = 0;
|
|
9518
|
-
var RING = 1;
|
|
9519
|
-
var RING_SIZE = 4096;
|
|
9520
|
-
var SLOT = 2;
|
|
9521
|
-
var DIRTY = RING + RING_SIZE * SLOT;
|
|
9522
|
-
var FOREIGN = DIRTY + 1;
|
|
9523
|
-
var CHANGES_BYTES = (FOREIGN + 1) * 4;
|
|
9524
|
-
function changeHash(path) {
|
|
9525
|
-
let h = 2166136261;
|
|
9526
|
-
for (let i = 0; i < path.length; i++) {
|
|
9527
|
-
h ^= path.charCodeAt(i);
|
|
9528
|
-
h = Math.imul(h, 16777619);
|
|
9529
|
-
}
|
|
9530
|
-
return h === 0 ? 1 : h;
|
|
9531
|
-
}
|
|
9532
|
-
function normal(path) {
|
|
9533
|
-
const parts2 = [];
|
|
9534
|
-
for (const part of path.split("/")) {
|
|
9535
|
-
if (part === "" || part === ".") continue;
|
|
9536
|
-
if (part === "..") parts2.pop();
|
|
9537
|
-
else parts2.push(part);
|
|
9538
|
-
}
|
|
9539
|
-
return `/${parts2.join("/")}`;
|
|
9540
|
-
}
|
|
9541
|
-
var FileChanges = class {
|
|
9542
|
-
sab;
|
|
9543
|
-
view;
|
|
9544
|
-
constructor(sab = new SharedArrayBuffer(CHANGES_BYTES)) {
|
|
9545
|
-
this.sab = sab;
|
|
9546
|
-
this.view = new Int32Array(sab);
|
|
9547
|
-
}
|
|
9548
|
-
dirtied(delta) {
|
|
9549
|
-
Atomics.add(this.view, DIRTY, delta);
|
|
9550
|
-
}
|
|
9551
|
-
foreign(on) {
|
|
9552
|
-
Atomics.store(this.view, FOREIGN, on ? 1 : 0);
|
|
9553
|
-
}
|
|
9554
|
-
flush() {
|
|
9555
|
-
Atomics.add(this.view, GEN, RING_SIZE + 1);
|
|
9556
|
-
}
|
|
9557
|
-
publish(...paths) {
|
|
9558
|
-
for (const path of paths) {
|
|
9559
|
-
const g = Atomics.add(this.view, GEN, 1) + 1 | 0;
|
|
9560
|
-
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
9561
|
-
Atomics.store(this.view, at, 0);
|
|
9562
|
-
Atomics.store(this.view, at + 1, changeHash(normal(path)));
|
|
9563
|
-
Atomics.store(this.view, at, g);
|
|
9564
|
-
}
|
|
9565
|
-
}
|
|
9566
|
-
};
|
|
9567
|
-
var ChangeView = class {
|
|
9568
|
-
view;
|
|
9569
|
-
constructor(sab) {
|
|
9570
|
-
this.view = new Int32Array(sab);
|
|
9571
|
-
}
|
|
9572
|
-
now() {
|
|
9573
|
-
return Atomics.load(this.view, GEN);
|
|
9574
|
-
}
|
|
9575
|
-
clean() {
|
|
9576
|
-
return this.view.length > DIRTY && Atomics.load(this.view, DIRTY) === 0;
|
|
9577
|
-
}
|
|
9578
|
-
foreign() {
|
|
9579
|
-
return this.view.length > FOREIGN && Atomics.load(this.view, FOREIGN) === 1;
|
|
9580
|
-
}
|
|
9581
|
-
changedSince(seen, path) {
|
|
9582
|
-
const now = Atomics.load(this.view, GEN);
|
|
9583
|
-
const distance = now - seen >>> 0;
|
|
9584
|
-
if (distance === 0) return { now, changed: false };
|
|
9585
|
-
if (distance > RING_SIZE) return { now, changed: true };
|
|
9586
|
-
const hash = changeHash(normal(path));
|
|
9587
|
-
for (let i = 1; i <= distance; i++) {
|
|
9588
|
-
const g = seen + i | 0;
|
|
9589
|
-
const at = RING + (g & RING_SIZE - 1) * SLOT;
|
|
9590
|
-
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
9591
|
-
const hit = Atomics.load(this.view, at + 1) === hash;
|
|
9592
|
-
if (Atomics.load(this.view, at) !== g) return { now, changed: true };
|
|
9593
|
-
if (hit) return { now, changed: true };
|
|
9594
|
-
}
|
|
9595
|
-
return { now, changed: false };
|
|
9596
|
-
}
|
|
9597
|
-
};
|
|
9598
|
-
|
|
9599
9970
|
// src/fs/commands.ts
|
|
9600
9971
|
var S_IFDIR2 = 16384;
|
|
9601
9972
|
var S_IFREG2 = 32768;
|
|
@@ -10024,10 +10395,10 @@ var FreshModules = class {
|
|
|
10024
10395
|
const ranged2 = rangedOps(fs);
|
|
10025
10396
|
if (ranged2) {
|
|
10026
10397
|
overrides.pwrite = async (path, at, bytes, transfer) => {
|
|
10027
|
-
const
|
|
10398
|
+
const touches3 = at < MAGIC.length && this.fresh.has(normalizePath(path));
|
|
10028
10399
|
const first = at === 0 && bytes.length >= MAGIC.length ? bytes.slice(0, MAGIC.length) : void 0;
|
|
10029
10400
|
await ranged2.pwrite(path, at, bytes, transfer);
|
|
10030
|
-
if (
|
|
10401
|
+
if (touches3) await decide(path, first);
|
|
10031
10402
|
};
|
|
10032
10403
|
overrides.truncate = async (path, size) => {
|
|
10033
10404
|
await ranged2.truncate(path, size);
|
|
@@ -10104,7 +10475,7 @@ var baseOf3 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
|
10104
10475
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
10105
10476
|
var under3 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
10106
10477
|
var parentOf7 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
10107
|
-
function
|
|
10478
|
+
function touches2(watcher, changed) {
|
|
10108
10479
|
return watcher.paths.some(
|
|
10109
10480
|
(watched) => changed === watched || under3(watched, changed) || (watcher.recursive ? under3(changed, watched) : parentOf7(changed) === watched)
|
|
10110
10481
|
);
|
|
@@ -10232,7 +10603,7 @@ var FsWatchers = class {
|
|
|
10232
10603
|
for (const watcher of this.watchers) {
|
|
10233
10604
|
for (const path of paths) {
|
|
10234
10605
|
const changed = normalizePath(path);
|
|
10235
|
-
if (
|
|
10606
|
+
if (touches2(watcher, changed)) watcher.pending.add(changed);
|
|
10236
10607
|
}
|
|
10237
10608
|
if (watcher.pending.size === 0 || watcher.scheduled) continue;
|
|
10238
10609
|
watcher.scheduled = true;
|
|
@@ -13897,7 +14268,18 @@ var SYS_TREE = {
|
|
|
13897
14268
|
slicc_opfs_ops: (listing) => `${listing.opfsOps ?? 0}
|
|
13898
14269
|
`,
|
|
13899
14270
|
slicc_cwd_checks: (listing) => `${listing.cwdChecks ?? 0}
|
|
13900
|
-
|
|
14271
|
+
`,
|
|
14272
|
+
slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
|
|
14273
|
+
`,
|
|
14274
|
+
slicc_rename_acks: (listing) => {
|
|
14275
|
+
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
14276
|
+
const median = samples[Math.floor(samples.length / 2)] ?? 0;
|
|
14277
|
+
const most = samples.at(-1) ?? 0;
|
|
14278
|
+
const waits = listing.renameAcks?.waits ?? 0;
|
|
14279
|
+
const queries = listing.renameAcks?.queries ?? 0;
|
|
14280
|
+
return `${listing.renameAcks?.acks ?? 0} ${median.toFixed(1)} ${most.toFixed(1)} ${waits} ${queries}
|
|
14281
|
+
`;
|
|
14282
|
+
}
|
|
13901
14283
|
}
|
|
13902
14284
|
};
|
|
13903
14285
|
function isSysFile(at) {
|
|
@@ -19569,7 +19951,7 @@ function sniffPg(start2) {
|
|
|
19569
19951
|
const length2 = int32(bytes, 0);
|
|
19570
19952
|
return length2 >= 8 && length2 <= PG_MESSAGE_MAX && int32(bytes, 4) === PROTOCOL_3 ? "yes" : "no";
|
|
19571
19953
|
}
|
|
19572
|
-
var
|
|
19954
|
+
var PLAIN2 = "SCRAM-SHA-256";
|
|
19573
19955
|
var PLUS = "SCRAM-SHA-256-PLUS";
|
|
19574
19956
|
var END_POINT = "p=tls-server-end-point,,";
|
|
19575
19957
|
var SASL = 10;
|
|
@@ -19691,7 +20073,7 @@ function pgLength(bytes, started) {
|
|
|
19691
20073
|
const length2 = int32(bytes, started ? 1 : 0);
|
|
19692
20074
|
return started ? 1 + length2 : length2;
|
|
19693
20075
|
}
|
|
19694
|
-
var MECHANISMS = /* @__PURE__ */ new Set([
|
|
20076
|
+
var MECHANISMS = /* @__PURE__ */ new Set([PLAIN2, PLUS]);
|
|
19695
20077
|
async function cleartext(message3, asks) {
|
|
19696
20078
|
const body = latin2(message3.subarray(5));
|
|
19697
20079
|
if (!body.endsWith("\0") || body.indexOf("\0") !== body.length - 1)
|
|
@@ -19724,7 +20106,7 @@ function serverHeader(header5, server) {
|
|
|
19724
20106
|
function rewritten(first, header5) {
|
|
19725
20107
|
const parsed2 = clientFirstOf(first.data);
|
|
19726
20108
|
if (!parsed2 || parsed2.header === header5) return first;
|
|
19727
|
-
return { mechanism: header5 === END_POINT ? PLUS :
|
|
20109
|
+
return { mechanism: header5 === END_POINT ? PLUS : PLAIN2, data: `${header5}${parsed2.bare}` };
|
|
19728
20110
|
}
|
|
19729
20111
|
var PgClient = class {
|
|
19730
20112
|
clientFirst;
|
|
@@ -27414,7 +27796,7 @@ var RULE = new RegExp(
|
|
|
27414
27796
|
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
27415
27797
|
);
|
|
27416
27798
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
27417
|
-
var
|
|
27799
|
+
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
27418
27800
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
27419
27801
|
function failed2(errno3, error) {
|
|
27420
27802
|
return { error, errno: errno3 };
|
|
@@ -27441,7 +27823,7 @@ function splitWords(text) {
|
|
|
27441
27823
|
return words2;
|
|
27442
27824
|
}
|
|
27443
27825
|
function quoteWord(word) {
|
|
27444
|
-
return
|
|
27826
|
+
return PLAIN3.test(word) ? word : `'${word.replaceAll("'", `'\\''`)}'`;
|
|
27445
27827
|
}
|
|
27446
27828
|
function validWho(who) {
|
|
27447
27829
|
if (who === "ALL") return true;
|
|
@@ -29250,7 +29632,8 @@ var Launcher = class {
|
|
|
29250
29632
|
fsCalls: servedFsCalls(),
|
|
29251
29633
|
opfsCalls: this.rootFs.opfsCalls?.() ?? 0,
|
|
29252
29634
|
opfsOps: this.rootFs.opfsOps?.() ?? 0,
|
|
29253
|
-
cwdChecks: this.cwds.checks
|
|
29635
|
+
cwdChecks: this.cwds.checks,
|
|
29636
|
+
renameAcks: this.rootFs.renameWaits?.()
|
|
29254
29637
|
}),
|
|
29255
29638
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
29256
29639
|
crontab: (call) => this.crontab(pid, call),
|
|
@@ -31716,7 +32099,7 @@ function nodeTransport(options = {}) {
|
|
|
31716
32099
|
}
|
|
31717
32100
|
var TERMINATED = "the kernel is terminated";
|
|
31718
32101
|
var EXIT_GRACE_MS = 50;
|
|
31719
|
-
function nodeWorker(file, live, closed) {
|
|
32102
|
+
function nodeWorker(file, live, closed, workerData) {
|
|
31720
32103
|
const errors = /* @__PURE__ */ new Set();
|
|
31721
32104
|
const messages = /* @__PURE__ */ new Map();
|
|
31722
32105
|
const fail3 = (message3) => {
|
|
@@ -31725,7 +32108,7 @@ function nodeWorker(file, live, closed) {
|
|
|
31725
32108
|
} });
|
|
31726
32109
|
}
|
|
31727
32110
|
};
|
|
31728
|
-
const worker = closed ? void 0 : new Worker(file);
|
|
32111
|
+
const worker = closed ? void 0 : new Worker(file, { env: workerEnv(), ...workerData ? { workerData } : {} });
|
|
31729
32112
|
let ending = false;
|
|
31730
32113
|
if (worker) {
|
|
31731
32114
|
const kill = () => {
|
|
@@ -31777,6 +32160,17 @@ function cronLock(root) {
|
|
|
31777
32160
|
if (!lock) cronLocks2.set(root, lock = `slicc-kernel-cron:${crypto.randomUUID()}`);
|
|
31778
32161
|
return lock;
|
|
31779
32162
|
}
|
|
32163
|
+
function workerEnv() {
|
|
32164
|
+
const { NODE_COMPILE_CACHE: _inherited, ...env } = process.env;
|
|
32165
|
+
return env;
|
|
32166
|
+
}
|
|
32167
|
+
function cacheDirOf(dir) {
|
|
32168
|
+
if (dir === void 0) return void 0;
|
|
32169
|
+
if (typeof dir !== "string" || !isAbsolute(dir)) {
|
|
32170
|
+
throw new TypeError("createNodeKernel: compileCache must be an absolute directory path");
|
|
32171
|
+
}
|
|
32172
|
+
return dir;
|
|
32173
|
+
}
|
|
31780
32174
|
async function createNodeKernel(options = {}) {
|
|
31781
32175
|
const root = options.root ?? memoryRoot();
|
|
31782
32176
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
@@ -31786,11 +32180,12 @@ async function createNodeKernel(options = {}) {
|
|
|
31786
32180
|
const clients = /* @__PURE__ */ new Set();
|
|
31787
32181
|
let terminated = false;
|
|
31788
32182
|
const file = options.worker ?? new URL("./node-process-worker.js", import.meta.url);
|
|
32183
|
+
const compileCache = cacheDirOf(options.compileCache);
|
|
31789
32184
|
const transport = options.network?.transport;
|
|
31790
32185
|
const launcher = new Launcher({
|
|
31791
32186
|
fs,
|
|
31792
32187
|
unlinkOwner: pidOwner(process),
|
|
31793
|
-
createWorker: () => nodeWorker(file, live, terminated),
|
|
32188
|
+
createWorker: () => nodeWorker(file, live, terminated, compileCache ? { compileCache } : void 0),
|
|
31794
32189
|
createDriverWorker: () => nodeWorker(
|
|
31795
32190
|
options.driverWorker ?? new URL("./node-driver-worker.js", import.meta.url),
|
|
31796
32191
|
live,
|