@ai-ecoverse/slicc-kernel 1.39.1 → 1.39.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/kernel-worker.js +101 -26
- package/dist/kernel-worker.js.map +2 -2
- package/dist/node-process-worker.js +56 -7
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +290 -201
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +56 -7
- package/dist/process-worker.js.map +2 -2
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -2606,6 +2606,210 @@ var OpfsFs = class {
|
|
|
2606
2606
|
}
|
|
2607
2607
|
};
|
|
2608
2608
|
|
|
2609
|
+
// src/fs/unlinked.ts
|
|
2610
|
+
var UNLINKED_DIR = ".slicc-unlinked";
|
|
2611
|
+
function pidOwner(proc) {
|
|
2612
|
+
return {
|
|
2613
|
+
id: `p${proc.pid}`,
|
|
2614
|
+
alive(id) {
|
|
2615
|
+
try {
|
|
2616
|
+
proc.kill(Number(id.slice(1)), 0);
|
|
2617
|
+
return true;
|
|
2618
|
+
} catch (err) {
|
|
2619
|
+
return err.code !== "ESRCH";
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
2624
|
+
function webLocks() {
|
|
2625
|
+
return globalThis.navigator?.locks;
|
|
2626
|
+
}
|
|
2627
|
+
var within2 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
2628
|
+
var parentOf3 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
2629
|
+
var lockName = (instance) => `slicc-unlinked:${instance}`;
|
|
2630
|
+
var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
|
|
2631
|
+
var PathGate = class {
|
|
2632
|
+
tails = /* @__PURE__ */ new Map();
|
|
2633
|
+
async acquire(path) {
|
|
2634
|
+
const prev = this.tails.get(path) ?? Promise.resolve();
|
|
2635
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
2636
|
+
const tail = prev.then(() => promise);
|
|
2637
|
+
this.tails.set(path, tail);
|
|
2638
|
+
await prev;
|
|
2639
|
+
return () => {
|
|
2640
|
+
resolve();
|
|
2641
|
+
if (this.tails.get(path) === tail) this.tails.delete(path);
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2644
|
+
async run(path, op) {
|
|
2645
|
+
const release = await this.acquire(path);
|
|
2646
|
+
try {
|
|
2647
|
+
return await op();
|
|
2648
|
+
} finally {
|
|
2649
|
+
release();
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
var UnlinkedKeeper = class {
|
|
2654
|
+
fs;
|
|
2655
|
+
holders;
|
|
2656
|
+
rootOf;
|
|
2657
|
+
locks;
|
|
2658
|
+
busy;
|
|
2659
|
+
waiting = /* @__PURE__ */ new Set();
|
|
2660
|
+
owner;
|
|
2661
|
+
instance;
|
|
2662
|
+
gate = new PathGate();
|
|
2663
|
+
queue = Promise.resolve();
|
|
2664
|
+
count = 0;
|
|
2665
|
+
constructor(fs, holders, rootOf, options = {}) {
|
|
2666
|
+
const { locks, owner } = options;
|
|
2667
|
+
this.fs = fs;
|
|
2668
|
+
this.holders = holders;
|
|
2669
|
+
this.rootOf = rootOf;
|
|
2670
|
+
this.locks = locks;
|
|
2671
|
+
this.busy = options.busy ?? (() => false);
|
|
2672
|
+
this.owner = owner;
|
|
2673
|
+
this.instance = owner ? `${owner.id}~${crypto.randomUUID()}` : crypto.randomUUID();
|
|
2674
|
+
void locks?.request(lockName(this.instance), () => new Promise(() => void 0));
|
|
2675
|
+
}
|
|
2676
|
+
serial(op) {
|
|
2677
|
+
const next = this.queue.then(op);
|
|
2678
|
+
this.queue = next.catch(() => void 0);
|
|
2679
|
+
return next;
|
|
2680
|
+
}
|
|
2681
|
+
wrap(fs = this.fs) {
|
|
2682
|
+
const keeper = this;
|
|
2683
|
+
const visible = (names) => names.filter((name2) => name2 !== UNLINKED_DIR);
|
|
2684
|
+
return {
|
|
2685
|
+
...fs,
|
|
2686
|
+
async rm(path, options) {
|
|
2687
|
+
const target = fs.resolvePath("/", path);
|
|
2688
|
+
const pinned = await keeper.pin(target);
|
|
2689
|
+
if (pinned.moved.has(target)) pinned.commit();
|
|
2690
|
+
else await keeper.settle(pinned, () => fs.rm(path, options));
|
|
2691
|
+
},
|
|
2692
|
+
async rename(from, to) {
|
|
2693
|
+
const target = fs.resolvePath("/", to);
|
|
2694
|
+
if (target === fs.resolvePath("/", from)) return fs.rename(from, to);
|
|
2695
|
+
const pinned = await keeper.pin(target);
|
|
2696
|
+
await keeper.settle(pinned, () => fs.rename(from, to));
|
|
2697
|
+
},
|
|
2698
|
+
readdir: async (path) => visible(await fs.readdir(path)),
|
|
2699
|
+
readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR)
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
async settle(pinned, op) {
|
|
2703
|
+
try {
|
|
2704
|
+
await op();
|
|
2705
|
+
} catch (err) {
|
|
2706
|
+
await pinned.rollback();
|
|
2707
|
+
throw err;
|
|
2708
|
+
}
|
|
2709
|
+
pinned.commit();
|
|
2710
|
+
}
|
|
2711
|
+
async pin(target) {
|
|
2712
|
+
const held = /* @__PURE__ */ new Map();
|
|
2713
|
+
for (const holder of this.holders) {
|
|
2714
|
+
if (holder.owns(target)) continue;
|
|
2715
|
+
for (const path of holder.held()) {
|
|
2716
|
+
if (!within2(path, target) || holder.isKept(path)) continue;
|
|
2717
|
+
held.set(path, [...held.get(path) ?? [], holder]);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
const paths = [...held.keys()].sort();
|
|
2721
|
+
const releases = [];
|
|
2722
|
+
for (const path of paths) releases.push(await this.gate.acquire(path));
|
|
2723
|
+
const hidden = /* @__PURE__ */ new Map();
|
|
2724
|
+
for (const path of paths) {
|
|
2725
|
+
const at = await this.hide(path);
|
|
2726
|
+
if (at !== void 0) hidden.set(path, at);
|
|
2727
|
+
}
|
|
2728
|
+
const done4 = () => {
|
|
2729
|
+
for (const release of releases) release();
|
|
2730
|
+
};
|
|
2731
|
+
const files = /* @__PURE__ */ new Map();
|
|
2732
|
+
for (const [path, at] of hidden) {
|
|
2733
|
+
const holders = held.get(path);
|
|
2734
|
+
const file = this.keptFile(at, { refs: holders.length + 1 });
|
|
2735
|
+
files.set(path, file);
|
|
2736
|
+
for (const holder of holders) holder.keep(path, file);
|
|
2737
|
+
}
|
|
2738
|
+
return {
|
|
2739
|
+
moved: new Set(hidden.keys()),
|
|
2740
|
+
commit: () => {
|
|
2741
|
+
for (const file of files.values()) file.release();
|
|
2742
|
+
done4();
|
|
2743
|
+
},
|
|
2744
|
+
rollback: async () => {
|
|
2745
|
+
for (const [path, file] of files) {
|
|
2746
|
+
for (const holder of held.get(path)) holder.unkeep(path, file);
|
|
2747
|
+
await this.serial(async () => {
|
|
2748
|
+
await Promise.allSettled([this.fs.rename(file.hidden, path)]);
|
|
2749
|
+
await this.tidy(parentOf3(file.hidden));
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
done4();
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
keptFile(hidden, entry) {
|
|
2757
|
+
return {
|
|
2758
|
+
hidden,
|
|
2759
|
+
release: () => {
|
|
2760
|
+
if (--entry.refs === 0) void this.serial(() => this.drop(hidden));
|
|
2761
|
+
}
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
hide(path) {
|
|
2765
|
+
return this.serial(async () => {
|
|
2766
|
+
const dir = dirOf(this.rootOf(path));
|
|
2767
|
+
const hidden = `${dir}/${this.instance}.${++this.count}`;
|
|
2768
|
+
try {
|
|
2769
|
+
await this.fs.mkdir(dir, { recursive: true });
|
|
2770
|
+
await this.fs.rename(path, hidden);
|
|
2771
|
+
return hidden;
|
|
2772
|
+
} catch {
|
|
2773
|
+
await this.tidy(dir);
|
|
2774
|
+
return void 0;
|
|
2775
|
+
}
|
|
2776
|
+
});
|
|
2777
|
+
}
|
|
2778
|
+
closed(path) {
|
|
2779
|
+
if (this.waiting.delete(path)) void this.serial(() => this.drop(path));
|
|
2780
|
+
}
|
|
2781
|
+
async drop(hidden) {
|
|
2782
|
+
if (this.busy(hidden)) {
|
|
2783
|
+
this.waiting.add(hidden);
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
await this.fs.rm(hidden).catch(() => void 0);
|
|
2787
|
+
await this.tidy(parentOf3(hidden));
|
|
2788
|
+
}
|
|
2789
|
+
async tidy(dir) {
|
|
2790
|
+
const left = await this.fs.readdir(dir).catch(() => [UNLINKED_DIR]);
|
|
2791
|
+
if (left.length === 0) await this.fs.rm(dir, { recursive: true }).catch(() => void 0);
|
|
2792
|
+
}
|
|
2793
|
+
sweep(root) {
|
|
2794
|
+
const query = this.locks?.query?.bind(this.locks);
|
|
2795
|
+
const owner = this.owner;
|
|
2796
|
+
if (!query && !owner) return Promise.resolve();
|
|
2797
|
+
return this.serial(async () => {
|
|
2798
|
+
const dir = dirOf(root);
|
|
2799
|
+
const names = await this.fs.readdir(dir).catch(() => void 0);
|
|
2800
|
+
if (!names) return;
|
|
2801
|
+
const held = query && new Set(((await query()).held ?? []).map((lock) => lock.name));
|
|
2802
|
+
for (const name2 of names) {
|
|
2803
|
+
const id = name2.slice(0, name2.lastIndexOf("."));
|
|
2804
|
+
const at = id.indexOf("~");
|
|
2805
|
+
const dead = id !== this.instance && (at < 0 ? held !== void 0 && !held.has(lockName(id)) : owner?.alive(id.slice(0, at)) === false);
|
|
2806
|
+
if (dead) await this.fs.rm(`${dir}/${name2}`, { recursive: true }).catch(() => void 0);
|
|
2807
|
+
}
|
|
2808
|
+
await this.tidy(dir);
|
|
2809
|
+
});
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
|
|
2609
2813
|
// src/kernel/net/http1.ts
|
|
2610
2814
|
var HttpError = class extends Error {
|
|
2611
2815
|
status;
|
|
@@ -3674,186 +3878,6 @@ function withCommandDirs(fs, names) {
|
|
|
3674
3878
|
};
|
|
3675
3879
|
}
|
|
3676
3880
|
|
|
3677
|
-
// src/fs/unlinked.ts
|
|
3678
|
-
var UNLINKED_DIR = ".slicc-unlinked";
|
|
3679
|
-
function webLocks() {
|
|
3680
|
-
return globalThis.navigator?.locks;
|
|
3681
|
-
}
|
|
3682
|
-
var within2 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
3683
|
-
var parentOf3 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
3684
|
-
var lockName = (instance) => `slicc-unlinked:${instance}`;
|
|
3685
|
-
var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
|
|
3686
|
-
var PathGate = class {
|
|
3687
|
-
tails = /* @__PURE__ */ new Map();
|
|
3688
|
-
async acquire(path) {
|
|
3689
|
-
const prev = this.tails.get(path) ?? Promise.resolve();
|
|
3690
|
-
const { promise, resolve } = Promise.withResolvers();
|
|
3691
|
-
const tail = prev.then(() => promise);
|
|
3692
|
-
this.tails.set(path, tail);
|
|
3693
|
-
await prev;
|
|
3694
|
-
return () => {
|
|
3695
|
-
resolve();
|
|
3696
|
-
if (this.tails.get(path) === tail) this.tails.delete(path);
|
|
3697
|
-
};
|
|
3698
|
-
}
|
|
3699
|
-
async run(path, op) {
|
|
3700
|
-
const release = await this.acquire(path);
|
|
3701
|
-
try {
|
|
3702
|
-
return await op();
|
|
3703
|
-
} finally {
|
|
3704
|
-
release();
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3707
|
-
};
|
|
3708
|
-
var UnlinkedKeeper = class {
|
|
3709
|
-
fs;
|
|
3710
|
-
holders;
|
|
3711
|
-
rootOf;
|
|
3712
|
-
locks;
|
|
3713
|
-
busy;
|
|
3714
|
-
waiting = /* @__PURE__ */ new Set();
|
|
3715
|
-
instance = crypto.randomUUID();
|
|
3716
|
-
gate = new PathGate();
|
|
3717
|
-
queue = Promise.resolve();
|
|
3718
|
-
count = 0;
|
|
3719
|
-
constructor(fs, holders, rootOf, locks, busy = () => false) {
|
|
3720
|
-
this.fs = fs;
|
|
3721
|
-
this.holders = holders;
|
|
3722
|
-
this.rootOf = rootOf;
|
|
3723
|
-
this.locks = locks;
|
|
3724
|
-
this.busy = busy;
|
|
3725
|
-
void locks?.request(lockName(this.instance), () => new Promise(() => void 0));
|
|
3726
|
-
}
|
|
3727
|
-
serial(op) {
|
|
3728
|
-
const next = this.queue.then(op);
|
|
3729
|
-
this.queue = next.catch(() => void 0);
|
|
3730
|
-
return next;
|
|
3731
|
-
}
|
|
3732
|
-
wrap() {
|
|
3733
|
-
const fs = this.fs;
|
|
3734
|
-
const keeper = this;
|
|
3735
|
-
const visible = (names) => names.filter((name2) => name2 !== UNLINKED_DIR);
|
|
3736
|
-
return {
|
|
3737
|
-
...fs,
|
|
3738
|
-
async rm(path, options) {
|
|
3739
|
-
const target = fs.resolvePath("/", path);
|
|
3740
|
-
const pinned = await keeper.pin(target);
|
|
3741
|
-
if (pinned.moved.has(target)) pinned.commit();
|
|
3742
|
-
else await keeper.settle(pinned, () => fs.rm(path, options));
|
|
3743
|
-
},
|
|
3744
|
-
async rename(from, to) {
|
|
3745
|
-
const pinned = await keeper.pin(fs.resolvePath("/", to));
|
|
3746
|
-
await keeper.settle(pinned, () => fs.rename(from, to));
|
|
3747
|
-
},
|
|
3748
|
-
readdir: async (path) => visible(await fs.readdir(path)),
|
|
3749
|
-
readdirStat: async (path) => (await fs.readdirStat(path)).filter(([name2]) => name2 !== UNLINKED_DIR)
|
|
3750
|
-
};
|
|
3751
|
-
}
|
|
3752
|
-
async settle(pinned, op) {
|
|
3753
|
-
try {
|
|
3754
|
-
await op();
|
|
3755
|
-
} catch (err) {
|
|
3756
|
-
await pinned.rollback();
|
|
3757
|
-
throw err;
|
|
3758
|
-
}
|
|
3759
|
-
pinned.commit();
|
|
3760
|
-
}
|
|
3761
|
-
async pin(target) {
|
|
3762
|
-
const held = /* @__PURE__ */ new Map();
|
|
3763
|
-
for (const holder of this.holders) {
|
|
3764
|
-
if (holder.owns(target)) continue;
|
|
3765
|
-
for (const path of holder.opens.keys()) {
|
|
3766
|
-
if (!within2(path, target) || holder.unlinked.has(path)) continue;
|
|
3767
|
-
held.set(path, [...held.get(path) ?? [], holder]);
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
const paths = [...held.keys()].sort();
|
|
3771
|
-
const releases = [];
|
|
3772
|
-
for (const path of paths) releases.push(await this.gate.acquire(path));
|
|
3773
|
-
const hidden = /* @__PURE__ */ new Map();
|
|
3774
|
-
for (const path of paths) {
|
|
3775
|
-
const at = await this.hide(path);
|
|
3776
|
-
if (at !== void 0) hidden.set(path, at);
|
|
3777
|
-
}
|
|
3778
|
-
const done4 = () => {
|
|
3779
|
-
for (const release of releases) release();
|
|
3780
|
-
};
|
|
3781
|
-
return {
|
|
3782
|
-
moved: new Set(hidden.keys()),
|
|
3783
|
-
commit: () => {
|
|
3784
|
-
for (const [path, at] of hidden) {
|
|
3785
|
-
const holders = held.get(path);
|
|
3786
|
-
const file = this.keptFile(at, { refs: holders.length });
|
|
3787
|
-
for (const holder of holders) holder.unlinked.set(path, file);
|
|
3788
|
-
}
|
|
3789
|
-
done4();
|
|
3790
|
-
},
|
|
3791
|
-
rollback: async () => {
|
|
3792
|
-
for (const [path, at] of hidden) {
|
|
3793
|
-
await this.serial(async () => {
|
|
3794
|
-
await Promise.allSettled([this.fs.rename(at, path)]);
|
|
3795
|
-
await this.tidy(parentOf3(at));
|
|
3796
|
-
});
|
|
3797
|
-
}
|
|
3798
|
-
done4();
|
|
3799
|
-
}
|
|
3800
|
-
};
|
|
3801
|
-
}
|
|
3802
|
-
keptFile(hidden, entry) {
|
|
3803
|
-
return {
|
|
3804
|
-
hidden,
|
|
3805
|
-
release: () => {
|
|
3806
|
-
if (--entry.refs === 0) void this.serial(() => this.drop(hidden));
|
|
3807
|
-
}
|
|
3808
|
-
};
|
|
3809
|
-
}
|
|
3810
|
-
hide(path) {
|
|
3811
|
-
return this.serial(async () => {
|
|
3812
|
-
const dir = dirOf(this.rootOf(path));
|
|
3813
|
-
const hidden = `${dir}/${this.instance}.${++this.count}`;
|
|
3814
|
-
try {
|
|
3815
|
-
await this.fs.mkdir(dir, { recursive: true });
|
|
3816
|
-
await this.fs.rename(path, hidden);
|
|
3817
|
-
return hidden;
|
|
3818
|
-
} catch {
|
|
3819
|
-
await this.tidy(dir);
|
|
3820
|
-
return void 0;
|
|
3821
|
-
}
|
|
3822
|
-
});
|
|
3823
|
-
}
|
|
3824
|
-
closed(path) {
|
|
3825
|
-
if (this.waiting.delete(path)) void this.serial(() => this.drop(path));
|
|
3826
|
-
}
|
|
3827
|
-
async drop(hidden) {
|
|
3828
|
-
if (this.busy(hidden)) {
|
|
3829
|
-
this.waiting.add(hidden);
|
|
3830
|
-
return;
|
|
3831
|
-
}
|
|
3832
|
-
await this.fs.rm(hidden).catch(() => void 0);
|
|
3833
|
-
await this.tidy(parentOf3(hidden));
|
|
3834
|
-
}
|
|
3835
|
-
async tidy(dir) {
|
|
3836
|
-
const left = await this.fs.readdir(dir).catch(() => [UNLINKED_DIR]);
|
|
3837
|
-
if (left.length === 0) await this.fs.rm(dir, { recursive: true }).catch(() => void 0);
|
|
3838
|
-
}
|
|
3839
|
-
sweep(root) {
|
|
3840
|
-
const query = this.locks?.query?.bind(this.locks);
|
|
3841
|
-
if (!query) return Promise.resolve();
|
|
3842
|
-
return this.serial(async () => {
|
|
3843
|
-
const dir = dirOf(root);
|
|
3844
|
-
const names = await this.fs.readdir(dir).catch(() => void 0);
|
|
3845
|
-
if (!names) return;
|
|
3846
|
-
const held = new Set(((await query()).held ?? []).map((lock) => lock.name));
|
|
3847
|
-
for (const name2 of names) {
|
|
3848
|
-
const owner = name2.slice(0, name2.lastIndexOf("."));
|
|
3849
|
-
if (owner === this.instance || held.has(lockName(owner))) continue;
|
|
3850
|
-
await this.fs.rm(`${dir}/${name2}`, { recursive: true }).catch(() => void 0);
|
|
3851
|
-
}
|
|
3852
|
-
await this.tidy(dir);
|
|
3853
|
-
});
|
|
3854
|
-
}
|
|
3855
|
-
};
|
|
3856
|
-
|
|
3857
3881
|
// src/fs/watch.ts
|
|
3858
3882
|
var WATCH_BATCH_LIMIT = 1e3;
|
|
3859
3883
|
var under2 = (path, dir) => dir === "/" || path.startsWith(`${dir}/`);
|
|
@@ -4281,6 +4305,18 @@ var HeldPaths = class extends Map {
|
|
|
4281
4305
|
holding(path) {
|
|
4282
4306
|
return this.opens.has(this.keyOf(path));
|
|
4283
4307
|
}
|
|
4308
|
+
held() {
|
|
4309
|
+
return this.opens.keys();
|
|
4310
|
+
}
|
|
4311
|
+
isKept(path) {
|
|
4312
|
+
return this.unlinked.has(path);
|
|
4313
|
+
}
|
|
4314
|
+
keep(path, file) {
|
|
4315
|
+
this.unlinked.set(path, file);
|
|
4316
|
+
}
|
|
4317
|
+
unkeep(path) {
|
|
4318
|
+
this.unlinked.delete(path);
|
|
4319
|
+
}
|
|
4284
4320
|
hold(path, on, open = false, real) {
|
|
4285
4321
|
if (open) {
|
|
4286
4322
|
const key = real ?? this.keyOf(path);
|
|
@@ -5148,6 +5184,9 @@ async function run(entry, path, req) {
|
|
|
5148
5184
|
case "symlink":
|
|
5149
5185
|
await fs.symlink(req.arg2 ?? "", path);
|
|
5150
5186
|
return done;
|
|
5187
|
+
case "create":
|
|
5188
|
+
await createExclusive(fs, path);
|
|
5189
|
+
return done;
|
|
5151
5190
|
case "readlink":
|
|
5152
5191
|
return json2(await fs.readlink(path));
|
|
5153
5192
|
case "chmod":
|
|
@@ -5167,6 +5206,15 @@ async function run(entry, path, req) {
|
|
|
5167
5206
|
return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
|
|
5168
5207
|
}
|
|
5169
5208
|
}
|
|
5209
|
+
async function createExclusive(fs, path) {
|
|
5210
|
+
if (fs.createExclusive) return fs.createExclusive(path);
|
|
5211
|
+
if (await fs.lstat(path).then(
|
|
5212
|
+
() => true,
|
|
5213
|
+
() => false
|
|
5214
|
+
))
|
|
5215
|
+
throw syncError("EEXIST", path);
|
|
5216
|
+
await fs.writeFile(path, new Uint8Array(0));
|
|
5217
|
+
}
|
|
5170
5218
|
async function ranged(fs, path, req) {
|
|
5171
5219
|
const ops = rangedOps(fs);
|
|
5172
5220
|
if (!ops) throw syncError("ENOSYS", path);
|
|
@@ -8126,6 +8174,8 @@ var VfsNode = class {
|
|
|
8126
8174
|
};
|
|
8127
8175
|
var VfsNodes = class {
|
|
8128
8176
|
byPath = /* @__PURE__ */ new Map();
|
|
8177
|
+
kept = /* @__PURE__ */ new Map();
|
|
8178
|
+
keepsOnDisk = false;
|
|
8129
8179
|
fs;
|
|
8130
8180
|
entries = /* @__PURE__ */ new Map();
|
|
8131
8181
|
onClosed;
|
|
@@ -8208,15 +8258,47 @@ var VfsNodes = class {
|
|
|
8208
8258
|
return;
|
|
8209
8259
|
}
|
|
8210
8260
|
if (this.byPath.get(node.path) === node) this.byPath.delete(node.path);
|
|
8261
|
+
this.kept.get(node)?.release();
|
|
8262
|
+
this.kept.delete(node);
|
|
8211
8263
|
this.onClosed?.(node.path);
|
|
8212
8264
|
}
|
|
8265
|
+
held() {
|
|
8266
|
+
return this.byPath.keys();
|
|
8267
|
+
}
|
|
8268
|
+
owns() {
|
|
8269
|
+
return false;
|
|
8270
|
+
}
|
|
8271
|
+
isKept() {
|
|
8272
|
+
return false;
|
|
8273
|
+
}
|
|
8274
|
+
keep(path, file) {
|
|
8275
|
+
const node = this.byPath.get(path);
|
|
8276
|
+
if (!node) {
|
|
8277
|
+
file.release();
|
|
8278
|
+
return;
|
|
8279
|
+
}
|
|
8280
|
+
this.byPath.delete(path);
|
|
8281
|
+
node.renamedTo(file.hidden);
|
|
8282
|
+
this.byPath.set(file.hidden, node);
|
|
8283
|
+
this.kept.set(node, file);
|
|
8284
|
+
}
|
|
8285
|
+
unkeep(path, file) {
|
|
8286
|
+
const node = this.byPath.get(file.hidden);
|
|
8287
|
+
if (!node) return;
|
|
8288
|
+
this.byPath.delete(file.hidden);
|
|
8289
|
+
node.renamedTo(path);
|
|
8290
|
+
this.byPath.set(path, node);
|
|
8291
|
+
this.kept.delete(node);
|
|
8292
|
+
}
|
|
8213
8293
|
async flush(path) {
|
|
8214
8294
|
for (const [p, node] of this.byPath) if (within5(p, path)) await node.serial(() => node.flush());
|
|
8215
8295
|
}
|
|
8216
8296
|
async unlinking(path) {
|
|
8217
8297
|
for (const [held, node] of [...this.byPath]) {
|
|
8218
8298
|
if (!within5(held, path)) continue;
|
|
8219
|
-
await node.serial(async () =>
|
|
8299
|
+
await node.serial(async () => {
|
|
8300
|
+
await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
|
|
8301
|
+
});
|
|
8220
8302
|
}
|
|
8221
8303
|
}
|
|
8222
8304
|
revoke(prefix) {
|
|
@@ -8346,6 +8428,7 @@ function keepingOpen(fs, nodes) {
|
|
|
8346
8428
|
});
|
|
8347
8429
|
},
|
|
8348
8430
|
writeFile: (path, content) => nodes.onEntry(fs.resolvePath("/", path), () => fs.writeFile(path, content)),
|
|
8431
|
+
createExclusive: async (path) => nodes.createExclusive(await nodes.entryKey(fs.resolvePath("/", path))),
|
|
8349
8432
|
symlink: (target, path) => nodes.onEntry(fs.resolvePath("/", path), () => fs.symlink(target, path)),
|
|
8350
8433
|
mkdir: (path, options) => nodes.onEntry(fs.resolvePath("/", path), () => fs.mkdir(path, options))
|
|
8351
8434
|
};
|
|
@@ -9171,13 +9254,13 @@ var Dying = class {
|
|
|
9171
9254
|
timer;
|
|
9172
9255
|
busy = 0;
|
|
9173
9256
|
finish;
|
|
9174
|
-
start(code, sig, header3,
|
|
9257
|
+
start(code, sig, header3, process2, finish) {
|
|
9175
9258
|
if (this.ending) return;
|
|
9176
9259
|
this.ending = { code, sig };
|
|
9177
9260
|
this.finish = finish;
|
|
9178
9261
|
this.arm();
|
|
9179
9262
|
Atomics.store(header3, SAB_I_KILLED, code);
|
|
9180
|
-
|
|
9263
|
+
process2.die();
|
|
9181
9264
|
}
|
|
9182
9265
|
async serving(work) {
|
|
9183
9266
|
this.busy++;
|
|
@@ -9213,8 +9296,8 @@ function notifiers(header3) {
|
|
|
9213
9296
|
}
|
|
9214
9297
|
};
|
|
9215
9298
|
}
|
|
9216
|
-
function publishStops(
|
|
9217
|
-
|
|
9299
|
+
function publishStops(process2, header3) {
|
|
9300
|
+
process2.onState((state) => {
|
|
9218
9301
|
Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
|
|
9219
9302
|
Atomics.notify(header3, SAB_I_STOP);
|
|
9220
9303
|
});
|
|
@@ -9284,7 +9367,7 @@ function holdingToken(opts, holds) {
|
|
|
9284
9367
|
function spawnWasmProcess(opts) {
|
|
9285
9368
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
9286
9369
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
9287
|
-
const
|
|
9370
|
+
const process2 = new WasmProcess(opts.pid, opts.fds, {
|
|
9288
9371
|
...inherited(opts),
|
|
9289
9372
|
...opts.identity ? { identity: opts.identity } : {},
|
|
9290
9373
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
@@ -9312,14 +9395,14 @@ function spawnWasmProcess(opts) {
|
|
|
9312
9395
|
raise: (sig) => signal(sig),
|
|
9313
9396
|
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
|
|
9314
9397
|
});
|
|
9315
|
-
publishStops(
|
|
9398
|
+
publishStops(process2, header3);
|
|
9316
9399
|
const holds = new HeldPaths();
|
|
9317
9400
|
opts.held?.add(holds);
|
|
9318
9401
|
const token = holdingToken(opts, holds);
|
|
9319
|
-
|
|
9402
|
+
process2.keptPath = (path) => holds.keptAt(path)?.hidden;
|
|
9320
9403
|
const worker = opts.createWorker();
|
|
9321
9404
|
const dying = new Dying();
|
|
9322
|
-
const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ?
|
|
9405
|
+
const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process2.syscall(req) : dispatchSyncFs(req));
|
|
9323
9406
|
const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
|
|
9324
9407
|
const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
|
|
9325
9408
|
const { promise: exited, resolve: settle } = Promise.withResolvers();
|
|
@@ -9329,7 +9412,7 @@ function spawnWasmProcess(opts) {
|
|
|
9329
9412
|
if (done4) return;
|
|
9330
9413
|
done4 = true;
|
|
9331
9414
|
dying.clear();
|
|
9332
|
-
endedBy = sig ??
|
|
9415
|
+
endedBy = sig ?? process2.execTermsig;
|
|
9333
9416
|
worker.removeEventListener("message", onMessage);
|
|
9334
9417
|
worker.removeEventListener("error", onError);
|
|
9335
9418
|
for (const tid of [...threads.keys()]) endThread(tid);
|
|
@@ -9338,7 +9421,7 @@ function spawnWasmProcess(opts) {
|
|
|
9338
9421
|
revokeSyncFsToken(token);
|
|
9339
9422
|
opts.held?.delete(holds);
|
|
9340
9423
|
worker.terminate();
|
|
9341
|
-
void
|
|
9424
|
+
void process2.exit().then(
|
|
9342
9425
|
() => settle(code),
|
|
9343
9426
|
() => settle(code)
|
|
9344
9427
|
);
|
|
@@ -9406,14 +9489,14 @@ function spawnWasmProcess(opts) {
|
|
|
9406
9489
|
tw.postMessage(tinit);
|
|
9407
9490
|
};
|
|
9408
9491
|
worker.postMessage(
|
|
9409
|
-
processInit(opts, sab,
|
|
9492
|
+
processInit(opts, sab, process2.umask, lane?.lane),
|
|
9410
9493
|
transferOf(opts, lane?.lane)
|
|
9411
9494
|
);
|
|
9412
9495
|
const signal = (sig) => {
|
|
9413
|
-
if (
|
|
9496
|
+
if (process2.signal(sig) !== "terminate") return;
|
|
9414
9497
|
const code = sig === SIG.KILL ? 137 : 128 + sig;
|
|
9415
9498
|
if (opts.program.abi !== "wasi" || done4) finish(code, sig);
|
|
9416
|
-
else dying.start(code, sig, header3,
|
|
9499
|
+
else dying.start(code, sig, header3, process2, () => finish(code, sig));
|
|
9417
9500
|
};
|
|
9418
9501
|
const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
|
|
9419
9502
|
return {
|
|
@@ -9422,10 +9505,10 @@ function spawnWasmProcess(opts) {
|
|
|
9422
9505
|
kill,
|
|
9423
9506
|
signal,
|
|
9424
9507
|
termsig: () => endedBy,
|
|
9425
|
-
onState: (listener) =>
|
|
9508
|
+
onState: (listener) => process2.onState(listener),
|
|
9426
9509
|
memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
|
|
9427
|
-
ignoredSignals: (fork) =>
|
|
9428
|
-
umask: () =>
|
|
9510
|
+
ignoredSignals: (fork) => process2.inheritable(fork),
|
|
9511
|
+
umask: () => process2.umask,
|
|
9429
9512
|
writesBack: () => opts.program.abi === "wasi" && !done4
|
|
9430
9513
|
};
|
|
9431
9514
|
}
|
|
@@ -11013,15 +11096,20 @@ var Launcher = class {
|
|
|
11013
11096
|
enableCdp(this.net, this.cdp);
|
|
11014
11097
|
const fs = withCommandDirs(this.base, async () => new Set((await this.commands()).keys()));
|
|
11015
11098
|
this.nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
11099
|
+
this.nodes.keepsOnDisk = true;
|
|
11016
11100
|
this.openFiles.add(this.nodes);
|
|
11101
|
+
const holders = [this.held, [this.nodes]];
|
|
11017
11102
|
this.unlinked = new UnlinkedKeeper(
|
|
11018
11103
|
fs,
|
|
11019
|
-
|
|
11104
|
+
{ [Symbol.iterator]: () => holders.flatMap((set2) => [...set2]).values() },
|
|
11020
11105
|
(path) => this.mountRoot(path),
|
|
11021
|
-
|
|
11022
|
-
|
|
11106
|
+
{
|
|
11107
|
+
locks: webLocks(),
|
|
11108
|
+
busy: (path) => [...this.openFiles].some((nodes) => nodes.holds(path)),
|
|
11109
|
+
owner: options.unlinkOwner
|
|
11110
|
+
}
|
|
11023
11111
|
);
|
|
11024
|
-
this.fs =
|
|
11112
|
+
this.fs = this.unlinked.wrap(keepingOpen(fs, this.nodes));
|
|
11025
11113
|
void this.unlinked.sweep("/");
|
|
11026
11114
|
this.watchers.watch([this.modulesDir, this.pnpmHome], { recursive: true }, () => {
|
|
11027
11115
|
this.catalog = void 0;
|
|
@@ -12718,6 +12806,7 @@ async function createNodeKernel(options = {}) {
|
|
|
12718
12806
|
const transport = options.network?.transport;
|
|
12719
12807
|
const launcher = new Launcher({
|
|
12720
12808
|
fs,
|
|
12809
|
+
unlinkOwner: pidOwner(process),
|
|
12721
12810
|
createWorker: () => nodeWorker(file, live, terminated),
|
|
12722
12811
|
createDriverWorker: () => nodeWorker(
|
|
12723
12812
|
options.driverWorker ?? new URL("./node-driver-worker.js", import.meta.url),
|