@zenfs/core 1.8.8 → 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 +19 -16
- 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/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/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
package/tests/fs/stat.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
-
import { credentials } from '../../dist/
|
|
3
|
+
import { credentials } from '../../dist/index.js';
|
|
4
4
|
import { Stats } from '../../dist/stats.js';
|
|
5
5
|
import { fs } from '../common.js';
|
|
6
6
|
|
package/tests/fs/times.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
3
|
import { wait } from 'utilium';
|
|
4
|
-
import { ErrnoError } from '../../dist/
|
|
4
|
+
import { ErrnoError } from '../../dist/index.js';
|
|
5
5
|
import type { StatsLike } from '../../dist/stats.js';
|
|
6
6
|
import { fs } from '../common.js';
|
|
7
7
|
|
package/tests/fs/watch.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { suite, test } from 'node:test';
|
|
|
3
3
|
import { fs, type Stats } from '../common.js';
|
|
4
4
|
|
|
5
5
|
const testDir = '/test-watch-dir';
|
|
6
|
-
const testFile =
|
|
6
|
+
const testFile = testDir + '/test.txt';
|
|
7
7
|
|
|
8
8
|
await fs.promises.mkdir(testDir);
|
|
9
9
|
await fs.promises.writeFile(testFile, 'Initial content');
|
|
@@ -11,7 +11,7 @@ await fs.promises.writeFile(testFile, 'Initial content');
|
|
|
11
11
|
/**
|
|
12
12
|
* @todo convert using watcher to void discards pending ES proposal
|
|
13
13
|
*/
|
|
14
|
-
suite('Watch Features', () => {
|
|
14
|
+
await suite('Watch Features', () => {
|
|
15
15
|
test('fs.watch should emit events on file change', async () => {
|
|
16
16
|
using watcher = fs.watch(testFile, (eventType, filename) => {
|
|
17
17
|
assert.equal(eventType, 'change');
|
|
@@ -67,14 +67,14 @@ suite('Watch Features', () => {
|
|
|
67
67
|
assert.equal(filename, 'newFile.txt');
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
await fs.promises.writeFile(
|
|
70
|
+
await fs.promises.writeFile(testDir + '/newFile.txt', 'Content');
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
test('fs.watch should detect file renames', async () => {
|
|
74
|
-
const oldFileName =
|
|
75
|
-
const newFileName =
|
|
76
|
-
const oldFile =
|
|
77
|
-
const newFile =
|
|
74
|
+
const oldFileName = 'oldFile.txt';
|
|
75
|
+
const newFileName = 'newFile.txt';
|
|
76
|
+
const oldFile = testDir + '/' + oldFileName;
|
|
77
|
+
const newFile = testDir + '/' + newFileName;
|
|
78
78
|
|
|
79
79
|
await fs.promises.writeFile(oldFile, 'Some content');
|
|
80
80
|
const oldFileResolver = Promise.withResolvers<void>();
|
|
@@ -84,6 +84,7 @@ suite('Watch Features', () => {
|
|
|
84
84
|
[oldFileName]: { resolver: oldFileResolver, eventType: 'rename' },
|
|
85
85
|
[newFileName]: { resolver: newFileResolver, eventType: 'change' },
|
|
86
86
|
};
|
|
87
|
+
|
|
87
88
|
using watcher = fs.watch(testDir, (eventType, filename) => {
|
|
88
89
|
const resolver = fileResolvers[filename];
|
|
89
90
|
assert.notEqual(resolver, undefined); // should have a resolver so file is expected
|
|
@@ -116,41 +117,39 @@ suite('Watch Features', () => {
|
|
|
116
117
|
|
|
117
118
|
const watcher = fs.promises.watch(tempFile);
|
|
118
119
|
|
|
119
|
-
const
|
|
120
|
-
(async () => {
|
|
120
|
+
const promise = (async () => {
|
|
121
121
|
for await (const event of watcher) {
|
|
122
122
|
assert.equal(event.eventType, 'rename');
|
|
123
123
|
assert.equal(event.filename, 'tempFile.txt');
|
|
124
|
-
|
|
124
|
+
return;
|
|
125
125
|
}
|
|
126
|
-
resolve();
|
|
127
126
|
})();
|
|
128
127
|
|
|
129
128
|
await fs.promises.unlink(tempFile);
|
|
129
|
+
await watcher.return!();
|
|
130
130
|
await promise;
|
|
131
131
|
});
|
|
132
|
+
|
|
132
133
|
test('fs.promises.watch should detect file creations recursively', async () => {
|
|
133
|
-
const
|
|
134
|
-
const subDir = `${testDir}sub-dir`;
|
|
134
|
+
const subDir = `${testDir}/sub-dir`;
|
|
135
135
|
const tempFile = `${subDir}/tempFile.txt`;
|
|
136
136
|
await fs.promises.mkdir(subDir);
|
|
137
|
-
const watcher = fs.promises.watch(
|
|
137
|
+
const watcher = fs.promises.watch('/');
|
|
138
138
|
|
|
139
139
|
await fs.promises.writeFile(tempFile, 'Temporary content');
|
|
140
|
-
const
|
|
141
|
-
(async () => {
|
|
140
|
+
const promise = (async () => {
|
|
142
141
|
for await (const event of watcher) {
|
|
143
142
|
assert.equal(event.eventType, 'rename');
|
|
144
|
-
assert.equal(event.filename, tempFile.
|
|
145
|
-
|
|
143
|
+
assert.equal(event.filename, tempFile.slice(1));
|
|
144
|
+
return;
|
|
146
145
|
}
|
|
147
|
-
resolve();
|
|
148
146
|
})();
|
|
149
147
|
|
|
150
148
|
await fs.promises.unlink(tempFile);
|
|
149
|
+
await watcher.return!();
|
|
151
150
|
await promise;
|
|
152
151
|
});
|
|
153
|
-
}).then(async () => {
|
|
154
|
-
await fs.promises.rm(testFile);
|
|
155
|
-
await fs.promises.rm(testDir, { recursive: true, force: true });
|
|
156
152
|
});
|
|
153
|
+
|
|
154
|
+
await fs.promises.rm(testFile);
|
|
155
|
+
await fs.promises.rm(testDir, { recursive: true, force: true });
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
3
4
|
import { fs } from '../common.js';
|
|
5
|
+
import { join } from 'node:path/posix';
|
|
6
|
+
import { data as dataPath } from '../setup.js';
|
|
4
7
|
|
|
5
|
-
const
|
|
6
|
-
'南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、经济现状。\n';
|
|
8
|
+
const utf8example = readFileSync(join(dataPath, 'utf8.txt'), 'utf8');
|
|
7
9
|
|
|
8
10
|
suite('writeFile', () => {
|
|
9
11
|
test('write and read file with specified content', async () => {
|
|
10
12
|
const filename = 'test.txt';
|
|
11
|
-
await fs.promises.writeFile(filename,
|
|
13
|
+
await fs.promises.writeFile(filename, utf8example);
|
|
12
14
|
const data = await fs.promises.readFile(filename);
|
|
13
|
-
assert.equal(data.length, Buffer.from(
|
|
15
|
+
assert.equal(data.length, Buffer.from(utf8example).length);
|
|
14
16
|
await fs.promises.unlink(filename);
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
test('write and read file using buffer', async () => {
|
|
18
20
|
const filename = 'test2.txt';
|
|
19
|
-
const expected = Buffer.from(
|
|
21
|
+
const expected = Buffer.from(utf8example, 'utf8');
|
|
20
22
|
|
|
21
23
|
await fs.promises.writeFile(filename, expected);
|
|
22
24
|
const actual = await fs.promises.readFile(filename);
|
|
@@ -26,8 +28,7 @@ suite('writeFile', () => {
|
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
test('write base64 data to a file and read it back asynchronously', async () => {
|
|
29
|
-
const data =
|
|
30
|
-
'/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAQABADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDhfBUFl/wkOmPqKJJZw3aiZFBw4z93jnkkc9u9dj8XLfSI/EBt7DTo7ea2Ox5YXVo5FC7gTjq24nJPXNVtO0KATRvNHCIg3zoWJWQHqp+o4pun+EtJ0zxBq8mnLJa2d1L50NvnKRjJBUE5PAx3NYxxUY0pRtvYHSc5Ka2X9d7H/9k=';
|
|
31
|
+
const data = readFileSync(join(dataPath, 'image.jpg'), 'base64');
|
|
31
32
|
|
|
32
33
|
const buffer = Buffer.from(data, 'base64');
|
|
33
34
|
const filePath = 'test.jpg';
|
package/tests/readme.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Tests
|
|
2
2
|
|
|
3
|
-
-
|
|
4
|
-
-
|
|
5
|
-
-
|
|
3
|
+
- `data` contains files used in the tests. It is copied into the root of the virtual file system.
|
|
4
|
+
- `fs` contains tests for the exported `fs` module
|
|
5
|
+
- `port` contains tests for the port backends
|
package/tests/setup/context.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { bindContext } from '../../dist/context.js';
|
|
2
2
|
import { fs as _fs } from '../../dist/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { copySync, data } from '../setup.js';
|
|
4
4
|
|
|
5
5
|
_fs.mkdirSync('/new_root');
|
|
6
6
|
|
|
7
7
|
export const { fs } = bindContext('/new_root');
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
copySync(data, fs);
|
package/tests/setup/index.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path/posix';
|
|
3
3
|
import { configureSingle, InMemory, InMemoryStore, mounts, Overlay, Readonly, resolveMountConfig, StoreFS } from '../../dist/index.js';
|
|
4
4
|
import { S_IFDIR } from '../../dist/vfs/constants.js';
|
|
5
|
-
import {
|
|
5
|
+
import { copySync, data } from '../setup.js';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
copySync(data);
|
|
8
8
|
|
|
9
9
|
const index = (mounts.get('/') as StoreFS).createIndexSync();
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ class MockFS extends Readonly(StoreFS) {
|
|
|
13
13
|
super(new InMemoryStore());
|
|
14
14
|
this.loadIndexSync(index);
|
|
15
15
|
|
|
16
|
-
using tx = this.
|
|
16
|
+
using tx = this.transaction();
|
|
17
17
|
|
|
18
18
|
for (const [path, node] of index) {
|
|
19
19
|
if (node.mode & S_IFDIR) continue;
|
package/tests/setup/memory.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { copySync, data } from '../setup.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
copySync(data);
|
package/tests/setup/port.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MessageChannel } from 'node:worker_threads';
|
|
2
2
|
import { InMemory, Port, configureSingle, fs, resolveMountConfig, resolveRemoteMount } from '../../dist/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { copySync, data } from '../setup.js';
|
|
4
4
|
|
|
5
5
|
const { port1: localPort, port2: remotePort } = new MessageChannel();
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ fs.umount('/');
|
|
|
8
8
|
const tmpfs = await resolveMountConfig({ backend: InMemory, name: 'tmp' });
|
|
9
9
|
|
|
10
10
|
fs.mount('/', tmpfs);
|
|
11
|
-
|
|
11
|
+
copySync(data, fs);
|
|
12
12
|
|
|
13
13
|
await resolveRemoteMount(remotePort, tmpfs);
|
|
14
14
|
|
package/tests/setup.ts
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
1
2
|
import { join, relative } from 'node:path';
|
|
2
|
-
import { statSync, readFileSync, readdirSync, existsSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import { fs as _fs } from '../dist/index.js';
|
|
4
4
|
|
|
5
5
|
export const data = join(import.meta.dirname, 'data');
|
|
6
6
|
|
|
7
7
|
export const tmp = join(import.meta.dirname, 'tmp');
|
|
8
8
|
|
|
9
|
-
if (!existsSync(tmp))
|
|
10
|
-
|
|
9
|
+
if (!existsSync(tmp)) mkdirSync(tmp);
|
|
10
|
+
|
|
11
|
+
export async function copyAsync(_path: string, fs: typeof _fs = _fs): Promise<void> {
|
|
12
|
+
const path = relative(data, _path) || '/';
|
|
13
|
+
const stats = statSync(_path);
|
|
14
|
+
|
|
15
|
+
if (!stats.isDirectory()) {
|
|
16
|
+
await fs.promises.writeFile(path, readFileSync(_path));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (path != '/') {
|
|
21
|
+
await fs.promises.mkdir(path);
|
|
22
|
+
}
|
|
23
|
+
for (const file of readdirSync(_path)) {
|
|
24
|
+
await copyAsync(join(_path, file), fs);
|
|
25
|
+
}
|
|
11
26
|
}
|
|
12
27
|
|
|
13
|
-
export function
|
|
28
|
+
export function copySync(_path: string, fs: typeof _fs = _fs): void {
|
|
14
29
|
const path = relative(data, _path) || '/';
|
|
15
30
|
const stats = statSync(_path);
|
|
16
31
|
|
|
@@ -23,6 +38,11 @@ export function copy(_path: string, fs: typeof _fs = _fs) {
|
|
|
23
38
|
fs.mkdirSync(path);
|
|
24
39
|
}
|
|
25
40
|
for (const file of readdirSync(_path)) {
|
|
26
|
-
|
|
41
|
+
copySync(join(_path, file), fs);
|
|
27
42
|
}
|
|
28
43
|
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated @hidden
|
|
47
|
+
*/
|
|
48
|
+
export const copy = copySync;
|
package/tests/tsconfig.json
CHANGED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { File } from '../../file.js';
|
|
2
|
-
import type { CreationOptions } from '../../filesystem.js';
|
|
3
|
-
import { Stats } from '../../stats.js';
|
|
4
|
-
import type { IndexData } from './file_index.js';
|
|
5
|
-
import { Index } from './file_index.js';
|
|
6
|
-
import { StoreFS } from './fs.js';
|
|
7
|
-
import type { Store } from './store.js';
|
|
8
|
-
/**
|
|
9
|
-
* Uses an `Index` for metadata.
|
|
10
|
-
*
|
|
11
|
-
* Implementors: You *must* populate the underlying store for read operations to work!
|
|
12
|
-
* @deprecated
|
|
13
|
-
*/
|
|
14
|
-
export declare abstract class IndexFS<T extends Store> extends StoreFS<T> {
|
|
15
|
-
private indexData;
|
|
16
|
-
protected readonly index: Index;
|
|
17
|
-
protected _isInitialized: boolean;
|
|
18
|
-
ready(): Promise<void>;
|
|
19
|
-
constructor(store: T, indexData: IndexData | Promise<IndexData>);
|
|
20
|
-
/**
|
|
21
|
-
* @deprecated
|
|
22
|
-
*/
|
|
23
|
-
reloadFiles(): Promise<void>;
|
|
24
|
-
/**
|
|
25
|
-
* @deprecated
|
|
26
|
-
*/
|
|
27
|
-
reloadFilesSync(): void;
|
|
28
|
-
stat(path: string): Promise<Stats>;
|
|
29
|
-
statSync(path: string): Stats;
|
|
30
|
-
createFile(path: string, flag: string, mode: number, options: CreationOptions): Promise<File>;
|
|
31
|
-
createFileSync(path: string, flag: string, mode: number, options: CreationOptions): File;
|
|
32
|
-
sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
|
|
33
|
-
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
34
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { ErrnoError } from '../../error.js';
|
|
2
|
-
import { LazyFile } from '../../file.js';
|
|
3
|
-
import { Stats } from '../../stats.js';
|
|
4
|
-
import { S_IFREG } from '../../vfs/constants.js';
|
|
5
|
-
import { Index } from './file_index.js';
|
|
6
|
-
import { StoreFS } from './fs.js';
|
|
7
|
-
/**
|
|
8
|
-
* Uses an `Index` for metadata.
|
|
9
|
-
*
|
|
10
|
-
* Implementors: You *must* populate the underlying store for read operations to work!
|
|
11
|
-
* @deprecated
|
|
12
|
-
*/
|
|
13
|
-
/* node:coverage disable */
|
|
14
|
-
export class IndexFS extends StoreFS {
|
|
15
|
-
async ready() {
|
|
16
|
-
await super.ready();
|
|
17
|
-
if (this._isInitialized)
|
|
18
|
-
return;
|
|
19
|
-
this.index.fromJSON(await this.indexData);
|
|
20
|
-
this._isInitialized = true;
|
|
21
|
-
}
|
|
22
|
-
constructor(store, indexData) {
|
|
23
|
-
super(store);
|
|
24
|
-
this.indexData = indexData;
|
|
25
|
-
this.index = new Index();
|
|
26
|
-
this._isInitialized = false;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated
|
|
30
|
-
*/
|
|
31
|
-
async reloadFiles() { }
|
|
32
|
-
/**
|
|
33
|
-
* @deprecated
|
|
34
|
-
*/
|
|
35
|
-
reloadFilesSync() { }
|
|
36
|
-
stat(path) {
|
|
37
|
-
return Promise.resolve(this.statSync(path));
|
|
38
|
-
}
|
|
39
|
-
statSync(path) {
|
|
40
|
-
if (!this.index.has(path))
|
|
41
|
-
throw ErrnoError.With('ENOENT', path, 'stat');
|
|
42
|
-
return new Stats(this.index.get(path));
|
|
43
|
-
}
|
|
44
|
-
async createFile(path, flag, mode, options) {
|
|
45
|
-
const node = await this.commitNew(path, S_IFREG, { mode, ...options }, new Uint8Array(), 'createFile');
|
|
46
|
-
const file = new LazyFile(this, path, flag, node.toStats());
|
|
47
|
-
this.index.set(path, node);
|
|
48
|
-
return file;
|
|
49
|
-
}
|
|
50
|
-
createFileSync(path, flag, mode, options) {
|
|
51
|
-
const node = this.commitNewSync(path, S_IFREG, { mode, ...options }, new Uint8Array(), 'createFile');
|
|
52
|
-
const file = new LazyFile(this, path, flag, node.toStats());
|
|
53
|
-
this.index.set(path, node);
|
|
54
|
-
return file;
|
|
55
|
-
}
|
|
56
|
-
async sync(path, data, stats) {
|
|
57
|
-
var _a;
|
|
58
|
-
(_a = this.index.get(path)) === null || _a === void 0 ? void 0 : _a.update(stats);
|
|
59
|
-
await super.sync(path, data, stats);
|
|
60
|
-
}
|
|
61
|
-
syncSync(path, data, stats) {
|
|
62
|
-
var _a;
|
|
63
|
-
(_a = this.index.get(path)) === null || _a === void 0 ? void 0 : _a.update(stats);
|
|
64
|
-
super.syncSync(path, data, stats);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/* node:coverage enable */
|
package/dist/filesystem.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { ZenFsType } from './stats.js';
|
|
2
|
-
/**
|
|
3
|
-
* Provides a consistent and easy to use internal API.
|
|
4
|
-
* Default implementations for `exists` and `existsSync` are included.
|
|
5
|
-
* If you are extending this class, note that every path is an absolute path and all arguments are present.
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
export class FileSystem {
|
|
9
|
-
/**
|
|
10
|
-
* Get metadata about the current file system
|
|
11
|
-
*/
|
|
12
|
-
metadata() {
|
|
13
|
-
var _a;
|
|
14
|
-
return {
|
|
15
|
-
name: this.constructor.name.toLowerCase(),
|
|
16
|
-
readonly: false,
|
|
17
|
-
totalSpace: 0,
|
|
18
|
-
freeSpace: 0,
|
|
19
|
-
noResizableBuffers: false,
|
|
20
|
-
noAsyncCache: (_a = this._disableSync) !== null && _a !== void 0 ? _a : false,
|
|
21
|
-
features: [],
|
|
22
|
-
type: ZenFsType,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
26
|
-
constructor(...args) { }
|
|
27
|
-
async ready() { }
|
|
28
|
-
/**
|
|
29
|
-
* Test whether or not `path` exists.
|
|
30
|
-
*/
|
|
31
|
-
async exists(path) {
|
|
32
|
-
try {
|
|
33
|
-
await this.stat(path);
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
catch (e) {
|
|
37
|
-
return e.code != 'ENOENT';
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Test whether or not `path` exists.
|
|
42
|
-
*/
|
|
43
|
-
existsSync(path) {
|
|
44
|
-
try {
|
|
45
|
-
this.statSync(path);
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
catch (e) {
|
|
49
|
-
return e.code != 'ENOENT';
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
package/tests/fetch/cow+fetch.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { configureSingle, Fetch, InMemory, Overlay, resolveMountConfig } from '../../dist/index.js';
|
|
2
|
-
|
|
3
|
-
const baseUrl = 'http://localhost:26514';
|
|
4
|
-
|
|
5
|
-
await configureSingle({
|
|
6
|
-
backend: Overlay,
|
|
7
|
-
readable: await resolveMountConfig({
|
|
8
|
-
backend: Fetch,
|
|
9
|
-
baseUrl,
|
|
10
|
-
index: baseUrl + '/.index.json',
|
|
11
|
-
}),
|
|
12
|
-
writable: InMemory.create({ name: 'cow' }),
|
|
13
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { suite, test } from 'node:test';
|
|
3
|
-
import { MessageChannel } from 'node:worker_threads';
|
|
4
|
-
import { Port, attachFS } from '../../dist/backends/port/fs.js';
|
|
5
|
-
import type { StoreFS } from '../../dist/index.js';
|
|
6
|
-
import { InMemory, configureSingle, fs, resolveMountConfig, type InMemoryStore } from '../../dist/index.js';
|
|
7
|
-
|
|
8
|
-
const { port1, port2 } = new MessageChannel(),
|
|
9
|
-
content = 'FS is in a port';
|
|
10
|
-
let tmpfs: StoreFS<InMemoryStore>;
|
|
11
|
-
|
|
12
|
-
await suite('FS with MessageChannel', () => {
|
|
13
|
-
test('configuration', async () => {
|
|
14
|
-
tmpfs = await resolveMountConfig({ backend: InMemory, name: 'tmp' });
|
|
15
|
-
attachFS(port2, tmpfs);
|
|
16
|
-
await configureSingle({ backend: Port, port: port1, disableAsyncCache: true, timeout: 250 });
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('write', async () => {
|
|
20
|
-
await fs.promises.writeFile('/test', content);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('remote content', () => {
|
|
24
|
-
fs.mount('/tmp', tmpfs);
|
|
25
|
-
assert(fs.readFileSync('/tmp/test', 'utf8') == content);
|
|
26
|
-
fs.umount('/tmp');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('read', async () => {
|
|
30
|
-
assert((await fs.promises.readFile('/test', 'utf8')) === content);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('readFileSync should throw', () => {
|
|
34
|
-
assert.throws(() => fs.readFileSync('/test', 'utf8'), { code: 'ENOTSUP' });
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
port1.unref();
|
|
39
|
-
port2.unref();
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { dirname } from 'node:path';
|
|
3
|
-
import { suite, test } from 'node:test';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { Worker } from 'node:worker_threads';
|
|
6
|
-
import { Port } from '../../dist/backends/port/fs.js';
|
|
7
|
-
import { configureSingle, fs } from '../../dist/index.js';
|
|
8
|
-
|
|
9
|
-
const dir = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
|
|
11
|
-
const port = new Worker(dir + '/config.worker.js');
|
|
12
|
-
|
|
13
|
-
await suite('Remote FS with resolveRemoteMount', () => {
|
|
14
|
-
const content = 'FS is in a port';
|
|
15
|
-
|
|
16
|
-
test('Configuration', async () => {
|
|
17
|
-
await configureSingle({ backend: Port, port, timeout: 500 });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('Write', async () => {
|
|
21
|
-
await fs.promises.writeFile('/test', content);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('Read', async () => {
|
|
25
|
-
assert((await fs.promises.readFile('/test', 'utf8')) === content);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
await port?.terminate();
|
|
30
|
-
port.unref();
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { dirname } from 'node:path';
|
|
3
|
-
import { suite, test } from 'node:test';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { Worker } from 'node:worker_threads';
|
|
6
|
-
import { Port } from '../../dist/backends/port/fs.js';
|
|
7
|
-
import { configureSingle, fs } from '../../dist/index.js';
|
|
8
|
-
|
|
9
|
-
const dir = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
|
|
11
|
-
const port = new Worker(dir + '/remote.worker.js');
|
|
12
|
-
|
|
13
|
-
await suite('Remote FS', () => {
|
|
14
|
-
const content = 'FS is in a port';
|
|
15
|
-
|
|
16
|
-
test('Configuration', async () => {
|
|
17
|
-
await configureSingle({ backend: Port, port, timeout: 500 });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('Write', async () => {
|
|
21
|
-
await fs.promises.writeFile('/test', content);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('Read', async () => {
|
|
25
|
-
assert((await fs.promises.readFile('/test', 'utf8')) === content);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('Cleanup', async () => {});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
await port.terminate();
|
|
32
|
-
port.unref();
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { suite, test } from 'node:test';
|
|
3
|
-
import { MessageChannel } from 'node:worker_threads';
|
|
4
|
-
import { Port } from '../../dist/backends/port/fs.js';
|
|
5
|
-
import { ErrnoError, InMemory, configure, configureSingle, fs } from '../../dist/index.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Tests a mis-configured PortFS using a MessageChannel
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const { port1, port2 } = new MessageChannel();
|
|
12
|
-
port2.unref();
|
|
13
|
-
|
|
14
|
-
await suite('Timeout', { timeout: 1000 }, () => {
|
|
15
|
-
test('Misconfiguration', async () => {
|
|
16
|
-
let error: ErrnoError;
|
|
17
|
-
try {
|
|
18
|
-
await configure({
|
|
19
|
-
mounts: {
|
|
20
|
-
'/tmp': { backend: InMemory, name: 'tmp' },
|
|
21
|
-
'/port': { backend: Port, port: port1, timeout: 100 },
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
} catch (e) {
|
|
25
|
-
assert(e instanceof ErrnoError);
|
|
26
|
-
error = e;
|
|
27
|
-
}
|
|
28
|
-
assert(error! instanceof ErrnoError);
|
|
29
|
-
assert.equal(error.code, 'EIO');
|
|
30
|
-
assert(error.message.includes('RPC Failed'));
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('Remote not attached', async () => {
|
|
34
|
-
let error: ErrnoError;
|
|
35
|
-
try {
|
|
36
|
-
await configureSingle({ backend: Port, port: port1, timeout: 100 });
|
|
37
|
-
await fs.promises.writeFile('/test', 'anything');
|
|
38
|
-
} catch (e) {
|
|
39
|
-
assert(e instanceof ErrnoError);
|
|
40
|
-
error = e;
|
|
41
|
-
}
|
|
42
|
-
assert(error! instanceof ErrnoError);
|
|
43
|
-
assert.equal(error.code, 'EIO');
|
|
44
|
-
assert(error.message.includes('RPC Failed'));
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
port1.unref();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|