@zenfs/core 1.1.4 → 1.1.6

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 (91) hide show
  1. package/dist/backends/fetch.js +5 -5
  2. package/dist/config.js +1 -0
  3. package/license.md +1 -1
  4. package/package.json +7 -4
  5. package/readme.md +3 -8
  6. package/scripts/make-index.js +3 -3
  7. package/scripts/test.js +31 -0
  8. package/tests/assignment.ts +20 -0
  9. package/tests/common.ts +21 -0
  10. package/tests/data/49chars.txt +1 -0
  11. package/tests/data/a.js +46 -0
  12. package/tests/data/a1.js +46 -0
  13. package/tests/data/elipses.txt +1 -0
  14. package/tests/data/empty.txt +0 -0
  15. package/tests/data/exit.js +22 -0
  16. package/tests/data/x.txt +1 -0
  17. package/tests/devices.test.ts +29 -0
  18. package/tests/fs/appendFile.test.ts +33 -0
  19. package/tests/fs/chmod.test.ts +48 -0
  20. package/tests/fs/dir.test.ts +156 -0
  21. package/tests/fs/directory.test.ts +129 -0
  22. package/tests/fs/errors.test.ts +53 -0
  23. package/tests/fs/exists.test.ts +22 -0
  24. package/tests/fs/links.test.ts +46 -0
  25. package/tests/fs/open.test.ts +39 -0
  26. package/tests/fs/permissions.test.ts +52 -0
  27. package/tests/fs/read.test.ts +67 -0
  28. package/tests/fs/readFile.test.ts +73 -0
  29. package/tests/fs/readdir.test.ts +87 -0
  30. package/tests/fs/rename.test.ts +107 -0
  31. package/tests/fs/stat.test.ts +48 -0
  32. package/tests/fs/streams.test.ts +177 -0
  33. package/tests/fs/times.test.ts +84 -0
  34. package/tests/fs/truncate.test.ts +94 -0
  35. package/tests/fs/watch.test.ts +124 -0
  36. package/tests/fs/write.test.ts +58 -0
  37. package/tests/fs/writeFile.test.ts +69 -0
  38. package/tests/handle.test.ts +60 -0
  39. package/tests/mutex.test.ts +62 -0
  40. package/tests/path.test.ts +34 -0
  41. package/tests/port/channel.test.ts +39 -0
  42. package/tests/port/config.test.ts +31 -0
  43. package/tests/port/config.worker.ts +5 -0
  44. package/tests/port/remote.test.ts +33 -0
  45. package/tests/port/remote.worker.ts +5 -0
  46. package/tests/port/timeout.test.ts +48 -0
  47. package/tests/readme.md +5 -0
  48. package/tests/setup/common.ts +28 -0
  49. package/tests/setup/cow+fetch.ts +43 -0
  50. package/tests/setup/memory.ts +3 -0
  51. package/tests/tsconfig.json +14 -0
  52. package/src/backends/backend.ts +0 -160
  53. package/src/backends/fetch.ts +0 -179
  54. package/src/backends/file_index.ts +0 -210
  55. package/src/backends/memory.ts +0 -50
  56. package/src/backends/overlay.ts +0 -568
  57. package/src/backends/port/fs.ts +0 -335
  58. package/src/backends/port/readme.md +0 -54
  59. package/src/backends/port/rpc.ts +0 -167
  60. package/src/backends/readme.md +0 -3
  61. package/src/backends/store/fs.ts +0 -715
  62. package/src/backends/store/readme.md +0 -9
  63. package/src/backends/store/simple.ts +0 -146
  64. package/src/backends/store/store.ts +0 -173
  65. package/src/config.ts +0 -152
  66. package/src/credentials.ts +0 -31
  67. package/src/devices.ts +0 -471
  68. package/src/emulation/async.ts +0 -834
  69. package/src/emulation/constants.ts +0 -182
  70. package/src/emulation/dir.ts +0 -138
  71. package/src/emulation/index.ts +0 -8
  72. package/src/emulation/path.ts +0 -440
  73. package/src/emulation/promises.ts +0 -1098
  74. package/src/emulation/shared.ts +0 -135
  75. package/src/emulation/streams.ts +0 -34
  76. package/src/emulation/sync.ts +0 -845
  77. package/src/emulation/watchers.ts +0 -193
  78. package/src/error.ts +0 -307
  79. package/src/file.ts +0 -661
  80. package/src/filesystem.ts +0 -174
  81. package/src/index.ts +0 -25
  82. package/src/inode.ts +0 -132
  83. package/src/mixins/async.ts +0 -208
  84. package/src/mixins/index.ts +0 -5
  85. package/src/mixins/mutexed.ts +0 -257
  86. package/src/mixins/readonly.ts +0 -96
  87. package/src/mixins/shared.ts +0 -25
  88. package/src/mixins/sync.ts +0 -58
  89. package/src/polyfills.ts +0 -21
  90. package/src/stats.ts +0 -363
  91. package/src/utils.ts +0 -288
