@ghostlytools/cli 1.0.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.
Files changed (57) hide show
  1. package/README.md +405 -0
  2. package/SKILL.md +282 -0
  3. package/dist/assets/argon2id-088uQfnH.js +645 -0
  4. package/dist/assets/argon2id-088uQfnH.js.map +1 -0
  5. package/dist/assets/bark_ffi_wasm_bg-Bxru_BVW.wasm +0 -0
  6. package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js +6 -0
  7. package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -0
  8. package/dist/assets/bitcoindevkit_bg-B-iLWrmX.js +6 -0
  9. package/dist/assets/bitcoindevkit_bg-B-iLWrmX.js.map +1 -0
  10. package/dist/assets/bitcoindevkit_bg-CRkZTSbO.wasm +0 -0
  11. package/dist/assets/breez_sdk_spark_wasm_bg.wasm +0 -0
  12. package/dist/assets/endpoint-h3cqRyRz.js +185 -0
  13. package/dist/assets/endpoint-h3cqRyRz.js.map +1 -0
  14. package/dist/assets/fedimintWorker.mjs +95 -0
  15. package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js +6 -0
  16. package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js.map +1 -0
  17. package/dist/assets/fedimint_client_wasm_bg-DeFtkIv6.wasm +0 -0
  18. package/dist/assets/fileBytes-ByS16quP.js +154 -0
  19. package/dist/assets/fileBytes-ByS16quP.js.map +1 -0
  20. package/dist/assets/fileBytesIdb-COzoilo9.js +230 -0
  21. package/dist/assets/fileBytesIdb-COzoilo9.js.map +1 -0
  22. package/dist/assets/fileBytesOpfs-B27wAMUh.js +145 -0
  23. package/dist/assets/fileBytesOpfs-B27wAMUh.js.map +1 -0
  24. package/dist/assets/ghostly_iroh_web-CPa_YEfb.js +1154 -0
  25. package/dist/assets/ghostly_iroh_web-CPa_YEfb.js.map +1 -0
  26. package/dist/assets/ghostly_iroh_web_bg.wasm +0 -0
  27. package/dist/assets/hyperdhtRelay-BKsFpPjr.js +342 -0
  28. package/dist/assets/hyperdhtRelay-BKsFpPjr.js.map +1 -0
  29. package/dist/assets/legacy_ciphers-JJOu0JXL.js +5185 -0
  30. package/dist/assets/legacy_ciphers-JJOu0JXL.js.map +1 -0
  31. package/dist/assets/mainline-DOncVbJN.js +176 -0
  32. package/dist/assets/mainline-DOncVbJN.js.map +1 -0
  33. package/dist/assets/nacl-fast-CDhNCYHs.js +1512 -0
  34. package/dist/assets/nacl-fast-CDhNCYHs.js.map +1 -0
  35. package/dist/assets/noble_curves-DDWn5AH0.js +2978 -0
  36. package/dist/assets/noble_curves-DDWn5AH0.js.map +1 -0
  37. package/dist/assets/noble_hashes-B7AZyFyS.js +427 -0
  38. package/dist/assets/noble_hashes-B7AZyFyS.js.map +1 -0
  39. package/dist/assets/openpgp-BBFr-zHQ.js +16573 -0
  40. package/dist/assets/openpgp-BBFr-zHQ.js.map +1 -0
  41. package/dist/assets/server-5T5l8hfy.js +28293 -0
  42. package/dist/assets/server-5T5l8hfy.js.map +1 -0
  43. package/dist/assets/sha512-BYId-G-T.js +1034 -0
  44. package/dist/assets/sha512-BYId-G-T.js.map +1 -0
  45. package/dist/assets/src-DptDr2et.js +20971 -0
  46. package/dist/assets/src-DptDr2et.js.map +1 -0
  47. package/dist/assets/storage-Bya5b2Xt.js +1648 -0
  48. package/dist/assets/storage-Bya5b2Xt.js.map +1 -0
  49. package/dist/assets/tree-store-N362nuzZ.js +1031 -0
  50. package/dist/assets/tree-store-N362nuzZ.js.map +1 -0
  51. package/dist/assets/unbzip2-stream-B1C-JX9L.js +681 -0
  52. package/dist/assets/unbzip2-stream-B1C-JX9L.js.map +1 -0
  53. package/dist/assets/web-OUQl4Q7L.js +3802 -0
  54. package/dist/assets/web-OUQl4Q7L.js.map +1 -0
  55. package/dist/ghostly.mjs +17087 -0
  56. package/dist/ghostly.mjs.map +1 -0
  57. package/package.json +76 -0
