opfs-worker 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/raw.js CHANGED
@@ -1,146 +1,146 @@
1
- import { expose as p } from "comlink";
2
- class s extends Error {
3
- constructor(e, t, n) {
4
- super(e), this.code = t, this.path = n, this.name = "OPFSError";
1
+ import { expose as E } from "comlink";
2
+ class o extends Error {
3
+ constructor(e, t, r) {
4
+ super(e), this.code = t, this.path = r, this.name = "OPFSError";
5
5
  }
6
6
  }
7
- class A extends s {
7
+ class S extends o {
8
8
  constructor() {
9
9
  super("OPFS is not supported in this browser", "OPFS_NOT_SUPPORTED");
10
10
  }
11
11
  }
12
- class y extends s {
12
+ class y extends o {
13
13
  constructor() {
14
14
  super("OPFS is not mounted", "OPFS_NOT_MOUNTED");
15
15
  }
16
16
  }
17
- class g extends s {
17
+ class g extends o {
18
18
  constructor(e, t) {
19
19
  super(e, "INVALID_PATH", t);
20
20
  }
21
21
  }
22
- class m extends s {
22
+ class m extends o {
23
23
  constructor(e) {
24
24
  super(`File not found: ${e}`, "FILE_NOT_FOUND", e);
25
25
  }
26
26
  }
27
- function S(r, e = "utf-8") {
27
+ function A(a, e = "utf-8") {
28
28
  switch (e) {
29
29
  case "utf8":
30
30
  case "utf-8":
31
- return new TextEncoder().encode(r);
31
+ return new TextEncoder().encode(a);
32
32
  case "utf16le":
33
33
  case "ucs2":
34
34
  case "ucs-2":
35
- return I(r);
35
+ return I(a);
36
36
  case "ascii":
37
- return H(r);
37
+ return $(a);
38
38
  case "latin1":
39
- return N(r);
39
+ return v(a);
40
40
  case "binary":
41
- return Uint8Array.from(r, (t) => t.charCodeAt(0));
41
+ return Uint8Array.from(a, (t) => t.charCodeAt(0));
42
42
  case "base64":
43
- return Uint8Array.from(atob(r), (t) => t.charCodeAt(0));
43
+ return Uint8Array.from(atob(a), (t) => t.charCodeAt(0));
44
44
  case "hex":
45
- if (!/^[\da-f]+$/i.test(r) || r.length % 2 !== 0)
46
- throw new s("Invalid hex string", "INVALID_HEX_FORMAT");
47
- return Uint8Array.from(r.match(/.{1,2}/g).map((t) => parseInt(t, 16)));
45
+ if (!/^[\da-f]+$/i.test(a) || a.length % 2 !== 0)
46
+ throw new o("Invalid hex string", "INVALID_HEX_FORMAT");
47
+ return Uint8Array.from(a.match(/.{1,2}/g).map((t) => parseInt(t, 16)));
48
48
  default:
49
- return console.warn("Encoding not supported, falling back to UTF-8"), new TextEncoder().encode(r);
49
+ return console.warn("Encoding not supported, falling back to UTF-8"), new TextEncoder().encode(a);
50
50
  }
51
51
  }
52
- function D(r, e = "utf-8") {
52
+ function D(a, e = "utf-8") {
53
53
  switch (e) {
54
54
  case "utf8":
55
55
  case "utf-8":
56
- return new TextDecoder().decode(r);
56
+ return new TextDecoder().decode(a);
57
57
  case "utf16le":
58
58
  case "ucs2":
59
59
  case "ucs-2":
60
- return T(r);
60
+ return T(a);
61
61
  case "latin1":
62
- return String.fromCharCode(...r);
62
+ return String.fromCharCode(...a);
63
63
  case "binary":
64
- return String.fromCharCode(...r);
64
+ return String.fromCharCode(...a);
65
65
  case "ascii":
66
- return String.fromCharCode(...r.map((t) => t & 127));
66
+ return String.fromCharCode(...a.map((t) => t & 127));
67
67
  case "base64":
68
- return btoa(String.fromCharCode(...r));
68
+ return btoa(String.fromCharCode(...a));
69
69
  case "hex":
70
- return Array.from(r).map((t) => t.toString(16).padStart(2, "0")).join("");
70
+ return Array.from(a).map((t) => t.toString(16).padStart(2, "0")).join("");
71
71
  default:
72
- return console.warn("Unsupported encoding, falling back to UTF-8"), new TextDecoder().decode(r);
72
+ return console.warn("Unsupported encoding, falling back to UTF-8"), new TextDecoder().decode(a);
73
73
  }
74
74
  }
75
- function I(r) {
76
- const e = new Uint8Array(r.length * 2);
77
- for (let t = 0; t < r.length; t++) {
78
- const n = r.charCodeAt(t);
79
- e[t * 2] = n & 255, e[t * 2 + 1] = n >> 8;
75
+ function I(a) {
76
+ const e = new Uint8Array(a.length * 2);
77
+ for (let t = 0; t < a.length; t++) {
78
+ const r = a.charCodeAt(t);
79
+ e[t * 2] = r & 255, e[t * 2 + 1] = r >> 8;
80
80
  }
81
81
  return e;
82
82
  }
83
- function T(r) {
84
- r.length % 2 !== 0 && (console.warn("Invalid UTF-16LE buffer length, truncating last byte"), r = r.slice(0, r.length - 1));
85
- const e = new Uint16Array(r.buffer, r.byteOffset, r.byteLength / 2);
83
+ function T(a) {
84
+ a.length % 2 !== 0 && (console.warn("Invalid UTF-16LE buffer length, truncating last byte"), a = a.slice(0, a.length - 1));
85
+ const e = new Uint16Array(a.buffer, a.byteOffset, a.byteLength / 2);
86
86
  return String.fromCharCode(...e);
87
87
  }
88
- function N(r) {
89
- const e = new Uint8Array(r.length);
90
- for (let t = 0; t < r.length; t++)
91
- e[t] = r.charCodeAt(t) & 255;
88
+ function v(a) {
89
+ const e = new Uint8Array(a.length);
90
+ for (let t = 0; t < a.length; t++)
91
+ e[t] = a.charCodeAt(t) & 255;
92
92
  return e;
93
93
  }
94
- function H(r) {
95
- const e = new Uint8Array(r.length);
96
- for (let t = 0; t < r.length; t++)
97
- e[t] = r.charCodeAt(t) & 127;
94
+ function $(a) {
95
+ const e = new Uint8Array(a.length);
96
+ for (let t = 0; t < a.length; t++)
97
+ e[t] = a.charCodeAt(t) & 127;
98
98
  return e;
99
99
  }
100
- function $() {
100
+ function N() {
101
101
  if (!("storage" in navigator) || !("getDirectory" in navigator.storage))
102
- throw new A();
102
+ throw new S();
103
103
  }
104
- function u(r) {
105
- return Array.isArray(r) ? r : r.split("/").filter(Boolean);
104
+ function f(a) {
105
+ return Array.isArray(a) ? a : a.split("/").filter(Boolean);
106
106
  }
107
- function F(r) {
108
- return typeof r == "string" ? r ?? "/" : `/${r.join("/")}`;
107
+ function p(a) {
108
+ return typeof a == "string" ? a ?? "/" : `/${a.join("/")}`;
109
109
  }
110
- function O(r, e = "utf-8") {
111
- return typeof r == "string" ? S(r, e) : r instanceof Uint8Array ? r : new Uint8Array(r);
110
+ function H(a, e = "utf-8") {
111
+ return typeof a == "string" ? A(a, e) : a instanceof Uint8Array ? a : new Uint8Array(a);
112
112
  }
113
- async function x(r) {
114
- const e = await r.createSyncAccessHandle();
113
+ async function x(a) {
114
+ const e = await a.createSyncAccessHandle();
115
115
  try {
116
- const t = e.getSize(), n = new Uint8Array(t);
117
- return e.read(n, { at: 0 }), n;
116
+ const t = e.getSize(), r = new Uint8Array(t);
117
+ return e.read(r, { at: 0 }), r;
118
118
  } finally {
119
119
  e.close();
120
120
  }
121
121
  }
122
- async function E(r, e, t, n = {}) {
123
- let o = null;
122
+ async function F(a, e, t, r = {}) {
123
+ let n = null;
124
124
  try {
125
- o = await r.createSyncAccessHandle();
126
- const i = O(e, t), a = n.append ? o.getSize() : 0;
127
- o.write(i, { at: a }), n.truncate && !n.append && o.truncate(i.byteLength), o.flush();
125
+ n = await a.createSyncAccessHandle();
126
+ const i = H(e, t), s = r.append ? n.getSize() : 0;
127
+ n.write(i, { at: s }), r.truncate && !r.append && n.truncate(i.byteLength), n.flush();
128
128
  } catch (i) {
129
129
  console.error(i);
130
- const a = n.append ? "append" : "write";
131
- throw new s(`Failed to ${a} file`, `${a.toUpperCase()}_FAILED`);
130
+ const s = r.append ? "append" : "write";
131
+ throw new o(`Failed to ${s} file`, `${s.toUpperCase()}_FAILED`);
132
132
  } finally {
133
- if (o)
133
+ if (n)
134
134
  try {
135
- o.close();
135
+ n.close();
136
136
  } catch {
137
137
  }
138
138
  }
139
139
  }
140
- async function v(r, e = "SHA-1") {
140
+ async function O(a, e = "SHA-1") {
141
141
  try {
142
- const t = new Uint8Array(r), n = await crypto.subtle.digest(e, t);
143
- return Array.from(new Uint8Array(n)).map((i) => i.toString(16).padStart(2, "0")).join("");
142
+ const t = new Uint8Array(a), r = await crypto.subtle.digest(e, t);
143
+ return Array.from(new Uint8Array(r)).map((i) => i.toString(16).padStart(2, "0")).join("");
144
144
  } catch (t) {
145
145
  throw console.warn(`Failed to calculate ${e} hash:`, t), t;
146
146
  }
@@ -148,13 +148,23 @@ async function v(r, e = "SHA-1") {
148
148
  class U {
149
149
  /** Root directory handle for the file system */
150
150
  root = null;
151
+ /** Watch event callback */
152
+ watchCallback = null;
153
+ /** Map of watched paths to their last known state */
154
+ watchers = /* @__PURE__ */ new Map();
155
+ /** Interval handle for polling watched paths */
156
+ watchTimer = null;
157
+ /** Polling interval in milliseconds */
158
+ watchInterval = 1e3;
159
+ /** Flag to avoid concurrent scans */
160
+ scanning = !1;
151
161
  /**
152
162
  * Creates a new OPFSFileSystem instance
153
163
  *
154
164
  * @throws {OPFSError} If OPFS is not supported in the current browser
155
165
  */
156
166
  constructor() {
157
- $();
167
+ N();
158
168
  }
159
169
  /**
160
170
  * Initialize the file system within a given directory
@@ -172,12 +182,12 @@ class U {
172
182
  * const success = await fs.init('/my-app');
173
183
  * ```
174
184
  */
175
- async mount(e = "/") {
185
+ async mount(e = "/", t, r) {
176
186
  try {
177
- const t = await navigator.storage.getDirectory();
178
- return this.root = await this.getDirectoryHandle(e, !0, t), !0;
179
- } catch (t) {
180
- throw console.error(t), new s("Failed to initialize OPFS", "INIT_FAILED");
187
+ const n = await navigator.storage.getDirectory();
188
+ return this.root = await this.getDirectoryHandle(e, !0, n), t && (this.watchCallback = t, r?.watchInterval && (this.watchInterval = r.watchInterval)), !0;
189
+ } catch (n) {
190
+ throw console.error(n), new o("Failed to initialize OPFS", "INIT_FAILED");
181
191
  }
182
192
  }
183
193
  /**
@@ -198,13 +208,13 @@ class U {
198
208
  * const docsDir2 = await fs.getDirectoryHandle(['users', 'john', 'documents'], true);
199
209
  * ```
200
210
  */
201
- async getDirectoryHandle(e, t = !1, n = this.root) {
202
- if (!n)
211
+ async getDirectoryHandle(e, t = !1, r = this.root) {
212
+ if (!r)
203
213
  throw new y();
204
- const o = Array.isArray(e) ? e : u(e);
205
- let i = n;
206
- for (const a of o)
207
- i = await i.getDirectoryHandle(a, { create: t });
214
+ const n = Array.isArray(e) ? e : f(e);
215
+ let i = r;
216
+ for (const s of n)
217
+ i = await i.getDirectoryHandle(s, { create: t });
208
218
  return i;
209
219
  }
210
220
  /**
@@ -226,14 +236,14 @@ class U {
226
236
  * const fileHandle2 = await fs.getFileHandle(['config', 'settings.json'], true);
227
237
  * ```
228
238
  */
229
- async getFileHandle(e, t = !1, n = this.root) {
230
- if (!n)
239
+ async getFileHandle(e, t = !1, r = this.root) {
240
+ if (!r)
231
241
  throw new y();
232
- const o = u(e);
233
- if (o.length === 0)
242
+ const n = f(e);
243
+ if (n.length === 0)
234
244
  throw new g("Path must not be empty", Array.isArray(e) ? e.join("/") : e);
235
- const i = o.pop();
236
- return (await this.getDirectoryHandle(o, t, n)).getFileHandle(i, { create: t });
245
+ const i = n.pop();
246
+ return (await this.getDirectoryHandle(n, t, r)).getFileHandle(i, { create: t });
237
247
  }
238
248
  /**
239
249
  * Recursively list all files and directories with their stats
@@ -273,15 +283,15 @@ class U {
273
283
  * ```
274
284
  */
275
285
  async index(e) {
276
- const t = /* @__PURE__ */ new Map(), n = async (o) => {
277
- const i = await this.readdir(o, { withFileTypes: !0 });
278
- for (const a of i) {
279
- const l = `${o === "/" ? "" : o}/${a.name}`;
286
+ const t = /* @__PURE__ */ new Map(), r = async (n) => {
287
+ const i = await this.readdir(n, { withFileTypes: !0 });
288
+ for (const s of i) {
289
+ const c = `${n === "/" ? "" : n}/${s.name}`;
280
290
  try {
281
- const c = await this.stat(l, e);
282
- t.set(l, c), c.isDirectory && await n(l);
283
- } catch (c) {
284
- console.warn(`Skipping broken entry: ${l}`, c);
291
+ const l = await this.stat(c, e);
292
+ t.set(c, l), l.isDirectory && await r(c);
293
+ } catch (l) {
294
+ console.warn(`Skipping broken entry: ${c}`, l);
285
295
  }
286
296
  }
287
297
  };
@@ -292,14 +302,14 @@ class U {
292
302
  ctime: (/* @__PURE__ */ new Date(0)).toISOString(),
293
303
  isFile: !1,
294
304
  isDirectory: !0
295
- }), await n("/"), t;
305
+ }), await r("/"), t;
296
306
  }
297
307
  async readFile(e, t = "utf-8") {
298
308
  try {
299
- const n = await this.getFileHandle(e, !1), o = await x(n);
300
- return t === "binary" ? o : D(o, t);
301
- } catch (n) {
302
- throw console.error(n), new m(e);
309
+ const r = await this.getFileHandle(e, !1), n = await x(r);
310
+ return t === "binary" ? n : D(n, t);
311
+ } catch (r) {
312
+ throw console.error(r), new m(e);
303
313
  }
304
314
  }
305
315
  /**
@@ -327,9 +337,9 @@ class U {
327
337
  * await fs.writeFile('/data/utf16.txt', 'Hello World', 'utf-16le');
328
338
  * ```
329
339
  */
330
- async writeFile(e, t, n) {
331
- const o = await this.getFileHandle(e, !0);
332
- await E(o, t, n, { truncate: !0 });
340
+ async writeFile(e, t, r) {
341
+ const n = await this.getFileHandle(e, !0);
342
+ await F(n, t, r, { truncate: !0 });
333
343
  }
334
344
  /**
335
345
  * Append data to a file
@@ -353,9 +363,9 @@ class U {
353
363
  * await fs.appendFile('/data/binary.dat', additionalData);
354
364
  * ```
355
365
  */
356
- async appendFile(e, t, n) {
357
- const o = await this.getFileHandle(e, !0);
358
- await E(o, t, n, { append: !0 });
366
+ async appendFile(e, t, r) {
367
+ const n = await this.getFileHandle(e, !0);
368
+ await F(n, t, r, { append: !0 });
359
369
  }
360
370
  /**
361
371
  * Create a directory
@@ -381,17 +391,17 @@ class U {
381
391
  async mkdir(e, t) {
382
392
  if (!this.root)
383
393
  throw new y();
384
- const n = t?.recursive ?? !1, o = u(e);
394
+ const r = t?.recursive ?? !1, n = f(e);
385
395
  let i = this.root;
386
- for (let a = 0; a < o.length; a++) {
387
- const l = o[a];
396
+ for (let s = 0; s < n.length; s++) {
397
+ const c = n[s];
388
398
  try {
389
- i = await i.getDirectoryHandle(l, { create: n || a === o.length - 1 });
390
- } catch (c) {
391
- throw c.name === "NotFoundError" ? new s(
392
- `Parent directory does not exist: ${F(o.slice(0, a + 1))}`,
399
+ i = await i.getDirectoryHandle(c, { create: r || s === n.length - 1 });
400
+ } catch (l) {
401
+ throw l.name === "NotFoundError" ? new o(
402
+ `Parent directory does not exist: ${p(n.slice(0, s + 1))}`,
393
403
  "ENOENT"
394
- ) : c.name === "TypeMismatchError" ? new s(`Path segment is not a directory: ${l}`, "ENOTDIR") : new s("Failed to create directory", "MKDIR_FAILED");
404
+ ) : l.name === "TypeMismatchError" ? new o(`Path segment is not a directory: ${c}`, "ENOTDIR") : new o("Failed to create directory", "MKDIR_FAILED");
395
405
  }
396
406
  }
397
407
  }
@@ -425,30 +435,30 @@ class U {
425
435
  * ```
426
436
  */
427
437
  async stat(e, t) {
428
- const n = u(e), o = n.pop(), i = await this.getDirectoryHandle(n, !1), a = t?.includeHash ?? !1, l = t?.hashAlgorithm ?? "SHA-1";
438
+ const r = f(e), n = r.pop(), i = await this.getDirectoryHandle(r, !1), s = t?.includeHash ?? !1, c = t?.hashAlgorithm ?? "SHA-1";
429
439
  try {
430
- const f = await (await i.getFileHandle(o, { create: !1 })).getFile(), h = {
440
+ const h = await (await i.getFileHandle(n, { create: !1 })).getFile(), w = {
431
441
  kind: "file",
432
- size: f.size,
433
- mtime: new Date(f.lastModified).toISOString(),
434
- ctime: new Date(f.lastModified).toISOString(),
442
+ size: h.size,
443
+ mtime: new Date(h.lastModified).toISOString(),
444
+ ctime: new Date(h.lastModified).toISOString(),
435
445
  isFile: !0,
436
446
  isDirectory: !1
437
447
  };
438
- if (a)
448
+ if (s)
439
449
  try {
440
- const w = new Uint8Array(await f.arrayBuffer()), d = await v(w, l);
441
- h.hash = d;
442
- } catch (w) {
443
- console.warn(`Failed to calculate hash for ${e}:`, w);
450
+ const u = new Uint8Array(await h.arrayBuffer()), d = await O(u, c);
451
+ w.hash = d;
452
+ } catch (u) {
453
+ console.warn(`Failed to calculate hash for ${e}:`, u);
444
454
  }
445
- return h;
446
- } catch (c) {
447
- if (c.name !== "TypeMismatchError" && c.name !== "NotFoundError")
448
- throw new s("Failed to stat (file)", "STAT_FAILED");
455
+ return w;
456
+ } catch (l) {
457
+ if (l.name !== "TypeMismatchError" && l.name !== "NotFoundError")
458
+ throw new o("Failed to stat (file)", "STAT_FAILED");
449
459
  }
450
460
  try {
451
- return await i.getDirectoryHandle(o, { create: !1 }), {
461
+ return await i.getDirectoryHandle(n, { create: !1 }), {
452
462
  kind: "directory",
453
463
  size: 0,
454
464
  mtime: (/* @__PURE__ */ new Date(0)).toISOString(),
@@ -457,28 +467,28 @@ class U {
457
467
  isDirectory: !0
458
468
  // Directories don't have hashes
459
469
  };
460
- } catch (c) {
461
- throw c.name === "NotFoundError" ? new s(`No such file or directory: ${e}`, "ENOENT") : new s("Failed to stat (directory)", "STAT_FAILED");
470
+ } catch (l) {
471
+ throw l.name === "NotFoundError" ? new o(`No such file or directory: ${e}`, "ENOENT") : new o("Failed to stat (directory)", "STAT_FAILED");
462
472
  }
463
473
  }
464
474
  async readdir(e, t) {
465
- const n = t?.withFileTypes ?? !1, o = await this.getDirectoryHandle(e, !1);
466
- if (n) {
475
+ const r = t?.withFileTypes ?? !1, n = await this.getDirectoryHandle(e, !1);
476
+ if (r) {
467
477
  const i = [];
468
- for await (const [a, l] of o.entries()) {
469
- const c = l.kind === "file";
478
+ for await (const [s, c] of n.entries()) {
479
+ const l = c.kind === "file";
470
480
  i.push({
471
- name: a,
472
- kind: l.kind,
473
- isFile: c,
474
- isDirectory: !c
481
+ name: s,
482
+ kind: c.kind,
483
+ isFile: l,
484
+ isDirectory: !l
475
485
  });
476
486
  }
477
487
  return i;
478
488
  } else {
479
489
  const i = [];
480
- for await (const [a] of o.entries())
481
- i.push(a);
490
+ for await (const [s] of n.entries())
491
+ i.push(s);
482
492
  return i;
483
493
  }
484
494
  }
@@ -497,23 +507,23 @@ class U {
497
507
  * ```
498
508
  */
499
509
  async exists(e) {
500
- const t = u(e), n = t.pop();
501
- let o = null;
510
+ const t = f(e), r = t.pop();
511
+ let n = null;
502
512
  try {
503
- o = await this.getDirectoryHandle(t, !1);
513
+ n = await this.getDirectoryHandle(t, !1);
504
514
  } catch (i) {
505
- throw (i.name === "NotFoundError" || i.name === "TypeMismatchError") && (o = null), i;
515
+ throw (i.name === "NotFoundError" || i.name === "TypeMismatchError") && (n = null), i;
506
516
  }
507
- if (!o || !n)
517
+ if (!n || !r)
508
518
  return !1;
509
519
  try {
510
- return await o.getFileHandle(n, { create: !1 }), !0;
520
+ return await n.getFileHandle(r, { create: !1 }), !0;
511
521
  } catch (i) {
512
522
  if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
513
523
  throw i;
514
524
  }
515
525
  try {
516
- return await o.getDirectoryHandle(n, { create: !1 }), !0;
526
+ return await n.getDirectoryHandle(r, { create: !1 }), !0;
517
527
  } catch (i) {
518
528
  if (i.name !== "NotFoundError" && i.name !== "TypeMismatchError")
519
529
  throw i;
@@ -542,12 +552,12 @@ class U {
542
552
  async clear(e = "/") {
543
553
  try {
544
554
  const t = await this.readdir(e, { withFileTypes: !0 });
545
- for (const n of t) {
546
- const o = `${e === "/" ? "" : e}/${n.name}`;
547
- await this.remove(o, { recursive: !0 });
555
+ for (const r of t) {
556
+ const n = `${e === "/" ? "" : e}/${r.name}`;
557
+ await this.remove(n, { recursive: !0 });
548
558
  }
549
559
  } catch (t) {
550
- throw t instanceof s ? t : new s(`Failed to clear directory: ${e}`, "CLEAR_FAILED");
560
+ throw t instanceof o ? t : new o(`Failed to clear directory: ${e}`, "CLEAR_FAILED");
551
561
  }
552
562
  }
553
563
  /**
@@ -575,17 +585,17 @@ class U {
575
585
  * ```
576
586
  */
577
587
  async remove(e, t) {
578
- const n = t?.recursive ?? !1, o = t?.force ?? !1, i = u(e), a = i.pop();
579
- if (!a)
588
+ const r = t?.recursive ?? !1, n = t?.force ?? !1, i = f(e), s = i.pop();
589
+ if (!s)
580
590
  throw new g("Invalid path", e);
581
- const l = await this.getDirectoryHandle(i, !1);
591
+ const c = await this.getDirectoryHandle(i, !1);
582
592
  try {
583
- await l.removeEntry(a, { recursive: n });
584
- } catch (c) {
585
- if (c.name === "NotFoundError") {
586
- if (!o)
587
- throw new s(`No such file or directory: ${e}`, "ENOENT");
588
- } else throw c.name === "InvalidModificationError" ? new s(`Directory not empty: ${e}. Use recursive option to force removal.`, "ENOTEMPTY") : c.name === "TypeMismatchError" && !n ? new s(`Cannot remove directory without recursive option: ${e}`, "EISDIR") : new s(`Failed to remove path: ${e}`, "RM_FAILED");
593
+ await c.removeEntry(s, { recursive: r });
594
+ } catch (l) {
595
+ if (l.name === "NotFoundError") {
596
+ if (!n)
597
+ throw new o(`No such file or directory: ${e}`, "ENOENT");
598
+ } else throw l.name === "InvalidModificationError" ? new o(`Directory not empty: ${e}. Use recursive option to force removal.`, "ENOTEMPTY") : l.name === "TypeMismatchError" && !r ? new o(`Cannot remove directory without recursive option: ${e}`, "EISDIR") : new o(`Failed to remove path: ${e}`, "RM_FAILED");
589
599
  }
590
600
  }
591
601
  /**
@@ -608,21 +618,21 @@ class U {
608
618
  */
609
619
  async realpath(e) {
610
620
  try {
611
- const t = u(e), n = [];
612
- for (const a of t)
613
- if (!(a === "." || a === ""))
614
- if (a === "..") {
615
- if (n.length === 0)
616
- throw new s("Path escapes root", "EINVAL");
617
- n.length > 0 && n.pop();
621
+ const t = f(e), r = [];
622
+ for (const s of t)
623
+ if (!(s === "." || s === ""))
624
+ if (s === "..") {
625
+ if (r.length === 0)
626
+ throw new o("Path escapes root", "EINVAL");
627
+ r.length > 0 && r.pop();
618
628
  } else
619
- n.push(a);
620
- const o = F(n);
621
- if (!await this.exists(o))
622
- throw new m(o);
623
- return o;
629
+ r.push(s);
630
+ const n = p(r);
631
+ if (!await this.exists(n))
632
+ throw new m(n);
633
+ return n;
624
634
  } catch (t) {
625
- throw t instanceof s ? t : new s(`Failed to resolve path: ${e}`, "REALPATH_FAILED");
635
+ throw t instanceof o ? t : new o(`Failed to resolve path: ${e}`, "REALPATH_FAILED");
626
636
  }
627
637
  }
628
638
  /**
@@ -646,8 +656,8 @@ class U {
646
656
  if (!await this.exists(e))
647
657
  throw new m(e);
648
658
  await this.copy(e, t, { recursive: !0 }), await this.remove(e, { recursive: !0 });
649
- } catch (n) {
650
- throw n instanceof s ? n : new s(`Failed to rename from ${e} to ${t}`, "RENAME_FAILED");
659
+ } catch (r) {
660
+ throw r instanceof o ? r : new o(`Failed to rename from ${e} to ${t}`, "RENAME_FAILED");
651
661
  }
652
662
  }
653
663
  /**
@@ -675,28 +685,87 @@ class U {
675
685
  * await fs.cp('/source', '/dest', { recursive: true, force: false });
676
686
  * ```
677
687
  */
678
- async copy(e, t, n) {
688
+ async copy(e, t, r) {
679
689
  try {
680
- const o = n?.recursive ?? !1, i = n?.force ?? !0;
690
+ const n = r?.recursive ?? !1, i = r?.force ?? !0;
681
691
  if (!await this.exists(e))
682
- throw new s(`Source does not exist: ${e}`, "ENOENT");
692
+ throw new o(`Source does not exist: ${e}`, "ENOENT");
683
693
  if (await this.exists(t) && !i)
684
- throw new s(`Destination already exists: ${t}`, "EEXIST");
694
+ throw new o(`Destination already exists: ${t}`, "EEXIST");
685
695
  if ((await this.stat(e)).isFile) {
686
- const f = await this.readFile(e, "binary");
687
- await this.writeFile(t, f);
696
+ const h = await this.readFile(e, "binary");
697
+ await this.writeFile(t, h);
688
698
  } else {
689
- if (!o)
690
- throw new s(`Cannot copy directory without recursive option: ${e}`, "EISDIR");
699
+ if (!n)
700
+ throw new o(`Cannot copy directory without recursive option: ${e}`, "EISDIR");
691
701
  await this.mkdir(t, { recursive: !0 });
692
- const f = await this.readdir(e, { withFileTypes: !0 });
693
- for (const h of f) {
694
- const w = `${e}/${h.name}`, d = `${t}/${h.name}`;
695
- await this.copy(w, d, { recursive: !0, force: i });
702
+ const h = await this.readdir(e, { withFileTypes: !0 });
703
+ for (const w of h) {
704
+ const u = `${e}/${w.name}`, d = `${t}/${w.name}`;
705
+ await this.copy(u, d, { recursive: !0, force: i });
706
+ }
707
+ }
708
+ } catch (n) {
709
+ throw n instanceof o ? n : new o(`Failed to copy from ${e} to ${t}`, "CP_FAILED");
710
+ }
711
+ }
712
+ /**
713
+ * Start watching a file or directory for changes
714
+ */
715
+ async watch(e) {
716
+ const t = e.startsWith("/") ? e : `/${e}`, r = await this.buildSnapshot(t);
717
+ this.watchers.set(t, r), this.watchTimer || (this.watchTimer = setInterval(() => {
718
+ this.scanWatches();
719
+ }, this.watchInterval));
720
+ }
721
+ /**
722
+ * Stop watching a previously watched path
723
+ */
724
+ unwatch(e) {
725
+ const t = e.startsWith("/") ? e : `/${e}`;
726
+ this.watchers.delete(t), this.watchers.size === 0 && this.watchTimer && (clearInterval(this.watchTimer), this.watchTimer = null);
727
+ }
728
+ async buildSnapshot(e) {
729
+ const t = /* @__PURE__ */ new Map(), r = async (n) => {
730
+ const i = await this.stat(n);
731
+ if (t.set(n, i), i.isDirectory) {
732
+ const s = await this.readdir(n, { withFileTypes: !0 });
733
+ for (const c of s) {
734
+ const l = `${n === "/" ? "" : n}/${c.name}`;
735
+ await r(l);
696
736
  }
697
737
  }
698
- } catch (o) {
699
- throw o instanceof s ? o : new s(`Failed to copy from ${e} to ${t}`, "CP_FAILED");
738
+ };
739
+ return await r(e), t;
740
+ }
741
+ async scanWatches() {
742
+ if (!this.scanning) {
743
+ this.scanning = !0;
744
+ try {
745
+ await Promise.all(
746
+ [...this.watchers.entries()].map(async ([e, t]) => {
747
+ let r;
748
+ try {
749
+ r = await this.buildSnapshot(e);
750
+ } catch {
751
+ r = /* @__PURE__ */ new Map();
752
+ }
753
+ const n = [];
754
+ for (const [i, s] of r) {
755
+ const c = t.get(i);
756
+ c ? (c.mtime !== s.mtime || c.size !== s.size) && n.push({ path: i, type: "change" }) : n.push({ path: i, type: "create" });
757
+ }
758
+ for (const i of t.keys())
759
+ r.has(i) || n.push({ path: i, type: "delete" });
760
+ if (n.length && this.watchCallback)
761
+ for (const i of n)
762
+ this.watchCallback(i);
763
+ this.watchers.set(e, r);
764
+ })
765
+ );
766
+ } finally {
767
+ this.scanning = !1;
768
+ }
700
769
  }
701
770
  }
702
771
  /**
@@ -730,22 +799,22 @@ class U {
730
799
  async sync(e, t) {
731
800
  try {
732
801
  (t?.cleanBefore ?? !1) && await this.clear("/");
733
- for (const [o, i] of e) {
734
- const a = o.startsWith("/") ? o : `/${o}`;
735
- let l;
802
+ for (const [n, i] of e) {
803
+ const s = n.startsWith("/") ? n : `/${n}`;
804
+ let c;
736
805
  if (i instanceof Blob) {
737
- const c = await i.arrayBuffer();
738
- l = new Uint8Array(c);
806
+ const l = await i.arrayBuffer();
807
+ c = new Uint8Array(l);
739
808
  } else
740
- l = i;
741
- await this.writeFile(a, l);
809
+ c = i;
810
+ await this.writeFile(s, c);
742
811
  }
743
- } catch (n) {
744
- throw n instanceof s ? n : new s("Failed to sync file system", "SYNC_FAILED");
812
+ } catch (r) {
813
+ throw r instanceof o ? r : new o("Failed to sync file system", "SYNC_FAILED");
745
814
  }
746
815
  }
747
816
  }
748
- p(new U());
817
+ typeof self < "u" && self.constructor.name === "DedicatedWorkerGlobalScope" && E(new U());
749
818
  export {
750
819
  U as OPFSWorker
751
820
  };