opfs-worker 1.3.2 → 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 (65) hide show
  1. package/README.md +89 -106
  2. package/dist/{facade.d.ts → OPFSFacade.d.ts} +22 -5
  3. package/dist/OPFSFacade.d.ts.map +1 -0
  4. package/dist/{worker.d.ts → OPFSWorker.d.ts} +10 -6
  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-Ca2c767K.js → helpers-WY2jfbOT.js} +221 -221
  12. package/dist/helpers-WY2jfbOT.js.map +1 -0
  13. package/dist/index.cjs +296 -285
  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 +369 -340
  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} +241 -186
  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/helpers.d.ts +11 -1
  28. package/dist/utils/helpers.d.ts.map +1 -1
  29. package/dist/worker.entry.d.ts +2 -0
  30. package/dist/worker.entry.d.ts.map +1 -0
  31. package/docs/api-reference.md +815 -0
  32. package/docs/file-descriptors.md +696 -0
  33. package/docs/types.md +232 -0
  34. package/package.json +14 -8
  35. package/src/OPFSFacade.ts +460 -0
  36. package/src/OPFSWorker.ts +1544 -0
  37. package/src/createOPFSWorker.ts +57 -0
  38. package/src/index.pure.ts +7 -0
  39. package/src/index.ts +15 -0
  40. package/src/types.ts +99 -0
  41. package/src/utils/encoder.ts +205 -0
  42. package/src/utils/errors.ts +297 -0
  43. package/src/utils/helpers.ts +465 -0
  44. package/src/worker.entry.ts +6 -0
  45. package/dist/assets/worker-1Wh1cr7P.js.map +0 -1
  46. package/dist/assets/worker-BeJaVyBV.js.map +0 -1
  47. package/dist/assets/worker-DYYLzR1Y.js.map +0 -1
  48. package/dist/facade.d.ts.map +0 -1
  49. package/dist/helpers-BuGfPAg0.js +0 -1439
  50. package/dist/helpers-BuGfPAg0.js.map +0 -1
  51. package/dist/helpers-CF7A2WQG.cjs +0 -4
  52. package/dist/helpers-CF7A2WQG.cjs.map +0 -1
  53. package/dist/helpers-CIiblZ8d.cjs +0 -4
  54. package/dist/helpers-CIiblZ8d.cjs.map +0 -1
  55. package/dist/helpers-CKOebsbw.js +0 -1423
  56. package/dist/helpers-CKOebsbw.js.map +0 -1
  57. package/dist/helpers-Ca2c767K.js.map +0 -1
  58. package/dist/helpers-Dwc92hv9.cjs +0 -4
  59. package/dist/helpers-Dwc92hv9.cjs.map +0 -1
  60. package/dist/raw.cjs +0 -2
  61. package/dist/raw.cjs.map +0 -1
  62. package/dist/raw.d.ts +0 -13
  63. package/dist/raw.d.ts.map +0 -1
  64. package/dist/raw.js.map +0 -1
  65. package/dist/worker.d.ts.map +0 -1
@@ -1,6 +1,7 @@
1
- import { expose as O, transfer as p } from "comlink";
2
- import { V as E, t as D, l as k, h as z, q as F, s as v, P, w as u, E as m, m as l, n as M, j as x, W as h, o as b, p as S, z as T, O as f, D as $, G as _, v as H, A as C, c as N, g as R, r as B, L as U, J as A, H as I, K as W, k as g, C as L } from "./helpers-Ca2c767K.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
  /**
@@ -43,29 +46,29 @@ class j {
43
46
  if (!this.options.broadcastChannel)
44
47
  return;
45
48
  const e = t.path;
46
- 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))))
47
50
  return;
48
- let i;
51
+ let a;
49
52
  if (this.options.hashAlgorithm)
50
53
  try {
51
- i = (await this.stat(e)).hash;
54
+ a = (await this.stat(e)).hash;
52
55
  } catch {
53
56
  }
54
57
  try {
55
58
  this.broadcastChannel || (this.broadcastChannel = new BroadcastChannel(this.options.broadcastChannel));
56
- const r = {
59
+ const i = {
57
60
  namespace: this.options.namespace,
58
61
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
59
62
  ...t,
60
- ...i && { hash: i }
63
+ ...a && { hash: a }
61
64
  };
62
- this.broadcastChannel.postMessage(r);
63
- } catch (r) {
64
- 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);
65
68
  }
66
69
  }
67
70
  /**
68
- * Creates a new OPFSFileSystem instance
71
+ * Creates a new OPFSWorker instance
69
72
  *
70
73
  * @param options - Optional configuration options
71
74
  * @param options.root - Root path for the file system (default: '/')
@@ -75,7 +78,7 @@ class j {
75
78
  * @throws {OPFSError} If OPFS is not supported in the current browser
76
79
  */