@@ -0,0 +1,230 @@
1
+ import { Ot as wrap, Tt as openDb, bt as digestText, mt as checkFileId, xt as STORES, yt as FILE_BYTES_STEP } from "../ghostly.mjs";
2
+ import { sha256 } from "@noble/hashes/sha2.js";
3
+ //#region ../browser/src/shared/fileBytesIdb.ts
4
+ var STEP = FILE_BYTES_STEP;
5
+ async function chunks(mode) {
6
+ return (await openDb()).transaction(STORES.fileChunks, mode).objectStore(STORES.fileChunks);
7
+ }
8
+ var range = (id) => IDBKeyRange.bound([id, 0], [id, Infinity]);
9
+ /**
10
+ * Files in IndexedDB, in 1 MiB pieces stored as Blobs (which browsers keep on disk), for platforms without
11
+ * the origin-private file system. Reading one hands out a Blob made of the pieces, so a download never
12
+ * loads the file into memory either.
13
+ */
14
+ var IdbFileBytes = class {
15
+ kind = "idb";
16
+ tails = /* @__PURE__ */ new Map();
17
+ /** Writes to one file run one after another. */
18
+ queues = /* @__PURE__ */ new Map();
19
+ serial(id, work) {
20
+ const run = (this.queues.get(id) ?? Promise.resolve()).then(work, work);
21
+ const settled = run.catch(() => {});
22
+ this.queues.set(id, settled);
23
+ settled.then(() => {
24
+ if (this.queues.get(id) === settled) this.queues.delete(id);
25
+ });
26
+ return run;
27
+ }
28
+ async list(id) {
29
+ const store = await chunks("readonly");
30
+ const keys = await wrap(store.getAllKeys(range(id)));
31
+ if (!keys.length) return [];
32
+ const last = await wrap(store.get(keys[keys.length - 1]));
33
+ return keys.map(([, index], i) => ({
34
+ id,
35
+ index,
36
+ length: i === keys.length - 1 ? last.length : STEP
37
+ }));
38
+ }
39
+ async put(chunk) {
40
+ await wrap((await chunks("readwrite")).put(chunk));
41
+ }
42
+ /** The piece being filled, loaded from storage the first time a file is written. */
43
+ async tail(id) {
44
+ let tail = this.tails.get(id);
45
+ if (tail) return tail;
46
+ const pieces = await this.list(id);
47
+ const last = pieces[pieces.length - 1];
48
+ tail = {
49
+ index: 0,
50
+ bytes: new Uint8Array(STEP),
51
+ length: 0,
52
+ dirty: false
53
+ };
54
+ if (last && last.length < STEP) {
55
+ const stored = await wrap((await chunks("readonly")).get([id, last.index]));
56
+ tail.index = last.index;
57
+ tail.bytes.set(new Uint8Array(await stored.data.arrayBuffer()));
58
+ tail.length = last.length;
59
+ } else if (last) tail.index = last.index + 1;
60
+ this.tails.set(id, tail);
61
+ return tail;
62
+ }
63
+ async sizeNow(id) {
64
+ const tail = this.tails.get(id);
65
+ if (tail) return tail.index * STEP + tail.length;
66
+ const pieces = await this.list(id);
67
+ if (!pieces.length) return null;
68
+ return (pieces.length - 1) * STEP + pieces[pieces.length - 1].length;
69
+ }
70
+ async flushNow(id) {
71
+ const tail = this.tails.get(id);
72
+ if (!tail?.dirty) return;
73
+ await this.put({
74
+ id,
75
+ index: tail.index,
76
+ length: tail.length,
77
+ data: new Blob([tail.bytes.slice(0, tail.length)])
78
+ });
79
+ tail.dirty = false;
80
+ }
81
+ async stage(id, source, onProgress) {
82
+ checkFileId(id);
83
+ await this.remove(id);
84
+ const hash = sha256.create();
85
+ let offset = 0;
86
+ const reader = source.stream().getReader();
87
+ try {
88
+ for (;;) {
89
+ const { done, value } = await reader.read();
90
+ if (done) break;
91
+ hash.update(value);
92
+ await this.append(id, offset, value);
93
+ offset += value.length;
94
+ onProgress?.(offset);
95
+ }
96
+ await this.close(id);
97
+ } catch (error) {
98
+ await reader.cancel().catch(() => {});
99
+ await this.remove(id).catch(() => {});
100
+ throw error;
101
+ }
102
+ return digestText(hash.digest());
103
+ }
104
+ append(id, offset, bytes) {
105
+ checkFileId(id);
106
+ return this.serial(id, async () => {
107
+ const tail = await this.tail(id);
108
+ if (offset !== tail.index * STEP + tail.length) throw new Error("File write out of order");
109
+ let pos = 0;
110
+ while (pos < bytes.length) {
111
+ const take = Math.min(STEP - tail.length, bytes.length - pos);
112
+ tail.bytes.set(bytes.subarray(pos, pos + take), tail.length);
113
+ tail.length += take;
114
+ pos += take;
115
+ tail.dirty = true;
116
+ if (tail.length === STEP) {
117
+ await this.flushNow(id);
118
+ tail.index += 1;
119
+ tail.length = 0;
120
+ }
121
+ }
122
+ });
123
+ }
124
+ flush(id) {
125
+ return this.serial(id, () => this.flushNow(id));
126
+ }
127
+ close(id) {
128
+ return this.serial(id, async () => {
129
+ await this.flushNow(id);
130
+ this.tails.delete(id);
131
+ });
132
+ }
133
+ size(id) {
134
+ checkFileId(id);
135
+ return this.serial(id, () => this.sizeNow(id));
136
+ }
137
+ truncate(id, size) {
138
+ checkFileId(id);
139
+ return this.serial(id, async () => {
140
+ await this.flushNow(id);
141
+ this.tails.delete(id);
142
+ const pieces = await this.list(id);
143
+ const keep = Math.floor(size / STEP), rest = size % STEP;
144
+ const store = await chunks("readwrite");
145
+ await Promise.all(pieces.filter((piece) => piece.index > keep || piece.index === keep && rest === 0).map((piece) => wrap(store.delete([id, piece.index]))));
146
+ const cut = pieces.find((piece) => piece.index === keep);
147
+ if (cut && rest > 0 && cut.length > rest) {
148
+ const stored = await wrap((await chunks("readonly")).get([id, keep]));
149
+ await this.put({
150
+ id,
151
+ index: keep,
152
+ length: rest,
153
+ data: stored.data.slice(0, rest)
154
+ });
155
+ }
156
+ });
157
+ }
158
+ read(id, offset, length) {
159
+ checkFileId(id);
160
+ return this.serial(id, async () => {
161
+ await this.flushNow(id);
162
+ const out = [];
163
+ const store = await chunks("readonly");
164
+ const end = offset + length;
165
+ for (let index = Math.floor(offset / STEP); index * STEP < end; index++) {
166
+ const piece = await wrap(store.get([id, index]));
167
+ if (!piece) break;
168
+ const from = Math.max(0, offset - index * STEP), to = Math.min(piece.length, end - index * STEP);
169
+ if (from < to) out.push(new Uint8Array(await piece.data.slice(from, to).arrayBuffer()));
170
+ if (piece.length < STEP) break;
171
+ }
172
+ if (out.length === 1) return out[0];
173
+ const joined = new Uint8Array(out.reduce((n, part) => n + part.length, 0));
174
+ let pos = 0;
175
+ for (const part of out) {
176
+ joined.set(part, pos);
177
+ pos += part.length;
178
+ }
179
+ return joined;
180
+ });
181
+ }
182
+ async digest(id) {
183
+ const hash = sha256.create();
184
+ for await (const part of this.pieces(id)) hash.update(new Uint8Array(await part.arrayBuffer()));
185
+ return digestText(hash.digest());
186
+ }
187
+ async *pieces(id) {
188
+ checkFileId(id);
189
+ await this.flush(id);
190
+ const pieces = await this.list(id);
191
+ for (const piece of pieces) {
192
+ const stored = await wrap((await chunks("readonly")).get([id, piece.index]));
193
+ if (stored) yield stored.data;
194
+ }
195
+ }
196
+ async blob(id, type) {
197
+ const parts = [];
198
+ for await (const part of this.pieces(id)) parts.push(part);
199
+ return parts.length ? new Blob(parts, { type }) : await this.size(id) === 0 ? new Blob([], { type }) : null;
200
+ }
201
+ remove(id) {
202
+ checkFileId(id);
203
+ return this.serial(id, async () => {
204
+ this.tails.delete(id);
205
+ await wrap((await chunks("readwrite")).delete(range(id)));
206
+ });
207
+ }
208
+ async removeWhere(prefix) {
209
+ for (const id of [...this.tails.keys()]) if (id.startsWith(prefix)) this.tails.delete(id);
210
+ const store = await chunks("readwrite");
211
+ await wrap(prefix ? store.delete(IDBKeyRange.bound([prefix, 0], [`${prefix}￿`, Infinity])) : store.clear());
212
+ }
213
+ async room() {
214
+ return storageRoom();
215
+ }
216
+ };
217
+ /** What the browser still lets this origin store, or null when it does not say. */
218
+ async function storageRoom() {
219
+ try {
220
+ const estimate = await navigator.storage?.estimate?.();
221
+ if (!estimate?.quota) return null;
222
+ return Math.max(0, estimate.quota - (estimate.usage ?? 0));
223
+ } catch {
224
+ return null;
225
+ }
226
+ }
227
+ //#endregion
228
+ export { IdbFileBytes, storageRoom };
229
+
230
+ //# sourceMappingURL=fileBytesIdb-COzoilo9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileBytesIdb-COzoilo9.js","names":[],"sources":["../../../browser/src/shared/fileBytesIdb.ts"],"sourcesContent":["import { sha256 } from \"@noble/hashes/sha2.js\";\nimport { STORES, openDb, wrap } from \"./idb\";\nimport { FILE_BYTES_STEP, checkFileId, digestText, type FileBytes } from \"./fileBytes\";\n\n/** One piece of a file. Every piece but the last is exactly `FILE_BYTES_STEP` long. */\ninterface Chunk { id: string; index: number; length: number; data: Blob }\n\n/** The piece being filled, kept in memory until it is full or flushed: at most one step per open file. */\ninterface Tail { index: number; bytes: Uint8Array; length: number; dirty: boolean }\n\nconst STEP = FILE_BYTES_STEP;\n\nasync function chunks(mode: IDBTransactionMode): Promise<IDBObjectStore> {\n return (await openDb()).transaction(STORES.fileChunks, mode).objectStore(STORES.fileChunks);\n}\nconst range = (id: string) => IDBKeyRange.bound([id, 0], [id, Infinity]);\n\n/**\n * Files in IndexedDB, in 1 MiB pieces stored as Blobs (which browsers keep on disk), for platforms without\n * the origin-private file system. Reading one hands out a Blob made of the pieces, so a download never\n * loads the file into memory either.\n */\nexport class IdbFileBytes implements FileBytes {\n readonly kind = \"idb\" as const;\n private readonly tails = new Map<string, Tail>();\n /** Writes to one file run one after another. */\n private readonly queues = new Map<string, Promise<unknown>>();\n\n private serial<T>(id: string, work: () => Promise<T>): Promise<T> {\n const run = (this.queues.get(id) ?? Promise.resolve()).then(work, work);\n const settled = run.catch(() => {});\n this.queues.set(id, settled);\n void settled.then(() => { if (this.queues.get(id) === settled) this.queues.delete(id); });\n return run;\n }\n\n private async list(id: string): Promise<Omit<Chunk, \"data\">[]> {\n const store = await chunks(\"readonly\");\n const keys = (await wrap(store.getAllKeys(range(id)))) as [string, number][];\n if (!keys.length) return [];\n const last = (await wrap(store.get(keys[keys.length - 1]))) as Chunk;\n return keys.map(([, index], i) => ({ id, index, length: i === keys.length - 1 ? last.length : STEP }));\n }\n\n private async put(chunk: Chunk): Promise<void> {\n await wrap((await chunks(\"readwrite\")).put(chunk));\n }\n\n /** The piece being filled, loaded from storage the first time a file is written. */\n private async tail(id: string): Promise<Tail> {\n let tail = this.tails.get(id);\n if (tail) return tail;\n const pieces = await this.list(id);\n const last = pieces[pieces.length - 1];\n tail = { index: 0, bytes: new Uint8Array(STEP), length: 0, dirty: false };\n if (last && last.length < STEP) {\n const stored = (await wrap((await chunks(\"readonly\")).get([id, last.index]))) as Chunk;\n tail.index = last.index;\n tail.bytes.set(new Uint8Array(await stored.data.arrayBuffer()));\n tail.length = last.length;\n } else if (last) tail.index = last.index + 1;\n this.tails.set(id, tail);\n return tail;\n }\n\n private async sizeNow(id: string): Promise<number | null> {\n const tail = this.tails.get(id);\n if (tail) return tail.index * STEP + tail.length;\n const pieces = await this.list(id);\n if (!pieces.length) return null;\n return (pieces.length - 1) * STEP + pieces[pieces.length - 1].length;\n }\n\n private async flushNow(id: string): Promise<void> {\n const tail = this.tails.get(id);\n if (!tail?.dirty) return;\n await this.put({ id, index: tail.index, length: tail.length, data: new Blob([tail.bytes.slice(0, tail.length)]) });\n tail.dirty = false;\n }\n\n async stage(id: string, source: Blob, onProgress?: (copied: number) => void): Promise<string> {\n checkFileId(id);\n await this.remove(id);\n const hash = sha256.create();\n let offset = 0;\n const reader = source.stream().getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n hash.update(value);\n await this.append(id, offset, value);\n offset += value.length;\n onProgress?.(offset);\n }\n await this.close(id);\n } catch (error) {\n await reader.cancel().catch(() => {});\n await this.remove(id).catch(() => {});\n throw error;\n }\n return digestText(hash.digest());\n }\n\n append(id: string, offset: number, bytes: Uint8Array): Promise<void> {\n checkFileId(id);\n return this.serial(id, async () => {\n const tail = await this.tail(id);\n if (offset !== tail.index * STEP + tail.length) throw new Error(\"File write out of order\");\n let pos = 0;\n while (pos < bytes.length) {\n const take = Math.min(STEP - tail.length, bytes.length - pos);\n tail.bytes.set(bytes.subarray(pos, pos + take), tail.length);\n tail.length += take; pos += take; tail.dirty = true;\n if (tail.length === STEP) {\n await this.flushNow(id);\n tail.index += 1; tail.length = 0;\n }\n }\n });\n }\n\n flush(id: string): Promise<void> {\n return this.serial(id, () => this.flushNow(id));\n }\n\n close(id: string): Promise<void> {\n return this.serial(id, async () => { await this.flushNow(id); this.tails.delete(id); });\n }\n\n size(id: string): Promise<number | null> {\n checkFileId(id);\n return this.serial(id, () => this.sizeNow(id));\n }\n\n truncate(id: string, size: number): Promise<void> {\n checkFileId(id);\n return this.serial(id, async () => {\n await this.flushNow(id);\n this.tails.delete(id);\n const pieces = await this.list(id);\n const keep = Math.floor(size / STEP), rest = size % STEP;\n const store = await chunks(\"readwrite\");\n await Promise.all(pieces.filter((piece) => piece.index > keep || (piece.index === keep && rest === 0))\n .map((piece) => wrap(store.delete([id, piece.index]))));\n const cut = pieces.find((piece) => piece.index === keep);\n if (cut && rest > 0 && cut.length > rest) {\n const stored = (await wrap((await chunks(\"readonly\")).get([id, keep]))) as Chunk;\n await this.put({ id, index: keep, length: rest, data: stored.data.slice(0, rest) });\n }\n });\n }\n\n read(id: string, offset: number, length: number): Promise<Uint8Array> {\n checkFileId(id);\n return this.serial(id, async () => {\n await this.flushNow(id);\n const out: Uint8Array[] = [];\n const store = await chunks(\"readonly\");\n const end = offset + length;\n for (let index = Math.floor(offset / STEP); index * STEP < end; index++) {\n const piece = (await wrap(store.get([id, index]))) as Chunk | undefined;\n if (!piece) break;\n const from = Math.max(0, offset - index * STEP), to = Math.min(piece.length, end - index * STEP);\n if (from < to) out.push(new Uint8Array(await piece.data.slice(from, to).arrayBuffer()));\n if (piece.length < STEP) break;\n }\n if (out.length === 1) return out[0];\n const joined = new Uint8Array(out.reduce((n, part) => n + part.length, 0));\n let pos = 0;\n for (const part of out) { joined.set(part, pos); pos += part.length; }\n return joined;\n });\n }\n\n async digest(id: string): Promise<string> {\n const hash = sha256.create();\n for await (const part of this.pieces(id)) hash.update(new Uint8Array(await part.arrayBuffer()));\n return digestText(hash.digest());\n }\n\n private async *pieces(id: string): AsyncGenerator<Blob> {\n checkFileId(id);\n await this.flush(id);\n const pieces = await this.list(id);\n for (const piece of pieces) {\n const stored = (await wrap((await chunks(\"readonly\")).get([id, piece.index]))) as Chunk | undefined;\n if (stored) yield stored.data;\n }\n }\n\n async blob(id: string, type: string): Promise<Blob | null> {\n const parts: Blob[] = [];\n for await (const part of this.pieces(id)) parts.push(part);\n return parts.length ? new Blob(parts, { type }) : (await this.size(id)) === 0 ? new Blob([], { type }) : null;\n }\n\n remove(id: string): Promise<void> {\n checkFileId(id);\n return this.serial(id, async () => {\n this.tails.delete(id);\n await wrap((await chunks(\"readwrite\")).delete(range(id)));\n });\n }\n\n async removeWhere(prefix: string): Promise<void> {\n for (const id of [...this.tails.keys()]) if (id.startsWith(prefix)) this.tails.delete(id);\n const store = await chunks(\"readwrite\");\n await wrap(prefix ? store.delete(IDBKeyRange.bound([prefix, 0], [`${prefix}￿`, Infinity])) : store.clear());\n }\n\n async room(): Promise<number | null> {\n return storageRoom();\n }\n}\n\n/** What the browser still lets this origin store, or null when it does not say. */\nexport async function storageRoom(): Promise<number | null> {\n try {\n const estimate = await navigator.storage?.estimate?.();\n if (!estimate?.quota) return null;\n return Math.max(0, estimate.quota - (estimate.usage ?? 0));\n } catch { return null; }\n}\n"],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ import { _t as fileSpace, mt as checkFileId, yt as FILE_BYTES_STEP } from "../ghostly.mjs";
2
+ import { storageRoom } from "./fileBytesIdb-COzoilo9.js";
3
+ //#region ../browser/src/shared/fileBytesOpfs.ts
4
+ /**
5
+ * Files in the origin-private file system, written by `fileBytesWorker.ts`. Every page and the peer of one
6
+ * profile see the same folder; a file is written by one of them at a time (the page copies a file it sends,
7
+ * the peer writes one it receives), and read as a Blob only once it is closed.
8
+ */
9
+ var OpfsFileBytes = class OpfsFileBytes {
10
+ worker;
11
+ kind = "opfs";
12
+ next = 1;
13
+ waiting = /* @__PURE__ */ new Map();
14
+ constructor(worker) {
15
+ this.worker = worker;
16
+ worker.onmessage = (event) => {
17
+ const reply = event.data, pending = this.waiting.get(reply.n);
18
+ if (!pending) return;
19
+ if ("progress" in reply) return pending.progress?.(reply.progress);
20
+ this.waiting.delete(reply.n);
21
+ if (reply.ok) pending.resolve(reply.value);
22
+ else pending.reject(new Error(reply.error));
23
+ };
24
+ worker.onerror = (event) => {
25
+ event.preventDefault();
26
+ for (const pending of this.waiting.values()) pending.reject(/* @__PURE__ */ new Error(`File storage stopped: ${event.message || "unknown error"}`));
27
+ this.waiting.clear();
28
+ };
29
+ }
30
+ /** The worker, if this browser can run it and gives it sync access handles; null otherwise. */
31
+ static async open() {
32
+ if (typeof Worker === "undefined" || typeof navigator === "undefined" || !navigator.storage?.getDirectory) return null;
33
+ const store = new OpfsFileBytes(new Worker(new URL("./fileBytesWorker.ts", import.meta.url), { type: "module" }));
34
+ try {
35
+ if (await store.call({ op: "probe" })) return store;
36
+ } catch {}
37
+ store.worker.terminate();
38
+ return null;
39
+ }
40
+ call(request, transfer = [], progress) {
41
+ const n = this.next++;
42
+ return new Promise((resolve, reject) => {
43
+ this.waiting.set(n, {
44
+ resolve,
45
+ reject,
46
+ progress
47
+ });
48
+ this.worker.postMessage({
49
+ ...request,
50
+ n,
51
+ space: fileSpace()
52
+ }, transfer);
53
+ });
54
+ }
55
+ stage(id, source, onProgress) {
56
+ return this.call({
57
+ op: "stage",
58
+ id: checkFileId(id),
59
+ source
60
+ }, [], onProgress);
61
+ }
62
+ append(id, offset, bytes) {
63
+ const copy = bytes.slice();
64
+ return this.call({
65
+ op: "append",
66
+ id: checkFileId(id),
67
+ offset,
68
+ bytes: copy
69
+ }, [copy.buffer]);
70
+ }
71
+ flush(id) {
72
+ return this.call({
73
+ op: "flush",
74
+ id: checkFileId(id)
75
+ });
76
+ }
77
+ close(id) {
78
+ return this.call({
79
+ op: "close",
80
+ id: checkFileId(id)
81
+ });
82
+ }
83
+ size(id) {
84
+ return this.call({
85
+ op: "size",
86
+ id: checkFileId(id)
87
+ });
88
+ }
89
+ truncate(id, size) {
90
+ return this.call({
91
+ op: "truncate",
92
+ id: checkFileId(id),
93
+ size
94
+ });
95
+ }
96
+ read(id, offset, length) {
97
+ return this.call({
98
+ op: "read",
99
+ id: checkFileId(id),
100
+ offset,
101
+ length: Math.min(length, 16 * FILE_BYTES_STEP)
102
+ });
103
+ }
104
+ digest(id) {
105
+ return this.call({
106
+ op: "digest",
107
+ id: checkFileId(id)
108
+ });
109
+ }
110
+ remove(id) {
111
+ return this.call({
112
+ op: "remove",
113
+ id: checkFileId(id)
114
+ });
115
+ }
116
+ removeWhere(prefix) {
117
+ return this.call({
118
+ op: "removeWhere",
119
+ prefix
120
+ });
121
+ }
122
+ async blob(id, type) {
123
+ await this.close(id);
124
+ try {
125
+ const file = await (await (await (await (await navigator.storage.getDirectory()).getDirectoryHandle("ghostly-files")).getDirectoryHandle(fileSpace())).getFileHandle(checkFileId(id))).getFile();
126
+ return file.slice(0, file.size, type);
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+ room() {
132
+ return storageRoom();
133
+ }
134
+ async dropSpace(space) {
135
+ try {
136
+ await (await (await navigator.storage.getDirectory()).getDirectoryHandle("ghostly-files")).removeEntry(space, { recursive: true });
137
+ } catch (error) {
138
+ if (error?.name !== "NotFoundError") throw error;
139
+ }
140
+ }
141
+ };
142
+ //#endregion
143
+ export { OpfsFileBytes };
144
+
145
+ //# sourceMappingURL=fileBytesOpfs-B27wAMUh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileBytesOpfs-B27wAMUh.js","names":[],"sources":["../../../browser/src/shared/fileBytesOpfs.ts"],"sourcesContent":["import { FILE_BYTES_STEP, checkFileId, fileSpace, type FileBytes } from \"./fileBytes\";\nimport { storageRoom } from \"./fileBytesIdb\";\nimport type { WorkerReply, WorkerRequest } from \"./fileBytesWorker\";\n\ntype Request = WorkerRequest extends infer R ? R extends unknown ? Omit<R, \"n\" | \"space\"> : never : never;\n\n/**\n * Files in the origin-private file system, written by `fileBytesWorker.ts`. Every page and the peer of one\n * profile see the same folder; a file is written by one of them at a time (the page copies a file it sends,\n * the peer writes one it receives), and read as a Blob only once it is closed.\n */\nexport class OpfsFileBytes implements FileBytes {\n readonly kind = \"opfs\" as const;\n private next = 1;\n private readonly waiting = new Map<number, { resolve(value: unknown): void; reject(error: Error): void; progress?(n: number): void }>();\n\n private constructor(private readonly worker: Worker) {\n worker.onmessage = (event: MessageEvent<WorkerReply>) => {\n const reply = event.data, pending = this.waiting.get(reply.n);\n if (!pending) return;\n if (\"progress\" in reply) return pending.progress?.(reply.progress);\n this.waiting.delete(reply.n);\n if (reply.ok) pending.resolve(reply.value); else pending.reject(new Error(reply.error));\n };\n worker.onerror = (event) => {\n event.preventDefault();\n for (const pending of this.waiting.values()) pending.reject(new Error(`File storage stopped: ${event.message || \"unknown error\"}`));\n this.waiting.clear();\n };\n }\n\n /** The worker, if this browser can run it and gives it sync access handles; null otherwise. */\n static async open(): Promise<OpfsFileBytes | null> {\n if (typeof Worker === \"undefined\" || typeof navigator === \"undefined\" || !navigator.storage?.getDirectory) return null;\n const store = new OpfsFileBytes(new Worker(new URL(\"./fileBytesWorker.ts\", import.meta.url), { type: \"module\" }));\n try {\n if (await store.call<boolean>({ op: \"probe\" })) return store;\n } catch { /* no OPFS here (a private window, an old engine) */ }\n store.worker.terminate();\n return null;\n }\n\n private call<T>(request: Request, transfer: Transferable[] = [], progress?: (n: number) => void): Promise<T> {\n const n = this.next++;\n return new Promise<T>((resolve, reject) => {\n this.waiting.set(n, { resolve: resolve as (value: unknown) => void, reject, progress });\n this.worker.postMessage({ ...request, n, space: fileSpace() } as WorkerRequest, transfer);\n });\n }\n\n stage(id: string, source: Blob, onProgress?: (copied: number) => void): Promise<string> {\n return this.call({ op: \"stage\", id: checkFileId(id), source }, [], onProgress);\n }\n append(id: string, offset: number, bytes: Uint8Array): Promise<void> {\n // A copy goes to the worker: the caller's buffer may be a view into something it still uses.\n const copy = bytes.slice();\n return this.call({ op: \"append\", id: checkFileId(id), offset, bytes: copy }, [copy.buffer]);\n }\n flush(id: string): Promise<void> { return this.call({ op: \"flush\", id: checkFileId(id) }); }\n close(id: string): Promise<void> { return this.call({ op: \"close\", id: checkFileId(id) }); }\n size(id: string): Promise<number | null> { return this.call({ op: \"size\", id: checkFileId(id) }); }\n truncate(id: string, size: number): Promise<void> { return this.call({ op: \"truncate\", id: checkFileId(id), size }); }\n read(id: string, offset: number, length: number): Promise<Uint8Array> {\n return this.call({ op: \"read\", id: checkFileId(id), offset, length: Math.min(length, 16 * FILE_BYTES_STEP) });\n }\n digest(id: string): Promise<string> { return this.call({ op: \"digest\", id: checkFileId(id) }); }\n remove(id: string): Promise<void> { return this.call({ op: \"remove\", id: checkFileId(id) }); }\n removeWhere(prefix: string): Promise<void> { return this.call({ op: \"removeWhere\", prefix }); }\n\n async blob(id: string, type: string): Promise<Blob | null> {\n // Closed first: a file with a sync access handle open cannot be read as a Blob.\n await this.close(id);\n try {\n const root = await (await navigator.storage.getDirectory()).getDirectoryHandle(\"ghostly-files\");\n const file = await (await (await root.getDirectoryHandle(fileSpace())).getFileHandle(checkFileId(id))).getFile();\n // A slice with a type: still the file on disk, never read into memory.\n return file.slice(0, file.size, type);\n } catch { return null; }\n }\n\n room(): Promise<number | null> { return storageRoom(); }\n\n async dropSpace(space: string): Promise<void> {\n try {\n const root = await (await navigator.storage.getDirectory()).getDirectoryHandle(\"ghostly-files\");\n await root.removeEntry(space, { recursive: true });\n } catch (error) { if ((error as { name?: string })?.name !== \"NotFoundError\") throw error; }\n }\n}\n"],"mappings":"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"}