@zenfs/core 2.3.8 → 2.3.10
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.js +8 -1
- package/dist/backends/port.d.ts +0 -5
- package/dist/backends/port.js +1 -8
- package/dist/config.d.ts +1 -0
- package/dist/config.js +5 -1
- package/dist/internal/index_fs.js +9 -3
- package/dist/internal/rpc.js +7 -6
- package/dist/mixins/async.d.ts +1 -3
- package/dist/mixins/async.js +36 -26
- package/package.json +1 -1
- package/readme.md +4 -0
- package/scripts/test.js +3 -3
- package/tests/backend/port.test.ts +2 -2
- package/tests/common.ts +5 -0
- package/tests/fs/read.test.ts +4 -1
- package/tests/fs/scaling.test.ts +2 -0
- package/tests/setup/port.ts +4 -2
package/dist/backends/backend.js
CHANGED
|
@@ -21,6 +21,13 @@ export function _fnOpt(name, fn) {
|
|
|
21
21
|
Object.defineProperty(fn, 'name', { value: name });
|
|
22
22
|
return fn;
|
|
23
23
|
}
|
|
24
|
+
function _isClass(func) {
|
|
25
|
+
if (!(func && func.constructor === Function) || func.prototype === undefined)
|
|
26
|
+
return false;
|
|
27
|
+
if (Function.prototype !== Object.getPrototypeOf(func))
|
|
28
|
+
return true;
|
|
29
|
+
return Object.getOwnPropertyNames(func.prototype).length > 1;
|
|
30
|
+
}
|
|
24
31
|
/**
|
|
25
32
|
* Checks that `options` object is valid for the file system options.
|
|
26
33
|
* @category Backends and Configuration
|
|
@@ -41,7 +48,7 @@ export function checkOptions(backend, options) {
|
|
|
41
48
|
throw err(withErrno('EINVAL', 'Missing required option: ' + optName));
|
|
42
49
|
}
|
|
43
50
|
const isType = (type, _ = value) => typeof type == 'function'
|
|
44
|
-
?
|
|
51
|
+
? _isClass(type)
|
|
45
52
|
? value instanceof type
|
|
46
53
|
: type(value)
|
|
47
54
|
: typeof value === type || value?.constructor?.name === type;
|
package/dist/backends/port.d.ts
CHANGED
|
@@ -33,11 +33,6 @@ export declare class PortFS<T extends RPC.Channel = RPC.Channel> extends PortFS_
|
|
|
33
33
|
readonly channel: T;
|
|
34
34
|
readonly timeout: number;
|
|
35
35
|
readonly port: RPC.Port<T>;
|
|
36
|
-
/**
|
|
37
|
-
* A map of outstanding RPC requests
|
|
38
|
-
* @internal @hidden
|
|
39
|
-
*/
|
|
40
|
-
readonly _executors: Map<string, RPC.Executor>;
|
|
41
36
|
/**
|
|
42
37
|
* @hidden
|
|
43
38
|
*/
|
package/dist/backends/port.js
CHANGED
|
@@ -19,11 +19,6 @@ export class PortFS extends Async(FileSystem) {
|
|
|
19
19
|
channel;
|
|
20
20
|
timeout;
|
|
21
21
|
port;
|
|
22
|
-
/**
|
|
23
|
-
* A map of outstanding RPC requests
|
|
24
|
-
* @internal @hidden
|
|
25
|
-
*/
|
|
26
|
-
_executors = new Map();
|
|
27
22
|
/**
|
|
28
23
|
* @hidden
|
|
29
24
|
*/
|
|
@@ -61,10 +56,8 @@ export class PortFS extends Async(FileSystem) {
|
|
|
61
56
|
await this.rpc('touch', path, new Uint8Array(inode.buffer, inode.byteOffset, inode.byteLength));
|
|
62
57
|
}
|
|
63
58
|
async sync() {
|
|
59
|
+
await super.sync();
|
|
64
60
|
await this.rpc('sync');
|
|
65
|
-
for (const executor of this._executors.values()) {
|
|
66
|
-
await executor.promise.catch(() => { });
|
|
67
|
-
}
|
|
68
61
|
}
|
|
69
62
|
async createFile(path, options) {
|
|
70
63
|
if (options instanceof Inode)
|
package/dist/config.d.ts
CHANGED
|
@@ -87,3 +87,4 @@ export declare function addDevice(driver: DeviceDriver, options?: object): Devic
|
|
|
87
87
|
* @see Configuration
|
|
88
88
|
*/
|
|
89
89
|
export declare function configure<T extends ConfigMounts>(configuration: Partial<Configuration<T>>): Promise<void>;
|
|
90
|
+
export declare function sync(): Promise<void>;
|
package/dist/config.js
CHANGED
|
@@ -65,7 +65,7 @@ export async function resolveMountConfig(configuration, _depth = 0) {
|
|
|
65
65
|
* @category Backends and Configuration
|
|
66
66
|
*/
|
|
67
67
|
export async function configureSingle(configuration) {
|
|
68
|
-
if (!
|
|
68
|
+
if (!isMountConfig(configuration)) {
|
|
69
69
|
throw new TypeError('Invalid single mount point configuration');
|
|
70
70
|
}
|
|
71
71
|
const resolved = await resolveMountConfig(configuration);
|
|
@@ -137,3 +137,7 @@ export async function configure(configuration) {
|
|
|
137
137
|
await mount('/dev', devfs);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
+
export async function sync() {
|
|
141
|
+
for (const fs of mounts.values())
|
|
142
|
+
await fs.sync();
|
|
143
|
+
}
|
|
@@ -93,9 +93,8 @@ export class IndexFS extends FileSystem {
|
|
|
93
93
|
throw withErrno('ENOTDIR');
|
|
94
94
|
if (isDir && isUnlink)
|
|
95
95
|
throw withErrno('EISDIR');
|
|
96
|
-
if (isDir
|
|
97
|
-
|
|
98
|
-
this.index.delete(path);
|
|
96
|
+
if (!isDir)
|
|
97
|
+
this.index.delete(path);
|
|
99
98
|
}
|
|
100
99
|
async unlink(path) {
|
|
101
100
|
this._remove(path, true);
|
|
@@ -107,10 +106,17 @@ export class IndexFS extends FileSystem {
|
|
|
107
106
|
}
|
|
108
107
|
async rmdir(path) {
|
|
109
108
|
this._remove(path, false);
|
|
109
|
+
const entries = await this.readdir(path);
|
|
110
|
+
if (entries.length)
|
|
111
|
+
throw withErrno('ENOTEMPTY');
|
|
112
|
+
this.index.delete(path);
|
|
110
113
|
await this.remove(path);
|
|
111
114
|
}
|
|
112
115
|
rmdirSync(path) {
|
|
113
116
|
this._remove(path, false);
|
|
117
|
+
if (this.readdirSync(path).length)
|
|
118
|
+
throw withErrno('ENOTEMPTY');
|
|
119
|
+
this.index.delete(path);
|
|
114
120
|
this.removeSync(path);
|
|
115
121
|
}
|
|
116
122
|
create(path, options) {
|
package/dist/internal/rpc.js
CHANGED
|
@@ -10,14 +10,17 @@ export function isPort(port) {
|
|
|
10
10
|
* Creates a new RPC port from a `Worker` or `MessagePort` that extends `EventTarget`
|
|
11
11
|
*/
|
|
12
12
|
export function fromWeb(port) {
|
|
13
|
+
const _handlers = new Map();
|
|
13
14
|
return {
|
|
14
15
|
channel: port,
|
|
15
16
|
send: port.postMessage.bind(port),
|
|
16
17
|
addHandler(handler) {
|
|
17
|
-
|
|
18
|
+
const _handler = (event) => handler(event.data);
|
|
19
|
+
_handlers.set(handler, _handler);
|
|
20
|
+
port.addEventListener('message', _handler);
|
|
18
21
|
},
|
|
19
22
|
removeHandler(handler) {
|
|
20
|
-
port.removeEventListener('message', (
|
|
23
|
+
port.removeEventListener('message', _handlers.get(handler));
|
|
21
24
|
},
|
|
22
25
|
};
|
|
23
26
|
}
|
|
@@ -133,7 +136,6 @@ function disposeExecutors(id) {
|
|
|
133
136
|
if (typeof executor.timeout == 'object')
|
|
134
137
|
executor.timeout.unref();
|
|
135
138
|
}
|
|
136
|
-
executor.fs._executors.delete(id);
|
|
137
139
|
executors.delete(id);
|
|
138
140
|
}
|
|
139
141
|
/**
|
|
@@ -145,15 +147,14 @@ export function request(request, { port, timeout: ms = 1000, fs }) {
|
|
|
145
147
|
if (!port)
|
|
146
148
|
throw err(withErrno('EINVAL', 'Can not make an RPC request without a port'));
|
|
147
149
|
const { resolve, reject, promise } = Promise.withResolvers();
|
|
148
|
-
const id = Math.random().toString(16).slice(
|
|
150
|
+
const id = Math.random().toString(16).slice(5);
|
|
149
151
|
const timeout = setTimeout(() => {
|
|
150
|
-
const error = err(withErrno('
|
|
152
|
+
const error = err(withErrno('ETIMEDOUT', 'RPC request timed out'));
|
|
151
153
|
error.stack += stack;
|
|
152
154
|
disposeExecutors(id);
|
|
153
155
|
reject(error);
|
|
154
156
|
}, ms);
|
|
155
157
|
const executor = { resolve, reject, promise, fs, timeout };
|
|
156
|
-
fs._executors.set(id, executor);
|
|
157
158
|
executors.set(id, executor);
|
|
158
159
|
port.send({ ...request, _zenfs: true, id, stack });
|
|
159
160
|
return promise;
|
package/dist/mixins/async.d.ts
CHANGED
|
@@ -20,10 +20,8 @@ export interface AsyncMixin extends Pick<FileSystem, Exclude<_SyncFSKeys, 'exist
|
|
|
20
20
|
* @deprecated Use {@link sync | `sync`} instead
|
|
21
21
|
*/
|
|
22
22
|
queueDone(): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* @deprecated Use {@link sync | `sync`} instead
|
|
25
|
-
*/
|
|
26
23
|
ready(): Promise<void>;
|
|
24
|
+
sync(): Promise<void>;
|
|
27
25
|
}
|
|
28
26
|
/**
|
|
29
27
|
* Async() implements synchronous methods on an asynchronous file system
|
package/dist/mixins/async.js
CHANGED
|
@@ -29,8 +29,9 @@ export function Async(FS) {
|
|
|
29
29
|
return this.sync();
|
|
30
30
|
}
|
|
31
31
|
_promise = Promise.resolve();
|
|
32
|
-
_async(
|
|
33
|
-
|
|
32
|
+
_async(thunk) {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
34
|
+
this._promise = this._promise.finally(() => thunk());
|
|
34
35
|
}
|
|
35
36
|
_isInitialized = false;
|
|
36
37
|
/** Tracks how many updates to the sync. cache we skipped during initialization */
|
|
@@ -41,9 +42,9 @@ export function Async(FS) {
|
|
|
41
42
|
}
|
|
42
43
|
async ready() {
|
|
43
44
|
await super.ready();
|
|
44
|
-
await this._promise;
|
|
45
45
|
if (this._isInitialized || this.attributes.has('no_async_preload'))
|
|
46
46
|
return;
|
|
47
|
+
await this._promise;
|
|
47
48
|
this.checkSync();
|
|
48
49
|
await this._sync.ready();
|
|
49
50
|
// optimization: for 2 storeFS', we copy at a lower abstraction level.
|
|
@@ -79,7 +80,7 @@ export function Async(FS) {
|
|
|
79
80
|
renameSync(oldPath, newPath) {
|
|
80
81
|
this.checkSync();
|
|
81
82
|
this._sync.renameSync(oldPath, newPath);
|
|
82
|
-
this._async(this.rename(oldPath, newPath));
|
|
83
|
+
this._async(() => this.rename(oldPath, newPath));
|
|
83
84
|
}
|
|
84
85
|
statSync(path) {
|
|
85
86
|
this.checkSync();
|
|
@@ -88,27 +89,29 @@ export function Async(FS) {
|
|
|
88
89
|
touchSync(path, metadata) {
|
|
89
90
|
this.checkSync();
|
|
90
91
|
this._sync.touchSync(path, metadata);
|
|
91
|
-
this._async(this.touch(path, metadata));
|
|
92
|
+
this._async(() => this.touch(path, metadata));
|
|
92
93
|
}
|
|
93
94
|
createFileSync(path, options) {
|
|
94
95
|
this.checkSync();
|
|
95
|
-
this.
|
|
96
|
-
|
|
96
|
+
const result = this._sync.createFileSync(path, options);
|
|
97
|
+
this._async(() => this.createFile(path, options));
|
|
98
|
+
return result;
|
|
97
99
|
}
|
|
98
100
|
unlinkSync(path) {
|
|
99
101
|
this.checkSync();
|
|
100
|
-
this._async(this.unlink(path));
|
|
101
102
|
this._sync.unlinkSync(path);
|
|
103
|
+
this._async(() => this.unlink(path));
|
|
102
104
|
}
|
|
103
105
|
rmdirSync(path) {
|
|
104
106
|
this.checkSync();
|
|
105
107
|
this._sync.rmdirSync(path);
|
|
106
|
-
this._async(this.rmdir(path));
|
|
108
|
+
this._async(() => this.rmdir(path));
|
|
107
109
|
}
|
|
108
110
|
mkdirSync(path, options) {
|
|
109
111
|
this.checkSync();
|
|
110
|
-
this.
|
|
111
|
-
|
|
112
|
+
const result = this._sync.mkdirSync(path, options);
|
|
113
|
+
this._async(() => this.mkdir(path, options));
|
|
114
|
+
return result;
|
|
112
115
|
}
|
|
113
116
|
readdirSync(path) {
|
|
114
117
|
this.checkSync();
|
|
@@ -117,12 +120,12 @@ export function Async(FS) {
|
|
|
117
120
|
linkSync(srcpath, dstpath) {
|
|
118
121
|
this.checkSync();
|
|
119
122
|
this._sync.linkSync(srcpath, dstpath);
|
|
120
|
-
this._async(this.link(srcpath, dstpath));
|
|
123
|
+
this._async(() => this.link(srcpath, dstpath));
|
|
121
124
|
}
|
|
122
125
|
async sync() {
|
|
123
126
|
if (!this.attributes.has('no_async_preload') && this._sync)
|
|
124
127
|
this._sync.syncSync();
|
|
125
|
-
await this._promise;
|
|
128
|
+
await this._promise.catch(() => { });
|
|
126
129
|
}
|
|
127
130
|
syncSync() {
|
|
128
131
|
this.checkSync();
|
|
@@ -139,7 +142,7 @@ export function Async(FS) {
|
|
|
139
142
|
writeSync(path, buffer, offset) {
|
|
140
143
|
this.checkSync();
|
|
141
144
|
this._sync.writeSync(path, buffer, offset);
|
|
142
|
-
this._async(this.write(path, buffer, offset));
|
|
145
|
+
this._async(() => this.write(path, buffer, offset));
|
|
143
146
|
}
|
|
144
147
|
streamWrite(path, options) {
|
|
145
148
|
this.checkSync();
|
|
@@ -186,18 +189,27 @@ export function Async(FS) {
|
|
|
186
189
|
* Patch all async methods to also call their synchronous counterparts unless called from themselves (either sync or async)
|
|
187
190
|
*/
|
|
188
191
|
_patchAsync() {
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
const noPatch = ['read', 'readdir', 'stat', 'exists'];
|
|
193
|
+
const toPatch = _asyncFSKeys.filter(key => !noPatch.includes(key));
|
|
194
|
+
for (const key of toPatch) {
|
|
191
195
|
// TS does not narrow the union based on the key
|
|
192
196
|
const originalMethod = this[key].bind(this);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
function isInLoop(depth, error) {
|
|
198
|
+
if (!error) {
|
|
199
|
+
error = new Error();
|
|
200
|
+
Error.captureStackTrace(error, isInLoop);
|
|
201
|
+
}
|
|
202
|
+
if (!error.stack)
|
|
203
|
+
return false;
|
|
204
|
+
const stack = error.stack.split('\n').slice(depth).join('\n');
|
|
196
205
|
// From the async queue
|
|
197
|
-
|
|
198
|
-
|| stack.includes(`at <computed> [as ${key}]`)
|
|
206
|
+
return (stack.includes(`at <computed> [as ${key}]`)
|
|
199
207
|
|| stack.includes(`at async <computed> [as ${key}]`)
|
|
200
|
-
|| stack.includes(`${key}Sync `))
|
|
208
|
+
|| stack.includes(`${key}Sync `));
|
|
209
|
+
}
|
|
210
|
+
this[key] = async (...args) => {
|
|
211
|
+
const result = await originalMethod(...args);
|
|
212
|
+
if (isInLoop(2))
|
|
201
213
|
return result;
|
|
202
214
|
if (!this._isInitialized) {
|
|
203
215
|
this._skippedCacheUpdates++;
|
|
@@ -208,10 +220,7 @@ export function Async(FS) {
|
|
|
208
220
|
this._sync?.[`${key}Sync`]?.(...args);
|
|
209
221
|
}
|
|
210
222
|
catch (e) {
|
|
211
|
-
|
|
212
|
-
if (stack.includes(`at <computed> [as ${key}]`)
|
|
213
|
-
|| stack.includes(`at async <computed> [as ${key}]`)
|
|
214
|
-
|| stack.includes(`${key}Sync `))
|
|
223
|
+
if (isInLoop(3, e))
|
|
215
224
|
return result;
|
|
216
225
|
e.message += ' (Out of sync!)';
|
|
217
226
|
throw err(e);
|
|
@@ -219,6 +228,7 @@ export function Async(FS) {
|
|
|
219
228
|
return result;
|
|
220
229
|
};
|
|
221
230
|
}
|
|
231
|
+
debug(`Async: patched ${toPatch.length} methods`);
|
|
222
232
|
}
|
|
223
233
|
}
|
|
224
234
|
return AsyncFS;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -220,6 +220,10 @@ A huge thank you to [ or by emailing jp@zenfs.dev
|
|
226
|
+
|
|
223
227
|
### Testing
|
|
224
228
|
|
|
225
229
|
Run unit tests with:
|
package/scripts/test.js
CHANGED
|
@@ -22,7 +22,7 @@ const { values: options, positionals } = parseArgs({
|
|
|
22
22
|
build: { short: 'b', type: 'boolean', default: false },
|
|
23
23
|
common: { short: 'c', type: 'boolean', default: false },
|
|
24
24
|
inspect: { short: 'I', type: 'boolean', default: false },
|
|
25
|
-
skip: { short: 's', type: 'string' },
|
|
25
|
+
skip: { short: 's', type: 'string', multiple: true, default: [] },
|
|
26
26
|
'exit-on-fail': { short: 'e', type: 'boolean' },
|
|
27
27
|
|
|
28
28
|
// Coverage
|
|
@@ -47,7 +47,7 @@ Behavior:
|
|
|
47
47
|
-t, --test <glob> Which FS test suite(s) to run
|
|
48
48
|
-f, --force Whether to use --test-force-exit
|
|
49
49
|
-I, --inspect Use the inspector for debugging
|
|
50
|
-
-s, --skip <pattern> Skip tests with names matching the given pattern.
|
|
50
|
+
-s, --skip <pattern> Skip tests with names matching the given pattern. Can be specified multiple times.
|
|
51
51
|
|
|
52
52
|
Output:
|
|
53
53
|
-h, --help Outputs this help message
|
|
@@ -215,7 +215,7 @@ for (const setupFile of positionals) {
|
|
|
215
215
|
options.inspect ? '--inspect' : '',
|
|
216
216
|
'--test --experimental-test-coverage',
|
|
217
217
|
options.force ? '--test-force-exit' : '',
|
|
218
|
-
options.skip ? `--test-skip-pattern
|
|
218
|
+
options.skip.length ? `--test-skip-pattern='${options.skip.join('|').replaceAll("'", "\\'")}'` : '',
|
|
219
219
|
`'${testsGlob.replaceAll("'", "\\'")}'`,
|
|
220
220
|
process.env.CMD,
|
|
221
221
|
].join(' '),
|
|
@@ -21,13 +21,13 @@ await suite('Timeout', { timeout: 1000 }, () => {
|
|
|
21
21
|
},
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
await assert.rejects(configured, { code: '
|
|
24
|
+
await assert.rejects(configured, { code: 'ETIMEDOUT' });
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
test('Remote not attached', async () => {
|
|
28
28
|
const configured = configureSingle({ backend: Port, port: timeoutChannel.port1, timeout: 100 });
|
|
29
29
|
|
|
30
|
-
await assert.rejects(configured, { code: '
|
|
30
|
+
await assert.rejects(configured, { code: 'ETIMEDOUT' });
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
after(() => {
|
package/tests/common.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { join, resolve } from 'node:path';
|
|
2
2
|
import { fs as defaultFS } from '../dist/index.js';
|
|
3
3
|
import { setupLogs } from './logs.js';
|
|
4
|
+
import { styleText } from 'node:util';
|
|
4
5
|
export type * from '../dist/index.js';
|
|
5
6
|
|
|
6
7
|
setupLogs();
|
|
7
8
|
|
|
8
9
|
const setupPath = resolve(process.env.SETUP || join(import.meta.dirname, 'setup/memory.ts'));
|
|
9
10
|
|
|
11
|
+
process.on('unhandledRejection', (reason: Error) => {
|
|
12
|
+
console.error('Unhandled rejection:', styleText('red', reason.stack || reason.message));
|
|
13
|
+
});
|
|
14
|
+
|
|
10
15
|
const setup = await import(setupPath).catch(error => {
|
|
11
16
|
console.log('Failed to import test setup:');
|
|
12
17
|
throw error;
|
package/tests/fs/read.test.ts
CHANGED
|
@@ -3,7 +3,8 @@ import assert from 'node:assert/strict';
|
|
|
3
3
|
import type { OpenMode, PathLike } from 'node:fs';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
6
|
-
import {
|
|
6
|
+
import { sync } from '../../dist/config.js';
|
|
7
|
+
import { fs } from '../common.js';
|
|
7
8
|
|
|
8
9
|
const filepath = 'x.txt';
|
|
9
10
|
const expected = 'xyz\n';
|
|
@@ -73,6 +74,8 @@ suite('read', () => {
|
|
|
73
74
|
const path = '/text.txt';
|
|
74
75
|
|
|
75
76
|
fs.writeFileSync(path, 'hello world');
|
|
77
|
+
await sync();
|
|
78
|
+
|
|
76
79
|
const fd: number = (await promisify<PathLike, OpenMode, number | string>(fs.open)(path, 0, 0)) as any;
|
|
77
80
|
|
|
78
81
|
const read = promisify(fs.read);
|
package/tests/fs/scaling.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
+
import { sync } from '../../dist/config.js';
|
|
3
4
|
import { fs } from '../common.js';
|
|
4
5
|
|
|
5
6
|
const n_files = 130;
|
|
@@ -14,6 +15,7 @@ suite('Scaling', () => {
|
|
|
14
15
|
fs.writeFileSync('/n/' + i, i.toString(16));
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
await sync();
|
|
17
19
|
assert.equal(fs.readdirSync('/n').length, n_files);
|
|
18
20
|
|
|
19
21
|
const results = [];
|
package/tests/setup/port.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { after } from 'node:test';
|
|
1
|
+
import { after, afterEach } from 'node:test';
|
|
2
2
|
import { MessageChannel } from 'node:worker_threads';
|
|
3
|
-
import { InMemory, Port, configureSingle, fs, resolveMountConfig, resolveRemoteMount } from '../../dist/index.js';
|
|
3
|
+
import { InMemory, Port, configureSingle, fs, resolveMountConfig, resolveRemoteMount, sync } from '../../dist/index.js';
|
|
4
4
|
import { copySync, data } from '../setup.js';
|
|
5
5
|
|
|
6
6
|
const { port1: localPort, port2: remotePort } = new MessageChannel();
|
|
@@ -15,6 +15,8 @@ await resolveRemoteMount(remotePort, tmpfs);
|
|
|
15
15
|
|
|
16
16
|
await configureSingle({ backend: Port, port: localPort });
|
|
17
17
|
|
|
18
|
+
afterEach(sync);
|
|
19
|
+
|
|
18
20
|
after(() => {
|
|
19
21
|
localPort.close();
|
|
20
22
|
remotePort.close();
|