77
80
  constructor(t) {
78
- k(), t && this.setOptions(t);
81
+ O(), t && this.setOptions(t);
79
82
  }
80
83
  /**
81
84
  * Initialize the file system within a given directory
@@ -88,7 +91,7 @@ class j {
88
91
  *
89
92
  * @example
90
93
  * ```typescript
91
- * const fs = new OPFSFileSystem();
94
+ * const fs = new OPFSWorker();
92
95
  *
93
96
  * // Use OPFS root (default)
94
97
  * await fs.mount();
@@ -99,12 +102,12 @@ class j {
99
102
  */
100
103
  async mount() {
101
104
  const t = this.options.root;
102
- 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) => {
103
106
  try {
104
- const i = await navigator.storage.getDirectory();
105
- this.root = t === "/" ? i : await this.getDirectoryHandle(t, !0, i), e(!0);
106
- } catch (i) {
107
- a(new z(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));
108
111
  } finally {
109
112
  this.mountingPromise = null;
110
113
  }
@@ -121,7 +124,7 @@ class j {
121
124
  * @param options.broadcastChannel - Custom name for the broadcast channel
122
125
  */
123
126
  async setOptions(t) {
124
- 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());
125
128
  }
126
129
  /**
127
130
  * Get a directory handle from a path
@@ -141,12 +144,12 @@ class j {
141
144
  * const docsDir2 = await fs.getDirectoryHandle(['users', 'john', 'documents'], true);
142
145
  * ```
143
146
  */
144
- async getDirectoryHandle(t, e = !1, a = this.root) {
145
- const i = Array.isArray(t) ? t : v(t);
146
- let r = a;
147
- for (const s of i)
148
- r = await r.getDirectoryHandle(s, { create: e });
149
- 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;
150
153
  }
151
154
  /**
152
155
  * Get a file handle from a path
@@ -167,12 +170,12 @@ class j {
167
170
  * const fileHandle2 = await fs.getFileHandle(['config', 'settings.json'], true);
168
171
  * ```
169
172
  */
170
- async getFileHandle(t, e = !1, a = this.root) {
171
- const i = v(t);
172
- if (i.length === 0)
173
- throw new P("Path must not be empty", Array.isArray(t) ? t.join("/") : t);
174
- const r = i.pop();
175
- 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 });
176
179
  }
177
180
  /**
178
181
  * Get a complete index of all files and directories in the file system
@@ -194,10 +197,10 @@ class j {
194
197
  * ```
195
198
  */
