opfs-worker 1.3.1 → 2.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.
- package/README.md +89 -106
- package/dist/{facade.d.ts → OPFSFacade.d.ts} +26 -9
- package/dist/OPFSFacade.d.ts.map +1 -0
- package/dist/{worker.d.ts → OPFSWorker.d.ts} +11 -11
- package/dist/OPFSWorker.d.ts.map +1 -0
- package/dist/assets/worker.entry-DUlEoroc.js.map +1 -0
- package/dist/createOPFSWorker.d.ts +17 -0
- package/dist/createOPFSWorker.d.ts.map +1 -0
- package/dist/helpers-DNj8ZoMu.cjs +4 -0
- package/dist/helpers-DNj8ZoMu.cjs.map +1 -0
- package/dist/{helpers-CKOebsbw.js → helpers-WY2jfbOT.js} +257 -253
- package/dist/helpers-WY2jfbOT.js.map +1 -0
- package/dist/index.cjs +349 -329
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +428 -382
- package/dist/index.js.map +1 -1
- package/dist/index.pure.cjs +2 -0
- package/dist/index.pure.cjs.map +1 -0
- package/dist/index.pure.d.ts +6 -0
- package/dist/index.pure.d.ts.map +1 -0
- package/dist/{raw.js → index.pure.js} +248 -188
- package/dist/index.pure.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/errors.d.ts +14 -6
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts +15 -3
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/worker.entry.d.ts +2 -0
- package/dist/worker.entry.d.ts.map +1 -0
- package/docs/api-reference.md +815 -0
- package/docs/file-descriptors.md +696 -0
- package/docs/types.md +232 -0
- package/package.json +15 -9
- package/src/OPFSFacade.ts +460 -0
- package/src/OPFSWorker.ts +1544 -0
- package/src/createOPFSWorker.ts +57 -0
- package/src/index.pure.ts +7 -0
- package/src/index.ts +15 -0
- package/src/types.ts +99 -0
- package/src/utils/encoder.ts +205 -0
- package/src/utils/errors.ts +297 -0
- package/src/utils/helpers.ts +465 -0
- package/src/worker.entry.ts +6 -0
- package/dist/assets/worker-1Wh1cr7P.js.map +0 -1
- package/dist/assets/worker-BeJaVyBV.js.map +0 -1
- package/dist/facade.d.ts.map +0 -1
- package/dist/helpers-BuGfPAg0.js +0 -1439
- package/dist/helpers-BuGfPAg0.js.map +0 -1
- package/dist/helpers-CF7A2WQG.cjs +0 -4
- package/dist/helpers-CF7A2WQG.cjs.map +0 -1
- package/dist/helpers-CIiblZ8d.cjs +0 -4
- package/dist/helpers-CIiblZ8d.cjs.map +0 -1
- package/dist/helpers-CKOebsbw.js.map +0 -1
- package/dist/raw.cjs +0 -2
- package/dist/raw.cjs.map +0 -1
- package/dist/raw.d.ts +0 -13
- package/dist/raw.d.ts.map +0 -1
- package/dist/raw.js.map +0 -1
- package/dist/worker.d.ts.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { V as C, t as g, l as O, h as P, q as p, s as D, P as z, w as u, O as w, m as h, W as l, n as k, j as F, o as v, p as E, z as M, E as S, D as T, G as $, v as b, A as H, c as B, g as N, r as _, L as R, J as A, H as I, K as L, k as m, C as U } from "./helpers-WY2jfbOT.js";
|
|
2
|
+
import { M as K, F as X, I as Y, a as Q, f as Z, b as tt, S as et, B as at, y as rt, d as it, e as st, x as nt, i as ot, u as ct } from "./helpers-WY2jfbOT.js";
|
|
3
|
+
import { transfer as x } from "comlink";
|
|
4
|
+
class V {
|
|
4
5
|
/** Root directory handle for the file system */
|
|
5
6
|
root;
|
|
6
7
|
/** Map of watched paths and options */
|
|
@@ -17,6 +18,8 @@ class j {
|
|
|
17
18
|
hashAlgorithm: "etag",
|
|
18
19
|
broadcastChannel: "opfs-worker"
|
|
19
20
|
};
|
|
21
|
+
/** Shared sync handles per path (OPFS allows only one handle per file) */
|
|
22
|
+
openHandles = /* @__PURE__ */ new Map();
|
|
20
23
|
/** Map of open file descriptors to their metadata */
|
|
21
24
|
openFiles = /* @__PURE__ */ new Map();
|
|
22
25
|
/** Next available file descriptor number */
|
|
@@ -28,7 +31,7 @@ class j {
|
|
|
28
31
|
_getFileDescriptor(t) {
|
|
29
32
|
const e = this.openFiles.get(t);
|
|
30
33
|
if (!e)
|
|
31
|
-
throw new
|
|
34
|
+
throw new C("descriptor", `Invalid file descriptor: ${t}`);
|
|
32
35
|
return e;
|
|
33
36
|
}
|
|
34
37
|
/**
|
|
@@ -37,36 +40,35 @@ class j {
|
|
|
37
40
|
* This method is called by internal operations to notify clients about
|
|
38
41
|
* changes, even when no specific paths are being watched.
|
|
39
42
|
*
|
|
40
|
-
* @param
|
|
41
|
-
* @param type - The type of change (create, change, delete)
|
|
43
|
+
* @param event - The event describing the change
|
|
42
44
|
*/
|
|
43
45
|
async notifyChange(t) {
|
|
44
46
|
if (!this.options.broadcastChannel)
|
|
45
47
|
return;
|
|
46
48
|
const e = t.path;
|
|
47
|
-
if (![...this.watchers.values()].some((
|
|
49
|
+
if (![...this.watchers.values()].some((i) => g(e, i.pattern) && i.include.some((s) => s && g(e, s)) && !i.exclude.some((s) => s && g(e, s))))
|
|
48
50
|
return;
|
|
49
|
-
let
|
|
51
|
+
let a;
|
|
50
52
|
if (this.options.hashAlgorithm)
|
|
51
53
|
try {
|
|
52
|
-
|
|
54
|
+
a = (await this.stat(e)).hash;
|
|
53
55
|
} catch {
|
|
54
56
|
}
|
|
55
57
|
try {
|
|
56
58
|
this.broadcastChannel || (this.broadcastChannel = new BroadcastChannel(this.options.broadcastChannel));
|
|
57
|
-
const
|
|
59
|
+
const i = {
|
|
58
60
|
namespace: this.options.namespace,
|
|
59
61
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
60
62
|
...t,
|
|
61
|
-
...
|
|
63
|
+
...a && { hash: a }
|
|
62
64
|
};
|
|
63
|
-
this.broadcastChannel.postMessage(
|
|
64
|
-
} catch (
|
|
65
|
-
console.warn("Failed to send event via BroadcastChannel:",
|
|
65
|
+
this.broadcastChannel.postMessage(i);
|
|
66
|
+
} catch (i) {
|
|
67
|
+
console.warn("Failed to send event via BroadcastChannel:", i);
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
/**
|
|
69
|
-
* Creates a new
|
|
71
|
+
* Creates a new OPFSWorker instance
|
|
70
72
|
*
|
|
71
73
|
* @param options - Optional configuration options
|
|
72
74
|
* @param options.root - Root path for the file system (default: '/')
|
|
@@ -76,7 +78,7 @@ class j {
|
|
|
76
78
|
* @throws {OPFSError} If OPFS is not supported in the current browser
|
|
77
79
|
*/
|
|
78
80
|
constructor(t) {
|
|
79
|
-
|
|
81
|
+
O(), t && this.setOptions(t);
|
|
80
82
|
}
|
|
81
83
|
/**
|
|
82
84
|
* Initialize the file system within a given directory
|
|
@@ -84,13 +86,12 @@ class j {
|
|
|
84
86
|
* This method sets up the root directory for all subsequent operations.
|
|
85
87
|
* If no root is specified, it will use the OPFS root directory.
|
|
86
88
|
*
|
|
87
|
-
* @param root - The root path for the file system (default: '/')
|
|
88
89
|
* @returns Promise that resolves to true if initialization was successful
|
|
89
90
|
* @throws {OPFSError} If initialization fails
|
|
90
91
|
*
|
|
91
92
|
* @example
|
|
92
93
|
* ```typescript
|
|
93
|
-
* const fs = new
|
|
94
|
+
* const fs = new OPFSWorker();
|
|
94
95
|
*
|
|
95
96
|
* // Use OPFS root (default)
|
|
96
97
|
* await fs.mount();
|
|
@@ -101,12 +102,12 @@ class j {
|
|
|
101
102
|
*/
|
|
102
103
|
async mount() {
|
|
103
104
|
const t = this.options.root;
|
|
104
|
-
return this.mountingPromise && await this.mountingPromise, this.mountingPromise = new Promise(async (e,
|
|
105
|
+
return this.mountingPromise && await this.mountingPromise, this.mountingPromise = new Promise(async (e, r) => {
|
|
105
106
|
try {
|
|
106
|
-
const
|
|
107
|
-
this.root = t === "/" ?
|
|
108
|
-
} catch (
|
|
109
|
-
|
|
107
|
+
const a = await navigator.storage.getDirectory();
|
|
108
|
+
this.root = t === "/" ? a : await this.getDirectoryHandle(t, !0, a), e(!0);
|
|
109
|
+
} catch (a) {
|
|
110
|
+
r(new P(t, a));
|
|
110
111
|
} finally {
|
|
111
112
|
this.mountingPromise = null;
|
|
112
113
|
}
|
|
@@ -123,7 +124,7 @@ class j {
|
|
|
123
124
|
* @param options.broadcastChannel - Custom name for the broadcast channel
|
|
124
125
|
*/
|
|
125
126
|
async setOptions(t) {
|
|
126
|
-
t.hashAlgorithm !== void 0 && (this.options.hashAlgorithm = t.hashAlgorithm), t.maxFileSize !== void 0 && (this.options.maxFileSize = t.maxFileSize), t.broadcastChannel !== void 0 && (this.broadcastChannel && this.options.broadcastChannel !== t.broadcastChannel && (this.broadcastChannel.close(), this.broadcastChannel = null), this.options.broadcastChannel = t.broadcastChannel), t.namespace && (this.options.namespace = t.namespace), t.root !== void 0 && (this.options.root =
|
|
127
|
+
t.hashAlgorithm !== void 0 && (this.options.hashAlgorithm = t.hashAlgorithm), t.maxFileSize !== void 0 && (this.options.maxFileSize = t.maxFileSize), t.broadcastChannel !== void 0 && (this.broadcastChannel && this.options.broadcastChannel !== t.broadcastChannel && (this.broadcastChannel.close(), this.broadcastChannel = null), this.options.broadcastChannel = t.broadcastChannel), t.namespace && (this.options.namespace = t.namespace), t.root !== void 0 && (this.options.root = p(t.root), this.options.namespace || (this.options.namespace = `opfs-worker:${this.options.root}`), await this.mount());
|
|
127
128
|
}
|
|
128
129
|
/**
|
|
129
130
|
* Get a directory handle from a path
|
|
@@ -143,12 +144,12 @@ class j {
|
|
|
143
144
|
* const docsDir2 = await fs.getDirectoryHandle(['users', 'john', 'documents'], true);
|
|
144
145
|
* ```
|
|
145
146
|
*/
|
|
146
|
-
async getDirectoryHandle(t, e = !1,
|
|
147
|
-
const
|
|
148
|
-
let
|
|
149
|
-
for (const s of
|
|
150
|
-
|
|
151
|
-
return
|
|
147
|
+
async getDirectoryHandle(t, e = !1, r = this.root) {
|
|
148
|
+
const a = Array.isArray(t) ? t : D(t);
|
|
149
|
+
let i = r;
|
|
150
|
+
for (const s of a)
|
|
151
|
+
i = await i.getDirectoryHandle(s, { create: e });
|
|
152
|
+
return i;
|
|
152
153
|
}
|
|
153
154
|
/**
|
|
154
155
|
* Get a file handle from a path
|
|
@@ -169,12 +170,12 @@ class j {
|
|
|
169
170
|
* const fileHandle2 = await fs.getFileHandle(['config', 'settings.json'], true);
|
|
170
171
|
* ```
|
|
171
172
|
*/
|
|
172
|
-
async getFileHandle(t, e = !1,
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
175
|
-
throw new
|
|
176
|
-
const
|
|
177
|
-
return (await this.getDirectoryHandle(
|
|
173
|
+
async getFileHandle(t, e = !1, r = this.root) {
|
|
174
|
+
const a = D(t);
|
|
175
|
+
if (a.length === 0)
|
|
176
|
+
throw new z("Path must not be empty", Array.isArray(t) ? t.join("/") : t);
|
|
177
|
+
const i = a.pop();
|
|
178
|
+
return (await this.getDirectoryHandle(a, e, r)).getFileHandle(i, { create: e });
|
|
178
179
|
}
|
|
179
180
|
/**
|
|
180
181
|
* Get a complete index of all files and directories in the file system
|
|
@@ -196,10 +197,10 @@ class j {
|
|
|
196
197
|
* ```
|
|
197
198
|
*/
|
|
198
199
|
async index() {
|
|
199
|
-
const t = /* @__PURE__ */ new Map(), e = async (
|
|
200
|
-
const
|
|
201
|
-
for (const
|
|
202
|
-
const s = `${
|
|
200
|
+
const t = /* @__PURE__ */ new Map(), e = async (r) => {
|
|
201
|
+
const a = await this.readDir(r);
|
|
202
|
+
for (const i of a) {
|
|
203
|
+
const s = `${r === "/" ? "" : r}/${i.name}`;
|
|
203
204
|
try {
|
|
204
205
|
const n = await this.stat(s);
|
|
205
206
|
t.set(s, n), n.isDirectory && await e(s);
|
|
@@ -239,17 +240,17 @@ class j {
|
|
|
239
240
|
async readFile(t) {
|
|
240
241
|
await this.mount();
|
|
241
242
|
try {
|
|
242
|
-
return await
|
|
243
|
+
return await u(t, async () => {
|
|
243
244
|
const e = await this.open(t);
|
|
244
245
|
try {
|
|
245
|
-
const { size:
|
|
246
|
-
return
|
|
246
|
+
const { size: r } = await this.fstat(e), a = new Uint8Array(r);
|
|
247
|
+
return r > 0 && await this.read(e, a, 0, r, 0), x(a, [a.buffer]);
|
|
247
248
|
} finally {
|
|
248
249
|
await this.close(e);
|
|
249
250
|
}
|
|
250
251
|
});
|
|
251
252
|
} catch (e) {
|
|
252
|
-
throw
|
|
253
|
+
throw e instanceof w ? e : h(e, { path: t, isDirectory: !1 });
|
|
253
254
|
}
|
|
254
255
|
}
|
|
255
256
|
/**
|
|
@@ -276,15 +277,15 @@ class j {
|
|
|
276
277
|
*/
|
|
277
278
|
async writeFile(t, e) {
|
|
278
279
|
await this.mount();
|
|
279
|
-
const
|
|
280
|
-
await
|
|
281
|
-
const
|
|
280
|
+
const r = e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
281
|
+
await u(t, async () => {
|
|
282
|
+
const a = await this.exists(t), i = await this.open(t, { create: !0, truncate: !0 });
|
|
282
283
|
try {
|
|
283
|
-
await this.write(
|
|
284
|
+
await this.write(i, r, 0, r.length, null, !1), await this.fsync(i);
|
|
284
285
|
} finally {
|
|
285
|
-
await this.close(
|
|
286
|
+
await this.close(i);
|
|
286
287
|
}
|
|
287
|
-
await this.notifyChange({ path: t, type:
|
|
288
|
+
await this.notifyChange({ path: t, type: a ? l.Changed : l.Added, isDirectory: !1 });
|
|
288
289
|
});
|
|
289
290
|
}
|
|
290
291
|
/**
|
|
@@ -311,16 +312,16 @@ class j {
|
|
|
311
312
|
*/
|
|
312
313
|
async appendFile(t, e) {
|
|
313
314
|
await this.mount();
|
|
314
|
-
const
|
|
315
|
-
await
|
|
316
|
-
const
|
|
315
|
+
const r = e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
316
|
+
await u(t, async () => {
|
|
317
|
+
const a = await this.open(t, { create: !0 });
|
|
317
318
|
try {
|
|
318
|
-
const { size:
|
|
319
|
-
await this.write(
|
|
319
|
+
const { size: i } = await this.fstat(a);
|
|
320
|
+
await this.write(a, r, 0, r.length, i, !1), await this.fsync(a);
|
|
320
321
|
} finally {
|
|
321
|
-
await this.close(
|
|
322
|
+
await this.close(a);
|
|
322
323
|
}
|
|
323
|
-
await this.notifyChange({ path: t, type:
|
|
324
|
+
await this.notifyChange({ path: t, type: l.Changed, isDirectory: !1 });
|
|
324
325
|
});
|
|
325
326
|
}
|
|
326
327
|
/**
|
|
@@ -346,17 +347,20 @@ class j {
|
|
|
346
347
|
*/
|
|
347
348
|
async mkdir(t, e) {
|
|
348
349
|
await this.mount();
|
|
349
|
-
const
|
|
350
|
-
let
|
|
351
|
-
for (let s = 0; s <
|
|
352
|
-
const n =
|
|
350
|
+
const r = e?.recursive ?? !1, a = D(t);
|
|
351
|
+
let i = this.root;
|
|
352
|
+
for (let s = 0; s < a.length; s++) {
|
|
353
|
+
const n = a[s];
|
|
353
354
|
try {
|
|
354
|
-
|
|
355
|
+
i = await i.getDirectoryHandle(n, { create: r || s === a.length - 1 });
|
|
355
356
|
} catch (o) {
|
|
356
|
-
throw o.name === "NotFoundError" ?
|
|
357
|
+
throw o.name === "NotFoundError" ? h(o, {
|
|
358
|
+
path: k(a.slice(0, s + 1)),
|
|
359
|
+
existenceType: "directory"
|
|
360
|
+
}) : o.name === "TypeMismatchError" ? h(o, { path: n, isDirectory: !1 }) : new F("create directory", n, o);
|
|
357
361
|
}
|
|
358
362
|
}
|
|
359
|
-
await this.notifyChange({ path: t, type:
|
|
363
|
+
await this.notifyChange({ path: t, type: l.Added, isDirectory: !0 });
|
|
360
364
|
}
|
|
361
365
|
/**
|
|
362
366
|
* Get file or directory statistics
|
|
@@ -390,11 +394,11 @@ class j {
|
|
|
390
394
|
isFile: !1,
|
|
391
395
|
isDirectory: !0
|
|
392
396
|
};
|
|
393
|
-
const e =
|
|
394
|
-
let
|
|
397
|
+
const e = v(t);
|
|
398
|
+
let r;
|
|
395
399
|
try {
|
|
396
|
-
|
|
397
|
-
const
|
|
400
|
+
r = await this.getDirectoryHandle(E(t), !1);
|
|
401
|
+
const a = this.options.hashAlgorithm, s = await (await r.getFileHandle(e, { create: !1 })).getFile(), n = {
|
|
398
402
|
kind: "file",
|
|
399
403
|
size: s.size,
|
|
400
404
|
mtime: new Date(s.lastModified).toISOString(),
|
|
@@ -402,24 +406,24 @@ class j {
|
|
|
402
406
|
isFile: !0,
|
|
403
407
|
isDirectory: !1
|
|
404
408
|
};
|
|
405
|
-
if (
|
|
409
|
+
if (a === "etag")
|
|
406
410
|
n.hash = `${s.lastModified.toString(36)}-${s.size.toString(36)}`;
|
|
407
|
-
else if (typeof
|
|
411
|
+
else if (typeof a == "string")
|
|
408
412
|
try {
|
|
409
|
-
const o = await
|
|
413
|
+
const o = await M(s, a, this.options.maxFileSize);
|
|
410
414
|
n.hash = o;
|
|
411
415
|
} catch (o) {
|
|
412
416
|
console.warn(`Failed to calculate hash for ${t}:`, o);
|
|
413
417
|
}
|
|
414
418
|
return n;
|
|
415
|
-
} catch (
|
|
416
|
-
if (
|
|
417
|
-
throw new
|
|
418
|
-
if (
|
|
419
|
-
throw new
|
|
419
|
+
} catch (a) {
|
|
420
|
+
if (a.name === "NotFoundError")
|
|
421
|
+
throw new S("file", t, a);
|
|
422
|
+
if (a.name !== "TypeMismatchError")
|
|
423
|
+
throw new F("stat", t, a);
|
|
420
424
|
}
|
|
421
425
|
try {
|
|
422
|
-
return await
|
|
426
|
+
return await r.getDirectoryHandle(e, { create: !1 }), {
|
|
423
427
|
kind: "directory",
|
|
424
428
|
size: 0,
|
|
425
429
|
mtime: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
@@ -427,8 +431,8 @@ class j {
|
|
|
427
431
|
isFile: !1,
|
|
428
432
|
isDirectory: !0
|
|
429
433
|
};
|
|
430
|
-
} catch (
|
|
431
|
-
throw new
|
|
434
|
+
} catch (a) {
|
|
435
|
+
throw new F("stat", t, a);
|
|
432
436
|
}
|
|
433
437
|
}
|
|
434
438
|
/**
|
|
@@ -451,17 +455,17 @@ class j {
|
|
|
451
455
|
*/
|
|
452
456
|
async readDir(t) {
|
|
453
457
|
await this.mount();
|
|
454
|
-
const e = await this.getDirectoryHandle(t, !1),
|
|
455
|
-
for await (const [
|
|
456
|
-
const s =
|
|
457
|
-
|
|
458
|
-
name:
|
|
459
|
-
kind:
|
|
458
|
+
const e = await this.getDirectoryHandle(t, !1), r = [];
|
|
459
|
+
for await (const [a, i] of e.entries()) {
|
|
460
|
+
const s = i.kind === "file";
|
|
461
|
+
r.push({
|
|
462
|
+
name: a,
|
|
463
|
+
kind: i.kind,
|
|
460
464
|
isFile: s,
|
|
461
465
|
isDirectory: !s
|
|
462
466
|
});
|
|
463
467
|
}
|
|
464
|
-
return
|
|
468
|
+
return r;
|
|
465
469
|
}
|
|
466
470
|
/**
|
|
467
471
|
* Check if a file or directory exists
|
|
@@ -480,26 +484,26 @@ class j {
|
|
|
480
484
|
async exists(t) {
|
|
481
485
|
if (await this.mount(), t === "/")
|
|
482
486
|
return !0;
|
|
483
|
-
const e =
|
|
484
|
-
let
|
|
487
|
+
const e = v(t);
|
|
488
|
+
let r = null;
|
|
485
489
|
try {
|
|
486
|
-
|
|
487
|
-
} catch (
|
|
488
|
-
if (
|
|
489
|
-
throw
|
|
490
|
+
r = await this.getDirectoryHandle(E(t), !1);
|
|
491
|
+
} catch (a) {
|
|
492
|
+
if (r = null, a.name !== "NotFoundError" && a.name !== "TypeMismatchError")
|
|
493
|
+
throw a;
|
|
490
494
|
}
|
|
491
|
-
if (!
|
|
495
|
+
if (!r || !e)
|
|
492
496
|
return !1;
|
|
493
497
|
try {
|
|
494
|
-
return await
|
|
495
|
-
} catch (
|
|
496
|
-
if (
|
|
497
|
-
throw
|
|
498
|
+
return await r.getFileHandle(e, { create: !1 }), !0;
|
|
499
|
+
} catch (a) {
|
|
500
|
+
if (a.name !== "NotFoundError" && a.name !== "TypeMismatchError")
|
|
501
|
+
throw a;
|
|
498
502
|
try {
|
|
499
|
-
return await
|
|
500
|
-
} catch (
|
|
501
|
-
if (
|
|
502
|
-
throw
|
|
503
|
+
return await r.getDirectoryHandle(e, { create: !1 }), !0;
|
|
504
|
+
} catch (i) {
|
|
505
|
+
if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
|
|
506
|
+
throw i;
|
|
503
507
|
return !1;
|
|
504
508
|
}
|
|
505
509
|
}
|
|
@@ -527,13 +531,13 @@ class j {
|
|
|
527
531
|
await this.mount();
|
|
528
532
|
try {
|
|
529
533
|
const e = await this.readDir(t);
|
|
530
|
-
for (const
|
|
531
|
-
const
|
|
532
|
-
await this.remove(
|
|
534
|
+
for (const r of e) {
|
|
535
|
+
const a = `${t === "/" ? "" : t}/${r.name}`;
|
|
536
|
+
await this.remove(a, { recursive: !0 });
|
|
533
537
|
}
|
|
534
|
-
await this.notifyChange({ path: t, type:
|
|
538
|
+
await this.notifyChange({ path: t, type: l.Changed, isDirectory: !0 });
|
|
535
539
|
} catch (e) {
|
|
536
|
-
throw e instanceof
|
|
540
|
+
throw e instanceof w ? e : h(e, { path: t, isDirectory: !0 });
|
|
537
541
|
}
|
|
538
542
|
}
|
|
539
543
|
/**
|
|
@@ -562,9 +566,9 @@ class j {
|
|
|
562
566
|
*/
|
|
563
567
|
async remove(t, e) {
|
|
564
568
|
if (await this.mount(), t === "/")
|
|
565
|
-
throw new
|
|
566
|
-
const { recursive:
|
|
567
|
-
await
|
|
569
|
+
throw new T("EROOT", t);
|
|
570
|
+
const { recursive: r = !1, force: a = !1 } = e || {}, i = await this.getDirectoryHandle(E(t), !1), s = await this.stat(t);
|
|
571
|
+
await $(i, t, { recursive: r, force: a }), await this.notifyChange({ path: t, type: l.Removed, isDirectory: s.isDirectory });
|
|
568
572
|
}
|
|
569
573
|
/**
|
|
570
574
|
* Resolve a path to an absolute path
|
|
@@ -587,12 +591,12 @@ class j {
|
|
|
587
591
|
async realpath(t) {
|
|
588
592
|
await this.mount();
|
|
589
593
|
try {
|
|
590
|
-
const e =
|
|
594
|
+
const e = b(t);
|
|
591
595
|
if (!await this.exists(e))
|
|
592
|
-
throw new
|
|
596
|
+
throw new S("file", e);
|
|
593
597
|
return e;
|
|
594
598
|
} catch (e) {
|
|
595
|
-
throw e instanceof
|
|
599
|
+
throw e instanceof w ? e : h(e, { path: t });
|
|
596
600
|
}
|
|
597
601
|
}
|
|
598
602
|
/**
|
|
@@ -617,15 +621,15 @@ class j {
|
|
|
617
621
|
* await fs.rename('/old/path/file.txt', '/new/path/renamed.txt', { overwrite: true });
|
|
618
622
|
* ```
|
|
619
623
|
*/
|
|
620
|
-
async rename(t, e,
|
|
624
|
+
async rename(t, e, r) {
|
|
621
625
|
await this.mount();
|
|
622
626
|
try {
|
|
623
|
-
const
|
|
624
|
-
if (await this.exists(e) && !
|
|
625
|
-
throw new
|
|
626
|
-
await this.copy(t, e, { recursive: !0, overwrite:
|
|
627
|
-
} catch (
|
|
628
|
-
throw
|
|
627
|
+
const a = r?.overwrite ?? !1, i = await this.stat(t);
|
|
628
|
+
if (await this.exists(e) && !a)
|
|
629
|
+
throw new H(e);
|
|
630
|
+
await this.copy(t, e, { recursive: !0, overwrite: a }), await this.remove(t, { recursive: !0 }), await this.notifyChange({ path: t, type: l.Removed, isDirectory: i.isDirectory }), await this.notifyChange({ path: e, type: l.Added, isDirectory: i.isDirectory });
|
|
631
|
+
} catch (a) {
|
|
632
|
+
throw a instanceof w ? a : h(a, { path: t });
|
|
629
633
|
}
|
|
630
634
|
}
|
|
631
635
|
/**
|
|
@@ -653,29 +657,29 @@ class j {
|
|
|
653
657
|
* await fs.copy('/source', '/dest', { recursive: true, overwrite: false });
|
|
654
658
|
* ```
|
|
655
659
|
*/
|
|
656
|
-
async copy(t, e,
|
|
660
|
+
async copy(t, e, r) {
|
|
657
661
|
await this.mount();
|
|
658
662
|
try {
|
|
659
|
-
const
|
|
663
|
+
const a = r?.recursive ?? !1, i = r?.overwrite ?? !0;
|
|
660
664
|
if (!await this.exists(t))
|
|
661
|
-
throw new
|
|
662
|
-
if (await this.exists(e) && !
|
|
663
|
-
throw new
|
|
665
|
+
throw new S("source", t);
|
|
666
|
+
if (await this.exists(e) && !i)
|
|
667
|
+
throw new H(e);
|
|
664
668
|
if ((await this.stat(t)).isFile) {
|
|
665
669
|
const c = await this.readFile(t);
|
|
666
670
|
await this.writeFile(e, c);
|
|
667
671
|
} else {
|
|
668
|
-
if (!
|
|
669
|
-
throw new
|
|
672
|
+
if (!a)
|
|
673
|
+
throw new B("directory", t);
|
|
670
674
|
await this.mkdir(e, { recursive: !0 });
|
|
671
675
|
const c = await this.readDir(t);
|
|
672
|
-
for (const
|
|
673
|
-
const
|
|
674
|
-
await this.copy(
|
|
676
|
+
for (const y of c) {
|
|
677
|
+
const f = `${t}/${y.name}`, d = `${e}/${y.name}`;
|
|
678
|
+
await this.copy(f, d, { recursive: !0, overwrite: i });
|
|
675
679
|
}
|
|
676
680
|
}
|
|
677
|
-
} catch (
|
|
678
|
-
throw
|
|
681
|
+
} catch (a) {
|
|
682
|
+
throw a instanceof w ? a : h(a, { path: t });
|
|
679
683
|
}
|
|
680
684
|
}
|
|
681
685
|
/**
|
|
@@ -705,13 +709,13 @@ class j {
|
|
|
705
709
|
*/
|
|
706
710
|
async watch(t, e) {
|
|
707
711
|
if (!this.options.broadcastChannel)
|
|
708
|
-
throw new
|
|
709
|
-
const
|
|
710
|
-
pattern:
|
|
712
|
+
throw new N("This instance is not configured to send events. Please specify options.broadcastChannel to enable watching.");
|
|
713
|
+
const r = {
|
|
714
|
+
pattern: _(t, e?.recursive ?? !0),
|
|
711
715
|
include: Array.isArray(e?.include) ? e.include : [e?.include ?? "**"],
|
|
712
716
|
exclude: Array.isArray(e?.exclude) ? e.exclude : [e?.exclude ?? ""]
|
|
713
717
|
};
|
|
714
|
-
this.watchers.set(t,
|
|
718
|
+
this.watchers.set(t, r);
|
|
715
719
|
}
|
|
716
720
|
/**
|
|
717
721
|
* Stop watching a previously watched path
|
|
@@ -748,37 +752,50 @@ class j {
|
|
|
748
752
|
*/
|
|
749
753
|
async open(t, e) {
|
|
750
754
|
await this.mount();
|
|
751
|
-
const { create:
|
|
755
|
+
const { create: r = !1, exclusive: a = !1, truncate: i = !1 } = e || {}, s = p(b(t));
|
|
752
756
|
try {
|
|
753
|
-
return
|
|
757
|
+
return r && a ? await u(s, async () => {
|
|
754
758
|
if (await this.exists(s))
|
|
755
|
-
throw new
|
|
756
|
-
return this._openFile(s,
|
|
757
|
-
}) : await this._openFile(s,
|
|
759
|
+
throw new H(s);
|
|
760
|
+
return this._openFile(s, r, i);
|
|
761
|
+
}) : await this._openFile(s, r, i);
|
|
758
762
|
} catch (n) {
|
|
759
|
-
|
|
763
|
+
if (n instanceof w)
|
|
764
|
+
throw n;
|
|
765
|
+
const o = n && n.name === "TypeMismatchError";
|
|
766
|
+
throw h(n, {
|
|
767
|
+
path: s,
|
|
768
|
+
isDirectory: !!o
|
|
769
|
+
});
|
|
760
770
|
}
|
|
761
771
|
}
|
|
762
772
|
/**
|
|
763
773
|
* Internal method to open a file (without locking)
|
|
774
|
+
*
|
|
775
|
+
* Multiple FDs for the same path share one sync access handle (OPFS limit),
|
|
776
|
+
* with independent per-FD positions — similar to Node.js.
|
|
764
777
|
* @private
|
|
765
778
|
*/
|
|
766
|
-
async _openFile(t, e,
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
await
|
|
770
|
-
|
|
771
|
-
|
|
779
|
+
async _openFile(t, e, r) {
|
|
780
|
+
let a = this.openHandles.get(t);
|
|
781
|
+
if (!a) {
|
|
782
|
+
const s = await this.getFileHandle(t, e);
|
|
783
|
+
try {
|
|
784
|
+
await s.getFile();
|
|
785
|
+
} catch (o) {
|
|
786
|
+
throw h(o, { path: t, isDirectory: !0 });
|
|
787
|
+
}
|
|
788
|
+
const n = await R(s, t);
|
|
789
|
+
a = { fileHandle: s, syncHandle: n, refCount: 0 }, this.openHandles.set(t, a);
|
|
772
790
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
return this.openFiles.set(s, {
|
|
791
|
+
a.refCount++, r && (a.syncHandle.truncate(0), a.syncHandle.flush());
|
|
792
|
+
const i = this.nextFd++;
|
|
793
|
+
return this.openFiles.set(i, {
|
|
777
794
|
path: t,
|
|
778
|
-
fileHandle:
|
|
779
|
-
syncHandle:
|
|
795
|
+
fileHandle: a.fileHandle,
|
|
796
|
+
syncHandle: a.syncHandle,
|
|
780
797
|
position: 0
|
|
781
|
-
}),
|
|
798
|
+
}), i;
|
|
782
799
|
}
|
|
783
800
|
/**
|
|
784
801
|
* Close a file descriptor
|
|
@@ -796,7 +813,9 @@ class j {
|
|
|
796
813
|
*/
|
|
797
814
|
async close(t) {
|
|
798
815
|
const e = this._getFileDescriptor(t);
|
|
799
|
-
|
|
816
|
+
this.openFiles.delete(t);
|
|
817
|
+
const r = this.openHandles.get(e.path);
|
|
818
|
+
r && (r.refCount--, r.refCount <= 0 && (A(t, r.syncHandle, e.path), this.openHandles.delete(e.path)));
|
|
800
819
|
}
|
|
801
820
|
/**
|
|
802
821
|
* Read data from a file descriptor
|
|
@@ -822,17 +841,17 @@ class j {
|
|
|
822
841
|
* await fs.close(fd);
|
|
823
842
|
* ```
|
|
824
843
|
*/
|
|
825
|
-
async read(t, e, a, i
|
|
844
|
+
async read(t, e, r, a, i) {
|
|
826
845
|
const s = this._getFileDescriptor(t);
|
|
827
|
-
|
|
846
|
+
I(e.length, r, a, i);
|
|
828
847
|
try {
|
|
829
|
-
const n =
|
|
848
|
+
const n = i ?? s.position, o = s.syncHandle.getSize(), { isEOF: c, actualLength: y } = L(n, a, o);
|
|
830
849
|
if (c)
|
|
831
|
-
return
|
|
832
|
-
const
|
|
833
|
-
return
|
|
850
|
+
return x({ bytesRead: 0, buffer: e }, [e.buffer]);
|
|
851
|
+
const f = e.subarray(r, r + y), d = s.syncHandle.read(f, { at: n });
|
|
852
|
+
return i == null && (s.position = n + d), x({ bytesRead: d, buffer: e }, [e.buffer]);
|
|
834
853
|
} catch (n) {
|
|
835
|
-
throw
|
|
854
|
+
throw m("read", t, s.path, n);
|
|
836
855
|
}
|
|
837
856
|
}
|
|
838
857
|
/**
|
|
@@ -856,14 +875,14 @@ class j {
|
|
|
856
875
|
* await fs.close(fd);
|
|
857
876
|
* ```
|
|
858
877
|
*/
|
|
859
|
-
async write(t, e,
|
|
860
|
-
const n = this._getFileDescriptor(t), o =
|
|
861
|
-
|
|
878
|
+
async write(t, e, r = 0, a, i, s = !0) {
|
|
879
|
+
const n = this._getFileDescriptor(t), o = a ?? e.length - r;
|
|
880
|
+
I(e.length, r, o, i);
|
|
862
881
|
try {
|
|
863
|
-
const c =
|
|
864
|
-
return (
|
|
882
|
+
const c = i ?? n.position, y = e.subarray(r, r + o), f = n.syncHandle.write(y, { at: c });
|
|
883
|
+
return (i == null || i === n.position) && (n.position = c + f), s && await this.notifyChange({ path: n.path, type: l.Changed, isDirectory: !1 }), f;
|
|
865
884
|
} catch (c) {
|
|
866
|
-
throw
|
|
885
|
+
throw m("write", t, n.path, c);
|
|
867
886
|
}
|
|
868
887
|
}
|
|
869
888
|
/**
|
|
@@ -905,13 +924,13 @@ class j {
|
|
|
905
924
|
* ```
|
|
906
925
|
*/
|
|
907
926
|
async ftruncate(t, e = 0) {
|
|
908
|
-
const
|
|
927
|
+
const r = this._getFileDescriptor(t);
|
|
909
928
|
if (e < 0 || !Number.isInteger(e))
|
|
910
|
-
throw new
|
|
929
|
+
throw new C("argument", "Invalid size");
|
|
911
930
|
try {
|
|
912
|
-
|
|
913
|
-
} catch (
|
|
914
|
-
throw
|
|
931
|
+
r.syncHandle.truncate(e), r.syncHandle.flush(), r.position > e && (r.position = e), await this.notifyChange({ path: r.path, type: l.Changed, isDirectory: !1 });
|
|
932
|
+
} catch (a) {
|
|
933
|
+
throw m("truncate", t, r.path, a);
|
|
915
934
|
}
|
|
916
935
|
}
|
|
917
936
|
/**
|
|
@@ -932,8 +951,8 @@ class j {
|
|
|
932
951
|
const e = this._getFileDescriptor(t);
|
|
933
952
|
try {
|
|
934
953
|
e.syncHandle.flush();
|
|
935
|
-
} catch (
|
|
936
|
-
throw
|
|
954
|
+
} catch (r) {
|
|
955
|
+
throw m("sync", t, e.path, r);
|
|
937
956
|
}
|
|
938
957
|
}
|
|
939
958
|
/**
|
|
@@ -944,9 +963,9 @@ class j {
|
|
|
944
963
|
*/
|
|
945
964
|
dispose() {
|
|
946
965
|
this.broadcastChannel && (this.broadcastChannel.close(), this.broadcastChannel = null), this.watchers.clear();
|
|
947
|
-
for (const [t, e] of this.
|
|
948
|
-
|
|
949
|
-
this.openFiles.clear(), this.nextFd = 1;
|
|
966
|
+
for (const [t, e] of this.openHandles)
|
|
967
|
+
A(-1, e.syncHandle, t);
|
|
968
|
+
this.openHandles.clear(), this.openFiles.clear(), this.nextFd = 1;
|
|
950
969
|
}
|
|
951
970
|
/**
|
|
952
971
|
* Synchronize the file system with external data
|
|
@@ -955,8 +974,6 @@ class j {
|
|
|
955
974
|
* This is useful for importing data from external sources or syncing with remote data.
|
|
956
975
|
*
|
|
957
976
|
* @param entries - Array of [path, data] tuples to sync
|
|
958
|
-
* @param options - Options for synchronization
|
|
959
|
-
* @param options.cleanBefore - Whether to clear the file system before syncing (default: false)
|
|
960
977
|
* @returns Promise that resolves when synchronization is complete
|
|
961
978
|
* @throws {OPFSError} If the synchronization fails
|
|
962
979
|
*
|
|
@@ -979,18 +996,61 @@ class j {
|
|
|
979
996
|
async createIndex(t) {
|
|
980
997
|
await this.mount();
|
|
981
998
|
try {
|
|
982
|
-
for (const [e,
|
|
983
|
-
const
|
|
984
|
-
let
|
|
985
|
-
|
|
999
|
+
for (const [e, r] of t) {
|
|
1000
|
+
const a = p(e);
|
|
1001
|
+
let i;
|
|
1002
|
+
r instanceof Blob ? i = await U(r) : typeof r == "string" ? i = new TextEncoder().encode(r) : i = r, await this.writeFile(a, i);
|
|
986
1003
|
}
|
|
987
1004
|
} catch (e) {
|
|
988
|
-
throw e instanceof
|
|
1005
|
+
throw e instanceof w ? e : h(e);
|
|
989
1006
|
}
|
|
990
1007
|
}
|
|
991
1008
|
}
|
|
992
|
-
typeof globalThis < "u" && globalThis.constructor.name === "DedicatedWorkerGlobalScope" && k(new j());
|
|
993
1009
|
export {
|
|
994
|
-
|
|
1010
|
+
H as AlreadyExistsError,
|
|
1011
|
+
K as BINARY_FILE_EXTENSIONS,
|
|
1012
|
+
T as DirectoryOperationError,
|
|
1013
|
+
S as ExistenceError,
|
|
1014
|
+
X as FileBusyError,
|
|
1015
|
+
F as FileSystemOperationError,
|
|
1016
|
+
B as FileTypeError,
|
|
1017
|
+
Y as IOError,
|
|
1018
|
+
P as InitializationFailedError,
|
|
1019
|
+
w as OPFSError,
|
|
1020
|
+
Q as OPFSNotSupportedError,
|
|
1021
|
+
V as OPFSWorker,
|
|
1022
|
+
Z as OperationAbortedError,
|
|
1023
|
+
N as OperationNotSupportedError,
|
|
1024
|
+
z as PathError,
|
|
1025
|
+
tt as PermissionError,
|
|
1026
|
+
et as StorageError,
|
|
1027
|
+
C as ValidationError,
|
|
1028
|
+
l as WatchEventType,
|
|
1029
|
+
v as basename,
|
|
1030
|
+
at as buffersEqual,
|
|
1031
|
+
M as calculateFileHash,
|
|
1032
|
+
L as calculateReadLength,
|
|
1033
|
+
O as checkOPFSSupport,
|
|
1034
|
+
U as convertBlobToUint8Array,
|
|
1035
|
+
rt as createBuffer,
|
|
1036
|
+
m as createFDError,
|
|
1037
|
+
R as createSyncHandleSafe,
|
|
1038
|
+
it as decodeBuffer,
|
|
1039
|
+
E as dirname,
|
|
1040
|
+
st as encodeString,
|
|
1041
|
+
nt as extname,
|
|
1042
|
+
ot as isBinaryFileExtension,
|
|
1043
|
+
ct as isPathExcluded,
|
|
1044
|
+
k as joinPath,
|
|
1045
|
+
h as mapDomError,
|
|
1046
|
+
g as matchMinimatch,
|
|
1047
|
+
_ as normalizeMinimatch,
|
|
1048
|
+
p as normalizePath,
|
|
1049
|
+
$ as removeEntry,
|
|
1050
|
+
b as resolvePath,
|
|
1051
|
+
A as safeCloseSyncHandle,
|
|
1052
|
+
D as splitPath,
|
|
1053
|
+
I as validateReadWriteArgs,
|
|
1054
|
+
u as withLock
|
|
995
1055
|
};
|
|
996
|
-
//# sourceMappingURL=
|
|
1056
|
+
//# sourceMappingURL=index.pure.js.map
|