@zenfs/core 0.2.1 → 0.2.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/backends/AsyncStore.d.ts +4 -3
- package/dist/backends/AsyncStore.js +6 -0
- package/dist/backends/InMemory.d.ts +3 -9
- package/dist/backends/InMemory.js +4 -17
- package/dist/backends/Overlay.d.ts +110 -0
- package/dist/backends/Overlay.js +544 -0
- package/dist/backends/SyncStore.js +1 -5
- package/dist/backends/backend.d.ts +1 -2
- package/dist/backends/backend.js +4 -1
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.js +1 -1
- package/dist/browser.min.js +5 -5
- package/dist/browser.min.js.map +4 -4
- package/dist/emulation/index.d.ts +1 -1
- package/dist/emulation/index.js +1 -1
- package/dist/emulation/shared.d.ts +26 -8
- package/dist/emulation/shared.js +26 -12
- package/dist/filesystem.d.ts +18 -0
- package/dist/filesystem.js +46 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +2 -3
- package/dist/utils.d.ts +0 -3
- package/package.json +1 -1
- package/readme.md +40 -108
|
@@ -4,5 +4,5 @@ export * as promises from './promises.js';
|
|
|
4
4
|
export * as constants from './constants.js';
|
|
5
5
|
export * from './streams.js';
|
|
6
6
|
export * from './dir.js';
|
|
7
|
-
export { initialize,
|
|
7
|
+
export { initialize, mounts, mount, umount, _toUnixTimestamp } from './shared.js';
|
|
8
8
|
export { Stats, BigIntStats } from '../stats.js';
|
package/dist/emulation/index.js
CHANGED
|
@@ -4,5 +4,5 @@ export * as promises from './promises.js';
|
|
|
4
4
|
export * as constants from './constants.js';
|
|
5
5
|
export * from './streams.js';
|
|
6
6
|
export * from './dir.js';
|
|
7
|
-
export { initialize,
|
|
7
|
+
export { initialize, mounts, mount, umount, _toUnixTimestamp } from './shared.js';
|
|
8
8
|
export { Stats, BigIntStats } from '../stats.js';
|
|
@@ -5,16 +5,38 @@ import type { File } from '../file.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* converts Date or number to a integer UNIX timestamp
|
|
7
7
|
* Grabbed from NodeJS sources (lib/fs.js)
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
8
10
|
*/
|
|
9
11
|
export declare function _toUnixTimestamp(time: Date | number): number;
|
|
12
|
+
/**
|
|
13
|
+
* Normalizes a mode
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
10
16
|
export declare function normalizeMode(mode: string | number | unknown, def?: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes a time
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
11
21
|
export declare function normalizeTime(time: string | number | Date): Date;
|
|
22
|
+
/**
|
|
23
|
+
* Normalizes a path
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
12
26
|
export declare function normalizePath(p: string): string;
|
|
13
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Normalizes options
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export declare function normalizeOptions(options: unknown, defEnc: string | null, defFlag: string, defMode: number | null): {
|
|
14
32
|
encoding: BufferEncoding;
|
|
15
33
|
flag: string;
|
|
16
34
|
mode: number;
|
|
17
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Do nothing
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
18
40
|
export declare function nop(): void;
|
|
19
41
|
export declare let cred: Cred;
|
|
20
42
|
export declare function setCred(val: Cred): void;
|
|
@@ -24,15 +46,11 @@ export declare function fd2file(fd: number): File;
|
|
|
24
46
|
export interface MountMapping {
|
|
25
47
|
[point: string]: FileSystem;
|
|
26
48
|
}
|
|
27
|
-
export declare const mounts: Map<string, FileSystem>;
|
|
28
|
-
/**
|
|
29
|
-
* Gets the file system mounted at `mountPoint`
|
|
30
|
-
*/
|
|
31
|
-
export declare function getMount(mountPoint: string): FileSystem;
|
|
32
49
|
/**
|
|
33
|
-
*
|
|
50
|
+
* The map of mount points
|
|
51
|
+
* @internal
|
|
34
52
|
*/
|
|
35
|
-
export declare
|
|
53
|
+
export declare const mounts: Map<string, FileSystem>;
|
|
36
54
|
/**
|
|
37
55
|
* Mounts the file system at the given mount point.
|
|
38
56
|
*/
|
package/dist/emulation/shared.js
CHANGED
|
@@ -6,6 +6,8 @@ import { InMemory } from '../backends/InMemory.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* converts Date or number to a integer UNIX timestamp
|
|
8
8
|
* Grabbed from NodeJS sources (lib/fs.js)
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
9
11
|
*/
|
|
10
12
|
export function _toUnixTimestamp(time) {
|
|
11
13
|
if (typeof time === 'number') {
|
|
@@ -16,6 +18,10 @@ export function _toUnixTimestamp(time) {
|
|
|
16
18
|
}
|
|
17
19
|
throw new Error('Cannot parse time: ' + time);
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Normalizes a mode
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
19
25
|
export function normalizeMode(mode, def) {
|
|
20
26
|
switch (typeof mode) {
|
|
21
27
|
case 'number':
|
|
@@ -33,6 +39,10 @@ export function normalizeMode(mode, def) {
|
|
|
33
39
|
}
|
|
34
40
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid mode: ' + mode?.toString());
|
|
35
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Normalizes a time
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
36
46
|
export function normalizeTime(time) {
|
|
37
47
|
if (time instanceof Date) {
|
|
38
48
|
return time;
|
|
@@ -45,6 +55,10 @@ export function normalizeTime(time) {
|
|
|
45
55
|
}
|
|
46
56
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid time.');
|
|
47
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalizes a path
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
48
62
|
export function normalizePath(p) {
|
|
49
63
|
// Node doesn't allow null characters in paths.
|
|
50
64
|
if (p.indexOf('\u0000') >= 0) {
|
|
@@ -56,6 +70,10 @@ export function normalizePath(p) {
|
|
|
56
70
|
p = p.replaceAll(/\/+/g, '/');
|
|
57
71
|
return resolve(p);
|
|
58
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Normalizes options
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
59
77
|
export function normalizeOptions(options, defEnc, defFlag, defMode) {
|
|
60
78
|
// typeof null === 'object' so special-case handing is needed.
|
|
61
79
|
switch (options === null ? 'null' : typeof options) {
|
|
@@ -83,6 +101,10 @@ export function normalizeOptions(options, defEnc, defFlag, defMode) {
|
|
|
83
101
|
throw new TypeError(`"options" must be a string or an object, got ${typeof options} instead.`);
|
|
84
102
|
}
|
|
85
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Do nothing
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
86
108
|
export function nop() {
|
|
87
109
|
// do nothing
|
|
88
110
|
}
|
|
@@ -105,23 +127,15 @@ export function fd2file(fd) {
|
|
|
105
127
|
}
|
|
106
128
|
return fdMap.get(fd);
|
|
107
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* The map of mount points
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
108
134
|
export const mounts = new Map();
|
|
109
135
|
/*
|
|
110
136
|
Set a default root.
|
|
111
137
|
*/
|
|
112
138
|
mount('/', InMemory.create({ name: 'root' }));
|
|
113
|
-
/**
|
|
114
|
-
* Gets the file system mounted at `mountPoint`
|
|
115
|
-
*/
|
|
116
|
-
export function getMount(mountPoint) {
|
|
117
|
-
return mounts.get(mountPoint);
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Gets an object of mount points (keys) and filesystems (values)
|
|
121
|
-
*/
|
|
122
|
-
export function getMounts() {
|
|
123
|
-
return Object.fromEntries(mounts.entries());
|
|
124
|
-
}
|
|
125
139
|
/**
|
|
126
140
|
* Mounts the file system at the given mount point.
|
|
127
141
|
*/
|
package/dist/filesystem.d.ts
CHANGED
|
@@ -171,6 +171,15 @@ export declare abstract class SyncFileSystem extends FileSystem {
|
|
|
171
171
|
link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
|
|
172
172
|
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
173
173
|
}
|
|
174
|
+
export declare abstract class ReadonlySyncFileSystem extends SyncFileSystem {
|
|
175
|
+
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
176
|
+
createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
|
|
177
|
+
unlinkSync(path: string, cred: Cred): void;
|
|
178
|
+
rmdirSync(path: string, cred: Cred): void;
|
|
179
|
+
mkdirSync(path: string, mode: number, cred: Cred): void;
|
|
180
|
+
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
181
|
+
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
182
|
+
}
|
|
174
183
|
export declare abstract class AsyncFileSystem extends FileSystem {
|
|
175
184
|
renameSync(oldPath: string, newPath: string, cred: Cred): void;
|
|
176
185
|
statSync(path: string, cred: Cred): Stats;
|
|
@@ -184,3 +193,12 @@ export declare abstract class AsyncFileSystem extends FileSystem {
|
|
|
184
193
|
linkSync(srcpath: string, dstpath: string, cred: Cred): void;
|
|
185
194
|
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
186
195
|
}
|
|
196
|
+
export declare abstract class ReadonlyAsyncFileSystem extends AsyncFileSystem {
|
|
197
|
+
rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
|
|
198
|
+
createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
|
|
199
|
+
unlink(path: string, cred: Cred): Promise<void>;
|
|
200
|
+
rmdir(path: string, cred: Cred): Promise<void>;
|
|
201
|
+
mkdir(path: string, mode: number, cred: Cred): Promise<void>;
|
|
202
|
+
link(srcpath: string, dstpath: string, cred: Cred): Promise<void>;
|
|
203
|
+
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
204
|
+
}
|
package/dist/filesystem.js
CHANGED
|
@@ -94,6 +94,29 @@ export class SyncFileSystem extends FileSystem {
|
|
|
94
94
|
return this.syncSync(path, data, stats);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
+
export class ReadonlySyncFileSystem extends SyncFileSystem {
|
|
98
|
+
renameSync(oldPath, newPath, cred) {
|
|
99
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
100
|
+
}
|
|
101
|
+
createFileSync(path, flag, mode, cred) {
|
|
102
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
103
|
+
}
|
|
104
|
+
unlinkSync(path, cred) {
|
|
105
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
106
|
+
}
|
|
107
|
+
rmdirSync(path, cred) {
|
|
108
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
109
|
+
}
|
|
110
|
+
mkdirSync(path, mode, cred) {
|
|
111
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
112
|
+
}
|
|
113
|
+
linkSync(srcpath, dstpath, cred) {
|
|
114
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
115
|
+
}
|
|
116
|
+
syncSync(path, data, stats) {
|
|
117
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
97
120
|
export class AsyncFileSystem extends FileSystem {
|
|
98
121
|
renameSync(oldPath, newPath, cred) {
|
|
99
122
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
@@ -129,3 +152,26 @@ export class AsyncFileSystem extends FileSystem {
|
|
|
129
152
|
throw new ApiError(ErrorCode.ENOTSUP);
|
|
130
153
|
}
|
|
131
154
|
}
|
|
155
|
+
export class ReadonlyAsyncFileSystem extends AsyncFileSystem {
|
|
156
|
+
async rename(oldPath, newPath, cred) {
|
|
157
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
158
|
+
}
|
|
159
|
+
async createFile(path, flag, mode, cred) {
|
|
160
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
161
|
+
}
|
|
162
|
+
async unlink(path, cred) {
|
|
163
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
164
|
+
}
|
|
165
|
+
async rmdir(path, cred) {
|
|
166
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
167
|
+
}
|
|
168
|
+
async mkdir(path, mode, cred) {
|
|
169
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
170
|
+
}
|
|
171
|
+
async link(srcpath, dstpath, cred) {
|
|
172
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
173
|
+
}
|
|
174
|
+
async sync(path, data, stats) {
|
|
175
|
+
throw new ApiError(ErrorCode.EROFS);
|
|
176
|
+
}
|
|
177
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,6 @@ export * from './backends/AsyncStore.js';
|
|
|
31
31
|
export * from './backends/SyncStore.js';
|
|
32
32
|
export * from './ApiError.js';
|
|
33
33
|
export * from './cred.js';
|
|
34
|
-
export * from './FileIndex.js';
|
|
35
34
|
export * from './file.js';
|
|
36
35
|
export * from './filesystem.js';
|
|
37
36
|
export * from './inode.js';
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { setCred } from './emulation/shared.js';
|
|
|
12
12
|
*/
|
|
13
13
|
export function initialize(mounts, uid = 0, gid = 0) {
|
|
14
14
|
setCred(new Cred(uid, gid, uid, gid, uid, gid));
|
|
15
|
-
|
|
15
|
+
fs.initialize(mounts);
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Creates filesystems with the given configuration, and initializes ZenFS with it.
|
|
@@ -39,14 +39,13 @@ export async function configure(config) {
|
|
|
39
39
|
}
|
|
40
40
|
config[point] = await resolveBackendConfig(value);
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
initialize(config);
|
|
43
43
|
}
|
|
44
44
|
export * from './backends/index.js';
|
|
45
45
|
export * from './backends/AsyncStore.js';
|
|
46
46
|
export * from './backends/SyncStore.js';
|
|
47
47
|
export * from './ApiError.js';
|
|
48
48
|
export * from './cred.js';
|
|
49
|
-
export * from './FileIndex.js';
|
|
50
49
|
export * from './file.js';
|
|
51
50
|
export * from './filesystem.js';
|
|
52
51
|
export * from './inode.js';
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
|
-
/**
|
|
4
|
-
* Grab bag of utility functions used across the code.
|
|
5
|
-
*/
|
|
6
3
|
import { FileSystem } from './filesystem.js';
|
|
7
4
|
import { Cred } from './cred.js';
|
|
8
5
|
import type { TextDecoder as _TextDecoder, TextEncoder as _TextEncoder } from 'node:util';
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -7,14 +7,13 @@ ZenFS is an in-browser file system that emulates the [Node JS file system API](h
|
|
|
7
7
|
ZenFS is highly extensible, and includes many builtin filesystem 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
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
|
-
- `FolderAdapter`: Wraps a file system, and scopes all interactions to a subfolder of that file system.
|
|
14
13
|
|
|
15
14
|
More backends can be defined by separate libraries, so long as they extend they implement `ZenFS.FileSystem`. Multiple backends can be active at once at different locations in the directory hierarchy.
|
|
16
15
|
|
|
17
|
-
ZenFS supports a number of other backends (as `@zenfs
|
|
16
|
+
ZenFS supports a number of other backends (many are provided as seperate packages under `@zenfs`).
|
|
18
17
|
|
|
19
18
|
For more information, see the [API documentation for ZenFS](https://zen-fs.github.io/core).
|
|
20
19
|
|
|
@@ -24,13 +23,6 @@ For more information, see the [API documentation for ZenFS](https://zen-fs.githu
|
|
|
24
23
|
npm install @zenfs/core
|
|
25
24
|
```
|
|
26
25
|
|
|
27
|
-
## Building
|
|
28
|
-
|
|
29
|
-
- Make sure you have Node and NPM installed. You must have Node v18 or newer.
|
|
30
|
-
- Install dependencies with `npm install`
|
|
31
|
-
- Build using `npm run build`
|
|
32
|
-
- You can find the built code in `dist`.
|
|
33
|
-
|
|
34
26
|
## Usage
|
|
35
27
|
|
|
36
28
|
> 🛈 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.
|
|
@@ -46,15 +38,13 @@ console.log(contents);
|
|
|
46
38
|
|
|
47
39
|
#### Using different backends
|
|
48
40
|
|
|
49
|
-
A `InMemory` backend is created by default. If you would like to use a different one, you must configure ZenFS. It is recommended to do so using the `configure` function. Here is an example using the `Storage` backend from `@zenfs/
|
|
41
|
+
A `InMemory` backend is created by default. If you would like to use a different one, you must configure ZenFS. It is recommended to do so using the `configure` function. Here is an example using the `Storage` backend from `@zenfs/dom`:
|
|
50
42
|
|
|
51
43
|
```js
|
|
52
|
-
import { configure, fs
|
|
53
|
-
import {
|
|
54
|
-
registerBackend(StorageFileSystem);
|
|
44
|
+
import { configure, fs } from '@zenfs/core';
|
|
45
|
+
import { StorageStore } from '@zenfs/dom';
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
await configure({ fs: 'Storage' });
|
|
47
|
+
await configure({ backend: StorageStore });
|
|
58
48
|
|
|
59
49
|
if (!fs.existsSync('/test.txt')) {
|
|
60
50
|
fs.writeFileSync('/test.txt', 'This will persist across reloads!');
|
|
@@ -69,23 +59,19 @@ console.log(contents);
|
|
|
69
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):
|
|
70
60
|
|
|
71
61
|
```js
|
|
72
|
-
import { configure
|
|
73
|
-
import {
|
|
74
|
-
import {
|
|
75
|
-
import Buffer from 'buffer';
|
|
76
|
-
registerBackend(IndexedDBFileSystem, ZipFS);
|
|
62
|
+
import { configure } from '@zenfs/core';
|
|
63
|
+
import { IndexedDB } from '@zenfs/dom';
|
|
64
|
+
import { Zip } from '@zenfs/zip';
|
|
77
65
|
|
|
78
66
|
const zipData = await (await fetch('mydata.zip')).arrayBuffer();
|
|
79
67
|
|
|
80
68
|
await configure({
|
|
81
69
|
'/mnt/zip': {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
zipData: Buffer.from(zipData)
|
|
85
|
-
}
|
|
70
|
+
backend: Zip,
|
|
71
|
+
zipData: zipData,
|
|
86
72
|
},
|
|
87
73
|
'/tmp': 'InMemory',
|
|
88
|
-
'/home':
|
|
74
|
+
'/home': IndexedDB,
|
|
89
75
|
};
|
|
90
76
|
```
|
|
91
77
|
|
|
@@ -94,11 +80,10 @@ await configure({
|
|
|
94
80
|
The FS promises API is exposed as `promises`.
|
|
95
81
|
|
|
96
82
|
```js
|
|
97
|
-
import { configure, promises
|
|
98
|
-
import {
|
|
99
|
-
registerBackend(IndexedDBFileSystem);
|
|
83
|
+
import { configure, promises } from '@zenfs/core';
|
|
84
|
+
import { IndexedDB } from '@zenfs/dom';
|
|
100
85
|
|
|
101
|
-
await configure({ '/':
|
|
86
|
+
await configure({ '/': IndexedDB });
|
|
102
87
|
|
|
103
88
|
const exists = await promises.exists('/myfile.txt');
|
|
104
89
|
if (!exists) {
|
|
@@ -106,46 +91,48 @@ if (!exists) {
|
|
|
106
91
|
}
|
|
107
92
|
```
|
|
108
93
|
|
|
109
|
-
ZenFS does _not_ provide a seperate
|
|
94
|
+
ZenFS does _not_ provide a seperate public import for importing promises in its built form. If you are using ESM, you can import promises functions from `dist/emulation/promises`, though this may change at any time and is not recommended.
|
|
110
95
|
|
|
111
96
|
#### Using asynchronous backends synchronously
|
|
112
97
|
|
|
113
|
-
You may have noticed that attempting to use a synchronous
|
|
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 wish to use an asynchronous backend synchronously you need to wrap it in an `AsyncMirror`:
|
|
114
99
|
|
|
115
100
|
```js
|
|
116
101
|
import { configure, fs } from '@zenfs/core';
|
|
117
|
-
import {
|
|
118
|
-
registerBackend(IndexedDBFileSystem);
|
|
102
|
+
import { IndexedDB } from '@zenfs/dom';
|
|
119
103
|
|
|
120
104
|
await configure({
|
|
121
|
-
'/': {
|
|
105
|
+
'/': {
|
|
106
|
+
backend: 'AsyncMirror',
|
|
107
|
+
sync: 'InMemory',
|
|
108
|
+
async: IndexedDB,
|
|
109
|
+
},
|
|
122
110
|
});
|
|
123
111
|
|
|
124
|
-
fs.writeFileSync('/persistant.txt', 'My persistant data'); // This fails if you configure
|
|
112
|
+
fs.writeFileSync('/persistant.txt', 'My persistant data'); // This fails if you configure with only IndexedDB
|
|
125
113
|
```
|
|
126
114
|
|
|
127
115
|
### Advanced usage
|
|
128
116
|
|
|
129
117
|
#### Creating backends
|
|
130
118
|
|
|
131
|
-
If you would like to create backends without configure, you may do so by importing the backend
|
|
119
|
+
If you would like to create backends without configure, you may do so by importing the backend and calling `createBackend` with it. You can import the backend directly or with `backends`:
|
|
132
120
|
|
|
133
121
|
```js
|
|
134
122
|
import { configure, backends, InMemory } from '@zenfs/core';
|
|
135
123
|
|
|
136
|
-
console.log(backends.InMemory === InMemory) // they are the same
|
|
124
|
+
console.log(backends.InMemory === InMemory); // they are the same
|
|
137
125
|
|
|
138
|
-
const
|
|
126
|
+
const internalInMemoryFS = await createBackend(InMemory);
|
|
139
127
|
```
|
|
140
128
|
|
|
141
|
-
> ⚠ Instances of backends follow the
|
|
129
|
+
> ⚠ Instances of backends follow the **_internal_** ZenFS API. You should never use a backend's methods unless you are extending a backend.
|
|
142
130
|
|
|
143
|
-
Coming soon:
|
|
144
131
|
```js
|
|
145
132
|
import { configure, InMemory } from '@zenfs/core';
|
|
146
133
|
|
|
147
|
-
const
|
|
148
|
-
await
|
|
134
|
+
const internalInMemoryFS = new InMemory();
|
|
135
|
+
await internalInMemoryFS.ready();
|
|
149
136
|
```
|
|
150
137
|
|
|
151
138
|
#### Mounting
|
|
@@ -155,9 +142,9 @@ If you would like to mount and unmount backends, you can do so using the `mount`
|
|
|
155
142
|
```js
|
|
156
143
|
import { fs, InMemory } from '@zenfs/core';
|
|
157
144
|
|
|
158
|
-
const
|
|
145
|
+
const internalInMemoryFS = await createBackend(InMemory); // create an FS instance
|
|
159
146
|
|
|
160
|
-
fs.mount('/tmp',
|
|
147
|
+
fs.mount('/tmp', internalInMemoryFS); // mount
|
|
161
148
|
|
|
162
149
|
fs.umount('/tmp'); // unmount /tmp
|
|
163
150
|
```
|
|
@@ -165,10 +152,8 @@ fs.umount('/tmp'); // unmount /tmp
|
|
|
165
152
|
This could be used in the "multiple backends" example like so:
|
|
166
153
|
|
|
167
154
|
```js
|
|
168
|
-
import {
|
|
169
|
-
import {
|
|
170
|
-
import Buffer from 'buffer';
|
|
171
|
-
registerBackend(IndexedDBFileSystem);
|
|
155
|
+
import { IndexedDB } from '@zenfs/dom';
|
|
156
|
+
import { Zip } from '@zenfs/zip';
|
|
172
157
|
|
|
173
158
|
await configure({
|
|
174
159
|
'/tmp': 'InMemory',
|
|
@@ -178,8 +163,7 @@ await configure({
|
|
|
178
163
|
fs.mkdirSync('/mnt');
|
|
179
164
|
|
|
180
165
|
const res = await fetch('mydata.zip');
|
|
181
|
-
const
|
|
182
|
-
const zipFs = await ZipFS.Create({ zipData });
|
|
166
|
+
const zipFs = await createBackend(Zip, { zipData: await res.arrayBuffer() });
|
|
183
167
|
fs.mount('/mnt/zip', zipFs);
|
|
184
168
|
|
|
185
169
|
// do stuff with the mounted zip
|
|
@@ -191,64 +175,12 @@ fs.umount('/mnt/zip'); // finished using the zip
|
|
|
191
175
|
|
|
192
176
|
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.
|
|
193
177
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
tsconfig.json
|
|
197
|
-
|
|
198
|
-
```json
|
|
199
|
-
{
|
|
200
|
-
...
|
|
201
|
-
"paths": {
|
|
202
|
-
"fs": ["node_modules/zenfs/dist/index.js"]
|
|
203
|
-
}
|
|
204
|
-
...
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
[Why tsconfig.json?](https://stackoverflow.com/a/71935037/17637456)
|
|
209
|
-
|
|
210
|
-
Webpack:
|
|
211
|
-
|
|
212
|
-
```js
|
|
213
|
-
module.exports = {
|
|
214
|
-
// ...
|
|
215
|
-
resolve: {
|
|
216
|
-
alias: {
|
|
217
|
-
fs: require.resolve('zenfs'),
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
// ...
|
|
221
|
-
};
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Rollup:
|
|
225
|
-
|
|
226
|
-
```js
|
|
227
|
-
import alias from '@rollup/plugin-alias';
|
|
228
|
-
|
|
229
|
-
export default {
|
|
230
|
-
// ...
|
|
231
|
-
plugins: [
|
|
232
|
-
alias({
|
|
233
|
-
entries: [{ find: 'fs', replacement: 'zenfs' }],
|
|
234
|
-
}),
|
|
235
|
-
],
|
|
236
|
-
// ...
|
|
237
|
-
};
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Using with Emscripten
|
|
241
|
-
|
|
242
|
-
You can use any _synchronous_ ZenFS file systems with Emscripten.
|
|
243
|
-
|
|
244
|
-
```js
|
|
245
|
-
import { EmscriptenFSPlugin } from '@zenfs/fs-emscripten';
|
|
246
|
-
const BFS = new EmscriptenFSPlugin(); // Create a ZenFS Emscripten FS plugin.
|
|
247
|
-
FS.createFolder(FS.root, 'data', true, true); // Create the folder to turn into a mount point.
|
|
248
|
-
FS.mount(BFS, { root: '/' }, '/data'); // Mount BFS's root folder into /data.
|
|
249
|
-
```
|
|
178
|
+
## Building
|
|
250
179
|
|
|
251
|
-
|
|
180
|
+
- Make sure you have Node and NPM installed. You must have Node v18 or newer.
|
|
181
|
+
- Install dependencies with `npm install`
|
|
182
|
+
- Build using `npm run build`
|
|
183
|
+
- You can find the built code in `dist`.
|
|
252
184
|
|
|
253
185
|
### Testing
|
|
254
186
|
|