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/README.md +51 -6
- package/dist/assets/worker-D5GbafFH.js.map +1 -0
- package/dist/index.cjs +282 -213
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/raw.cjs +1 -1
- package/dist/raw.cjs.map +1 -1
- package/dist/raw.js +268 -199
- package/dist/raw.js.map +1 -1
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +148 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +24 -2
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +102 -2
- package/package.json +1 -1
- package/dist/assets/worker-BiWuxhcz.js.map +0 -1
package/dist/raw.js
CHANGED
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
import { expose as
|
|
2
|
-
class
|
|
3
|
-
constructor(e, t,
|
|
4
|
-
super(e), this.code = t, this.path =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
31
|
+
return new TextEncoder().encode(a);
|
|
32
32
|
case "utf16le":
|
|
33
33
|
case "ucs2":
|
|
34
34
|
case "ucs-2":
|
|
35
|
-
return I(
|
|
35
|
+
return I(a);
|
|
36
36
|
case "ascii":
|
|
37
|
-
return
|
|
37
|
+
return $(a);
|
|
38
38
|
case "latin1":
|
|
39
|
-
return
|
|
39
|
+
return v(a);
|
|
40
40
|
case "binary":
|
|
41
|
-
return Uint8Array.from(
|
|
41
|
+
return Uint8Array.from(a, (t) => t.charCodeAt(0));
|
|
42
42
|
case "base64":
|
|
43
|
-
return Uint8Array.from(atob(
|
|
43
|
+
return Uint8Array.from(atob(a), (t) => t.charCodeAt(0));
|
|
44
44
|
case "hex":
|
|
45
|
-
if (!/^[\da-f]+$/i.test(
|
|
46
|
-
throw new
|
|
47
|
-
return Uint8Array.from(
|
|
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(
|
|
49
|
+
return console.warn("Encoding not supported, falling back to UTF-8"), new TextEncoder().encode(a);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
function D(
|
|
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(
|
|
56
|
+
return new TextDecoder().decode(a);
|
|
57
57
|
case "utf16le":
|
|
58
58
|
case "ucs2":
|
|
59
59
|
case "ucs-2":
|
|
60
|
-
return T(
|
|
60
|
+
return T(a);
|
|
61
61
|
case "latin1":
|
|
62
|
-
return String.fromCharCode(...
|
|
62
|
+
return String.fromCharCode(...a);
|
|
63
63
|
case "binary":
|
|
64
|
-
return String.fromCharCode(...
|
|
64
|
+
return String.fromCharCode(...a);
|
|
65
65
|
case "ascii":
|
|
66
|
-
return String.fromCharCode(...
|
|
66
|
+
return String.fromCharCode(...a.map((t) => t & 127));
|
|
67
67
|
case "base64":
|
|
68
|
-
return btoa(String.fromCharCode(...
|
|
68
|
+
return btoa(String.fromCharCode(...a));
|
|
69
69
|
case "hex":
|
|
70
|
-
return Array.from(
|
|
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(
|
|
72
|
+
return console.warn("Unsupported encoding, falling back to UTF-8"), new TextDecoder().decode(a);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
function I(
|
|
76
|
-
const e = new Uint8Array(
|
|
77
|
-
for (let t = 0; t <
|
|
78
|
-
const
|
|
79
|
-
e[t * 2] =
|
|
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(
|
|
84
|
-
|
|
85
|
-
const e = new Uint16Array(
|
|
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
|
|
89
|
-
const e = new Uint8Array(
|
|
90
|
-
for (let t = 0; t <
|
|
91
|
-
e[t] =
|
|
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
|
|
95
|
-
const e = new Uint8Array(
|
|
96
|
-
for (let t = 0; t <
|
|
97
|
-
e[t] =
|
|
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
|
|
102
|
+
throw new S();
|
|
103
103
|
}
|
|
104
|
-
function
|
|
105
|
-
return Array.isArray(
|
|
104
|
+
function f(a) {
|
|
105
|
+
return Array.isArray(a) ? a : a.split("/").filter(Boolean);
|
|
106
106
|
}
|
|
107
|
-
function
|
|
108
|
-
return typeof
|
|
107
|
+
function p(a) {
|
|
108
|
+
return typeof a == "string" ? a ?? "/" : `/${a.join("/")}`;
|
|
109
109
|
}
|
|
110
|
-
function
|
|
111
|
-
return typeof
|
|
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(
|
|
114
|
-
const e = await
|
|
113
|
+
async function x(a) {
|
|
114
|
+
const e = await a.createSyncAccessHandle();
|
|
115
115
|
try {
|
|
116
|
-
const t = e.getSize(),
|
|
117
|
-
return e.read(
|
|
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
|
|
123
|
-
let
|
|
122
|
+
async function F(a, e, t, r = {}) {
|
|
123
|
+
let n = null;
|
|
124
124
|
try {
|
|
125
|
-
|
|
126
|
-
const i =
|
|
127
|
-
|
|
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
|
|
131
|
-
throw new
|
|
130
|
+
const s = r.append ? "append" : "write";
|
|
131
|
+
throw new o(`Failed to ${s} file`, `${s.toUpperCase()}_FAILED`);
|
|
132
132
|
} finally {
|
|
133
|
-
if (
|
|
133
|
+
if (n)
|
|
134
134
|
try {
|
|
135
|
-
|
|
135
|
+
n.close();
|
|
136
136
|
} catch {
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
-
async function
|
|
140
|
+
async function O(a, e = "SHA-1") {
|
|
141
141
|
try {
|
|
142
|
-
const t = new Uint8Array(
|
|
143
|
-
return Array.from(new Uint8Array(
|
|
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
|
|
178
|
-
return this.root = await this.getDirectoryHandle(e, !0, t), !0;
|
|
179
|
-
} catch (
|
|
180
|
-
throw console.error(
|
|
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,
|
|
202
|
-
if (!
|
|
211
|
+
async getDirectoryHandle(e, t = !1, r = this.root) {
|
|
212
|
+
if (!r)
|
|
203
213
|
throw new y();
|
|
204
|
-
const
|
|
205
|
-
let i =
|
|
206
|
-
for (const
|
|
207
|
-
i = await i.getDirectoryHandle(
|
|
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,
|
|
230
|
-
if (!
|
|
239
|
+
async getFileHandle(e, t = !1, r = this.root) {
|
|
240
|
+
if (!r)
|
|
231
241
|
throw new y();
|
|
232
|
-
const
|
|
233
|
-
if (
|
|
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 =
|
|
236
|
-
return (await this.getDirectoryHandle(
|
|
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(),
|
|
277
|
-
const i = await this.readdir(
|
|
278
|
-
for (const
|
|
279
|
-
const
|
|
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
|
|
282
|
-
t.set(
|
|
283
|
-
} catch (
|
|
284
|
-
console.warn(`Skipping broken entry: ${
|
|
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
|
|
305
|
+
}), await r("/"), t;
|
|
296
306
|
}
|
|
297
307
|
async readFile(e, t = "utf-8") {
|
|
298
308
|
try {
|
|
299
|
-
const
|
|
300
|
-
return t === "binary" ?
|
|
301
|
-
} catch (
|
|
302
|
-
throw console.error(
|
|
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,
|
|
331
|
-
const
|
|
332
|
-
await
|
|
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,
|
|
357
|
-
const
|
|
358
|
-
await
|
|
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
|
|
394
|
+
const r = t?.recursive ?? !1, n = f(e);
|
|
385
395
|
let i = this.root;
|
|
386
|
-
for (let
|
|
387
|
-
const
|
|
396
|
+
for (let s = 0; s < n.length; s++) {
|
|
397
|
+
const c = n[s];
|
|
388
398
|
try {
|
|
389
|
-
i = await i.getDirectoryHandle(
|
|
390
|
-
} catch (
|
|
391
|
-
throw
|
|
392
|
-
`Parent directory does not exist: ${
|
|
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
|
-
) :
|
|
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
|
|
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
|
|
440
|
+
const h = await (await i.getFileHandle(n, { create: !1 })).getFile(), w = {
|
|
431
441
|
kind: "file",
|
|
432
|
-
size:
|
|
433
|
-
mtime: new Date(
|
|
434
|
-
ctime: new Date(
|
|
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 (
|
|
448
|
+
if (s)
|
|
439
449
|
try {
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
} catch (
|
|
443
|
-
console.warn(`Failed to calculate hash for ${e}:`,
|
|
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
|
|
446
|
-
} catch (
|
|
447
|
-
if (
|
|
448
|
-
throw new
|
|
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(
|
|
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 (
|
|
461
|
-
throw
|
|
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
|
|
466
|
-
if (
|
|
475
|
+
const r = t?.withFileTypes ?? !1, n = await this.getDirectoryHandle(e, !1);
|
|
476
|
+
if (r) {
|
|
467
477
|
const i = [];
|
|
468
|
-
for await (const [
|
|
469
|
-
const
|
|
478
|
+
for await (const [s, c] of n.entries()) {
|
|
479
|
+
const l = c.kind === "file";
|
|
470
480
|
i.push({
|
|
471
|
-
name:
|
|
472
|
-
kind:
|
|
473
|
-
isFile:
|
|
474
|
-
isDirectory: !
|
|
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 [
|
|
481
|
-
i.push(
|
|
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 =
|
|
501
|
-
let
|
|
510
|
+
const t = f(e), r = t.pop();
|
|
511
|
+
let n = null;
|
|
502
512
|
try {
|
|
503
|
-
|
|
513
|
+
n = await this.getDirectoryHandle(t, !1);
|
|
504
514
|
} catch (i) {
|
|
505
|
-
throw (i.name === "NotFoundError" || i.name === "TypeMismatchError") && (
|
|
515
|
+
throw (i.name === "NotFoundError" || i.name === "TypeMismatchError") && (n = null), i;
|
|
506
516
|
}
|
|
507
|
-
if (!
|
|
517
|
+
if (!n || !r)
|
|
508
518
|
return !1;
|
|
509
519
|
try {
|
|
510
|
-
return await
|
|
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
|
|
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
|
|
546
|
-
const
|
|
547
|
-
await this.remove(
|
|
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
|
|
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
|
|
579
|
-
if (!
|
|
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
|
|
591
|
+
const c = await this.getDirectoryHandle(i, !1);
|
|
582
592
|
try {
|
|
583
|
-
await
|
|
584
|
-
} catch (
|
|
585
|
-
if (
|
|
586
|
-
if (!
|
|
587
|
-
throw new
|
|
588
|
-
} else throw
|
|
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 =
|
|
612
|
-
for (const
|
|
613
|
-
if (!(
|
|
614
|
-
if (
|
|
615
|
-
if (
|
|
616
|
-
throw new
|
|
617
|
-
|
|
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
|
-
|
|
620
|
-
const
|
|
621
|
-
if (!await this.exists(
|
|
622
|
-
throw new m(
|
|
623
|
-
return
|
|
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
|
|
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 (
|
|
650
|
-
throw
|
|
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,
|
|
688
|
+
async copy(e, t, r) {
|
|
679
689
|
try {
|
|
680
|
-
const
|
|
690
|
+
const n = r?.recursive ?? !1, i = r?.force ?? !0;
|
|
681
691
|
if (!await this.exists(e))
|
|
682
|
-
throw new
|
|
692
|
+
throw new o(`Source does not exist: ${e}`, "ENOENT");
|
|
683
693
|
if (await this.exists(t) && !i)
|
|
684
|
-
throw new
|
|
694
|
+
throw new o(`Destination already exists: ${t}`, "EEXIST");
|
|
685
695
|
if ((await this.stat(e)).isFile) {
|
|
686
|
-
const
|
|
687
|
-
await this.writeFile(t,
|
|
696
|
+
const h = await this.readFile(e, "binary");
|
|
697
|
+
await this.writeFile(t, h);
|
|
688
698
|
} else {
|
|
689
|
-
if (!
|
|
690
|
-
throw new
|
|
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
|
|
693
|
-
for (const
|
|
694
|
-
const
|
|
695
|
-
await this.copy(
|
|
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
|
-
}
|
|
699
|
-
|
|
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 [
|
|
734
|
-
const
|
|
735
|
-
let
|
|
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
|
|
738
|
-
|
|
806
|
+
const l = await i.arrayBuffer();
|
|
807
|
+
c = new Uint8Array(l);
|
|
739
808
|
} else
|
|
740
|
-
|
|
741
|
-
await this.writeFile(
|
|
809
|
+
c = i;
|
|
810
|
+
await this.writeFile(s, c);
|
|
742
811
|
}
|
|
743
|
-
} catch (
|
|
744
|
-
throw
|
|
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
|
-
|
|
817
|
+
typeof self < "u" && self.constructor.name === "DedicatedWorkerGlobalScope" && E(new U());
|
|
749
818
|
export {
|
|
750
819
|
U as OPFSWorker
|
|
751
820
|
};
|