@zenfs/core 1.11.3 → 2.0.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.
Files changed (116) hide show
  1. package/dist/backends/backend.d.ts +19 -15
  2. package/dist/backends/backend.js +31 -15
  3. package/dist/backends/cow.d.ts +20 -30
  4. package/dist/backends/cow.js +52 -142
  5. package/dist/backends/fetch.d.ts +1 -0
  6. package/dist/backends/fetch.js +3 -1
  7. package/dist/backends/index.d.ts +1 -1
  8. package/dist/backends/index.js +1 -1
  9. package/dist/backends/memory.d.ts +5 -7
  10. package/dist/backends/memory.js +2 -3
  11. package/dist/backends/passthrough.d.ts +19 -22
  12. package/dist/backends/passthrough.js +85 -160
  13. package/dist/backends/port.d.ts +207 -0
  14. package/dist/backends/port.js +297 -0
  15. package/dist/backends/single_buffer.d.ts +11 -5
  16. package/dist/backends/single_buffer.js +18 -12
  17. package/dist/backends/store/fs.d.ts +11 -27
  18. package/dist/backends/store/fs.js +67 -91
  19. package/dist/backends/store/store.d.ts +7 -12
  20. package/dist/config.d.ts +1 -10
  21. package/dist/config.js +7 -8
  22. package/dist/context.d.ts +8 -21
  23. package/dist/context.js +33 -10
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +2 -1
  26. package/dist/internal/contexts.d.ts +63 -0
  27. package/dist/internal/contexts.js +15 -0
  28. package/dist/internal/credentials.d.ts +2 -11
  29. package/dist/internal/credentials.js +0 -19
  30. package/dist/internal/devices.d.ts +18 -80
  31. package/dist/internal/devices.js +76 -279
  32. package/dist/internal/file_index.js +3 -3
  33. package/dist/internal/filesystem.d.ts +31 -89
  34. package/dist/internal/filesystem.js +21 -20
  35. package/dist/internal/index.d.ts +0 -1
  36. package/dist/internal/index.js +0 -1
  37. package/dist/internal/index_fs.d.ts +12 -30
  38. package/dist/internal/index_fs.js +23 -55
  39. package/dist/internal/inode.d.ts +147 -9
  40. package/dist/internal/inode.js +333 -25
  41. package/dist/internal/log.d.ts +19 -13
  42. package/dist/internal/log.js +81 -80
  43. package/dist/mixins/async.js +26 -90
  44. package/dist/mixins/mutexed.d.ts +17 -16
  45. package/dist/mixins/mutexed.js +29 -31
  46. package/dist/mixins/readonly.d.ts +7 -6
  47. package/dist/mixins/readonly.js +6 -0
  48. package/dist/mixins/sync.js +8 -8
  49. package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
  50. package/dist/{vfs/path.js → path.js} +6 -9
  51. package/dist/readline.d.ts +134 -0
  52. package/dist/readline.js +623 -0
  53. package/dist/utils.d.ts +4 -35
  54. package/dist/utils.js +8 -73
  55. package/dist/vfs/acl.d.ts +42 -0
  56. package/dist/vfs/acl.js +249 -0
  57. package/dist/vfs/async.d.ts +7 -21
  58. package/dist/vfs/async.js +19 -19
  59. package/dist/vfs/config.d.ts +6 -18
  60. package/dist/vfs/config.js +8 -18
  61. package/dist/vfs/dir.d.ts +3 -3
  62. package/dist/vfs/dir.js +9 -8
  63. package/dist/vfs/file.d.ts +106 -0
  64. package/dist/vfs/file.js +235 -0
  65. package/dist/vfs/flags.d.ts +19 -0
  66. package/dist/vfs/flags.js +62 -0
  67. package/dist/vfs/index.d.ts +4 -10
  68. package/dist/vfs/index.js +4 -13
  69. package/dist/vfs/ioctl.d.ts +87 -0
  70. package/dist/vfs/ioctl.js +304 -0
  71. package/dist/vfs/promises.d.ts +78 -16
  72. package/dist/vfs/promises.js +273 -122
  73. package/dist/vfs/shared.d.ts +7 -26
  74. package/dist/vfs/shared.js +25 -53
  75. package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
  76. package/dist/{stats.js → vfs/stats.js} +11 -66
  77. package/dist/vfs/streams.d.ts +1 -0
  78. package/dist/vfs/streams.js +24 -19
  79. package/dist/vfs/sync.d.ts +4 -3
  80. package/dist/vfs/sync.js +143 -128
  81. package/dist/vfs/watchers.d.ts +2 -2
  82. package/dist/vfs/watchers.js +6 -6
  83. package/dist/vfs/xattr.d.ts +116 -0
  84. package/dist/vfs/xattr.js +218 -0
  85. package/package.json +3 -3
  86. package/readme.md +1 -1
  87. package/tests/backend/config.worker.js +4 -1
  88. package/tests/backend/fetch.test.ts +3 -0
  89. package/tests/backend/port.test.ts +21 -35
  90. package/tests/backend/remote.worker.js +4 -1
  91. package/tests/backend/single-buffer.test.ts +24 -0
  92. package/tests/common/context.test.ts +1 -1
  93. package/tests/common/handle.test.ts +17 -12
  94. package/tests/common/path.test.ts +1 -1
  95. package/tests/common/readline.test.ts +104 -0
  96. package/tests/common.ts +4 -19
  97. package/tests/fetch/fetch.ts +1 -1
  98. package/tests/fs/links.test.ts +1 -1
  99. package/tests/fs/permissions.test.ts +7 -6
  100. package/tests/fs/readFile.test.ts +3 -3
  101. package/tests/fs/stat.test.ts +6 -6
  102. package/tests/fs/streams.test.ts +2 -11
  103. package/tests/fs/times.test.ts +1 -1
  104. package/tests/fs/xattr.test.ts +85 -0
  105. package/tests/logs.js +22 -0
  106. package/tests/setup/context.ts +1 -1
  107. package/tests/setup/index.ts +3 -3
  108. package/tests/setup/port.ts +1 -1
  109. package/dist/backends/port/fs.d.ts +0 -84
  110. package/dist/backends/port/fs.js +0 -151
  111. package/dist/backends/port/rpc.d.ts +0 -77
  112. package/dist/backends/port/rpc.js +0 -100
  113. package/dist/backends/store/simple.d.ts +0 -20
  114. package/dist/backends/store/simple.js +0 -13
  115. package/dist/internal/file.d.ts +0 -351
  116. package/dist/internal/file.js +0 -739
