@themartiancompany/opfs 1.8.11
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/COPYING +674 -0
- package/README.cn.md +301 -0
- package/README.md +241 -0
- package/dist/main.cjs +1840 -0
- package/dist/main.cjs.map +1 -0
- package/dist/main.mjs +1751 -0
- package/dist/main.mjs.map +1 -0
- package/dist/types.d.ts +920 -0
- package/dist/types.d.ts.map +1 -0
- package/docs/README.md +115 -0
- package/docs/classes/SyncMessenger.md +42 -0
- package/docs/functions/appendFile.md +29 -0
- package/docs/functions/appendFileSync.md +26 -0
- package/docs/functions/assertAbsolutePath.md +29 -0
- package/docs/functions/assertFileUrl.md +29 -0
- package/docs/functions/connectSyncAgent.md +25 -0
- package/docs/functions/copy.md +35 -0
- package/docs/functions/copySync.md +30 -0
- package/docs/functions/createFile.md +27 -0
- package/docs/functions/createFileSync.md +25 -0
- package/docs/functions/deleteTemp.md +23 -0
- package/docs/functions/deleteTempSync.md +19 -0
- package/docs/functions/downloadFile.md +58 -0
- package/docs/functions/emptyDir.md +28 -0
- package/docs/functions/emptyDirSync.md +25 -0
- package/docs/functions/exists.md +29 -0
- package/docs/functions/existsSync.md +26 -0
- package/docs/functions/generateTempPath.md +27 -0
- package/docs/functions/getFileDataByHandle.md +27 -0
- package/docs/functions/getSyncMessenger.md +22 -0
- package/docs/functions/isDirectoryHandle.md +27 -0
- package/docs/functions/isFileHandle.md +27 -0
- package/docs/functions/isFileHandleLike.md +27 -0
- package/docs/functions/isOPFSSupported.md +21 -0
- package/docs/functions/isTempPath.md +27 -0
- package/docs/functions/mkTemp.md +28 -0
- package/docs/functions/mkTempSync.md +25 -0
- package/docs/functions/mkdir.md +27 -0
- package/docs/functions/mkdirSync.md +25 -0
- package/docs/functions/move.md +34 -0
- package/docs/functions/moveSync.md +30 -0
- package/docs/functions/pruneTemp.md +28 -0
- package/docs/functions/pruneTempSync.md +25 -0
- package/docs/functions/readBlobFile.md +28 -0
- package/docs/functions/readBlobFileSync.md +25 -0
- package/docs/functions/readDir.md +28 -0
- package/docs/functions/readDirSync.md +26 -0
- package/docs/functions/readFile.md +132 -0
- package/docs/functions/readFileSync.md +70 -0
- package/docs/functions/readJsonFile.md +35 -0
- package/docs/functions/readJsonFileSync.md +31 -0
- package/docs/functions/readTextFile.md +28 -0
- package/docs/functions/readTextFileSync.md +25 -0
- package/docs/functions/remove.md +27 -0
- package/docs/functions/removeSync.md +25 -0
- package/docs/functions/setSyncMessenger.md +26 -0
- package/docs/functions/startSyncAgent.md +21 -0
- package/docs/functions/stat.md +27 -0
- package/docs/functions/statSync.md +25 -0
- package/docs/functions/toFileSystemHandleLike.md +27 -0
- package/docs/functions/unzip.md +32 -0
- package/docs/functions/unzipFromUrl.md +36 -0
- package/docs/functions/unzipSync.md +26 -0
- package/docs/functions/uploadFile.md +33 -0
- package/docs/functions/writeFile.md +32 -0
- package/docs/functions/writeFileSync.md +30 -0
- package/docs/functions/zip.md +65 -0
- package/docs/functions/zipFromUrl.md +63 -0
- package/docs/functions/zipSync.md +55 -0
- package/docs/interfaces/CopyOptions.md +17 -0
- package/docs/interfaces/DownloadFileTempResponse.md +18 -0
- package/docs/interfaces/ErrorLike.md +18 -0
- package/docs/interfaces/ExistsOptions.md +18 -0
- package/docs/interfaces/FileLike.md +21 -0
- package/docs/interfaces/FileSystemFileHandleLike.md +25 -0
- package/docs/interfaces/FileSystemHandleLike.md +22 -0
- package/docs/interfaces/MoveOptions.md +17 -0
- package/docs/interfaces/ReadDirEntry.md +18 -0
- package/docs/interfaces/ReadDirEntrySync.md +18 -0
- package/docs/interfaces/ReadDirOptions.md +17 -0
- package/docs/interfaces/ReadOptions.md +17 -0
- package/docs/interfaces/SyncAgentOptions.md +19 -0
- package/docs/interfaces/TempOptions.md +19 -0
- package/docs/interfaces/UploadRequestInit.md +21 -0
- package/docs/interfaces/WriteOptions.md +19 -0
- package/docs/interfaces/ZipOptions.md +17 -0
- package/docs/type-aliases/FileEncoding.md +15 -0
- package/docs/type-aliases/FsRequestInit.md +15 -0
- package/docs/type-aliases/ReadFileContent.md +15 -0
- package/docs/type-aliases/WriteFileContent.md +15 -0
- package/docs/type-aliases/WriteSyncFileContent.md +16 -0
- package/docs/variables/CURRENT_DIR.md +15 -0
- package/docs/variables/NOT_FOUND_ERROR.md +18 -0
- package/docs/variables/ROOT_DIR.md +15 -0
- package/docs/variables/TMP_DIR.md +15 -0
- package/package.json +141 -0
- package/src/fs/assertions.ts +63 -0
- package/src/fs/constants.ts +63 -0
- package/src/fs/defines.ts +352 -0
- package/src/fs/helpers.ts +338 -0
- package/src/fs/opfs_core.ts +413 -0
- package/src/fs/opfs_download.ts +174 -0
- package/src/fs/opfs_ext.ts +504 -0
- package/src/fs/opfs_tmp.ts +131 -0
- package/src/fs/opfs_unzip.ts +168 -0
- package/src/fs/opfs_upload.ts +126 -0
- package/src/fs/opfs_zip.ts +314 -0
- package/src/fs/support.ts +36 -0
- package/src/fs/utils.ts +176 -0
- package/src/mod.ts +41 -0
- package/src/worker/helpers.ts +168 -0
- package/src/worker/opfs_worker.ts +298 -0
- package/src/worker/opfs_worker_adapter.ts +666 -0
- package/src/worker/shared.ts +400 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
|
|
3
|
+
/** ----------------------------------------------------------------------
|
|
4
|
+
* Copyright ©
|
|
5
|
+
* Jiang Jie
|
|
6
|
+
* 2024, 2025
|
|
7
|
+
* Pellegrino Prevete
|
|
8
|
+
* 2025
|
|
9
|
+
*
|
|
10
|
+
* All rights reserved
|
|
11
|
+
* ----------------------------------------------------------------------
|
|
12
|
+
*
|
|
13
|
+
* This program is free software: you can redistribute it and/or modify
|
|
14
|
+
* it under the terms of the GNU General Public License as published by
|
|
15
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
16
|
+
* (at your option) any later version.
|
|
17
|
+
*
|
|
18
|
+
* This program is distributed in the hope that it will be useful,
|
|
19
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21
|
+
* GNU General Public License for more details.
|
|
22
|
+
*
|
|
23
|
+
* You should have received a copy of the GNU General Public License
|
|
24
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { sleepUntil } from './helpers.ts';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Async I/O operations called from main thread to worker thread.
|
|
31
|
+
*/
|
|
32
|
+
export
|
|
33
|
+
const
|
|
34
|
+
enum WorkerAsyncOp {
|
|
35
|
+
// core
|
|
36
|
+
createFile,
|
|
37
|
+
mkdir,
|
|
38
|
+
move,
|
|
39
|
+
readDir,
|
|
40
|
+
remove,
|
|
41
|
+
stat,
|
|
42
|
+
writeFile,
|
|
43
|
+
// ext
|
|
44
|
+
appendFile,
|
|
45
|
+
copy,
|
|
46
|
+
emptyDir,
|
|
47
|
+
exists,
|
|
48
|
+
deleteTemp,
|
|
49
|
+
mkTemp,
|
|
50
|
+
pruneTemp,
|
|
51
|
+
readBlobFile,
|
|
52
|
+
unzip,
|
|
53
|
+
zip,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Main thread lock index used in Int32Array.
|
|
58
|
+
*/
|
|
59
|
+
const
|
|
60
|
+
MAIN_LOCK_INDEX =
|
|
61
|
+
0;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Worker thread lock index used in Int32Array.
|
|
65
|
+
*/
|
|
66
|
+
const
|
|
67
|
+
WORKER_LOCK_INDEX =
|
|
68
|
+
1;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Data index used in Int32Array.
|
|
72
|
+
*/
|
|
73
|
+
const
|
|
74
|
+
DATA_INDEX =
|
|
75
|
+
2;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Main thread locked value.
|
|
79
|
+
*/
|
|
80
|
+
const
|
|
81
|
+
MAIN_LOCKED =
|
|
82
|
+
1;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Main thread unlocked value.
|
|
86
|
+
* Default.
|
|
87
|
+
*/
|
|
88
|
+
const
|
|
89
|
+
MAIN_UNLOCKED =
|
|
90
|
+
0;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Worker thread locked value.
|
|
94
|
+
* Default.
|
|
95
|
+
*/
|
|
96
|
+
const
|
|
97
|
+
WORKER_LOCKED =
|
|
98
|
+
MAIN_UNLOCKED;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Worker thread unlocked value.
|
|
102
|
+
*/
|
|
103
|
+
const
|
|
104
|
+
WORKER_UNLOCKED =
|
|
105
|
+
MAIN_LOCKED;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Cache the `TextEncoder` instance.
|
|
109
|
+
*/
|
|
110
|
+
let
|
|
111
|
+
encoder:
|
|
112
|
+
TextEncoder;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Cache the `TextDecoder` instance.
|
|
116
|
+
*/
|
|
117
|
+
let
|
|
118
|
+
decoder:
|
|
119
|
+
TextDecoder;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get the cached `TextEncoder` instance.
|
|
123
|
+
* @returns Instance of `TextEncoder`.
|
|
124
|
+
*/
|
|
125
|
+
function
|
|
126
|
+
getEncoder():
|
|
127
|
+
TextEncoder {
|
|
128
|
+
encoder ??=
|
|
129
|
+
new TextEncoder();
|
|
130
|
+
return encoder;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get the cached `TextDecoder` instance.
|
|
135
|
+
* @returns Instance of `TextDecoder`.
|
|
136
|
+
*/
|
|
137
|
+
function
|
|
138
|
+
getDecoder():
|
|
139
|
+
TextDecoder {
|
|
140
|
+
decoder ??=
|
|
141
|
+
new TextDecoder();
|
|
142
|
+
return decoder;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Used to encode parameters and return values.
|
|
147
|
+
* @param data - Any data to encode.
|
|
148
|
+
* @returns Encoded binary data.
|
|
149
|
+
*/
|
|
150
|
+
export
|
|
151
|
+
function
|
|
152
|
+
encodeToBuffer<T>(
|
|
153
|
+
data:
|
|
154
|
+
T):
|
|
155
|
+
Uint8Array {
|
|
156
|
+
const
|
|
157
|
+
str =
|
|
158
|
+
JSON.stringify(data);
|
|
159
|
+
return getEncoder().encode(
|
|
160
|
+
str);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Used to decode parameters and return values.
|
|
165
|
+
* @param data - Binary data to decode.
|
|
166
|
+
* @returns Decoded data.
|
|
167
|
+
*/
|
|
168
|
+
export
|
|
169
|
+
function
|
|
170
|
+
decodeFromBuffer<T>(
|
|
171
|
+
data:
|
|
172
|
+
Uint8Array):
|
|
173
|
+
T {
|
|
174
|
+
const
|
|
175
|
+
str =
|
|
176
|
+
decodeToString(
|
|
177
|
+
data);
|
|
178
|
+
return JSON.parse(
|
|
179
|
+
str);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Commonly decode binary data to string.
|
|
184
|
+
* @param data - Binary data to decode.
|
|
185
|
+
* @returns Decoded string.
|
|
186
|
+
*/
|
|
187
|
+
export
|
|
188
|
+
function
|
|
189
|
+
decodeToString(
|
|
190
|
+
data:
|
|
191
|
+
Uint8Array):
|
|
192
|
+
string {
|
|
193
|
+
return getDecoder().decode(
|
|
194
|
+
data);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Inspired by [memfs](https://github.com/streamich/memfs/blob/master/src/fsa-to-node/worker/SyncMessenger.ts).
|
|
199
|
+
*
|
|
200
|
+
* Used both in main thread and worker thread.
|
|
201
|
+
*/
|
|
202
|
+
export
|
|
203
|
+
class SyncMessenger {
|
|
204
|
+
// View of SharedArrayBuffer, used to communicate between main thread and worker.
|
|
205
|
+
readonly i32a:
|
|
206
|
+
Int32Array;
|
|
207
|
+
// View of the same SharedArrayBuffer, used to read and write binary data.
|
|
208
|
+
readonly u8a:
|
|
209
|
+
Uint8Array;
|
|
210
|
+
// 4 int: MAIN_LOCK_INDEX WORKER_LOCK_INDEX DATA_INDEX NOT_USE
|
|
211
|
+
readonly headerLength =
|
|
212
|
+
4 * 4;
|
|
213
|
+
// maximum length of data to be sent. If data is longer than this, it will throw an error.
|
|
214
|
+
readonly maxDataLength:
|
|
215
|
+
number;
|
|
216
|
+
constructor(
|
|
217
|
+
sab:
|
|
218
|
+
SharedArrayBuffer) {
|
|
219
|
+
this.i32a =
|
|
220
|
+
new Int32Array(
|
|
221
|
+
sab);
|
|
222
|
+
this.u8a =
|
|
223
|
+
new Uint8Array(
|
|
224
|
+
sab);
|
|
225
|
+
this.maxDataLength =
|
|
226
|
+
sab.byteLength -
|
|
227
|
+
this.headerLength;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Calls a function in worker thread from main tread and returns the result.
|
|
233
|
+
* Used in main thread.
|
|
234
|
+
* @param messenger - SyncMessenger
|
|
235
|
+
* @param data - Request buffer which is encoded parameters.
|
|
236
|
+
* @returns - Response buffer which is encoded return value.
|
|
237
|
+
*/
|
|
238
|
+
export
|
|
239
|
+
function
|
|
240
|
+
callWorkerFromMain(
|
|
241
|
+
messenger:
|
|
242
|
+
SyncMessenger,
|
|
243
|
+
data:
|
|
244
|
+
Uint8Array):
|
|
245
|
+
Uint8Array {
|
|
246
|
+
const
|
|
247
|
+
{ i32a,
|
|
248
|
+
u8a,
|
|
249
|
+
headerLength,
|
|
250
|
+
maxDataLength } =
|
|
251
|
+
messenger;
|
|
252
|
+
const
|
|
253
|
+
requestLength =
|
|
254
|
+
data.byteLength;
|
|
255
|
+
// check whether request is too large
|
|
256
|
+
if ( requestLength > maxDataLength ) {
|
|
257
|
+
throw new RangeError(
|
|
258
|
+
`Request is too large: ` +
|
|
259
|
+
`${ requestLength } > ${ maxDataLength }. ` +
|
|
260
|
+
`Consider grow the size of SharedArrayBuffer.`);
|
|
261
|
+
}
|
|
262
|
+
// lock main thread
|
|
263
|
+
Atomics.store(
|
|
264
|
+
i32a,
|
|
265
|
+
MAIN_LOCK_INDEX,
|
|
266
|
+
MAIN_LOCKED);
|
|
267
|
+
// payload and length
|
|
268
|
+
i32a[
|
|
269
|
+
DATA_INDEX] =
|
|
270
|
+
requestLength;
|
|
271
|
+
u8a.set(
|
|
272
|
+
data,
|
|
273
|
+
headerLength);
|
|
274
|
+
// wakeup worker
|
|
275
|
+
// Atomics.notify(i32a, WORKER_LOCK_INDEX);
|
|
276
|
+
// this may not work
|
|
277
|
+
Atomics.store(
|
|
278
|
+
i32a,
|
|
279
|
+
WORKER_LOCK_INDEX,
|
|
280
|
+
WORKER_UNLOCKED);
|
|
281
|
+
// wait for worker to finish
|
|
282
|
+
sleepUntil(
|
|
283
|
+
() => Atomics.load(
|
|
284
|
+
i32a,
|
|
285
|
+
MAIN_LOCK_INDEX) === MAIN_UNLOCKED);
|
|
286
|
+
// worker return
|
|
287
|
+
const
|
|
288
|
+
responseLength =
|
|
289
|
+
i32a[
|
|
290
|
+
DATA_INDEX];
|
|
291
|
+
const
|
|
292
|
+
response =
|
|
293
|
+
u8a.slice(
|
|
294
|
+
headerLength,
|
|
295
|
+
headerLength + responseLength);
|
|
296
|
+
return response;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Responds to main thread from worker thread.
|
|
301
|
+
* Used in worker thread.
|
|
302
|
+
* @param messenger - SyncMessenger
|
|
303
|
+
* @param transfer - Function to transfer request data.
|
|
304
|
+
*/
|
|
305
|
+
export
|
|
306
|
+
async function
|
|
307
|
+
respondToMainFromWorker(
|
|
308
|
+
messenger:
|
|
309
|
+
SyncMessenger,
|
|
310
|
+
transfer:
|
|
311
|
+
(data:
|
|
312
|
+
Uint8Array) => Promise<Uint8Array>):
|
|
313
|
+
Promise<void> {
|
|
314
|
+
const
|
|
315
|
+
{ i32a,
|
|
316
|
+
u8a,
|
|
317
|
+
headerLength,
|
|
318
|
+
maxDataLength } =
|
|
319
|
+
messenger;
|
|
320
|
+
while (
|
|
321
|
+
true) {
|
|
322
|
+
if ( Atomics.load(
|
|
323
|
+
i32a,
|
|
324
|
+
WORKER_LOCK_INDEX) === WORKER_UNLOCKED) {
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// because of `Atomics.notify` may not work
|
|
329
|
+
// const
|
|
330
|
+
// waitRes =
|
|
331
|
+
// Atomics.wait(
|
|
332
|
+
// i32a,
|
|
333
|
+
// WORKER_LOCK_INDEX,
|
|
334
|
+
// WORKER_LOCKED);
|
|
335
|
+
// if ( waitRes !== 'ok' ) {
|
|
336
|
+
// throw new Error(
|
|
337
|
+
// `Unexpected Atomics.wait ` +
|
|
338
|
+
// `result: ${ waitRes }`);
|
|
339
|
+
// }
|
|
340
|
+
// payload and length
|
|
341
|
+
const
|
|
342
|
+
requestLength =
|
|
343
|
+
i32a[
|
|
344
|
+
DATA_INDEX];
|
|
345
|
+
// console.log(
|
|
346
|
+
// `requestLength: ${ requestLength }`);
|
|
347
|
+
const
|
|
348
|
+
data =
|
|
349
|
+
u8a.slice(
|
|
350
|
+
headerLength,
|
|
351
|
+
headerLength + requestLength);
|
|
352
|
+
// call async I/O operation
|
|
353
|
+
let
|
|
354
|
+
response =
|
|
355
|
+
await transfer(
|
|
356
|
+
data);
|
|
357
|
+
const
|
|
358
|
+
responseLength =
|
|
359
|
+
response.byteLength;
|
|
360
|
+
// check whether response is too large
|
|
361
|
+
if ( responseLength > maxDataLength ) {
|
|
362
|
+
const
|
|
363
|
+
message =
|
|
364
|
+
`Response is too large: ` +
|
|
365
|
+
`${ responseLength } > ${ maxDataLength }. ` +
|
|
366
|
+
`Consider grow the size of SharedArrayBuffer.`;
|
|
367
|
+
response =
|
|
368
|
+
encodeToBuffer(
|
|
369
|
+
[ { name:
|
|
370
|
+
'RangeError',
|
|
371
|
+
message } ]);
|
|
372
|
+
// the error is too large?
|
|
373
|
+
if ( response.byteLength > maxDataLength ) {
|
|
374
|
+
// lock worker thread before throw
|
|
375
|
+
Atomics.store(
|
|
376
|
+
i32a,
|
|
377
|
+
WORKER_LOCK_INDEX,
|
|
378
|
+
WORKER_LOCKED);
|
|
379
|
+
throw new RangeError(
|
|
380
|
+
message);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// write response data
|
|
384
|
+
i32a[
|
|
385
|
+
DATA_INDEX] =
|
|
386
|
+
response.byteLength;
|
|
387
|
+
u8a.set(
|
|
388
|
+
response,
|
|
389
|
+
headerLength);
|
|
390
|
+
// lock worker thread
|
|
391
|
+
Atomics.store(
|
|
392
|
+
i32a,
|
|
393
|
+
WORKER_LOCK_INDEX,
|
|
394
|
+
WORKER_LOCKED);
|
|
395
|
+
// wakeup main thread
|
|
396
|
+
Atomics.store(
|
|
397
|
+
i32a,
|
|
398
|
+
MAIN_LOCK_INDEX,
|
|
399
|
+
MAIN_UNLOCKED);
|
|
400
|
+
}
|