@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.
Files changed (114) hide show
  1. package/COPYING +674 -0
  2. package/README.cn.md +301 -0
  3. package/README.md +241 -0
  4. package/dist/main.cjs +1840 -0
  5. package/dist/main.cjs.map +1 -0
  6. package/dist/main.mjs +1751 -0
  7. package/dist/main.mjs.map +1 -0
  8. package/dist/types.d.ts +920 -0
  9. package/dist/types.d.ts.map +1 -0
  10. package/docs/README.md +115 -0
  11. package/docs/classes/SyncMessenger.md +42 -0
  12. package/docs/functions/appendFile.md +29 -0
  13. package/docs/functions/appendFileSync.md +26 -0
  14. package/docs/functions/assertAbsolutePath.md +29 -0
  15. package/docs/functions/assertFileUrl.md +29 -0
  16. package/docs/functions/connectSyncAgent.md +25 -0
  17. package/docs/functions/copy.md +35 -0
  18. package/docs/functions/copySync.md +30 -0
  19. package/docs/functions/createFile.md +27 -0
  20. package/docs/functions/createFileSync.md +25 -0
  21. package/docs/functions/deleteTemp.md +23 -0
  22. package/docs/functions/deleteTempSync.md +19 -0
  23. package/docs/functions/downloadFile.md +58 -0
  24. package/docs/functions/emptyDir.md +28 -0
  25. package/docs/functions/emptyDirSync.md +25 -0
  26. package/docs/functions/exists.md +29 -0
  27. package/docs/functions/existsSync.md +26 -0
  28. package/docs/functions/generateTempPath.md +27 -0
  29. package/docs/functions/getFileDataByHandle.md +27 -0
  30. package/docs/functions/getSyncMessenger.md +22 -0
  31. package/docs/functions/isDirectoryHandle.md +27 -0
  32. package/docs/functions/isFileHandle.md +27 -0
  33. package/docs/functions/isFileHandleLike.md +27 -0
  34. package/docs/functions/isOPFSSupported.md +21 -0
  35. package/docs/functions/isTempPath.md +27 -0
  36. package/docs/functions/mkTemp.md +28 -0
  37. package/docs/functions/mkTempSync.md +25 -0
  38. package/docs/functions/mkdir.md +27 -0
  39. package/docs/functions/mkdirSync.md +25 -0
  40. package/docs/functions/move.md +34 -0
  41. package/docs/functions/moveSync.md +30 -0
  42. package/docs/functions/pruneTemp.md +28 -0
  43. package/docs/functions/pruneTempSync.md +25 -0
  44. package/docs/functions/readBlobFile.md +28 -0
  45. package/docs/functions/readBlobFileSync.md +25 -0
  46. package/docs/functions/readDir.md +28 -0
  47. package/docs/functions/readDirSync.md +26 -0
  48. package/docs/functions/readFile.md +132 -0
  49. package/docs/functions/readFileSync.md +70 -0
  50. package/docs/functions/readJsonFile.md +35 -0
  51. package/docs/functions/readJsonFileSync.md +31 -0
  52. package/docs/functions/readTextFile.md +28 -0
  53. package/docs/functions/readTextFileSync.md +25 -0
  54. package/docs/functions/remove.md +27 -0
  55. package/docs/functions/removeSync.md +25 -0
  56. package/docs/functions/setSyncMessenger.md +26 -0
  57. package/docs/functions/startSyncAgent.md +21 -0
  58. package/docs/functions/stat.md +27 -0
  59. package/docs/functions/statSync.md +25 -0
  60. package/docs/functions/toFileSystemHandleLike.md +27 -0
  61. package/docs/functions/unzip.md +32 -0
  62. package/docs/functions/unzipFromUrl.md +36 -0
  63. package/docs/functions/unzipSync.md +26 -0
  64. package/docs/functions/uploadFile.md +33 -0
  65. package/docs/functions/writeFile.md +32 -0
  66. package/docs/functions/writeFileSync.md +30 -0
  67. package/docs/functions/zip.md +65 -0
  68. package/docs/functions/zipFromUrl.md +63 -0
  69. package/docs/functions/zipSync.md +55 -0
  70. package/docs/interfaces/CopyOptions.md +17 -0
  71. package/docs/interfaces/DownloadFileTempResponse.md +18 -0
  72. package/docs/interfaces/ErrorLike.md +18 -0
  73. package/docs/interfaces/ExistsOptions.md +18 -0
  74. package/docs/interfaces/FileLike.md +21 -0
  75. package/docs/interfaces/FileSystemFileHandleLike.md +25 -0
  76. package/docs/interfaces/FileSystemHandleLike.md +22 -0
  77. package/docs/interfaces/MoveOptions.md +17 -0
  78. package/docs/interfaces/ReadDirEntry.md +18 -0
  79. package/docs/interfaces/ReadDirEntrySync.md +18 -0
  80. package/docs/interfaces/ReadDirOptions.md +17 -0
  81. package/docs/interfaces/ReadOptions.md +17 -0
  82. package/docs/interfaces/SyncAgentOptions.md +19 -0
  83. package/docs/interfaces/TempOptions.md +19 -0
  84. package/docs/interfaces/UploadRequestInit.md +21 -0
  85. package/docs/interfaces/WriteOptions.md +19 -0
  86. package/docs/interfaces/ZipOptions.md +17 -0
  87. package/docs/type-aliases/FileEncoding.md +15 -0
  88. package/docs/type-aliases/FsRequestInit.md +15 -0
  89. package/docs/type-aliases/ReadFileContent.md +15 -0
  90. package/docs/type-aliases/WriteFileContent.md +15 -0
  91. package/docs/type-aliases/WriteSyncFileContent.md +16 -0
  92. package/docs/variables/CURRENT_DIR.md +15 -0
  93. package/docs/variables/NOT_FOUND_ERROR.md +18 -0
  94. package/docs/variables/ROOT_DIR.md +15 -0
  95. package/docs/variables/TMP_DIR.md +15 -0
  96. package/package.json +141 -0
  97. package/src/fs/assertions.ts +63 -0
  98. package/src/fs/constants.ts +63 -0
  99. package/src/fs/defines.ts +352 -0
  100. package/src/fs/helpers.ts +338 -0
  101. package/src/fs/opfs_core.ts +413 -0
  102. package/src/fs/opfs_download.ts +174 -0
  103. package/src/fs/opfs_ext.ts +504 -0
  104. package/src/fs/opfs_tmp.ts +131 -0
  105. package/src/fs/opfs_unzip.ts +168 -0
  106. package/src/fs/opfs_upload.ts +126 -0
  107. package/src/fs/opfs_zip.ts +314 -0
  108. package/src/fs/support.ts +36 -0
  109. package/src/fs/utils.ts +176 -0
  110. package/src/mod.ts +41 -0
  111. package/src/worker/helpers.ts +168 -0
  112. package/src/worker/opfs_worker.ts +298 -0
  113. package/src/worker/opfs_worker_adapter.ts +666 -0
  114. 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
+ }