@zenfs/core 2.7.2 → 2.7.3
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/fetch.d.ts +2 -0
- package/dist/backends/fetch.js +9 -1
- package/dist/internal/index_fs.d.ts +6 -0
- package/dist/internal/index_fs.js +20 -2
- package/dist/mixins/async.d.ts +5 -6
- package/dist/mixins/async.js +72 -9
- package/dist/node/sync.d.ts +7 -6
- package/dist/node/sync.js +19 -2
- package/package.json +4 -5
package/dist/backends/fetch.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export declare class FetchFS extends IndexFS {
|
|
|
47
47
|
protected _async(p: Promise<unknown>): void;
|
|
48
48
|
constructor(index: Index, baseUrl: string, requestInit?: RequestInit, remoteWrite?: boolean | undefined);
|
|
49
49
|
protected resize(path: string, inode: Inode, oldSize: number): Promise<void> | void;
|
|
50
|
+
protected _create(path: string, inode: Inode): Promise<void>;
|
|
51
|
+
protected _createSync(path: string, inode: Inode): void;
|
|
50
52
|
touch(path: string, metadata: InodeLike): Promise<void>;
|
|
51
53
|
touchSync(path: string, metadata: InodeLike): void;
|
|
52
54
|
protected remove(path: string): Promise<void>;
|
package/dist/backends/fetch.js
CHANGED
|
@@ -63,6 +63,14 @@ export class FetchFS extends IndexFS {
|
|
|
63
63
|
if (this.remoteWrite)
|
|
64
64
|
return requests.set(url, zeroes, { offset: oldSize, warn }, this.requestInit).catch(parseError);
|
|
65
65
|
}
|
|
66
|
+
async _create(path, inode) {
|
|
67
|
+
await requests
|
|
68
|
+
.set(this.baseUrl + path, new Uint8Array(inode.size), { warn, cacheOnly: !this.remoteWrite, method: 'PUT' }, this.requestInit)
|
|
69
|
+
.catch(parseError);
|
|
70
|
+
}
|
|
71
|
+
_createSync(path, inode) {
|
|
72
|
+
this._async(this._create(path, inode));
|
|
73
|
+
}
|
|
66
74
|
async touch(path, metadata) {
|
|
67
75
|
const inode = this.index.get(path) ?? _throw(withErrno('ENOENT'));
|
|
68
76
|
const oldSize = inode.size;
|
|
@@ -81,7 +89,7 @@ export class FetchFS extends IndexFS {
|
|
|
81
89
|
await requests.remove(this.baseUrl + path, { warn, cacheOnly: !this.remoteWrite }, this.requestInit);
|
|
82
90
|
}
|
|
83
91
|
removeSync(path) {
|
|
84
|
-
this._async(
|
|
92
|
+
this._async(this.remove(path));
|
|
85
93
|
}
|
|
86
94
|
async read(path, buffer, offset = 0, end) {
|
|
87
95
|
const inode = this.index.get(path);
|
|
@@ -5,6 +5,8 @@ import { Inode, type InodeLike } from './inode.js';
|
|
|
5
5
|
* A file system that uses an `Index` for metadata.
|
|
6
6
|
* @category Internals
|
|
7
7
|
* @internal
|
|
8
|
+
*
|
|
9
|
+
* @todo [breaking] replace the three method `create` system with something more intuitive, e.g. requiring subclasses to implement `createFile`, with this just exposing `create` for convenience.
|
|
8
10
|
*/
|
|
9
11
|
export declare abstract class IndexFS extends FileSystem {
|
|
10
12
|
readonly index: Index;
|
|
@@ -27,6 +29,10 @@ export declare abstract class IndexFS extends FileSystem {
|
|
|
27
29
|
unlinkSync(path: string): void;
|
|
28
30
|
rmdir(path: string): Promise<void>;
|
|
29
31
|
rmdirSync(path: string): void;
|
|
32
|
+
/** Create a new file in the underlying backend */
|
|
33
|
+
protected _create?(path: string, inode: Inode): Promise<void>;
|
|
34
|
+
/** Create a new file in the underlying backend */
|
|
35
|
+
protected _createSync?(path: string, inode: Inode): void;
|
|
30
36
|
protected create(path: string, options: CreationOptions): Inode;
|
|
31
37
|
createFile(path: string, options: CreationOptions): Promise<Inode>;
|
|
32
38
|
createFileSync(path: string, options: CreationOptions): Inode;
|
|
@@ -11,6 +11,8 @@ import { Inode } from './inode.js';
|
|
|
11
11
|
* A file system that uses an `Index` for metadata.
|
|
12
12
|
* @category Internals
|
|
13
13
|
* @internal
|
|
14
|
+
*
|
|
15
|
+
* @todo [breaking] replace the three method `create` system with something more intuitive, e.g. requiring subclasses to implement `createFile`, with this just exposing `create` for convenience.
|
|
14
16
|
*/
|
|
15
17
|
export class IndexFS extends FileSystem {
|
|
16
18
|
index;
|
|
@@ -165,10 +167,26 @@ export class IndexFS extends FileSystem {
|
|
|
165
167
|
return inode;
|
|
166
168
|
}
|
|
167
169
|
async createFile(path, options) {
|
|
168
|
-
|
|
170
|
+
const inode = this.create(path, { ...options, mode: options.mode | S_IFREG });
|
|
171
|
+
try {
|
|
172
|
+
await this._create?.(path, inode);
|
|
173
|
+
return inode;
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
this.index.delete(path);
|
|
177
|
+
throw e;
|
|
178
|
+
}
|
|
169
179
|
}
|
|
170
180
|
createFileSync(path, options) {
|
|
171
|
-
|
|
181
|
+
const inode = this.create(path, { ...options, mode: options.mode | S_IFREG });
|
|
182
|
+
try {
|
|
183
|
+
this._createSync?.(path, inode);
|
|
184
|
+
return inode;
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
this.index.delete(path);
|
|
188
|
+
throw e;
|
|
189
|
+
}
|
|
172
190
|
}
|
|
173
191
|
async mkdir(path, options) {
|
|
174
192
|
options = { ...options, mode: options.mode | S_IFDIR };
|
package/dist/mixins/async.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Semaphore } from 'kerium/locks';
|
|
1
2
|
import type { FileSystem } from '../internal/filesystem.js';
|
|
2
3
|
import { type _SyncFSKeys, type AsyncFSMethods, type Mixin } from './shared.js';
|
|
3
4
|
/**
|
|
@@ -12,13 +13,11 @@ export type AsyncOperation = {
|
|
|
12
13
|
* @category Internals
|
|
13
14
|
*/
|
|
14
15
|
export interface AsyncMixin extends Pick<FileSystem, Exclude<_SyncFSKeys, 'existsSync'>> {
|
|
15
|
-
/**
|
|
16
|
-
* @internal @protected
|
|
17
|
-
*/
|
|
16
|
+
/** @internal @protected */
|
|
18
17
|
_sync?: FileSystem;
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
/** Restrict how many files can be copied across at once @internal @protected */
|
|
19
|
+
_crossCopySemaphore?: Semaphore;
|
|
20
|
+
/** @deprecated Use {@link sync | `sync`} instead */
|
|
22
21
|
queueDone(): Promise<void>;
|
|
23
22
|
ready(): Promise<void>;
|
|
24
23
|
sync(): Promise<void>;
|
package/dist/mixins/async.js
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
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
|
+
});
|
|
1
53
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
54
|
import { withErrno } from 'kerium';
|
|
3
55
|
import { crit, debug, err } from 'kerium/log';
|
|
@@ -164,19 +216,30 @@ export function Async(FS) {
|
|
|
164
216
|
},
|
|
165
217
|
});
|
|
166
218
|
}
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
|
|
219
|
+
/** @internal @protected */
|
|
220
|
+
_crossCopySemaphore;
|
|
221
|
+
/** @internal */
|
|
170
222
|
async crossCopy(path) {
|
|
171
223
|
this.checkSync();
|
|
172
224
|
const stats = await this.stat(path);
|
|
173
225
|
if (!isDirectory(stats)) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
226
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
227
|
+
try {
|
|
228
|
+
const _ = __addDisposableResource(env_1, (await this._crossCopySemaphore?.get()) || { [Symbol.dispose]() { } }, false);
|
|
229
|
+
this._sync.createFileSync(path, stats);
|
|
230
|
+
const buffer = new Uint8Array(stats.size);
|
|
231
|
+
await this.read(path, buffer, 0, stats.size);
|
|
232
|
+
this._sync.writeSync(path, buffer, 0);
|
|
233
|
+
this._sync.touchSync(path, stats);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
catch (e_1) {
|
|
237
|
+
env_1.error = e_1;
|
|
238
|
+
env_1.hasError = true;
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
__disposeResources(env_1);
|
|
242
|
+
}
|
|
180
243
|
}
|
|
181
244
|
if (path !== '/') {
|
|
182
245
|
this._sync.mkdirSync(path, stats);
|
package/dist/node/sync.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BufferView } from 'node:buffer';
|
|
1
2
|
import type * as fs from 'node:fs';
|
|
2
3
|
import type { V_Context } from '../context.js';
|
|
3
4
|
import type { FileContents } from '../vfs/shared.js';
|
|
@@ -72,14 +73,14 @@ export declare function lopenSync(this: V_Context, path: fs.PathLike, flag: stri
|
|
|
72
73
|
* Synchronously reads the entire contents of a file.
|
|
73
74
|
* @option encoding The string encoding for the file contents. Defaults to `null`.
|
|
74
75
|
* @option flag Defaults to `'r'`.
|
|
76
|
+
* @option buffer A view (or a factory taking the file size) the contents are read into,
|
|
77
|
+
* instead of allocating a new buffer. It must be large enough to hold the entire file.
|
|
75
78
|
* @returns file contents
|
|
76
79
|
*/
|
|
77
|
-
export declare function readFileSync(this: V_Context, path: fs.PathOrFileDescriptor, options
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
export declare function readFileSync(this: V_Context, path: fs.PathOrFileDescriptor, options
|
|
81
|
-
flag?: string;
|
|
82
|
-
}) | BufferEncoding | null): string;
|
|
80
|
+
export declare function readFileSync<T extends NodeJS.ArrayBufferView>(this: V_Context, path: fs.PathOrFileDescriptor, options: fs.ReadFileSyncOptionsWithBuffer<T>): BufferView<T>;
|
|
81
|
+
export declare function readFileSync(this: V_Context, path: fs.PathOrFileDescriptor, options?: fs.ReadFileSyncOptionsWithBufferEncoding | null): NonSharedBuffer;
|
|
82
|
+
export declare function readFileSync(this: V_Context, path: fs.PathOrFileDescriptor, options: fs.ReadFileSyncOptionsWithStringEncoding | BufferEncoding): string;
|
|
83
|
+
export declare function readFileSync(this: V_Context, path: fs.PathOrFileDescriptor, options: fs.ReadFileSyncOptions): string | NonSharedBuffer;
|
|
83
84
|
/**
|
|
84
85
|
* Synchronously writes data to a file, replacing the file if it already exists.
|
|
85
86
|
*
|
package/dist/node/sync.js
CHANGED
|
@@ -175,6 +175,22 @@ openSync;
|
|
|
175
175
|
export function lopenSync(path, flag, mode) {
|
|
176
176
|
return toFD(_sync.open(this, path, { flag, mode, preserveSymlinks: true }));
|
|
177
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolves the `buffer` option of `readFileSync` into a buffer covering the first `size` bytes of the view.
|
|
180
|
+
* @hidden
|
|
181
|
+
*/
|
|
182
|
+
function intoBuffer(into, size) {
|
|
183
|
+
const isFn = typeof into == 'function';
|
|
184
|
+
const view = isFn ? into(size) : into;
|
|
185
|
+
const name = isFn ? 'options.buffer()' : 'options.buffer';
|
|
186
|
+
if (!ArrayBuffer.isView(view))
|
|
187
|
+
throw Object.assign(new TypeError(`The "options.buffer" property must be of type function or an instance of Buffer, TypedArray, or DataView. Received ${typeof view}`), { code: 'ERR_INVALID_ARG_TYPE' });
|
|
188
|
+
if (view.byteLength < size)
|
|
189
|
+
throw Object.assign(new TypeError(`The property '${name}.byteLength' is smaller than the file size of ${size} bytes. Received ${view.byteLength}`), {
|
|
190
|
+
code: 'ERR_INVALID_ARG_VALUE',
|
|
191
|
+
});
|
|
192
|
+
return Buffer.from(view.buffer, view.byteOffset, size);
|
|
193
|
+
}
|
|
178
194
|
export function readFileSync(path, _options = {}) {
|
|
179
195
|
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
180
196
|
try {
|
|
@@ -186,7 +202,8 @@ export function readFileSync(path, _options = {}) {
|
|
|
186
202
|
? fromFD(this, path)
|
|
187
203
|
: _sync.open(this, path.toString(), { flag: options.flag, mode: 0o644, preserveSymlinks: false }), false);
|
|
188
204
|
const { size } = file.stat();
|
|
189
|
-
const
|
|
205
|
+
const into = typeof _options == 'object' && _options !== null ? _options.buffer : undefined;
|
|
206
|
+
const data = into === undefined ? Buffer.alloc(size) : intoBuffer(into, size);
|
|
190
207
|
file.readSync(data, 0, size, 0);
|
|
191
208
|
return options.encoding ? data.toString(options.encoding) : data;
|
|
192
209
|
}
|
|
@@ -584,7 +601,7 @@ export function copyFileSync(source, destination, flags) {
|
|
|
584
601
|
destination = normalizePath.call(this, destination);
|
|
585
602
|
if (flags && flags & constants.COPYFILE_EXCL && existsSync.call(this, destination))
|
|
586
603
|
throw UV('EEXIST', 'copyFile', destination);
|
|
587
|
-
writeFileSync.call(this, destination, readFileSync.call(this, source));
|
|
604
|
+
writeFileSync.call(this, destination, readFileSync.call(this, source, {}));
|
|
588
605
|
emitChange(this, 'rename', destination.toString());
|
|
589
606
|
}
|
|
590
607
|
copyFileSync;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/core",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.3",
|
|
4
4
|
"description": "A filesystem, anywhere",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -69,16 +69,15 @@
|
|
|
69
69
|
"lint": "eslint src tests",
|
|
70
70
|
"test": "npx -s zenfs-test --clean; npx -s zenfs-test -abcpn; tests/fetch/run.sh; npx -s zenfs-test --report-only",
|
|
71
71
|
"test:native": "npx -s zenfs-test tests/native-setup.ts --verbose",
|
|
72
|
-
"build": "tsc
|
|
73
|
-
"
|
|
74
|
-
"dev": "tsc -p tsconfig.json --watch",
|
|
72
|
+
"build": "tsc --build",
|
|
73
|
+
"dev": "tsc --build --watch",
|
|
75
74
|
"prepublishOnly": "npm run build"
|
|
76
75
|
},
|
|
77
76
|
"dependencies": {
|
|
78
77
|
"@types/node": "^26.0.0",
|
|
79
78
|
"buffer": "^6.0.3",
|
|
80
79
|
"eventemitter3": "^5.0.1",
|
|
81
|
-
"kerium": "^1.
|
|
80
|
+
"kerium": "^1.5.0",
|
|
82
81
|
"memium": "^1.0.0",
|
|
83
82
|
"readable-stream": "^4.5.2",
|
|
84
83
|
"utilium": "^3.0.0"
|