@zenfs/core 0.5.12 → 0.7.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.
@@ -1,4 +1,7 @@
1
1
  import { ApiError, ErrorCode } from './ApiError.js';
2
+ import { PreloadFile, parseFlag } from './file.js';
3
+ import { rootCred } from './cred.js';
4
+ import { join } from './emulation/path.js';
2
5
  /**
3
6
  * Structure for a filesystem. All ZenFS FileSystems must implement this.
4
7
  *
@@ -10,11 +13,13 @@ import { ApiError, ErrorCode } from './ApiError.js';
10
13
  * - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values.
11
14
  */
12
15
  export class FileSystem {
16
+ /**
17
+ * Get metadata about the current file syste,
18
+ */
13
19
  metadata() {
14
20
  return {
15
21
  name: this.constructor.name,
16
22
  readonly: false,
17
- synchronous: false,
18
23
  supportsProperties: false,
19
24
  totalSpace: 0,
20
25
  freeSpace: 0,
@@ -57,9 +62,6 @@ export function Sync(FS) {
57
62
  * Implements the asynchronous API in terms of the synchronous API.
58
63
  */
59
64
  class _SyncFileSystem extends FS {
60
- metadata() {
61
- return { ...super.metadata(), synchronous: true };
62
- }
63
65
  async ready() {
64
66
  return this;
65
67
  }
@@ -99,44 +101,148 @@ export function Sync(FS) {
99
101
  }
100
102
  return _SyncFileSystem;
101
103
  }
104
+ /**
105
+ * Async() implements synchronous methods on an asynchronous file system
106
+ *
107
+ * Implementing classes must define a protected _sync property for the synchronous file system used as a cache.
108
+ * by:
109
+ *
110
+ * - Performing operations over the in-memory copy, while asynchronously pipelining them
111
+ * to the backing store.
112
+ * - During application loading, the contents of the async file system can be reloaded into
113
+ * the synchronous store, if desired.
114
+ *
115
+ */
102
116
  export function Async(FS) {
103
117
  class _AsyncFileSystem extends FS {
104
- metadata() {
105
- return { ...super.metadata(), synchronous: false };
118
+ constructor() {
119
+ super(...arguments);
120
+ /**
121
+ * Queue of pending asynchronous operations.
122
+ */
123
+ this._queue = [];
124
+ this._queueRunning = false;
125
+ this._isInitialized = false;
126
+ }
127
+ async ready() {
128
+ await this._initialize();
129
+ return this;
106
130
  }
107
- /* eslint-disable @typescript-eslint/no-unused-vars */
108
131
  renameSync(oldPath, newPath, cred) {
109
- throw new ApiError(ErrorCode.ENOTSUP);
132
+ this._sync.renameSync(oldPath, newPath, cred);
133
+ this.queue('rename', oldPath, newPath, cred);
110
134
  }
111
- statSync(path, cred) {
112
- throw new ApiError(ErrorCode.ENOTSUP);
135
+ statSync(p, cred) {
136
+ return this._sync.statSync(p, cred);
113
137
  }
114
138
  createFileSync(path, flag, mode, cred) {
115
- throw new ApiError(ErrorCode.ENOTSUP);
139
+ const file = this._sync.createFileSync(path, flag, mode, cred);
140
+ this.queue('createFile', path, flag, mode, cred);
141
+ const stats = file.statSync();
142
+ const buffer = new Uint8Array(stats.size);
143
+ file.readSync(buffer);
144
+ return new PreloadFile(this, path, flag, stats, buffer);
116
145
  }
117
146
  openFileSync(path, flag, cred) {
118
- throw new ApiError(ErrorCode.ENOTSUP);
147
+ return this._sync.openFileSync(path, flag, cred);
119
148
  }
120
- unlinkSync(path, cred) {
121
- throw new ApiError(ErrorCode.ENOTSUP);
149
+ unlinkSync(p, cred) {
150
+ this._sync.unlinkSync(p, cred);
151
+ this.queue('unlink', p, cred);
122
152
  }
123
- rmdirSync(path, cred) {
124
- throw new ApiError(ErrorCode.ENOTSUP);
153
+ rmdirSync(p, cred) {
154
+ this._sync.rmdirSync(p, cred);
155
+ this.queue('rmdir', p, cred);
125
156
  }
126
- mkdirSync(path, mode, cred) {
127
- throw new ApiError(ErrorCode.ENOTSUP);
157
+ mkdirSync(p, mode, cred) {
158
+ this._sync.mkdirSync(p, mode, cred);
159
+ this.queue('mkdir', p, mode, cred);
128
160
  }
129
- readdirSync(path, cred) {
130
- throw new ApiError(ErrorCode.ENOTSUP);
161
+ readdirSync(p, cred) {
162
+ return this._sync.readdirSync(p, cred);
131
163
  }
132
164
  linkSync(srcpath, dstpath, cred) {
133
- throw new ApiError(ErrorCode.ENOTSUP);
165
+ this._sync.linkSync(srcpath, dstpath, cred);
166
+ this.queue('link', srcpath, dstpath, cred);
134
167
  }
135
168
  syncSync(path, data, stats) {
136
- throw new ApiError(ErrorCode.ENOTSUP);
169
+ this._sync.syncSync(path, data, stats);
170
+ this.queue('sync', path, data, stats);
171
+ }
172
+ existsSync(p, cred) {
173
+ return this._sync.existsSync(p, cred);
174
+ }
175
+ /**
176
+ * @internal
177
+ */
178
+ async crossCopy(p) {
179
+ const stats = await this.stat(p, rootCred);
180
+ if (stats.isDirectory()) {
181
+ if (p !== '/') {
182
+ const stats = await this.stat(p, rootCred);
183
+ this._sync.mkdirSync(p, stats.mode, stats.cred());
184
+ }
185
+ const files = await this.readdir(p, rootCred);
186
+ for (const file of files) {
187
+ await this.crossCopy(join(p, file));
188
+ }
189
+ }
190
+ else {
191
+ const asyncFile = await this.openFile(p, parseFlag('r'), rootCred);
192
+ const syncFile = this._sync.createFileSync(p, parseFlag('w'), stats.mode, rootCred);
193
+ try {
194
+ const { size } = await asyncFile.stat();
195
+ const buffer = new Uint8Array(size);
196
+ await asyncFile.read(buffer);
197
+ syncFile.writeSync(buffer);
198
+ }
199
+ finally {
200
+ await asyncFile.close();
201
+ syncFile.closeSync();
202
+ }
203
+ }
204
+ }
205
+ /**
206
+ * Called once to load up files from async storage into sync storage.
207
+ */
208
+ async _initialize() {
209
+ if (this._isInitialized) {
210
+ return;
211
+ }
212
+ try {
213
+ await this.crossCopy('/');
214
+ this._isInitialized = true;
215
+ }
216
+ catch (e) {
217
+ this._isInitialized = false;
218
+ throw e;
219
+ }
220
+ }
221
+ /**
222
+ * @internal
223
+ */
224
+ async _next() {
225
+ if (this._queue.length == 0) {
226
+ this._queueRunning = false;
227
+ return;
228
+ }
229
+ const [method, ...args] = this._queue.shift();
230
+ // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
231
+ await this[method](...args);
232
+ await this._next();
233
+ }
234
+ /**
235
+ * @internal
236
+ */
237
+ queue(...op) {
238
+ this._queue.push(op);
239
+ if (this._queueRunning) {
240
+ return;
241
+ }
242
+ this._queueRunning = true;
243
+ this._next();
137
244
  }
138
245
  }
139
- /* eslint-enable @typescript-eslint/no-unused-vars */
140
246
  return _AsyncFileSystem;
141
247
  }
142
248
  export function Readonly(FS) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './backends/backend.js';
2
- export * from './backends/AsyncMirror.js';
3
2
  export * from './backends/AsyncStore.js';
4
3
  export * from './backends/InMemory.js';
5
4
  export * from './backends/Locked.js';
@@ -15,6 +14,7 @@ export * from './inode.js';
15
14
  export * from './mutex.js';
16
15
  export * from './stats.js';
17
16
  export * from './utils.js';
17
+ export * from './emulation/index.js';
18
18
  import * as fs from './emulation/index.js';
19
19
  export { fs };
20
20
  export default fs;
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './backends/backend.js';
2
- export * from './backends/AsyncMirror.js';
3
2
  export * from './backends/AsyncStore.js';
4
3
  export * from './backends/InMemory.js';
5
4
  export * from './backends/Locked.js';
@@ -15,6 +14,7 @@ export * from './inode.js';
15
14
  export * from './mutex.js';
16
15
  export * from './stats.js';
17
16
  export * from './utils.js';
17
+ export * from './emulation/index.js';
18
18
  import * as fs from './emulation/index.js';
19
19
  export { fs };
20
20
  export default fs;
package/dist/utils.d.ts CHANGED
@@ -14,7 +14,10 @@ export declare function mkdirpSync(p: string, mode: number, cred: Cred, fs: File
14
14
  * @hidden
15
15
  */
16
16
  export declare function levenshtein(a: string, b: string): number;
17
- /** Waits n ms. */
17
+ /**
18
+ * Waits n ms.
19
+ * @hidden
20
+ */
18
21
  export declare function wait(ms: number): Promise<void>;
19
22
  /**
20
23
  * @hidden
@@ -32,11 +35,28 @@ export declare function encode(input: string): Uint8Array;
32
35
  export declare function decode(input?: Uint8Array): string;
33
36
  /**
34
37
  * Decodes a directory listing
35
- * @internal
38
+ * @hidden
36
39
  */
37
40
  export declare function decodeDirListing(data: Uint8Array): Record<string, bigint>;
38
41
  /**
39
42
  * Encodes a directory listing
40
- * @internal
43
+ * @hidden
41
44
  */
42
45
  export declare function encodeDirListing(data: Record<string, bigint>): Uint8Array;
46
+ /**
47
+ * Extracts an object of properties assignable to P from an object T
48
+ * @hidden
49
+ */
50
+ export type ExtractProperties<T, P> = {
51
+ [K in keyof T as T[K] extends infer Prop ? (Prop extends P ? K : never) : never]: T[K];
52
+ };
53
+ /**
54
+ * Extract a the keys in T which are required properties
55
+ * @hidden
56
+ * @see https://stackoverflow.com/a/55247867/17637456
57
+ */
58
+ export type RequiredKeys<T> = {
59
+ [K in keyof T]-?: {} extends {
60
+ [P in K]: T[K];
61
+ } ? never : K;
62
+ }[keyof T];
package/dist/utils.js CHANGED
@@ -83,7 +83,10 @@ export function levenshtein(a, b) {
83
83
  }
84
84
  return dd;
85
85
  }
86
- /** Waits n ms. */
86
+ /**
87
+ * Waits n ms.
88
+ * @hidden
89
+ */
87
90
  export function wait(ms) {
88
91
  return new Promise(resolve => {
89
92
  setTimeout(resolve, ms);
@@ -117,7 +120,7 @@ export function decode(input) {
117
120
  }
118
121
  /**
119
122
  * Decodes a directory listing
120
- * @internal
123
+ * @hidden
121
124
  */
122
125
  export function decodeDirListing(data) {
123
126
  return JSON.parse(decode(data), (k, v) => {
@@ -129,7 +132,7 @@ export function decodeDirListing(data) {
129
132
  }
130
133
  /**
131
134
  * Encodes a directory listing
132
- * @internal
135
+ * @hidden
133
136
  */
134
137
  export function encodeDirListing(data) {
135
138
  return encode(JSON.stringify(data, (k, v) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "0.5.12",
3
+ "version": "0.7.0",
4
4
  "description": "A filesystem in your browser",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist",
@@ -32,7 +32,8 @@
32
32
  },
33
33
  "exports": {
34
34
  ".": "./dist/index.js",
35
- "./*": "./dist/*"
35
+ "./*": "./dist/*",
36
+ "./promises": "./dist/emulations/promises.js"
36
37
  },
37
38
  "typesVersions": {
38
39
  "*": {
@@ -1,126 +0,0 @@
1
- import { FileSystem, FileSystemMetadata } from '../filesystem.js';
2
- import { File, PreloadFile } from '../file.js';
3
- import type { Stats } from '../stats.js';
4
- import { Cred } from '../cred.js';
5
- import type { Backend } from './backend.js';
6
- /**
7
- * We define our own file to interpose on syncSync() for mirroring purposes.
8
- * @internal
9
- */
10
- export declare class MirrorFile extends PreloadFile<AsyncMirrorFS> {
11
- constructor(fs: AsyncMirrorFS, path: string, flag: string, stat: Stats, data: Uint8Array);
12
- sync(): Promise<void>;
13
- syncSync(): void;
14
- close(): Promise<void>;
15
- closeSync(): void;
16
- }
17
- /**
18
- * Configuration options for the AsyncMirror file system.
19
- */
20
- export interface AsyncMirrorOptions {
21
- /**
22
- * The synchronous file system to mirror the asynchronous file system to.
23
- */
24
- sync: FileSystem;
25
- /**
26
- * The asynchronous file system to mirror.
27
- */
28
- async: FileSystem;
29
- }
30
- declare const AsyncMirrorFS_base: (abstract new (...args: any[]) => {
31
- metadata(): FileSystemMetadata;
32
- ready(): Promise<any>;
33
- exists(path: string, cred: Cred): Promise<boolean>;
34
- rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
35
- stat(path: string, cred: Cred): Promise<Stats>;
36
- createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
37
- openFile(path: string, flag: string, cred: Cred): Promise<File>;
38
- unlink(path: string, cred: Cred): Promise<void>;
39
- rmdir(path: string, cred: Cred): Promise<void>;
40
- mkdir(path: string, mode: number, cred: Cred): Promise<void>;
41
- readdir(path: string, cred: Cred): Promise<string[]>;
42
- link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
43
- sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
44
- renameSync(oldPath: string, newPath: string, cred: Cred): void;
45
- statSync(path: string, cred: Cred): Stats;
46
- openFileSync(path: string, flag: string, cred: Cred): File;
47
- createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
48
- unlinkSync(path: string, cred: Cred): void;
49
- rmdirSync(path: string, cred: Cred): void;
50
- mkdirSync(path: string, mode: number, cred: Cred): void;
51
- readdirSync(path: string, cred: Cred): string[];
52
- existsSync(path: string, cred: Cred): boolean;
53
- linkSync(srcpath: string, dstpath: string, cred: Cred): void;
54
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
55
- }) & typeof FileSystem;
56
- /**
57
- * AsyncMirrorFS mirrors a synchronous filesystem into an asynchronous filesystem
58
- * by:
59
- *
60
- * * Performing operations over the in-memory copy, while asynchronously pipelining them
61
- * to the backing store.
62
- * * During application loading, the contents of the async file system can be reloaded into
63
- * the synchronous store, if desired.
64
- *
65
- * The two stores will be kept in sync. The most common use-case is to pair a synchronous
66
- * in-memory filesystem with an asynchronous backing store.
67
- *
68
- */
69
- export declare class AsyncMirrorFS extends AsyncMirrorFS_base {
70
- /**
71
- * Queue of pending asynchronous operations.
72
- */
73
- private _queue;
74
- private _queueRunning;
75
- private _sync;
76
- private _async;
77
- private _isInitialized;
78
- private _ready;
79
- ready(): Promise<this>;
80
- /**
81
- *
82
- * Mirrors the synchronous file system into the asynchronous file system.
83
- *
84
- * @param sync The synchronous file system to mirror the asynchronous file system to.
85
- * @param async The asynchronous file system to mirror.
86
- */
87
- constructor({ sync, async }: AsyncMirrorOptions);
88
- metadata(): FileSystemMetadata;
89
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
90
- openFileSync(path: string, flag: string, cred: Cred): File;
91
- createFileSync(path: string, flag: string, mode: number, cred: Cred): MirrorFile;
92
- linkSync(srcpath: string, dstpath: string, cred: Cred): void;
93
- renameSync(oldPath: string, newPath: string, cred: Cred): void;
94
- statSync(p: string, cred: Cred): Stats;
95
- unlinkSync(p: string, cred: Cred): void;
96
- rmdirSync(p: string, cred: Cred): void;
97
- mkdirSync(p: string, mode: number, cred: Cred): void;
98
- readdirSync(p: string, cred: Cred): string[];
99
- existsSync(p: string, cred: Cred): boolean;
100
- /**
101
- * @internal
102
- */
103
- protected crossCopyDirectory(p: string, mode: number): Promise<void>;
104
- /**
105
- * @internal
106
- */
107
- protected crossCopyFile(p: string, mode: number): Promise<void>;
108
- /**
109
- * @internal
110
- */
111
- protected crossCopy(p: string): Promise<void>;
112
- /**
113
- * Called once to load up files from async storage into sync storage.
114
- */
115
- protected _initialize(): Promise<void>;
116
- /**
117
- * @internal
118
- */
119
- private _next;
120
- /**
121
- * @internal
122
- */
123
- private enqueue;
124
- }
125
- export declare const AsyncMirror: Backend<AsyncMirrorFS>;
126
- export {};
@@ -1,253 +0,0 @@
1
- import { FileSystem, Sync } from '../filesystem.js';
2
- import { ApiError, ErrorCode } from '../ApiError.js';
3
- import { PreloadFile, parseFlag } from '../file.js';
4
- import { join } from '../emulation/path.js';
5
- import { rootCred } from '../cred.js';
6
- /**
7
- * We define our own file to interpose on syncSync() for mirroring purposes.
8
- * @internal
9
- */
10
- export class MirrorFile extends PreloadFile {
11
- constructor(fs, path, flag, stat, data) {
12
- super(fs, path, flag, stat, data);
13
- }
14
- async sync() {
15
- this.syncSync();
16
- }
17
- syncSync() {
18
- if (this.isDirty()) {
19
- this.fs.syncSync(this.path, this._buffer, this.stats);
20
- this.resetDirty();
21
- }
22
- }
23
- async close() {
24
- this.closeSync();
25
- }
26
- closeSync() {
27
- this.syncSync();
28
- }
29
- }
30
- /**
31
- * AsyncMirrorFS mirrors a synchronous filesystem into an asynchronous filesystem
32
- * by:
33
- *
34
- * * Performing operations over the in-memory copy, while asynchronously pipelining them
35
- * to the backing store.
36
- * * During application loading, the contents of the async file system can be reloaded into
37
- * the synchronous store, if desired.
38
- *
39
- * The two stores will be kept in sync. The most common use-case is to pair a synchronous
40
- * in-memory filesystem with an asynchronous backing store.
41
- *
42
- */
43
- export class AsyncMirrorFS extends Sync(FileSystem) {
44
- async ready() {
45
- await this._ready;
46
- return this;
47
- }
48
- /**
49
- *
50
- * Mirrors the synchronous file system into the asynchronous file system.
51
- *
52
- * @param sync The synchronous file system to mirror the asynchronous file system to.
53
- * @param async The asynchronous file system to mirror.
54
- */
55
- constructor({ sync, async }) {
56
- super();
57
- /**
58
- * Queue of pending asynchronous operations.
59
- */
60
- this._queue = [];
61
- this._queueRunning = false;
62
- this._isInitialized = false;
63
- this._sync = sync;
64
- this._async = async;
65
- this._ready = this._initialize();
66
- }
67
- metadata() {
68
- return {
69
- ...super.metadata(),
70
- name: AsyncMirrorFS.name,
71
- synchronous: true,
72
- supportsProperties: this._sync.metadata().supportsProperties && this._async.metadata().supportsProperties,
73
- };
74
- }
75
- syncSync(path, data, stats) {
76
- this._sync.syncSync(path, data, stats);
77
- this.enqueue({
78
- apiMethod: 'sync',
79
- arguments: [path, data, stats],
80
- });
81
- }
82
- openFileSync(path, flag, cred) {
83
- return this._sync.openFileSync(path, flag, cred);
84
- }
85
- createFileSync(path, flag, mode, cred) {
86
- const file = this._sync.createFileSync(path, flag, mode, cred);
87
- this.enqueue({
88
- apiMethod: 'createFile',
89
- arguments: [path, flag, mode, cred],
90
- });
91
- const stats = file.statSync();
92
- const buffer = new Uint8Array(stats.size);
93
- file.readSync(buffer);
94
- return new MirrorFile(this, path, flag, stats, buffer);
95
- }
96
- linkSync(srcpath, dstpath, cred) {
97
- this._sync.linkSync(srcpath, dstpath, cred);
98
- this.enqueue({
99
- apiMethod: 'link',
100
- arguments: [srcpath, dstpath, cred],
101
- });
102
- }
103
- renameSync(oldPath, newPath, cred) {
104
- this._sync.renameSync(oldPath, newPath, cred);
105
- this.enqueue({
106
- apiMethod: 'rename',
107
- arguments: [oldPath, newPath, cred],
108
- });
109
- }
110
- statSync(p, cred) {
111
- return this._sync.statSync(p, cred);
112
- }
113
- unlinkSync(p, cred) {
114
- this._sync.unlinkSync(p, cred);
115
- this.enqueue({
116
- apiMethod: 'unlink',
117
- arguments: [p, cred],
118
- });
119
- }
120
- rmdirSync(p, cred) {
121
- this._sync.rmdirSync(p, cred);
122
- this.enqueue({
123
- apiMethod: 'rmdir',
124
- arguments: [p, cred],
125
- });
126
- }
127
- mkdirSync(p, mode, cred) {
128
- this._sync.mkdirSync(p, mode, cred);
129
- this.enqueue({
130
- apiMethod: 'mkdir',
131
- arguments: [p, mode, cred],
132
- });
133
- }
134
- readdirSync(p, cred) {
135
- return this._sync.readdirSync(p, cred);
136
- }
137
- existsSync(p, cred) {
138
- return this._sync.existsSync(p, cred);
139
- }
140
- /**
141
- * @internal
142
- */
143
- async crossCopyDirectory(p, mode) {
144
- if (p !== '/') {
145
- const stats = await this._async.stat(p, rootCred);
146
- this._sync.mkdirSync(p, mode, stats.cred());
147
- }
148
- const files = await this._async.readdir(p, rootCred);
149
- for (const file of files) {
150
- await this.crossCopy(join(p, file));
151
- }
152
- }
153
- /**
154
- * @internal
155
- */
156
- async crossCopyFile(p, mode) {
157
- const asyncFile = await this._async.openFile(p, parseFlag('r'), rootCred);
158
- const syncFile = this._sync.createFileSync(p, parseFlag('w'), mode, rootCred);
159
- try {
160
- const { size } = await asyncFile.stat();
161
- const buffer = new Uint8Array(size);
162
- await asyncFile.read(buffer);
163
- syncFile.writeSync(buffer);
164
- }
165
- finally {
166
- await asyncFile.close();
167
- syncFile.closeSync();
168
- }
169
- }
170
- /**
171
- * @internal
172
- */
173
- async crossCopy(p) {
174
- const stats = await this._async.stat(p, rootCred);
175
- if (stats.isDirectory()) {
176
- await this.crossCopyDirectory(p, stats.mode);
177
- }
178
- else {
179
- await this.crossCopyFile(p, stats.mode);
180
- }
181
- }
182
- /**
183
- * Called once to load up files from async storage into sync storage.
184
- */
185
- async _initialize() {
186
- if (this._isInitialized) {
187
- return;
188
- }
189
- try {
190
- await this.crossCopy('/');
191
- this._isInitialized = true;
192
- }
193
- catch (e) {
194
- this._isInitialized = false;
195
- throw e;
196
- }
197
- }
198
- /**
199
- * @internal
200
- */
201
- async _next() {
202
- if (this._queue.length == 0) {
203
- this._queueRunning = false;
204
- return;
205
- }
206
- const op = this._queue.shift();
207
- try {
208
- // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
209
- await this._async[op.apiMethod](...op.arguments);
210
- }
211
- catch (e) {
212
- throw new ApiError(ErrorCode.EIO, 'AsyncMirror desync: ' + e);
213
- }
214
- await this._next();
215
- }
216
- /**
217
- * @internal
218
- */
219
- enqueue(op) {
220
- this._queue.push(op);
221
- if (this._queueRunning) {
222
- return;
223
- }
224
- this._queueRunning = true;
225
- this._next();
226
- }
227
- }
228
- export const AsyncMirror = {
229
- name: 'AsyncMirror',
230
- options: {
231
- sync: {
232
- type: 'object',
233
- required: true,
234
- description: 'The synchronous file system to mirror the asynchronous file system to.',
235
- validator: async (backend) => {
236
- if ('metadata' in backend && !backend.metadata().synchronous) {
237
- throw new ApiError(ErrorCode.EINVAL, '"sync" option must be a file system that supports synchronous operations');
238
- }
239
- },
240
- },
241
- async: {
242
- type: 'object',
243
- required: true,
244
- description: 'The asynchronous file system to mirror.',
245
- },
246
- },
247
- isAvailable() {
248
- return true;
249
- },
250
- create(options) {
251
- return new AsyncMirrorFS(options);
252
- },
253
- };