196
199
  async index() {
197
- const t = /* @__PURE__ */ new Map(), e = async (a) => {
198
- const i = await this.readDir(a);
199
- for (const r of i) {
200
- 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}`;
201
204
  try {
202
205
  const n = await this.stat(s);
203
206
  t.set(s, n), n.isDirectory && await e(s);
@@ -237,17 +240,17 @@ class j {
237
240
  async readFile(t) {
238
241
  await this.mount();
239
242
  try {
240
- return await u(t, "shared", async () => {
243
+ return await u(t, async () => {
241
244
  const e = await this.open(t);
242
245
  try {
243
- const { size: a } = await this.fstat(e), i = new Uint8Array(a);
244
- 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]);
245
248
  } finally {
246
249
  await this.close(e);
247
250
  }
248
251
  });
249
252
  } catch (e) {
250
- throw new m("file", t, e);
253
+ throw e instanceof w ? e : h(e, { path: t, isDirectory: !1 });
251
254
  }
252
255
  }
253
256
  /**
@@ -274,15 +277,15 @@ class j {
274
277
  */
275
278
  async writeFile(t, e) {
276
279
  await this.mount();
277
- const a = e instanceof Uint8Array ? e : new Uint8Array(e);
278
- await u(t, "exclusive", async () => {
279
- 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 });
280
283
  try {
281
- 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);
282
285
  } finally {
283
- await this.close(r);
286
+ await this.close(i);
284
287
  }
285
- 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 });
286
289
  });
287
290
  }
288
291
  /**
@@ -309,16 +312,16 @@ class j {
309
312
  */
310
313
  async appendFile(t, e) {
311
314
  await this.mount();
312
- const a = e instanceof Uint8Array ? e : new Uint8Array(e);
313
- await u(t, "exclusive", async () => {
314
- 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 });
315
318
  try {
316
- const { size: r } = await this.fstat(i);
317
- 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);
318
321
  } finally {
319
- await this.close(i);
322
+ await this.close(a);
320
323
  }
321
- await this.notifyChange({ path: t, type: h.Changed, isDirectory: !1 });
324
+ await this.notifyChange({ path: t, type: l.Changed, isDirectory: !1 });
322
325
  });
323
326
  }
324
327
  /**
@@ -344,20 +347,20 @@ class j {
344
347
  */
345
348
  async mkdir(t, e) {
346
349
  await this.mount();
347
- const a = e?.recursive ?? !1, i = v(t);
348
- let r = this.root;
349
- for (let s = 0; s < i.length; s++) {
350
- 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];
351
354
  try {
352
- r = await r.getDirectoryHandle(n, { create: a || s === i.length - 1 });
355
+ i = await i.getDirectoryHandle(n, { create: r || s === a.length - 1 });
353
356
  } catch (o) {
354
- throw o.name === "NotFoundError" ? l(o, {
355
- path: M(i.slice(0, s + 1)),
357
+ throw o.name === "NotFoundError" ? h(o, {
358
+ path: k(a.slice(0, s + 1)),
356
359
  existenceType: "directory"
357
- }) : o.name === "TypeMismatchError" ? l(o, { path: n, isDirectory: !1 }) : new x("create directory", n, o);
360
+ }) : o.name === "TypeMismatchError" ? h(o, { path: n, isDirectory: !1 }) : new F("create directory", n, o);
358
361
  }
359
362
  }
360
- await this.notifyChange({ path: t, type: h.Added, isDirectory: !0 });
363
+ await this.notifyChange({ path: t, type: l.Added, isDirectory: !0 });
361
364
  }
362
365
  /**
363
366
  * Get file or directory statistics
@@ -391,11 +394,11 @@ class j {
391
394
  isFile: !1,
392
395
  isDirectory: !0
393
396
  };
394
- const e = b(t);
395
- let a;
397
+ const e = v(t);
398
+ let r;
396
399
  try {
397
- a = await this.getDirectoryHandle(S(t), !1);
398
- 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 = {
399
402
  kind: "file",
400
403
  size: s.size,
401
404
  mtime: new Date(s.lastModified).toISOString(),
@@ -403,24 +406,24 @@ class j {
403
406
  isFile: !0,
404
407
  isDirectory: !1
405
408
  };
406
- if (i === "etag")
409
+ if (a === "etag")
407
410
  n.hash = `${s.lastModified.toString(36)}-${s.size.toString(36)}`;
408
- else if (typeof i == "string")
411
+ else if (typeof a == "string")
409
412
  try {
410
- const o = await T(s, i, this.options.maxFileSize);
413
+ const o = await M(s, a, this.options.maxFileSize);
411
414
  n.hash = o;
412
415
  } catch (o) {
413
416
  console.warn(`Failed to calculate hash for ${t}:`, o);
414
417
  }
415
418
  return n;
416
- } catch (i) {
417
- if (i.name === "NotFoundError")
418
- throw new m("file", t, i);
419
- if (i.name !== "TypeMismatchError")
420
- throw new x("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);
421
424
  }
422
425
  try {
423
- return await a.getDirectoryHandle(e, { create: !1 }), {
426
+ return await r.getDirectoryHandle(e, { create: !1 }), {
424
427
  kind: "directory",
425
428
  size: 0,
426
429
  mtime: (/* @__PURE__ */ new Date(0)).toISOString(),
@@ -428,8 +431,8 @@ class j {
428
431
  isFile: !1,
429
432
  isDirectory: !0
430
433
  };
431
- } catch (i) {
432
- throw new x("stat", t, i);
434
+ } catch (a) {
435
+ throw new F("stat", t, a);
433
436
  }
434
437
  }
435
438
  /**
@@ -452,17 +455,17 @@ class j {
452
455
  */
453
456
  async readDir(t) {
454
457
  await this.mount();
455
- const e = await this.getDirectoryHandle(t, !1), a = [];
456
- for await (const [i, r] of e.entries()) {
457
- const s = r.kind === "file";
458
- a.push({
459
- name: i,
460
- 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,
461
464
  isFile: s,
462
465
  isDirectory: !s
463
466
  });
464
467
  }
465
- return a;
468
+ return r;
466
469
  }
467
470
  /**
468
471
  * Check if a file or directory exists
@@ -481,26 +484,26 @@ class j {
481
484
  async exists(t) {
482
485
  if (await this.mount(), t === "/")
483
486
  return !0;
484
- const e = b(t);
485
- let a = null;
487
+ const e = v(t);
488
+ let r = null;
486
489
  try {
487
- a = await this.getDirectoryHandle(S(t), !1);
488
- } catch (i) {
489
- if (a = null, i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
490
- 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;
491
494
  }
492
- if (!a || !e)
495
+ if (!r || !e)
493
496
  return !1;
494
497
  try {
495
- return await a.getFileHandle(e, { create: !1 }), !0;
496
- } catch (i) {
497
- if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
498
- 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;
499
502
  try {
500
- return await a.getDirectoryHandle(e, { create: !1 }), !0;
501
- } catch (r) {
502
- if (r.name !== "NotFoundError" && r.name !== "TypeMismatchError")
503
- 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;
504
507
  return !1;
505
508
  }
506
509
  }
@@ -528,13 +531,13 @@ class j {
528
531
  await this.mount();
529
532
  try {
530
533
  const e = await this.readDir(t);
531
- for (const a of e) {
532
- const i = `${t === "/" ? "" : t}/${a.name}`;
533
- 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 });
534
537
  }
535
- await this.notifyChange({ path: t, type: h.Changed, isDirectory: !0 });
538
+ await this.notifyChange({ path: t, type: l.Changed, isDirectory: !0 });
536
539
  } catch (e) {
537
- throw e instanceof f ? e : l(e, { path: t, isDirectory: !0 });
540
+ throw e instanceof w ? e : h(e, { path: t, isDirectory: !0 });
538
541
  }
539
542
  }
540
543
  /**
@@ -563,9 +566,9 @@ class j {
563
566
  */
564
567
  async remove(t, e) {
565
568
  if (await this.mount(), t === "/")
566
- throw new $("EROOT", t);
567
- const { recursive: a = !1, force: i = !1 } = e || {}, r = await this.getDirectoryHandle(S(t), !1), s = await this.stat(t);
568
- await _(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 });
569
572
  }
570
573
  /**
571
574
  * Resolve a path to an absolute path
@@ -588,12 +591,12 @@ class j {
588
591
  async realpath(t) {
589
592
  await this.mount();
590
593
  try {
591
- const e = H(t);
594
+ const e = b(t);
592
595
  if (!await this.exists(e))
593
- throw new m("file", e);
596
+ throw new S("file", e);
594
597
  return e;
595
598
  } catch (e) {
596
- throw e instanceof f ? e : l(e, { path: t });
599
+ throw e instanceof w ? e : h(e, { path: t });
597
600
  }
598
601
  }
599
602
  /**
@@ -618,15 +621,15 @@ class j {
618
621
  * await fs.rename('/old/path/file.txt', '/new/path/renamed.txt', { overwrite: true });
619
622
  * ```
620
623
  */
621
- async rename(t, e, a) {
624
+ async rename(t, e, r) {
622
625
  await this.mount();
623
626
  try {
624
- const i = a?.overwrite ?? !1, r = await this.stat(t);
625
- if (await this.exists(e) && !i)
626
- throw new C(e);
627
- 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 });
628
- } catch (i) {
629
- 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 });
630
633
  }
