@zenfs/core 1.9.2 → 1.9.4
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 +16 -2
- package/dist/backends/backend.js +9 -2
- package/dist/backends/fetch.d.ts +9 -0
- package/dist/backends/fetch.js +13 -3
- package/dist/backends/memory.d.ts +2 -0
- package/dist/backends/memory.js +2 -0
- package/dist/backends/overlay.d.ts +2 -0
- package/dist/backends/overlay.js +1 -0
- package/dist/backends/passthrough.d.ts +4 -0
- package/dist/backends/port/fs.d.ts +8 -2
- package/dist/backends/port/fs.js +6 -0
- package/dist/backends/store/fs.d.ts +2 -4
- package/dist/backends/store/fs.js +2 -4
- package/dist/backends/store/map.d.ts +6 -0
- package/dist/backends/store/map.js +4 -0
- package/dist/backends/store/simple.d.ts +3 -0
- package/dist/backends/store/simple.js +1 -0
- package/dist/backends/store/store.d.ts +12 -1
- package/dist/backends/store/store.js +5 -1
- package/dist/config.d.ts +9 -15
- package/dist/config.js +8 -5
- package/dist/context.d.ts +3 -4
- package/dist/context.js +1 -1
- package/dist/internal/credentials.d.ts +9 -0
- package/dist/internal/credentials.js +7 -0
- package/dist/internal/devices.d.ts +14 -0
- package/dist/internal/devices.js +10 -0
- package/dist/internal/error.d.ts +6 -0
- package/dist/internal/error.js +3 -0
- package/dist/internal/file.d.ts +23 -0
- package/dist/internal/file.js +23 -1
- package/dist/internal/file_index.d.ts +2 -1
- package/dist/internal/file_index.js +2 -1
- package/dist/internal/filesystem.d.ts +9 -0
- package/dist/internal/filesystem.js +1 -0
- package/dist/internal/index_fs.d.ts +3 -1
- package/dist/internal/index_fs.js +7 -3
- package/dist/internal/inode.d.ts +8 -0
- package/dist/internal/inode.js +1 -0
- package/dist/mixins/async.d.ts +6 -2
- package/dist/mixins/async.js +1 -1
- package/dist/mixins/mutexed.d.ts +6 -0
- package/dist/mixins/mutexed.js +6 -0
- package/dist/mixins/readonly.d.ts +1 -0
- package/dist/mixins/readonly.js +1 -0
- package/dist/mixins/shared.d.ts +3 -0
- package/dist/mixins/sync.d.ts +1 -0
- package/dist/mixins/sync.js +1 -0
- package/dist/vfs/promises.d.ts +2 -2
- package/dist/vfs/promises.js +71 -78
- package/dist/vfs/shared.d.ts +14 -1
- package/dist/vfs/shared.js +4 -6
- package/dist/vfs/sync.d.ts +2 -2
- package/dist/vfs/sync.js +48 -48
- package/dist/vfs/types.d.ts +1 -13
- package/package.json +1 -1
- package/readme.md +4 -0
- package/tests/backend/fetch.test.ts +3 -2
- package/dist/vfs/cache.d.ts +0 -46
- package/dist/vfs/cache.js +0 -75
package/dist/vfs/sync.js
CHANGED
|
@@ -56,7 +56,6 @@ import { Errno, ErrnoError } from '../internal/error.js';
|
|
|
56
56
|
import { flagToMode, isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../internal/file.js';
|
|
57
57
|
import { BigIntStats } from '../stats.js';
|
|
58
58
|
import { decodeUTF8, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
59
|
-
import * as cache from './cache.js';
|
|
60
59
|
import { config } from './config.js';
|
|
61
60
|
import * as constants from './constants.js';
|
|
62
61
|
import { Dir, Dirent } from './dir.js';
|
|
@@ -154,7 +153,7 @@ export function unlinkSync(path) {
|
|
|
154
153
|
path = normalizePath(path);
|
|
155
154
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
156
155
|
try {
|
|
157
|
-
if (config.checkAccess && !
|
|
156
|
+
if (config.checkAccess && !fs.statSync(resolved).hasAccess(constants.W_OK, this)) {
|
|
158
157
|
throw ErrnoError.With('EACCES', resolved, 'unlink');
|
|
159
158
|
}
|
|
160
159
|
fs.unlinkSync(resolved);
|
|
@@ -426,7 +425,7 @@ export function rmdirSync(path) {
|
|
|
426
425
|
path = normalizePath(path);
|
|
427
426
|
const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
|
|
428
427
|
try {
|
|
429
|
-
const stats =
|
|
428
|
+
const stats = fs.statSync(resolved);
|
|
430
429
|
if (!stats.isDirectory()) {
|
|
431
430
|
throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
|
|
432
431
|
}
|
|
@@ -484,8 +483,7 @@ export function readdirSync(path, options) {
|
|
|
484
483
|
const { fs, path: resolved } = resolveMount(realpathSync.call(this, path), this);
|
|
485
484
|
let entries;
|
|
486
485
|
try {
|
|
487
|
-
const stats =
|
|
488
|
-
cache.stats.set(path, stats);
|
|
486
|
+
const stats = fs.statSync(resolved);
|
|
489
487
|
if (config.checkAccess && !stats.hasAccess(constants.R_OK, this)) {
|
|
490
488
|
throw ErrnoError.With('EACCES', resolved, 'readdir');
|
|
491
489
|
}
|
|
@@ -500,8 +498,7 @@ export function readdirSync(path, options) {
|
|
|
500
498
|
// Iterate over entries and handle recursive case if needed
|
|
501
499
|
const values = [];
|
|
502
500
|
for (const entry of entries) {
|
|
503
|
-
const entryStat =
|
|
504
|
-
cache.stats.set(join(path, entry), entryStat);
|
|
501
|
+
const entryStat = fs.statSync(join(resolved, entry));
|
|
505
502
|
if (options === null || options === void 0 ? void 0 : options.withFileTypes) {
|
|
506
503
|
values.push(new Dirent(entry, entryStat));
|
|
507
504
|
}
|
|
@@ -513,7 +510,7 @@ export function readdirSync(path, options) {
|
|
|
513
510
|
}
|
|
514
511
|
if (!entryStat.isDirectory() || !(options === null || options === void 0 ? void 0 : options.recursive))
|
|
515
512
|
continue;
|
|
516
|
-
for (const subEntry of readdirSync.call(this, join(path, entry),
|
|
513
|
+
for (const subEntry of readdirSync.call(this, join(path, entry), options)) {
|
|
517
514
|
if (subEntry instanceof Dirent) {
|
|
518
515
|
subEntry.path = join(entry, subEntry.path);
|
|
519
516
|
values.push(subEntry);
|
|
@@ -526,9 +523,6 @@ export function readdirSync(path, options) {
|
|
|
526
523
|
}
|
|
527
524
|
}
|
|
528
525
|
}
|
|
529
|
-
if (!(options === null || options === void 0 ? void 0 : options._isIndirect)) {
|
|
530
|
-
cache.stats.clear();
|
|
531
|
-
}
|
|
532
526
|
return values;
|
|
533
527
|
}
|
|
534
528
|
readdirSync;
|
|
@@ -627,52 +621,64 @@ export function lutimesSync(path, atime, mtime) {
|
|
|
627
621
|
closeSync(fd);
|
|
628
622
|
}
|
|
629
623
|
lutimesSync;
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
624
|
+
/**
|
|
625
|
+
* Resolves the mount and real path for a path.
|
|
626
|
+
* Additionally, any stats fetched will be returned for de-duplication
|
|
627
|
+
* @internal @hidden
|
|
628
|
+
*/
|
|
629
|
+
function _resolveSync($, path, preserveSymlinks) {
|
|
630
|
+
if (preserveSymlinks) {
|
|
631
|
+
const resolved = resolveMount(path, $);
|
|
632
|
+
const stats = resolved.fs.statSync(resolved.path);
|
|
633
|
+
return { ...resolved, fullPath: path, stats };
|
|
634
|
+
}
|
|
635
635
|
/* Try to resolve it directly. If this works,
|
|
636
636
|
that means we don't need to perform any resolution for parent directories. */
|
|
637
637
|
try {
|
|
638
|
-
const
|
|
638
|
+
const resolved = resolveMount(path, $);
|
|
639
639
|
// Stat it to make sure it exists
|
|
640
|
-
const stats = fs.statSync(
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const target = resolve(dirname(resolvedPath), readlinkSync.call(this, resolvedPath, options).toString());
|
|
644
|
-
real = cache.paths.get(((this === null || this === void 0 ? void 0 : this.root) || '') + target) || realpathSync.call(this, target);
|
|
645
|
-
cache.paths.set(ctx_path, real);
|
|
640
|
+
const stats = resolved.fs.statSync(resolved.path);
|
|
641
|
+
if (!stats.isSymbolicLink()) {
|
|
642
|
+
return { ...resolved, fullPath: path, stats };
|
|
646
643
|
}
|
|
647
|
-
|
|
648
|
-
return
|
|
644
|
+
const target = resolve(dirname(path), readlinkSync.call($, path).toString());
|
|
645
|
+
return _resolveSync($, target);
|
|
649
646
|
}
|
|
650
647
|
catch {
|
|
651
648
|
// Go the long way
|
|
652
649
|
}
|
|
653
650
|
const { base, dir } = parse(path);
|
|
654
|
-
const realDir = dir == '/' ? '/' :
|
|
655
|
-
const
|
|
656
|
-
const
|
|
651
|
+
const realDir = dir == '/' ? '/' : realpathSync.call($, dir);
|
|
652
|
+
const maybePath = join(realDir, base);
|
|
653
|
+
const resolved = resolveMount(maybePath, $);
|
|
657
654
|
try {
|
|
658
|
-
const stats =
|
|
659
|
-
cache.stats.set(lpath, stats);
|
|
655
|
+
const stats = resolved.fs.statSync(resolved.path);
|
|
660
656
|
if (!stats.isSymbolicLink()) {
|
|
661
|
-
|
|
662
|
-
return lpath;
|
|
657
|
+
return { ...resolved, fullPath: maybePath, stats };
|
|
663
658
|
}
|
|
664
|
-
const target = resolve(realDir, readlinkSync.call(
|
|
665
|
-
const real =
|
|
666
|
-
|
|
667
|
-
return real;
|
|
659
|
+
const target = resolve(realDir, readlinkSync.call($, maybePath).toString());
|
|
660
|
+
const real = realpathSync.call($, target);
|
|
661
|
+
return { ...resolved, fullPath: real, stats };
|
|
668
662
|
}
|
|
669
663
|
catch (e) {
|
|
670
664
|
if (e.code == 'ENOENT') {
|
|
671
|
-
return path;
|
|
665
|
+
return { ...resolved, fullPath: path };
|
|
672
666
|
}
|
|
673
|
-
throw fixError(e, { [
|
|
667
|
+
throw fixError(e, { [resolved.path]: maybePath });
|
|
674
668
|
}
|
|
675
669
|
}
|
|
670
|
+
export function realpathSync(path, options) {
|
|
671
|
+
var _a;
|
|
672
|
+
const encoding = typeof options == 'string' ? options : ((_a = options === null || options === void 0 ? void 0 : options.encoding) !== null && _a !== void 0 ? _a : 'utf8');
|
|
673
|
+
path = normalizePath(path);
|
|
674
|
+
const { fullPath } = _resolveSync(this, path);
|
|
675
|
+
if (encoding == 'utf8' || encoding == 'utf-8')
|
|
676
|
+
return fullPath;
|
|
677
|
+
const buf = Buffer.from(fullPath, 'utf-8');
|
|
678
|
+
if (encoding == 'buffer')
|
|
679
|
+
return buf;
|
|
680
|
+
return buf.toString(encoding);
|
|
681
|
+
}
|
|
676
682
|
realpathSync;
|
|
677
683
|
export function accessSync(path, mode = 0o600) {
|
|
678
684
|
if (!config.checkAccess)
|
|
@@ -690,21 +696,19 @@ export function rmSync(path, options) {
|
|
|
690
696
|
path = normalizePath(path);
|
|
691
697
|
let stats;
|
|
692
698
|
try {
|
|
693
|
-
stats =
|
|
699
|
+
stats = lstatSync.bind(this)(path);
|
|
694
700
|
}
|
|
695
701
|
catch (error) {
|
|
696
702
|
if (error.code != 'ENOENT' || !(options === null || options === void 0 ? void 0 : options.force))
|
|
697
703
|
throw error;
|
|
698
704
|
}
|
|
699
|
-
if (!stats)
|
|
705
|
+
if (!stats)
|
|
700
706
|
return;
|
|
701
|
-
}
|
|
702
|
-
cache.stats.set(path, stats);
|
|
703
707
|
switch (stats.mode & constants.S_IFMT) {
|
|
704
708
|
case constants.S_IFDIR:
|
|
705
709
|
if (options === null || options === void 0 ? void 0 : options.recursive) {
|
|
706
|
-
for (const entry of readdirSync.call(this, path
|
|
707
|
-
rmSync.call(this, join(path, entry),
|
|
710
|
+
for (const entry of readdirSync.call(this, path)) {
|
|
711
|
+
rmSync.call(this, join(path, entry), options);
|
|
708
712
|
}
|
|
709
713
|
}
|
|
710
714
|
rmdirSync.call(this, path);
|
|
@@ -718,12 +722,8 @@ export function rmSync(path, options) {
|
|
|
718
722
|
case constants.S_IFIFO:
|
|
719
723
|
case constants.S_IFSOCK:
|
|
720
724
|
default:
|
|
721
|
-
cache.stats.clear();
|
|
722
725
|
throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
|
|
723
726
|
}
|
|
724
|
-
if (!(options === null || options === void 0 ? void 0 : options._isIndirect)) {
|
|
725
|
-
cache.stats.clear();
|
|
726
|
-
}
|
|
727
727
|
}
|
|
728
728
|
rmSync;
|
|
729
729
|
export function mkdtempSync(prefix, options) {
|
package/dist/vfs/types.d.ts
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import type * as fs from 'node:fs';
|
|
2
2
|
export type FileContents = ArrayBufferView | string;
|
|
3
|
-
/**
|
|
4
|
-
* Options used for caching, among other things.
|
|
5
|
-
* @internal @hidden *UNSTABLE*
|
|
6
|
-
*/
|
|
7
|
-
export interface InternalOptions {
|
|
8
|
-
/**
|
|
9
|
-
* If true, then this readdir was called from another function.
|
|
10
|
-
* In this case, don't clear the cache when done.
|
|
11
|
-
* @internal *UNSTABLE*
|
|
12
|
-
*/
|
|
13
|
-
_isIndirect?: boolean;
|
|
14
|
-
}
|
|
15
3
|
/**
|
|
16
4
|
* @internal @hidden Used for the internal `_open` functions
|
|
17
5
|
*/
|
|
@@ -27,7 +15,7 @@ export interface OpenOptions {
|
|
|
27
15
|
*/
|
|
28
16
|
allowDirectory?: boolean;
|
|
29
17
|
}
|
|
30
|
-
export interface ReaddirOptions
|
|
18
|
+
export interface ReaddirOptions {
|
|
31
19
|
withFileTypes?: boolean;
|
|
32
20
|
recursive?: boolean;
|
|
33
21
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Overview
|
|
3
|
+
---
|
|
4
|
+
|
|
1
5
|
# ZenFS
|
|
2
6
|
|
|
3
7
|
ZenFS is a cross-platform library that emulates the [NodeJS filesystem API](http://nodejs.org/api/fs.html). It works using a system of backends, which are used by ZenFS to store and retrieve data. ZenFS can also integrate with other tools.
|
|
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
4
|
import { Worker } from 'node:worker_threads';
|
|
5
|
-
import { Fetch, configureSingle, fs } from '../../dist/index.js';
|
|
5
|
+
import { Fetch, configureSingle, fs, mounts, type FetchFS } from '../../dist/index.js';
|
|
6
6
|
import { baseUrl, defaultEntries, indexPath, whenServerReady } from '../fetch/config.js';
|
|
7
7
|
|
|
8
8
|
const server = new Worker(join(import.meta.dirname, '../fetch/server.js'));
|
|
@@ -40,8 +40,9 @@ await suite('Fetch with `disableAsyncCache`', () => {
|
|
|
40
40
|
assert.deepEqual(entries, [...defaultEntries, 'example', 'duck']);
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
test('Uncached synchronous operations throw', () => {
|
|
43
|
+
test('Uncached synchronous operations throw', async () => {
|
|
44
44
|
assert.throws(() => fs.readFileSync('/x.txt', 'utf8'), { code: 'EAGAIN' });
|
|
45
|
+
await (mounts.get('/') as FetchFS)._asyncDone;
|
|
45
46
|
});
|
|
46
47
|
});
|
|
47
48
|
|
package/dist/vfs/cache.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { Stats } from '../stats.js';
|
|
2
|
-
/**
|
|
3
|
-
* Used for caching data
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
export declare class Cache<T> {
|
|
7
|
-
isEnabled: boolean;
|
|
8
|
-
protected sync: Map<string, T>;
|
|
9
|
-
protected async: Map<string, Promise<T>>;
|
|
10
|
-
/**
|
|
11
|
-
* Whether the data exists in the cache
|
|
12
|
-
*/
|
|
13
|
-
has(path: string): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Gets data from the cache, if is exists and the cache is enabled.
|
|
16
|
-
*/
|
|
17
|
-
get(path: string): T | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Adds data if the cache is enabled
|
|
20
|
-
*/
|
|
21
|
-
set(path: string, value: T): void;
|
|
22
|
-
/**
|
|
23
|
-
* Whether the data exists in the cache
|
|
24
|
-
*/
|
|
25
|
-
hasAsync(path: string): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Gets data from the cache, if it exists and the cache is enabled.
|
|
28
|
-
*/
|
|
29
|
-
getAsync(path: string): Promise<T> | undefined;
|
|
30
|
-
/**
|
|
31
|
-
* Adds data if the cache is enabled
|
|
32
|
-
*/
|
|
33
|
-
setAsync(path: string, value: Promise<T>): void;
|
|
34
|
-
/**
|
|
35
|
-
* Clears the cache if it is enabled
|
|
36
|
-
*/
|
|
37
|
-
clear(): void;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Used to cache
|
|
41
|
-
*/
|
|
42
|
-
export declare const stats: Cache<Stats>;
|
|
43
|
-
/**
|
|
44
|
-
* Used to cache realpath lookups
|
|
45
|
-
*/
|
|
46
|
-
export declare const paths: Cache<string>;
|
package/dist/vfs/cache.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/* Experimental caching */
|
|
2
|
-
/**
|
|
3
|
-
* Used for caching data
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
export class Cache {
|
|
7
|
-
constructor() {
|
|
8
|
-
this.isEnabled = false;
|
|
9
|
-
this.sync = new Map();
|
|
10
|
-
this.async = new Map();
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Whether the data exists in the cache
|
|
14
|
-
*/
|
|
15
|
-
has(path) {
|
|
16
|
-
return this.isEnabled && this.sync.has(path);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Gets data from the cache, if is exists and the cache is enabled.
|
|
20
|
-
*/
|
|
21
|
-
get(path) {
|
|
22
|
-
if (!this.isEnabled)
|
|
23
|
-
return;
|
|
24
|
-
return this.sync.get(path);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Adds data if the cache is enabled
|
|
28
|
-
*/
|
|
29
|
-
set(path, value) {
|
|
30
|
-
if (!this.isEnabled)
|
|
31
|
-
return;
|
|
32
|
-
this.sync.set(path, value);
|
|
33
|
-
this.async.set(path, Promise.resolve(value));
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Whether the data exists in the cache
|
|
37
|
-
*/
|
|
38
|
-
hasAsync(path) {
|
|
39
|
-
return this.isEnabled && this.async.has(path);
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Gets data from the cache, if it exists and the cache is enabled.
|
|
43
|
-
*/
|
|
44
|
-
getAsync(path) {
|
|
45
|
-
if (!this.isEnabled)
|
|
46
|
-
return;
|
|
47
|
-
return this.async.get(path);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Adds data if the cache is enabled
|
|
51
|
-
*/
|
|
52
|
-
setAsync(path, value) {
|
|
53
|
-
if (!this.isEnabled)
|
|
54
|
-
return;
|
|
55
|
-
this.async.set(path, value);
|
|
56
|
-
void value.then(v => this.sync.set(path, v));
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Clears the cache if it is enabled
|
|
60
|
-
*/
|
|
61
|
-
clear() {
|
|
62
|
-
if (!this.isEnabled)
|
|
63
|
-
return;
|
|
64
|
-
this.sync.clear();
|
|
65
|
-
this.async.clear();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Used to cache
|
|
70
|
-
*/
|
|
71
|
-
export const stats = new Cache();
|
|
72
|
-
/**
|
|
73
|
-
* Used to cache realpath lookups
|
|
74
|
-
*/
|
|
75
|
-
export const paths = new Cache();
|