@zenfs/core 0.9.7 → 0.10.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.
- package/dist/backends/AsyncStore.js +29 -29
- package/dist/backends/Fetch.d.ts +84 -0
- package/dist/backends/Fetch.js +171 -0
- package/dist/backends/Index.js +19 -19
- package/dist/backends/Locked.d.ts +11 -11
- package/dist/backends/Locked.js +50 -49
- package/dist/backends/Overlay.js +21 -21
- package/dist/backends/SyncStore.js +27 -27
- package/dist/backends/backend.js +4 -4
- package/dist/backends/port/fs.d.ts +124 -0
- package/dist/backends/port/fs.js +241 -0
- package/dist/backends/port/rpc.d.ts +60 -0
- package/dist/backends/port/rpc.js +71 -0
- package/dist/backends/port/store.d.ts +30 -0
- package/dist/backends/port/store.js +142 -0
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +4 -4
- package/dist/config.d.ts +8 -10
- package/dist/config.js +11 -11
- package/dist/emulation/async.js +6 -6
- package/dist/emulation/dir.js +2 -2
- package/dist/emulation/index.d.ts +1 -1
- package/dist/emulation/index.js +1 -1
- package/dist/emulation/path.d.ts +3 -2
- package/dist/emulation/path.js +19 -45
- package/dist/emulation/promises.d.ts +7 -12
- package/dist/emulation/promises.js +144 -146
- package/dist/emulation/shared.d.ts +5 -10
- package/dist/emulation/shared.js +8 -8
- package/dist/emulation/streams.js +3 -3
- package/dist/emulation/sync.js +25 -25
- package/dist/{ApiError.d.ts → error.d.ts} +13 -14
- package/dist/error.js +292 -0
- package/dist/file.d.ts +2 -0
- package/dist/file.js +10 -4
- package/dist/filesystem.js +15 -15
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/mutex.js +2 -1
- package/dist/utils.d.ts +8 -7
- package/dist/utils.js +11 -12
- package/package.json +3 -3
- package/readme.md +17 -9
- package/src/backends/AsyncStore.ts +29 -29
- package/src/backends/Fetch.ts +230 -0
- package/src/backends/Index.ts +19 -19
- package/src/backends/Locked.ts +50 -49
- package/src/backends/Overlay.ts +23 -23
- package/src/backends/SyncStore.ts +27 -27
- package/src/backends/backend.ts +6 -6
- package/src/backends/port/fs.ts +308 -0
- package/src/backends/port/readme.md +59 -0
- package/src/backends/port/rpc.ts +144 -0
- package/src/backends/port/store.ts +187 -0
- package/src/config.ts +20 -24
- package/src/emulation/async.ts +6 -6
- package/src/emulation/dir.ts +2 -2
- package/src/emulation/index.ts +1 -1
- package/src/emulation/path.ts +25 -49
- package/src/emulation/promises.ts +150 -159
- package/src/emulation/shared.ts +12 -14
- package/src/emulation/streams.ts +3 -3
- package/src/emulation/sync.ts +28 -28
- package/src/{ApiError.ts → error.ts} +89 -89
- package/src/file.ts +12 -4
- package/src/filesystem.ts +15 -15
- package/src/index.ts +4 -1
- package/src/mutex.ts +3 -1
- package/src/utils.ts +16 -18
- package/tsconfig.json +2 -2
- package/dist/ApiError.js +0 -292
package/src/config.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ErrnoError, Errno } from './error.js';
|
|
2
2
|
import type { Backend, BackendConfiguration } from './backends/backend.js';
|
|
3
3
|
import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js';
|
|
4
4
|
import * as fs from './emulation/index.js';
|
|
5
|
-
import { setCred, type
|
|
5
|
+
import { setCred, type MountObject } from './emulation/shared.js';
|
|
6
6
|
import { FileSystem } from './filesystem.js';
|
|
7
|
+
import type { AbsolutePath } from './emulation/path.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Configuration for a specific mount point
|
|
@@ -20,11 +21,11 @@ function isMountConfig(arg: unknown): arg is MountConfiguration {
|
|
|
20
21
|
*/
|
|
21
22
|
export async function resolveMountConfig<FS extends FileSystem, TOptions extends object = object>(config: MountConfiguration<FS, TOptions>, _depth = 0): Promise<FS> {
|
|
22
23
|
if (typeof config !== 'object' || config == null) {
|
|
23
|
-
throw new
|
|
24
|
+
throw new ErrnoError(Errno.EINVAL, 'Invalid options on mount configuration');
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
if (!isMountConfig(config)) {
|
|
27
|
-
throw new
|
|
28
|
+
throw new ErrnoError(Errno.EINVAL, 'Invalid mount configuration');
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
if (config instanceof FileSystem) {
|
|
@@ -45,7 +46,7 @@ export async function resolveMountConfig<FS extends FileSystem, TOptions extends
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
if (_depth > 10) {
|
|
48
|
-
throw new
|
|
49
|
+
throw new ErrnoError(Errno.EINVAL, 'Invalid configuration, too deep and possibly infinite');
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
(<Record<string, FileSystem>>config)[key] = await resolveMountConfig(value, ++_depth);
|
|
@@ -54,7 +55,7 @@ export async function resolveMountConfig<FS extends FileSystem, TOptions extends
|
|
|
54
55
|
const { backend } = config;
|
|
55
56
|
|
|
56
57
|
if (!(await backend.isAvailable())) {
|
|
57
|
-
throw new
|
|
58
|
+
throw new ErrnoError(Errno.EPERM, 'Backend not available: ' + backend);
|
|
58
59
|
}
|
|
59
60
|
checkOptions(backend, config);
|
|
60
61
|
const mount = backend.create(config);
|
|
@@ -63,39 +64,34 @@ export async function resolveMountConfig<FS extends FileSystem, TOptions extends
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
|
-
*
|
|
67
|
+
* Configuration
|
|
67
68
|
*/
|
|
68
|
-
export
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Configuration for the file systems
|
|
76
|
-
*/
|
|
77
|
-
export type Configuration = MountConfiguration | MappingConfiguration;
|
|
69
|
+
export interface Configuration {
|
|
70
|
+
mounts: Record<AbsolutePath, MountConfiguration>;
|
|
71
|
+
uid?: number;
|
|
72
|
+
gid?: number;
|
|
73
|
+
}
|
|
78
74
|
|
|
79
75
|
/**
|
|
80
76
|
* Creates filesystems with the given configuration, and initializes ZenFS with it.
|
|
81
77
|
* @see Configuration for more info on the configuration object.
|
|
82
78
|
*/
|
|
83
|
-
export async function configure(config: Configuration): Promise<void> {
|
|
79
|
+
export async function configure(config: MountConfiguration | Configuration): Promise<void> {
|
|
84
80
|
const uid = 'uid' in config ? config.uid || 0 : 0;
|
|
85
81
|
const gid = 'gid' in config ? config.gid || 0 : 0;
|
|
86
82
|
|
|
87
83
|
if (isMountConfig(config)) {
|
|
88
84
|
// single FS
|
|
89
|
-
config = { '/': config };
|
|
85
|
+
config = { mounts: { '/': config } };
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
for (const [point, value] of Object.entries(config)) {
|
|
93
|
-
if (point
|
|
94
|
-
|
|
88
|
+
for (const [point, value] of Object.entries(config.mounts) as [AbsolutePath, MountConfiguration][]) {
|
|
89
|
+
if (!point.startsWith('/')) {
|
|
90
|
+
throw new ErrnoError(Errno.EINVAL, 'Mount points must have absolute paths');
|
|
95
91
|
}
|
|
96
|
-
config[point] = await resolveMountConfig(value);
|
|
92
|
+
config.mounts[point] = await resolveMountConfig(value);
|
|
97
93
|
}
|
|
98
94
|
|
|
99
|
-
fs.
|
|
95
|
+
fs.mountObject(config.mounts as MountObject);
|
|
100
96
|
setCred({ uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
|
|
101
97
|
}
|
package/src/emulation/async.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as fs from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { ErrnoError, Errno } from '../error.js';
|
|
3
3
|
import type { FileContents } from '../filesystem.js';
|
|
4
4
|
import { BigIntStats, type BigIntStatsFs, type Stats, type StatsFs } from '../stats.js';
|
|
5
5
|
import { nop, normalizeMode, type Callback } from '../utils.js';
|
|
@@ -262,7 +262,7 @@ export function ftruncate(fd: number, lenOrCB?: any, cb: Callback = nop): void {
|
|
|
262
262
|
cb = typeof lenOrCB === 'function' ? lenOrCB : cb;
|
|
263
263
|
const file = fd2file(fd);
|
|
264
264
|
if (length < 0) {
|
|
265
|
-
throw new
|
|
265
|
+
throw new ErrnoError(Errno.EINVAL);
|
|
266
266
|
}
|
|
267
267
|
file.truncate(length)
|
|
268
268
|
.then(() => cb())
|
|
@@ -335,7 +335,7 @@ export function write(fd: number, data: FileContents, cbPosOff?: any, cbLenEnc?:
|
|
|
335
335
|
default:
|
|
336
336
|
// ...try to find the callback and get out of here!
|
|
337
337
|
cb = typeof cbLenEnc === 'function' ? cbLenEnc : typeof cbPos === 'function' ? cbPos : cb;
|
|
338
|
-
(<Callback<[number, Uint8Array | string]>>cb)(new
|
|
338
|
+
(<Callback<[number, Uint8Array | string]>>cb)(new ErrnoError(Errno.EINVAL, 'Invalid arguments.'));
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
341
341
|
buffer = Buffer.from(data);
|
|
@@ -661,7 +661,7 @@ access satisfies Omit<typeof fs.access, '__promisify__'>;
|
|
|
661
661
|
export function watchFile(path: fs.PathLike, listener: (curr: Stats, prev: Stats) => void): void;
|
|
662
662
|
export function watchFile(path: fs.PathLike, options: { persistent?: boolean; interval?: number }, listener: (curr: Stats, prev: Stats) => void): void;
|
|
663
663
|
export function watchFile(path: fs.PathLike, optsListener: any, listener: (curr: Stats, prev: Stats) => void = nop): void {
|
|
664
|
-
throw
|
|
664
|
+
throw ErrnoError.With('ENOSYS', path.toString(), 'watchFile');
|
|
665
665
|
}
|
|
666
666
|
watchFile satisfies Omit<typeof fs.watchFile, '__promisify__'>;
|
|
667
667
|
|
|
@@ -669,7 +669,7 @@ watchFile satisfies Omit<typeof fs.watchFile, '__promisify__'>;
|
|
|
669
669
|
* @todo Implement
|
|
670
670
|
*/
|
|
671
671
|
export function unwatchFile(path: fs.PathLike, listener: (curr: Stats, prev: Stats) => void = nop): void {
|
|
672
|
-
throw
|
|
672
|
+
throw ErrnoError.With('ENOSYS', path.toString(), 'unwatchFile');
|
|
673
673
|
}
|
|
674
674
|
unwatchFile satisfies Omit<typeof fs.unwatchFile, '__promisify__'>;
|
|
675
675
|
|
|
@@ -679,7 +679,7 @@ unwatchFile satisfies Omit<typeof fs.unwatchFile, '__promisify__'>;
|
|
|
679
679
|
export function watch(path: fs.PathLike, listener?: (event: string, filename: string) => any): fs.FSWatcher;
|
|
680
680
|
export function watch(path: fs.PathLike, options: { persistent?: boolean }, listener?: (event: string, filename: string) => any): fs.FSWatcher;
|
|
681
681
|
export function watch(path: fs.PathLike, options: any, listener: (event: string, filename: string) => any = nop): fs.FSWatcher {
|
|
682
|
-
throw
|
|
682
|
+
throw ErrnoError.With('ENOSYS', path.toString(), 'watch');
|
|
683
683
|
}
|
|
684
684
|
watch satisfies Omit<typeof fs.watch, '__promisify__'>;
|
|
685
685
|
|
package/src/emulation/dir.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Dirent as _Dirent, Dir as _Dir } from 'fs';
|
|
|
2
2
|
import type { Callback } from '../utils.js';
|
|
3
3
|
import type { Stats } from '../stats.js';
|
|
4
4
|
import { readdir } from './promises.js';
|
|
5
|
-
import {
|
|
5
|
+
import { ErrnoError, Errno } from '../error.js';
|
|
6
6
|
import { readdirSync } from './sync.js';
|
|
7
7
|
import { basename } from './path.js';
|
|
8
8
|
|
|
@@ -47,7 +47,7 @@ export class Dir implements _Dir {
|
|
|
47
47
|
|
|
48
48
|
protected checkClosed(): void {
|
|
49
49
|
if (this.closed) {
|
|
50
|
-
throw new
|
|
50
|
+
throw new ErrnoError(Errno.EBADF, 'Can not use closed Dir');
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
package/src/emulation/index.ts
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 {
|
|
7
|
+
export { mountObject, mounts, mount, umount } from './shared.js';
|
|
8
8
|
export { Stats, BigIntStats, StatsFs } from '../stats.js';
|
package/src/emulation/path.ts
CHANGED
|
@@ -22,12 +22,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
/*
|
|
25
|
-
This is the POSIX path code of NodeJS
|
|
25
|
+
This is derived from the POSIX path code of NodeJS
|
|
26
26
|
https://raw.githubusercontent.com/nodejs/node/3907bd1/lib/path.js
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import type { ParsedPath } from 'node:path';
|
|
30
30
|
|
|
31
|
+
export type AbsolutePath = `/${string}`;
|
|
32
|
+
|
|
31
33
|
export let cwd = '/';
|
|
32
34
|
|
|
33
35
|
export function cd(path: string): void {
|
|
@@ -36,12 +38,6 @@ export function cd(path: string): void {
|
|
|
36
38
|
|
|
37
39
|
export const sep = '/';
|
|
38
40
|
|
|
39
|
-
function validateString(str: unknown, name: string): void {
|
|
40
|
-
if (typeof str != 'string') {
|
|
41
|
-
throw new TypeError(`"${name}" is not a string`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
41
|
function validateObject(str: unknown, name: string): void {
|
|
46
42
|
if (typeof str != 'object') {
|
|
47
43
|
throw new TypeError(`"${name}" is not an object`);
|
|
@@ -113,23 +109,23 @@ export function formatExt(ext: string): string {
|
|
|
113
109
|
return ext ? `${ext[0] === '.' ? '' : '.'}${ext}` : '';
|
|
114
110
|
}
|
|
115
111
|
|
|
116
|
-
export function resolve(...
|
|
112
|
+
export function resolve(...parts: string[]): AbsolutePath {
|
|
117
113
|
let resolved = '';
|
|
118
|
-
let absolute = false;
|
|
119
114
|
|
|
120
|
-
for (
|
|
121
|
-
|
|
122
|
-
validateString(path, `paths[${i}]`);
|
|
123
|
-
|
|
124
|
-
// Skip empty entries
|
|
125
|
-
if (!path.length) {
|
|
115
|
+
for (const part of [...parts.reverse(), cwd]) {
|
|
116
|
+
if (!part.length) {
|
|
126
117
|
continue;
|
|
127
118
|
}
|
|
128
119
|
|
|
129
|
-
resolved = `${
|
|
130
|
-
|
|
120
|
+
resolved = `${part}/${resolved}`;
|
|
121
|
+
|
|
122
|
+
if (part.startsWith('/')) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
131
125
|
}
|
|
132
126
|
|
|
127
|
+
const absolute = resolved.startsWith('/');
|
|
128
|
+
|
|
133
129
|
// At this point the path should be resolved to a full absolute path, but
|
|
134
130
|
// handle relative paths to be safe (might happen when cwd fails)
|
|
135
131
|
|
|
@@ -139,21 +135,19 @@ export function resolve(...args: string[]): string {
|
|
|
139
135
|
if (absolute) {
|
|
140
136
|
return `/${resolved}`;
|
|
141
137
|
}
|
|
142
|
-
return resolved.length
|
|
138
|
+
return resolved.length ? (resolved as AbsolutePath) : '/';
|
|
143
139
|
}
|
|
144
140
|
|
|
145
141
|
export function normalize(path: string): string {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (path.length === 0) return '.';
|
|
142
|
+
if (!path.length) return '.';
|
|
149
143
|
|
|
150
|
-
const isAbsolute = path
|
|
151
|
-
const trailingSeparator = path.
|
|
144
|
+
const isAbsolute = path.startsWith('/');
|
|
145
|
+
const trailingSeparator = path.endsWith('/');
|
|
152
146
|
|
|
153
147
|
// Normalize the path
|
|
154
148
|
path = normalizeString(path, !isAbsolute);
|
|
155
149
|
|
|
156
|
-
if (path.length
|
|
150
|
+
if (!path.length) {
|
|
157
151
|
if (isAbsolute) return '/';
|
|
158
152
|
return trailingSeparator ? './' : '.';
|
|
159
153
|
}
|
|
@@ -163,29 +157,17 @@ export function normalize(path: string): string {
|
|
|
163
157
|
}
|
|
164
158
|
|
|
165
159
|
export function isAbsolute(path: string): boolean {
|
|
166
|
-
|
|
167
|
-
return path.length > 0 && path[0] === '/';
|
|
160
|
+
return path.startsWith('/');
|
|
168
161
|
}
|
|
169
162
|
|
|
170
|
-
export function join(...
|
|
171
|
-
if (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const arg = args[i];
|
|
175
|
-
validateString(arg, 'path');
|
|
176
|
-
if (arg.length > 0) {
|
|
177
|
-
if (joined === undefined) joined = arg;
|
|
178
|
-
else joined += `/${arg}`;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (joined === undefined) return '.';
|
|
163
|
+
export function join(...parts: string[]): string {
|
|
164
|
+
if (!parts.length) return '.';
|
|
165
|
+
const joined = parts.join('/');
|
|
166
|
+
if (!joined?.length) return '.';
|
|
182
167
|
return normalize(joined);
|
|
183
168
|
}
|
|
184
169
|
|
|
185
|
-
export function relative(from: string, to: string) {
|
|
186
|
-
validateString(from, 'from');
|
|
187
|
-
validateString(to, 'to');
|
|
188
|
-
|
|
170
|
+
export function relative(from: string, to: string): string {
|
|
189
171
|
if (from === to) return '';
|
|
190
172
|
|
|
191
173
|
// Trim leading forward slashes.
|
|
@@ -249,7 +231,6 @@ export function relative(from: string, to: string) {
|
|
|
249
231
|
}
|
|
250
232
|
|
|
251
233
|
export function dirname(path: string): string {
|
|
252
|
-
validateString(path, 'path');
|
|
253
234
|
if (path.length === 0) return '.';
|
|
254
235
|
const hasRoot = path[0] === '/';
|
|
255
236
|
let end = -1;
|
|
@@ -272,9 +253,6 @@ export function dirname(path: string): string {
|
|
|
272
253
|
}
|
|
273
254
|
|
|
274
255
|
export function basename(path: string, suffix?: string): string {
|
|
275
|
-
if (suffix !== undefined) validateString(suffix, 'ext');
|
|
276
|
-
validateString(path, 'path');
|
|
277
|
-
|
|
278
256
|
let start = 0;
|
|
279
257
|
let end = -1;
|
|
280
258
|
let matchedSlash = true;
|
|
@@ -341,7 +319,6 @@ export function basename(path: string, suffix?: string): string {
|
|
|
341
319
|
}
|
|
342
320
|
|
|
343
321
|
export function extname(path: string): string {
|
|
344
|
-
validateString(path, 'path');
|
|
345
322
|
let startDot = -1;
|
|
346
323
|
let startPart = 0;
|
|
347
324
|
let end = -1;
|
|
@@ -400,8 +377,7 @@ export function format(pathObject: ParsedPath): string {
|
|
|
400
377
|
}
|
|
401
378
|
|
|
402
379
|
export function parse(path: string): ParsedPath {
|
|
403
|
-
|
|
404
|
-
const isAbsolute = path[0] === '/';
|
|
380
|
+
const isAbsolute = path.startsWith('/');
|
|
405
381
|
const ret = { root: isAbsolute ? '/' : '', dir: '', base: '', ext: '', name: '' };
|
|
406
382
|
if (path.length === 0) return ret;
|
|
407
383
|
|