631
634
  }
632
635
  /**
@@ -654,29 +657,29 @@ class j {
654
657
  * await fs.copy('/source', '/dest', { recursive: true, overwrite: false });
655
658
  * ```
656
659
  */
657
- async copy(t, e, a) {
660
+ async copy(t, e, r) {
658
661
  await this.mount();
659
662
  try {
660
- const i = a?.recursive ?? !1, r = a?.overwrite ?? !0;
663
+ const a = r?.recursive ?? !1, i = r?.overwrite ?? !0;
661
664
  if (!await this.exists(t))
662
- throw new m("source", t);
663
- if (await this.exists(e) && !r)
664
- throw new C(e);
665
+ throw new S("source", t);
666
+ if (await this.exists(e) && !i)
667
+ throw new H(e);
665
668
  if ((await this.stat(t)).isFile) {
666
669
  const c = await this.readFile(t);
667
670
  await this.writeFile(e, c);
668
671
  } else {
669
- if (!i)
670
- throw new N("directory", t);
672
+ if (!a)
673
+ throw new B("directory", t);
671
674
  await this.mkdir(e, { recursive: !0 });
672
675
  const c = await this.readDir(t);
673
- for (const w of c) {
674
- const y = `${t}/${w.name}`, d = `${e}/${w.name}`;
675
- await this.copy(y, d, { 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 });
676
679
  }
677
680
  }
678
- } catch (i) {
679
- throw i instanceof f ? i : l(i, { path: t });
681
+ } catch (a) {
682
+ throw a instanceof w ? a : h(a, { path: t });
680
683
  }
681
684
  }
682
685
  /**
@@ -706,13 +709,13 @@ class j {
706
709
  */
707
710
  async watch(t, e) {
708
711
  if (!this.options.broadcastChannel)
709
- throw new R("This instance is not configured to send events. Please specify options.broadcastChannel to enable watching.");
710
- const a = {
711
- 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),
712
715
  include: Array.isArray(e?.include) ? e.include : [e?.include ?? "**"],
713
716
  exclude: Array.isArray(e?.exclude) ? e.exclude : [e?.exclude ?? ""]
714
717
  };
715
- this.watchers.set(t, a);
718
+ this.watchers.set(t, r);
716
719
  }
