opfs-worker 0.2.6 → 0.3.1

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/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
- import { wrap as i, proxy as o } from "comlink";
2
- import { D as d, F as p, O as u, b as y, a as w, P as m, c as g, S as v, T as F, e as S, k as E, d as b, l as P, h as x, o as T, f as A, m as O, g as D, j as _, n as I, i as C, r as k, s as U, w as R } from "./helpers-C0nyU6hv.js";
1
+ import { wrap as i } from "comlink";
2
+ import { D as d, F as f, O as p, b as u, a as y, P as m, c as w, S as g, T as v, e as b, k as E, d as S, l as F, h as P, o as x, f as D, m as T, g as C, j as A, n as O, i as _, r as I, s as U, w as R } from "./helpers-DxFcNkZe.js";
3
3
  const a = `/**
4
4
  * @license
5
5
  * Copyright 2019 Google LLC
6
6
  * SPDX-License-Identifier: Apache-2.0
7
7
  */
8
- const H = Symbol("Comlink.proxy"), R = Symbol("Comlink.endpoint"), B = Symbol("Comlink.releaseProxy"), D = Symbol("Comlink.finalizer"), E = Symbol("Comlink.thrown"), $ = (e) => typeof e == "object" && e !== null || typeof e == "function", W = {
8
+ const H = Symbol("Comlink.proxy"), R = Symbol("Comlink.endpoint"), B = Symbol("Comlink.releaseProxy"), C = Symbol("Comlink.finalizer"), p = Symbol("Comlink.thrown"), $ = (e) => typeof e == "object" && e !== null || typeof e == "function", W = {
9
9
  canHandle: (e) => $(e) && e[H],
10
10
  serialize(e) {
11
11
  const { port1: t, port2: r } = new MessageChannel();
12
- return I(e, t), [r, [r]];
12
+ return x(e, t), [r, [r]];
13
13
  },
14
14
  deserialize(e) {
15
15
  return e.start(), Y(e);
16
16
  }
17
17
  }, j = {
18
- canHandle: (e) => $(e) && E in e,
18
+ canHandle: (e) => $(e) && p in e,
19
19
  serialize({ value: e }) {
20
20
  let t;
21
21
  return e instanceof Error ? t = {
@@ -40,15 +40,15 @@ function V(e, t) {
40
40
  return !0;
41
41
  return !1;
42
42
  }
43
- function I(e, t = globalThis, r = ["*"]) {
44
- t.addEventListener("message", function n(i) {
45
- if (!i || !i.data)
43
+ function x(e, t = globalThis, r = ["*"]) {
44
+ t.addEventListener("message", function i(n) {
45
+ if (!n || !n.data)
46
46
  return;
47
- if (!V(r, i.origin)) {
48
- console.warn(\`Invalid origin '\${i.origin}' for comlink proxy\`);
47
+ if (!V(r, n.origin)) {
48
+ console.warn(\`Invalid origin '\${n.origin}' for comlink proxy\`);
49
49
  return;
50
50
  }
51
- const { id: a, type: s, path: o } = Object.assign({ path: [] }, i.data), l = (i.data.argumentList || []).map(y);
51
+ const { id: a, type: s, path: o } = Object.assign({ path: [] }, n.data), l = (n.data.argumentList || []).map(d);
52
52
  let h;
53
53
  try {
54
54
  const u = o.slice(0, -1).reduce((f, g) => f[g], e), w = o.reduce((f, g) => f[g], e);
@@ -57,7 +57,7 @@ function I(e, t = globalThis, r = ["*"]) {
57
57
  h = w;
58
58
  break;
59
59
  case "SET":
60
- u[o.slice(-1)[0]] = y(i.data.value), h = !0;
60
+ u[o.slice(-1)[0]] = d(n.data.value), h = !0;
61
61
  break;
62
62
  case "APPLY":
63
63
  h = w.apply(u, l);
@@ -71,7 +71,7 @@ function I(e, t = globalThis, r = ["*"]) {
71
71
  case "ENDPOINT":
72
72
  {
73
73
  const { port1: f, port2: g } = new MessageChannel();
74
- I(e, g), h = J(f, [f]);
74
+ x(e, g), h = J(f, [f]);
75
75
  }
76
76
  break;
77
77
  case "RELEASE":
@@ -81,15 +81,15 @@ function I(e, t = globalThis, r = ["*"]) {
81
81
  return;
82
82
  }
83
83
  } catch (u) {
84
- h = { value: u, [E]: 0 };
84
+ h = { value: u, [p]: 0 };
85
85
  }
86
- Promise.resolve(h).catch((u) => ({ value: u, [E]: 0 })).then((u) => {
86
+ Promise.resolve(h).catch((u) => ({ value: u, [p]: 0 })).then((u) => {
87
87
  const [w, f] = A(u);
88
- t.postMessage(Object.assign(Object.assign({}, w), { id: a }), f), s === "RELEASE" && (t.removeEventListener("message", n), L(t), D in e && typeof e[D] == "function" && e[D]());
88
+ t.postMessage(Object.assign(Object.assign({}, w), { id: a }), f), s === "RELEASE" && (t.removeEventListener("message", i), L(t), C in e && typeof e[C] == "function" && e[C]());
89
89
  }).catch((u) => {
90
90
  const [w, f] = A({
91
91
  value: new TypeError("Unserializable return value"),
92
- [E]: 0
92
+ [p]: 0
93
93
  });
94
94
  t.postMessage(Object.assign(Object.assign({}, w), { id: a }), f);
95
95
  });
@@ -103,8 +103,8 @@ function L(e) {
103
103
  }
104
104
  function Y(e, t) {
105
105
  const r = /* @__PURE__ */ new Map();
106
- return e.addEventListener("message", function(i) {
107
- const { data: a } = i;
106
+ return e.addEventListener("message", function(n) {
107
+ const { data: a } = n;
108
108
  if (!a || !a.id)
109
109
  return;
110
110
  const s = r.get(a.id);
@@ -116,81 +116,81 @@ function Y(e, t) {
116
116
  }
117
117
  }), M(e, r, [], t);
118
118
  }
119
- function p(e) {
119
+ function E(e) {
120
120
  if (e)
121
121
  throw new Error("Proxy has been released and is not useable");
122
122
  }
123
123
  function U(e) {
124
- return d(e, /* @__PURE__ */ new Map(), {
124
+ return y(e, /* @__PURE__ */ new Map(), {
125
125
  type: "RELEASE"
126
126
  }).then(() => {
127
127
  L(e);
128
128
  });
129
129
  }
130
- const F = /* @__PURE__ */ new WeakMap(), S = "FinalizationRegistry" in globalThis && new FinalizationRegistry((e) => {
131
- const t = (F.get(e) || 0) - 1;
132
- F.set(e, t), t === 0 && U(e);
130
+ const S = /* @__PURE__ */ new WeakMap(), D = "FinalizationRegistry" in globalThis && new FinalizationRegistry((e) => {
131
+ const t = (S.get(e) || 0) - 1;
132
+ S.set(e, t), t === 0 && U(e);
133
133
  });
134
134
  function X(e, t) {
135
- const r = (F.get(t) || 0) + 1;
136
- F.set(t, r), S && S.register(e, t, e);
135
+ const r = (S.get(t) || 0) + 1;
136
+ S.set(t, r), D && D.register(e, t, e);
137
137
  }
138
138
  function q(e) {
139
- S && S.unregister(e);
139
+ D && D.unregister(e);
140
140
  }
141
- function M(e, t, r = [], n = function() {
141
+ function M(e, t, r = [], i = function() {
142
142
  }) {
143
- let i = !1;
144
- const a = new Proxy(n, {
143
+ let n = !1;
144
+ const a = new Proxy(i, {
145
145
  get(s, o) {
146
- if (p(i), o === B)
146
+ if (E(n), o === B)
147
147
  return () => {
148
- q(a), U(e), t.clear(), i = !0;
148
+ q(a), U(e), t.clear(), n = !0;
149
149
  };
150
150
  if (o === "then") {
151
151
  if (r.length === 0)
152
152
  return { then: () => a };
153
- const l = d(e, t, {
153
+ const l = y(e, t, {
154
154
  type: "GET",
155
155
  path: r.map((h) => h.toString())
156
- }).then(y);
156
+ }).then(d);
157
157
  return l.then.bind(l);
158
158
  }
159
159
  return M(e, t, [...r, o]);
160
160
  },
161
161
  set(s, o, l) {
162
- p(i);
162
+ E(n);
163
163
  const [h, u] = A(l);
164
- return d(e, t, {
164
+ return y(e, t, {
165
165
  type: "SET",
166
166
  path: [...r, o].map((w) => w.toString()),
167
167
  value: h
168
- }, u).then(y);
168
+ }, u).then(d);
169
169
  },
170
170
  apply(s, o, l) {
171
- p(i);
171
+ E(n);
172
172
  const h = r[r.length - 1];
173
173
  if (h === R)
174
- return d(e, t, {
174
+ return y(e, t, {
175
175
  type: "ENDPOINT"
176
- }).then(y);
176
+ }).then(d);
177
177
  if (h === "bind")
178
178
  return M(e, t, r.slice(0, -1));
179
- const [u, w] = N(l);
180
- return d(e, t, {
179
+ const [u, w] = v(l);
180
+ return y(e, t, {
181
181
  type: "APPLY",
182
182
  path: r.map((f) => f.toString()),
183
183
  argumentList: u
184
- }, w).then(y);
184
+ }, w).then(d);
185
185
  },
186
186
  construct(s, o) {
187
- p(i);
188
- const [l, h] = N(o);
189
- return d(e, t, {
187
+ E(n);
188
+ const [l, h] = v(o);
189
+ return y(e, t, {
190
190
  type: "CONSTRUCT",
191
191
  path: r.map((u) => u.toString()),
192
192
  argumentList: l
193
- }, h).then(y);
193
+ }, h).then(d);
194
194
  }
195
195
  });
196
196
  return X(a, e), a;
@@ -198,7 +198,7 @@ function M(e, t, r = [], n = function() {
198
198
  function K(e) {
199
199
  return Array.prototype.concat.apply([], e);
200
200
  }
201
- function N(e) {
201
+ function v(e) {
202
202
  const t = e.map(A);
203
203
  return [t.map((r) => r[0]), K(t.map((r) => r[1]))];
204
204
  }
@@ -212,14 +212,14 @@ function Q(e) {
212
212
  function A(e) {
213
213
  for (const [t, r] of z)
214
214
  if (r.canHandle(e)) {
215
- const [n, i] = r.serialize(e);
215
+ const [i, n] = r.serialize(e);
216
216
  return [
217
217
  {
218
218
  type: "HANDLER",
219
219
  name: t,
220
- value: n
220
+ value: i
221
221
  },
222
- i
222
+ n
223
223
  ];
224
224
  }
225
225
  return [
@@ -230,7 +230,7 @@ function A(e) {
230
230
  _.get(e) || []
231
231
  ];
232
232
  }
233
- function y(e) {
233
+ function d(e) {
234
234
  switch (e.type) {
235
235
  case "HANDLER":
236
236
  return z.get(e.name).deserialize(e.value);
@@ -238,18 +238,18 @@ function y(e) {
238
238
  return e.value;
239
239
  }
240
240
  }
241
- function d(e, t, r, n) {
242
- return new Promise((i) => {
241
+ function y(e, t, r, i) {
242
+ return new Promise((n) => {
243
243
  const a = Z();
244
- t.set(a, i), e.start && e.start(), e.postMessage(Object.assign({ id: a }, r), n);
244
+ t.set(a, n), e.start && e.start(), e.postMessage(Object.assign({ id: a }, r), i);
245
245
  });
246
246
  }
247
247
  function Z() {
248
248
  return new Array(4).fill(0).map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)).join("-");
249
249
  }
250
250
  class c extends Error {
251
- constructor(t, r, n) {
252
- super(t), this.code = r, this.path = n, this.name = "OPFSError";
251
+ constructor(t, r, i) {
252
+ super(t), this.code = r, this.path = i, this.name = "OPFSError";
253
253
  }
254
254
  }
255
255
  class tt extends c {
@@ -257,17 +257,17 @@ class tt extends c {
257
257
  super("OPFS is not supported in this browser", "OPFS_NOT_SUPPORTED");
258
258
  }
259
259
  }
260
- class T extends c {
260
+ class b extends c {
261
261
  constructor() {
262
262
  super("OPFS is not mounted", "OPFS_NOT_MOUNTED");
263
263
  }
264
264
  }
265
- class k extends c {
265
+ class N extends c {
266
266
  constructor(t, r) {
267
267
  super(t, "INVALID_PATH", r);
268
268
  }
269
269
  }
270
- class O extends c {
270
+ class T extends c {
271
271
  constructor(t) {
272
272
  super(\`File not found: \${t}\`, "FILE_NOT_FOUND", t);
273
273
  }
@@ -323,8 +323,8 @@ function rt(e, t = "utf-8") {
323
323
  function nt(e) {
324
324
  const t = new Uint8Array(e.length * 2);
325
325
  for (let r = 0; r < e.length; r++) {
326
- const n = e.charCodeAt(r);
327
- t[r * 2] = n & 255, t[r * 2 + 1] = n >> 8;
326
+ const i = e.charCodeAt(r);
327
+ t[r * 2] = i & 255, t[r * 2 + 1] = i >> 8;
328
328
  }
329
329
  return t;
330
330
  }
@@ -350,33 +350,33 @@ function ot() {
350
350
  throw new tt();
351
351
  }
352
352
  function m(e) {
353
- return Array.isArray(e) ? e : e.split("/").filter(Boolean);
353
+ return Array.isArray(e) ? e : (e.startsWith("~/") ? e.slice(2) : e).split("/").filter(Boolean);
354
354
  }
355
- function P(e) {
355
+ function I(e) {
356
356
  return typeof e == "string" ? e ?? "/" : \`/\${e.join("/")}\`;
357
357
  }
358
- function b(e) {
358
+ function O(e) {
359
359
  const t = m(e);
360
360
  return t[t.length - 1] || "";
361
361
  }
362
- function x(e) {
362
+ function P(e) {
363
363
  const t = m(e);
364
- return t.pop(), P(t);
364
+ return t.pop(), I(t);
365
365
  }
366
- function C(e) {
367
- return !e || e === "/" ? "/" : e.startsWith("/") ? e : \`/\${e}\`;
366
+ function F(e) {
367
+ return !e || e === "/" ? "/" : e.startsWith("~/") ? \`/\${e.slice(2)}\` : e.startsWith("/") ? e : \`/\${e}\`;
368
368
  }
369
369
  function ct(e) {
370
- const t = m(e), r = [];
371
- for (const n of t)
370
+ const t = F(e), r = m(t), i = [];
371
+ for (const n of r)
372
372
  if (!(n === "." || n === ""))
373
373
  if (n === "..") {
374
- if (r.length === 0)
374
+ if (i.length === 0)
375
375
  continue;
376
- r.pop();
376
+ i.pop();
377
377
  } else
378
- r.push(n);
379
- return P(r);
378
+ i.push(n);
379
+ return I(i);
380
380
  }
381
381
  function lt(e, t = "utf-8") {
382
382
  return typeof e == "string" ? et(e, t) : e instanceof Uint8Array ? e : new Uint8Array(e);
@@ -384,26 +384,26 @@ function lt(e, t = "utf-8") {
384
384
  async function ht(e) {
385
385
  const t = await e.createSyncAccessHandle();
386
386
  try {
387
- const r = t.getSize(), n = new Uint8Array(r);
388
- return t.read(n, { at: 0 }), n;
387
+ const r = t.getSize(), i = new Uint8Array(r);
388
+ return t.read(i, { at: 0 }), i;
389
389
  } finally {
390
390
  t.close();
391
391
  }
392
392
  }
393
- async function v(e, t, r, n = {}) {
394
- let i = null;
393
+ async function k(e, t, r, i = {}) {
394
+ let n = null;
395
395
  try {
396
- i = await e.createSyncAccessHandle();
397
- const a = lt(t, r), s = n.append ? i.getSize() : 0;
398
- i.write(a, { at: s }), n.truncate && !n.append && i.truncate(a.byteLength), i.flush();
396
+ n = await e.createSyncAccessHandle();
397
+ const a = lt(t, r), s = i.append ? n.getSize() : 0;
398
+ n.write(a, { at: s }), i.truncate && !i.append && n.truncate(a.byteLength), n.flush();
399
399
  } catch (a) {
400
400
  console.error(a);
401
- const s = n.append ? "append" : "write";
401
+ const s = i.append ? "append" : "write";
402
402
  throw new c(\`Failed to \${s} file\`, \`\${s.toUpperCase()}_FAILED\`);
403
403
  } finally {
404
- if (i)
404
+ if (n)
405
405
  try {
406
- i.close();
406
+ n.close();
407
407
  } catch {
408
408
  }
409
409
  }
@@ -411,8 +411,8 @@ async function v(e, t, r, n = {}) {
411
411
  async function ut(e, t = "SHA-1", r = 50 * 1024 * 1024) {
412
412
  if (e instanceof File && (e = await e.arrayBuffer()), e.byteLength > r)
413
413
  throw new Error(\`File size \${e.byteLength} bytes exceeds maximum allowed size \${r} bytes\`);
414
- const n = new Uint8Array(e), i = await crypto.subtle.digest(t, n);
415
- return Array.from(new Uint8Array(i)).map((s) => s.toString(16).padStart(2, "0")).join("");
414
+ const i = new Uint8Array(e), n = await crypto.subtle.digest(t, i);
415
+ return Array.from(new Uint8Array(n)).map((s) => s.toString(16).padStart(2, "0")).join("");
416
416
  }
417
417
  async function ft(e) {
418
418
  const t = await e.arrayBuffer();
@@ -421,8 +421,6 @@ async function ft(e) {
421
421
  class wt {
422
422
  /** Root directory handle for the file system */
423
423
  root = null;
424
- /** Watch event callback */
425
- watchCallback = null;
426
424
  /** Map of watched paths to their last known state */
427
425
  watchers = /* @__PURE__ */ new Map();
428
426
  /** Interval handle for polling watched paths */
@@ -431,11 +429,14 @@ class wt {
431
429
  scanning = !1;
432
430
  /** Promise to prevent concurrent mount operations */
433
431
  mountingPromise = null;
432
+ /** BroadcastChannel instance for sending events */
433
+ broadcastChannel = null;
434
434
  /** Configuration options */
435
435
  options = {
436
436
  watchInterval: 1e3,
437
437
  maxFileSize: 50 * 1024 * 1024,
438
- hashAlgorithm: null
438
+ hashAlgorithm: null,
439
+ broadcastChannel: "opfs-worker"
439
440
  };
440
441
  /**
441
442
  * Notify about internal changes to the file system
@@ -447,34 +448,39 @@ class wt {
447
448
  * @param type - The type of change (create, change, delete)
448
449
  */
449
450
  async notifyChange(t) {
450
- if (!this.watchCallback)
451
+ if (!this.options.broadcastChannel)
451
452
  return;
452
453
  let r;
453
454
  if (this.options.hashAlgorithm && !t.isDirectory && t.type !== "removed")
454
455
  try {
455
- const n = await this.stat(t.path);
456
- n.isFile && n.hash && (r = n.hash);
457
- } catch (n) {
458
- console.warn(\`Failed to calculate hash for \${t.path}:\`, n);
456
+ const i = await this.stat(t.path);
457
+ i.isFile && i.hash && (r = i.hash);
458
+ } catch (i) {
459
+ console.warn(\`Failed to calculate hash for \${t.path}:\`, i);
459
460
  }
460
- this.watchCallback({
461
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
462
- ...t,
463
- ...r && { hash: r }
464
- });
461
+ try {
462
+ this.broadcastChannel || (this.broadcastChannel = new BroadcastChannel(this.options.broadcastChannel));
463
+ const i = {
464
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
465
+ ...t,
466
+ ...r && { hash: r }
467
+ };
468
+ this.broadcastChannel.postMessage(i);
469
+ } catch (i) {
470
+ console.warn("Failed to send event via BroadcastChannel:", i);
471
+ }
465
472
  }
466
473
  /**
467
474
  * Creates a new OPFSFileSystem instance
468
475
  *
469
- * @param watchCallback - Optional callback for file change events
470
476
  * @param options - Optional configuration options
471
477
  * @param options.watchInterval - Polling interval in milliseconds for file watching
472
478
  * @param options.hashAlgorithm - Hash algorithm for file hashing
473
479
  * @param options.maxFileSize - Maximum file size for hashing in bytes (default: 50MB)
474
480
  * @throws {OPFSError} If OPFS is not supported in the current browser
475
481
  */
476
- constructor(t, r) {
477
- ot(), t && (this.watchCallback = t), r && this.setOptions(r), this.mount("/");
482
+ constructor(t) {
483
+ ot(), t && this.setOptions(t), this.mount("/");
478
484
  }
479
485
  /**
480
486
  * Initialize the file system within a given directory
@@ -498,26 +504,18 @@ class wt {
498
504
  * \`\`\`
499
505
  */
500
506
  async mount(t = "/") {
501
- return this.mountingPromise && await this.mountingPromise, this.mountingPromise = new Promise(async (r, n) => {
507
+ return this.mountingPromise && await this.mountingPromise, this.mountingPromise = new Promise(async (r, i) => {
502
508
  this.root = null;
503
509
  try {
504
- const i = await navigator.storage.getDirectory();
505
- t === "/" ? this.root = i : this.root = await this.getDirectoryHandle(t, !0, i), r(!0);
506
- } catch (i) {
507
- console.error(i), n(new c("Failed to initialize OPFS", "INIT_FAILED"));
510
+ const n = await navigator.storage.getDirectory();
511
+ t === "/" ? this.root = n : this.root = await this.getDirectoryHandle(t, !0, n), r(!0);
512
+ } catch (n) {
513
+ console.error(n), i(new c("Failed to initialize OPFS", "INIT_FAILED"));
508
514
  } finally {
509
515
  this.mountingPromise = null;
510
516
  }
511
517
  }), this.mountingPromise;
512
518
  }
513
- /**
514
- * Set the watch callback for file change events
515
- *
516
- * @param callback - The callback function to invoke when files change
517
- */
518
- setWatchCallback(t) {
519
- this.watchCallback = t;
520
- }
521
519
  /**
522
520
  * Update configuration options
523
521
  *
@@ -525,9 +523,10 @@ class wt {
525
523
  * @param options.watchInterval - Polling interval in milliseconds for file watching
526
524
  * @param options.hashAlgorithm - Hash algorithm for file hashing
527
525
  * @param options.maxFileSize - Maximum file size for hashing in bytes
526
+ * @param options.broadcastChannel - Custom name for the broadcast channel
528
527
  */
529
528
  setOptions(t) {
530
- t.watchInterval !== void 0 && (this.options.watchInterval = t.watchInterval), t.hashAlgorithm !== void 0 && (this.options.hashAlgorithm = t.hashAlgorithm), t.maxFileSize !== void 0 && (this.options.maxFileSize = t.maxFileSize);
529
+ t.watchInterval !== void 0 && (this.options.watchInterval = t.watchInterval), 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);
531
530
  }
532
531
  /**
533
532
  * Automatically mount the OPFS root if not already mounted
@@ -565,12 +564,12 @@ class wt {
565
564
  * const docsDir2 = await fs.getDirectoryHandle(['users', 'john', 'documents'], true);
566
565
  * \`\`\`
567
566
  */
568
- async getDirectoryHandle(t, r = !1, n = this.root) {
569
- if (!n)
570
- throw new T();
571
- const i = Array.isArray(t) ? t : m(t);
572
- let a = n;
573
- for (const s of i)
567
+ async getDirectoryHandle(t, r = !1, i = this.root) {
568
+ if (!i)
569
+ throw new b();
570
+ const n = Array.isArray(t) ? t : m(t);
571
+ let a = i;
572
+ for (const s of n)
574
573
  a = await a.getDirectoryHandle(s, { create: r });
575
574
  return a;
576
575
  }
@@ -593,14 +592,14 @@ class wt {
593
592
  * const fileHandle2 = await fs.getFileHandle(['config', 'settings.json'], true);
594
593
  * \`\`\`
595
594
  */
596
- async getFileHandle(t, r = !1, n = this.root) {
597
- if (!n)
598
- throw new T();
599
- const i = m(t);
600
- if (i.length === 0)
601
- throw new k("Path must not be empty", Array.isArray(t) ? t.join("/") : t);
602
- const a = i.pop();
603
- return (await this.getDirectoryHandle(i, r, n)).getFileHandle(a, { create: r });
595
+ async getFileHandle(t, r = !1, i = this.root) {
596
+ if (!i)
597
+ throw new b();
598
+ const n = m(t);
599
+ if (n.length === 0)
600
+ throw new N("Path must not be empty", Array.isArray(t) ? t.join("/") : t);
601
+ const a = n.pop();
602
+ return (await this.getDirectoryHandle(n, r, i)).getFileHandle(a, { create: r });
604
603
  }
605
604
  /**
606
605
  * Get a complete index of all files and directories in the file system
@@ -622,10 +621,10 @@ class wt {
622
621
  * \`\`\`
623
622
  */
624
623
  async index() {
625
- const t = /* @__PURE__ */ new Map(), r = async (n) => {
626
- const i = await this.readdir(n, { withFileTypes: !0 });
627
- for (const a of i) {
628
- const s = \`\${n === "/" ? "" : n}/\${a.name}\`;
624
+ const t = /* @__PURE__ */ new Map(), r = async (i) => {
625
+ const n = await this.readDir(i);
626
+ for (const a of n) {
627
+ const s = \`\${i === "/" ? "" : i}/\${a.name}\`;
629
628
  try {
630
629
  const o = await this.stat(s);
631
630
  t.set(s, o), o.isDirectory && await r(s);
@@ -646,10 +645,10 @@ class wt {
646
645
  async readFile(t, r = "utf-8") {
647
646
  await this.ensureMounted();
648
647
  try {
649
- const n = await this.getFileHandle(t, !1), i = await ht(n);
650
- return r === "binary" ? i : rt(i, r);
651
- } catch (n) {
652
- throw console.error(n), new O(t);
648
+ const i = await this.getFileHandle(t, !1), n = await ht(i);
649
+ return r === "binary" ? n : rt(n, r);
650
+ } catch (i) {
651
+ throw console.error(i), new T(t);
653
652
  }
654
653
  }
655
654
  /**
@@ -677,10 +676,10 @@ class wt {
677
676
  * await fs.writeFile('/data/utf16.txt', 'Hello World', 'utf-16le');
678
677
  * \`\`\`
679
678
  */
680
- async writeFile(t, r, n) {
679
+ async writeFile(t, r, i) {
681
680
  await this.ensureMounted();
682
- const i = await this.getFileHandle(t, !0);
683
- await v(i, r, n, { truncate: !0 }), await this.notifyChange({ path: t, type: "changed", isDirectory: !1 });
681
+ const n = await this.getFileHandle(t, !0);
682
+ await k(n, r, i, { truncate: !0 }), await this.notifyChange({ path: t, type: "changed", isDirectory: !1 });
684
683
  }
685
684
  /**
686
685
  * Append data to a file
@@ -704,10 +703,10 @@ class wt {
704
703
  * await fs.appendFile('/data/binary.dat', additionalData);
705
704
  * \`\`\`
706
705
  */
707
- async appendFile(t, r, n) {
706
+ async appendFile(t, r, i) {
708
707
  await this.ensureMounted();
709
- const i = await this.getFileHandle(t, !0);
710
- await v(i, r, n, { append: !0 }), await this.notifyChange({ path: t, type: "changed", isDirectory: !1 });
708
+ const n = await this.getFileHandle(t, !0);
709
+ await k(n, r, i, { append: !0 }), await this.notifyChange({ path: t, type: "changed", isDirectory: !1 });
711
710
  }
712
711
  /**
713
712
  * Create a directory
@@ -732,16 +731,16 @@ class wt {
732
731
  */
733
732
  async mkdir(t, r) {
734
733
  if (await this.ensureMounted(), !this.root)
735
- throw new T();
736
- const n = r?.recursive ?? !1, i = m(t);
734
+ throw new b();
735
+ const i = r?.recursive ?? !1, n = m(t);
737
736
  let a = this.root;
738
- for (let s = 0; s < i.length; s++) {
739
- const o = i[s];
737
+ for (let s = 0; s < n.length; s++) {
738
+ const o = n[s];
740
739
  try {
741
- a = await a.getDirectoryHandle(o, { create: n || s === i.length - 1 });
740
+ a = await a.getDirectoryHandle(o, { create: i || s === n.length - 1 });
742
741
  } catch (l) {
743
742
  throw l.name === "NotFoundError" ? new c(
744
- \`Parent directory does not exist: \${P(i.slice(0, s + 1))}\`,
743
+ \`Parent directory does not exist: \${I(n.slice(0, s + 1))}\`,
745
744
  "ENOENT"
746
745
  ) : l.name === "TypeMismatchError" ? new c(\`Path segment is not a directory: \${o}\`, "ENOTDIR") : new c("Failed to create directory", "MKDIR_FAILED");
747
746
  }
@@ -780,9 +779,9 @@ class wt {
780
779
  isFile: !1,
781
780
  isDirectory: !0
782
781
  };
783
- const r = b(t), n = await this.getDirectoryHandle(x(t), !1), i = this.options.hashAlgorithm !== null;
782
+ const r = O(t), i = await this.getDirectoryHandle(P(t), !1), n = this.options.hashAlgorithm !== null;
784
783
  try {
785
- const s = await (await n.getFileHandle(r, { create: !1 })).getFile(), o = {
784
+ const s = await (await i.getFileHandle(r, { create: !1 })).getFile(), o = {
786
785
  kind: "file",
787
786
  size: s.size,
788
787
  mtime: new Date(s.lastModified).toISOString(),
@@ -790,7 +789,7 @@ class wt {
790
789
  isFile: !0,
791
790
  isDirectory: !1
792
791
  };
793
- if (i && this.options.hashAlgorithm)
792
+ if (n && this.options.hashAlgorithm)
794
793
  try {
795
794
  const l = await ut(s, this.options.hashAlgorithm, this.options.maxFileSize);
796
795
  o.hash = l;
@@ -803,7 +802,7 @@ class wt {
803
802
  throw new c("Failed to stat (file)", "STAT_FAILED");
804
803
  }
805
804
  try {
806
- return await n.getDirectoryHandle(r, { create: !1 }), {
805
+ return await i.getDirectoryHandle(r, { create: !1 }), {
807
806
  kind: "directory",
808
807
  size: 0,
809
808
  mtime: (/* @__PURE__ */ new Date(0)).toISOString(),
@@ -815,27 +814,37 @@ class wt {
815
814
  throw a.name === "NotFoundError" ? new c(\`No such file or directory: \${t}\`, "ENOENT") : new c("Failed to stat (directory)", "STAT_FAILED");
816
815
  }
817
816
  }
818
- async readdir(t, r) {
817
+ /**
818
+ * Read a directory's contents
819
+ *
820
+ * Lists all files and subdirectories within the specified directory.
821
+ *
822
+ * @param path - The path to the directory to read
823
+ * @returns Promise that resolves to an array of detailed file/directory information
824
+ * @throws {OPFSError} If the directory does not exist or cannot be accessed
825
+ *
826
+ * @example
827
+ * \`\`\`typescript
828
+ * // Get detailed information about files and directories
829
+ * const detailed = await fs.readDir('/users/john/documents');
830
+ * detailed.forEach(item => {
831
+ * console.log(\`\${item.name} - \${item.isFile ? 'file' : 'directory'}\`);
832
+ * });
833
+ * \`\`\`
834
+ */
835
+ async readDir(t) {
819
836
  await this.ensureMounted();
820
- const n = r?.withFileTypes ?? !1, i = await this.getDirectoryHandle(t, !1);
821
- if (n) {
822
- const a = [];
823
- for await (const [s, o] of i.entries()) {
824
- const l = o.kind === "file";
825
- a.push({
826
- name: s,
827
- kind: o.kind,
828
- isFile: l,
829
- isDirectory: !l
830
- });
831
- }
832
- return a;
833
- } else {
834
- const a = [];
835
- for await (const [s] of i.entries())
836
- a.push(s);
837
- return a;
837
+ const r = await this.getDirectoryHandle(t, !1), i = [];
838
+ for await (const [n, a] of r.entries()) {
839
+ const s = a.kind === "file";
840
+ i.push({
841
+ name: n,
842
+ kind: a.kind,
843
+ isFile: s,
844
+ isDirectory: !s
845
+ });
838
846
  }
847
+ return i;
839
848
  }
840
849
  /**
841
850
  * Check if a file or directory exists
@@ -854,26 +863,26 @@ class wt {
854
863
  async exists(t) {
855
864
  if (await this.ensureMounted(), t === "/")
856
865
  return !0;
857
- const r = b(t);
858
- let n = null;
866
+ const r = O(t);
867
+ let i = null;
859
868
  try {
860
- n = await this.getDirectoryHandle(x(t), !1);
861
- } catch (i) {
862
- throw (i.name === "NotFoundError" || i.name === "TypeMismatchError") && (n = null), i;
869
+ i = await this.getDirectoryHandle(P(t), !1);
870
+ } catch (n) {
871
+ throw (n.name === "NotFoundError" || n.name === "TypeMismatchError") && (i = null), n;
863
872
  }
864
- if (!n || !r)
873
+ if (!i || !r)
865
874
  return !1;
866
875
  try {
867
- return await n.getFileHandle(r, { create: !1 }), !0;
868
- } catch (i) {
869
- if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
870
- throw i;
876
+ return await i.getFileHandle(r, { create: !1 }), !0;
877
+ } catch (n) {
878
+ if (n.name !== "NotFoundError" && n.name !== "TypeMismatchError")
879
+ throw n;
871
880
  }
872
881
  try {
873
- return await n.getDirectoryHandle(r, { create: !1 }), !0;
874
- } catch (i) {
875
- if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
876
- throw i;
882
+ return await i.getDirectoryHandle(r, { create: !1 }), !0;
883
+ } catch (n) {
884
+ if (n.name !== "NotFoundError" && n.name !== "TypeMismatchError")
885
+ throw n;
877
886
  }
878
887
  return !1;
879
888
  }
@@ -899,10 +908,10 @@ class wt {
899
908
  async clear(t = "/") {
900
909
  await this.ensureMounted();
901
910
  try {
902
- const r = await this.readdir(t, { withFileTypes: !0 });
903
- for (const n of r) {
904
- const i = \`\${t === "/" ? "" : t}/\${n.name}\`;
905
- await this.remove(i, { recursive: !0 });
911
+ const r = await this.readDir(t);
912
+ for (const i of r) {
913
+ const n = \`\${t === "/" ? "" : t}/\${i.name}\`;
914
+ await this.remove(n, { recursive: !0 });
906
915
  }
907
916
  await this.notifyChange({ path: t, type: "changed", isDirectory: !0 });
908
917
  } catch (r) {
@@ -935,20 +944,20 @@ class wt {
935
944
  */
936
945
  async remove(t, r) {
937
946
  await this.ensureMounted();
938
- const n = r?.recursive ?? !1, i = r?.force ?? !1;
947
+ const i = r?.recursive ?? !1, n = r?.force ?? !1;
939
948
  if (t === "/")
940
949
  throw new c("Cannot remove root directory", "EROOT");
941
- const a = b(t);
950
+ const a = O(t);
942
951
  if (!a)
943
- throw new k("Invalid path", t);
944
- const s = await this.getDirectoryHandle(x(t), !1);
952
+ throw new N("Invalid path", t);
953
+ const s = await this.getDirectoryHandle(P(t), !1);
945
954
  try {
946
- await s.removeEntry(a, { recursive: n });
955
+ await s.removeEntry(a, { recursive: i });
947
956
  } catch (o) {
948
957
  if (o.name === "NotFoundError") {
949
- if (!i)
958
+ if (!n)
950
959
  throw new c(\`No such file or directory: \${t}\`, "ENOENT");
951
- } else throw o.name === "InvalidModificationError" ? new c(\`Directory not empty: \${t}. Use recursive option to force removal.\`, "ENOTEMPTY") : o.name === "TypeMismatchError" && !n ? new c(\`Cannot remove directory without recursive option: \${t}\`, "EISDIR") : new c(\`Failed to remove path: \${t}\`, "RM_FAILED");
960
+ } else throw o.name === "InvalidModificationError" ? new c(\`Directory not empty: \${t}. Use recursive option to force removal.\`, "ENOTEMPTY") : o.name === "TypeMismatchError" && !i ? new c(\`Cannot remove directory without recursive option: \${t}\`, "EISDIR") : new c(\`Failed to remove path: \${t}\`, "RM_FAILED");
952
961
  }
953
962
  await this.notifyChange({ path: t, type: "removed", isDirectory: !1 });
954
963
  }
@@ -975,7 +984,7 @@ class wt {
975
984
  try {
976
985
  const r = ct(t);
977
986
  if (!await this.exists(r))
978
- throw new O(r);
987
+ throw new T(r);
979
988
  return r;
980
989
  } catch (r) {
981
990
  throw r instanceof c ? r : new c(\`Failed to resolve path: \${t}\`, "REALPATH_FAILED");
@@ -1001,10 +1010,10 @@ class wt {
1001
1010
  await this.ensureMounted();
1002
1011
  try {
1003
1012
  if (!await this.exists(t))
1004
- throw new O(t);
1013
+ throw new T(t);
1005
1014
  await this.copy(t, r, { recursive: !0 }), await this.remove(t, { recursive: !0 }), await this.notifyChange({ path: t, type: "removed", isDirectory: !1 }), await this.notifyChange({ path: r, type: "added", isDirectory: !1 });
1006
- } catch (n) {
1007
- throw n instanceof c ? n : new c(\`Failed to rename from \${t} to \${r}\`, "RENAME_FAILED");
1015
+ } catch (i) {
1016
+ throw i instanceof c ? i : new c(\`Failed to rename from \${t} to \${r}\`, "RENAME_FAILED");
1008
1017
  }
1009
1018
  }
1010
1019
  /**
@@ -1032,10 +1041,10 @@ class wt {
1032
1041
  * await fs.copy('/source', '/dest', { recursive: true, force: false });
1033
1042
  * \`\`\`
1034
1043
  */
1035
- async copy(t, r, n) {
1044
+ async copy(t, r, i) {
1036
1045
  await this.ensureMounted();
1037
1046
  try {
1038
- const i = n?.recursive ?? !1, a = n?.force ?? !0;
1047
+ const n = i?.recursive ?? !1, a = i?.force ?? !0;
1039
1048
  if (!await this.exists(t))
1040
1049
  throw new c(\`Source does not exist: \${t}\`, "ENOENT");
1041
1050
  if (await this.exists(r) && !a)
@@ -1044,18 +1053,18 @@ class wt {
1044
1053
  const h = await this.readFile(t, "binary");
1045
1054
  await this.writeFile(r, h);
1046
1055
  } else {
1047
- if (!i)
1056
+ if (!n)
1048
1057
  throw new c(\`Cannot copy directory without recursive option: \${t}\`, "EISDIR");
1049
1058
  await this.mkdir(r, { recursive: !0 });
1050
- const h = await this.readdir(t, { withFileTypes: !0 });
1059
+ const h = await this.readDir(t);
1051
1060
  for (const u of h) {
1052
1061
  const w = \`\${t}/\${u.name}\`, f = \`\${r}/\${u.name}\`;
1053
1062
  await this.copy(w, f, { recursive: !0, force: a });
1054
1063
  }
1055
1064
  }
1056
1065
  await this.notifyChange({ path: r, type: "added", isDirectory: !1 });
1057
- } catch (i) {
1058
- throw i instanceof c ? i : new c(\`Failed to copy from \${t} to \${r}\`, "CP_FAILED");
1066
+ } catch (n) {
1067
+ throw n instanceof c ? n : new c(\`Failed to copy from \${t} to \${r}\`, "CP_FAILED");
1059
1068
  }
1060
1069
  }
1061
1070
  /**
@@ -1063,8 +1072,8 @@ class wt {
1063
1072
  */
1064
1073
  async watch(t) {
1065
1074
  await this.ensureMounted();
1066
- const r = C(t), n = await this.buildSnapshot(r);
1067
- this.watchers.set(r, n), this.watchTimer || (this.watchTimer = setInterval(() => {
1075
+ const r = F(t), i = await this.buildSnapshot(r);
1076
+ this.watchers.set(r, i), this.watchTimer || (this.watchTimer = setInterval(() => {
1068
1077
  this.scanWatches();
1069
1078
  }, this.options.watchInterval));
1070
1079
  }
@@ -1072,21 +1081,30 @@ class wt {
1072
1081
  * Stop watching a previously watched path
1073
1082
  */
1074
1083
  unwatch(t) {
1075
- const r = C(t);
1084
+ const r = F(t);
1076
1085
  this.watchers.delete(r), this.watchers.size === 0 && this.watchTimer && (clearInterval(this.watchTimer), this.watchTimer = null);
1077
1086
  }
1087
+ /**
1088
+ * Dispose of resources and clean up the file system instance
1089
+ *
1090
+ * This method should be called when the file system instance is no longer needed
1091
+ * to properly clean up resources like the broadcast channel and watch timers.
1092
+ */
1093
+ dispose() {
1094
+ this.broadcastChannel && (this.broadcastChannel.close(), this.broadcastChannel = null), this.watchTimer && (clearInterval(this.watchTimer), this.watchTimer = null), this.watchers.clear();
1095
+ }
1078
1096
  async buildSnapshot(t) {
1079
- const r = /* @__PURE__ */ new Map(), n = async (i) => {
1080
- const a = await this.stat(i);
1081
- if (r.set(i, a), a.isDirectory) {
1082
- const s = await this.readdir(i, { withFileTypes: !0 });
1097
+ const r = /* @__PURE__ */ new Map(), i = async (n) => {
1098
+ const a = await this.stat(n);
1099
+ if (r.set(n, a), a.isDirectory) {
1100
+ const s = await this.readDir(n);
1083
1101
  for (const o of s) {
1084
- const l = \`\${i === "/" ? "" : i}/\${o.name}\`;
1085
- await n(l);
1102
+ const l = \`\${n === "/" ? "" : n}/\${o.name}\`;
1103
+ await i(l);
1086
1104
  }
1087
1105
  }
1088
1106
  };
1089
- return await n(t), r;
1107
+ return await i(t), r;
1090
1108
  }
1091
1109
  async scanWatches() {
1092
1110
  if (!this.scanning) {
@@ -1094,19 +1112,22 @@ class wt {
1094
1112
  try {
1095
1113
  await Promise.all(
1096
1114
  [...this.watchers.entries()].map(async ([t, r]) => {
1097
- let n;
1115
+ let i;
1098
1116
  try {
1099
- n = await this.buildSnapshot(t);
1117
+ i = await this.buildSnapshot(t);
1100
1118
  } catch {
1101
- n = /* @__PURE__ */ new Map();
1119
+ i = /* @__PURE__ */ new Map();
1102
1120
  }
1103
- for (const [i, a] of n) {
1104
- const s = r.get(i);
1105
- s ? (s.mtime !== a.mtime || s.size !== a.size) && await this.notifyChange({ path: i, type: "changed", isDirectory: !1 }) : await this.notifyChange({ path: i, type: "added", isDirectory: !1 });
1121
+ for (const [n, a] of i) {
1122
+ const s = r.get(n);
1123
+ s ? (s.mtime !== a.mtime || s.size !== a.size) && await this.notifyChange({ path: n, type: "changed", isDirectory: a.isDirectory }) : await this.notifyChange({ path: n, type: "added", isDirectory: a.isDirectory });
1106
1124
  }
1107
- for (const i of r.keys())
1108
- n.has(i) || await this.notifyChange({ path: i, type: "removed", isDirectory: !1 });
1109
- this.watchers.set(t, n);
1125
+ for (const n of r.keys())
1126
+ if (!i.has(n)) {
1127
+ const a = r.get(n);
1128
+ await this.notifyChange({ path: n, type: "removed", isDirectory: a?.isDirectory ?? !1 });
1129
+ }
1130
+ this.watchers.set(t, i);
1110
1131
  })
1111
1132
  );
1112
1133
  } finally {
@@ -1146,72 +1167,69 @@ class wt {
1146
1167
  await this.ensureMounted();
1147
1168
  try {
1148
1169
  (r?.cleanBefore ?? !1) && await this.clear("/");
1149
- for (const [i, a] of t) {
1150
- const s = C(i);
1170
+ for (const [n, a] of t) {
1171
+ const s = F(n);
1151
1172
  let o;
1152
1173
  a instanceof Blob ? o = await ft(a) : o = a, await this.writeFile(s, o);
1153
1174
  }
1154
1175
  await this.notifyChange({ path: "/", type: "changed", isDirectory: !0 });
1155
- } catch (n) {
1156
- throw n instanceof c ? n : new c("Failed to sync file system", "SYNC_FAILED");
1176
+ } catch (i) {
1177
+ throw i instanceof c ? i : new c("Failed to sync file system", "SYNC_FAILED");
1157
1178
  }
1158
1179
  }
1159
1180
  }
1160
- typeof self < "u" && self.constructor.name === "DedicatedWorkerGlobalScope" && I(new wt());
1161
- //# sourceMappingURL=worker-CHy3JxL1.js.map
1181
+ typeof self < "u" && self.constructor.name === "DedicatedWorkerGlobalScope" && x(new wt());
1182
+ //# sourceMappingURL=worker-DilNsKoO.js.map
1162
1183
  `, r = typeof self < "u" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", a], { type: "text/javascript;charset=utf-8" });
