@zenfs/core 1.8.7 → 1.9.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/backend.d.ts +1 -1
- package/dist/backends/backend.js +7 -4
- package/dist/backends/fetch.d.ts +23 -32
- package/dist/backends/fetch.js +94 -134
- package/dist/backends/index.d.ts +1 -4
- package/dist/backends/index.js +1 -4
- package/dist/backends/memory.d.ts +7 -5
- package/dist/backends/memory.js +6 -4
- package/dist/backends/overlay.d.ts +4 -5
- package/dist/backends/overlay.js +16 -20
- package/dist/backends/passthrough.d.ts +3 -3
- package/dist/backends/passthrough.js +4 -6
- package/dist/backends/port/fs.d.ts +4 -5
- package/dist/backends/port/fs.js +7 -12
- package/dist/backends/port/rpc.d.ts +1 -1
- package/dist/backends/port/rpc.js +15 -13
- package/dist/backends/store/fs.d.ts +51 -40
- package/dist/backends/store/fs.js +347 -241
- package/dist/backends/store/map.d.ts +41 -0
- package/dist/backends/store/map.js +45 -0
- package/dist/backends/store/simple.d.ts +10 -58
- package/dist/backends/store/simple.js +8 -115
- package/dist/backends/store/store.d.ts +111 -44
- package/dist/backends/store/store.js +230 -38
- package/dist/config.d.ts +7 -3
- package/dist/config.js +17 -14
- package/dist/context.d.ts +1 -1
- package/dist/context.js +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +1 -5
- package/dist/{devices.d.ts → internal/devices.d.ts} +4 -4
- package/dist/{devices.js → internal/devices.js} +18 -14
- package/dist/{file.d.ts → internal/file.d.ts} +3 -2
- package/dist/{file.js → internal/file.js} +17 -12
- package/dist/{backends/store → internal}/file_index.d.ts +13 -3
- package/dist/{backends/store → internal}/file_index.js +28 -5
- package/dist/{filesystem.d.ts → internal/filesystem.d.ts} +99 -32
- package/dist/internal/filesystem.js +83 -0
- package/dist/internal/index.d.ts +9 -0
- package/dist/internal/index.js +9 -0
- package/dist/internal/index_fs.d.ts +56 -0
- package/dist/internal/index_fs.js +184 -0
- package/dist/{backends/store → internal}/inode.d.ts +6 -1
- package/dist/{backends/store → internal}/inode.js +14 -6
- package/dist/internal/log.d.ts +132 -0
- package/dist/internal/log.js +177 -0
- package/dist/mixins/async.d.ts +2 -2
- package/dist/mixins/async.js +33 -49
- package/dist/mixins/mutexed.d.ts +9 -3
- package/dist/mixins/mutexed.js +22 -3
- package/dist/mixins/readonly.d.ts +2 -2
- package/dist/mixins/readonly.js +4 -3
- package/dist/mixins/shared.d.ts +1 -1
- package/dist/mixins/sync.d.ts +2 -2
- package/dist/mixins/sync.js +6 -0
- package/dist/stats.d.ts +2 -3
- package/dist/stats.js +7 -5
- package/dist/utils.d.ts +2 -15
- package/dist/utils.js +10 -47
- package/dist/vfs/async.d.ts +2 -2
- package/dist/vfs/async.js +3 -3
- package/dist/vfs/dir.js +1 -1
- package/dist/vfs/promises.d.ts +6 -6
- package/dist/vfs/promises.js +54 -49
- package/dist/vfs/shared.d.ts +3 -3
- package/dist/vfs/shared.js +16 -10
- package/dist/vfs/streams.js +1 -1
- package/dist/vfs/sync.d.ts +1 -2
- package/dist/vfs/sync.js +14 -15
- package/dist/vfs/types.d.ts +1 -0
- package/dist/vfs/watchers.d.ts +5 -1
- package/dist/vfs/watchers.js +16 -19
- package/package.json +3 -3
- package/readme.md +12 -12
- package/scripts/test.js +15 -3
- package/tests/backend/fetch.test.ts +49 -0
- package/tests/backend/port.test.ts +130 -0
- package/tests/common/context.test.ts +9 -4
- package/tests/common.ts +21 -3
- package/tests/data/image.jpg +0 -0
- package/tests/data/utf8.txt +1 -0
- package/tests/fetch/config.js +40 -0
- package/tests/fetch/fetch.ts +20 -0
- package/tests/fetch/run.sh +3 -3
- package/tests/fetch/{server.ts → server.js} +15 -11
- package/tests/fs/directory.test.ts +1 -1
- package/tests/fs/errors.test.ts +1 -1
- package/tests/fs/links.test.ts +1 -1
- package/tests/fs/open.test.ts +1 -1
- package/tests/fs/permissions.test.ts +2 -3
- package/tests/fs/rename.test.ts +1 -1
- package/tests/fs/stat.test.ts +1 -1
- package/tests/fs/times.test.ts +1 -1
- package/tests/fs/watch.test.ts +21 -22
- package/tests/fs/write.test.ts +1 -1
- package/tests/fs/writeFile.test.ts +8 -7
- package/tests/readme.md +3 -3
- package/tests/setup/_overlay.ts +7 -0
- package/tests/setup/context.ts +2 -2
- package/tests/setup/index.ts +3 -3
- package/tests/setup/memory.ts +2 -2
- package/tests/setup/port.ts +2 -2
- package/tests/setup.ts +25 -5
- package/tests/tsconfig.json +3 -2
- package/dist/backends/store/index_fs.d.ts +0 -34
- package/dist/backends/store/index_fs.js +0 -67
- package/dist/filesystem.js +0 -52
- package/tests/fetch/cow+fetch.ts +0 -13
- package/tests/port/channel.test.ts +0 -39
- package/tests/port/config.test.ts +0 -30
- package/tests/port/remote.test.ts +0 -32
- package/tests/port/timeout.test.ts +0 -48
- /package/dist/{credentials.d.ts → internal/credentials.d.ts} +0 -0
- /package/dist/{credentials.js → internal/credentials.js} +0 -0
- /package/dist/{error.d.ts → internal/error.d.ts} +0 -0
- /package/dist/{error.js → internal/error.js} +0 -0
- /package/tests/{port → backend}/config.worker.js +0 -0
- /package/tests/{port → backend}/remote.worker.js +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RequiredKeys } from 'utilium';
|
|
2
|
-
import type { FileSystem } from '../filesystem.js';
|
|
2
|
+
import type { FileSystem } from '../internal/filesystem.js';
|
|
3
3
|
type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | (abstract new (...args: any[]) => any);
|
|
4
4
|
/**
|
|
5
5
|
* Resolves the type of Backend.options from the options interface
|
package/dist/backends/backend.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Errno, ErrnoError } from '../error.js';
|
|
1
|
+
import { Errno, ErrnoError } from '../internal/error.js';
|
|
2
|
+
import { debug, err } from '../internal/log.js';
|
|
2
3
|
/** @internal */
|
|
3
4
|
export function isBackend(arg) {
|
|
4
5
|
return arg != null && typeof arg == 'object' && 'create' in arg && typeof arg.create == 'function';
|
|
@@ -9,16 +10,17 @@ export function isBackend(arg) {
|
|
|
9
10
|
*/
|
|
10
11
|
export async function checkOptions(backend, options) {
|
|
11
12
|
if (typeof options != 'object' || options === null) {
|
|
12
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid options');
|
|
13
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Invalid options'));
|
|
13
14
|
}
|
|
14
15
|
// Check for required options.
|
|
15
16
|
for (const [optName, opt] of Object.entries(backend.options)) {
|
|
16
17
|
const value = options === null || options === void 0 ? void 0 : options[optName];
|
|
17
18
|
if (value === undefined || value === null) {
|
|
18
19
|
if (!opt.required) {
|
|
20
|
+
debug('Missing non-required option: ' + optName);
|
|
19
21
|
continue;
|
|
20
22
|
}
|
|
21
|
-
throw new ErrnoError(Errno.EINVAL, 'Missing required option: ' + optName);
|
|
23
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Missing required option: ' + optName));
|
|
22
24
|
}
|
|
23
25
|
const isType = (type, _ = value) => (typeof type == 'function' ? value instanceof type : typeof value === type);
|
|
24
26
|
if (Array.isArray(opt.type) ? !opt.type.some(v => isType(v)) : !isType(opt.type)) {
|
|
@@ -27,8 +29,9 @@ export async function checkOptions(backend, options) {
|
|
|
27
29
|
// The expected type (as a string)
|
|
28
30
|
const name = (type) => (typeof type == 'function' ? type.name : type);
|
|
29
31
|
const expected = Array.isArray(opt.type) ? `one of ${opt.type.map(name).join(', ')}` : name(opt.type);
|
|
30
|
-
throw new ErrnoError(Errno.EINVAL, `Incorrect type for "${optName}": ${type} (expected ${expected})`);
|
|
32
|
+
throw err(new ErrnoError(Errno.EINVAL, `Incorrect type for "${optName}": ${type} (expected ${expected})`));
|
|
31
33
|
}
|
|
34
|
+
debug('Using custom validator for option: ' + optName);
|
|
32
35
|
if (opt.validator)
|
|
33
36
|
await opt.validator(value);
|
|
34
37
|
// Otherwise: All good!
|
package/dist/backends/fetch.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import type { IndexData } from '../internal/file_index.js';
|
|
2
|
+
import { Index } from '../internal/file_index.js';
|
|
3
|
+
import { IndexFS } from '../internal/index_fs.js';
|
|
4
|
+
import type { SharedConfig } from './backend.js';
|
|
4
5
|
/**
|
|
5
6
|
* Configuration options for FetchFS.
|
|
6
7
|
*/
|
|
7
|
-
export interface FetchOptions {
|
|
8
|
+
export interface FetchOptions extends SharedConfig {
|
|
8
9
|
/**
|
|
9
10
|
* Options to pass through to fetch calls
|
|
10
11
|
*/
|
|
@@ -19,36 +20,26 @@ export interface FetchOptions {
|
|
|
19
20
|
*/
|
|
20
21
|
baseUrl?: string;
|
|
21
22
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* If true, enables writing to the remote (using post and delete)
|
|
24
|
+
* @default false
|
|
24
25
|
*/
|
|
25
|
-
|
|
26
|
+
remoteWrite?: boolean;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* A simple filesystem backed by HTTP using the `fetch` API.
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Index objects look like the following:
|
|
32
|
-
*
|
|
33
|
-
* ```json
|
|
34
|
-
* {
|
|
35
|
-
* "version": 1,
|
|
36
|
-
* "entries": {
|
|
37
|
-
* "/home": { ... },
|
|
38
|
-
* "/home/john": { ... },
|
|
39
|
-
* "/home/james": { ... }
|
|
40
|
-
* }
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* Each entry contains the stats associated with the file.
|
|
30
|
+
* @internal
|
|
45
31
|
*/
|
|
46
|
-
export declare class FetchFS extends
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
export declare class FetchFS extends IndexFS {
|
|
33
|
+
protected baseUrl: string;
|
|
34
|
+
protected requestInit: RequestInit;
|
|
35
|
+
protected remoteWrite?: boolean | undefined;
|
|
36
|
+
constructor(index: Index, baseUrl: string, requestInit?: RequestInit, remoteWrite?: boolean | undefined);
|
|
37
|
+
protected remove(path: string): Promise<void>;
|
|
38
|
+
protected removeSync(path: string): void;
|
|
39
|
+
read(path: string, buffer: Uint8Array, offset: number | undefined, end: number): Promise<void>;
|
|
40
|
+
readSync(path: string, buffer: Uint8Array, offset: number | undefined, end: number): void;
|
|
41
|
+
write(path: string, data: Uint8Array, offset: number): Promise<void>;
|
|
42
|
+
writeSync(path: string, data: Uint8Array, offset: number): void;
|
|
52
43
|
}
|
|
53
44
|
declare const _Fetch: {
|
|
54
45
|
readonly name: "Fetch";
|
|
@@ -65,13 +56,13 @@ declare const _Fetch: {
|
|
|
65
56
|
readonly type: "object";
|
|
66
57
|
readonly required: false;
|
|
67
58
|
};
|
|
68
|
-
readonly
|
|
69
|
-
readonly type: "
|
|
59
|
+
readonly remoteWrite: {
|
|
60
|
+
readonly type: "boolean";
|
|
70
61
|
readonly required: false;
|
|
71
62
|
};
|
|
72
63
|
};
|
|
73
64
|
readonly isAvailable: () => boolean;
|
|
74
|
-
readonly create: (options: FetchOptions) => FetchFS
|
|
65
|
+
readonly create: (options: FetchOptions) => Promise<FetchFS>;
|
|
75
66
|
};
|
|
76
67
|
type _Fetch = typeof _Fetch;
|
|
77
68
|
export interface Fetch extends _Fetch {
|
package/dist/backends/fetch.js
CHANGED
|
@@ -1,142 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
dispose = value[Symbol.asyncDispose];
|
|
8
|
-
}
|
|
9
|
-
if (dispose === void 0) {
|
|
10
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
-
dispose = value[Symbol.dispose];
|
|
12
|
-
if (async) inner = dispose;
|
|
13
|
-
}
|
|
14
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
-
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
-
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
-
}
|
|
18
|
-
else if (async) {
|
|
19
|
-
env.stack.push({ async: true });
|
|
20
|
-
}
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
23
|
-
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
-
return function (env) {
|
|
25
|
-
function fail(e) {
|
|
26
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
-
env.hasError = true;
|
|
28
|
-
}
|
|
29
|
-
var r, s = 0;
|
|
30
|
-
function next() {
|
|
31
|
-
while (r = env.stack.pop()) {
|
|
32
|
-
try {
|
|
33
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
-
if (r.dispose) {
|
|
35
|
-
var result = r.dispose.call(r.value);
|
|
36
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
-
}
|
|
38
|
-
else s |= 1;
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
fail(e);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
-
if (env.hasError) throw env.error;
|
|
46
|
-
}
|
|
47
|
-
return next();
|
|
48
|
-
};
|
|
49
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
-
var e = new Error(message);
|
|
51
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
-
});
|
|
53
|
-
import { Errno, ErrnoError } from '../error.js';
|
|
1
|
+
import * as requests from 'utilium/requests.js';
|
|
2
|
+
import { Errno, ErrnoError } from '../internal/error.js';
|
|
3
|
+
import { Index } from '../internal/file_index.js';
|
|
4
|
+
import { IndexFS } from '../internal/index_fs.js';
|
|
5
|
+
import { err, warn } from '../internal/log.js';
|
|
6
|
+
import { decodeUTF8, normalizePath } from '../utils.js';
|
|
54
7
|
import { S_IFREG } from '../vfs/constants.js';
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
throw new ErrnoError(Errno.EIO, e.message, path);
|
|
70
|
-
});
|
|
71
|
-
return new Uint8Array(arrayBuffer);
|
|
8
|
+
/** Parse and throw */
|
|
9
|
+
function parseError(path, fs) {
|
|
10
|
+
return (error) => {
|
|
11
|
+
if (!('tag' in error))
|
|
12
|
+
throw err(new ErrnoError(Errno.EIO, error.stack, path), { fs });
|
|
13
|
+
switch (error.tag) {
|
|
14
|
+
case 'fetch':
|
|
15
|
+
throw err(new ErrnoError(Errno.EREMOTEIO, error.message, path), { fs });
|
|
16
|
+
case 'status':
|
|
17
|
+
throw err(new ErrnoError(error.response.status > 500 ? Errno.EREMOTEIO : Errno.EIO, 'Response status code is ' + error.response.status, path), { fs });
|
|
18
|
+
case 'size':
|
|
19
|
+
throw err(new ErrnoError(Errno.EBADE, error.message, path), { fs });
|
|
20
|
+
case 'buffer':
|
|
21
|
+
throw err(new ErrnoError(Errno.EIO, 'Failed to decode buffer', path), { fs });
|
|
72
22
|
}
|
|
73
|
-
|
|
74
|
-
return response.json().catch((e) => {
|
|
75
|
-
throw new ErrnoError(Errno.EIO, e.message, path);
|
|
76
|
-
});
|
|
77
|
-
default:
|
|
78
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid download type: ' + type);
|
|
79
|
-
}
|
|
23
|
+
};
|
|
80
24
|
}
|
|
81
25
|
/**
|
|
82
26
|
* A simple filesystem backed by HTTP using the `fetch` API.
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* Index objects look like the following:
|
|
86
|
-
*
|
|
87
|
-
* ```json
|
|
88
|
-
* {
|
|
89
|
-
* "version": 1,
|
|
90
|
-
* "entries": {
|
|
91
|
-
* "/home": { ... },
|
|
92
|
-
* "/home/john": { ... },
|
|
93
|
-
* "/home/james": { ... }
|
|
94
|
-
* }
|
|
95
|
-
* }
|
|
96
|
-
* ```
|
|
97
|
-
*
|
|
98
|
-
* Each entry contains the stats associated with the file.
|
|
27
|
+
* @internal
|
|
99
28
|
*/
|
|
100
|
-
export class FetchFS extends
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
if (this._initialized)
|
|
105
|
-
return;
|
|
106
|
-
await super.ready();
|
|
107
|
-
const index = new Index();
|
|
108
|
-
index.fromJSON(await this.indexData);
|
|
109
|
-
await this.loadIndex(index);
|
|
110
|
-
if (this._disableSync)
|
|
111
|
-
return;
|
|
112
|
-
const tx = __addDisposableResource(env_1, this.store.transaction(), true);
|
|
113
|
-
// Iterate over all of the files and cache their contents
|
|
114
|
-
for (const [path, node] of index) {
|
|
115
|
-
if (!(node.mode & S_IFREG))
|
|
116
|
-
continue;
|
|
117
|
-
const content = await fetchFile(this.baseUrl + path, 'buffer', this.requestInit);
|
|
118
|
-
await tx.set(node.data, content);
|
|
119
|
-
}
|
|
120
|
-
await tx.commit();
|
|
121
|
-
}
|
|
122
|
-
catch (e_1) {
|
|
123
|
-
env_1.error = e_1;
|
|
124
|
-
env_1.hasError = true;
|
|
125
|
-
}
|
|
126
|
-
finally {
|
|
127
|
-
const result_1 = __disposeResources(env_1);
|
|
128
|
-
if (result_1)
|
|
129
|
-
await result_1;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
constructor(index = 'index.json', cache = new InMemoryStore('fetch'), baseUrl = '', requestInit) {
|
|
133
|
-
super(cache);
|
|
29
|
+
export class FetchFS extends IndexFS {
|
|
30
|
+
constructor(index, baseUrl, requestInit = {}, remoteWrite) {
|
|
31
|
+
super(0x206e6673, 'nfs', index);
|
|
134
32
|
this.baseUrl = baseUrl;
|
|
135
33
|
this.requestInit = requestInit;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.
|
|
34
|
+
this.remoteWrite = remoteWrite;
|
|
35
|
+
}
|
|
36
|
+
async remove(path) {
|
|
37
|
+
await requests.remove(this.baseUrl + path, { warn, cacheOnly: !this.remoteWrite }, this.requestInit);
|
|
38
|
+
}
|
|
39
|
+
removeSync(path) {
|
|
40
|
+
void requests.remove(this.baseUrl + path, { warn, cacheOnly: !this.remoteWrite }, this.requestInit);
|
|
41
|
+
}
|
|
42
|
+
async read(path, buffer, offset = 0, end) {
|
|
43
|
+
const inode = this.index.get(path);
|
|
44
|
+
if (!inode)
|
|
45
|
+
throw ErrnoError.With('ENOENT', path, 'read');
|
|
46
|
+
end !== null && end !== void 0 ? end : (end = inode.size);
|
|
47
|
+
if (end - offset == 0)
|
|
48
|
+
return;
|
|
49
|
+
const data = await requests
|
|
50
|
+
.get(this.baseUrl + path, { start: offset, end, size: inode.size, warn }, this.requestInit)
|
|
51
|
+
.catch(parseError(path, this))
|
|
52
|
+
.catch(() => undefined);
|
|
53
|
+
if (!data)
|
|
54
|
+
throw ErrnoError.With('ENODATA', path, 'read');
|
|
55
|
+
buffer.set(data);
|
|
56
|
+
}
|
|
57
|
+
readSync(path, buffer, offset = 0, end) {
|
|
58
|
+
const inode = this.index.get(path);
|
|
59
|
+
if (!inode)
|
|
60
|
+
throw ErrnoError.With('ENOENT', path, 'read');
|
|
61
|
+
end !== null && end !== void 0 ? end : (end = inode.size);
|
|
62
|
+
if (end - offset == 0)
|
|
63
|
+
return;
|
|
64
|
+
const { data, missing } = requests.getCached(this.baseUrl + path, { start: offset, end, size: inode.size, warn });
|
|
65
|
+
if (!data)
|
|
66
|
+
throw ErrnoError.With('ENODATA', path, 'read');
|
|
67
|
+
if (missing.length) {
|
|
68
|
+
void requests.get(this.baseUrl + path, { start: offset, end, size: inode.size, warn });
|
|
69
|
+
throw ErrnoError.With('EAGAIN', path, 'read');
|
|
70
|
+
}
|
|
71
|
+
buffer.set(data);
|
|
72
|
+
}
|
|
73
|
+
async write(path, data, offset) {
|
|
74
|
+
await requests.set(this.baseUrl + path, data, { offset, warn, cacheOnly: !this.remoteWrite }, this.requestInit).catch(parseError(path, this));
|
|
75
|
+
}
|
|
76
|
+
writeSync(path, data, offset) {
|
|
77
|
+
void requests.set(this.baseUrl + path, data, { offset, warn, cacheOnly: !this.remoteWrite }, this.requestInit).catch(parseError(path, this));
|
|
140
78
|
}
|
|
141
79
|
}
|
|
142
80
|
const _Fetch = {
|
|
@@ -145,15 +83,37 @@ const _Fetch = {
|
|
|
145
83
|
index: { type: ['string', 'object'], required: false },
|
|
146
84
|
baseUrl: { type: 'string', required: false },
|
|
147
85
|
requestInit: { type: 'object', required: false },
|
|
148
|
-
|
|
86
|
+
remoteWrite: { type: 'boolean', required: false },
|
|
149
87
|
},
|
|
150
88
|
isAvailable() {
|
|
151
89
|
return typeof globalThis.fetch == 'function';
|
|
152
90
|
},
|
|
153
|
-
create(options) {
|
|
91
|
+
async create(options) {
|
|
92
|
+
var _a;
|
|
154
93
|
const url = new URL(options.baseUrl || '');
|
|
155
94
|
url.pathname = normalizePath(url.pathname);
|
|
156
|
-
|
|
95
|
+
let baseUrl = url.toString();
|
|
96
|
+
if (baseUrl.at(-1) == '/')
|
|
97
|
+
baseUrl = baseUrl.slice(0, -1);
|
|
98
|
+
(_a = options.index) !== null && _a !== void 0 ? _a : (options.index = 'index.json');
|
|
99
|
+
const index = new Index();
|
|
100
|
+
if (typeof options.index != 'string') {
|
|
101
|
+
index.fromJSON(options.index);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const data = await requests.get(options.index, { warn }, options.requestInit).catch(parseError());
|
|
105
|
+
index.fromJSON(JSON.parse(decodeUTF8(data)));
|
|
106
|
+
}
|
|
107
|
+
const fs = new FetchFS(index, baseUrl, options.requestInit, options.remoteWrite);
|
|
108
|
+
if (options.disableAsyncCache)
|
|
109
|
+
return fs;
|
|
110
|
+
// Iterate over all of the files and cache their contents
|
|
111
|
+
for (const [path, node] of index) {
|
|
112
|
+
if (!(node.mode & S_IFREG))
|
|
113
|
+
continue;
|
|
114
|
+
await requests.get(baseUrl + path, { warn }, options.requestInit).catch(parseError(path, fs));
|
|
115
|
+
}
|
|
116
|
+
return fs;
|
|
157
117
|
},
|
|
158
118
|
};
|
|
159
119
|
export const Fetch = _Fetch;
|
package/dist/backends/index.d.ts
CHANGED
|
@@ -5,8 +5,5 @@ export * from './overlay.js';
|
|
|
5
5
|
export * from './passthrough.js';
|
|
6
6
|
export * from './port/fs.js';
|
|
7
7
|
export * from './store/fs.js';
|
|
8
|
-
export * from './store/
|
|
9
|
-
export * from './store/index_fs.js';
|
|
10
|
-
export * from './store/inode.js';
|
|
11
|
-
export * from './store/simple.js';
|
|
8
|
+
export * from './store/map.js';
|
|
12
9
|
export * from './store/store.js';
|
package/dist/backends/index.js
CHANGED
|
@@ -5,8 +5,5 @@ export * from './overlay.js';
|
|
|
5
5
|
export * from './passthrough.js';
|
|
6
6
|
export * from './port/fs.js';
|
|
7
7
|
export * from './store/fs.js';
|
|
8
|
-
export * from './store/
|
|
9
|
-
export * from './store/index_fs.js';
|
|
10
|
-
export * from './store/inode.js';
|
|
11
|
-
export * from './store/simple.js';
|
|
8
|
+
export * from './store/map.js';
|
|
12
9
|
export * from './store/store.js';
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { StoreFS } from './store/fs.js';
|
|
2
|
-
import {
|
|
2
|
+
import { SyncMapTransaction, type SyncMapStore } from './store/map.js';
|
|
3
3
|
/**
|
|
4
4
|
* A simple in-memory store
|
|
5
5
|
*/
|
|
6
|
-
export declare class InMemoryStore extends Map<number, Uint8Array> implements
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
export declare class InMemoryStore extends Map<number, Uint8Array> implements SyncMapStore {
|
|
7
|
+
readonly label?: string | undefined;
|
|
8
|
+
readonly flags: readonly [];
|
|
9
|
+
readonly name = "tmpfs";
|
|
10
|
+
constructor(label?: string | undefined);
|
|
9
11
|
sync(): Promise<void>;
|
|
10
12
|
clearSync(): void;
|
|
11
|
-
transaction():
|
|
13
|
+
transaction(): SyncMapTransaction;
|
|
12
14
|
}
|
|
13
15
|
declare const _InMemory: {
|
|
14
16
|
readonly name: "InMemory";
|
package/dist/backends/memory.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { StoreFS } from './store/fs.js';
|
|
2
|
-
import {
|
|
2
|
+
import { SyncMapTransaction } from './store/map.js';
|
|
3
3
|
/**
|
|
4
4
|
* A simple in-memory store
|
|
5
5
|
*/
|
|
6
6
|
export class InMemoryStore extends Map {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(label) {
|
|
8
8
|
super();
|
|
9
|
-
this.
|
|
9
|
+
this.label = label;
|
|
10
|
+
this.flags = [];
|
|
11
|
+
this.name = 'tmpfs';
|
|
10
12
|
}
|
|
11
13
|
async sync() { }
|
|
12
14
|
clearSync() {
|
|
13
15
|
this.clear();
|
|
14
16
|
}
|
|
15
17
|
transaction() {
|
|
16
|
-
return new
|
|
18
|
+
return new SyncMapTransaction(this);
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
const _InMemory = {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { File } from '../file.js';
|
|
2
|
-
import type { CreationOptions
|
|
1
|
+
import type { File } from '../internal/file.js';
|
|
2
|
+
import type { CreationOptions } from '../internal/filesystem.js';
|
|
3
3
|
import type { Stats } from '../stats.js';
|
|
4
|
-
import type { InodeLike } from '
|
|
5
|
-
import { FileSystem } from '../filesystem.js';
|
|
4
|
+
import type { InodeLike } from '../internal/inode.js';
|
|
5
|
+
import { FileSystem } from '../internal/filesystem.js';
|
|
6
6
|
/**
|
|
7
7
|
* Configuration options for OverlayFS instances.
|
|
8
8
|
*/
|
|
@@ -36,7 +36,6 @@ export declare class OverlayFS extends FileSystem {
|
|
|
36
36
|
private _deleteLogError?;
|
|
37
37
|
private _ready;
|
|
38
38
|
constructor({ writable, readable }: OverlayOptions);
|
|
39
|
-
metadata(): FileSystemMetadata;
|
|
40
39
|
sync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): Promise<void>;
|
|
41
40
|
syncSync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): void;
|
|
42
41
|
read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
|
package/dist/backends/overlay.js
CHANGED
|
@@ -50,10 +50,12 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
50
50
|
var e = new Error(message);
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
53
|
+
import { canary } from 'utilium';
|
|
54
|
+
import { Errno, ErrnoError } from '../internal/error.js';
|
|
55
|
+
import { LazyFile, parseFlag } from '../internal/file.js';
|
|
56
|
+
import { FileSystem } from '../internal/filesystem.js';
|
|
57
|
+
import { crit, err, info } from '../internal/log.js';
|
|
58
|
+
import { decodeUTF8, encodeUTF8 } from '../utils.js';
|
|
57
59
|
import { dirname, join } from '../vfs/path.js';
|
|
58
60
|
/** @internal */
|
|
59
61
|
const deletionLogPath = '/.deleted';
|
|
@@ -72,7 +74,7 @@ export class OverlayFS extends FileSystem {
|
|
|
72
74
|
await this._ready;
|
|
73
75
|
}
|
|
74
76
|
constructor({ writable, readable }) {
|
|
75
|
-
super();
|
|
77
|
+
super(0x62756c6c, readable.name);
|
|
76
78
|
this._isInitialized = false;
|
|
77
79
|
this._deletedFiles = new Set();
|
|
78
80
|
this._deleteLog = '';
|
|
@@ -83,17 +85,11 @@ export class OverlayFS extends FileSystem {
|
|
|
83
85
|
this._deleteLogUpdateNeeded = false;
|
|
84
86
|
this.writable = writable;
|
|
85
87
|
this.readable = readable;
|
|
86
|
-
if (this.writable.
|
|
87
|
-
throw new ErrnoError(Errno.EINVAL, 'Writable file
|
|
88
|
+
if (this.writable.attributes.has('no_write')) {
|
|
89
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Writable file can not be written to'));
|
|
88
90
|
}
|
|
89
91
|
this._ready = this._initialize();
|
|
90
92
|
}
|
|
91
|
-
metadata() {
|
|
92
|
-
return {
|
|
93
|
-
...super.metadata(),
|
|
94
|
-
name: OverlayFS.name,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
93
|
async sync(path, data, stats) {
|
|
98
94
|
await this.copyForWrite(path);
|
|
99
95
|
await this.writable.sync(path, data, stats);
|
|
@@ -133,10 +129,10 @@ export class OverlayFS extends FileSystem {
|
|
|
133
129
|
const { buffer } = await file.read(new Uint8Array(size));
|
|
134
130
|
this._deleteLog = decodeUTF8(buffer);
|
|
135
131
|
}
|
|
136
|
-
catch (
|
|
137
|
-
if (
|
|
138
|
-
throw err;
|
|
139
|
-
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (error.errno !== Errno.ENOENT)
|
|
134
|
+
throw err(error);
|
|
135
|
+
info('Overlay does not have a deletion log');
|
|
140
136
|
}
|
|
141
137
|
this._isInitialized = true;
|
|
142
138
|
this._reparseDeletionLog();
|
|
@@ -405,7 +401,7 @@ export class OverlayFS extends FileSystem {
|
|
|
405
401
|
}
|
|
406
402
|
checkInitialized() {
|
|
407
403
|
if (!this._isInitialized) {
|
|
408
|
-
throw new ErrnoError(Errno.EPERM, 'Overlay is not initialized');
|
|
404
|
+
throw crit(new ErrnoError(Errno.EPERM, 'Overlay is not initialized'), { fs: this });
|
|
409
405
|
}
|
|
410
406
|
if (!this._deleteLogError) {
|
|
411
407
|
return;
|
|
@@ -426,7 +422,7 @@ export class OverlayFS extends FileSystem {
|
|
|
426
422
|
createParentDirectoriesSync(path) {
|
|
427
423
|
let parent = dirname(path);
|
|
428
424
|
const toCreate = [];
|
|
429
|
-
const silence = canary(path);
|
|
425
|
+
const silence = canary(ErrnoError.With('EDEADLK', path));
|
|
430
426
|
while (!this.writable.existsSync(parent)) {
|
|
431
427
|
toCreate.push(parent);
|
|
432
428
|
parent = dirname(parent);
|
|
@@ -444,7 +440,7 @@ export class OverlayFS extends FileSystem {
|
|
|
444
440
|
async createParentDirectories(path) {
|
|
445
441
|
let parent = dirname(path);
|
|
446
442
|
const toCreate = [];
|
|
447
|
-
const silence = canary(path);
|
|
443
|
+
const silence = canary(ErrnoError.With('EDEADLK', path));
|
|
448
444
|
while (!(await this.writable.exists(parent))) {
|
|
449
445
|
toCreate.push(parent);
|
|
450
446
|
parent = dirname(parent);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type * as fs from 'node:fs';
|
|
2
|
-
import { File } from '../file.js';
|
|
3
|
-
import { FileSystem } from '../filesystem.js';
|
|
2
|
+
import { File } from '../internal/file.js';
|
|
3
|
+
import { FileSystem } from '../internal/filesystem.js';
|
|
4
|
+
import type { InodeLike } from '../internal/inode.js';
|
|
4
5
|
import { Stats } from '../stats.js';
|
|
5
|
-
import type { InodeLike } from './store/inode.js';
|
|
6
6
|
export type NodeFS = typeof fs;
|
|
7
7
|
export interface PassthroughOptions {
|
|
8
8
|
fs: NodeFS;
|
|
@@ -50,9 +50,9 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
50
50
|
var e = new Error(message);
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
|
-
import { ErrnoError } from '../error.js';
|
|
54
|
-
import { File } from '../file.js';
|
|
55
|
-
import { FileSystem } from '../filesystem.js';
|
|
53
|
+
import { ErrnoError } from '../internal/error.js';
|
|
54
|
+
import { File } from '../internal/file.js';
|
|
55
|
+
import { FileSystem } from '../internal/filesystem.js';
|
|
56
56
|
import { Stats } from '../stats.js';
|
|
57
57
|
import { join, resolve } from '../vfs/path.js';
|
|
58
58
|
class PassthroughFile extends File {
|
|
@@ -137,7 +137,7 @@ class PassthroughFile extends File {
|
|
|
137
137
|
}
|
|
138
138
|
export class PassthroughFS extends FileSystem {
|
|
139
139
|
constructor(nodeFS, prefix) {
|
|
140
|
-
super();
|
|
140
|
+
super(0x6e6f6465, 'nodefs');
|
|
141
141
|
this.nodeFS = nodeFS;
|
|
142
142
|
this.prefix = prefix;
|
|
143
143
|
}
|
|
@@ -426,8 +426,6 @@ export class PassthroughFS extends FileSystem {
|
|
|
426
426
|
if (fd)
|
|
427
427
|
this.nodeFS.closeSync(fd);
|
|
428
428
|
}
|
|
429
|
-
// unreachable
|
|
430
|
-
throw ErrnoError.With('EIO', path, 'read');
|
|
431
429
|
}
|
|
432
430
|
async write(path, buffer, offset) {
|
|
433
431
|
try {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ExtractProperties } from 'utilium';
|
|
2
|
+
import type { Inode, InodeLike } from '../..//internal/inode.js';
|
|
2
3
|
import type { MountConfiguration } from '../../config.js';
|
|
3
|
-
import type {
|
|
4
|
+
import type { File } from '../../internal/file.js';
|
|
5
|
+
import type { CreationOptions, FileSystemMetadata } from '../../internal/filesystem.js';
|
|
4
6
|
import type { Backend, FilesystemOf } from '../backend.js';
|
|
5
|
-
import
|
|
6
|
-
import type { File } from '../../file.js';
|
|
7
|
-
import { FileSystem } from '../../filesystem.js';
|
|
7
|
+
import { FileSystem } from '../../internal/filesystem.js';
|
|
8
8
|
import { Stats } from '../../stats.js';
|
|
9
9
|
import * as RPC from './rpc.js';
|
|
10
10
|
type FSMethods = ExtractProperties<FileSystem, (...args: any[]) => Promise<any> | FileSystemMetadata>;
|
|
@@ -33,7 +33,6 @@ export declare class PortFS extends PortFS_base {
|
|
|
33
33
|
* Constructs a new PortFS instance that connects with the FS running on `options.port`.
|
|
34
34
|
*/
|
|
35
35
|
constructor(options: RPC.Options);
|
|
36
|
-
metadata(): FileSystemMetadata;
|
|
37
36
|
protected rpc<const T extends FSMethod>(method: T, ...args: Parameters<FSMethods[T]>): Promise<Awaited<ReturnType<FSMethods[T]>>>;
|
|
38
37
|
ready(): Promise<void>;
|
|
39
38
|
rename(oldPath: string, newPath: string): Promise<void>;
|