717
720
  /**
718
721
  * Stop watching a previously watched path
@@ -749,18 +752,18 @@ class j {
749
752
  */
750
753
  async open(t, e) {
751
754
  await this.mount();
752
- const { create: a = !1, exclusive: i = !1, truncate: r = !1 } = e || {}, s = F(H(t));
755
+ const { create: r = !1, exclusive: a = !1, truncate: i = !1 } = e || {}, s = p(b(t));
753
756
  try {
754
- return a && i ? await u(s, "exclusive", async () => {
757
+ return r && a ? await u(s, async () => {
755
758
  if (await this.exists(s))
756
- throw new C(s);
757
- return this._openFile(s, a, r);
758
- }) : 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);
759
762
  } catch (n) {
760
- if (n instanceof f)
763
+ if (n instanceof w)
761
764
  throw n;
762
765
  const o = n && n.name === "TypeMismatchError";
763
- throw l(n, {
766
+ throw h(n, {
764
767
  path: s,
765
768
  isDirectory: !!o
766
769
  });
@@ -768,24 +771,31 @@ class j {
768
771
  }
769
772
  /**
770
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.
771
777
  * @private
772
778
  */
773
- async _openFile(t, e, a) {
774
- const i = await this.getFileHandle(t, e);
775
- try {
776
- await i.getFile();
777
- } catch (n) {
778
- 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);
779
790
  }
780
- const r = await U(i, t);
781
- a && (r.truncate(0), r.flush());
782
- const s = this.nextFd++;
783
- 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, {
784
794
  path: t,
785
- fileHandle: i,
786
- syncHandle: r,
795
+ fileHandle: a.fileHandle,
796
+ syncHandle: a.syncHandle,
787
797
  position: 0
788
- }), s;
798
+ }), i;
789
799
  }
790
800
  /**
791
801
  * Close a file descriptor
@@ -803,7 +813,9 @@ class j {
803
813
  */
804
814
  async close(t) {
805
815
  const e = this._getFileDescriptor(t);
806
- A(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)));
807
819
  }
