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.
Files changed (62) hide show
  1. package/README.md +89 -106
  2. package/dist/{facade.d.ts → OPFSFacade.d.ts} +26 -9
  3. package/dist/OPFSFacade.d.ts.map +1 -0
  4. package/dist/{worker.d.ts → OPFSWorker.d.ts} +11 -11
  5. package/dist/OPFSWorker.d.ts.map +1 -0
  6. package/dist/assets/worker.entry-DUlEoroc.js.map +1 -0
  7. package/dist/createOPFSWorker.d.ts +17 -0
  8. package/dist/createOPFSWorker.d.ts.map +1 -0
  9. package/dist/helpers-DNj8ZoMu.cjs +4 -0
  10. package/dist/helpers-DNj8ZoMu.cjs.map +1 -0
  11. package/dist/{helpers-CKOebsbw.js → helpers-WY2jfbOT.js} +257 -253
  12. package/dist/helpers-WY2jfbOT.js.map +1 -0
  13. package/dist/index.cjs +349 -329
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +3 -9
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +428 -382
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.pure.cjs +2 -0
  20. package/dist/index.pure.cjs.map +1 -0
  21. package/dist/index.pure.d.ts +6 -0
  22. package/dist/index.pure.d.ts.map +1 -0
  23. package/dist/{raw.js → index.pure.js} +248 -188
  24. package/dist/index.pure.js.map +1 -0
  25. package/dist/types.d.ts +1 -1
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/utils/errors.d.ts +14 -6
  28. package/dist/utils/errors.d.ts.map +1 -1
  29. package/dist/utils/helpers.d.ts +15 -3
  30. package/dist/utils/helpers.d.ts.map +1 -1
  31. package/dist/worker.entry.d.ts +2 -0
  32. package/dist/worker.entry.d.ts.map +1 -0
  33. package/docs/api-reference.md +815 -0
  34. package/docs/file-descriptors.md +696 -0
  35. package/docs/types.md +232 -0
  36. package/package.json +15 -9
  37. package/src/OPFSFacade.ts +460 -0
  38. package/src/OPFSWorker.ts +1544 -0
  39. package/src/createOPFSWorker.ts +57 -0
  40. package/src/index.pure.ts +7 -0
  41. package/src/index.ts +15 -0
  42. package/src/types.ts +99 -0
  43. package/src/utils/encoder.ts +205 -0
  44. package/src/utils/errors.ts +297 -0
  45. package/src/utils/helpers.ts +465 -0
  46. package/src/worker.entry.ts +6 -0
  47. package/dist/assets/worker-1Wh1cr7P.js.map +0 -1
  48. package/dist/assets/worker-BeJaVyBV.js.map +0 -1
  49. package/dist/facade.d.ts.map +0 -1
  50. package/dist/helpers-BuGfPAg0.js +0 -1439
  51. package/dist/helpers-BuGfPAg0.js.map +0 -1
  52. package/dist/helpers-CF7A2WQG.cjs +0 -4
  53. package/dist/helpers-CF7A2WQG.cjs.map +0 -1
  54. package/dist/helpers-CIiblZ8d.cjs +0 -4
  55. package/dist/helpers-CIiblZ8d.cjs.map +0 -1
  56. package/dist/helpers-CKOebsbw.js.map +0 -1
  57. package/dist/raw.cjs +0 -2
  58. package/dist/raw.cjs.map +0 -1
  59. package/dist/raw.d.ts +0 -13
  60. package/dist/raw.d.ts.map +0 -1
  61. package/dist/raw.js.map +0 -1
  62. package/dist/worker.d.ts.map +0 -1
@@ -1,6 +1,7 @@
1
- import { expose as k, transfer as p } from "comlink";
2
- import { V as E, t as D, l as z, h as P, q as F, s as v, P as M, w as m, E as d, n as $, c as b, j as S, W as h, o as H, p as x, z as T, O as f, m as l, D as _, G as N, v as A, A as C, g as R, r as B, L as U, J as I, H as O, K as W, k as g, C as L } from "./helpers-CKOebsbw.js";
3
- class j {
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 E("descriptor", `Invalid file descriptor: ${t}`);
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 path - The path that was changed
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((r) => D(e, r.pattern) && r.include.some((s) => s && D(e, s)) && !r.exclude.some((s) => s && D(e, s))))
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 i;
51
+ let a;
50
52
  if (this.options.hashAlgorithm)
