@zenfs/core 0.3.0 → 0.3.2
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/dist/FileIndex.d.ts +3 -25
- package/dist/backends/AsyncMirror.d.ts +16 -18
- package/dist/backends/AsyncMirror.js +4 -5
- package/dist/backends/AsyncStore.d.ts +8 -21
- package/dist/backends/AsyncStore.js +3 -3
- package/dist/backends/InMemory.js +2 -2
- package/dist/backends/Locked.d.ts +1 -1
- package/dist/backends/Locked.js +3 -3
- package/dist/backends/Overlay.d.ts +1 -1
- package/dist/backends/Overlay.js +5 -5
- package/dist/backends/SyncStore.d.ts +8 -8
- package/dist/backends/SyncStore.js +3 -4
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +3 -3
- package/dist/file.js +6 -6
- package/dist/filesystem.d.ts +25 -165
- package/dist/filesystem.js +15 -13
- package/package.json +1 -1
- package/readme.md +48 -70
- package/dist/backends/FolderAdapter.d.ts +0 -52
- package/dist/backends/FolderAdapter.js +0 -173
- package/dist/backends/OverlayFS.d.ts +0 -112
- package/dist/backends/OverlayFS.js +0 -542
- package/dist/emulation/fs.d.ts +0 -6
- package/dist/emulation/fs.js +0 -4
package/dist/file.js
CHANGED
|
@@ -296,7 +296,7 @@ export class PreloadFile extends File {
|
|
|
296
296
|
*/
|
|
297
297
|
truncate(len) {
|
|
298
298
|
this.truncateSync(len);
|
|
299
|
-
if (this.flag.isSynchronous() && !this.fs.metadata.synchronous) {
|
|
299
|
+
if (this.flag.isSynchronous() && !this.fs.metadata().synchronous) {
|
|
300
300
|
return this.sync();
|
|
301
301
|
}
|
|
302
302
|
}
|
|
@@ -314,7 +314,7 @@ export class PreloadFile extends File {
|
|
|
314
314
|
const buf = new Uint8Array(len - this._buffer.length);
|
|
315
315
|
// Write will set stats.size for us.
|
|
316
316
|
this.writeSync(buf, 0, buf.length, this._buffer.length);
|
|
317
|
-
if (this.flag.isSynchronous() && this.fs.metadata.synchronous) {
|
|
317
|
+
if (this.flag.isSynchronous() && this.fs.metadata().synchronous) {
|
|
318
318
|
this.syncSync();
|
|
319
319
|
}
|
|
320
320
|
return;
|
|
@@ -322,7 +322,7 @@ export class PreloadFile extends File {
|
|
|
322
322
|
this.stats.size = len;
|
|
323
323
|
// Truncate buffer to 'len'.
|
|
324
324
|
this._buffer = this._buffer.subarray(0, len);
|
|
325
|
-
if (this.flag.isSynchronous() && this.fs.metadata.synchronous) {
|
|
325
|
+
if (this.flag.isSynchronous() && this.fs.metadata().synchronous) {
|
|
326
326
|
this.syncSync();
|
|
327
327
|
}
|
|
328
328
|
}
|
|
@@ -441,7 +441,7 @@ export class PreloadFile extends File {
|
|
|
441
441
|
* @param mode
|
|
442
442
|
*/
|
|
443
443
|
chmodSync(mode) {
|
|
444
|
-
if (!this.fs.metadata.supportsProperties) {
|
|
444
|
+
if (!this.fs.metadata().supportsProperties) {
|
|
445
445
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
446
446
|
}
|
|
447
447
|
this._dirty = true;
|
|
@@ -462,7 +462,7 @@ export class PreloadFile extends File {
|
|
|
462
462
|
* @param gid
|
|
463
463
|
*/
|
|
464
464
|
chownSync(uid, gid) {
|
|
465
|
-
if (!this.fs.metadata.supportsProperties) {
|
|
465
|
+
if (!this.fs.metadata().supportsProperties) {
|
|
466
466
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
467
467
|
}
|
|
468
468
|
this._dirty = true;
|
|
@@ -473,7 +473,7 @@ export class PreloadFile extends File {
|
|
|
473
473
|
this.utimesSync(atime, mtime);
|
|
474
474
|
}
|
|
475
475
|
utimesSync(atime, mtime) {
|
|
476
|
-
if (!this.fs.metadata.supportsProperties) {
|
|
476
|
+
if (!this.fs.metadata().supportsProperties) {
|
|
477
477
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
478
478
|
}
|
|
479
479
|
this._dirty = true;
|
package/dist/filesystem.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface FileSystemMetadata {
|
|
|
46
46
|
* - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values.
|
|
47
47
|
*/
|
|
48
48
|
export declare abstract class FileSystem {
|
|
49
|
-
|
|
49
|
+
metadata(): FileSystemMetadata;
|
|
50
50
|
constructor(options?: object);
|
|
51
51
|
abstract ready(): Promise<this>;
|
|
52
52
|
/**
|
|
@@ -154,15 +154,11 @@ export declare abstract class FileSystem {
|
|
|
154
154
|
abstract syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
155
155
|
}
|
|
156
156
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* @example ```ts
|
|
160
|
-
* class SyncFS extends Sync(FileSystem) {}
|
|
161
|
-
* ```
|
|
157
|
+
* @internal
|
|
162
158
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
ready(): Promise<
|
|
159
|
+
declare abstract class SyncFileSystem extends FileSystem {
|
|
160
|
+
metadata(): FileSystemMetadata;
|
|
161
|
+
ready(): Promise<this>;
|
|
166
162
|
exists(path: string, cred: Cred): Promise<boolean>;
|
|
167
163
|
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
|
|
168
164
|
stat(path: string, cred: Cred): Promise<Stats>;
|
|
@@ -174,58 +170,16 @@ export declare function Sync<T extends abstract new (...args: any[]) => FileSyst
|
|
|
174
170
|
readdir(path: string, cred: Cred): Promise<string[]>;
|
|
175
171
|
link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
|
|
176
172
|
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
* @param p The path to open.
|
|
188
|
-
* @param flag The flag to use when opening the file.
|
|
189
|
-
* @return A File object corresponding to the opened file.
|
|
190
|
-
*/
|
|
191
|
-
openFileSync(path: string, flag: FileFlag, cred: Cred): File;
|
|
192
|
-
/**
|
|
193
|
-
* Create the file at path p with the given mode. Then, open it with the given
|
|
194
|
-
* flag.
|
|
195
|
-
*/
|
|
196
|
-
createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
|
|
197
|
-
/**
|
|
198
|
-
* Synchronous `unlink`.
|
|
199
|
-
*/
|
|
200
|
-
unlinkSync(path: string, cred: Cred): void;
|
|
201
|
-
/**
|
|
202
|
-
* Synchronous `rmdir`.
|
|
203
|
-
*/
|
|
204
|
-
rmdirSync(path: string, cred: Cred): void;
|
|
205
|
-
/**
|
|
206
|
-
* Synchronous `mkdir`.
|
|
207
|
-
* @param mode Mode to make the directory using. Can be ignored if
|
|
208
|
-
* the filesystem doesn't support permissions.
|
|
209
|
-
*/
|
|
210
|
-
mkdirSync(path: string, mode: number, cred: Cred): void;
|
|
211
|
-
/**
|
|
212
|
-
* Synchronous `readdir`. Reads the contents of a directory.
|
|
213
|
-
*/
|
|
214
|
-
readdirSync(path: string, cred: Cred): string[];
|
|
215
|
-
/**
|
|
216
|
-
* Test whether or not the given path exists by checking with the file system.
|
|
217
|
-
*/
|
|
218
|
-
existsSync(path: string, cred: Cred): boolean;
|
|
219
|
-
/**
|
|
220
|
-
* Synchronous `link`.
|
|
221
|
-
*/
|
|
222
|
-
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
223
|
-
/**
|
|
224
|
-
* Synchronize the data and stats for path synchronously
|
|
225
|
-
*/
|
|
226
|
-
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
227
|
-
}) & T;
|
|
228
|
-
export declare function Async<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => {
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Implements the asynchronous API in terms of the synchronous API.
|
|
176
|
+
*/
|
|
177
|
+
export declare function Sync<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => SyncFileSystem) & T;
|
|
178
|
+
/**
|
|
179
|
+
* @internal
|
|
180
|
+
*/
|
|
181
|
+
declare abstract class AsyncFileSystem {
|
|
182
|
+
metadata(): FileSystemMetadata;
|
|
229
183
|
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
230
184
|
statSync(path: string, cred: Cred): Stats;
|
|
231
185
|
createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
|
|
@@ -236,67 +190,13 @@ export declare function Async<T extends abstract new (...args: any[]) => FileSys
|
|
|
236
190
|
readdirSync(path: string, cred: Cred): string[];
|
|
237
191
|
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
238
192
|
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Asynchronous `stat`.
|
|
248
|
-
*/
|
|
249
|
-
stat(path: string, cred: Cred): Promise<Stats>;
|
|
250
|
-
/**
|
|
251
|
-
* Opens the file at path p with the given flag. The file must exist.
|
|
252
|
-
* @param p The path to open.
|
|
253
|
-
* @param flag The flag to use when opening the file.
|
|
254
|
-
*/
|
|
255
|
-
openFile(path: string, flag: FileFlag, cred: Cred): Promise<File>;
|
|
256
|
-
/**
|
|
257
|
-
* Create the file at path p with the given mode. Then, open it with the given
|
|
258
|
-
* flag.
|
|
259
|
-
*/
|
|
260
|
-
createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
|
|
261
|
-
/**
|
|
262
|
-
* Asynchronous `unlink`.
|
|
263
|
-
*/
|
|
264
|
-
unlink(path: string, cred: Cred): Promise<void>;
|
|
265
|
-
/**
|
|
266
|
-
* Asynchronous `rmdir`.
|
|
267
|
-
*/
|
|
268
|
-
rmdir(path: string, cred: Cred): Promise<void>;
|
|
269
|
-
/**
|
|
270
|
-
* Asynchronous `mkdir`.
|
|
271
|
-
* @param mode Mode to make the directory using. Can be ignored if
|
|
272
|
-
* the filesystem doesn't support permissions.
|
|
273
|
-
*/
|
|
274
|
-
mkdir(path: string, mode: number, cred: Cred): Promise<void>;
|
|
275
|
-
/**
|
|
276
|
-
* Asynchronous `readdir`. Reads the contents of a directory.
|
|
277
|
-
*
|
|
278
|
-
* The callback gets two arguments `(err, files)` where `files` is an array of
|
|
279
|
-
* the names of the files in the directory excluding `'.'` and `'..'`.
|
|
280
|
-
*/
|
|
281
|
-
readdir(path: string, cred: Cred): Promise<string[]>;
|
|
282
|
-
/**
|
|
283
|
-
* Test whether or not the given path exists by checking with the file system.
|
|
284
|
-
*/
|
|
285
|
-
exists(path: string, cred: Cred): Promise<boolean>;
|
|
286
|
-
/**
|
|
287
|
-
* Test whether or not the given path exists by checking with the file system.
|
|
288
|
-
*/
|
|
289
|
-
existsSync(path: string, cred: Cred): boolean;
|
|
290
|
-
/**
|
|
291
|
-
* Asynchronous `link`.
|
|
292
|
-
*/
|
|
293
|
-
link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
|
|
294
|
-
/**
|
|
295
|
-
* Synchronize the data and stats for path asynchronously
|
|
296
|
-
*/
|
|
297
|
-
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
298
|
-
}) & T;
|
|
299
|
-
export declare function Readonly<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => {
|
|
193
|
+
}
|
|
194
|
+
export declare function Async<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => AsyncFileSystem) & T;
|
|
195
|
+
/**
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
declare abstract class ReadonlyFileSystem {
|
|
199
|
+
metadata(): FileSystemMetadata;
|
|
300
200
|
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
|
|
301
201
|
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
302
202
|
createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
|
|
@@ -311,46 +211,6 @@ export declare function Readonly<T extends abstract new (...args: any[]) => File
|
|
|
311
211
|
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
312
212
|
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
313
213
|
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
* Asynchronous `stat`.
|
|
318
|
-
*/
|
|
319
|
-
stat(path: string, cred: Cred): Promise<Stats>;
|
|
320
|
-
/**
|
|
321
|
-
* Synchronous `stat`.
|
|
322
|
-
*/
|
|
323
|
-
statSync(path: string, cred: Cred): Stats;
|
|
324
|
-
/**
|
|
325
|
-
* Opens the file at path p with the given flag. The file must exist.
|
|
326
|
-
* @param p The path to open.
|
|
327
|
-
* @param flag The flag to use when opening the file.
|
|
328
|
-
*/
|
|
329
|
-
openFile(path: string, flag: FileFlag, cred: Cred): Promise<File>;
|
|
330
|
-
/**
|
|
331
|
-
* Opens the file at path p with the given flag. The file must exist.
|
|
332
|
-
* @param p The path to open.
|
|
333
|
-
* @param flag The flag to use when opening the file.
|
|
334
|
-
* @return A File object corresponding to the opened file.
|
|
335
|
-
*/
|
|
336
|
-
openFileSync(path: string, flag: FileFlag, cred: Cred): File;
|
|
337
|
-
/**
|
|
338
|
-
* Asynchronous `readdir`. Reads the contents of a directory.
|
|
339
|
-
*
|
|
340
|
-
* The callback gets two arguments `(err, files)` where `files` is an array of
|
|
341
|
-
* the names of the files in the directory excluding `'.'` and `'..'`.
|
|
342
|
-
*/
|
|
343
|
-
readdir(path: string, cred: Cred): Promise<string[]>;
|
|
344
|
-
/**
|
|
345
|
-
* Synchronous `readdir`. Reads the contents of a directory.
|
|
346
|
-
*/
|
|
347
|
-
readdirSync(path: string, cred: Cred): string[];
|
|
348
|
-
/**
|
|
349
|
-
* Test whether or not the given path exists by checking with the file system.
|
|
350
|
-
*/
|
|
351
|
-
exists(path: string, cred: Cred): Promise<boolean>;
|
|
352
|
-
/**
|
|
353
|
-
* Test whether or not the given path exists by checking with the file system.
|
|
354
|
-
*/
|
|
355
|
-
existsSync(path: string, cred: Cred): boolean;
|
|
356
|
-
}) & T;
|
|
214
|
+
}
|
|
215
|
+
export declare function Readonly<T extends abstract new (...args: any[]) => FileSystem>(FS: T): (abstract new (...args: any[]) => ReadonlyFileSystem) & T;
|
|
216
|
+
export {};
|
package/dist/filesystem.js
CHANGED
|
@@ -10,7 +10,7 @@ import { ApiError, ErrorCode } from './ApiError.js';
|
|
|
10
10
|
* - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values.
|
|
11
11
|
*/
|
|
12
12
|
export class FileSystem {
|
|
13
|
-
|
|
13
|
+
metadata() {
|
|
14
14
|
return {
|
|
15
15
|
name: this.constructor.name,
|
|
16
16
|
readonly: false,
|
|
@@ -51,18 +51,14 @@ export class FileSystem {
|
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* Implements the asynchronous API in terms of the synchronous API.
|
|
54
|
-
*
|
|
55
|
-
* @example ```ts
|
|
56
|
-
* class SyncFS extends Sync(FileSystem) {}
|
|
57
|
-
* ```
|
|
58
54
|
*/
|
|
59
55
|
export function Sync(FS) {
|
|
60
56
|
/**
|
|
61
57
|
* Implements the asynchronous API in terms of the synchronous API.
|
|
62
58
|
*/
|
|
63
|
-
class
|
|
64
|
-
|
|
65
|
-
return { ...super.metadata, synchronous: true };
|
|
59
|
+
class _SyncFileSystem extends FS {
|
|
60
|
+
metadata() {
|
|
61
|
+
return { ...super.metadata(), synchronous: true };
|
|
66
62
|
}
|
|
67
63
|
async ready() {
|
|
68
64
|
return this;
|
|
@@ -101,10 +97,13 @@ export function Sync(FS) {
|
|
|
101
97
|
return this.syncSync(path, data, stats);
|
|
102
98
|
}
|
|
103
99
|
}
|
|
104
|
-
return
|
|
100
|
+
return _SyncFileSystem;
|
|
105
101
|
}
|
|
106
102
|
export function Async(FS) {
|
|
107
|
-
class
|
|
103
|
+
class _AsyncFileSystem extends FS {
|
|
104
|
+
metadata() {
|
|
105
|
+
return { ...super.metadata(), synchronous: false };
|
|
106
|
+
}
|
|
108
107
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
109
108
|
renameSync(oldPath, newPath, cred) {
|
|
110
109
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
@@ -138,10 +137,13 @@ export function Async(FS) {
|
|
|
138
137
|
}
|
|
139
138
|
}
|
|
140
139
|
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
141
|
-
return
|
|
140
|
+
return _AsyncFileSystem;
|
|
142
141
|
}
|
|
143
142
|
export function Readonly(FS) {
|
|
144
|
-
class
|
|
143
|
+
class _ReadonlyFileSystem extends FS {
|
|
144
|
+
metadata() {
|
|
145
|
+
return { ...super.metadata(), readonly: true };
|
|
146
|
+
}
|
|
145
147
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
146
148
|
async rename(oldPath, newPath, cred) {
|
|
147
149
|
throw new ApiError(ErrorCode.EROFS);
|
|
@@ -186,5 +188,5 @@ export function Readonly(FS) {
|
|
|
186
188
|
throw new ApiError(ErrorCode.EROFS);
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
|
-
return
|
|
191
|
+
return _ReadonlyFileSystem;
|
|
190
192
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -4,14 +4,16 @@ ZenFS is an in-browser file system that emulates the [Node JS file system API](h
|
|
|
4
4
|
|
|
5
5
|
## Backends
|
|
6
6
|
|
|
7
|
-
ZenFS is highly extensible, and includes
|
|
7
|
+
ZenFS is highly extensible, and includes a few built-in backends:
|
|
8
8
|
|
|
9
9
|
- `InMemory`: Stores files in-memory. It is a temporary file store that clears when the user navigates away.
|
|
10
10
|
- `Overlay`: Mount a read-only file system as read-write by overlaying a writable file system on top of it. Like Docker's overlayfs, it will only write changed files to the writable file system.
|
|
11
11
|
- `AsyncMirror`: Use an asynchronous backend synchronously. Invaluable for Emscripten; let your Emscripten applications write to larger file stores with no additional effort!
|
|
12
|
-
- `AsyncMirror` loads the entire contents of the async file system into a synchronous backend during construction. It performs operations synchronous file system and then queues them to be mirrored onto the asynchronous backend.
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
> [!NOTE]
|
|
14
|
+
> When constructed, `AsyncMirror` loads the entire contents of the async file system into a synchronous backend. It performs operations on the synchronous file system and then queues them to be mirrored onto the asynchronous backend.
|
|
15
|
+
|
|
16
|
+
More backends can be defined by separate libraries, as long as they implement `FileSystem`.
|
|
15
17
|
|
|
16
18
|
ZenFS supports a number of other backends (many are provided as seperate packages under `@zenfs`).
|
|
17
19
|
|
|
@@ -25,7 +27,8 @@ npm install @zenfs/core
|
|
|
25
27
|
|
|
26
28
|
## Usage
|
|
27
29
|
|
|
28
|
-
>
|
|
30
|
+
> [!NOTE]
|
|
31
|
+
> The examples are written in ESM. If you are using CJS, you can `require` the package. If running in a browser you can add a script tag to your HTML pointing to the `browser.min.js` and use ZenFS via the global `ZenFS` object.
|
|
29
32
|
|
|
30
33
|
```js
|
|
31
34
|
import fs from '@zenfs/core';
|
|
@@ -36,27 +39,15 @@ const contents = fs.readFileSync('/test.txt', 'utf-8');
|
|
|
36
39
|
console.log(contents);
|
|
37
40
|
```
|
|
38
41
|
|
|
39
|
-
#### Using different backends
|
|
42
|
+
#### Using different and/or different backends
|
|
40
43
|
|
|
41
|
-
A `InMemory` backend is created by default
|
|
44
|
+
A single `InMemory` backend is created by default, mounted on `/`.
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
import { configure, fs } from '@zenfs/core';
|
|
45
|
-
import { StorageStore } from '@zenfs/dom';
|
|
46
|
+
You can configure ZenFS to use a different backend and mount multiple backends. It is strongly recommended to do so using the `configure` function.
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
You can use multiple backends by passing an object to `configure` which maps paths to file systems.
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
fs.writeFileSync('/test.txt', 'This will persist across reloads!');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const contents = fs.readFileSync('/test.txt', 'utf-8');
|
|
54
|
-
console.log(contents);
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
#### Using multiple backends
|
|
58
|
-
|
|
59
|
-
You can use multiple backends by passing an object to `configure` which maps paths to file systems. The following example mounts a zip file to `/zip`, in-memory storage to `/tmp`, and IndexedDB storage to `/home` (note that `/` has the default in-memory backend):
|
|
50
|
+
The following example mounts a zip file to `/zip`, in-memory storage to `/tmp`, and IndexedDB to `/home`. Note that `/` has the default in-memory backend.
|
|
60
51
|
|
|
61
52
|
```js
|
|
62
53
|
import { configure } from '@zenfs/core';
|
|
@@ -66,16 +57,32 @@ import { Zip } from '@zenfs/zip';
|
|
|
66
57
|
const zipData = await (await fetch('mydata.zip')).arrayBuffer();
|
|
67
58
|
|
|
68
59
|
await configure({
|
|
69
|
-
'/mnt/zip': {
|
|
70
|
-
backend: Zip,
|
|
71
|
-
zipData: zipData,
|
|
72
|
-
},
|
|
60
|
+
'/mnt/zip': { backend: Zip, zipData },
|
|
73
61
|
'/tmp': 'InMemory',
|
|
74
62
|
'/home': IndexedDB,
|
|
75
63
|
};
|
|
76
64
|
```
|
|
77
65
|
|
|
78
|
-
|
|
66
|
+
> [!TIP]
|
|
67
|
+
> When configuring a mount point, you can pass in 1. A string that maps to a built-in backend 2. A `Backend` object, if the backend has no required options 3. An object that has a `backend` property which is a `Backend` or a string that maps to a built-in backend and the options accepted by the backend
|
|
68
|
+
|
|
69
|
+
Here is an example that mounts the `Storage` backend from `@zenfs/dom` on `/`:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { configure, fs } from '@zenfs/core';
|
|
73
|
+
import { Storage } from '@zenfs/dom';
|
|
74
|
+
|
|
75
|
+
await configure({ backend: Storage });
|
|
76
|
+
|
|
77
|
+
if (!fs.existsSync('/test.txt')) {
|
|
78
|
+
fs.writeFileSync('/test.txt', 'This will persist across reloads!');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const contents = fs.readFileSync('/test.txt', 'utf-8');
|
|
82
|
+
console.log(contents);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### FS Promises
|
|
79
86
|
|
|
80
87
|
The FS promises API is exposed as `promises`.
|
|
81
88
|
|
|
@@ -91,11 +98,15 @@ if (!exists) {
|
|
|
91
98
|
}
|
|
92
99
|
```
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
> [!NOTE]
|
|
102
|
+
> You can import the promises API using `promises`, or using `fs.promises` on the exported `fs`.
|
|
103
|
+
|
|
104
|
+
> [!IMPORTANT]
|
|
105
|
+
> ZenFS does _not_ provide a seperate public import for importing promises like `fs/promises`. If you are using ESM, you can import promises functions like `fs/promises` from the `dist/emulation/promises.ts` file, though this may change at any time and is **not recommended**.
|
|
95
106
|
|
|
96
107
|
#### Using asynchronous backends synchronously
|
|
97
108
|
|
|
98
|
-
You may have noticed that attempting to use a synchronous function on an asynchronous backend (e.g. IndexedDB) results in a "not supplied" error (`ENOTSUP`). If you
|
|
109
|
+
You may have noticed that attempting to use a synchronous function on an asynchronous backend (e.g. `IndexedDB`) results in a "not supplied" error (`ENOTSUP`). If you would like to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`:
|
|
99
110
|
|
|
100
111
|
```js
|
|
101
112
|
import { configure, fs } from '@zenfs/core';
|
|
@@ -109,55 +120,23 @@ await configure({
|
|
|
109
120
|
},
|
|
110
121
|
});
|
|
111
122
|
|
|
112
|
-
fs.writeFileSync('/persistant.txt', 'My persistant data');
|
|
123
|
+
fs.writeFileSync('/persistant.txt', 'My persistant data');
|
|
113
124
|
```
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
#### Mounting and unmounting, creating backends
|
|
116
127
|
|
|
117
|
-
|
|
128
|
+
If you would like to create backends without configure (e.g. to do something dynamic at runtime), you may do so by importing the backend and calling `createBackend` with it.
|
|
118
129
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
```js
|
|
122
|
-
import { configure, backends, InMemory } from '@zenfs/core';
|
|
123
|
-
|
|
124
|
-
console.log(backends.InMemory === InMemory); // they are the same
|
|
125
|
-
|
|
126
|
-
const internalInMemoryFS = await createBackend(InMemory);
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
> ⚠ Instances of backends follow the **_internal_** ZenFS API. You should never use a backend's methods unless you are extending a backend.
|
|
130
|
-
|
|
131
|
-
```js
|
|
132
|
-
import { configure, InMemory } from '@zenfs/core';
|
|
133
|
-
|
|
134
|
-
const internalInMemoryFS = new InMemory();
|
|
135
|
-
await internalInMemoryFS.ready();
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
#### Mounting
|
|
139
|
-
|
|
140
|
-
If you would like to mount and unmount backends, you can do so using the `mount` and `umount` functions:
|
|
141
|
-
|
|
142
|
-
```js
|
|
143
|
-
import { fs, InMemory } from '@zenfs/core';
|
|
144
|
-
|
|
145
|
-
const internalInMemoryFS = await createBackend(InMemory); // create an FS instance
|
|
146
|
-
|
|
147
|
-
fs.mount('/tmp', internalInMemoryFS); // mount
|
|
148
|
-
|
|
149
|
-
fs.umount('/tmp'); // unmount /tmp
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
This could be used in the "multiple backends" example like so:
|
|
130
|
+
You can then mount and unmount the backend instance by using `mount` and `umount`.
|
|
153
131
|
|
|
154
132
|
```js
|
|
133
|
+
import { configure, createBackend } from '@zenfs/core';
|
|
155
134
|
import { IndexedDB } from '@zenfs/dom';
|
|
156
135
|
import { Zip } from '@zenfs/zip';
|
|
157
136
|
|
|
158
137
|
await configure({
|
|
159
138
|
'/tmp': 'InMemory',
|
|
160
|
-
'/home':
|
|
139
|
+
'/home': IndexedDB,
|
|
161
140
|
};
|
|
162
141
|
|
|
163
142
|
fs.mkdirSync('/mnt');
|
|
@@ -171,6 +150,9 @@ fs.mount('/mnt/zip', zipFs);
|
|
|
171
150
|
fs.umount('/mnt/zip'); // finished using the zip
|
|
172
151
|
```
|
|
173
152
|
|
|
153
|
+
> [!WARNING]
|
|
154
|
+
> Instances of backends follow the **internal** ZenFS API. You should never use a backend's methods unless you are extending a backend.
|
|
155
|
+
|
|
174
156
|
## Using with bundlers
|
|
175
157
|
|
|
176
158
|
ZenFS exports a drop-in for Node's `fs` module (up to the version of `@types/node` in package.json), so you can use it for your bundler of preference using the default export.
|
|
@@ -185,7 +167,3 @@ ZenFS exports a drop-in for Node's `fs` module (up to the version of `@types/nod
|
|
|
185
167
|
### Testing
|
|
186
168
|
|
|
187
169
|
Run unit tests with `npm test`.
|
|
188
|
-
|
|
189
|
-
### License
|
|
190
|
-
|
|
191
|
-
ZenFS is licensed under the MIT License.
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { BaseFileSystem, type FileSystem } from '../filesystem.js';
|
|
2
|
-
import { type BackendOptions } from './backend.js';
|
|
3
|
-
export declare namespace FolderAdapter {
|
|
4
|
-
/**
|
|
5
|
-
* Configuration options for a FolderAdapter file system.
|
|
6
|
-
*/
|
|
7
|
-
interface Options {
|
|
8
|
-
folder: string;
|
|
9
|
-
wrapped: FileSystem;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* The FolderAdapter file system wraps a file system, and scopes all interactions to a subfolder of that file system.
|
|
14
|
-
*
|
|
15
|
-
* Example: Given a file system `foo` with folder `bar` and file `bar/baz`...
|
|
16
|
-
*
|
|
17
|
-
* ```javascript
|
|
18
|
-
* ZenFS.configure({
|
|
19
|
-
* fs: "FolderAdapter",
|
|
20
|
-
* options: {
|
|
21
|
-
* folder: "bar",
|
|
22
|
-
* wrapped: foo
|
|
23
|
-
* }
|
|
24
|
-
* }, function(e) {
|
|
25
|
-
* var fs = ZenFS.BFSRequire('fs');
|
|
26
|
-
* fs.readdirSync('/'); // ['baz']
|
|
27
|
-
* });
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
export declare class FolderAdapter extends BaseFileSystem {
|
|
31
|
-
static readonly Name = "FolderAdapter";
|
|
32
|
-
static Create: any;
|
|
33
|
-
static readonly Options: BackendOptions;
|
|
34
|
-
static isAvailable(): boolean;
|
|
35
|
-
_wrapped: FileSystem;
|
|
36
|
-
_folder: string;
|
|
37
|
-
constructor({ folder, wrapped }: FolderAdapter.Options);
|
|
38
|
-
get metadata(): {
|
|
39
|
-
supportsLinks: boolean;
|
|
40
|
-
name: string;
|
|
41
|
-
readonly: boolean;
|
|
42
|
-
synchronous: boolean;
|
|
43
|
-
supportsProperties: boolean;
|
|
44
|
-
totalSpace: number;
|
|
45
|
-
freeSpace: number;
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Initialize the file system. Ensures that the wrapped file system
|
|
49
|
-
* has the given folder.
|
|
50
|
-
*/
|
|
51
|
-
private _initialize;
|
|
52
|
-
}
|