@ai-ecoverse/slicc-kernel 1.172.1 → 1.173.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/README.md +12 -5
- package/dist/index.js +37 -5
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +443 -190
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +204 -27
- package/dist/meta.js.map +4 -4
- package/dist/node-process-worker.cjs +3 -1
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +3 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +18 -3
- package/dist/node.js.map +2 -2
- package/dist/process-worker.js +3 -1
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/meta-reads.d.ts +41 -0
- package/dist/types/fs/meta.d.ts +12 -1
- package/dist/types/fs/opfs.d.ts +2 -1
- package/dist/types/fs/portable.d.ts +11 -0
- package/dist/types/fs/roots.d.ts +1 -1
- package/dist/types/fs/types.d.ts +4 -0
- package/dist/types/fs/watch.d.ts +3 -0
- package/dist/types/kernel/proc-info.d.ts +4 -0
- package/dist/types/mount/media.d.ts +3 -1
- package/dist/types/serve.d.ts +6 -4
- package/package.json +4 -4
package/dist/meta.js
CHANGED
|
@@ -1,5 +1,149 @@
|
|
|
1
|
+
// src/fs/meta-reads.ts
|
|
2
|
+
var parentOf = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
3
|
+
var within = (path, root) => root === "/" || path === root || path.startsWith(`${root}/`);
|
|
4
|
+
var Invalidations = class {
|
|
5
|
+
seq = 0;
|
|
6
|
+
log = [];
|
|
7
|
+
open = /* @__PURE__ */ new Map();
|
|
8
|
+
start() {
|
|
9
|
+
const at = this.seq;
|
|
10
|
+
this.open.set(at, (this.open.get(at) ?? 0) + 1);
|
|
11
|
+
return at;
|
|
12
|
+
}
|
|
13
|
+
end(at) {
|
|
14
|
+
const left = (this.open.get(at) ?? 1) - 1;
|
|
15
|
+
if (left > 0) this.open.set(at, left);
|
|
16
|
+
else this.open.delete(at);
|
|
17
|
+
const oldest = this.open.keys().next();
|
|
18
|
+
if (oldest.done) this.log.length = 0;
|
|
19
|
+
else while (this.log.length > 0 && this.log[0].at <= oldest.value) this.log.shift();
|
|
20
|
+
}
|
|
21
|
+
note({ paths = [], trees = [] }) {
|
|
22
|
+
this.seq++;
|
|
23
|
+
if (this.open.size > 0) this.log.push({ at: this.seq, paths, trees });
|
|
24
|
+
}
|
|
25
|
+
since(at, hit) {
|
|
26
|
+
for (let i = this.log.length - 1; i >= 0; i--) {
|
|
27
|
+
const noted = this.log[i];
|
|
28
|
+
if (noted.at <= at) return false;
|
|
29
|
+
if (hit(noted)) return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
entryStale(at, path) {
|
|
34
|
+
return this.since(
|
|
35
|
+
at,
|
|
36
|
+
({ paths, trees }) => paths.includes(path) || trees.some((tree) => within(path, tree))
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
listingStale(at, dir) {
|
|
40
|
+
return this.since(
|
|
41
|
+
at,
|
|
42
|
+
({ paths, trees }) => paths.some((path) => path !== "/" && parentOf(path) === dir) || trees.some((tree) => within(dir, tree) || tree !== "/" && parentOf(tree) === dir)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var META_READS_IN_FLIGHT = 4;
|
|
47
|
+
var BatchedReads = class {
|
|
48
|
+
run;
|
|
49
|
+
invalidations;
|
|
50
|
+
keep;
|
|
51
|
+
queued = {
|
|
52
|
+
entry: /* @__PURE__ */ new Map(),
|
|
53
|
+
links: /* @__PURE__ */ new Map()
|
|
54
|
+
};
|
|
55
|
+
reading = {
|
|
56
|
+
entry: /* @__PURE__ */ new Map(),
|
|
57
|
+
links: /* @__PURE__ */ new Map()
|
|
58
|
+
};
|
|
59
|
+
inFlight = 0;
|
|
60
|
+
constructor(invalidations, run, keep) {
|
|
61
|
+
this.invalidations = invalidations;
|
|
62
|
+
this.run = run;
|
|
63
|
+
this.keep = keep;
|
|
64
|
+
}
|
|
65
|
+
entries(paths) {
|
|
66
|
+
const wanted = paths.map((path) => [path, this.want("entry", path)]);
|
|
67
|
+
this.pump();
|
|
68
|
+
return Promise.all(wanted.map(([, w]) => w.promise)).then(
|
|
69
|
+
(found) => new Map(wanted.map(([path], i) => [path, found[i]]))
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
links(dir) {
|
|
73
|
+
const wanted = this.want("links", dir);
|
|
74
|
+
this.pump();
|
|
75
|
+
return wanted.promise;
|
|
76
|
+
}
|
|
77
|
+
stale(kind, key, at) {
|
|
78
|
+
return kind === "entry" ? this.invalidations.entryStale(at, key) : this.invalidations.listingStale(at, key);
|
|
79
|
+
}
|
|
80
|
+
want(kind, key) {
|
|
81
|
+
const reading = this.reading[kind].get(key);
|
|
82
|
+
if (reading && !this.stale(kind, key, reading.at)) return reading;
|
|
83
|
+
const queued = this.queued[kind].get(key);
|
|
84
|
+
if (queued) return queued;
|
|
85
|
+
const made = Promise.withResolvers();
|
|
86
|
+
made.promise.catch(() => void 0);
|
|
87
|
+
this.queued[kind].set(key, made);
|
|
88
|
+
return made;
|
|
89
|
+
}
|
|
90
|
+
pump() {
|
|
91
|
+
while (this.inFlight < META_READS_IN_FLIGHT && (this.queued.entry.size > 0 || this.queued.links.size > 0)) {
|
|
92
|
+
this.flush();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
flush() {
|
|
96
|
+
const entries = this.queued.entry;
|
|
97
|
+
const links = this.queued.links;
|
|
98
|
+
this.queued.entry = /* @__PURE__ */ new Map();
|
|
99
|
+
this.queued.links = /* @__PURE__ */ new Map();
|
|
100
|
+
const at = this.invalidations.start();
|
|
101
|
+
for (const [kind, taken] of [
|
|
102
|
+
["entry", entries],
|
|
103
|
+
["links", links]
|
|
104
|
+
]) {
|
|
105
|
+
for (const [key, wanted] of taken) {
|
|
106
|
+
wanted.at = at;
|
|
107
|
+
this.reading[kind].set(key, wanted);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.inFlight++;
|
|
111
|
+
const settled = (result, error) => {
|
|
112
|
+
this.inFlight--;
|
|
113
|
+
for (const [kind, taken, found] of [
|
|
114
|
+
["entry", entries, result?.entries],
|
|
115
|
+
["links", links, result?.links]
|
|
116
|
+
]) {
|
|
117
|
+
for (const [key, wanted] of taken) {
|
|
118
|
+
if (this.reading[kind].get(key) === wanted) this.reading[kind].delete(key);
|
|
119
|
+
if (!found) {
|
|
120
|
+
wanted.reject(error);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const value = found.get(key) ?? (kind === "entry" ? null : []);
|
|
124
|
+
if (!this.stale(kind, key, at)) this.keep(kind, key, value);
|
|
125
|
+
wanted.resolve(value);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
this.invalidations.end(at);
|
|
129
|
+
this.pump();
|
|
130
|
+
};
|
|
131
|
+
let reading;
|
|
132
|
+
try {
|
|
133
|
+
reading = this.run({ entries: [...entries.keys()], links: [...links.keys()] });
|
|
134
|
+
} catch (error) {
|
|
135
|
+
settled(void 0, error);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
reading.then(
|
|
139
|
+
(result) => settled(result),
|
|
140
|
+
(error) => settled(void 0, error)
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
1
145
|
// src/fs/path-map.ts
|
|
2
|
-
function
|
|
146
|
+
function parentOf2(path) {
|
|
3
147
|
if (path === "/" || path === "") return void 0;
|
|
4
148
|
const at = path.lastIndexOf("/");
|
|
5
149
|
return at <= 0 ? "/" : path.slice(0, at);
|
|
@@ -57,24 +201,24 @@ var PathMap = class {
|
|
|
57
201
|
this.children.clear();
|
|
58
202
|
}
|
|
59
203
|
link(path) {
|
|
60
|
-
for (let child = path, parent =
|
|
204
|
+
for (let child = path, parent = parentOf2(path); parent !== void 0; ) {
|
|
61
205
|
const set = this.children.get(parent);
|
|
62
206
|
if (set?.has(child)) return;
|
|
63
207
|
if (set) set.add(child);
|
|
64
208
|
else this.children.set(parent, /* @__PURE__ */ new Set([child]));
|
|
65
209
|
child = parent;
|
|
66
|
-
parent =
|
|
210
|
+
parent = parentOf2(parent);
|
|
67
211
|
}
|
|
68
212
|
}
|
|
69
213
|
prune(path) {
|
|
70
|
-
for (let child = path, parent =
|
|
214
|
+
for (let child = path, parent = parentOf2(path); parent !== void 0; ) {
|
|
71
215
|
if (this.values.has(child) || this.children.has(child)) return;
|
|
72
216
|
const set = this.children.get(parent);
|
|
73
217
|
set?.delete(child);
|
|
74
218
|
if (set && set.size > 0) return;
|
|
75
219
|
this.children.delete(parent);
|
|
76
220
|
child = parent;
|
|
77
|
-
parent =
|
|
221
|
+
parent = parentOf2(parent);
|
|
78
222
|
}
|
|
79
223
|
}
|
|
80
224
|
};
|
|
@@ -83,11 +227,11 @@ var PathMap = class {
|
|
|
83
227
|
var META_DB = "slicc-kernel";
|
|
84
228
|
var META_VERSION = 1;
|
|
85
229
|
var META_STORE = "entries";
|
|
86
|
-
function
|
|
230
|
+
function parentOf3(path) {
|
|
87
231
|
return path.slice(0, path.lastIndexOf("/")) || "/";
|
|
88
232
|
}
|
|
89
233
|
function moved(entry, path) {
|
|
90
|
-
return entry.link === void 0 ? { ...entry, path } : { ...entry, path, dir:
|
|
234
|
+
return entry.link === void 0 ? { ...entry, path } : { ...entry, path, dir: parentOf3(path) };
|
|
91
235
|
}
|
|
92
236
|
function descendants(path) {
|
|
93
237
|
return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);
|
|
@@ -100,11 +244,21 @@ function settle(transaction, value) {
|
|
|
100
244
|
}
|
|
101
245
|
var REMOVE_BATCH = 256;
|
|
102
246
|
var REMOVE_WAIT_MS = 5;
|
|
247
|
+
var LISTINGS_KEPT = 4096;
|
|
103
248
|
var IndexedDbMeta = class {
|
|
104
249
|
db;
|
|
105
250
|
cache = new PathMap();
|
|
251
|
+
listings = new PathMap();
|
|
106
252
|
channel;
|
|
107
|
-
|
|
253
|
+
invalidations = new Invalidations();
|
|
254
|
+
reads = new BatchedReads(
|
|
255
|
+
this.invalidations,
|
|
256
|
+
(batch) => this.read(batch),
|
|
257
|
+
(kind, key, value) => {
|
|
258
|
+
if (kind === "entry") this.cache.set(key, value);
|
|
259
|
+
else this.keepListing(key, value);
|
|
260
|
+
}
|
|
261
|
+
);
|
|
108
262
|
listeners = /* @__PURE__ */ new Set();
|
|
109
263
|
listen(listener) {
|
|
110
264
|
this.listeners.add(listener);
|
|
@@ -123,32 +277,56 @@ var IndexedDbMeta = class {
|
|
|
123
277
|
this.drop({ trees: [...trees] });
|
|
124
278
|
}
|
|
125
279
|
drop({ paths = [], trees = [] }) {
|
|
126
|
-
this.
|
|
127
|
-
for (const path of paths)
|
|
128
|
-
|
|
280
|
+
this.invalidations.note({ paths, trees });
|
|
281
|
+
for (const path of paths) {
|
|
282
|
+
this.cache.delete(path);
|
|
283
|
+
if (path !== "/") this.listings.delete(parentOf3(path));
|
|
284
|
+
}
|
|
285
|
+
for (const tree of trees) {
|
|
286
|
+
this.cache.deleteTree(tree);
|
|
287
|
+
this.listings.deleteTree(tree);
|
|
288
|
+
if (tree !== "/") this.listings.delete(parentOf3(tree));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
keepListing(dir, links) {
|
|
292
|
+
if (this.listings.size >= LISTINGS_KEPT) this.listings.clear();
|
|
293
|
+
this.listings.set(dir, links);
|
|
294
|
+
}
|
|
295
|
+
async read({ entries, links }) {
|
|
296
|
+
this.settleRemoves();
|
|
297
|
+
const [transaction, store] = this.transaction("readonly");
|
|
298
|
+
const result = { entries: /* @__PURE__ */ new Map(), links: /* @__PURE__ */ new Map() };
|
|
299
|
+
for (const path of entries) {
|
|
300
|
+
const request = store.get(path);
|
|
301
|
+
request.onsuccess = () => void result.entries.set(path, request.result ?? null);
|
|
302
|
+
}
|
|
303
|
+
if (links.length > 0) {
|
|
304
|
+
const index = store.index("dir");
|
|
305
|
+
for (const dir of links) {
|
|
306
|
+
const request = index.getAll(dir);
|
|
307
|
+
request.onsuccess = () => void result.links.set(dir, request.result);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return settle(transaction, () => result);
|
|
129
311
|
}
|
|
130
312
|
changed(invalidation) {
|
|
131
313
|
this.drop(invalidation);
|
|
132
314
|
this.channel.postMessage(invalidation);
|
|
133
315
|
}
|
|
316
|
+
counted = { reads: 0, writes: 0 };
|
|
317
|
+
transactions() {
|
|
318
|
+
return { ...this.counted };
|
|
319
|
+
}
|
|
134
320
|
transaction(mode) {
|
|
321
|
+
if (mode === "readonly") this.counted.reads++;
|
|
322
|
+
else this.counted.writes++;
|
|
135
323
|
const transaction = this.db.transaction(META_STORE, mode);
|
|
136
324
|
return [transaction, transaction.objectStore(META_STORE)];
|
|
137
325
|
}
|
|
138
326
|
async get(paths) {
|
|
139
327
|
const missing = paths.filter((path) => !this.cache.has(path));
|
|
140
328
|
if (missing.length > 0) {
|
|
141
|
-
this.
|
|
142
|
-
const generation = this.generation;
|
|
143
|
-
const [transaction, store] = this.transaction("readonly");
|
|
144
|
-
const found = /* @__PURE__ */ new Map();
|
|
145
|
-
for (const path of missing) {
|
|
146
|
-
const request = store.get(path);
|
|
147
|
-
request.onsuccess = () => void found.set(path, request.result ?? null);
|
|
148
|
-
}
|
|
149
|
-
await settle(transaction, () => void 0);
|
|
150
|
-
if (generation === this.generation)
|
|
151
|
-
for (const [path, entry] of found) this.cache.set(path, entry);
|
|
329
|
+
const found = await this.reads.entries(missing);
|
|
152
330
|
return paths.map(
|
|
153
331
|
(path) => (found.has(path) ? found.get(path) : this.cache.get(path)) ?? void 0
|
|
154
332
|
);
|
|
@@ -230,7 +408,8 @@ var IndexedDbMeta = class {
|
|
|
230
408
|
async removeFile(path) {
|
|
231
409
|
const known = this.cache.get(path);
|
|
232
410
|
if (!known) return this.remove([path]);
|
|
233
|
-
this.
|
|
411
|
+
this.invalidations.note({ paths: [path] });
|
|
412
|
+
if (path !== "/") this.listings.delete(parentOf3(path));
|
|
234
413
|
this.cache.set(path, null);
|
|
235
414
|
this.removing.set(path, JSON.stringify(known));
|
|
236
415
|
if (this.removing.size >= REMOVE_BATCH) return this.flushRemoves();
|
|
@@ -270,10 +449,8 @@ var IndexedDbMeta = class {
|
|
|
270
449
|
return settle(transaction, () => void this.channel.postMessage({ paths }));
|
|
271
450
|
}
|
|
272
451
|
async links(dir) {
|
|
273
|
-
this.
|
|
274
|
-
|
|
275
|
-
const request = store.index("dir").getAll(dir);
|
|
276
|
-
return settle(transaction, () => request.result);
|
|
452
|
+
const known = this.listings.get(dir);
|
|
453
|
+
return [...known ?? await this.reads.links(dir)];
|
|
277
454
|
}
|
|
278
455
|
async under(path) {
|
|
279
456
|
this.settleRemoves();
|
package/dist/meta.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/fs/path-map.ts", "../src/fs/meta.ts", "../src/fs/notice.ts", "../src/fs/types.ts", "../src/kernel/replacing.ts", "../src/meta.ts"],
|
|
4
|
-
"sourcesContent": ["function parentOf(path: string): string | undefined {\n if (path === '/' || path === '') return undefined;\n const at = path.lastIndexOf('/');\n return at <= 0 ? '/' : path.slice(0, at);\n}\n\nexport class PathMap<V> {\n private readonly values = new Map<string, V>();\n private readonly children = new Map<string, Set<string>>();\n\n get size(): number {\n return this.values.size;\n }\n\n has(path: string): boolean {\n return this.values.has(path);\n }\n\n get(path: string): V | undefined {\n return this.values.get(path);\n }\n\n keys(): IterableIterator<string> {\n return this.values.keys();\n }\n\n set(path: string, value: V): this {\n if (!this.values.has(path)) this.link(path);\n this.values.set(path, value);\n return this;\n }\n\n delete(path: string): boolean {\n if (!this.values.delete(path)) return false;\n this.prune(path);\n return true;\n }\n\n subtree(root: string): string[] {\n const out: string[] = [];\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n if (this.values.has(path)) out.push(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n }\n return out;\n }\n\n entries(): IterableIterator<[string, V]> {\n return this.values.entries();\n }\n\n deleteTree(root: string): void {\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n this.values.delete(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n this.children.delete(path);\n }\n this.prune(root);\n }\n\n clear(): void {\n this.values.clear();\n this.children.clear();\n }\n\n private link(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n const set = this.children.get(parent);\n if (set?.has(child)) return;\n if (set) set.add(child);\n else this.children.set(parent, new Set([child]));\n child = parent;\n parent = parentOf(parent);\n }\n }\n\n private prune(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n if (this.values.has(child) || this.children.has(child)) return;\n const set = this.children.get(parent);\n set?.delete(child);\n if (set && set.size > 0) return;\n this.children.delete(parent);\n child = parent;\n parent = parentOf(parent);\n }\n }\n}\n", "import { PathMap } from './path-map.ts';\nexport interface MetaEntry {\n path: string;\n mode?: number;\n atimeMs?: number;\n mtimeMs?: number;\n mtimeFor?: number;\n timesAt?: number;\n timesBy?: string;\n ctimeMs?: number;\n ino?: number;\n fid?: string;\n link?: string;\n socket?: true;\n fifo?: true;\n dir?: string;\n uid?: number;\n gid?: number;\n heir?: [number, number];\n writes?: number;\n epoch?: number;\n vacated?: true;\n rename?: {\n from: string;\n to: string;\n at: number;\n replace?: true;\n lock?: string;\n root?: { ino: number; uid?: number; gid?: number; mode?: number };\n };\n}\n\nexport type MetaChange = (entry: MetaEntry | undefined) => MetaEntry | undefined;\n\nexport interface MetaUpdate {\n path: string;\n change: MetaChange;\n}\n\nexport interface MetaStore {\n get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n fresh?(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n update(path: string, change: MetaChange): Promise<void>;\n updateMany?(changes: ReadonlyArray<MetaUpdate>): Promise<void>;\n move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ): Promise<void>;\n remove(paths: readonly string[], left?: MetaEntry): Promise<void>;\n links(dir: string): Promise<MetaEntry[]>;\n under(path: string): Promise<MetaEntry[]>;\n all(): Promise<MetaEntry[]>;\n absent?(path: string): boolean;\n removeFile?(path: string): Promise<void>;\n forgetTrees?(trees: readonly string[]): void;\n}\n\nexport const META_DB = 'slicc-kernel';\nexport const META_VERSION = 1;\nexport const META_STORE = 'entries';\n\nfunction parentOf(path: string): string {\n return path.slice(0, path.lastIndexOf('/')) || '/';\n}\n\nfunction moved(entry: MetaEntry, path: string): MetaEntry {\n return entry.link === undefined ? { ...entry, path } : { ...entry, path, dir: parentOf(path) };\n}\n\nfunction under(path: string, root: string): boolean {\n return path === root || path.startsWith(`${root}/`);\n}\n\nexport class MemoryMeta implements MetaStore {\n private readonly entries = new PathMap<MetaEntry>();\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return paths.map((path) => this.entries.get(path));\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return this.get(paths);\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.set(path, change(this.entries.get(path)));\n }\n\n private set(path: string, entry: MetaEntry | undefined): void {\n if (entry) this.entries.set(path, entry);\n else this.entries.delete(path);\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n await this.remove([to]);\n const carried = this.entries.subtree(from).map((path) => this.entries.get(path) as MetaEntry);\n for (const entry of carried) this.entries.delete(entry.path);\n for (const entry of carried) {\n const path = to + entry.path.slice(from.length);\n if (path !== to) this.entries.set(path, moved(entry, path));\n }\n this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));\n if (left) this.entries.set(from, left);\n }\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n for (const path of paths) this.entries.deleteTree(path);\n if (left) this.entries.set(left.path, left);\n }\n\n absent(path: string): boolean {\n return !this.entries.has(path);\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => under(entry.path, path));\n }\n\n async all(): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e);\n }\n}\n\nfunction descendants(path: string): IDBKeyRange {\n return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);\n}\n\nfunction settle<T>(transaction: IDBTransaction, value: () => T): Promise<T> {\n return new Promise((resolve, reject) => {\n transaction.oncomplete = () => resolve(value());\n transaction.onabort = () =>\n reject(transaction.error ?? new Error('metadata transaction aborted'));\n });\n}\n\ninterface Invalidation {\n paths?: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n}\n\nconst REMOVE_BATCH = 256;\nconst REMOVE_WAIT_MS = 5;\n\nexport class IndexedDbMeta implements MetaStore {\n private readonly db: IDBDatabase;\n private readonly cache = new PathMap<MetaEntry | null>();\n private readonly channel: BroadcastChannel;\n private generation = 0;\n private readonly listeners = new Set<(change: Invalidation) => void>();\n\n listen(listener: (change: Invalidation) => void): void {\n this.listeners.add(listener);\n }\n\n constructor(db: IDBDatabase) {\n this.db = db;\n db.onversionchange = () => db.close();\n this.channel = new BroadcastChannel(`slicc-kernel-meta:${db.name}`);\n this.channel.onmessage = ({ data }) => {\n this.drop(data as Invalidation);\n for (const listener of this.listeners) listener(data as Invalidation);\n };\n (this.channel as BroadcastChannel & { unref?: () => void }).unref?.();\n }\n\n forgetTrees(trees: readonly string[]): void {\n this.drop({ trees: [...trees] });\n }\n\n private drop({ paths = [], trees = [] }: Invalidation): void {\n this.generation++;\n for (const path of paths) this.cache.delete(path);\n for (const tree of trees) this.cache.deleteTree(tree);\n }\n\n private changed(invalidation: Invalidation): void {\n this.drop(invalidation);\n this.channel.postMessage(invalidation);\n }\n\n private transaction(mode: IDBTransactionMode): [IDBTransaction, IDBObjectStore] {\n const transaction = this.db.transaction(META_STORE, mode);\n return [transaction, transaction.objectStore(META_STORE)];\n }\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const missing = paths.filter((path) => !this.cache.has(path));\n if (missing.length > 0) {\n this.settleRemoves();\n const generation = this.generation;\n const [transaction, store] = this.transaction('readonly');\n const found = new Map<string, MetaEntry | null>();\n for (const path of missing) {\n const request = store.get(path);\n request.onsuccess = () => void found.set(path, request.result ?? null);\n }\n await settle(transaction, () => undefined);\n if (generation === this.generation)\n for (const [path, entry] of found) this.cache.set(path, entry);\n return paths.map(\n (path) => (found.has(path) ? found.get(path) : this.cache.get(path)) ?? undefined\n );\n }\n return paths.map((path) => this.cache.get(path) ?? undefined);\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const [transaction, store] = this.transaction('readonly');\n const requests = paths.map((path) => store.get(path));\n return settle(transaction, () =>\n requests.map((request) => (request.result as MetaEntry | undefined) ?? undefined)\n );\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const request = store.get(path);\n let next: MetaEntry | undefined;\n request.onsuccess = () => {\n next = change(request.result);\n if (next) store.put(next);\n else store.delete(path);\n };\n await settle(transaction, () => undefined);\n this.changed({ paths: [path] });\n this.cache.set(path, next ?? null);\n }\n\n async updateMany(changes: ReadonlyArray<MetaUpdate>): Promise<void> {\n if (changes.length === 0) return;\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const next = new Map<string, MetaEntry | null>();\n for (const { path, change } of changes) {\n const request = store.get(path);\n request.onsuccess = () => {\n const entry = change(request.result);\n next.set(path, entry ?? null);\n if (entry) store.put(entry);\n else store.delete(path);\n };\n }\n await settle(transaction, () => undefined);\n this.changed({ paths: changes.map(({ path }) => path) });\n for (const [path, entry] of next) this.cache.set(path, entry);\n }\n\n close(): void {\n this.channel.close();\n this.db.close();\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n store.delete(to);\n store.delete(descendants(to));\n const source = store.get(from);\n const below = store.getAll(descendants(from));\n below.onsuccess = () => {\n store.delete(from);\n store.delete(descendants(from));\n for (const entry of below.result as MetaEntry[]) {\n store.put(moved(entry, to + entry.path.slice(from.length)));\n }\n store.put(moved(root(source.result), to));\n if (left) store.put(left);\n };\n await settle(transaction, () => undefined);\n this.changed({ trees: [from, to], moved: { from, to } });\n }\n\n absent(path: string): boolean {\n return this.cache.has(path) && this.cache.get(path) === null;\n }\n\n private removing = new Map<string, string>();\n private removeTimer: ReturnType<typeof setTimeout> | undefined;\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n this.settleRemoves();\n return this.removeNow(paths, left);\n }\n\n async removeFile(path: string): Promise<void> {\n const known = this.cache.get(path);\n if (!known) return this.remove([path]);\n this.generation++;\n this.cache.set(path, null);\n this.removing.set(path, JSON.stringify(known));\n if (this.removing.size >= REMOVE_BATCH) return this.flushRemoves();\n this.removeTimer ??= setTimeout(\n () => void this.flushRemoves().catch(() => undefined),\n REMOVE_WAIT_MS\n );\n }\n\n private async removeNow(paths: readonly string[], left?: MetaEntry): Promise<void> {\n const [transaction, store] = this.transaction('readwrite');\n for (const path of paths) {\n store.delete(path);\n store.delete(descendants(path));\n }\n if (left) store.put(left);\n await settle(transaction, () => undefined);\n this.changed({ trees: paths });\n if (left) this.cache.set(left.path, left);\n }\n\n private settleRemoves(): void {\n if (this.removing.size > 0) void this.flushRemoves().catch(() => undefined);\n }\n\n private flushRemoves(): Promise<void> {\n clearTimeout(this.removeTimer);\n this.removeTimer = undefined;\n const batch = this.removing;\n if (batch.size === 0) return Promise.resolve();\n this.removing = new Map();\n const [transaction, store] = this.transaction('readwrite');\n for (const [path, seen] of batch) {\n const request = store.get(path);\n request.onsuccess = () => {\n if (request.result && JSON.stringify(request.result) === seen) store.delete(path);\n };\n }\n const paths = [...batch.keys()];\n return settle(transaction, () => void this.channel.postMessage({ paths }));\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.index('dir').getAll(dir);\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const self = store.get(path);\n const below = store.getAll(descendants(path));\n return settle(transaction, () =>\n [self.result as MetaEntry | undefined, ...(below.result as MetaEntry[])].filter(\n (entry): entry is MetaEntry => entry !== undefined\n )\n );\n }\n\n async all(): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.getAll();\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n}\n\nexport function openMetaDb(name: string, factory: IDBFactory): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = factory.open(name, META_VERSION);\n request.onupgradeneeded = (event) => {\n if (event.oldVersion < 1) {\n request.result.createObjectStore(META_STORE, { keyPath: 'path' }).createIndex('dir', 'dir');\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function openMeta(name: string, factory: IDBFactory): Promise<IndexedDbMeta> {\n return new IndexedDbMeta(await openMetaDb(name, factory));\n}\n", "export interface FsNotice {\n paths?: readonly string[];\n trees?: readonly string[];\n}\n\nexport function dirsChannel(metadata: string): string {\n return `slicc-kernel-dirs:${metadata}`;\n}\n\nexport function noticeOf(data: unknown): { paths: string[]; trees: string[]; outside?: true } {\n if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === 'string'), trees: [] };\n const notice = (data ?? {}) as FsNotice;\n const strings = (list: unknown) =>\n Array.isArray(list) ? list.filter((p): p is string => typeof p === 'string') : [];\n return { paths: strings(notice.paths), trees: strings(notice.trees), outside: true };\n}\n", "export interface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n isSocket?: boolean;\n isFifo?: boolean;\n size: number;\n mode: number;\n mtime: Date;\n atime: Date;\n ctime: Date;\n ino: number;\n fid?: string;\n nlink?: number;\n dev?: number;\n readonly?: boolean;\n maxFile?: number;\n ranged?: boolean;\n linkable?: boolean;\n version?: string;\n uid?: number;\n gid?: number;\n}\n\nexport type UsersMode = 'off' | 'report' | 'enforce';\n\nexport const DEFAULT_USERS: UsersMode = 'enforce';\n\nexport interface Owner {\n uid: number;\n gid: number;\n}\n\nexport interface Perm {\n uid: number;\n gid: number;\n mode?: number;\n link?: string;\n}\n\nexport interface NewOwner extends Owner {\n mode?: number;\n parents?: number;\n socket?: boolean;\n fifo?: boolean;\n existing?: true;\n}\n\nexport interface CopyOptions {\n exclusive: boolean;\n owner?: NewOwner;\n}\n\nexport interface OwnerChange {\n uid?: number;\n gid?: number;\n follow?: boolean;\n kind?: 'chown' | 'adopt' | 'new';\n mode?: number;\n}\n\nexport interface HeldEntry {\n writeFile: KernelFs['writeFile'];\n direct: boolean;\n}\n\nexport interface Peers {\n joined(): Promise<unknown>;\n crowded(): boolean;\n watch(listener: (crowded: boolean) => void): void;\n fresh?(): void;\n}\n\nexport interface KernelFs {\n resolvePath(base: string, path: string): string;\n exclusive?<T>(path: string, run: (held: HeldEntry) => Promise<T>, follow?: boolean): Promise<T>;\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: Uint8Array | string, owner?: NewOwner): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FsStat>;\n lstat(path: string): Promise<FsStat>;\n readdir(path: string): Promise<string[]>;\n readdirStat(path: string): Promise<Array<[string, FsStat | null]>>;\n mkdir(path: string, options?: { recursive?: boolean; owner?: NewOwner }): Promise<void>;\n rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean; file?: boolean }\n ): Promise<void>;\n rename(from: string, to: string): Promise<void>;\n link(from: string, to: string, follow?: boolean): Promise<void>;\n links?(path: string): boolean;\n symlink(target: string, path: string, owner?: NewOwner): Promise<void>;\n readlink(path: string): Promise<string>;\n realpath?(path: string, follow: boolean): Promise<string>;\n createExclusive?(path: string, owner?: NewOwner): Promise<void>;\n copyFile?(from: string, to: string, options: CopyOptions): Promise<void>;\n readonly rootName?: string;\n chown?(path: string, change: OwnerChange): Promise<void>;\n trackOwners?(): void;\n onPeer?(settle: () => Promise<void>): void;\n heldBy?(held: (dir: string) => readonly string[]): void;\n fileId?(path: string): Promise<string>;\n bindId?(path: string): Promise<string | undefined>;\n remoteChanges?(\n listener: (change: {\n paths: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n content?: true;\n outside?: true;\n }) => void\n ): () => void;\n refresh?(trees: readonly string[]): void;\n peers?(): Peers | undefined;\n crossings?(mounted: (path: string) => boolean): void;\n ancestry?(path: string): Promise<Array<Perm | undefined>>;\n hasOwner?(path: string): Promise<boolean>;\n chmod(path: string, mode: number): Promise<void>;\n append?(path: string, bytes: Uint8Array, options?: PwriteOptions): Promise<number>;\n utimes(path: string, atime: Date, mtime: Date): Promise<void>;\n lutimes?(path: string, atime: Date, mtime: Date): Promise<void>;\n pread?(path: string, offset: number, length: number, version?: string): Promise<Uint8Array>;\n pwrite?(\n path: string,\n offset: number,\n bytes: Uint8Array,\n transfer?: boolean,\n options?: PwriteOptions\n ): Promise<void>;\n truncate?(path: string, size: number): Promise<void>;\n protect?(prefixes: readonly string[], versions?: boolean): void;\n unguarded?(): KernelFs;\n noLinks?(): KernelFs;\n mayChange?(path: string, follow: boolean, whole?: boolean): Promise<void>;\n commandTarget?(path: string): Promise<string | undefined>;\n readVersioned?(path: string, cached?: boolean): Promise<{ bytes: Uint8Array; version: string }>;\n version?(path: string, cached?: boolean): Promise<string>;\n opfsCalls?(): number;\n renameWaits?(): {\n acks: number;\n busy: number;\n waits: number;\n queries: number;\n ackMs: readonly number[];\n };\n opfsOps?(): number;\n fileIdWrites?(): number;\n announceHolds?(\n add: ReadonlyArray<[string, string | undefined]>,\n drop: readonly string[],\n wait: boolean\n ): Promise<void>;\n holdCounts?(): { mine: number; peers: number; sent: number; held: string[] } | undefined;\n peerHolds?(listener: (paths: string[]) => void): void;\n rehold?(from: string, to: string): void;\n peerKeeps?(): PeerKeeps | undefined;\n servePeerKeeps?(\n instance: string,\n handlers: {\n keeping(tab: string, paths: readonly string[]): Promise<void>;\n kept(\n tab: string,\n items: ReadonlyArray<{\n path: string;\n hidden: string | undefined;\n fid: string | undefined;\n }>,\n paths: readonly string[]\n ): Promise<void>;\n left(tab: string): void;\n }\n ): void;\n}\n\nexport interface PeerKeeps {\n shared(): boolean;\n heldWithin(\n path: string\n ): Array<{ tab: string; path: string; fid: string | undefined; instance: string | undefined }>;\n ask(\n to: string,\n body: {\n keeping?: { paths: string[] };\n kept?: {\n items: Array<{\n path: string;\n hidden: string | undefined;\n fid: string | undefined;\n }>;\n paths?: string[];\n };\n },\n cap: number\n ): Promise<boolean>;\n}\n\nexport interface PwriteOptions {\n create?: false;\n alone?: true;\n}\n\nexport type RangedOps = Required<Pick<KernelFs, 'pread' | 'pwrite' | 'truncate'>>;\n\nexport function rangedOps(fs: Partial<RangedOps>): RangedOps | undefined {\n const { pread, pwrite, truncate } = fs;\n if (!pread || !pwrite || !truncate) return undefined;\n return { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };\n}\n\nexport async function lutimesOf(\n fs: KernelFs,\n path: string,\n atime: Date,\n mtime: Date\n): Promise<void> {\n if (fs.lutimes) return fs.lutimes(path, atime, mtime);\n if ((await fs.lstat(path)).isSymbolicLink) throw fsError('EOPNOTSUPP', path);\n return fs.utimes(path, atime, mtime);\n}\n\nexport function mayLink(fs: { links?(path: string): boolean }, path: string): boolean {\n return fs.links?.(path) ?? true;\n}\n\nexport function modeOption(mode: unknown): number {\n if (!Number.isInteger(mode) || (mode as number) < 0 || (mode as number) > 0o7777) {\n throw fsError('EINVAL', `not a mode: ${String(mode)}`);\n }\n return mode as number;\n}\n\nexport function fsError(code: string, path: string): Error & { code: string } {\n return Object.assign(new Error(`${code}: ${path}`), { code });\n}\n\nexport function normalizePath(path: string): string {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') parts.pop();\n else parts.push(part);\n }\n return `/${parts.join('/')}`;\n}\n\nexport function resolvePath(base: string, path: string): string {\n return normalizePath(path.startsWith('/') ? path : `${base}/${path}`);\n}\n\nexport function inodeOf(path: string): number {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n for (let i = 0; i < path.length; i++) {\n const c = path.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, 2654435761);\n h2 = Math.imul(h2 ^ c, 1597334677);\n }\n h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;\n}\n\nexport interface Redirect {\n of: string;\n to: string;\n}\n\nexport function redirected(of: string, to: string): Error {\n return Object.assign(fsError('EXDEV', `${of} leads to the mount at ${to}`), {\n redirect: { of: normalizePath(of), to: normalizePath(to) },\n });\n}\n\nexport function redirectOf(err: unknown): Redirect | undefined {\n return (err as { redirect?: Redirect } | null)?.redirect;\n}\n", "export const REPLACING_LOCK = 'slicc-kernel-replacing:v1:';\nexport const REPLACED_WAIT_MS = 150;\n\nexport interface ReplacingLocks {\n request(\n name: string,\n options: { mode: 'shared' | 'exclusive'; ifAvailable?: boolean },\n callback: (lock: unknown) => unknown\n ): Promise<unknown>;\n}\n\nexport function replacingLocks(scope: object = globalThis): ReplacingLocks | undefined {\n const locks = (scope as { navigator?: { locks?: ReplacingLocks } }).navigator?.locks;\n return typeof locks?.request === 'function' ? locks : undefined;\n}\n\nexport function replacingLock(metadata: string, root: string): string {\n return `${REPLACING_LOCK}${metadata}:${root}`;\n}\n\nexport function exclusively<T>(\n locks: ReplacingLocks,\n names: readonly string[],\n run: () => Promise<T>\n): Promise<T> {\n const [name, ...rest] = names;\n if (name === undefined) return run();\n return locks.request(name, { mode: 'exclusive' }, () =>\n exclusively(locks, rest, run)\n ) as Promise<T>;\n}\n\nfunction shared<T>(\n locks: ReplacingLocks,\n names: readonly string[],\n run: (waited: boolean) => Promise<T>,\n waited: boolean\n): Promise<T> {\n const [name, ...rest] = names;\n if (name === undefined) return run(waited);\n const next = (after: boolean) => shared(locks, rest, run, after);\n return locks.request(name, { mode: 'shared', ifAvailable: true }, (lock) =>\n lock ? next(waited) : locks.request(name, { mode: 'shared' }, () => next(true))\n ) as Promise<T>;\n}\n\nexport class PackageLocks {\n private readonly locks: ReplacingLocks | undefined;\n private readonly metadata: string;\n\n constructor(metadata: string, locks = replacingLocks()) {\n this.metadata = metadata;\n this.locks = locks;\n }\n\n loading<T>(roots: readonly string[], run: (waited: boolean) => Promise<T>): Promise<T> {\n if (!this.locks || roots.length === 0) return run(false);\n const names = roots.map((root) => replacingLock(this.metadata, root));\n return shared(this.locks, names, run, false);\n }\n\n holding(root: string): Promise<() => void> {\n const { locks } = this;\n if (!locks) return Promise.resolve(() => {});\n const { promise: held, resolve: release } = Promise.withResolvers<void>();\n return new Promise((granted, failed) => {\n locks\n .request(replacingLock(this.metadata, root), { mode: 'exclusive' }, () => {\n granted(() => release());\n return held;\n })\n .catch(failed);\n });\n }\n}\n", "import { META_DB, type MetaEntry, openMeta } from './fs/meta.ts';\nimport { dirsChannel, type FsNotice } from './fs/notice.ts';\nimport { fsError, normalizePath } from './fs/types.ts';\nimport {\n exclusively,\n REPLACED_WAIT_MS,\n replacingLock,\n replacingLocks,\n} from './kernel/replacing.ts';\n\nexport type { FsNotice };\n\nexport interface MetadataEntry {\n path: string;\n mode?: number;\n uid?: number;\n gid?: number;\n}\n\nexport interface WriteMetadataOptions {\n metadata?: string;\n indexedDB?: IDBFactory;\n}\n\nconst MAX_ID = 0xfffffffe;\n\nfunction id(value: unknown, what: string): number {\n if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > MAX_ID) {\n throw fsError('EINVAL', `not a ${what}: ${String(value)}`);\n }\n return value as number;\n}\n\nfunction checked(entry: MetadataEntry): MetadataEntry {\n if (!String(entry.path).startsWith('/'))\n throw fsError('EINVAL', `not an absolute path: ${entry.path}`);\n const path = normalizePath(String(entry.path));\n if ((entry.uid === undefined) !== (entry.gid === undefined)) {\n throw fsError('EINVAL', `${path}: give both uid and gid, or neither`);\n }\n const mode = entry.mode;\n if (mode !== undefined && (!Number.isInteger(mode) || mode < 0 || mode > 0o7777)) {\n throw fsError('EINVAL', `${path}: not a mode: ${String(mode)}`);\n }\n return {\n path,\n ...(mode !== undefined ? { mode } : {}),\n ...(entry.uid !== undefined ? { uid: id(entry.uid, 'uid'), gid: id(entry.gid, 'gid') } : {}),\n };\n}\n\nasync function present(root: FileSystemDirectoryHandle, path: string): Promise<boolean> {\n const parts = path.split('/').filter(Boolean);\n let dir = root;\n for (const [i, name] of parts.entries()) {\n const last = i === parts.length - 1;\n try {\n dir = await dir.getDirectoryHandle(name);\n } catch {\n if (!last) return false;\n return dir.getFileHandle(name).then(\n () => true,\n () => false\n );\n }\n }\n return true;\n}\n\nexport async function writeMetadata(\n root: FileSystemDirectoryHandle,\n entries: readonly MetadataEntry[],\n options: WriteMetadataOptions = {}\n): Promise<void> {\n const merged = new Map<string, MetadataEntry>();\n for (const want of entries.map(checked))\n merged.set(want.path, { ...merged.get(want.path), ...want });\n const wanted = [...merged.values()];\n for (const { path } of wanted) {\n if (!(await present(root, path))) throw fsError('ENOENT', path);\n }\n const factory = options.indexedDB ?? globalThis.indexedDB;\n const store = await openMeta(options.metadata ?? META_DB, factory);\n const ctimeMs = Date.now();\n try {\n await store.updateMany(\n wanted.map((want) => ({\n path: want.path,\n change: (entry: MetaEntry | undefined): MetaEntry => ({\n ...entry,\n path: want.path,\n ...(want.mode !== undefined ? { mode: want.mode } : {}),\n ...(want.uid !== undefined ? { uid: want.uid, gid: want.gid as number } : {}),\n ctimeMs,\n }),\n }))\n );\n } finally {\n store.close();\n }\n}\n\nexport interface PostFsNoticeOptions {\n metadata?: string;\n}\n\nfunction absolute(list: readonly string[] | undefined): string[] {\n return (list ?? []).map((path) => {\n if (!String(path).startsWith('/')) throw fsError('EINVAL', `not an absolute path: ${path}`);\n return normalizePath(String(path));\n });\n}\n\nexport function postFsNotice(notice: FsNotice, options: PostFsNoticeOptions = {}): void {\n const paths = absolute(notice.paths);\n const trees = absolute(notice.trees);\n if (paths.length === 0 && trees.length === 0) return;\n const channel = new BroadcastChannel(dirsChannel(options.metadata ?? META_DB));\n try {\n channel.postMessage({ paths, trees });\n } finally {\n channel.close();\n }\n}\n\nexport interface ReplacingOptions {\n metadata?: string;\n}\n\nconst HELD = Symbol.for('slicc-kernel.replacing.v1');\n\nfunction realmHeld(): Set<string> {\n const scope = globalThis as { [HELD]?: Set<string> };\n scope[HELD] ??= new Set();\n return scope[HELD];\n}\n\nexport async function replacing<T>(\n paths: readonly string[],\n task: () => T | Promise<T>,\n options: ReplacingOptions = {}\n): Promise<T> {\n if (!Array.isArray(paths)) throw new TypeError('replacing: paths must be an array of paths');\n if (typeof task !== 'function') throw new TypeError('replacing: task must be a function');\n const roots = [...new Set(absolute(paths))].sort();\n const metadata = options.metadata ?? META_DB;\n const held = realmHeld();\n const busy = roots.find((root) => held.has(root));\n if (busy !== undefined) {\n throw fsError('EDEADLK', `${busy} is already being replaced in this realm`);\n }\n const locks = replacingLocks();\n const run = async () => {\n try {\n return await task();\n } finally {\n postFsNotice({ trees: roots }, { metadata });\n if (locks && roots.length > 0) {\n await new Promise((resolve) => setTimeout(resolve, REPLACED_WAIT_MS));\n }\n }\n };\n for (const root of roots) held.add(root);\n try {\n if (!locks) return await run();\n const names = roots.map((root) => replacingLock(metadata, root));\n return await exclusively(locks, names, run);\n } finally {\n for (const root of roots) held.delete(root);\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["parentOf"]
|
|
3
|
+
"sources": ["../src/fs/meta-reads.ts", "../src/fs/path-map.ts", "../src/fs/meta.ts", "../src/fs/notice.ts", "../src/fs/types.ts", "../src/kernel/replacing.ts", "../src/meta.ts"],
|
|
4
|
+
"sourcesContent": ["import type { MetaEntry } from './meta.ts';\n\nexport interface Invalidated {\n paths?: readonly string[];\n trees?: readonly string[];\n}\n\nconst parentOf = (path: string): string => path.slice(0, path.lastIndexOf('/')) || '/';\nconst within = (path: string, root: string): boolean =>\n root === '/' || path === root || path.startsWith(`${root}/`);\n\ninterface Noted {\n at: number;\n paths: readonly string[];\n trees: readonly string[];\n}\n\nexport class Invalidations {\n private seq = 0;\n private readonly log: Noted[] = [];\n private readonly open = new Map<number, number>();\n\n start(): number {\n const at = this.seq;\n this.open.set(at, (this.open.get(at) ?? 0) + 1);\n return at;\n }\n\n end(at: number): void {\n const left = (this.open.get(at) ?? 1) - 1;\n if (left > 0) this.open.set(at, left);\n else this.open.delete(at);\n const oldest = this.open.keys().next();\n if (oldest.done) this.log.length = 0;\n else while (this.log.length > 0 && (this.log[0] as Noted).at <= oldest.value) this.log.shift();\n }\n\n note({ paths = [], trees = [] }: Invalidated): void {\n this.seq++;\n if (this.open.size > 0) this.log.push({ at: this.seq, paths, trees });\n }\n\n private since(at: number, hit: (noted: Noted) => boolean): boolean {\n for (let i = this.log.length - 1; i >= 0; i--) {\n const noted = this.log[i] as Noted;\n if (noted.at <= at) return false;\n if (hit(noted)) return true;\n }\n return false;\n }\n\n entryStale(at: number, path: string): boolean {\n return this.since(\n at,\n ({ paths, trees }) => paths.includes(path) || trees.some((tree) => within(path, tree))\n );\n }\n\n listingStale(at: number, dir: string): boolean {\n return this.since(\n at,\n ({ paths, trees }) =>\n paths.some((path) => path !== '/' && parentOf(path) === dir) ||\n trees.some((tree) => within(dir, tree) || (tree !== '/' && parentOf(tree) === dir))\n );\n }\n}\n\nexport type MetaReadKind = 'entry' | 'links';\n\ninterface Wanted<T> {\n promise: Promise<T>;\n resolve: (value: T) => void;\n reject: (error: unknown) => void;\n at?: number;\n}\n\nexport interface ReadBatch {\n entries: readonly string[];\n links: readonly string[];\n}\n\nexport interface ReadResult {\n entries: Map<string, MetaEntry | null>;\n links: Map<string, MetaEntry[]>;\n}\n\nexport const META_READS_IN_FLIGHT = 4;\n\nexport class BatchedReads {\n private readonly run: (batch: ReadBatch) => Promise<ReadResult>;\n private readonly invalidations: Invalidations;\n private readonly keep: (kind: MetaReadKind, key: string, value: unknown) => void;\n private readonly queued: Record<MetaReadKind, Map<string, Wanted<unknown>>> = {\n entry: new Map(),\n links: new Map(),\n };\n private readonly reading: Record<MetaReadKind, Map<string, Wanted<unknown>>> = {\n entry: new Map(),\n links: new Map(),\n };\n private inFlight = 0;\n\n constructor(\n invalidations: Invalidations,\n run: (batch: ReadBatch) => Promise<ReadResult>,\n keep: (kind: MetaReadKind, key: string, value: unknown) => void\n ) {\n this.invalidations = invalidations;\n this.run = run;\n this.keep = keep;\n }\n\n entries(paths: readonly string[]): Promise<Map<string, MetaEntry | null>> {\n const wanted = paths.map((path) => [path, this.want('entry', path)] as const);\n this.pump();\n return Promise.all(wanted.map(([, w]) => w.promise)).then(\n (found) => new Map(wanted.map(([path], i) => [path, found[i] as MetaEntry | null]))\n );\n }\n\n links(dir: string): Promise<MetaEntry[]> {\n const wanted = this.want('links', dir);\n this.pump();\n return wanted.promise as Promise<MetaEntry[]>;\n }\n\n private stale(kind: MetaReadKind, key: string, at: number): boolean {\n return kind === 'entry'\n ? this.invalidations.entryStale(at, key)\n : this.invalidations.listingStale(at, key);\n }\n\n private want(kind: MetaReadKind, key: string): Wanted<unknown> {\n const reading = this.reading[kind].get(key);\n if (reading && !this.stale(kind, key, reading.at as number)) return reading;\n const queued = this.queued[kind].get(key);\n if (queued) return queued;\n const made = Promise.withResolvers<unknown>();\n made.promise.catch(() => undefined);\n this.queued[kind].set(key, made);\n return made;\n }\n\n private pump(): void {\n while (\n this.inFlight < META_READS_IN_FLIGHT &&\n (this.queued.entry.size > 0 || this.queued.links.size > 0)\n ) {\n this.flush();\n }\n }\n\n private flush(): void {\n const entries = this.queued.entry;\n const links = this.queued.links;\n this.queued.entry = new Map();\n this.queued.links = new Map();\n const at = this.invalidations.start();\n for (const [kind, taken] of [\n ['entry', entries],\n ['links', links],\n ] as const) {\n for (const [key, wanted] of taken) {\n wanted.at = at;\n this.reading[kind].set(key, wanted);\n }\n }\n this.inFlight++;\n const settled = (result: ReadResult | undefined, error?: unknown) => {\n this.inFlight--;\n for (const [kind, taken, found] of [\n ['entry', entries, result?.entries],\n ['links', links, result?.links],\n ] as const) {\n for (const [key, wanted] of taken) {\n if (this.reading[kind].get(key) === wanted) this.reading[kind].delete(key);\n if (!found) {\n wanted.reject(error);\n continue;\n }\n const value = found.get(key) ?? (kind === 'entry' ? null : []);\n if (!this.stale(kind, key, at)) this.keep(kind, key, value);\n wanted.resolve(value);\n }\n }\n this.invalidations.end(at);\n this.pump();\n };\n let reading: Promise<ReadResult>;\n try {\n reading = this.run({ entries: [...entries.keys()], links: [...links.keys()] });\n } catch (error) {\n settled(undefined, error);\n return;\n }\n reading.then(\n (result) => settled(result),\n (error: unknown) => settled(undefined, error)\n );\n }\n}\n", "function parentOf(path: string): string | undefined {\n if (path === '/' || path === '') return undefined;\n const at = path.lastIndexOf('/');\n return at <= 0 ? '/' : path.slice(0, at);\n}\n\nexport class PathMap<V> {\n private readonly values = new Map<string, V>();\n private readonly children = new Map<string, Set<string>>();\n\n get size(): number {\n return this.values.size;\n }\n\n has(path: string): boolean {\n return this.values.has(path);\n }\n\n get(path: string): V | undefined {\n return this.values.get(path);\n }\n\n keys(): IterableIterator<string> {\n return this.values.keys();\n }\n\n set(path: string, value: V): this {\n if (!this.values.has(path)) this.link(path);\n this.values.set(path, value);\n return this;\n }\n\n delete(path: string): boolean {\n if (!this.values.delete(path)) return false;\n this.prune(path);\n return true;\n }\n\n subtree(root: string): string[] {\n const out: string[] = [];\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n if (this.values.has(path)) out.push(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n }\n return out;\n }\n\n entries(): IterableIterator<[string, V]> {\n return this.values.entries();\n }\n\n deleteTree(root: string): void {\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n this.values.delete(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n this.children.delete(path);\n }\n this.prune(root);\n }\n\n clear(): void {\n this.values.clear();\n this.children.clear();\n }\n\n private link(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n const set = this.children.get(parent);\n if (set?.has(child)) return;\n if (set) set.add(child);\n else this.children.set(parent, new Set([child]));\n child = parent;\n parent = parentOf(parent);\n }\n }\n\n private prune(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n if (this.values.has(child) || this.children.has(child)) return;\n const set = this.children.get(parent);\n set?.delete(child);\n if (set && set.size > 0) return;\n this.children.delete(parent);\n child = parent;\n parent = parentOf(parent);\n }\n }\n}\n", "import { BatchedReads, Invalidations, type ReadBatch, type ReadResult } from './meta-reads.ts';\nimport { PathMap } from './path-map.ts';\nexport interface MetaEntry {\n path: string;\n mode?: number;\n atimeMs?: number;\n mtimeMs?: number;\n mtimeFor?: number;\n timesAt?: number;\n timesBy?: string;\n ctimeMs?: number;\n ino?: number;\n fid?: string;\n link?: string;\n socket?: true;\n fifo?: true;\n dir?: string;\n uid?: number;\n gid?: number;\n heir?: [number, number];\n writes?: number;\n epoch?: number;\n vacated?: true;\n rename?: {\n from: string;\n to: string;\n at: number;\n replace?: true;\n lock?: string;\n root?: { ino: number; uid?: number; gid?: number; mode?: number };\n };\n}\n\nexport type MetaChange = (entry: MetaEntry | undefined) => MetaEntry | undefined;\n\nexport interface MetaUpdate {\n path: string;\n change: MetaChange;\n}\n\nexport interface MetaStore {\n get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n fresh?(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n update(path: string, change: MetaChange): Promise<void>;\n updateMany?(changes: ReadonlyArray<MetaUpdate>): Promise<void>;\n move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ): Promise<void>;\n remove(paths: readonly string[], left?: MetaEntry): Promise<void>;\n links(dir: string): Promise<MetaEntry[]>;\n under(path: string): Promise<MetaEntry[]>;\n all(): Promise<MetaEntry[]>;\n absent?(path: string): boolean;\n removeFile?(path: string): Promise<void>;\n forgetTrees?(trees: readonly string[]): void;\n transactions?(): MetaTransactions;\n}\n\nexport interface MetaTransactions {\n reads: number;\n writes: number;\n}\n\nexport const META_DB = 'slicc-kernel';\nexport const META_VERSION = 1;\nexport const META_STORE = 'entries';\n\nfunction parentOf(path: string): string {\n return path.slice(0, path.lastIndexOf('/')) || '/';\n}\n\nfunction moved(entry: MetaEntry, path: string): MetaEntry {\n return entry.link === undefined ? { ...entry, path } : { ...entry, path, dir: parentOf(path) };\n}\n\nfunction under(path: string, root: string): boolean {\n return path === root || path.startsWith(`${root}/`);\n}\n\nexport class MemoryMeta implements MetaStore {\n private readonly entries = new PathMap<MetaEntry>();\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return paths.map((path) => this.entries.get(path));\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return this.get(paths);\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.set(path, change(this.entries.get(path)));\n }\n\n private set(path: string, entry: MetaEntry | undefined): void {\n if (entry) this.entries.set(path, entry);\n else this.entries.delete(path);\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n await this.remove([to]);\n const carried = this.entries.subtree(from).map((path) => this.entries.get(path) as MetaEntry);\n for (const entry of carried) this.entries.delete(entry.path);\n for (const entry of carried) {\n const path = to + entry.path.slice(from.length);\n if (path !== to) this.entries.set(path, moved(entry, path));\n }\n this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));\n if (left) this.entries.set(from, left);\n }\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n for (const path of paths) this.entries.deleteTree(path);\n if (left) this.entries.set(left.path, left);\n }\n\n absent(path: string): boolean {\n return !this.entries.has(path);\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => under(entry.path, path));\n }\n\n async all(): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e);\n }\n}\n\nfunction descendants(path: string): IDBKeyRange {\n return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);\n}\n\nfunction settle<T>(transaction: IDBTransaction, value: () => T): Promise<T> {\n return new Promise((resolve, reject) => {\n transaction.oncomplete = () => resolve(value());\n transaction.onabort = () =>\n reject(transaction.error ?? new Error('metadata transaction aborted'));\n });\n}\n\ninterface Invalidation {\n paths?: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n}\n\nconst REMOVE_BATCH = 256;\nconst REMOVE_WAIT_MS = 5;\nconst LISTINGS_KEPT = 4096;\n\nexport class IndexedDbMeta implements MetaStore {\n private readonly db: IDBDatabase;\n private readonly cache = new PathMap<MetaEntry | null>();\n private readonly listings = new PathMap<readonly MetaEntry[]>();\n private readonly channel: BroadcastChannel;\n private readonly invalidations = new Invalidations();\n private readonly reads = new BatchedReads(\n this.invalidations,\n (batch) => this.read(batch),\n (kind, key, value) => {\n if (kind === 'entry') this.cache.set(key, value as MetaEntry | null);\n else this.keepListing(key, value as MetaEntry[]);\n }\n );\n private readonly listeners = new Set<(change: Invalidation) => void>();\n\n listen(listener: (change: Invalidation) => void): void {\n this.listeners.add(listener);\n }\n\n constructor(db: IDBDatabase) {\n this.db = db;\n db.onversionchange = () => db.close();\n this.channel = new BroadcastChannel(`slicc-kernel-meta:${db.name}`);\n this.channel.onmessage = ({ data }) => {\n this.drop(data as Invalidation);\n for (const listener of this.listeners) listener(data as Invalidation);\n };\n (this.channel as BroadcastChannel & { unref?: () => void }).unref?.();\n }\n\n forgetTrees(trees: readonly string[]): void {\n this.drop({ trees: [...trees] });\n }\n\n private drop({ paths = [], trees = [] }: Invalidation): void {\n this.invalidations.note({ paths, trees });\n for (const path of paths) {\n this.cache.delete(path);\n if (path !== '/') this.listings.delete(parentOf(path));\n }\n for (const tree of trees) {\n this.cache.deleteTree(tree);\n this.listings.deleteTree(tree);\n if (tree !== '/') this.listings.delete(parentOf(tree));\n }\n }\n\n private keepListing(dir: string, links: MetaEntry[]): void {\n if (this.listings.size >= LISTINGS_KEPT) this.listings.clear();\n this.listings.set(dir, links);\n }\n\n private async read({ entries, links }: ReadBatch): Promise<ReadResult> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const result: ReadResult = { entries: new Map(), links: new Map() };\n for (const path of entries) {\n const request = store.get(path);\n request.onsuccess = () => void result.entries.set(path, request.result ?? null);\n }\n if (links.length > 0) {\n const index = store.index('dir');\n for (const dir of links) {\n const request = index.getAll(dir);\n request.onsuccess = () => void result.links.set(dir, request.result as MetaEntry[]);\n }\n }\n return settle(transaction, () => result);\n }\n\n private changed(invalidation: Invalidation): void {\n this.drop(invalidation);\n this.channel.postMessage(invalidation);\n }\n\n private readonly counted: MetaTransactions = { reads: 0, writes: 0 };\n\n transactions(): MetaTransactions {\n return { ...this.counted };\n }\n\n private transaction(mode: IDBTransactionMode): [IDBTransaction, IDBObjectStore] {\n if (mode === 'readonly') this.counted.reads++;\n else this.counted.writes++;\n const transaction = this.db.transaction(META_STORE, mode);\n return [transaction, transaction.objectStore(META_STORE)];\n }\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const missing = paths.filter((path) => !this.cache.has(path));\n if (missing.length > 0) {\n const found = await this.reads.entries(missing);\n return paths.map(\n (path) => (found.has(path) ? found.get(path) : this.cache.get(path)) ?? undefined\n );\n }\n return paths.map((path) => this.cache.get(path) ?? undefined);\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const [transaction, store] = this.transaction('readonly');\n const requests = paths.map((path) => store.get(path));\n return settle(transaction, () =>\n requests.map((request) => (request.result as MetaEntry | undefined) ?? undefined)\n );\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const request = store.get(path);\n let next: MetaEntry | undefined;\n request.onsuccess = () => {\n next = change(request.result);\n if (next) store.put(next);\n else store.delete(path);\n };\n await settle(transaction, () => undefined);\n this.changed({ paths: [path] });\n this.cache.set(path, next ?? null);\n }\n\n async updateMany(changes: ReadonlyArray<MetaUpdate>): Promise<void> {\n if (changes.length === 0) return;\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const next = new Map<string, MetaEntry | null>();\n for (const { path, change } of changes) {\n const request = store.get(path);\n request.onsuccess = () => {\n const entry = change(request.result);\n next.set(path, entry ?? null);\n if (entry) store.put(entry);\n else store.delete(path);\n };\n }\n await settle(transaction, () => undefined);\n this.changed({ paths: changes.map(({ path }) => path) });\n for (const [path, entry] of next) this.cache.set(path, entry);\n }\n\n close(): void {\n this.channel.close();\n this.db.close();\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n store.delete(to);\n store.delete(descendants(to));\n const source = store.get(from);\n const below = store.getAll(descendants(from));\n below.onsuccess = () => {\n store.delete(from);\n store.delete(descendants(from));\n for (const entry of below.result as MetaEntry[]) {\n store.put(moved(entry, to + entry.path.slice(from.length)));\n }\n store.put(moved(root(source.result), to));\n if (left) store.put(left);\n };\n await settle(transaction, () => undefined);\n this.changed({ trees: [from, to], moved: { from, to } });\n }\n\n absent(path: string): boolean {\n return this.cache.has(path) && this.cache.get(path) === null;\n }\n\n private removing = new Map<string, string>();\n private removeTimer: ReturnType<typeof setTimeout> | undefined;\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n this.settleRemoves();\n return this.removeNow(paths, left);\n }\n\n async removeFile(path: string): Promise<void> {\n const known = this.cache.get(path);\n if (!known) return this.remove([path]);\n this.invalidations.note({ paths: [path] });\n if (path !== '/') this.listings.delete(parentOf(path));\n this.cache.set(path, null);\n this.removing.set(path, JSON.stringify(known));\n if (this.removing.size >= REMOVE_BATCH) return this.flushRemoves();\n this.removeTimer ??= setTimeout(\n () => void this.flushRemoves().catch(() => undefined),\n REMOVE_WAIT_MS\n );\n }\n\n private async removeNow(paths: readonly string[], left?: MetaEntry): Promise<void> {\n const [transaction, store] = this.transaction('readwrite');\n for (const path of paths) {\n store.delete(path);\n store.delete(descendants(path));\n }\n if (left) store.put(left);\n await settle(transaction, () => undefined);\n this.changed({ trees: paths });\n if (left) this.cache.set(left.path, left);\n }\n\n private settleRemoves(): void {\n if (this.removing.size > 0) void this.flushRemoves().catch(() => undefined);\n }\n\n private flushRemoves(): Promise<void> {\n clearTimeout(this.removeTimer);\n this.removeTimer = undefined;\n const batch = this.removing;\n if (batch.size === 0) return Promise.resolve();\n this.removing = new Map();\n const [transaction, store] = this.transaction('readwrite');\n for (const [path, seen] of batch) {\n const request = store.get(path);\n request.onsuccess = () => {\n if (request.result && JSON.stringify(request.result) === seen) store.delete(path);\n };\n }\n const paths = [...batch.keys()];\n return settle(transaction, () => void this.channel.postMessage({ paths }));\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n const known = this.listings.get(dir);\n return [...(known ?? (await this.reads.links(dir)))];\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const self = store.get(path);\n const below = store.getAll(descendants(path));\n return settle(transaction, () =>\n [self.result as MetaEntry | undefined, ...(below.result as MetaEntry[])].filter(\n (entry): entry is MetaEntry => entry !== undefined\n )\n );\n }\n\n async all(): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.getAll();\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n}\n\nexport function openMetaDb(name: string, factory: IDBFactory): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = factory.open(name, META_VERSION);\n request.onupgradeneeded = (event) => {\n if (event.oldVersion < 1) {\n request.result.createObjectStore(META_STORE, { keyPath: 'path' }).createIndex('dir', 'dir');\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function openMeta(name: string, factory: IDBFactory): Promise<IndexedDbMeta> {\n return new IndexedDbMeta(await openMetaDb(name, factory));\n}\n", "export interface FsNotice {\n paths?: readonly string[];\n trees?: readonly string[];\n}\n\nexport function dirsChannel(metadata: string): string {\n return `slicc-kernel-dirs:${metadata}`;\n}\n\nexport function noticeOf(data: unknown): { paths: string[]; trees: string[]; outside?: true } {\n if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === 'string'), trees: [] };\n const notice = (data ?? {}) as FsNotice;\n const strings = (list: unknown) =>\n Array.isArray(list) ? list.filter((p): p is string => typeof p === 'string') : [];\n return { paths: strings(notice.paths), trees: strings(notice.trees), outside: true };\n}\n", "export interface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n isSocket?: boolean;\n isFifo?: boolean;\n size: number;\n mode: number;\n mtime: Date;\n atime: Date;\n ctime: Date;\n ino: number;\n fid?: string;\n nlink?: number;\n dev?: number;\n readonly?: boolean;\n maxFile?: number;\n ranged?: boolean;\n linkable?: boolean;\n version?: string;\n uid?: number;\n gid?: number;\n}\n\nexport type UsersMode = 'off' | 'report' | 'enforce';\n\nexport const DEFAULT_USERS: UsersMode = 'enforce';\n\nexport interface Owner {\n uid: number;\n gid: number;\n}\n\nexport interface Perm {\n uid: number;\n gid: number;\n mode?: number;\n link?: string;\n}\n\nexport interface NewOwner extends Owner {\n mode?: number;\n parents?: number;\n socket?: boolean;\n fifo?: boolean;\n existing?: true;\n}\n\nexport interface CopyOptions {\n exclusive: boolean;\n owner?: NewOwner;\n}\n\nexport interface OwnerChange {\n uid?: number;\n gid?: number;\n follow?: boolean;\n kind?: 'chown' | 'adopt' | 'new';\n mode?: number;\n}\n\nexport interface HeldEntry {\n writeFile: KernelFs['writeFile'];\n direct: boolean;\n}\n\nexport interface Peers {\n joined(): Promise<unknown>;\n crowded(): boolean;\n watch(listener: (crowded: boolean) => void): void;\n fresh?(): void;\n}\n\nexport interface KernelFs {\n resolvePath(base: string, path: string): string;\n exclusive?<T>(path: string, run: (held: HeldEntry) => Promise<T>, follow?: boolean): Promise<T>;\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: Uint8Array | string, owner?: NewOwner): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FsStat>;\n lstat(path: string): Promise<FsStat>;\n readdir(path: string): Promise<string[]>;\n readdirStat(path: string): Promise<Array<[string, FsStat | null]>>;\n mkdir(path: string, options?: { recursive?: boolean; owner?: NewOwner }): Promise<void>;\n rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean; file?: boolean }\n ): Promise<void>;\n rename(from: string, to: string): Promise<void>;\n link(from: string, to: string, follow?: boolean): Promise<void>;\n links?(path: string): boolean;\n symlink(target: string, path: string, owner?: NewOwner): Promise<void>;\n readlink(path: string): Promise<string>;\n realpath?(path: string, follow: boolean): Promise<string>;\n createExclusive?(path: string, owner?: NewOwner): Promise<void>;\n copyFile?(from: string, to: string, options: CopyOptions): Promise<void>;\n readonly rootName?: string;\n chown?(path: string, change: OwnerChange): Promise<void>;\n trackOwners?(): void;\n onPeer?(settle: () => Promise<void>): void;\n heldBy?(held: (dir: string) => readonly string[]): void;\n fileId?(path: string): Promise<string>;\n bindId?(path: string): Promise<string | undefined>;\n remoteChanges?(\n listener: (change: {\n paths: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n content?: true;\n outside?: true;\n }) => void\n ): () => void;\n refresh?(trees: readonly string[]): void;\n peers?(): Peers | undefined;\n crossings?(mounted: (path: string) => boolean): void;\n ancestry?(path: string): Promise<Array<Perm | undefined>>;\n hasOwner?(path: string): Promise<boolean>;\n chmod(path: string, mode: number): Promise<void>;\n append?(path: string, bytes: Uint8Array, options?: PwriteOptions): Promise<number>;\n utimes(path: string, atime: Date, mtime: Date): Promise<void>;\n lutimes?(path: string, atime: Date, mtime: Date): Promise<void>;\n pread?(path: string, offset: number, length: number, version?: string): Promise<Uint8Array>;\n pwrite?(\n path: string,\n offset: number,\n bytes: Uint8Array,\n transfer?: boolean,\n options?: PwriteOptions\n ): Promise<void>;\n truncate?(path: string, size: number): Promise<void>;\n protect?(prefixes: readonly string[], versions?: boolean): void;\n unguarded?(): KernelFs;\n noLinks?(): KernelFs;\n mayChange?(path: string, follow: boolean, whole?: boolean): Promise<void>;\n commandTarget?(path: string): Promise<string | undefined>;\n readVersioned?(path: string, cached?: boolean): Promise<{ bytes: Uint8Array; version: string }>;\n version?(path: string, cached?: boolean): Promise<string>;\n opfsCalls?(): number;\n renameWaits?(): {\n acks: number;\n busy: number;\n waits: number;\n queries: number;\n ackMs: readonly number[];\n };\n opfsOps?(): number;\n metaTransactions?(): { reads: number; writes: number } | undefined;\n fileIdWrites?(): number;\n announceHolds?(\n add: ReadonlyArray<[string, string | undefined]>,\n drop: readonly string[],\n wait: boolean\n ): Promise<void>;\n holdCounts?(): { mine: number; peers: number; sent: number; held: string[] } | undefined;\n peerHolds?(listener: (paths: string[]) => void): void;\n rehold?(from: string, to: string): void;\n peerKeeps?(): PeerKeeps | undefined;\n servePeerKeeps?(\n instance: string,\n handlers: {\n keeping(tab: string, paths: readonly string[]): Promise<void>;\n kept(\n tab: string,\n items: ReadonlyArray<{\n path: string;\n hidden: string | undefined;\n fid: string | undefined;\n }>,\n paths: readonly string[]\n ): Promise<void>;\n left(tab: string): void;\n }\n ): void;\n}\n\nexport interface PeerKeeps {\n shared(): boolean;\n heldWithin(\n path: string\n ): Array<{ tab: string; path: string; fid: string | undefined; instance: string | undefined }>;\n ask(\n to: string,\n body: {\n keeping?: { paths: string[] };\n kept?: {\n items: Array<{\n path: string;\n hidden: string | undefined;\n fid: string | undefined;\n }>;\n paths?: string[];\n };\n },\n cap: number\n ): Promise<boolean>;\n}\n\nexport interface PwriteOptions {\n create?: false;\n alone?: true;\n}\n\nexport type RangedOps = Required<Pick<KernelFs, 'pread' | 'pwrite' | 'truncate'>>;\n\nexport function rangedOps(fs: Partial<RangedOps>): RangedOps | undefined {\n const { pread, pwrite, truncate } = fs;\n if (!pread || !pwrite || !truncate) return undefined;\n return { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };\n}\n\nexport async function lutimesOf(\n fs: KernelFs,\n path: string,\n atime: Date,\n mtime: Date\n): Promise<void> {\n if (fs.lutimes) return fs.lutimes(path, atime, mtime);\n if ((await fs.lstat(path)).isSymbolicLink) throw fsError('EOPNOTSUPP', path);\n return fs.utimes(path, atime, mtime);\n}\n\nexport function mayLink(fs: { links?(path: string): boolean }, path: string): boolean {\n return fs.links?.(path) ?? true;\n}\n\nexport function modeOption(mode: unknown): number {\n if (!Number.isInteger(mode) || (mode as number) < 0 || (mode as number) > 0o7777) {\n throw fsError('EINVAL', `not a mode: ${String(mode)}`);\n }\n return mode as number;\n}\n\nexport function fsError(code: string, path: string): Error & { code: string } {\n return Object.assign(new Error(`${code}: ${path}`), { code });\n}\n\nexport function normalizePath(path: string): string {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') parts.pop();\n else parts.push(part);\n }\n return `/${parts.join('/')}`;\n}\n\nexport function resolvePath(base: string, path: string): string {\n return normalizePath(path.startsWith('/') ? path : `${base}/${path}`);\n}\n\nexport function inodeOf(path: string): number {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n for (let i = 0; i < path.length; i++) {\n const c = path.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, 2654435761);\n h2 = Math.imul(h2 ^ c, 1597334677);\n }\n h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;\n}\n\nexport interface Redirect {\n of: string;\n to: string;\n}\n\nexport function redirected(of: string, to: string): Error {\n return Object.assign(fsError('EXDEV', `${of} leads to the mount at ${to}`), {\n redirect: { of: normalizePath(of), to: normalizePath(to) },\n });\n}\n\nexport function redirectOf(err: unknown): Redirect | undefined {\n return (err as { redirect?: Redirect } | null)?.redirect;\n}\n", "export const REPLACING_LOCK = 'slicc-kernel-replacing:v1:';\nexport const REPLACED_WAIT_MS = 150;\n\nexport interface ReplacingLocks {\n request(\n name: string,\n options: { mode: 'shared' | 'exclusive'; ifAvailable?: boolean },\n callback: (lock: unknown) => unknown\n ): Promise<unknown>;\n}\n\nexport function replacingLocks(scope: object = globalThis): ReplacingLocks | undefined {\n const locks = (scope as { navigator?: { locks?: ReplacingLocks } }).navigator?.locks;\n return typeof locks?.request === 'function' ? locks : undefined;\n}\n\nexport function replacingLock(metadata: string, root: string): string {\n return `${REPLACING_LOCK}${metadata}:${root}`;\n}\n\nexport function exclusively<T>(\n locks: ReplacingLocks,\n names: readonly string[],\n run: () => Promise<T>\n): Promise<T> {\n const [name, ...rest] = names;\n if (name === undefined) return run();\n return locks.request(name, { mode: 'exclusive' }, () =>\n exclusively(locks, rest, run)\n ) as Promise<T>;\n}\n\nfunction shared<T>(\n locks: ReplacingLocks,\n names: readonly string[],\n run: (waited: boolean) => Promise<T>,\n waited: boolean\n): Promise<T> {\n const [name, ...rest] = names;\n if (name === undefined) return run(waited);\n const next = (after: boolean) => shared(locks, rest, run, after);\n return locks.request(name, { mode: 'shared', ifAvailable: true }, (lock) =>\n lock ? next(waited) : locks.request(name, { mode: 'shared' }, () => next(true))\n ) as Promise<T>;\n}\n\nexport class PackageLocks {\n private readonly locks: ReplacingLocks | undefined;\n private readonly metadata: string;\n\n constructor(metadata: string, locks = replacingLocks()) {\n this.metadata = metadata;\n this.locks = locks;\n }\n\n loading<T>(roots: readonly string[], run: (waited: boolean) => Promise<T>): Promise<T> {\n if (!this.locks || roots.length === 0) return run(false);\n const names = roots.map((root) => replacingLock(this.metadata, root));\n return shared(this.locks, names, run, false);\n }\n\n holding(root: string): Promise<() => void> {\n const { locks } = this;\n if (!locks) return Promise.resolve(() => {});\n const { promise: held, resolve: release } = Promise.withResolvers<void>();\n return new Promise((granted, failed) => {\n locks\n .request(replacingLock(this.metadata, root), { mode: 'exclusive' }, () => {\n granted(() => release());\n return held;\n })\n .catch(failed);\n });\n }\n}\n", "import { META_DB, type MetaEntry, openMeta } from './fs/meta.ts';\nimport { dirsChannel, type FsNotice } from './fs/notice.ts';\nimport { fsError, normalizePath } from './fs/types.ts';\nimport {\n exclusively,\n REPLACED_WAIT_MS,\n replacingLock,\n replacingLocks,\n} from './kernel/replacing.ts';\n\nexport type { FsNotice };\n\nexport interface MetadataEntry {\n path: string;\n mode?: number;\n uid?: number;\n gid?: number;\n}\n\nexport interface WriteMetadataOptions {\n metadata?: string;\n indexedDB?: IDBFactory;\n}\n\nconst MAX_ID = 0xfffffffe;\n\nfunction id(value: unknown, what: string): number {\n if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > MAX_ID) {\n throw fsError('EINVAL', `not a ${what}: ${String(value)}`);\n }\n return value as number;\n}\n\nfunction checked(entry: MetadataEntry): MetadataEntry {\n if (!String(entry.path).startsWith('/'))\n throw fsError('EINVAL', `not an absolute path: ${entry.path}`);\n const path = normalizePath(String(entry.path));\n if ((entry.uid === undefined) !== (entry.gid === undefined)) {\n throw fsError('EINVAL', `${path}: give both uid and gid, or neither`);\n }\n const mode = entry.mode;\n if (mode !== undefined && (!Number.isInteger(mode) || mode < 0 || mode > 0o7777)) {\n throw fsError('EINVAL', `${path}: not a mode: ${String(mode)}`);\n }\n return {\n path,\n ...(mode !== undefined ? { mode } : {}),\n ...(entry.uid !== undefined ? { uid: id(entry.uid, 'uid'), gid: id(entry.gid, 'gid') } : {}),\n };\n}\n\nasync function present(root: FileSystemDirectoryHandle, path: string): Promise<boolean> {\n const parts = path.split('/').filter(Boolean);\n let dir = root;\n for (const [i, name] of parts.entries()) {\n const last = i === parts.length - 1;\n try {\n dir = await dir.getDirectoryHandle(name);\n } catch {\n if (!last) return false;\n return dir.getFileHandle(name).then(\n () => true,\n () => false\n );\n }\n }\n return true;\n}\n\nexport async function writeMetadata(\n root: FileSystemDirectoryHandle,\n entries: readonly MetadataEntry[],\n options: WriteMetadataOptions = {}\n): Promise<void> {\n const merged = new Map<string, MetadataEntry>();\n for (const want of entries.map(checked))\n merged.set(want.path, { ...merged.get(want.path), ...want });\n const wanted = [...merged.values()];\n for (const { path } of wanted) {\n if (!(await present(root, path))) throw fsError('ENOENT', path);\n }\n const factory = options.indexedDB ?? globalThis.indexedDB;\n const store = await openMeta(options.metadata ?? META_DB, factory);\n const ctimeMs = Date.now();\n try {\n await store.updateMany(\n wanted.map((want) => ({\n path: want.path,\n change: (entry: MetaEntry | undefined): MetaEntry => ({\n ...entry,\n path: want.path,\n ...(want.mode !== undefined ? { mode: want.mode } : {}),\n ...(want.uid !== undefined ? { uid: want.uid, gid: want.gid as number } : {}),\n ctimeMs,\n }),\n }))\n );\n } finally {\n store.close();\n }\n}\n\nexport interface PostFsNoticeOptions {\n metadata?: string;\n}\n\nfunction absolute(list: readonly string[] | undefined): string[] {\n return (list ?? []).map((path) => {\n if (!String(path).startsWith('/')) throw fsError('EINVAL', `not an absolute path: ${path}`);\n return normalizePath(String(path));\n });\n}\n\nexport function postFsNotice(notice: FsNotice, options: PostFsNoticeOptions = {}): void {\n const paths = absolute(notice.paths);\n const trees = absolute(notice.trees);\n if (paths.length === 0 && trees.length === 0) return;\n const channel = new BroadcastChannel(dirsChannel(options.metadata ?? META_DB));\n try {\n channel.postMessage({ paths, trees });\n } finally {\n channel.close();\n }\n}\n\nexport interface ReplacingOptions {\n metadata?: string;\n}\n\nconst HELD = Symbol.for('slicc-kernel.replacing.v1');\n\nfunction realmHeld(): Set<string> {\n const scope = globalThis as { [HELD]?: Set<string> };\n scope[HELD] ??= new Set();\n return scope[HELD];\n}\n\nexport async function replacing<T>(\n paths: readonly string[],\n task: () => T | Promise<T>,\n options: ReplacingOptions = {}\n): Promise<T> {\n if (!Array.isArray(paths)) throw new TypeError('replacing: paths must be an array of paths');\n if (typeof task !== 'function') throw new TypeError('replacing: task must be a function');\n const roots = [...new Set(absolute(paths))].sort();\n const metadata = options.metadata ?? META_DB;\n const held = realmHeld();\n const busy = roots.find((root) => held.has(root));\n if (busy !== undefined) {\n throw fsError('EDEADLK', `${busy} is already being replaced in this realm`);\n }\n const locks = replacingLocks();\n const run = async () => {\n try {\n return await task();\n } finally {\n postFsNotice({ trees: roots }, { metadata });\n if (locks && roots.length > 0) {\n await new Promise((resolve) => setTimeout(resolve, REPLACED_WAIT_MS));\n }\n }\n };\n for (const root of roots) held.add(root);\n try {\n if (!locks) return await run();\n const names = roots.map((root) => replacingLock(metadata, root));\n return await exclusively(locks, names, run);\n } finally {\n for (const root of roots) held.delete(root);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["parentOf", "parentOf", "parentOf"]
|
|
7
7
|
}
|
|
@@ -7513,7 +7513,7 @@ var init_version = __esm({
|
|
|
7513
7513
|
"src/version.ts"() {
|
|
7514
7514
|
"use strict";
|
|
7515
7515
|
init_captured_globals();
|
|
7516
|
-
KERNEL_VERSION = true ? "1.
|
|
7516
|
+
KERNEL_VERSION = true ? "1.173.0" : "0.0.0-dev";
|
|
7517
7517
|
OS_RELEASE = "6.0.0-slicc";
|
|
7518
7518
|
}
|
|
7519
7519
|
});
|
|
@@ -11794,6 +11794,8 @@ var init_procfs = __esm({
|
|
|
11794
11794
|
slicc_opfs_calls: (listing2) => `${listing2.opfsCalls ?? 0}
|
|
11795
11795
|
`,
|
|
11796
11796
|
slicc_opfs_ops: (listing2) => `${listing2.opfsOps ?? 0}
|
|
11797
|
+
`,
|
|
11798
|
+
slicc_meta_transactions: ({ meta }) => `${meta?.reads ?? 0} ${meta?.writes ?? 0}
|
|
11797
11799
|
`,
|
|
11798
11800
|
slicc_cwd_checks: (listing2) => `${listing2.cwdChecks ?? 0}
|
|
11799
11801
|
`,
|