51
53
  try {
52
- i = (await this.stat(e)).hash;
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 r = {
59
+ const i = {
58
60
  namespace: this.options.namespace,
59
61
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
60
62
  ...t,
61
- ...i && { hash: i }
63
+ ...a && { hash: a }
62
64
  };
63
- this.broadcastChannel.postMessage(r);
64
- } catch (r) {
65
- console.warn("Failed to send event via BroadcastChannel:", r);
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 OPFSFileSystem instance
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
- z(), t && this.setOptions(t);
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 OPFSFileSystem();
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, a) => {
105
+ return this.mountingPromise && await this.mountingPromise, this.mountingPromise = new Promise(async (e, r) => {
105
106
  try {
106
- const i = await navigator.storage.getDirectory();
107
- this.root = t === "/" ? i : await this.getDirectoryHandle(t, !0, i), e(!0);
108
- } catch (i) {
109
- a(new P(t, i));
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 = F(t.root), this.options.namespace || (this.options.namespace = `opfs-worker:${this.options.root}`), await this.mount());
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, a = this.root) {
147
- const i = Array.isArray(t) ? t : v(t);
148
- let r = a;
149
- for (const s of i)
150
- r = await r.getDirectoryHandle(s, { create: e });
151
- return r;
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, a = this.root) {
173
- const i = v(t);
174
- if (i.length === 0)
175
- throw new M("Path must not be empty", Array.isArray(t) ? t.join("/") : t);
176
- const r = i.pop();
177
- return (await this.getDirectoryHandle(i, e, a)).getFileHandle(r, { create: e });
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 (a) => {
200
- const i = await this.readDir(a);
201
- for (const r of i) {
202
- const s = `${a === "/" ? "" : a}/${r.name}`;
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 m(t, "shared", async () => {
243
+ return await u(t, async () => {
243
244
  const e = await this.open(t);
244
245
  try {
245
- const { size: a } = await this.fstat(e), i = new Uint8Array(a);
246
- return a > 0 && await this.read(e, i, 0, a, 0), p(i, [i.buffer]);
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 new d("file", t, e);
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 a = e instanceof Uint8Array ? e : new Uint8Array(e);
280
- await m(t, "exclusive", async () => {
281
- const i = await this.exists(t), r = await this.open(t, { create: !0, truncate: !0 });
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(r, a, 0, a.length, null, !1), await this.fsync(r);
284
+ await this.write(i, r, 0, r.length, null, !1), await this.fsync(i);
284
285
  } finally {
285
- await this.close(r);
286
+ await this.close(i);
286
287
  }
287
- await this.notifyChange({ path: t, type: i ? h.Changed : h.Added, isDirectory: !1 });
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 a = e instanceof Uint8Array ? e : new Uint8Array(e);
315
- await m(t, "exclusive", async () => {
316
- const i = await this.open(t, { create: !0 });
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: r } = await this.fstat(i);
319
- await this.write(i, a, 0, a.length, r, !1), await this.fsync(i);
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(i);
322
+ await this.close(a);
322
323
  }
323
- await this.notifyChange({ path: t, type: h.Changed, isDirectory: !1 });
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 a = e?.recursive ?? !1, i = v(t);
350
- let r = this.root;
351
- for (let s = 0; s < i.length; s++) {
352
- const n = i[s];
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
- r = await r.getDirectoryHandle(n, { create: a || s === i.length - 1 });
355
+ i = await i.getDirectoryHandle(n, { create: r || s === a.length - 1 });
355
356
  } catch (o) {
356
- throw o.name === "NotFoundError" ? new d("directory", $(i.slice(0, s + 1)), o) : o.name === "TypeMismatchError" ? new b("file", n, o) : new S("create directory", n, o);
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: h.Added, isDirectory: !0 });
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 = H(t);
394
- let a;
397
+ const e = v(t);
398
+ let r;
395
399
  try {
396
- a = await this.getDirectoryHandle(x(t), !1);
397
- const i = this.options.hashAlgorithm, s = await (await a.getFileHandle(e, { create: !1 })).getFile(), n = {
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 (i === "etag")
409
+ if (a === "etag")
406
410
  n.hash = `${s.lastModified.toString(36)}-${s.size.toString(36)}`;
407
- else if (typeof i == "string")
411
+ else if (typeof a == "string")
408
412
  try {
409
- const o = await T(s, i, this.options.maxFileSize);
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 (i) {
416
- if (i.name === "NotFoundError")
417
- throw new d("file", t, i);
418
- if (i.name !== "TypeMismatchError")
419
- throw new S("stat", t, i);
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 a.getDirectoryHandle(e, { create: !1 }), {
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 (i) {
431
- throw new S("stat", t, i);
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), a = [];
455
- for await (const [i, r] of e.entries()) {
456
- const s = r.kind === "file";
457
- a.push({
458
- name: i,
459
- kind: r.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 a;
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 = H(t);
484
- let a = null;
487
+ const e = v(t);
488
+ let r = null;
485
489
  try {
486
- a = await this.getDirectoryHandle(x(t), !1);
487
- } catch (i) {
488
- if (a = null, i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
489
- throw i;
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 (!a || !e)
495
+ if (!r || !e)
492
496
  return !1;
493
497
  try {
494
- return await a.getFileHandle(e, { create: !1 }), !0;
495
- } catch (i) {
496
- if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
497
- throw i;
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 a.getDirectoryHandle(e, { create: !1 }), !0;
500
- } catch (r) {
501
- if (r.name !== "NotFoundError" && r.name !== "TypeMismatchError")
502
- throw r;
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 a of e) {
531
- const i = `${t === "/" ? "" : t}/${a.name}`;
532
- await this.remove(i, { recursive: !0 });
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: h.Changed, isDirectory: !0 });
538
+ await this.notifyChange({ path: t, type: l.Changed, isDirectory: !0 });
535
539
  } catch (e) {
536
- throw e instanceof f ? e : l(e, { path: t, isDirectory: !0 });
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 _("EROOT", t);
566
- const { recursive: a = !1, force: i = !1 } = e || {}, r = await this.getDirectoryHandle(x(t), !1), s = await this.stat(t);
567
- await N(r, t, { recursive: a, force: i }), await this.notifyChange({ path: t, type: h.Removed, isDirectory: s.isDirectory });
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 = A(t);
594
+ const e = b(t);
591
595
  if (!await this.exists(e))
592
- throw new d("file", e);
596
+ throw new S("file", e);
593
597
  return e;
594
598
  } catch (e) {
595
- throw e instanceof f ? e : l(e, { path: t });
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, a) {
624
+ async rename(t, e, r) {
621
625
  await this.mount();
622
626
  try {
623
- const i = a?.overwrite ?? !1, r = await this.stat(t);
624
- if (await this.exists(e) && !i)
625
- throw new C(e);
626
- await this.copy(t, e, { recursive: !0, overwrite: i }), await this.remove(t, { recursive: !0 }), await this.notifyChange({ path: t, type: h.Removed, isDirectory: r.isDirectory }), await this.notifyChange({ path: e, type: h.Added, isDirectory: r.isDirectory });
627
- } catch (i) {
628
- throw i instanceof f ? i : l(i, { path: t });
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, a) {
660
+ async copy(t, e, r) {
657
661
  await this.mount();
658
662
  try {
659
- const i = a?.recursive ?? !1, r = a?.overwrite ?? !0;
663
+ const a = r?.recursive ?? !1, i = r?.overwrite ?? !0;
660
664
  if (!await this.exists(t))
661
- throw new d("source", t);
662
- if (await this.exists(e) && !r)
663
- throw new C(e);
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 (!i)
669
- throw new b("directory", t);
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 w of c) {
673
- const y = `${t}/${w.name}`, u = `${e}/${w.name}`;
674
- await this.copy(y, u, { recursive: !0, overwrite: r });
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 (i) {
678
- throw i instanceof f ? i : l(i, { path: t });
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 R("This instance is not configured to send events. Please specify options.broadcastChannel to enable watching.");
709
- const a = {
710
- pattern: B(t, e?.recursive ?? !0),
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, a);
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: a = !1, exclusive: i = !1, truncate: r = !1 } = e || {}, s = F(A(t));
755
+ const { create: r = !1, exclusive: a = !1, truncate: i = !1 } = e || {}, s = p(b(t));
752
756
  try {
753
- return a && i ? await m(s, "exclusive", async () => {
757
+ return r && a ? await u(s, async () => {
754
758
  if (await this.exists(s))
755
- throw new C(s);
756
- return this._openFile(s, a, r);
757
- }) : await this._openFile(s, a, r);
759
+ throw new H(s);
760
+ return this._openFile(s, r, i);
761
+ }) : await this._openFile(s, r, i);
758
762
  } catch (n) {
759
- throw n instanceof f ? n : l(n, { path: s, isDirectory: !1 });
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, a) {
767
- const i = await this.getFileHandle(t, e);
768
- try {
769
- await i.getFile();
770
- } catch (n) {
771
- throw l(n, { path: t, isDirectory: !0 });
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
- const r = await U(i, t);
774
- a && (r.truncate(0), r.flush());
775
- const s = this.nextFd++;
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: i,
779
- syncHandle: r,
795
+ fileHandle: a.fileHandle,
796
+ syncHandle: a.syncHandle,
780
797
  position: 0
781
- }), s;
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
- I(t, e.syncHandle, e.path), this.openFiles.delete(t);
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, r) {
844
+ async read(t, e, r, a, i) {
826
845
  const s = this._getFileDescriptor(t);
827
- O(e.length, a, i, r);
846
+ I(e.length, r, a, i);
828
847
  try {
829
- const n = r ?? s.position, o = s.syncHandle.getSize(), { isEOF: c, actualLength: w } = W(n, i, o);
848
+ const n = i ?? s.position, o = s.syncHandle.getSize(), { isEOF: c, actualLength: y } = L(n, a, o);
830
849
  if (c)
831
- return p({ bytesRead: 0, buffer: e }, [e.buffer]);
832
- const y = e.subarray(a, a + w), u = s.syncHandle.read(y, { at: n });
833
- return r == null && (s.position = n + u), p({ bytesRead: u, buffer: e }, [e.buffer]);
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 g("read", t, s.path, n);
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, a = 0, i, r, s = !0) {
860
- const n = this._getFileDescriptor(t), o = i ?? e.length - a;
861
- O(e.length, a, o, r);
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 = r ?? n.position, w = e.subarray(a, a + o), y = n.syncHandle.write(w, { at: c });
864
- return (r == null || r === n.position) && (n.position = c + y), s && await this.notifyChange({ path: n.path, type: h.Changed, isDirectory: !1 }), y;
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 g("write", t, n.path, c);
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 a = this._getFileDescriptor(t);
927
+ const r = this._getFileDescriptor(t);
909
928
  if (e < 0 || !Number.isInteger(e))
910
- throw new E("argument", "Invalid size");
929
+ throw new C("argument", "Invalid size");
911
930
  try {
912
- a.syncHandle.truncate(e), a.syncHandle.flush(), a.position > e && (a.position = e), await this.notifyChange({ path: a.path, type: h.Changed, isDirectory: !1 });
913
- } catch (i) {
914
- throw g("truncate", t, a.path, i);
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 (a) {
936
- throw g("sync", t, e.path, a);
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.openFiles)
948
- I(t, e.syncHandle, e.path);
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, a] of t) {
983
- const i = F(e);
984
- let r;
985
- a instanceof Blob ? r = await L(a) : typeof a == "string" ? r = new TextEncoder().encode(a) : r = a, await this.writeFile(i, r);
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 f ? e : l(e);
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
- j as OPFSWorker
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=raw.js.map
1056
+ //# sourceMappingURL=index.pure.js.map