@@ -1,8 +1,7 @@
1
1
  import type * as fs from 'node:fs';
2
- import { File } from '../internal/file.js';
3
- import { FileSystem, type UsageInfo } from '../internal/filesystem.js';
4
- import type { InodeLike } from '../internal/inode.js';
5
- import { Stats } from '../stats.js';
2
+ import type { CreationOptions, UsageInfo } from '../internal/filesystem.js';
3
+ import { FileSystem } from '../internal/filesystem.js';
4
+ import { type InodeLike } from '../internal/inode.js';
6
5
  export type NodeFS = typeof fs;
7
6
  /**
8
7
  * Passthrough backend options
@@ -10,7 +9,7 @@ export type NodeFS = typeof fs;
10
9
  */
11
10
  export interface PassthroughOptions {
12
11
  fs: NodeFS;
13
- prefix?: string;
12
+ prefix: string;
14
13
  }
15
14
  export declare class PassthroughFS extends FileSystem {
16
15
  readonly nodeFS: NodeFS;
@@ -30,19 +29,13 @@ export declare class PassthroughFS extends FileSystem {
30
29
  /**
31
30
  * Get file statistics.
32
31
  */
33
- stat(path: string): Promise<Stats>;
32
+ stat(path: string): Promise<InodeLike>;
34
33
  /**
35
34
  * Get file statistics synchronously.
36
35
  */
37
- statSync(path: string): Stats;
38
- /**
39
- * Open a file.
40
- */
41
- openFile(path: string, flag: string): Promise<File>;
42
- /**
43
- * Open a file synchronously.
44
- */
45
- openFileSync(path: string, flag: string): File;
36
+ statSync(path: string): InodeLike;
37
+ touch(path: string, metadata: InodeLike): Promise<void>;
38
+ touchSync(path: string, metadata: InodeLike): void;
46
39
  /**
47
40
  * Unlink (delete) a file.
48
41
  */
@@ -54,11 +47,11 @@ export declare class PassthroughFS extends FileSystem {
54
47
  /**
55
48
  * Create a directory.
56
49
  */
57
- mkdir(path: string, mode: number): Promise<void>;
50
+ mkdir(path: string, options: CreationOptions): Promise<InodeLike>;
58
51
  /**
59
52
  * Create a directory synchronously.
60
53
  */
61
- mkdirSync(path: string, mode: number): void;
54
+ mkdirSync(path: string, options: CreationOptions): InodeLike;
62
55
  /**
63
56
  * Read the contents of a directory.
64
57
  */
@@ -70,11 +63,11 @@ export declare class PassthroughFS extends FileSystem {
70
63
  /**
71
64
  * Create a file.
72
65
  */
73
- createFile(path: string, flag: string, mode: number): Promise<File>;
66
+ createFile(path: string, options: CreationOptions): Promise<InodeLike>;
74
67
  /**
75
68
  * Create a file synchronously.
76
69
  */
77
- createFileSync(path: string, flag: string, mode: number): File;
70
+ createFileSync(path: string, options: CreationOptions): InodeLike;
78
71
  /**
79
72
  * Remove a directory.
80
73
  */
@@ -86,11 +79,11 @@ export declare class PassthroughFS extends FileSystem {
86
79
  /**
87
80
  * Synchronize data to the file system.
88
81
  */
89
- sync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): Promise<void>;
82
+ sync(path: string): Promise<void>;
90
83
  /**
91
84
  * Synchronize data to the file system synchronously.
92
85
  */
93
- syncSync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): void;
86
+ syncSync(path: string): void;
94
87
  /**
95
88
  * Create a hard link.
96
89
  */
@@ -113,12 +106,16 @@ declare const _Passthrough: {
113
106
  };
114
107
  readonly prefix: {
115
108
  readonly type: "string";
116
- readonly required: false;
109
+ readonly required: true;
117
110
  };
118
111
  };
119
112
  readonly create: ({ fs, prefix }: PassthroughOptions) => PassthroughFS;
120
113
  };
121
114
  type _Passthrough = typeof _Passthrough;
115
+ /**
116
+ * A file system that passes through to another FS
117
+ * @category Backends and Configuration
118
+ */
122
119
  export interface Passthrough extends _Passthrough {
123
120
  }
124
121
  /**
@@ -51,90 +51,10 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
51
51
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
52
  });
53
53
  import { ErrnoError } from '../internal/error.js';
54
- import { File } from '../internal/file.js';
55
54
  import { FileSystem } from '../internal/filesystem.js';
56
- import { Stats } from '../stats.js';
57
- import { join, resolve } from '../vfs/path.js';
58
- class PassthroughFile extends File {
59
- constructor(fs, path, fd) {
60
- super(fs, path);
61
- this.fd = fd;
62
- this.node = fs.nodeFS;
63
- this.nodePath = fs.path(path);
64
- }
65
- error(err) {
66
- const error = err;
67
- return ErrnoError.With(error.code, this.path, error.syscall);
68
- }
69
- get position() {
70
- // Placeholder: Implement proper position tracking if needed.
71
- return 0;
72
- }
73
- async stat() {
74
- const { resolve, reject, promise } = Promise.withResolvers();
75
- this.node.fstat(this.fd, (err, stats) => (err ? reject(this.error(err)) : resolve(new Stats(stats))));
76
- return promise;
77
- }
78
- statSync() {
79
- return new Stats(this.node.fstatSync(this.fd));
80
- }
81
- close() {
82
- const { resolve, reject, promise } = Promise.withResolvers();
83
- this.node.close(this.fd, err => (err ? reject(this.error(err)) : resolve()));
84
- return promise;
85
- }
86
- closeSync() {
87
- this.node.closeSync(this.fd);
88
- }
89
- async truncate(len) {
90
- await this.node.promises.truncate(this.nodePath, len);
91
- }
92
- truncateSync(len) {
93
- this.node.ftruncateSync(this.fd, len);
94
- }
95
- async sync() {
96
- const { resolve, reject, promise } = Promise.withResolvers();
97
- this.node.fsync(this.fd, err => (err ? reject(this.error(err)) : resolve()));
98
- return promise;
99
- }
100
- syncSync() {
101
- this.node.fsyncSync(this.fd);
102
- }
103
- async write(buffer, offset, length, position) {
104
- const { resolve, reject, promise } = Promise.withResolvers();
105
- this.node.write(this.fd, buffer, offset, length, position, (err, written) => (err ? reject(this.error(err)) : resolve(written)));
106
- return promise;
107
- }
108
- writeSync(buffer, offset, length, position) {
109
- return this.node.writeSync(this.fd, buffer, offset, length, position);
110
- }
111
- async read(buffer, offset = 0, length, position = null) {
112
- const { resolve, reject, promise } = Promise.withResolvers();
113
- this.node.read(this.fd, buffer, offset, length || (await this.stat()).size, position, (err, bytesRead, buffer) => err ? reject(this.error(err)) : resolve({ bytesRead, buffer }));
114
- return promise;
115
- }
116
- readSync(buffer, offset = 0, length = this.statSync().size, position = null) {
117
- return this.node.readSync(this.fd, buffer, offset, length, position);
118
- }
119
- async chmod(mode) {
120
- await this.node.promises.chmod(this.nodePath, mode);
121
- }
122
- chmodSync(mode) {
123
- this.node.fchmodSync(this.fd, mode);
124
- }
125
- async chown(uid, gid) {
126
- await this.node.promises.chown(this.nodePath, uid, gid);
127
- }
128
- chownSync(uid, gid) {
129
- this.node.fchownSync(this.fd, uid, gid);
130
- }
131
- async utimes(atime, mtime) {
132
- await this.node.promises.utimes(this.nodePath, atime, mtime);
133
- }
134
- utimesSync(atime, mtime) {
135
- this.node.futimesSync(this.fd, atime, mtime);
136
- }
137
- }
55
+ import { isDirectory } from '../internal/inode.js';
56
+ import { resolve } from '../path.js';
57
+ import { warn } from '../internal/log.js';
138
58
  export class PassthroughFS extends FileSystem {
139
59
  constructor(nodeFS, prefix) {
140
60
  super(0x6e6f6465, 'nodefs');
@@ -149,7 +69,7 @@ export class PassthroughFS extends FileSystem {
149
69
  };
150
70
  }
151
71
  path(path) {
152
- return join(this.prefix, path.slice(1));
72
+ return this.prefix + path;
153
73
  }
154
74
  error(err, path) {
155
75
  const error = err;
@@ -182,7 +102,7 @@ export class PassthroughFS extends FileSystem {
182
102
  */
183
103
  async stat(path) {
184
104
  try {
185
- return new Stats(await this.nodeFS.promises.stat(this.path(path)));
105
+ return await this.nodeFS.promises.stat(this.path(path));
186
106
  }
187
107
  catch (err) {
188
108
  this.error(err, path);
@@ -193,31 +113,40 @@ export class PassthroughFS extends FileSystem {
193
113
  */
194
114
  statSync(path) {
195
115
  try {
196
- return new Stats(this.nodeFS.statSync(this.path(path)));
116
+ return this.nodeFS.statSync(this.path(path));
197
117
  }
198
118
  catch (err) {
199
119
  this.error(err, path);
200
120
  }
201
121
  }
202
- /**
203
- * Open a file.
204
- */
205
- async openFile(path, flag) {
122
+ async touch(path, metadata) {
206
123
  try {
207
- const { fd } = await this.nodeFS.promises.open(this.path(path), flag);
208
- return new PassthroughFile(this, path, fd);
124
+ const env_1 = { stack: [], error: void 0, hasError: false };
125
+ try {
126
+ const handle = __addDisposableResource(env_1, await this.nodeFS.promises.open(this.path(path), 'w'), true);
127
+ await handle.chmod(metadata.mode);
128
+ await handle.chown(metadata.uid, metadata.gid);
129
+ await handle.utimes(metadata.atimeMs, metadata.mtimeMs);
130
+ }
131
+ catch (e_1) {
132
+ env_1.error = e_1;
133
+ env_1.hasError = true;
134
+ }
135
+ finally {
136
+ const result_1 = __disposeResources(env_1);
137
+ if (result_1)
138
+ await result_1;
139
+ }
209
140
  }
210
141
  catch (err) {
211
142
  this.error(err, path);
212
143
  }
213
144
  }
214
- /**
215
- * Open a file synchronously.
216
- */
217
- openFileSync(path, flag) {
145
+ touchSync(path, metadata) {
218
146
  try {
219
- const fd = this.nodeFS.openSync(this.path(path), flag);
220
- return new PassthroughFile(this, path, fd);
147
+ this.nodeFS.chmodSync(this.path(path), metadata.mode);
148
+ this.nodeFS.chownSync(this.path(path), metadata.uid, metadata.gid);
149
+ this.nodeFS.utimesSync(this.path(path), metadata.atimeMs, metadata.mtimeMs);
221
150
  }
222
151
  catch (err) {
223
152
  this.error(err, path);
@@ -248,9 +177,10 @@ export class PassthroughFS extends FileSystem {
248
177
  /**
249
178
  * Create a directory.
250
179
  */
251
- async mkdir(path, mode) {
180
+ async mkdir(path, options) {
252
181
  try {
253
- await this.nodeFS.promises.mkdir(this.path(path), { mode });
182
+ await this.nodeFS.promises.mkdir(this.path(path), options);
183
+ return await this.nodeFS.promises.stat(this.path(path));
254
184
  }
255
185
  catch (err) {
256
186
  this.error(err, path);
@@ -259,9 +189,10 @@ export class PassthroughFS extends FileSystem {
259
189
  /**
260
190
  * Create a directory synchronously.
261
191
  */
262
- mkdirSync(path, mode) {
192
+ mkdirSync(path, options) {
263
193
  try {
264
- this.nodeFS.mkdirSync(this.path(path), { mode });
194
+ this.nodeFS.mkdirSync(this.path(path), options);
195
+ return this.nodeFS.statSync(this.path(path));
265
196
  }
266
197
  catch (err) {
267
198
  this.error(err, path);
@@ -292,10 +223,28 @@ export class PassthroughFS extends FileSystem {
292
223
  /**
293
224
  * Create a file.
294
225
  */
295
- async createFile(path, flag, mode) {
226
+ async createFile(path, options) {
296
227
  try {
297
- const { fd } = await this.nodeFS.promises.open(this.path(path), flag, mode);
298
- return new PassthroughFile(this, path, fd);
228
+ if (isDirectory(options)) {
229
+ await this.nodeFS.promises.mkdir(this.path(path), { mode: options.mode });
230
+ }
231
+ else {
232
+ const env_2 = { stack: [], error: void 0, hasError: false };
233
+ try {
234
+ const handle = __addDisposableResource(env_2, await this.nodeFS.promises.open(this.path(path), 'wx'), true);
235
+ await handle.close();
236
+ }
237
+ catch (e_2) {
238
+ env_2.error = e_2;
239
+ env_2.hasError = true;
240
+ }
241
+ finally {
242
+ const result_2 = __disposeResources(env_2);
243
+ if (result_2)
244
+ await result_2;
245
+ }
246
+ }
247
+ return await this.nodeFS.promises.stat(this.path(path));
299
248
  }
300
249
  catch (err) {
301
250
  this.error(err, path);
@@ -304,10 +253,16 @@ export class PassthroughFS extends FileSystem {
304
253
  /**
305
254
  * Create a file synchronously.
306
255
  */
307
- createFileSync(path, flag, mode) {
256
+ createFileSync(path, options) {
308
257
  try {
309
- const fd = this.nodeFS.openSync(this.path(path), flag, mode);
310
- return new PassthroughFile(this, path, fd);
258
+ if (isDirectory(options)) {
259
+ this.nodeFS.mkdirSync(this.path(path), { mode: options.mode });
260
+ }
261
+ else {
262
+ const fd = this.nodeFS.openSync(this.path(path), 'wx');
263
+ this.nodeFS.closeSync(fd);
264
+ }
265
+ return this.nodeFS.statSync(this.path(path));
311
266
  }
312
267
  catch (err) {
313
268
  this.error(err, path);
@@ -338,44 +293,14 @@ export class PassthroughFS extends FileSystem {
338
293
  /**
339
294
  * Synchronize data to the file system.
340
295
  */
341
- async sync(path, data, stats) {
342
- try {
343
- const env_1 = { stack: [], error: void 0, hasError: false };
344
- try {
345
- const handle = __addDisposableResource(env_1, await this.nodeFS.promises.open(this.path(path), 'w'), true);
346
- await handle.writeFile(data);
347
- await handle.chmod(stats.mode);
348
- await handle.chown(stats.uid, stats.gid);
349
- await handle.utimes(stats.atimeMs, stats.mtimeMs);
350
- }
351
- catch (e_1) {
352
- env_1.error = e_1;
353
- env_1.hasError = true;
354
- }
355
- finally {
356
- const result_1 = __disposeResources(env_1);
357
- if (result_1)
358
- await result_1;
359
- }
360
- }
361
- catch (err) {
362
- this.error(err, path);
363
- }
296
+ async sync(path) {
297
+ warn('Sync on passthrough is unnecessary');
364
298
  }
365
299
  /**
366
300
  * Synchronize data to the file system synchronously.
367
301
  */
368
- syncSync(path, data, stats) {
369
- try {
370
- const p = this.path(path);
371
- this.nodeFS.writeFileSync(p, data);
372
- this.nodeFS.chmodSync(p, stats.mode);
373
- this.nodeFS.chownSync(p, stats.uid, stats.gid);
374
- this.nodeFS.utimesSync(p, stats.atimeMs, stats.mtimeMs);
375
- }
376
- catch (err) {
377
- this.error(err, path);
378
- }
302
+ syncSync(path) {
303
+ warn('Sync on passthrough is unnecessary');
379
304
  }
380
305
  /**
381
306
  * Create a hard link.
@@ -401,19 +326,19 @@ export class PassthroughFS extends FileSystem {
401
326
  }
402
327
  async read(path, buffer, offset, end) {
403
328
  try {
404
- const env_2 = { stack: [], error: void 0, hasError: false };
329
+ const env_3 = { stack: [], error: void 0, hasError: false };
405
330
  try {
406
- const handle = __addDisposableResource(env_2, await this.nodeFS.promises.open(this.path(path), 'r'), true);
331
+ const handle = __addDisposableResource(env_3, await this.nodeFS.promises.open(this.path(path), 'r'), true);
407
332
  await handle.read({ buffer, offset, length: end - offset });
408
333
  }
409
- catch (e_2) {
410
- env_2.error = e_2;
411
- env_2.hasError = true;
334
+ catch (e_3) {
335
+ env_3.error = e_3;
336
+ env_3.hasError = true;
412
337
  }
413
338
  finally {
414
- const result_2 = __disposeResources(env_2);
415
- if (result_2)
416
- await result_2;
339
+ const result_3 = __disposeResources(env_3);
340
+ if (result_3)
341
+ await result_3;
417
342
  }
418
343
  }
419
344
  catch (err) {
@@ -436,19 +361,19 @@ export class PassthroughFS extends FileSystem {
436
361
  }
437
362
  async write(path, buffer, offset) {
438
363
  try {
439
- const env_3 = { stack: [], error: void 0, hasError: false };
364
+ const env_4 = { stack: [], error: void 0, hasError: false };
440
365
  try {
441
- const handle = __addDisposableResource(env_3, await this.nodeFS.promises.open(this.path(path), 'w'), true);
366
+ const handle = __addDisposableResource(env_4, await this.nodeFS.promises.open(this.path(path), 'w'), true);
442
367
  await handle.write(buffer, offset);
443
368
  }
444
- catch (e_3) {
445
- env_3.error = e_3;
446
- env_3.hasError = true;
369
+ catch (e_4) {
370
+ env_4.error = e_4;
371
+ env_4.hasError = true;
447
372
  }
448
373
  finally {
449
- const result_3 = __disposeResources(env_3);
450
- if (result_3)
451
- await result_3;
374
+ const result_4 = __disposeResources(env_4);
375
+ if (result_4)
376
+ await result_4;
452
377
  }
453
378
  }
454
379
  catch (err) {
@@ -474,9 +399,9 @@ const _Passthrough = {
474
399
  name: 'Passthrough',
475
400
  options: {
476
401
  fs: { type: 'object', required: true },
477
- prefix: { type: 'string', required: false },
402
+ prefix: { type: 'string', required: true },
478
403
  },
479
- create({ fs, prefix = '/' }) {
404
+ create({ fs, prefix }) {
480
405
  return new PassthroughFS(fs, resolve(prefix));
481
406
  },
482
407
  };
@@ -0,0 +1,207 @@
1
+ import type { TransferListItem } from 'node:worker_threads';
2
+ import type { MountConfiguration } from '../config.js';
3
+ import type { CreationOptions, UsageInfo } from '../internal/filesystem.js';
4
+ import type { InodeLike } from '../internal/inode.js';
5
+ import type { Backend, FilesystemOf } from './backend.js';
6
+ import { FileSystem } from '../internal/filesystem.js';
7
+ import { Inode } from '../internal/inode.js';
8
+ import '../polyfills.js';
9
+ type _MessageEvent<T = any> = T | {
10
+ data: T;
11
+ };
12
+ /** @internal */
13
+ export interface RPCPort {
14
+ postMessage(value: unknown, transfer?: TransferListItem[]): void;
15
+ on?(event: 'message' | 'online', listener: (value: unknown) => void): this;
16
+ off?(event: 'message', listener: (value: unknown) => void): this;
17
+ addEventListener?(type: 'message', listener: (ev: _MessageEvent) => void): void;
18
+ removeEventListener?(type: 'message', listener: (ev: _MessageEvent) => void): void;
19
+ }
20
+ /**
21
+ * The options for the Port backend
22
+ * @category Backends and Configuration
23
+ */
24
+ export interface PortOptions {
25
+ /**
26
+ * The target port that you want to connect to, or the current port if in a port context.
27
+ */
28
+ port: RPCPort;
29
+ /**
30
+ * How long to wait for a request to complete
31
+ */
32
+ timeout?: number;
33
+ }
34
+ /**
35
+ * The API for remote procedure calls
36
+ * @category Internals
37
+ * @internal
38
+ */
39
+ export interface RPCMethods {
40
+ usage(): UsageInfo;
41
+ ready(): void;
42
+ rename(oldPath: string, newPath: string): void;
43
+ createFile(path: string, options: CreationOptions): Uint8Array;
44
+ unlink(path: string): void;
45
+ rmdir(path: string): void;
46
+ mkdir(path: string, options: CreationOptions): Uint8Array;
47
+ readdir(path: string): string[];
48
+ touch(path: string, metadata: Uint8Array): void;
49
+ exists(path: string): boolean;
50
+ link(target: string, link: string): void;
51
+ sync(path: string): void;
52
+ read(path: string, buffer: Uint8Array, start: number, end: number): Uint8Array;
53
+ write(path: string, buffer: Uint8Array, offset: number): void;
54
+ stat(path: string): Uint8Array;
55
+ }
56
+ /**
57
+ * The methods that can be called on the RPC port
58
+ * @category Internals
59
+ * @internal
60
+ */
61
+ export type RPCMethod = keyof RPCMethods;
62
+ /**
63
+ * An RPC message
64
+ * @category Internals
65
+ * @internal
66
+ */
67
+ export interface RPCMessage {
68
+ _zenfs: true;
69
+ id: string;
70
+ method: RPCMethod;
71
+ stack: string;
72
+ }
73
+ interface RPCRequest<TMethod extends RPCMethod = RPCMethod> extends RPCMessage {
74
+ method: TMethod;
75
+ args: Parameters<RPCMethods[TMethod]>;
76
+ }
77
+ export declare function attach<T extends RPCMessage>(port: RPCPort, handler: (message: T) => unknown): void;
78
+ export declare function detach<T extends RPCMessage>(port: RPCPort, handler: (message: T) => unknown): void;
79
+ export declare function catchMessages<T extends Backend>(port: RPCPort): (fs: FilesystemOf<T>) => Promise<void>;
80
+ /**
81
+ * @internal
82
+ */
83
+ export declare function waitOnline(port: RPCPort): Promise<void>;
84
+ declare const PortFS_base: import("../index.js").Mixin<typeof FileSystem, import("../mixins/async.js").AsyncMixin>;
85
+ /**
86
+ * PortFS lets you access an FS instance that is running in a port, or the other way around.
87
+ *
88
+ * Note that *direct* synchronous operations are not permitted on the PortFS,
89
+ * regardless of the configuration option of the remote FS.
90
+ * @category Internals
91
+ * @internal
92
+ */
93
+ export declare class PortFS extends PortFS_base {
94
+ readonly options: PortOptions;
95
+ readonly port: RPCPort;
96
+ /**`
97
+ * @hidden
98
+ */
99
+ _sync: import("./index.js").StoreFS<import("./memory.js").InMemoryStore>;
100
+ /**
101
+ * Constructs a new PortFS instance that connects with the FS running on `options.port`.
102
+ */
103
+ constructor(options: PortOptions);
104
+ protected rpc<const T extends RPCMethod>(method: T, ...args: Parameters<RPCMethods[T]>): Promise<Awaited<ReturnType<RPCMethods[T]>>>;
105
+ ready(): Promise<void>;
106
+ rename(oldPath: string, newPath: string): Promise<void>;
107
+ stat(path: string): Promise<Inode>;
108
+ touch(path: string, metadata: InodeLike | Inode): Promise<void>;
109
+ sync(path: string): Promise<void>;
110
+ createFile(path: string, options: CreationOptions): Promise<Inode>;
111
+ unlink(path: string): Promise<void>;
112
+ rmdir(path: string): Promise<void>;
113
+ mkdir(path: string, options: CreationOptions): Promise<Inode>;
114
+ readdir(path: string): Promise<string[]>;
115
+ exists(path: string): Promise<boolean>;
116
+ link(srcpath: string, dstpath: string): Promise<void>;
117
+ read(path: string, buffer: Uint8Array, start: number, end: number): Promise<void>;
118
+ write(path: string, buffer: Uint8Array, offset: number): Promise<void>;
119
+ }
120
+ /** @internal */
121
+ export declare function handleRequest(port: RPCPort, fs: FileSystem & {
122
+ _descriptors?: Map<number, File>;
123
+ }, request: RPCRequest): Promise<void>;
124
+ export declare function attachFS(port: RPCPort, fs: FileSystem): void;
125
+ export declare function detachFS(port: RPCPort, fs: FileSystem): void;
126
+ declare const _Port: {
127
+ name: string;
128
+ options: {
129
+ port: {
130
+ type: (arg: RPCPort) => boolean;
131
+ required: true;
132
+ };
133
+ timeout: {
134
+ type: string;
135
+ required: false;
136
+ };
137
+ };
138
+ create(options: PortOptions): PortFS;
139
+ };
140
+ type _Port = typeof _Port;
141
+ /**
142
+ * @category Backends and Configuration
143
+ */
144
+ export interface Port extends _Port {
145
+ }
146
+ /**
147
+ * A backend for usage with ports and workers. See the examples below.
148
+ *
149
+ * #### Accessing an FS on a remote Worker from the main thread
150
+ *
151
+ * Main:
152
+ *
153
+ * ```ts
154
+ * import { configure } from '@zenfs/core';
155
+ * import { Port } from '@zenfs/port';
156
+ * import { Worker } from 'node:worker_threads';
157
+ *
158
+ * const worker = new Worker('worker.js');
159
+ *
160
+ * await configure({
161
+ * mounts: {
162
+ * '/worker': {
163
+ * backend: Port,
164
+ * port: worker,
165
+ * },
166
+ * },
167
+ * });
168
+ * ```
169
+ *
170
+ * Worker:
171
+ *
172
+ * ```ts
173
+ * import { InMemory, resolveRemoteMount, attachFS } from '@zenfs/core';
174
+ * import { parentPort } from 'node:worker_threads';
175
+ *
176
+ * await resolveRemoteMount(parentPort, { backend: InMemory, name: 'tmp' });
177
+ * ```
178
+ *
179
+ * If you are using using web workers, you would use `self` instead of importing `parentPort` in the worker, and would not need to import `Worker` in the main thread.
180
+ *
181
+ * #### Using with multiple ports on the same thread
182
+ *
183
+ * ```ts
184
+ * import { InMemory, fs, resolveMountConfig, resolveRemoteMount, Port } from '@zenfs/core';
185
+ * import { MessageChannel } from 'node:worker_threads';
186
+ *
187
+ * const { port1: localPort, port2: remotePort } = new MessageChannel();
188
+ *
189
+ * fs.mount('/remote', await resolveRemoteMount(remotePort, { backend: InMemory, name: 'tmp' }));
190
+ * fs.mount('/port', await resolveMountConfig({ backend: Port, port: localPort }));
191
+ *
192
+ * const content = 'FS is in a port';
193
+ *
194
+ * await fs.promises.writeFile('/port/test', content);
195
+ *
196
+ * fs.readFileSync('/remote/test', 'utf8'); // FS is in a port
197
+ * await fs.promises.readFile('/port/test', 'utf8'); // FS is in a port
198
+ * ```
199
+ *
200
+ * @category Backends and Configuration
201
+ */
202
+ export declare const Port: Port;
203
+ /**
204
+ * @category Backends and Configuration
205
+ */
206
+ export declare function resolveRemoteMount<T extends Backend>(port: RPCPort, config: MountConfiguration<T>, _depth?: number): Promise<FilesystemOf<T>>;
207
+ export {};