808
820
  /**
809
821
  * Read data from a file descriptor
@@ -829,17 +841,17 @@ class j {
829
841
  * await fs.close(fd);
830
842
  * ```
831
843
  */
832
- async read(t, e, a, i, r) {
844
+ async read(t, e, r, a, i) {
833
845
  const s = this._getFileDescriptor(t);
834
- I(e.length, a, i, r);
846
+ I(e.length, r, a, i);
835
847
  try {
836
- 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);
837
849
  if (c)
838
- return p({ bytesRead: 0, buffer: e }, [e.buffer]);
839
- const y = e.subarray(a, a + w), d = s.syncHandle.read(y, { at: n });
840
- return r == null && (s.position = n + d), p({ bytesRead: d, 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]);
841
853
  } catch (n) {
842
- throw g("read", t, s.path, n);
854
+ throw m("read", t, s.path, n);
843
855
  }
844
856
  }
845
857
  /**
@@ -863,14 +875,14 @@ class j {
863
875
  * await fs.close(fd);
864
876
  * ```
865
877
  */
866
- async write(t, e, a = 0, i, r, s = !0) {
867
- const n = this._getFileDescriptor(t), o = i ?? e.length - a;
868
- I(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);
869
881
  try {
870
- const c = r ?? n.position, w = e.subarray(a, a + o), y = n.syncHandle.write(w, { at: c });
871
- 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;
872
884
  } catch (c) {
873
- throw g("write", t, n.path, c);
885
+ throw m("write", t, n.path, c);
874
886
  }
875
887
  }
876
888
  /**
@@ -912,13 +924,13 @@ class j {
912
924
  * ```
913
925
  */
914
926
  async ftruncate(t, e = 0) {
915
- const a = this._getFileDescriptor(t);
927
+ const r = this._getFileDescriptor(t);
916
928
  if (e < 0 || !Number.isInteger(e))
917
- throw new E("argument", "Invalid size");
929
+ throw new C("argument", "Invalid size");
918
930
  try {
919
- a.syncHandle.truncate(e), a.syncHandle.flush(), a.position > e && (a.position = e), await this.notifyChange({ path: a.path, type: h.Changed, isDirectory: !1 });
920
- } catch (i) {
921
- 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);
922
934
  }
923
935
  }
924
936
  /**
@@ -939,8 +951,8 @@ class j {
939
951
  const e = this._getFileDescriptor(t);
940
952
  try {
941
953
  e.syncHandle.flush();
942
- } catch (a) {
943
- throw g("sync", t, e.path, a);
954
+ } catch (r) {
955
+ throw m("sync", t, e.path, r);
944
956
  }
945
957
  }
946
958
  /**
@@ -951,9 +963,9 @@ class j {
951
963
  */
952
964
  dispose() {
953
965
  this.broadcastChannel && (this.broadcastChannel.close(), this.broadcastChannel = null), this.watchers.clear();
954
- for (const [t, e] of this.openFiles)
955
- A(t, e.syncHandle, e.path);
956
- 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;
957
969
  }
958
970
  /**
959
971
  * Synchronize the file system with external data
@@ -984,18 +996,61 @@ class j {
984
996
  async createIndex(t) {
985
997
  await this.mount();
986
998
  try {
987
- for (const [e, a] of t) {
988
- const i = F(e);
989
- let r;
990
- 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);
991
1003
  }
992
1004
  } catch (e) {
993
- throw e instanceof f ? e : l(e);
1005
+ throw e instanceof w ? e : h(e);
994
1006
  }
995
1007
  }
996
1008
  }
997
- typeof globalThis < "u" && globalThis.constructor.name === "DedicatedWorkerGlobalScope" && O(new j());
998
1009
  export {
999
- 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
1000
1055
  };
1001
- //# sourceMappingURL=raw.js.map
1056
+ //# sourceMappingURL=index.pure.js.map