@zenfs/core 0.16.3 → 0.17.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.
Files changed (74) hide show
  1. package/dist/backends/backend.d.ts +3 -4
  2. package/dist/backends/fetch.d.ts +8 -3
  3. package/dist/backends/fetch.js +3 -2
  4. package/dist/backends/{index/fs.d.ts → file_index.d.ts} +49 -10
  5. package/dist/backends/{index/fs.js → file_index.js} +84 -5
  6. package/dist/backends/memory.d.ts +6 -1
  7. package/dist/backends/memory.js +2 -1
  8. package/dist/backends/overlay.d.ts +16 -16
  9. package/dist/backends/overlay.js +59 -82
  10. package/dist/backends/port/fs.d.ts +6 -2
  11. package/dist/backends/port/fs.js +4 -2
  12. package/dist/backends/store/fs.js +484 -304
  13. package/dist/backends/store/simple.js +5 -1
  14. package/dist/backends/store/store.d.ts +4 -1
  15. package/dist/backends/store/store.js +9 -5
  16. package/dist/browser.min.js +4 -4
  17. package/dist/browser.min.js.map +4 -4
  18. package/dist/config.d.ts +3 -3
  19. package/dist/emulation/async.d.ts +0 -3
  20. package/dist/emulation/async.js +6 -2
  21. package/dist/emulation/dir.d.ts +4 -0
  22. package/dist/emulation/dir.js +8 -6
  23. package/dist/emulation/promises.d.ts +1 -3
  24. package/dist/emulation/promises.js +26 -3
  25. package/dist/emulation/sync.js +1 -2
  26. package/dist/emulation/watchers.d.ts +9 -4
  27. package/dist/emulation/watchers.js +7 -0
  28. package/dist/file.d.ts +17 -1
  29. package/dist/file.js +86 -1
  30. package/dist/filesystem.d.ts +0 -63
  31. package/dist/filesystem.js +0 -311
  32. package/dist/index.d.ts +1 -2
  33. package/dist/index.js +1 -2
  34. package/dist/mixins/async.d.ts +39 -0
  35. package/dist/mixins/async.js +216 -0
  36. package/dist/mixins/mutexed.d.ts +33 -0
  37. package/dist/mixins/mutexed.js +465 -0
  38. package/dist/mixins/readonly.d.ts +25 -0
  39. package/dist/mixins/readonly.js +57 -0
  40. package/dist/mixins/shared.d.ts +12 -0
  41. package/dist/mixins/shared.js +4 -0
  42. package/dist/mixins/sync.d.ts +6 -0
  43. package/dist/mixins/sync.js +43 -0
  44. package/package.json +1 -1
  45. package/src/backends/backend.ts +3 -4
  46. package/src/backends/fetch.ts +7 -3
  47. package/src/backends/{index/fs.ts → file_index.ts} +106 -8
  48. package/src/backends/memory.ts +5 -1
  49. package/src/backends/overlay.ts +64 -90
  50. package/src/backends/port/fs.ts +7 -2
  51. package/src/backends/{index/readme.md → readme.md} +1 -1
  52. package/src/backends/store/fs.ts +97 -155
  53. package/src/backends/store/simple.ts +5 -1
  54. package/src/backends/store/store.ts +10 -5
  55. package/src/config.ts +3 -1
  56. package/src/emulation/async.ts +15 -6
  57. package/src/emulation/dir.ts +19 -16
  58. package/src/emulation/promises.ts +30 -8
  59. package/src/emulation/sync.ts +2 -3
  60. package/src/emulation/watchers.ts +10 -4
  61. package/src/file.ts +94 -1
  62. package/src/filesystem.ts +3 -366
  63. package/src/index.ts +1 -2
  64. package/src/mixins/async.ts +211 -0
  65. package/src/mixins/mutexed.ts +245 -0
  66. package/src/mixins/readonly.ts +97 -0
  67. package/src/mixins/shared.ts +20 -0
  68. package/src/mixins/sync.ts +59 -0
  69. package/dist/backends/index/index.d.ts +0 -43
  70. package/dist/backends/index/index.js +0 -83
  71. package/dist/backends/locked.d.ts +0 -92
  72. package/dist/backends/locked.js +0 -487
  73. package/src/backends/index/index.ts +0 -104
  74. package/src/backends/locked.ts +0 -264
