@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.
@@ -169,6 +169,15 @@ declare const FileIndexFS_base: (abstract new (...args: any[]) => {
169
169
  linkSync(srcpath: string, dstpath: string, cred: Cred): void;
170
170
  sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
171
171
  syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
172
+ ready(): Promise<any>;
173
+ stat(path: string, cred: Cred): Promise<Stats>;
174
+ statSync(path: string, cred: Cred): Stats;
175
+ openFile(path: string, flag: string, cred: Cred): Promise<import("./file.js").File>;
176
+ openFileSync(path: string, flag: string, cred: Cred): import("./file.js").File;
177
+ readdir(path: string, cred: Cred): Promise<string[]>;
178
+ readdirSync(path: string, cred: Cred): string[];
179
+ exists(path: string, cred: Cred): Promise<boolean>;
180
+ existsSync(path: string, cred: Cred): boolean;
172
181
  }) & typeof FileSystem;
173
182
  export declare abstract class FileIndexFS<TIndex> extends FileIndexFS_base {
174
183
  protected _index: FileIndex<TIndex>;
@@ -184,39 +193,14 @@ export declare abstract class FileIndexFS<TIndex> extends FileIndexFS_base {
184
193
  protected abstract openFileInode(inode: IndexFileInode<TIndex>, path: string, flag: string): Promise<NoSyncFile<this>>;
185
194
  protected abstract openFileInodeSync(inode: IndexFileInode<TIndex>, path: string, flag: string): NoSyncFile<this>;
186
195
  }
187
- declare const SyncFileIndexFS_base: (abstract new (...args: any[]) => {
188
- metadata(): import("./filesystem.js").FileSystemMetadata;
189
- ready(): Promise<any>;
190
- exists(path: string, cred: Cred): Promise<boolean>;
191
- rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
192
- stat(path: string, cred: Cred): Promise<Stats>;
193
- createFile(path: string, flag: string, mode: number, cred: Cred): Promise<import("./file.js").File>;
194
- openFile(path: string, flag: string, cred: Cred): Promise<import("./file.js").File>;
195
- unlink(path: string, cred: Cred): Promise<void>;
196
- rmdir(path: string, cred: Cred): Promise<void>;
197
- mkdir(path: string, mode: number, cred: Cred): Promise<void>;
198
- readdir(path: string, cred: Cred): Promise<string[]>;
199
- link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
200
- sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
201
- renameSync(oldPath: string, newPath: string, cred: Cred): void;
202
- statSync(path: string, cred: Cred): Stats;
203
- openFileSync(path: string, flag: string, cred: Cred): import("./file.js").File;
204
- createFileSync(path: string, flag: string, mode: number, cred: Cred): import("./file.js").File;
205
- unlinkSync(path: string, cred: Cred): void;
206
- rmdirSync(path: string, cred: Cred): void;
207
- mkdirSync(path: string, mode: number, cred: Cred): void;
208
- readdirSync(path: string, cred: Cred): string[];
209
- existsSync(path: string, cred: Cred): boolean;
210
- linkSync(srcpath: string, dstpath: string, cred: Cred): void;
211
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
212
- }) & (abstract new (index: ListingTree) => FileIndexFS<unknown>);
213
- export declare abstract class SyncFileIndexFS<TIndex> extends SyncFileIndexFS_base {
214
- _index: FileIndex<TIndex>;
196
+ export declare abstract class SyncFileIndexFS<TIndex> extends FileIndexFS<TIndex> {
215
197
  protected statFileInode(inode: IndexFileInode<TIndex>, path: string): Promise<Stats>;
216
198
  protected openFileInode(inode: IndexFileInode<TIndex>, path: string, flag: string): Promise<NoSyncFile<this>>;
217
199
  }
218
200
  declare const AsyncFileIndexFS_base: (abstract new (...args: any[]) => {
201
+ _sync: FileSystem;
219
202
  metadata(): import("./filesystem.js").FileSystemMetadata;
203
+ ready(): Promise<any>;
220
204
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
221
205
  statSync(path: string, cred: Cred): Stats;
222
206
  createFileSync(path: string, flag: string, mode: number, cred: Cred): import("./file.js").File;
@@ -227,6 +211,18 @@ declare const AsyncFileIndexFS_base: (abstract new (...args: any[]) => {
227
211
  readdirSync(path: string, cred: Cred): string[];
228
212
  linkSync(srcpath: string, dstpath: string, cred: Cred): void;
229
213
  syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
214
+ rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
215
+ stat(path: string, cred: Cred): Promise<Stats>;
216
+ openFile(path: string, flag: string, cred: Cred): Promise<import("./file.js").File>;
217
+ createFile(path: string, flag: string, mode: number, cred: Cred): Promise<import("./file.js").File>;
218
+ unlink(path: string, cred: Cred): Promise<void>;
219
+ rmdir(path: string, cred: Cred): Promise<void>;
220
+ mkdir(path: string, mode: number, cred: Cred): Promise<void>;
221
+ readdir(path: string, cred: Cred): Promise<string[]>;
222
+ exists(path: string, cred: Cred): Promise<boolean>;
223
+ existsSync(path: string, cred: Cred): boolean;
224
+ link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
225
+ sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
230
226
  }) & (abstract new (index: ListingTree) => FileIndexFS<unknown>);
231
227
  export declare abstract class AsyncFileIndexFS<TIndex> extends AsyncFileIndexFS_base {
232
228
  _index: FileIndex<TIndex>;
package/dist/FileIndex.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ApiError, ErrorCode } from './ApiError.js';
2
2
  import { basename, dirname, join } from './emulation/path.js';
3
3
  import { NoSyncFile, flagToMode, isWriteable } from './file.js';
4
- import { FileSystem, Sync, Async, Readonly } from './filesystem.js';
4
+ import { FileSystem, Async, Readonly } from './filesystem.js';
5
5
  import { FileType, Stats } from './stats.js';
6
6
  /**
7
7
  * A simple class for storing a filesystem index. Assumes that all paths passed
@@ -390,7 +390,7 @@ export class FileIndexFS extends Readonly(FileSystem) {
390
390
  throw ApiError.With('ENOTDIR', path, 'readdirSync');
391
391
  }
392
392
  }
393
- export class SyncFileIndexFS extends Sync((FileIndexFS)) {
393
+ export class SyncFileIndexFS extends FileIndexFS {
394
394
  async statFileInode(inode, path) {
395
395
  return this.statFileInodeSync(inode, path);
396
396
  }
@@ -1,5 +1,5 @@
1
1
  import type { Cred } from '../cred.js';
2
- import { PreloadFile, File } from '../file.js';
2
+ import { PreloadFile } from '../file.js';
3
3
  import { FileSystem, type FileSystemMetadata } from '../filesystem.js';
4
4
  import { type Ino } from '../inode.js';
5
5
  import { type Stats } from '../stats.js';
@@ -52,17 +52,6 @@ export interface AsyncTransaction {
52
52
  */
53
53
  abort(): Promise<void>;
54
54
  }
55
- /**
56
- * Async preload file for usage with AsyncStore
57
- * @internal
58
- */
59
- export declare class AsyncFile extends PreloadFile<AsyncStoreFS> {
60
- constructor(_fs: AsyncStoreFS, _path: string, _flag: string, _stat: Stats, contents?: Uint8Array);
61
- sync(): Promise<void>;
62
- syncSync(): void;
63
- close(): Promise<void>;
64
- closeSync(): void;
65
- }
66
55
  export interface AsyncStoreOptions {
67
56
  /**
68
57
  * Promise that resolves to the store
@@ -71,20 +60,38 @@ export interface AsyncStoreOptions {
71
60
  /**
72
61
  * The size of the cache. If not provided, no cache will be used
73
62
  */
74
- cacheSize?: number;
63
+ lruCacheSize?: number;
64
+ /**
65
+ * The file system to use for synchronous methods. Defaults to InMemory
66
+ */
67
+ sync?: FileSystem;
75
68
  }
76
69
  declare const AsyncStoreFS_base: (abstract new (...args: any[]) => {
70
+ _sync: FileSystem;
77
71
  metadata(): FileSystemMetadata;
72
+ ready(): Promise<any>;
78
73
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
79
74
  statSync(path: string, cred: Cred): Stats;
80
- createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
81
- openFileSync(path: string, flag: string, cred: Cred): File;
75
+ createFileSync(path: string, flag: string, mode: number, cred: Cred): import("../file.js").File;
76
+ openFileSync(path: string, flag: string, cred: Cred): import("../file.js").File;
82
77
  unlinkSync(path: string, cred: Cred): void;
83
78
  rmdirSync(path: string, cred: Cred): void;
84
79
  mkdirSync(path: string, mode: number, cred: Cred): void;
85
80
  readdirSync(path: string, cred: Cred): string[];
86
81
  linkSync(srcpath: string, dstpath: string, cred: Cred): void;
87
82
  syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
83
+ rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
84
+ stat(path: string, cred: Cred): Promise<Stats>;
85
+ openFile(path: string, flag: string, cred: Cred): Promise<import("../file.js").File>;
86
+ createFile(path: string, flag: string, mode: number, cred: Cred): Promise<import("../file.js").File>;
87
+ unlink(path: string, cred: Cred): Promise<void>;
88
+ rmdir(path: string, cred: Cred): Promise<void>;
89
+ mkdir(path: string, mode: number, cred: Cred): Promise<void>;
90
+ readdir(path: string, cred: Cred): Promise<string[]>;
91
+ exists(path: string, cred: Cred): Promise<boolean>;
92
+ existsSync(path: string, cred: Cred): boolean;
93
+ link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
94
+ sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
88
95
  }) & typeof FileSystem;
89
96
  /**
90
97
  * An asynchronous file system which uses an async store to store its data.
@@ -94,15 +101,16 @@ declare const AsyncStoreFS_base: (abstract new (...args: any[]) => {
94
101
  export declare class AsyncStoreFS extends AsyncStoreFS_base {
95
102
  protected store: AsyncStore;
96
103
  private _cache?;
97
- protected _ready: Promise<this>;
104
+ _sync: FileSystem;
105
+ protected _ready: Promise<void>;
98
106
  ready(): Promise<this>;
99
107
  metadata(): FileSystemMetadata;
100
- constructor({ store, cacheSize }: AsyncStoreOptions);
108
+ constructor(options: AsyncStoreOptions);
101
109
  /**
102
110
  * Initializes the file system. Typically called by subclasses' async
103
111
  * constructors.
104
112
  */
105
- protected _initialize(store: Promise<AsyncStore> | AsyncStore): Promise<this>;
113
+ protected _initialize({ store, lruCacheSize, sync }: AsyncStoreOptions): Promise<void>;
106
114
  /**
107
115
  * Delete all contents stored in the file system.
108
116
  */
@@ -112,8 +120,8 @@ export declare class AsyncStoreFS extends AsyncStoreFS_base {
112
120
  */
113
121
  rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
114
122
  stat(p: string, cred: Cred): Promise<Stats>;
115
- createFile(p: string, flag: string, mode: number, cred: Cred): Promise<File>;
116
- openFile(p: string, flag: string, cred: Cred): Promise<File>;
123
+ createFile(p: string, flag: string, mode: number, cred: Cred): Promise<PreloadFile<this>>;
124
+ openFile(p: string, flag: string, cred: Cred): Promise<PreloadFile<this>>;
117
125
  unlink(p: string, cred: Cred): Promise<void>;
118
126
  rmdir(p: string, cred: Cred): Promise<void>;
119
127
  mkdir(p: string, mode: number, cred: Cred): Promise<void>;
@@ -7,6 +7,7 @@ import { randomIno, Inode } from '../inode.js';
7
7
  import { FileType } from '../stats.js';
8
8
  import { encode, decodeDirListing, encodeDirListing } from '../utils.js';
9
9
  import { rootIno } from '../inode.js';
10
+ import { InMemory } from './InMemory.js';
10
11
  /**
11
12
  * Last Recently Used cache
12
13
  */
@@ -44,39 +45,16 @@ class LRUCache {
44
45
  this.cache = [];
45
46
  }
46
47
  }
47
- /**
48
- * Async preload file for usage with AsyncStore
49
- * @internal
50
- */
51
- export class AsyncFile extends PreloadFile {
52
- constructor(_fs, _path, _flag, _stat, contents) {
53
- super(_fs, _path, _flag, _stat, contents);
54
- }
55
- async sync() {
56
- if (!this.isDirty()) {
57
- return;
58
- }
59
- await this.fs.sync(this.path, this._buffer, this.stats);
60
- this.resetDirty();
61
- }
62
- syncSync() {
63
- throw new ApiError(ErrorCode.ENOTSUP);
64
- }
65
- async close() {
66
- this.sync();
67
- }
68
- closeSync() {
69
- throw new ApiError(ErrorCode.ENOTSUP);
70
- }
71
- }
72
48
  /**
73
49
  * An asynchronous file system which uses an async store to store its data.
74
50
  * @see AsyncStore
75
51
  * @internal
76
52
  */
77
53
  export class AsyncStoreFS extends Async(FileSystem) {
78
- ready() {
79
- return this._ready;
54
+ async ready() {
55
+ await super.ready();
56
+ await this._ready;
57
+ return this;
80
58
  }
81
59
  metadata() {
82
60
  return {
@@ -84,22 +62,21 @@ export class AsyncStoreFS extends Async(FileSystem) {
84
62
  name: this.store.name,
85
63
  };
86
64
  }
87
- constructor({ store, cacheSize }) {
65
+ constructor(options) {
88
66
  super();
89
- if (cacheSize > 0) {
90
- this._cache = new LRUCache(cacheSize);
91
- }
92
- this._ready = this._initialize(store);
67
+ this._ready = this._initialize(options);
93
68
  }
94
69
  /**
95
70
  * Initializes the file system. Typically called by subclasses' async
96
71
  * constructors.
97
72
  */
98
- async _initialize(store) {
73
+ async _initialize({ store, lruCacheSize, sync }) {
74
+ if (lruCacheSize > 0) {
75
+ this._cache = new LRUCache(lruCacheSize);
76
+ }
99
77
  this.store = await store;
100
- // INVARIANT: Ensure that the root exists.
101
78
  await this.makeRootDirectory();
102
- return this;
79
+ this._sync = sync || InMemory.create({ name: 'test' });
103
80
  }
104
81
  /**
105
82
  * Delete all contents stored in the file system.
@@ -204,7 +181,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
204
181
  async createFile(p, flag, mode, cred) {
205
182
  const tx = this.store.beginTransaction(), data = new Uint8Array(0), newFile = await this.commitNewFile(tx, p, FileType.FILE, mode, cred, data);
206
183
  // Open the file.
207
- return new AsyncFile(this, p, flag, newFile.toStats(), data);
184
+ return new PreloadFile(this, p, flag, newFile.toStats(), data);
208
185
  }
209
186
  async openFile(p, flag, cred) {
210
187
  const tx = this.store.beginTransaction(), node = await this.findINode(tx, p), data = await tx.get(node.ino);
@@ -214,7 +191,7 @@ export class AsyncStoreFS extends Async(FileSystem) {
214
191
  if (!data) {
215
192
  throw ApiError.With('ENOENT', p, 'openFile');
216
193
  }
217
- return new AsyncFile(this, p, flag, node.toStats(), data);
194
+ return new PreloadFile(this, p, flag, node.toStats(), data);
218
195
  }
219
196
  async unlink(p, cred) {
220
197
  return this.removeEntry(p, false, cred);
@@ -1,5 +1,4 @@
1
1
  import type { Ino } from '../inode.js';
2
- import type { Backend } from './backend.js';
3
2
  import { SyncStore, SimpleSyncStore, SyncTransaction, SyncStoreFS } from './SyncStore.js';
4
3
  /**
5
4
  * A simple in-memory store
@@ -18,4 +17,17 @@ export declare class InMemoryStore implements SyncStore, SimpleSyncStore {
18
17
  * A simple in-memory file system backed by an InMemoryStore.
19
18
  * Files are not persisted across page loads.
20
19
  */
21
- export declare const InMemory: Backend<SyncStoreFS>;
20
+ export declare const InMemory: {
21
+ readonly name: "InMemory";
22
+ readonly isAvailable: () => boolean;
23
+ readonly options: {
24
+ readonly name: {
25
+ readonly type: "string";
26
+ readonly required: false;
27
+ readonly description: "The name of the store";
28
+ };
29
+ };
30
+ readonly create: ({ name }: {
31
+ name?: string;
32
+ }) => SyncStoreFS;
33
+ };
@@ -1,20 +1,8 @@
1
1
  import { FileSystem, FileSystemMetadata } from '../filesystem.js';
2
- import { File, PreloadFile } from '../file.js';
2
+ import { File } from '../file.js';
3
3
  import { Stats } from '../stats.js';
4
4
  import { LockedFS } from './Locked.js';
5
5
  import { Cred } from '../cred.js';
6
- import type { Backend } from './backend.js';
7
- /**
8
- * Overlays a RO file to make it writable.
9
- * @internal
10
- */
11
- export declare class OverlayFile extends PreloadFile<UnlockedOverlayFS> implements File {
12
- constructor(fs: UnlockedOverlayFS, path: string, flag: string, stats: Stats, data: Uint8Array);
13
- sync(): Promise<void>;
14
- syncSync(): void;
15
- close(): Promise<void>;
16
- closeSync(): void;
17
- }
18
6
  /**
19
7
  * Configuration options for OverlayFS instances.
20
8
  */
@@ -119,4 +107,20 @@ export declare class OverlayFS extends LockedFS<UnlockedOverlayFS> {
119
107
  resDeletionLog(): string;
120
108
  unwrap(): UnlockedOverlayFS;
121
109
  }
122
- export declare const Overlay: Backend<OverlayFS>;
110
+ export declare const Overlay: {
111
+ readonly name: "Overlay";
112
+ readonly options: {
113
+ readonly writable: {
114
+ readonly type: "object";
115
+ readonly required: true;
116
+ readonly description: "The file system to write modified files to.";
117
+ };
118
+ readonly readable: {
119
+ readonly type: "object";
120
+ readonly required: true;
121
+ readonly description: "The file system that initially populates this file system.";
122
+ };
123
+ };
124
+ readonly isAvailable: () => boolean;
125
+ readonly create: (options: OverlayOptions) => OverlayFS;
126
+ };
@@ -10,34 +10,6 @@ import { decode, encode } from '../utils.js';
10
10
  * @internal
11
11
  */
12
12
  const deletionLogPath = '/.deleted';
13
- /**
14
- * Overlays a RO file to make it writable.
15
- * @internal
16
- */
17
- export class OverlayFile extends PreloadFile {
18
- constructor(fs, path, flag, stats, data) {
19
- super(fs, path, flag, stats, data);
20
- }
21
- async sync() {
22
- if (!this.isDirty()) {
23
- return;
24
- }
25
- await this.fs.sync(this.path, this.buffer, this.stats);
26
- this.resetDirty();
27
- }
28
- syncSync() {
29
- if (this.isDirty()) {
30
- this.fs.syncSync(this.path, this.buffer, this.stats);
31
- this.resetDirty();
32
- }
33
- }
34
- async close() {
35
- await this.sync();
36
- }
37
- closeSync() {
38
- this.syncSync();
39
- }
40
- }
41
13
  /**
42
14
  * OverlayFS makes a read-only filesystem writable by storing writes on a second, writable file system.
43
15
  * Deletes are persisted via metadata stored on the writable file system.
@@ -74,7 +46,6 @@ export class UnlockedOverlayFS extends FileSystem {
74
46
  return {
75
47
  ...super.metadata(),
76
48
  name: OverlayFS.name,
77
- synchronous: this._readable.metadata().synchronous && this._writable.metadata().synchronous,
78
49
  supportsProperties: this._readable.metadata().supportsProperties && this._writable.metadata().supportsProperties,
79
50
  };
80
51
  }
@@ -189,7 +160,7 @@ export class UnlockedOverlayFS extends FileSystem {
189
160
  const file = await this._readable.openFile(path, parseFlag('r'), cred);
190
161
  const stats = new Stats(await file.stat());
191
162
  const { buffer } = await file.read(new Uint8Array(stats.size));
192
- return new OverlayFile(this, path, flag, stats, buffer);
163
+ return new PreloadFile(this, path, flag, stats, buffer);
193
164
  }
194
165
  openFileSync(path, flag, cred) {
195
166
  if (this._writable.existsSync(path, cred)) {
@@ -200,7 +171,7 @@ export class UnlockedOverlayFS extends FileSystem {
200
171
  const stats = Stats.clone(file.statSync());
201
172
  const data = new Uint8Array(stats.size);
202
173
  file.readSync(data);
203
- return new OverlayFile(this, path, flag, stats, data);
174
+ return new PreloadFile(this, path, flag, stats, data);
204
175
  }
205
176
  async createFile(path, flag, mode, cred) {
206
177
  this.checkInitialized();
@@ -102,17 +102,6 @@ export interface SyncStoreOptions {
102
102
  */
103
103
  store: SyncStore;
104
104
  }
105
- /**
106
- * File backend by a SyncStoreFS
107
- * @internal
108
- */
109
- export declare class SyncStoreFile extends PreloadFile<SyncStoreFS> {
110
- constructor(_fs: SyncStoreFS, _path: string, _flag: string, _stat: Stats, contents?: Uint8Array);
111
- sync(): Promise<void>;
112
- syncSync(): void;
113
- close(): Promise<void>;
114
- closeSync(): void;
115
- }
116
105
  declare const SyncStoreFS_base: (abstract new (...args: any[]) => {
117
106
  metadata(): FileSystemMetadata;
118
107
  ready(): Promise<any>;
@@ -157,8 +146,8 @@ export declare class SyncStoreFS extends SyncStoreFS_base {
157
146
  empty(): void;
158
147
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
159
148
  statSync(p: string, cred: Cred): Stats;
160
- createFileSync(p: string, flag: string, mode: number, cred: Cred): SyncStoreFile;
161
- openFileSync(p: string, flag: string, cred: Cred): SyncStoreFile;
149
+ createFileSync(p: string, flag: string, mode: number, cred: Cred): PreloadFile<this>;
150
+ openFileSync(p: string, flag: string, cred: Cred): PreloadFile<this>;
162
151
  unlinkSync(p: string, cred: Cred): void;
163
152
  rmdirSync(p: string, cred: Cred): void;
164
153
  mkdirSync(p: string, mode: number, cred: Cred): void;
@@ -76,30 +76,6 @@ export class SimpleSyncTransaction {
76
76
  }
77
77
  }
78
78
  }
79
- /**
80
- * File backend by a SyncStoreFS
81
- * @internal
82
- */
83
- export class SyncStoreFile extends PreloadFile {
84
- constructor(_fs, _path, _flag, _stat, contents) {
85
- super(_fs, _path, _flag, _stat, contents);
86
- }
87
- async sync() {
88
- this.syncSync();
89
- }
90
- syncSync() {
91
- if (this.isDirty()) {
92
- this.fs.syncSync(this.path, this._buffer, this.stats);
93
- this.resetDirty();
94
- }
95
- }
96
- async close() {
97
- this.closeSync();
98
- }
99
- closeSync() {
100
- this.syncSync();
101
- }
102
- }
103
79
  /**
104
80
  * A synchronous key-value file system. Uses a SyncStore to store the data.
105
81
  *
@@ -210,7 +186,7 @@ export class SyncStoreFS extends Sync(FileSystem) {
210
186
  if (data === null) {
211
187
  throw ApiError.With('ENOENT', p, 'openFileSync');
212
188
  }
213
- return new SyncStoreFile(this, p, flag, node.toStats(), data);
189
+ return new PreloadFile(this, p, flag, node.toStats(), data);
214
190
  }
215
191
  unlinkSync(p, cred) {
216
192
  this.removeEntry(p, false, cred);
@@ -1,4 +1,5 @@
1
1
  import { FileSystem } from '../filesystem.js';
2
+ import { type RequiredKeys } from '../utils.js';
2
3
  type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function';
3
4
  /**
4
5
  * Describes a file system option.
@@ -23,18 +24,22 @@ export interface OptionConfig<T> {
23
24
  */
24
25
  validator?(opt: T): void | Promise<void>;
25
26
  }
26
- /**
27
- * Describes all of the options available in a file system.
28
- */
29
- type BackendOptionsConfig = Record<string, OptionConfig<unknown>>;
27
+ type InferOptionsConfig<T> = {
28
+ [K in keyof T]: {
29
+ type: OptionType | OptionType[];
30
+ description: string;
31
+ required: K extends RequiredKeys<T> ? true : false;
32
+ validator?(opt: T[K]): void | Promise<void>;
33
+ };
34
+ };
30
35
  /**
31
36
  * A backend
32
37
  */
33
- export interface Backend<FS extends FileSystem = FileSystem, OC extends BackendOptionsConfig = BackendOptionsConfig> {
38
+ export interface Backend<FS extends FileSystem = FileSystem, TOptions extends object = object> {
34
39
  /**
35
40
  * Create a new instance of the backend
36
41
  */
37
- create(options: object): FS;
42
+ create(options: TOptions): FS;
38
43
  /**
39
44
  * A name to identify the backend.
40
45
  */
@@ -42,7 +47,7 @@ export interface Backend<FS extends FileSystem = FileSystem, OC extends BackendO
42
47
  /**
43
48
  * Describes all of the options available for this backend.
44
49
  */
45
- options: OC;
50
+ options: InferOptionsConfig<TOptions>;
46
51
  /**
47
52
  * Whether the backend is available in the current environment.
48
53
  * It supports checking synchronously and asynchronously
@@ -63,7 +68,7 @@ export declare function isBackend(arg: unknown): arg is Backend;
63
68
  * Checks that the given options object is valid for the file system options.
64
69
  * @internal
65
70
  */
66
- export declare function checkOptions(backend: Backend, opts: object): Promise<void>;
71
+ export declare function checkOptions<T extends Backend>(backend: T, opts: object): Promise<void>;
67
72
  export declare function createBackend<B extends Backend>(backend: B, options?: object): Promise<ReturnType<B['create']>>;
68
73
  /**
69
74
  * Specifies a file system backend type and its options.
@@ -73,17 +78,11 @@ export declare function createBackend<B extends Backend>(backend: B, options?: o
73
78
  *
74
79
  * The option object for each file system corresponds to that file system's option object passed to its `Create()` method.
75
80
  */
76
- export interface BackendConfig<FS extends FileSystem = FileSystem, OC extends BackendOptionsConfig = BackendOptionsConfig> {
77
- backend: Backend<FS, OC>;
78
- [key: string]: unknown;
79
- }
81
+ export type BackendConfiguration<FS extends FileSystem = FileSystem, TOptions extends object = object> = TOptions & {
82
+ backend: Backend<FS, TOptions>;
83
+ };
80
84
  /**
81
85
  * @internal
82
86
  */
83
- export declare function isBackendConfig(arg: unknown): arg is BackendConfig;
84
- /**
85
- * Retrieve a file system with the given configuration.
86
- * @param config A BackendConfig object.
87
- */
88
- export declare function resolveBackend<FS extends FileSystem>(options: BackendConfig<FS>, _depth?: number): Promise<FS>;
87
+ export declare function isBackendConfig(arg: unknown): arg is BackendConfiguration;
89
88
  export {};
@@ -53,38 +53,5 @@ export function createBackend(backend, options) {
53
53
  * @internal
54
54
  */
55
55
  export function isBackendConfig(arg) {
56
- return arg != null && typeof arg == 'object' && 'backend' in arg;
57
- }
58
- /**
59
- * Retrieve a file system with the given configuration.
60
- * @param config A BackendConfig object.
61
- */
62
- export async function resolveBackend(options, _depth = 0) {
63
- if (typeof options !== 'object' || options == null) {
64
- throw new ApiError(ErrorCode.EINVAL, 'Invalid options on configuration object.');
65
- }
66
- const { backend } = options;
67
- if (!isBackend(backend)) {
68
- throw new ApiError(ErrorCode.EINVAL, 'Missing or invalid backend');
69
- }
70
- const props = Object.keys(options).filter(k => k != 'backend');
71
- for (const prop of props) {
72
- let option = options[prop];
73
- if (isBackend(option)) {
74
- option = { backend: option };
75
- }
76
- if (isBackendConfig(option)) {
77
- if (_depth > 10) {
78
- throw new ApiError(ErrorCode.EINVAL, 'Invalid configuration, too deep and possibly infinite');
79
- }
80
- options[prop] = await resolveBackend(option, ++_depth);
81
- }
82
- }
83
- if (!(await backend.isAvailable())) {
84
- throw new ApiError(ErrorCode.EPERM, 'Backend not available: ' + backend);
85
- }
86
- checkOptions(backend, options);
87
- const fs = backend.create(options);
88
- await fs.ready();
89
- return fs;
56
+ return arg != null && typeof arg == 'object' && 'backend' in arg && isBackend(arg.backend);
90
57
  }