1163
- function s(e) {
1184
+ function o(t) {
1164
1185
  let n;
1165
1186
  try {
1166
1187
  if (n = r && (self.URL || self.webkitURL).createObjectURL(r), !n) throw "";
1167
- const t = new Worker(n, {
1188
+ const e = new Worker(n, {
1168
1189
  type: "module",
1169
- name: e?.name
1190
+ name: t?.name
1170
1191
  });
1171
- return t.addEventListener("error", () => {
1192
+ return e.addEventListener("error", () => {
1172
1193
  (self.URL || self.webkitURL).revokeObjectURL(n);
1173
- }), t;
1194
+ }), e;
1174
1195
  } catch {
1175
1196
  return new Worker(
1176
1197
  "data:text/javascript;charset=utf-8," + encodeURIComponent(a),
1177
1198
  {
1178
1199
  type: "module",
1179
- name: e?.name
1200
+ name: t?.name
1180
1201
  }
1181
1202
  );
1182
1203
  }
1183
1204
  }
1184
- function h(e, n) {
1185
- const t = i(new s());
1186
- return e && t.setWatchCallback(
1187
- e ? o(e) : () => {
1188
- }
1189
- ), n && t.setOptions(n), t;
1205
+ function c(t) {
1206
+ const n = i(new o());
1207
+ return t && n.setOptions(t), n;
1190
1208
  }
1191
1209
  export {
1192
1210
  d as DirectoryNotFoundError,
1193
- p as FileNotFoundError,
1194
- u as OPFSError,
1195
- y as OPFSNotMountedError,
1196
- w as OPFSNotSupportedError,
1211
+ f as FileNotFoundError,
1212
+ p as OPFSError,
1213
+ u as OPFSNotMountedError,
1214
+ y as OPFSNotSupportedError,
1197
1215
  m as PathError,
1198
- g as PermissionError,
1199
- v as StorageError,
1200
- F as TimeoutError,
1201
- S as basename,
1216
+ w as PermissionError,
1217
+ g as StorageError,
1218
+ v as TimeoutError,
1219
+ b as basename,
1202
1220
  E as calculateFileHash,
1203
- b as checkOPFSSupport,
1204
- P as convertBlobToUint8Array,
1205
- x as createBuffer,
1206
- h as createWorker,
1207
- T as decodeBuffer,
1208
- A as dirname,
1209
- O as encodeString,
1210
- D as extname,
1211
- _ as joinPath,
1212
- I as normalizePath,
1213
- C as readFileData,
1214
- k as resolvePath,
1221
+ S as checkOPFSSupport,
1222
+ F as convertBlobToUint8Array,
1223
+ P as createBuffer,
1224
+ c as createWorker,
1225
+ x as decodeBuffer,
1226
+ D as dirname,
1227
+ T as encodeString,
1228
+ C as extname,
1229
+ A as joinPath,
1230
+ O as normalizePath,
1231
+ _ as readFileData,
1232
+ I as resolvePath,
1215
1233
  U as splitPath,
1216
1234
  R as writeFileData
1217
1235
  };