package/src/devices.ts DELETED
@@ -1,471 +0,0 @@
1
- import type { FileReadResult } from 'node:fs/promises';
2
- import { InMemoryStore } from './backends/memory.js';
3
- import { StoreFS } from './backends/store/fs.js';
4
- import { S_IFBLK, S_IFCHR } from './emulation/constants.js';
5
- import { Errno, ErrnoError } from './error.js';
6
- import { File } from './file.js';
7
- import type { StatsLike } from './stats.js';
8
- import { Stats } from './stats.js';
9
- import { basename, dirname } from './emulation/path.js';
10
- import type { Ino } from './inode.js';
11
-
12
- /**
13
- * A device
14
- * @todo Maybe add major/minor number or some other device information, like a UUID?
15
- * @experimental
16
- */
17
- export interface Device {
18
- /**
19
- * The device's driver
20
- */
21
- driver: DeviceDriver;
22
-
23
- /**
24
- * Which inode the device is assigned
25
- */
26
- ino: Ino;
27
- }
28
-
29
- /**
30
- * A device driver
31
- * @experimental
32
- */
33
- export interface DeviceDriver {
34
- /**
35
- * The name of the device driver
36
- */
37
- name: string;
38
-
39
- /**
40
- * Whether the device is buffered (a "block" device) or unbuffered (a "character" device)
41
- */
42
- isBuffered: boolean;
43
-
44
- /**
45
- * Synchronously read from the device
46
- */
47
- read(file: DeviceFile, buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
48
-
49
- /**
50
- * Synchronously write to the device
51
- */
52
- write(file: DeviceFile, buffer: Uint8Array, offset: number, length: number, position?: number): number;
53
-
54
- /**
55
- * Sync the device
56
- */
57
- sync?(file: DeviceFile): void;
58
-
59
- /**
60
- * Close the device
61
- */
62
- close?(file: DeviceFile): void;
63
- }
64
-
65
- /**
66
- * The base class for device files
67
- * This class only does some simple things:
68
- * It implements `truncate` using `write` and it has non-device methods throw.
69
- * It is up to device drivers to implement the rest of the functionality.
70
- * @experimental
71
- */
72
- export class DeviceFile extends File {
73
- public position = 0;
74
-
75
- public constructor(
76
- public fs: DeviceFS,
77
- path: string,
78
- public readonly device: Device
79
- ) {
80
- super(fs, path);
81
- }
82
-
83
- public get driver(): DeviceDriver {
84
- return this.device.driver;
85
- }
86
-
87
- protected get stats(): Partial<StatsLike> {
88
- return { mode: (this.driver.isBuffered ? S_IFBLK : S_IFCHR) | 0o666 };
89
- }
90
-
91
- public async stat(): Promise<Stats> {
92
- return Promise.resolve(new Stats(this.stats));
93
- }
94
-
95
- public statSync(): Stats {
96
- return new Stats(this.stats);
97
- }
98
-
99
- public readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number {
100
- return this.driver.read(this, buffer, offset, length, position);
101
- }
102
-
103
- // eslint-disable-next-line @typescript-eslint/require-await
104
- public async read<TBuffer extends NodeJS.ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number): Promise<FileReadResult<TBuffer>> {
105
- return { bytesRead: this.readSync(buffer, offset, length), buffer };
106
- }
107
-
108
- public writeSync(buffer: Uint8Array, offset = 0, length = buffer.length, position?: number): number {
109
- return this.driver.write(this, buffer, offset, length, position);
110
- }
111
-
112
- // eslint-disable-next-line @typescript-eslint/require-await
113
- public async write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number> {
114
- return this.writeSync(buffer, offset, length, position);
115
- }
116
-
117
- public async truncate(length: number): Promise<void> {
118
- const { size } = await this.stat();
119
-
120
- const buffer = new Uint8Array(length > size ? length - size : 0);
121
-
122
- await this.write(buffer, 0, buffer.length, length > size ? size : length);
123
- }
124
-
125
- public truncateSync(length: number): void {
126
- const { size } = this.statSync();
127
-
128
- const buffer = new Uint8Array(length > size ? length - size : 0);
129
-
130
- this.writeSync(buffer, 0, buffer.length, length > size ? size : length);
131
- }
132
-
133
- public closeSync(): void {
134
- this.driver.close?.(this);
135
- }
136
-
137
- public close(): Promise<void> {
138
- this.closeSync();
139
- return Promise.resolve();
140
- }
141
-
142
- public syncSync(): void {
143
- this.driver.sync?.(this);
144
- }
145
-
146
- public sync(): Promise<void> {
147
- this.syncSync();
148
- return Promise.resolve();
149
- }
150
-
151
- public chown(): Promise<void> {
152
- throw ErrnoError.With('ENOTSUP', this.path, 'chown');
153
- }
154
-
155
- public chownSync(): void {
156
- throw ErrnoError.With('ENOTSUP', this.path, 'chown');
157
- }
158
-
159
- public chmod(): Promise<void> {
160
- throw ErrnoError.With('ENOTSUP', this.path, 'chmod');
161
- }
162
-
163
- public chmodSync(): void {
164
- throw ErrnoError.With('ENOTSUP', this.path, 'chmod');
165
- }
166
-
167
- public utimes(): Promise<void> {
168
- throw ErrnoError.With('ENOTSUP', this.path, 'utimes');
169
- }
170
-
171
- public utimesSync(): void {
172
- throw ErrnoError.With('ENOTSUP', this.path, 'utimes');
173
- }
174
-
175
- public _setType(): Promise<void> {
176
- throw ErrnoError.With('ENOTSUP', this.path, '_setType');
177
- }
178
-
179
- public _setTypeSync(): void {
180
- throw ErrnoError.With('ENOTSUP', this.path, '_setType');
181
- }
182
- }
183
-
184
- /**
185
- * @experimental
186
- */
187
- export class DeviceFS extends StoreFS<InMemoryStore> {
188
- protected readonly devices = new Map<string, Device>();
189
-
190
- public createDevice(path: string, driver: DeviceDriver): Device {
191
- if (this.existsSync(path)) {
192
- throw ErrnoError.With('EEXIST', path, 'mknod');
193
- }
194
- let ino = 1n;
195
- while (this.store.has(ino)) ino++;
196
- const dev = {
197
- driver,
198
- ino,
199
- };
200
- this.devices.set(path, dev);
201
- return dev;
202
- }
203
-
204
- public constructor() {
205
- super(new InMemoryStore('devfs'));
206
- }
207
-
208
- public async rename(oldPath: string, newPath: string): Promise<void> {
209
- if (this.devices.has(oldPath)) {
210
- throw ErrnoError.With('EPERM', oldPath, 'rename');
211
- }
212
- if (this.devices.has(newPath)) {
213
- throw ErrnoError.With('EEXIST', newPath, 'rename');
214
- }
215
- return super.rename(oldPath, newPath);
216
- }
217
-
218
- public renameSync(oldPath: string, newPath: string): void {
219
- if (this.devices.has(oldPath)) {
220
- throw ErrnoError.With('EPERM', oldPath, 'rename');
221
- }
222
- if (this.devices.has(newPath)) {
223
- throw ErrnoError.With('EEXIST', newPath, 'rename');
224
- }
225
- return super.renameSync(oldPath, newPath);
226
- }
227
-
228
- public async stat(path: string): Promise<Stats> {
229
- if (this.devices.has(path)) {
230
- await using file = await this.openFile(path, 'r');
231
- return file.stat();
232
- }
233
- return super.stat(path);
234
- }
235
-
236
- public statSync(path: string): Stats {
237
- if (this.devices.has(path)) {
238
- using file = this.openFileSync(path, 'r');
239
- return file.statSync();
240
- }
241
- return super.statSync(path);
242
- }
243
-
244
- public async openFile(path: string, flag: string): Promise<File> {
245
- if (this.devices.has(path)) {
246
- return new DeviceFile(this, path, this.devices.get(path)!);
247
- }
248
- return await super.openFile(path, flag);
249
- }
250
-
251
- public openFileSync(path: string, flag: string): File {
252
- if (this.devices.has(path)) {
253
- return new DeviceFile(this, path, this.devices.get(path)!);
254
- }
255
- return super.openFileSync(path, flag);
256
- }
257
-
258
- public async createFile(path: string, flag: string, mode: number): Promise<File> {
259
- if (this.devices.has(path)) {
260
- throw ErrnoError.With('EEXIST', path, 'createFile');
261
- }
262
- return super.createFile(path, flag, mode);
263
- }
264
-
265
- public createFileSync(path: string, flag: string, mode: number): File {
266
- if (this.devices.has(path)) {
267
- throw ErrnoError.With('EEXIST', path, 'createFile');
268
- }
269
- return super.createFileSync(path, flag, mode);
270
- }
271
-
272
- public async unlink(path: string): Promise<void> {
273
- if (this.devices.has(path)) {
274
- throw ErrnoError.With('EPERM', path, 'unlink');
275
- }
276
- return super.unlink(path);
277
- }
278
-
279
- public unlinkSync(path: string): void {
280
- if (this.devices.has(path)) {
281
- throw ErrnoError.With('EPERM', path, 'unlink');
282
- }
283
- return super.unlinkSync(path);
284
- }
285
-
286
- public async rmdir(path: string): Promise<void> {
287
- if (this.devices.has(path)) {
288
- throw ErrnoError.With('ENOTDIR', path, 'rmdir');
289
- }
290
- return super.rmdir(path);
291
- }
292
-
293
- public rmdirSync(path: string): void {
294
- if (this.devices.has(path)) {
295
- throw ErrnoError.With('ENOTDIR', path, 'rmdir');
296
- }
297
- return super.rmdirSync(path);
298
- }
299
-
300
- public async mkdir(path: string, mode: number): Promise<void> {
301
- if (this.devices.has(path)) {
302
- throw ErrnoError.With('EEXIST', path, 'mkdir');
303
- }
304
- return super.mkdir(path, mode);
305
- }
306
-
307
- public mkdirSync(path: string, mode: number): void {
308
- if (this.devices.has(path)) {
309
- throw ErrnoError.With('EEXIST', path, 'mkdir');
310
- }
311
- return super.mkdirSync(path, mode);
312
- }
313
-
314
- public async readdir(path: string): Promise<string[]> {
315
- if (this.devices.has(path)) {
316
- throw ErrnoError.With('ENOTDIR', path, 'readdir');
317
- }
318
- const entries = await super.readdir(path);
319
- for (const dev of this.devices.keys()) {
320
- if (dirname(dev) == path) {
321
- entries.push(basename(dev));
322
- }
323
- }
324
- return entries;
325
- }
326
-
327
- public readdirSync(path: string): string[] {
328
- if (this.devices.has(path)) {
329
- throw ErrnoError.With('ENOTDIR', path, 'readdirSync');
330
- }
331
- const entries = super.readdirSync(path);
332
- for (const dev of this.devices.keys()) {
333
- if (dirname(dev) == path) {
334
- entries.push(basename(dev));
335
- }
336
- }
337
- return entries;
338
- }
339
-
340
- public async link(target: string, link: string): Promise<void> {
341
- if (this.devices.has(target)) {
342
- throw ErrnoError.With('EPERM', target, 'rmdir');
343
- }
344
- if (this.devices.has(link)) {
345
- throw ErrnoError.With('EEXIST', link, 'link');
346
- }
347
- return super.link(target, link);
348
- }
349
-
350
- public linkSync(target: string, link: string): void {
351
- if (this.devices.has(target)) {
352
- throw ErrnoError.With('EPERM', target, 'rmdir');
353
- }
354
- if (this.devices.has(link)) {
355
- throw ErrnoError.With('EEXIST', link, 'link');
356
- }
357
- return super.linkSync(target, link);
358
- }
359
-
360
- public async sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void> {
361
- if (this.devices.has(path)) {
362
- throw new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync');
363
- }
364
- return super.sync(path, data, stats);
365
- }
366
-
367
- public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
368
- if (this.devices.has(path)) {
369
- throw new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync');
370
- }
371
- return super.syncSync(path, data, stats);
372
- }
373
- }
374
-
375
- function defaultWrite(file: DeviceFile, buffer: Uint8Array, offset: number, length: number): number {
376
- file.position += length;
377
- return length;
378
- }
379
-
380
- /**
381
- * Simulates the `/dev/null` device.
382
- * - Reads return 0 bytes (EOF).
383
- * - Writes discard data, advancing the file position.
384
- * @experimental
385
- */
386
- export const nullDevice: DeviceDriver = {
387
- name: 'null',
388
- isBuffered: false,
389
- read(): number {
390
- return 0;
391
- },
392
- write: defaultWrite,
393
- };
394
-
395
- /**
396
- * Simulates the `/dev/zero` device
397
- * Provides an infinite stream of zeroes when read.
398
- * Discards any data written to it.
399
- *
400
- * - Reads fill the buffer with zeroes.
401
- * - Writes discard data but update the file position.
402
- * - Provides basic file metadata, treating it as a character device.
403
- * @experimental
404
- */
405
- export const zeroDevice: DeviceDriver = {
406
- name: 'zero',
407
- isBuffered: false,
408
- read(file: DeviceFile, buffer: ArrayBufferView, offset = 0, length = buffer.byteLength): number {
409
- const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
410
- for (let i = offset; i < offset + length; i++) {
411
- data[i] = 0;
412
- }
413
- file.position += length;
414
- return length;
415
- },
416
- write: defaultWrite,
417
- };
418
-
419
- /**
420
- * Simulates the `/dev/full` device.
421
- * - Reads behave like `/dev/zero` (returns zeroes).
422
- * - Writes always fail with ENOSPC (no space left on device).
423
- * @experimental
424
- */
425
- export const fullDevice: DeviceDriver = {
426
- name: 'full',
427
- isBuffered: false,
428
- read(file: DeviceFile, buffer: ArrayBufferView, offset = 0, length = buffer.byteLength): number {
429
- const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
430
- for (let i = offset; i < offset + length; i++) {
431
- data[i] = 0;
432
- }
433
- file.position += length;
434
- return length;
435
- },
436
-
437
- write(file: DeviceFile): number {
438
- throw ErrnoError.With('ENOSPC', file.path, 'write');
439
- },
440
- };
441
-
442
- /**
443
- * Simulates the `/dev/random` device.
444
- * - Reads return random bytes.
445
- * - Writes discard data, advancing the file position.
446
- * @experimental
447
- */
448
- export const randomDevice: DeviceDriver = {
449
- name: 'random',
450
- isBuffered: false,
451
- read(file: DeviceFile, buffer: ArrayBufferView, offset = 0, length = buffer.byteLength): number {
452
- const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
453
- for (let i = offset; i < offset + length; i++) {
454
- data[i] = Math.floor(Math.random() * 256);
455
- }
456
- file.position += length;
457
- return length;
458
- },
459
- write: defaultWrite,
460
- };
461
-
462
- /**
463
- * Shortcuts for importing.
464
- * @experimental
465
- */
466
- export default {
467
- null: nullDevice,
468
- zero: zeroDevice,
469
- full: fullDevice,
470
- random: randomDevice,
471
- };