package/src/filesystem.ts CHANGED
@@ -1,9 +1,6 @@
1
- /* eslint-disable @typescript-eslint/require-await */
2
- import type { ExtractProperties } from 'utilium';
3
- import { rootCred, type Cred } from './cred.js';
4
- import { join } from './emulation/path.js';
5
- import { Errno, ErrnoError } from './error.js';
6
- import { PreloadFile, parseFlag, type File } from './file.js';
1
+ import { type Cred } from './cred.js';
2
+ import type { ErrnoError } from './error.js';
3
+ import { type File } from './file.js';
7
4
  import { ZenFsType, type Stats } from './stats.js';
8
5
 
9
6
  export type FileContents = ArrayBufferView | string;
@@ -227,363 +224,3 @@ export abstract class FileSystem {
227
224
  */
228
225
  public abstract syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
229
226
  }
230
-
231
- /**
232
- * `TBase` with `TMixin` mixed-in.
233
- * @internal @experimental
234
- */
235
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
236
- export type Mixin<TBase extends typeof FileSystem, TMixin> = (abstract new (...args: any[]) => TMixin) & TBase;
237
-
238
- /**
239
- * Asynchronous `FileSystem` methods. This is a convience type.
240
- * @internal
241
- */
242
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
243
- export type _AsyncFSMethods = ExtractProperties<FileSystem, (...args: any[]) => Promise<unknown>>;
244
-
245
- /**
246
- * Implements the asynchronous API in terms of the synchronous API.
247
- */
248
- export function Sync<T extends typeof FileSystem>(FS: T): Mixin<T, _AsyncFSMethods> {
249
- abstract class SyncFS extends FS implements _AsyncFSMethods {
250
- public async exists(path: string, cred: Cred): Promise<boolean> {
251
- return this.existsSync(path, cred);
252
- }
253
-
254
- public async rename(oldPath: string, newPath: string, cred: Cred): Promise<void> {
255
- return this.renameSync(oldPath, newPath, cred);
256
- }
257
-
258
- public async stat(path: string, cred: Cred): Promise<Stats> {
259
- return this.statSync(path, cred);
260
- }
261
-
262
- public async createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File> {
263
- return this.createFileSync(path, flag, mode, cred);
264
- }
265
-
266
- public async openFile(path: string, flag: string, cred: Cred): Promise<File> {
267
- return this.openFileSync(path, flag, cred);
268
- }
269
-
270
- public async unlink(path: string, cred: Cred): Promise<void> {
271
- return this.unlinkSync(path, cred);
272
- }
273
-
274
- public async rmdir(path: string, cred: Cred): Promise<void> {
275
- return this.rmdirSync(path, cred);
276
- }
277
-
278
- public async mkdir(path: string, mode: number, cred: Cred): Promise<void> {
279
- return this.mkdirSync(path, mode, cred);
280
- }
281
-
282
- public async readdir(path: string, cred: Cred): Promise<string[]> {
283
- return this.readdirSync(path, cred);
284
- }
285
-
286
- public async link(srcpath: string, dstpath: string, cred: Cred): Promise<void> {
287
- return this.linkSync(srcpath, dstpath, cred);
288
- }
289
-
290
- public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
291
- return this.syncSync(path, data, stats);
292
- }
293
- }
294
- return SyncFS;
295
- }
296
-
297
- /**
298
- * @internal
299
- */
300
- type AsyncOperation = {
301
- [K in keyof _AsyncFSMethods]: [K, ...Parameters<FileSystem[K]>];
302
- }[keyof _AsyncFSMethods];
303
-
304
- /**
305
- * Async() implements synchronous methods on an asynchronous file system
306
- *
307
- * Implementing classes must define `_sync` for the synchronous file system used as a cache.
308
- * Synchronous methods on an asynchronous FS are implemented by:
309
- * - Performing operations over the in-memory copy,
310
- * while asynchronously pipelining them to the backing store.
311
- * - During loading, the contents of the async file system are preloaded into the synchronous store.
312
- *
313
- */
314
- export function Async<T extends typeof FileSystem>(
315
- FS: T
316
- ): Mixin<
317
- T,
318
- {
319
- /**
320
- * @internal @protected
321
- */
322
- _sync?: FileSystem;
323
- queueDone(): Promise<void>;
324
- ready(): Promise<void>;
325
- renameSync(oldPath: string, newPath: string, cred: Cred): void;
326
- statSync(path: string, cred: Cred): Stats;
327
- createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
328
- openFileSync(path: string, flag: string, cred: Cred): File;
329
- unlinkSync(path: string, cred: Cred): void;
330
- rmdirSync(path: string, cred: Cred): void;
331
- mkdirSync(path: string, mode: number, cred: Cred): void;
332
- readdirSync(path: string, cred: Cred): string[];
333
- linkSync(srcpath: string, dstpath: string, cred: Cred): void;
334
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
335
- }
336
- > {
337
- abstract class AsyncFS extends FS {
338
- /**
339
- * Queue of pending asynchronous operations.
340
- */
341
- private _queue: AsyncOperation[] = [];
342
- private get _queueRunning(): boolean {
343
- return !!this._queue.length;
344
- }
345
-
346
- public queueDone(): Promise<void> {
347
- return new Promise(resolve => {
348
- const check = (): unknown => (this._queueRunning ? setTimeout(check) : resolve());
349
- check();
350
- });
351
- }
352
-
353
- private _isInitialized: boolean = false;
354
-
355
- abstract _sync?: FileSystem;
356
-
357
- public async ready(): Promise<void> {
358
- await super.ready();
359
- if (this._isInitialized || this._disableSync) {
360
- return;
361
- }
362
- this.checkSync();
363
-
364
- await this._sync.ready();
365
-
366
- try {
367
- await this.crossCopy('/');
368
- this._isInitialized = true;
369
- } catch (e) {
370
- this._isInitialized = false;
371
- throw e;
372
- }
373
- }
374
-
375
- protected checkSync(path?: string, syscall?: string): asserts this is { _sync: FileSystem } {
376
- if (this._disableSync) {
377
- throw new ErrnoError(Errno.ENOTSUP, 'Sync caching has been disabled for this async file system', path, syscall);
378
- }
379
- if (!this._sync) {
380
- throw new ErrnoError(Errno.ENOTSUP, 'No sync cache is attached to this async file system', path, syscall);
381
- }
382
- }
383
-
384
- public renameSync(oldPath: string, newPath: string, cred: Cred): void {
385
- this.checkSync(oldPath, 'rename');
386
- this._sync.renameSync(oldPath, newPath, cred);
387
- this.queue('rename', oldPath, newPath, cred);
388
- }
389
-
390
- public statSync(path: string, cred: Cred): Stats {
391
- this.checkSync(path, 'stat');
392
- return this._sync.statSync(path, cred);
393
- }
394
-
395
- public createFileSync(path: string, flag: string, mode: number, cred: Cred): PreloadFile<this> {
396
- this.checkSync(path, 'createFile');
397
- this._sync.createFileSync(path, flag, mode, cred);
398
- this.queue('createFile', path, flag, mode, cred);
399
- return this.openFileSync(path, flag, cred);
400
- }
401
-
402
- public openFileSync(path: string, flag: string, cred: Cred): PreloadFile<this> {
403
- this.checkSync(path, 'openFile');
404
- const file = this._sync.openFileSync(path, flag, cred);
405
- const stats = file.statSync();
406
- const buffer = new Uint8Array(stats.size);
407
- file.readSync(buffer);
408
- return new PreloadFile(this, path, flag, stats, buffer);
409
- }
410
-
411
- public unlinkSync(path: string, cred: Cred): void {
412
- this.checkSync(path, 'unlinkSync');
413
- this._sync.unlinkSync(path, cred);
414
- this.queue('unlink', path, cred);
415
- }
416
-
417
- public rmdirSync(path: string, cred: Cred): void {
418
- this.checkSync(path, 'rmdir');
419
- this._sync.rmdirSync(path, cred);
420
- this.queue('rmdir', path, cred);
421
- }
422
-
423
- public mkdirSync(path: string, mode: number, cred: Cred): void {
424
- this.checkSync(path, 'mkdir');
425
- this._sync.mkdirSync(path, mode, cred);
426
- this.queue('mkdir', path, mode, cred);
427
- }
428
-
429
- public readdirSync(path: string, cred: Cred): string[] {
430
- this.checkSync(path, 'readdir');
431
- return this._sync.readdirSync(path, cred);
432
- }
433
-
434
- public linkSync(srcpath: string, dstpath: string, cred: Cred): void {
435
- this.checkSync(srcpath, 'link');
436
- this._sync.linkSync(srcpath, dstpath, cred);
437
- this.queue('link', srcpath, dstpath, cred);
438
- }
439
-
440
- public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
441
- this.checkSync(path, 'sync');
442
- this._sync.syncSync(path, data, stats);
443
- this.queue('sync', path, data, stats);
444
- }
445
-
446
- public existsSync(path: string, cred: Cred): boolean {
447
- this.checkSync(path, 'exists');
448
- return this._sync.existsSync(path, cred);
449
- }
450
-
451
- /**
452
- * @internal
453
- */
454
- protected async crossCopy(path: string): Promise<void> {
455
- this.checkSync(path, 'crossCopy');
456
- const stats = await this.stat(path, rootCred);
457
- if (stats.isDirectory()) {
458
- if (path !== '/') {
459
- const stats = await this.stat(path, rootCred);
460
- this._sync.mkdirSync(path, stats.mode, stats.cred());
461
- }
462
- const files = await this.readdir(path, rootCred);
463
- for (const file of files) {
464
- await this.crossCopy(join(path, file));
465
- }
466
- } else {
467
- await using asyncFile = await this.openFile(path, parseFlag('r'), rootCred);
468
- using syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred());
469
- const buffer = new Uint8Array(stats.size);
470
- await asyncFile.read(buffer);
471
- syncFile.writeSync(buffer, 0, stats.size);
472
- }
473
- }
474
-
475
- /**
476
- * @internal
477
- */
478
- private async _next(): Promise<void> {
479
- if (!this._queueRunning) {
480
- return;
481
- }
482
-
483
- const [method, ...args] = this._queue.shift()!;
484
- // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
485
- await this[method](...args);
486
- await this._next();
487
- }
488
-
489
- /**
490
- * @internal
491
- */
492
- private queue(...op: AsyncOperation) {
493
- this._queue.push(op);
494
- void this._next();
495
- }
496
- }
497
-
498
- return AsyncFS;
499
- }
500
-
501
- /**
502
- * Implements the non-readonly methods to throw `EROFS`
503
- */
504
- export function Readonly<T extends typeof FileSystem>(
505
- FS: T
506
- ): Mixin<
507
- T,
508
- {
509
- metadata(): FileSystemMetadata;
510
- rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
511
- renameSync(oldPath: string, newPath: string, cred: Cred): void;
512
- createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
513
- createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
514
- unlink(path: string, cred: Cred): Promise<void>;
515
- unlinkSync(path: string, cred: Cred): void;
516
- rmdir(path: string, cred: Cred): Promise<void>;
517
- rmdirSync(path: string, cred: Cred): void;
518
- mkdir(path: string, mode: number, cred: Cred): Promise<void>;
519
- mkdirSync(path: string, mode: number, cred: Cred): void;
520
- link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
521
- linkSync(srcpath: string, dstpath: string, cred: Cred): void;
522
- sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
523
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
524
- }
525
- > {
526
- abstract class ReadonlyFS extends FS {
527
- public metadata(): FileSystemMetadata {
528
- return { ...super.metadata(), readonly: true };
529
- }
530
- /* eslint-disable @typescript-eslint/no-unused-vars */
531
- public async rename(oldPath: string, newPath: string, cred: Cred): Promise<void> {
532
- throw new ErrnoError(Errno.EROFS);
533
- }
534
-
535
- public renameSync(oldPath: string, newPath: string, cred: Cred): void {
536
- throw new ErrnoError(Errno.EROFS);
537
- }
538
-
539
- public async createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File> {
540
- throw new ErrnoError(Errno.EROFS);
541
- }
542
-
543
- public createFileSync(path: string, flag: string, mode: number, cred: Cred): File {
544
- throw new ErrnoError(Errno.EROFS);
545
- }
546
-
547
- public async unlink(path: string, cred: Cred): Promise<void> {
548
- throw new ErrnoError(Errno.EROFS);
549
- }
550
-
551
- public unlinkSync(path: string, cred: Cred): void {
552
- throw new ErrnoError(Errno.EROFS);
553
- }
554
-
555
- public async rmdir(path: string, cred: Cred): Promise<void> {
556
- throw new ErrnoError(Errno.EROFS);
557
- }
558
-
559
- public rmdirSync(path: string, cred: Cred): void {
560
- throw new ErrnoError(Errno.EROFS);
561
- }
562
-
563
- public async mkdir(path: string, mode: number, cred: Cred): Promise<void> {
564
- throw new ErrnoError(Errno.EROFS);
565
- }
566
-
567
- public mkdirSync(path: string, mode: number, cred: Cred): void {
568
- throw new ErrnoError(Errno.EROFS);
569
- }
570
-
571
- public async link(srcpath: string, dstpath: string, cred: Cred): Promise<void> {
572
- throw new ErrnoError(Errno.EROFS);
573
- }
574
-
575
- public linkSync(srcpath: string, dstpath: string, cred: Cred): void {
576
- throw new ErrnoError(Errno.EROFS);
577
- }
578
-
579
- public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
580
- throw new ErrnoError(Errno.EROFS);
581
- }
582
-
583
- public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
584
- throw new ErrnoError(Errno.EROFS);
585
- }
586
- /* eslint-enable @typescript-eslint/no-unused-vars */
587
- }
588
- return ReadonlyFS;
589
- }
package/src/index.ts CHANGED
@@ -2,8 +2,7 @@ export * from './error.js';
2
2
  export * from './backends/port/fs.js';
