opfs-worker 0.2.0 → 0.2.2
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 +260 -27
- package/dist/assets/worker-CMvl9yOu.js.map +1 -0
- package/dist/helpers-Co-qCBmA.js +224 -0
- package/dist/helpers-Co-qCBmA.js.map +1 -0
- package/dist/helpers-hEpet7x7.cjs +2 -0
- package/dist/helpers-hEpet7x7.cjs.map +1 -0
- package/dist/index.cjs +320 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +9 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1184 -24
- package/dist/index.js.map +1 -1
- package/dist/raw.cjs +1 -1
- package/dist/raw.cjs.map +1 -1
- package/dist/raw.js +257 -363
- package/dist/raw.js.map +1 -1
- package/dist/types.d.ts +4 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/encoder.d.ts.map +1 -1
- package/dist/utils/helpers.d.ts +108 -0
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/worker.d.ts +36 -8
- package/dist/worker.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/assets/worker-D5GbafFH.js.map +0 -1
- package/dist/test/setup.d.ts +0 -2
- package/dist/test/setup.d.ts.map +0 -1
- package/dist/test/setup.js +0 -148
- package/dist/types.js +0 -1
- package/dist/utils/encoder.js +0 -86
- package/dist/utils/errors.js +0 -77
- package/dist/utils/helpers.js +0 -96
- package/dist/worker.js +0 -865
package/dist/raw.js
CHANGED
|
@@ -1,151 +1,6 @@
|
|
|
1
|
-
import { expose as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
super(e), this.code = t, this.path = r, this.name = "OPFSError";
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
class S extends o {
|
|
8
|
-
constructor() {
|
|
9
|
-
super("OPFS is not supported in this browser", "OPFS_NOT_SUPPORTED");
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
class y extends o {
|
|
13
|
-
constructor() {
|
|
14
|
-
super("OPFS is not mounted", "OPFS_NOT_MOUNTED");
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
class g extends o {
|
|
18
|
-
constructor(e, t) {
|
|
19
|
-
super(e, "INVALID_PATH", t);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
class m extends o {
|
|
23
|
-
constructor(e) {
|
|
24
|
-
super(`File not found: ${e}`, "FILE_NOT_FOUND", e);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function A(a, e = "utf-8") {
|
|
28
|
-
switch (e) {
|
|
29
|
-
case "utf8":
|
|
30
|
-
case "utf-8":
|
|
31
|
-
return new TextEncoder().encode(a);
|
|
32
|
-
case "utf16le":
|
|
33
|
-
case "ucs2":
|
|
34
|
-
case "ucs-2":
|
|
35
|
-
return I(a);
|
|
36
|
-
case "ascii":
|
|
37
|
-
return $(a);
|
|
38
|
-
case "latin1":
|
|
39
|
-
return v(a);
|
|
40
|
-
case "binary":
|
|
41
|
-
return Uint8Array.from(a, (t) => t.charCodeAt(0));
|
|
42
|
-
case "base64":
|
|
43
|
-
return Uint8Array.from(atob(a), (t) => t.charCodeAt(0));
|
|
44
|
-
case "hex":
|
|
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
|
-
default:
|
|
49
|
-
return console.warn("Encoding not supported, falling back to UTF-8"), new TextEncoder().encode(a);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function D(a, e = "utf-8") {
|
|
53
|
-
switch (e) {
|
|
54
|
-
case "utf8":
|
|
55
|
-
case "utf-8":
|
|
56
|
-
return new TextDecoder().decode(a);
|
|
57
|
-
case "utf16le":
|
|
58
|
-
case "ucs2":
|
|
59
|
-
case "ucs-2":
|
|
60
|
-
return T(a);
|
|
61
|
-
case "latin1":
|
|
62
|
-
return String.fromCharCode(...a);
|
|
63
|
-
case "binary":
|
|
64
|
-
return String.fromCharCode(...a);
|
|
65
|
-
case "ascii":
|
|
66
|
-
return String.fromCharCode(...a.map((t) => t & 127));
|
|
67
|
-
case "base64":
|
|
68
|
-
return btoa(String.fromCharCode(...a));
|
|
69
|
-
case "hex":
|
|
70
|
-
return Array.from(a).map((t) => t.toString(16).padStart(2, "0")).join("");
|
|
71
|
-
default:
|
|
72
|
-
return console.warn("Unsupported encoding, falling back to UTF-8"), new TextDecoder().decode(a);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
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
|
-
}
|
|
81
|
-
return e;
|
|
82
|
-
}
|
|
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
|
-
return String.fromCharCode(...e);
|
|
87
|
-
}
|
|
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
|
-
return e;
|
|
93
|
-
}
|
|
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
|
-
return e;
|
|
99
|
-
}
|
|
100
|
-
function N() {
|
|
101
|
-
if (!("storage" in navigator) || !("getDirectory" in navigator.storage))
|
|
102
|
-
throw new S();
|
|
103
|
-
}
|
|
104
|
-
function f(a) {
|
|
105
|
-
return Array.isArray(a) ? a : a.split("/").filter(Boolean);
|
|
106
|
-
}
|
|
107
|
-
function p(a) {
|
|
108
|
-
return typeof a == "string" ? a ?? "/" : `/${a.join("/")}`;
|
|
109
|
-
}
|
|
110
|
-
function H(a, e = "utf-8") {
|
|
111
|
-
return typeof a == "string" ? A(a, e) : a instanceof Uint8Array ? a : new Uint8Array(a);
|
|
112
|
-
}
|
|
113
|
-
async function x(a) {
|
|
114
|
-
const e = await a.createSyncAccessHandle();
|
|
115
|
-
try {
|
|
116
|
-
const t = e.getSize(), r = new Uint8Array(t);
|
|
117
|
-
return e.read(r, { at: 0 }), r;
|
|
118
|
-
} finally {
|
|
119
|
-
e.close();
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
async function F(a, e, t, r = {}) {
|
|
123
|
-
let n = null;
|
|
124
|
-
try {
|
|
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
|
-
} catch (i) {
|
|
129
|
-
console.error(i);
|
|
130
|
-
const s = r.append ? "append" : "write";
|
|
131
|
-
throw new o(`Failed to ${s} file`, `${s.toUpperCase()}_FAILED`);
|
|
132
|
-
} finally {
|
|
133
|
-
if (n)
|
|
134
|
-
try {
|
|
135
|
-
n.close();
|
|
136
|
-
} catch {
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
async function O(a, e = "SHA-1") {
|
|
141
|
-
try {
|
|
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
|
-
} catch (t) {
|
|
145
|
-
throw console.warn(`Failed to calculate ${e} hash:`, t), t;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
class U {
|
|
1
|
+
import { expose as p } from "comlink";
|
|
2
|
+
import { d as v, O as o, b as f, s as u, P as E, i as I, o as S, F as d, w as g, j as T, e as m, f as y, k as M, r as H, n as F, l as P } from "./helpers-Co-qCBmA.js";
|
|
3
|
+
class $ {
|
|
149
4
|
/** Root directory handle for the file system */
|
|
150
5
|
root = null;
|
|
151
6
|
/** Watch event callback */
|
|
@@ -158,19 +13,23 @@ class U {
|
|
|
158
13
|
watchInterval = 1e3;
|
|
159
14
|
/** Flag to avoid concurrent scans */
|
|
160
15
|
scanning = !1;
|
|
16
|
+
/** Promise to prevent concurrent mount operations */
|
|
17
|
+
mountingPromise = null;
|
|
161
18
|
/**
|
|
162
19
|
* Creates a new OPFSFileSystem instance
|
|
163
20
|
*
|
|
21
|
+
* @param watchCallback - Optional callback for file change events
|
|
22
|
+
* @param watchOptions - Optional configuration for watching
|
|
164
23
|
* @throws {OPFSError} If OPFS is not supported in the current browser
|
|
165
24
|
*/
|
|
166
|
-
constructor() {
|
|
167
|
-
|
|
25
|
+
constructor(t, e) {
|
|
26
|
+
v(), t && (this.watchCallback = t, e?.watchInterval && (this.watchInterval = e.watchInterval)), this.mount("/");
|
|
168
27
|
}
|
|
169
28
|
/**
|
|
170
29
|
* Initialize the file system within a given directory
|
|
171
30
|
*
|
|
172
31
|
* This method sets up the root directory for all subsequent operations.
|
|
173
|
-
*
|
|
32
|
+
* If no root is specified, it will use the OPFS root directory.
|
|
174
33
|
*
|
|
175
34
|
* @param root - The root path for the file system (default: '/')
|
|
176
35
|
* @returns Promise that resolves to true if initialization was successful
|
|
@@ -179,15 +38,52 @@ class U {
|
|
|
179
38
|
* @example
|
|
180
39
|
* ```typescript
|
|
181
40
|
* const fs = new OPFSFileSystem();
|
|
182
|
-
*
|
|
41
|
+
*
|
|
42
|
+
* // Use OPFS root (default)
|
|
43
|
+
* await fs.mount();
|
|
44
|
+
*
|
|
45
|
+
* // Use custom directory
|
|
46
|
+
* await fs.mount('/my-app');
|
|
183
47
|
* ```
|
|
184
48
|
*/
|
|
185
|
-
async mount(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
49
|
+
async mount(t = "/") {
|
|
50
|
+
return this.mountingPromise && await this.mountingPromise, this.mountingPromise = new Promise(async (e, i) => {
|
|
51
|
+
this.root = null;
|
|
52
|
+
try {
|
|
53
|
+
const r = await navigator.storage.getDirectory();
|
|
54
|
+
t === "/" ? this.root = r : this.root = await this.getDirectoryHandle(t, !0, r), e(!0);
|
|
55
|
+
} catch (r) {
|
|
56
|
+
console.error(r), i(new o("Failed to initialize OPFS", "INIT_FAILED"));
|
|
57
|
+
} finally {
|
|
58
|
+
this.mountingPromise = null;
|
|
59
|
+
}
|
|
60
|
+
}), this.mountingPromise;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Set the watch callback for file change events
|
|
64
|
+
*
|
|
65
|
+
* @param callback - The callback function to invoke when files change
|
|
66
|
+
* @param options - Optional configuration for watching
|
|
67
|
+
*/
|
|
68
|
+
setWatchCallback(t, e) {
|
|
69
|
+
this.watchCallback = t, e?.watchInterval && (this.watchInterval = e.watchInterval);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Automatically mount the OPFS root if not already mounted
|
|
73
|
+
*
|
|
74
|
+
* This method is called internally when file operations are performed
|
|
75
|
+
* without explicitly mounting first.
|
|
76
|
+
*
|
|
77
|
+
* @returns Promise that resolves when auto-mount is complete
|
|
78
|
+
* @throws {OPFSError} If auto-mount fails
|
|
79
|
+
*/
|
|
80
|
+
async ensureMounted() {
|
|
81
|
+
if (!this.root) {
|
|
82
|
+
if (this.mountingPromise) {
|
|
83
|
+
await this.mountingPromise;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
throw new o("OPFS not mounted", "NOT_MOUNTED");
|
|
191
87
|
}
|
|
192
88
|
}
|
|
193
89
|
/**
|
|
@@ -208,14 +104,14 @@ class U {
|
|
|
208
104
|
* const docsDir2 = await fs.getDirectoryHandle(['users', 'john', 'documents'], true);
|
|
209
105
|
* ```
|
|
210
106
|
*/
|
|
211
|
-
async getDirectoryHandle(
|
|
212
|
-
if (!
|
|
213
|
-
throw new
|
|
214
|
-
const
|
|
215
|
-
let
|
|
216
|
-
for (const
|
|
217
|
-
|
|
218
|
-
return
|
|
107
|
+
async getDirectoryHandle(t, e = !1, i = this.root) {
|
|
108
|
+
if (!i)
|
|
109
|
+
throw new f();
|
|
110
|
+
const r = Array.isArray(t) ? t : u(t);
|
|
111
|
+
let a = i;
|
|
112
|
+
for (const n of r)
|
|
113
|
+
a = await a.getDirectoryHandle(n, { create: e });
|
|
114
|
+
return a;
|
|
219
115
|
}
|
|
220
116
|
/**
|
|
221
117
|
* Get a file handle from a path
|
|
@@ -236,14 +132,14 @@ class U {
|
|
|
236
132
|
* const fileHandle2 = await fs.getFileHandle(['config', 'settings.json'], true);
|
|
237
133
|
* ```
|
|
238
134
|
*/
|
|
239
|
-
async getFileHandle(
|
|
240
|
-
if (!
|
|
241
|
-
throw new
|
|
242
|
-
const
|
|
243
|
-
if (
|
|
244
|
-
throw new
|
|
245
|
-
const
|
|
246
|
-
return (await this.getDirectoryHandle(
|
|
135
|
+
async getFileHandle(t, e = !1, i = this.root) {
|
|
136
|
+
if (!i)
|
|
137
|
+
throw new f();
|
|
138
|
+
const r = u(t);
|
|
139
|
+
if (r.length === 0)
|
|
140
|
+
throw new E("Path must not be empty", Array.isArray(t) ? t.join("/") : t);
|
|
141
|
+
const a = r.pop();
|
|
142
|
+
return (await this.getDirectoryHandle(r, e, i)).getFileHandle(a, { create: e });
|
|
247
143
|
}
|
|
248
144
|
/**
|
|
249
145
|
* Recursively list all files and directories with their stats
|
|
@@ -282,34 +178,35 @@ class U {
|
|
|
282
178
|
* }
|
|
283
179
|
* ```
|
|
284
180
|
*/
|
|
285
|
-
async index(
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
for (const
|
|
289
|
-
const
|
|
181
|
+
async index(t) {
|
|
182
|
+
const e = /* @__PURE__ */ new Map(), i = async (r) => {
|
|
183
|
+
const a = await this.readdir(r, { withFileTypes: !0 });
|
|
184
|
+
for (const n of a) {
|
|
185
|
+
const s = `${r === "/" ? "" : r}/${n.name}`;
|
|
290
186
|
try {
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
} catch (
|
|
294
|
-
console.warn(`Skipping broken entry: ${
|
|
187
|
+
const c = await this.stat(s, t);
|
|
188
|
+
e.set(s, c), c.isDirectory && await i(s);
|
|
189
|
+
} catch (c) {
|
|
190
|
+
console.warn(`Skipping broken entry: ${s}`, c);
|
|
295
191
|
}
|
|
296
192
|
}
|
|
297
193
|
};
|
|
298
|
-
return
|
|
194
|
+
return e.set("/", {
|
|
299
195
|
kind: "directory",
|
|
300
196
|
size: 0,
|
|
301
197
|
mtime: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
302
198
|
ctime: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
303
199
|
isFile: !1,
|
|
304
200
|
isDirectory: !0
|
|
305
|
-
}), await
|
|
201
|
+
}), await i("/"), e;
|
|
306
202
|
}
|
|
307
|
-
async readFile(
|
|
203
|
+
async readFile(t, e = "utf-8") {
|
|
204
|
+
await this.ensureMounted();
|
|
308
205
|
try {
|
|
309
|
-
const
|
|
310
|
-
return
|
|
311
|
-
} catch (
|
|
312
|
-
throw console.error(
|
|
206
|
+
const i = await this.getFileHandle(t, !1), r = await I(i);
|
|
207
|
+
return e === "binary" ? r : S(r, e);
|
|
208
|
+
} catch (i) {
|
|
209
|
+
throw console.error(i), new d(t);
|
|
313
210
|
}
|
|
314
211
|
}
|
|
315
212
|
/**
|
|
@@ -337,9 +234,10 @@ class U {
|
|
|
337
234
|
* await fs.writeFile('/data/utf16.txt', 'Hello World', 'utf-16le');
|
|
338
235
|
* ```
|
|
339
236
|
*/
|
|
340
|
-
async writeFile(
|
|
341
|
-
|
|
342
|
-
await
|
|
237
|
+
async writeFile(t, e, i) {
|
|
238
|
+
await this.ensureMounted();
|
|
239
|
+
const r = await this.getFileHandle(t, !0);
|
|
240
|
+
await g(r, e, i, { truncate: !0 });
|
|
343
241
|
}
|
|
344
242
|
/**
|
|
345
243
|
* Append data to a file
|
|
@@ -363,9 +261,10 @@ class U {
|
|
|
363
261
|
* await fs.appendFile('/data/binary.dat', additionalData);
|
|
364
262
|
* ```
|
|
365
263
|
*/
|
|
366
|
-
async appendFile(
|
|
367
|
-
|
|
368
|
-
await
|
|
264
|
+
async appendFile(t, e, i) {
|
|
265
|
+
await this.ensureMounted();
|
|
266
|
+
const r = await this.getFileHandle(t, !0);
|
|
267
|
+
await g(r, e, i, { append: !0 });
|
|
369
268
|
}
|
|
370
269
|
/**
|
|
371
270
|
* Create a directory
|
|
@@ -388,20 +287,20 @@ class U {
|
|
|
388
287
|
* await fs.mkdir('/users/john/documents/projects', { recursive: true });
|
|
389
288
|
* ```
|
|
390
289
|
*/
|
|
391
|
-
async mkdir(
|
|
392
|
-
if (!this.root)
|
|
393
|
-
throw new
|
|
394
|
-
const
|
|
395
|
-
let
|
|
396
|
-
for (let
|
|
397
|
-
const
|
|
290
|
+
async mkdir(t, e) {
|
|
291
|
+
if (await this.ensureMounted(), !this.root)
|
|
292
|
+
throw new f();
|
|
293
|
+
const i = e?.recursive ?? !1, r = u(t);
|
|
294
|
+
let a = this.root;
|
|
295
|
+
for (let n = 0; n < r.length; n++) {
|
|
296
|
+
const s = r[n];
|
|
398
297
|
try {
|
|
399
|
-
|
|
400
|
-
} catch (
|
|
401
|
-
throw
|
|
402
|
-
`Parent directory does not exist: ${
|
|
298
|
+
a = await a.getDirectoryHandle(s, { create: i || n === r.length - 1 });
|
|
299
|
+
} catch (c) {
|
|
300
|
+
throw c.name === "NotFoundError" ? new o(
|
|
301
|
+
`Parent directory does not exist: ${T(r.slice(0, n + 1))}`,
|
|
403
302
|
"ENOENT"
|
|
404
|
-
) :
|
|
303
|
+
) : c.name === "TypeMismatchError" ? new o(`Path segment is not a directory: ${s}`, "ENOTDIR") : new o("Failed to create directory", "MKDIR_FAILED");
|
|
405
304
|
}
|
|
406
305
|
}
|
|
407
306
|
}
|
|
@@ -434,62 +333,63 @@ class U {
|
|
|
434
333
|
* console.log(`Hash: ${statsWithHash.hash}`);
|
|
435
334
|
* ```
|
|
436
335
|
*/
|
|
437
|
-
async stat(
|
|
438
|
-
|
|
336
|
+
async stat(t, e) {
|
|
337
|
+
await this.ensureMounted();
|
|
338
|
+
const i = m(t), r = await this.getDirectoryHandle(y(t), !1), a = e?.includeHash ?? !1, n = e?.hashAlgorithm ?? "SHA-1";
|
|
439
339
|
try {
|
|
440
|
-
const
|
|
340
|
+
const c = await (await r.getFileHandle(i, { create: !1 })).getFile(), l = {
|
|
441
341
|
kind: "file",
|
|
442
|
-
size:
|
|
443
|
-
mtime: new Date(
|
|
444
|
-
ctime: new Date(
|
|
342
|
+
size: c.size,
|
|
343
|
+
mtime: new Date(c.lastModified).toISOString(),
|
|
344
|
+
ctime: new Date(c.lastModified).toISOString(),
|
|
445
345
|
isFile: !0,
|
|
446
346
|
isDirectory: !1
|
|
447
347
|
};
|
|
448
|
-
if (
|
|
348
|
+
if (a)
|
|
449
349
|
try {
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
} catch (
|
|
453
|
-
console.warn(`Failed to calculate hash for ${
|
|
350
|
+
const h = new Uint8Array(await c.arrayBuffer()), w = await M(h, n);
|
|
351
|
+
l.hash = w;
|
|
352
|
+
} catch (h) {
|
|
353
|
+
console.warn(`Failed to calculate hash for ${t}:`, h);
|
|
454
354
|
}
|
|
455
|
-
return
|
|
456
|
-
} catch (
|
|
457
|
-
if (
|
|
355
|
+
return l;
|
|
356
|
+
} catch (s) {
|
|
357
|
+
if (s.name !== "TypeMismatchError" && s.name !== "NotFoundError")
|
|
458
358
|
throw new o("Failed to stat (file)", "STAT_FAILED");
|
|
459
359
|
}
|
|
460
360
|
try {
|
|
461
|
-
return await
|
|
361
|
+
return await r.getDirectoryHandle(i, { create: !1 }), {
|
|
462
362
|
kind: "directory",
|
|
463
363
|
size: 0,
|
|
464
364
|
mtime: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
465
365
|
ctime: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
466
366
|
isFile: !1,
|
|
467
367
|
isDirectory: !0
|
|
468
|
-
// Directories don't have hashes
|
|
469
368
|
};
|
|
470
|
-
} catch (
|
|
471
|
-
throw
|
|
369
|
+
} catch (s) {
|
|
370
|
+
throw s.name === "NotFoundError" ? new o(`No such file or directory: ${t}`, "ENOENT") : new o("Failed to stat (directory)", "STAT_FAILED");
|
|
472
371
|
}
|
|
473
372
|
}
|
|
474
|
-
async readdir(
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
373
|
+
async readdir(t, e) {
|
|
374
|
+
await this.ensureMounted();
|
|
375
|
+
const i = e?.withFileTypes ?? !1, r = await this.getDirectoryHandle(t, !1);
|
|
376
|
+
if (i) {
|
|
377
|
+
const a = [];
|
|
378
|
+
for await (const [n, s] of r.entries()) {
|
|
379
|
+
const c = s.kind === "file";
|
|
380
|
+
a.push({
|
|
381
|
+
name: n,
|
|
382
|
+
kind: s.kind,
|
|
383
|
+
isFile: c,
|
|
384
|
+
isDirectory: !c
|
|
485
385
|
});
|
|
486
386
|
}
|
|
487
|
-
return
|
|
387
|
+
return a;
|
|
488
388
|
} else {
|
|
489
|
-
const
|
|
490
|
-
for await (const [
|
|
491
|
-
|
|
492
|
-
return
|
|
389
|
+
const a = [];
|
|
390
|
+
for await (const [n] of r.entries())
|
|
391
|
+
a.push(n);
|
|
392
|
+
return a;
|
|
493
393
|
}
|
|
494
394
|
}
|
|
495
395
|
/**
|
|
@@ -506,27 +406,28 @@ class U {
|
|
|
506
406
|
* console.log(`File exists: ${exists}`);
|
|
507
407
|
* ```
|
|
508
408
|
*/
|
|
509
|
-
async exists(
|
|
510
|
-
|
|
511
|
-
|
|
409
|
+
async exists(t) {
|
|
410
|
+
await this.ensureMounted();
|
|
411
|
+
const e = m(t);
|
|
412
|
+
let i = null;
|
|
512
413
|
try {
|
|
513
|
-
|
|
514
|
-
} catch (
|
|
515
|
-
throw (
|
|
414
|
+
i = await this.getDirectoryHandle(y(t), !1);
|
|
415
|
+
} catch (r) {
|
|
416
|
+
throw (r.name === "NotFoundError" || r.name === "TypeMismatchError") && (i = null), r;
|
|
516
417
|
}
|
|
517
|
-
if (!
|
|
418
|
+
if (!i || !e)
|
|
518
419
|
return !1;
|
|
519
420
|
try {
|
|
520
|
-
return await
|
|
521
|
-
} catch (
|
|
522
|
-
if (
|
|
523
|
-
throw
|
|
421
|
+
return await i.getFileHandle(e, { create: !1 }), !0;
|
|
422
|
+
} catch (r) {
|
|
423
|
+
if (r.name !== "NotFoundError" && r.name !== "TypeMismatchError")
|
|
424
|
+
throw r;
|
|
524
425
|
}
|
|
525
426
|
try {
|
|
526
|
-
return await
|
|
527
|
-
} catch (
|
|
528
|
-
if (
|
|
529
|
-
throw
|
|
427
|
+
return await i.getDirectoryHandle(e, { create: !1 }), !0;
|
|
428
|
+
} catch (r) {
|
|
429
|
+
if (r.name !== "NotFoundError" && r.name !== "TypeMismatchError")
|
|
430
|
+
throw r;
|
|
530
431
|
}
|
|
531
432
|
return !1;
|
|
532
433
|
}
|
|
@@ -549,15 +450,16 @@ class U {
|
|
|
549
450
|
* await fs.clear('/data');
|
|
550
451
|
* ```
|
|
551
452
|
*/
|
|
552
|
-
async clear(
|
|
453
|
+
async clear(t = "/") {
|
|
454
|
+
await this.ensureMounted();
|
|
553
455
|
try {
|
|
554
|
-
const
|
|
555
|
-
for (const
|
|
556
|
-
const
|
|
557
|
-
await this.remove(
|
|
456
|
+
const e = await this.readdir(t, { withFileTypes: !0 });
|
|
457
|
+
for (const i of e) {
|
|
458
|
+
const r = `${t === "/" ? "" : t}/${i.name}`;
|
|
459
|
+
await this.remove(r, { recursive: !0 });
|
|
558
460
|
}
|
|
559
|
-
} catch (
|
|
560
|
-
throw
|
|
461
|
+
} catch (e) {
|
|
462
|
+
throw e instanceof o ? e : new o(`Failed to clear directory: ${t}`, "CLEAR_FAILED");
|
|
561
463
|
}
|
|
562
464
|
}
|
|
563
465
|
/**
|
|
@@ -584,18 +486,19 @@ class U {
|
|
|
584
486
|
* await fs.rm('/maybe/exists', { force: true });
|
|
585
487
|
* ```
|
|
586
488
|
*/
|
|
587
|
-
async remove(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
489
|
+
async remove(t, e) {
|
|
490
|
+
await this.ensureMounted();
|
|
491
|
+
const i = e?.recursive ?? !1, r = e?.force ?? !1, a = m(t);
|
|
492
|
+
if (!a)
|
|
493
|
+
throw new E("Invalid path", t);
|
|
494
|
+
const n = await this.getDirectoryHandle(y(t), !1);
|
|
592
495
|
try {
|
|
593
|
-
await
|
|
594
|
-
} catch (
|
|
595
|
-
if (
|
|
596
|
-
if (!
|
|
597
|
-
throw new o(`No such file or directory: ${
|
|
598
|
-
} else throw
|
|
496
|
+
await n.removeEntry(a, { recursive: i });
|
|
497
|
+
} catch (s) {
|
|
498
|
+
if (s.name === "NotFoundError") {
|
|
499
|
+
if (!r)
|
|
500
|
+
throw new o(`No such file or directory: ${t}`, "ENOENT");
|
|
501
|
+
} else throw s.name === "InvalidModificationError" ? new o(`Directory not empty: ${t}. Use recursive option to force removal.`, "ENOTEMPTY") : s.name === "TypeMismatchError" && !i ? new o(`Cannot remove directory without recursive option: ${t}`, "EISDIR") : new o(`Failed to remove path: ${t}`, "RM_FAILED");
|
|
599
502
|
}
|
|
600
503
|
}
|
|
601
504
|
/**
|
|
@@ -616,23 +519,15 @@ class U {
|
|
|
616
519
|
* console.log(absolute); // '/data/file.txt'
|
|
617
520
|
* ```
|
|
618
521
|
*/
|
|
619
|
-
async realpath(
|
|
522
|
+
async realpath(t) {
|
|
523
|
+
await this.ensureMounted();
|
|
620
524
|
try {
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
r.length > 0 && r.pop();
|
|
628
|
-
} else
|
|
629
|
-
r.push(s);
|
|
630
|
-
const n = p(r);
|
|
631
|
-
if (!await this.exists(n))
|
|
632
|
-
throw new m(n);
|
|
633
|
-
return n;
|
|
634
|
-
} catch (t) {
|
|
635
|
-
throw t instanceof o ? t : new o(`Failed to resolve path: ${e}`, "REALPATH_FAILED");
|
|
525
|
+
const e = H(t);
|
|
526
|
+
if (!await this.exists(e))
|
|
527
|
+
throw new d(e);
|
|
528
|
+
return e;
|
|
529
|
+
} catch (e) {
|
|
530
|
+
throw e instanceof o ? e : new o(`Failed to resolve path: ${t}`, "REALPATH_FAILED");
|
|
636
531
|
}
|
|
637
532
|
}
|
|
638
533
|
/**
|
|
@@ -651,13 +546,14 @@ class U {
|
|
|
651
546
|
* await fs.rename('/old/path/file.txt', '/new/path/renamed.txt');
|
|
652
547
|
* ```
|
|
653
548
|
*/
|
|
654
|
-
async rename(
|
|
549
|
+
async rename(t, e) {
|
|
550
|
+
await this.ensureMounted();
|
|
655
551
|
try {
|
|
656
|
-
if (!await this.exists(
|
|
657
|
-
throw new
|
|
658
|
-
await this.copy(
|
|
659
|
-
} catch (
|
|
660
|
-
throw
|
|
552
|
+
if (!await this.exists(t))
|
|
553
|
+
throw new d(t);
|
|
554
|
+
await this.copy(t, e, { recursive: !0 }), await this.remove(t, { recursive: !0 });
|
|
555
|
+
} catch (i) {
|
|
556
|
+
throw i instanceof o ? i : new o(`Failed to rename from ${t} to ${e}`, "RENAME_FAILED");
|
|
661
557
|
}
|
|
662
558
|
}
|
|
663
559
|
/**
|
|
@@ -676,91 +572,93 @@ class U {
|
|
|
676
572
|
* @example
|
|
677
573
|
* ```typescript
|
|
678
574
|
* // Copy a file
|
|
679
|
-
* await fs.
|
|
575
|
+
* await fs.copy('/source/file.txt', '/dest/file.txt');
|
|
680
576
|
*
|
|
681
577
|
* // Copy a directory and all its contents
|
|
682
|
-
* await fs.
|
|
578
|
+
* await fs.copy('/source/dir', '/dest/dir', { recursive: true });
|
|
683
579
|
*
|
|
684
580
|
* // Copy without overwriting existing files
|
|
685
|
-
* await fs.
|
|
581
|
+
* await fs.copy('/source', '/dest', { recursive: true, force: false });
|
|
686
582
|
* ```
|
|
687
583
|
*/
|
|
688
|
-
async copy(
|
|
584
|
+
async copy(t, e, i) {
|
|
585
|
+
await this.ensureMounted();
|
|
689
586
|
try {
|
|
690
|
-
const
|
|
691
|
-
if (!await this.exists(
|
|
692
|
-
throw new o(`Source does not exist: ${
|
|
693
|
-
if (await this.exists(
|
|
694
|
-
throw new o(`Destination already exists: ${
|
|
695
|
-
if ((await this.stat(
|
|
696
|
-
const
|
|
697
|
-
await this.writeFile(
|
|
587
|
+
const r = i?.recursive ?? !1, a = i?.force ?? !0;
|
|
588
|
+
if (!await this.exists(t))
|
|
589
|
+
throw new o(`Source does not exist: ${t}`, "ENOENT");
|
|
590
|
+
if (await this.exists(e) && !a)
|
|
591
|
+
throw new o(`Destination already exists: ${e}`, "EEXIST");
|
|
592
|
+
if ((await this.stat(t)).isFile) {
|
|
593
|
+
const l = await this.readFile(t, "binary");
|
|
594
|
+
await this.writeFile(e, l);
|
|
698
595
|
} else {
|
|
699
|
-
if (!
|
|
700
|
-
throw new o(`Cannot copy directory without recursive option: ${
|
|
701
|
-
await this.mkdir(
|
|
702
|
-
const
|
|
703
|
-
for (const
|
|
704
|
-
const
|
|
705
|
-
await this.copy(
|
|
596
|
+
if (!r)
|
|
597
|
+
throw new o(`Cannot copy directory without recursive option: ${t}`, "EISDIR");
|
|
598
|
+
await this.mkdir(e, { recursive: !0 });
|
|
599
|
+
const l = await this.readdir(t, { withFileTypes: !0 });
|
|
600
|
+
for (const h of l) {
|
|
601
|
+
const w = `${t}/${h.name}`, D = `${e}/${h.name}`;
|
|
602
|
+
await this.copy(w, D, { recursive: !0, force: a });
|
|
706
603
|
}
|
|
707
604
|
}
|
|
708
|
-
} catch (
|
|
709
|
-
throw
|
|
605
|
+
} catch (r) {
|
|
606
|
+
throw r instanceof o ? r : new o(`Failed to copy from ${t} to ${e}`, "CP_FAILED");
|
|
710
607
|
}
|
|
711
608
|
}
|
|
712
609
|
/**
|
|
713
610
|
* Start watching a file or directory for changes
|
|
714
611
|
*/
|
|
715
|
-
async watch(
|
|
716
|
-
|
|
717
|
-
|
|
612
|
+
async watch(t) {
|
|
613
|
+
await this.ensureMounted();
|
|
614
|
+
const e = F(t), i = await this.buildSnapshot(e);
|
|
615
|
+
this.watchers.set(e, i), this.watchTimer || (this.watchTimer = setInterval(() => {
|
|
718
616
|
this.scanWatches();
|
|
719
617
|
}, this.watchInterval));
|
|
720
618
|
}
|
|
721
619
|
/**
|
|
722
620
|
* Stop watching a previously watched path
|
|
723
621
|
*/
|
|
724
|
-
unwatch(
|
|
725
|
-
const
|
|
726
|
-
this.watchers.delete(
|
|
727
|
-
}
|
|
728
|
-
async buildSnapshot(
|
|
729
|
-
const
|
|
730
|
-
const
|
|
731
|
-
if (
|
|
732
|
-
const
|
|
733
|
-
for (const
|
|
734
|
-
const
|
|
735
|
-
await
|
|
622
|
+
unwatch(t) {
|
|
623
|
+
const e = F(t);
|
|
624
|
+
this.watchers.delete(e), this.watchers.size === 0 && this.watchTimer && (clearInterval(this.watchTimer), this.watchTimer = null);
|
|
625
|
+
}
|
|
626
|
+
async buildSnapshot(t) {
|
|
627
|
+
const e = /* @__PURE__ */ new Map(), i = async (r) => {
|
|
628
|
+
const a = await this.stat(r);
|
|
629
|
+
if (e.set(r, a), a.isDirectory) {
|
|
630
|
+
const n = await this.readdir(r, { withFileTypes: !0 });
|
|
631
|
+
for (const s of n) {
|
|
632
|
+
const c = `${r === "/" ? "" : r}/${s.name}`;
|
|
633
|
+
await i(c);
|
|
736
634
|
}
|
|
737
635
|
}
|
|
738
636
|
};
|
|
739
|
-
return await
|
|
637
|
+
return await i(t), e;
|
|
740
638
|
}
|
|
741
639
|
async scanWatches() {
|
|
742
640
|
if (!this.scanning) {
|
|
743
641
|
this.scanning = !0;
|
|
744
642
|
try {
|
|
745
643
|
await Promise.all(
|
|
746
|
-
[...this.watchers.entries()].map(async ([
|
|
747
|
-
let
|
|
644
|
+
[...this.watchers.entries()].map(async ([t, e]) => {
|
|
645
|
+
let i;
|
|
748
646
|
try {
|
|
749
|
-
|
|
647
|
+
i = await this.buildSnapshot(t);
|
|
750
648
|
} catch {
|
|
751
|
-
|
|
649
|
+
i = /* @__PURE__ */ new Map();
|
|
752
650
|
}
|
|
753
|
-
const
|
|
754
|
-
for (const [
|
|
755
|
-
const
|
|
756
|
-
|
|
651
|
+
const r = [];
|
|
652
|
+
for (const [a, n] of i) {
|
|
653
|
+
const s = e.get(a);
|
|
654
|
+
s ? (s.mtime !== n.mtime || s.size !== n.size) && r.push({ path: a, type: "change" }) : r.push({ path: a, type: "create" });
|
|
757
655
|
}
|
|
758
|
-
for (const
|
|
759
|
-
|
|
760
|
-
if (
|
|
761
|
-
for (const
|
|
762
|
-
this.watchCallback(
|
|
763
|
-
this.watchers.set(
|
|
656
|
+
for (const a of e.keys())
|
|
657
|
+
i.has(a) || r.push({ path: a, type: "delete" });
|
|
658
|
+
if (r.length && this.watchCallback)
|
|
659
|
+
for (const a of r)
|
|
660
|
+
this.watchCallback(a);
|
|
661
|
+
this.watchers.set(t, i);
|
|
764
662
|
})
|
|
765
663
|
);
|
|
766
664
|
} finally {
|
|
@@ -796,26 +694,22 @@ class U {
|
|
|
796
694
|
* await fs.sync(entries, { cleanBefore: true });
|
|
797
695
|
* ```
|
|
798
696
|
*/
|
|
799
|
-
async sync(
|
|
697
|
+
async sync(t, e) {
|
|
698
|
+
await this.ensureMounted();
|
|
800
699
|
try {
|
|
801
|
-
(
|
|
802
|
-
for (const [
|
|
803
|
-
const
|
|
804
|
-
let
|
|
805
|
-
|
|
806
|
-
const l = await i.arrayBuffer();
|
|
807
|
-
c = new Uint8Array(l);
|
|
808
|
-
} else
|
|
809
|
-
c = i;
|
|
810
|
-
await this.writeFile(s, c);
|
|
700
|
+
(e?.cleanBefore ?? !1) && await this.clear("/");
|
|
701
|
+
for (const [r, a] of t) {
|
|
702
|
+
const n = F(r);
|
|
703
|
+
let s;
|
|
704
|
+
a instanceof Blob ? s = await P(a) : s = a, await this.writeFile(n, s);
|
|
811
705
|
}
|
|
812
|
-
} catch (
|
|
813
|
-
throw
|
|
706
|
+
} catch (i) {
|
|
707
|
+
throw i instanceof o ? i : new o("Failed to sync file system", "SYNC_FAILED");
|
|
814
708
|
}
|
|
815
709
|
}
|
|
816
710
|
}
|
|
817
|
-
typeof self < "u" && self.constructor.name === "DedicatedWorkerGlobalScope" &&
|
|
711
|
+
typeof self < "u" && self.constructor.name === "DedicatedWorkerGlobalScope" && p(new $());
|
|
818
712
|
export {
|
|
819
|
-
|
|
713
|
+
$ as OPFSWorker
|
|
820
714
|
};
|
|
821
715
|
//# sourceMappingURL=raw.js.map
|