3
3
  export * from './backends/fetch.js';
4
4
  export * from './backends/memory.js';
5
- export * from './backends/index/fs.js';
6
- export * from './backends/locked.js';
5
+ export * from './backends/file_index.js';
7
6
  export * from './backends/overlay.js';
8
7
  export * from './backends/store/fs.js';
9
8
  export * from './backends/store/simple.js';
@@ -0,0 +1,211 @@
1
+ import { rootCred, type Cred } from '../cred.js';
2
+ import { join } from '../emulation/path.js';
3
+ import { Errno, ErrnoError } from '../error.js';
4
+ import { PreloadFile, parseFlag, type File } from '../file.js';
5
+ import type { FileSystem } from '../filesystem.js';
6
+ import type { Stats } from '../stats.js';
7
+ import type { _AsyncFSMethods, Mixin } from './shared.js';
8
+
9
+ /**
10
+ * @internal
11
+ */
12
+ export type AsyncOperation = {
13
+ [K in keyof _AsyncFSMethods]: [K, ...Parameters<FileSystem[K]>];
14
+ }[keyof _AsyncFSMethods];
15
+
16
+ /**
17
+ * Async() implements synchronous methods on an asynchronous file system
18
+ *
19
+ * Implementing classes must define `_sync` for the synchronous file system used as a cache.
20
+ * Synchronous methods on an asynchronous FS are implemented by:
21
+ * - Performing operations over the in-memory copy,
22
+ * while asynchronously pipelining them to the backing store.
23
+ * - During loading, the contents of the async file system are preloaded into the synchronous store.
24
+ *
25
+ */
26
+ export function Async<T extends typeof FileSystem>(
27
+ FS: T
28
+ ): Mixin<
29
+ T,
30
+ {
31
+ /**
32
+ * @internal @protected
33
+ */
34
+ _sync?: FileSystem;
35
+ queueDone(): Promise<void>;
36
+ ready(): Promise<void>;
37
+ renameSync(oldPath: string, newPath: string, cred: Cred): void;
38
+ statSync(path: string, cred: Cred): Stats;
39
+ createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
40
+ openFileSync(path: string, flag: string, cred: Cred): File;
41
+ unlinkSync(path: string, cred: Cred): void;
42
+ rmdirSync(path: string, cred: Cred): void;
43
+ mkdirSync(path: string, mode: number, cred: Cred): void;
44
+ readdirSync(path: string, cred: Cred): string[];
45
+ linkSync(srcpath: string, dstpath: string, cred: Cred): void;
46
+ syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
47
+ }
48
+ > {
49
+ abstract class AsyncFS extends FS {
50
+ /**
51
+ * Queue of pending asynchronous operations.
52
+ */
53
+ private _queue: AsyncOperation[] = [];
54
+ private get _queueRunning(): boolean {
55
+ return !!this._queue.length;
56
+ }
57
+
58
+ public queueDone(): Promise<void> {
59
+ return new Promise(resolve => {
60
+ const check = (): unknown => (this._queueRunning ? setTimeout(check) : resolve());
61
+ check();
62
+ });
63
+ }
64
+
65
+ private _isInitialized: boolean = false;
66
+
67
+ abstract _sync?: FileSystem;
68
+
69
+ public async ready(): Promise<void> {
70
+ await super.ready();
71
+ if (this._isInitialized || this._disableSync) {
72
+ return;
73
+ }
74
+ this.checkSync();
75
+
76
+ await this._sync.ready();
77
+
78
+ try {
79
+ await this.crossCopy('/');
80
+ this._isInitialized = true;
81
+ } catch (e) {
82
+ this._isInitialized = false;
83
+ throw e;
84
+ }
85
+ }
86
+
87
+ protected checkSync(path?: string, syscall?: string): asserts this is { _sync: FileSystem } {
88
+ if (this._disableSync) {
89
+ throw new ErrnoError(Errno.ENOTSUP, 'Sync caching has been disabled for this async file system', path, syscall);
90
+ }
91
+ if (!this._sync) {
92
+ throw new ErrnoError(Errno.ENOTSUP, 'No sync cache is attached to this async file system', path, syscall);
93
+ }
94
+ }
95
+
96
+ public renameSync(oldPath: string, newPath: string, cred: Cred): void {
97
+ this.checkSync(oldPath, 'rename');
98
+ this._sync.renameSync(oldPath, newPath, cred);
99
+ this.queue('rename', oldPath, newPath, cred);
100
+ }
101
+
102
+ public statSync(path: string, cred: Cred): Stats {
103
+ this.checkSync(path, 'stat');
104
+ return this._sync.statSync(path, cred);
105
+ }
106
+
107
+ public createFileSync(path: string, flag: string, mode: number, cred: Cred): PreloadFile<this> {
108
+ this.checkSync(path, 'createFile');
109
+ this._sync.createFileSync(path, flag, mode, cred);
110
+ this.queue('createFile', path, flag, mode, cred);
111
+ return this.openFileSync(path, flag, cred);
112
+ }
113
+
114
+ public openFileSync(path: string, flag: string, cred: Cred): PreloadFile<this> {
115
+ this.checkSync(path, 'openFile');
116
+ const file = this._sync.openFileSync(path, flag, cred);
117
+ const stats = file.statSync();
118
+ const buffer = new Uint8Array(stats.size);
119
+ file.readSync(buffer);
120
+ return new PreloadFile(this, path, flag, stats, buffer);
121
+ }
122
+
123
+ public unlinkSync(path: string, cred: Cred): void {
124
+ this.checkSync(path, 'unlinkSync');
125
+ this._sync.unlinkSync(path, cred);
126
+ this.queue('unlink', path, cred);
127
+ }
128
+
129
+ public rmdirSync(path: string, cred: Cred): void {
130
+ this.checkSync(path, 'rmdir');
131
+ this._sync.rmdirSync(path, cred);
132
+ this.queue('rmdir', path, cred);
133
+ }
134
+
135
+ public mkdirSync(path: string, mode: number, cred: Cred): void {
136
+ this.checkSync(path, 'mkdir');
137
+ this._sync.mkdirSync(path, mode, cred);
138
+ this.queue('mkdir', path, mode, cred);
139
+ }
140
+
141
+ public readdirSync(path: string, cred: Cred): string[] {
142
+ this.checkSync(path, 'readdir');
143
+ return this._sync.readdirSync(path, cred);
144
+ }
145
+
146
+ public linkSync(srcpath: string, dstpath: string, cred: Cred): void {
147
+ this.checkSync(srcpath, 'link');
148
+ this._sync.linkSync(srcpath, dstpath, cred);
149
+ this.queue('link', srcpath, dstpath, cred);
150
+ }
151
+
152
+ public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
153
+ this.checkSync(path, 'sync');
154
+ this._sync.syncSync(path, data, stats);
155
+ this.queue('sync', path, data, stats);
156
+ }
157
+
158
+ public existsSync(path: string, cred: Cred): boolean {
159
+ this.checkSync(path, 'exists');
160
+ return this._sync.existsSync(path, cred);
161
+ }
162
+
163
+ /**
164
+ * @internal
165
+ */
166
+ protected async crossCopy(path: string): Promise<void> {
167
+ this.checkSync(path, 'crossCopy');
168
+ const stats = await this.stat(path, rootCred);
169
+ if (stats.isDirectory()) {
170
+ if (path !== '/') {
171
+ const stats = await this.stat(path, rootCred);
172
+ this._sync.mkdirSync(path, stats.mode, stats.cred());
173
+ }
174
+ const files = await this.readdir(path, rootCred);
175
+ for (const file of files) {
176
+ await this.crossCopy(join(path, file));
177
+ }
178
+ } else {
179
+ await using asyncFile = await this.openFile(path, parseFlag('r'), rootCred);
180
+ using syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode, stats.cred());
181
+ const buffer = new Uint8Array(stats.size);
182
+ await asyncFile.read(buffer);
183
+ syncFile.writeSync(buffer, 0, stats.size);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * @internal
189
+ */
190
+ private async _next(): Promise<void> {
191
+ if (!this._queueRunning) {
192
+ return;
193
+ }
194
+
195
+ const [method, ...args] = this._queue.shift()!;
196
+ // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
197
+ await this[method](...args);
198
+ await this._next();
199
+ }
200
+
201
+ /**
202
+ * @internal
203
+ */
204
+ private queue(...op: AsyncOperation) {
205
+ this._queue.push(op);
206
+ void this._next();
207
+ }
208
+ }
209
+
210
+ return AsyncFS;
211
+ }