@zenfs/core 1.0.10 → 1.1.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 (88) hide show
  1. package/dist/backends/backend.d.ts +4 -8
  2. package/dist/backends/backend.js +7 -11
  3. package/dist/backends/fetch.d.ts +2 -4
  4. package/dist/backends/fetch.js +1 -3
  5. package/dist/backends/file_index.js +3 -3
  6. package/dist/backends/memory.d.ts +1 -1
  7. package/dist/backends/overlay.d.ts +7 -3
  8. package/dist/backends/overlay.js +13 -9
  9. package/dist/backends/port/fs.d.ts +12 -17
  10. package/dist/backends/port/fs.js +5 -8
  11. package/dist/backends/port/rpc.d.ts +1 -1
  12. package/dist/backends/store/fs.d.ts +13 -15
  13. package/dist/backends/store/fs.js +35 -54
  14. package/dist/backends/store/simple.d.ts +1 -1
  15. package/dist/backends/store/simple.js +1 -1
  16. package/dist/backends/store/store.d.ts +7 -13
  17. package/dist/config.d.ts +13 -5
  18. package/dist/config.js +36 -26
  19. package/dist/devices.d.ts +158 -0
  20. package/dist/devices.js +423 -0
  21. package/dist/emulation/async.d.ts +21 -176
  22. package/dist/emulation/async.js +17 -111
  23. package/dist/emulation/constants.d.ts +5 -0
  24. package/dist/emulation/constants.js +5 -0
  25. package/dist/emulation/dir.d.ts +0 -1
  26. package/dist/emulation/path.d.ts +0 -4
  27. package/dist/emulation/path.js +4 -8
  28. package/dist/emulation/promises.d.ts +31 -121
  29. package/dist/emulation/promises.js +30 -97
  30. package/dist/emulation/shared.d.ts +7 -3
  31. package/dist/emulation/shared.js +11 -7
  32. package/dist/emulation/streams.d.ts +0 -3
  33. package/dist/emulation/sync.d.ts +25 -178
  34. package/dist/emulation/sync.js +36 -129
  35. package/dist/emulation/watchers.d.ts +0 -4
  36. package/dist/error.d.ts +11 -11
  37. package/dist/error.js +8 -10
  38. package/dist/file.d.ts +50 -171
  39. package/dist/file.js +34 -117
  40. package/dist/filesystem.d.ts +10 -62
  41. package/dist/filesystem.js +5 -6
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +2 -0
  44. package/dist/inode.d.ts +0 -5
  45. package/dist/inode.js +0 -5
  46. package/dist/mixins/async.d.ts +4 -6
  47. package/dist/mixins/async.js +3 -1
  48. package/dist/mixins/mutexed.d.ts +4 -4
  49. package/dist/mixins/mutexed.js +7 -5
  50. package/dist/mixins/readonly.js +14 -15
  51. package/dist/mixins/shared.d.ts +5 -5
  52. package/dist/mixins/sync.d.ts +2 -2
  53. package/dist/stats.d.ts +21 -37
  54. package/dist/stats.js +10 -23
  55. package/dist/utils.d.ts +15 -7
  56. package/dist/utils.js +28 -6
  57. package/package.json +4 -4
  58. package/readme.md +58 -2
  59. package/src/backends/backend.ts +7 -11
  60. package/src/backends/fetch.ts +2 -4
  61. package/src/backends/file_index.ts +3 -3
  62. package/src/backends/memory.ts +1 -1
  63. package/src/backends/overlay.ts +11 -9
  64. package/src/backends/port/fs.ts +11 -14
  65. package/src/backends/port/rpc.ts +1 -0
  66. package/src/backends/store/fs.ts +40 -55
  67. package/src/backends/store/simple.ts +1 -1
  68. package/src/backends/store/store.ts +7 -13
  69. package/src/config.ts +48 -26
  70. package/src/devices.ts +469 -0
  71. package/src/emulation/async.ts +28 -178
  72. package/src/emulation/constants.ts +6 -0
  73. package/src/emulation/path.ts +4 -11
  74. package/src/emulation/promises.ts +34 -116
  75. package/src/emulation/shared.ts +11 -8
  76. package/src/emulation/sync.ts +41 -185
  77. package/src/error.ts +7 -11
  78. package/src/file.ts +48 -182
  79. package/src/filesystem.ts +14 -65
  80. package/src/index.ts +2 -0
  81. package/src/inode.ts +0 -6
  82. package/src/mixins/async.ts +4 -6
  83. package/src/mixins/mutexed.ts +4 -4
  84. package/src/mixins/readonly.ts +15 -15
  85. package/src/mixins/shared.ts +5 -5
  86. package/src/mixins/sync.ts +3 -3
  87. package/src/stats.ts +22 -40
  88. package/src/utils.ts +33 -6
@@ -0,0 +1,423 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ function next() {
30
+ while (env.stack.length) {
31
+ var rec = env.stack.pop();
32
+ try {
33
+ var result = rec.dispose && rec.dispose.call(rec.value);
34
+ if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
35
+ }
36
+ catch (e) {
37
+ fail(e);
38
+ }
39
+ }
40
+ if (env.hasError) throw env.error;
41
+ }
42
+ return next();
43
+ };
44
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
45
+ var e = new Error(message);
46
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
47
+ });
48
+ import { InMemoryStore } from './backends/memory.js';
49
+ import { StoreFS } from './backends/store/fs.js';
50
+ import { S_IFBLK, S_IFCHR } from './emulation/constants.js';
51
+ import { Errno, ErrnoError } from './error.js';
52
+ import { File } from './file.js';
53
+ import { Stats } from './stats.js';
54
+ import { basename, dirname } from './emulation/path.js';
55
+ /**
56
+ * The base class for device files
57
+ * This class only does some simple things:
58
+ * It implements `truncate` using `write` and it has non-device methods throw.
59
+ * It is up to device drivers to implement the rest of the functionality.
60
+ * @experimental
61
+ */
62
+ export class DeviceFile extends File {
63
+ constructor(fs, path, device) {
64
+ super(fs, path);
65
+ this.fs = fs;
66
+ this.device = device;
67
+ this.position = 0;
68
+ }
69
+ get driver() {
70
+ return this.device.driver;
71
+ }
72
+ get stats() {
73
+ return { mode: (this.driver.isBuffered ? S_IFBLK : S_IFCHR) | 0o666 };
74
+ }
75
+ async stat() {
76
+ return Promise.resolve(new Stats(this.stats));
77
+ }
78
+ statSync() {
79
+ return new Stats(this.stats);
80
+ }
81
+ readSync(buffer, offset, length, position) {
82
+ return this.driver.read(this, buffer, offset, length, position);
83
+ }
84
+ // eslint-disable-next-line @typescript-eslint/require-await
85
+ async read(buffer, offset, length) {
86
+ return { bytesRead: this.readSync(buffer, offset, length), buffer };
87
+ }
88
+ writeSync(buffer, offset = 0, length = buffer.length, position) {
89
+ return this.driver.write(this, buffer, offset, length, position);
90
+ }
91
+ // eslint-disable-next-line @typescript-eslint/require-await
92
+ async write(buffer, offset, length, position) {
93
+ return this.writeSync(buffer, offset, length, position);
94
+ }
95
+ async truncate(length) {
96
+ const { size } = await this.stat();
97
+ const buffer = new Uint8Array(length > size ? length - size : 0);
98
+ await this.write(buffer, 0, buffer.length, length > size ? size : length);
99
+ }
100
+ truncateSync(length) {
101
+ const { size } = this.statSync();
102
+ const buffer = new Uint8Array(length > size ? length - size : 0);
103
+ this.writeSync(buffer, 0, buffer.length, length > size ? size : length);
104
+ }
105
+ closeSync() {
106
+ this.driver.close?.(this);
107
+ }
108
+ async close() {
109
+ this.closeSync();
110
+ }
111
+ syncSync() {
112
+ this.driver.sync?.(this);
113
+ }
114
+ async sync() {
115
+ this.syncSync();
116
+ }
117
+ chown() {
118
+ throw ErrnoError.With('ENOTSUP', this.path, 'chown');
119
+ }
120
+ chownSync() {
121
+ throw ErrnoError.With('ENOTSUP', this.path, 'chown');
122
+ }
123
+ chmod() {
124
+ throw ErrnoError.With('ENOTSUP', this.path, 'chmod');
125
+ }
126
+ chmodSync() {
127
+ throw ErrnoError.With('ENOTSUP', this.path, 'chmod');
128
+ }
129
+ utimes() {
130
+ throw ErrnoError.With('ENOTSUP', this.path, 'utimes');
131
+ }
132
+ utimesSync() {
133
+ throw ErrnoError.With('ENOTSUP', this.path, 'utimes');
134
+ }
135
+ _setType() {
136
+ throw ErrnoError.With('ENOTSUP', this.path, '_setType');
137
+ }
138
+ _setTypeSync() {
139
+ throw ErrnoError.With('ENOTSUP', this.path, '_setType');
140
+ }
141
+ }
142
+ /**
143
+ * @experimental
144
+ */
145
+ export class DeviceFS extends StoreFS {
146
+ createDevice(path, driver) {
147
+ if (this.existsSync(path)) {
148
+ throw ErrnoError.With('EEXIST', path, 'mknod');
149
+ }
150
+ let ino = 1n;
151
+ while (this.store.has(ino))
152
+ ino++;
153
+ const dev = {
154
+ driver,
155
+ ino,
156
+ };
157
+ this.devices.set(path, dev);
158
+ return dev;
159
+ }
160
+ constructor() {
161
+ super(new InMemoryStore('devfs'));
162
+ this.devices = new Map();
163
+ }
164
+ async rename(oldPath, newPath) {
165
+ if (this.devices.has(oldPath)) {
166
+ throw ErrnoError.With('EPERM', oldPath, 'rename');
167
+ }
168
+ if (this.devices.has(newPath)) {
169
+ throw ErrnoError.With('EEXIST', newPath, 'rename');
170
+ }
171
+ return super.rename(oldPath, newPath);
172
+ }
173
+ renameSync(oldPath, newPath) {
174
+ if (this.devices.has(oldPath)) {
175
+ throw ErrnoError.With('EPERM', oldPath, 'rename');
176
+ }
177
+ if (this.devices.has(newPath)) {
178
+ throw ErrnoError.With('EEXIST', newPath, 'rename');
179
+ }
180
+ return super.renameSync(oldPath, newPath);
181
+ }
182
+ async stat(path) {
183
+ if (this.devices.has(path)) {
184
+ const env_1 = { stack: [], error: void 0, hasError: false };
185
+ try {
186
+ const file = __addDisposableResource(env_1, await this.openFile(path, 'r'), true);
187
+ return file.stat();
188
+ }
189
+ catch (e_1) {
190
+ env_1.error = e_1;
191
+ env_1.hasError = true;
192
+ }
193
+ finally {
194
+ const result_1 = __disposeResources(env_1);
195
+ if (result_1)
196
+ await result_1;
197
+ }
198
+ }
199
+ return super.stat(path);
200
+ }
201
+ statSync(path) {
202
+ if (this.devices.has(path)) {
203
+ const env_2 = { stack: [], error: void 0, hasError: false };
204
+ try {
205
+ const file = __addDisposableResource(env_2, this.openFileSync(path, 'r'), false);
206
+ return file.statSync();
207
+ }
208
+ catch (e_2) {
209
+ env_2.error = e_2;
210
+ env_2.hasError = true;
211
+ }
212
+ finally {
213
+ __disposeResources(env_2);
214
+ }
215
+ }
216
+ return super.statSync(path);
217
+ }
218
+ async openFile(path, flag) {
219
+ if (this.devices.has(path)) {
220
+ return new DeviceFile(this, path, this.devices.get(path));
221
+ }
222
+ return await super.openFile(path, flag);
223
+ }
224
+ openFileSync(path, flag) {
225
+ if (this.devices.has(path)) {
226
+ return new DeviceFile(this, path, this.devices.get(path));
227
+ }
228
+ return super.openFileSync(path, flag);
229
+ }
230
+ async createFile(path, flag, mode) {
231
+ if (this.devices.has(path)) {
232
+ throw ErrnoError.With('EEXIST', path, 'createFile');
233
+ }
234
+ return super.createFile(path, flag, mode);
235
+ }
236
+ createFileSync(path, flag, mode) {
237
+ if (this.devices.has(path)) {
238
+ throw ErrnoError.With('EEXIST', path, 'createFile');
239
+ }
240
+ return super.createFileSync(path, flag, mode);
241
+ }
242
+ async unlink(path) {
243
+ if (this.devices.has(path)) {
244
+ throw ErrnoError.With('EPERM', path, 'unlink');
245
+ }
246
+ return super.unlink(path);
247
+ }
248
+ unlinkSync(path) {
249
+ if (this.devices.has(path)) {
250
+ throw ErrnoError.With('EPERM', path, 'unlink');
251
+ }
252
+ return super.unlinkSync(path);
253
+ }
254
+ async rmdir(path) {
255
+ if (this.devices.has(path)) {
256
+ throw ErrnoError.With('ENOTDIR', path, 'rmdir');
257
+ }
258
+ return super.rmdir(path);
259
+ }
260
+ rmdirSync(path) {
261
+ if (this.devices.has(path)) {
262
+ throw ErrnoError.With('ENOTDIR', path, 'rmdir');
263
+ }
264
+ return super.rmdirSync(path);
265
+ }
266
+ async mkdir(path, mode) {
267
+ if (this.devices.has(path)) {
268
+ throw ErrnoError.With('EEXIST', path, 'mkdir');
269
+ }
270
+ return super.mkdir(path, mode);
271
+ }
272
+ mkdirSync(path, mode) {
273
+ if (this.devices.has(path)) {
274
+ throw ErrnoError.With('EEXIST', path, 'mkdir');
275
+ }
276
+ return super.mkdirSync(path, mode);
277
+ }
278
+ async readdir(path) {
279
+ if (this.devices.has(path)) {
280
+ throw ErrnoError.With('ENOTDIR', path, 'readdir');
281
+ }
282
+ const entries = await super.readdir(path);
283
+ for (const dev of this.devices.keys()) {
284
+ if (dirname(dev) == path) {
285
+ entries.push(basename(dev));
286
+ }
287
+ }
288
+ return entries;
289
+ }
290
+ readdirSync(path) {
291
+ if (this.devices.has(path)) {
292
+ throw ErrnoError.With('ENOTDIR', path, 'readdirSync');
293
+ }
294
+ const entries = super.readdirSync(path);
295
+ for (const dev of this.devices.keys()) {
296
+ if (dirname(dev) == path) {
297
+ entries.push(basename(dev));
298
+ }
299
+ }
300
+ return entries;
301
+ }
302
+ async link(target, link) {
303
+ if (this.devices.has(target)) {
304
+ throw ErrnoError.With('EPERM', target, 'rmdir');
305
+ }
306
+ if (this.devices.has(link)) {
307
+ throw ErrnoError.With('EEXIST', link, 'link');
308
+ }
309
+ return super.link(target, link);
310
+ }
311
+ linkSync(target, link) {
312
+ if (this.devices.has(target)) {
313
+ throw ErrnoError.With('EPERM', target, 'rmdir');
314
+ }
315
+ if (this.devices.has(link)) {
316
+ throw ErrnoError.With('EEXIST', link, 'link');
317
+ }
318
+ return super.linkSync(target, link);
319
+ }
320
+ async sync(path, data, stats) {
321
+ if (this.devices.has(path)) {
322
+ throw new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync');
323
+ }
324
+ return super.sync(path, data, stats);
325
+ }
326
+ syncSync(path, data, stats) {
327
+ if (this.devices.has(path)) {
328
+ throw new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync');
329
+ }
330
+ return super.syncSync(path, data, stats);
331
+ }
332
+ }
333
+ function defaultWrite(file, buffer, offset, length) {
334
+ file.position += length;
335
+ return length;
336
+ }
337
+ /**
338
+ * Simulates the `/dev/null` device.
339
+ * - Reads return 0 bytes (EOF).
340
+ * - Writes discard data, advancing the file position.
341
+ * @experimental
342
+ */
343
+ export const nullDevice = {
344
+ name: 'null',
345
+ isBuffered: false,
346
+ read() {
347
+ return 0;
348
+ },
349
+ write: defaultWrite,
350
+ };
351
+ /**
352
+ * Simulates the `/dev/zero` device
353
+ * Provides an infinite stream of zeroes when read.
354
+ * Discards any data written to it.
355
+ *
356
+ * - Reads fill the buffer with zeroes.
357
+ * - Writes discard data but update the file position.
358
+ * - Provides basic file metadata, treating it as a character device.
359
+ * @experimental
360
+ */
361
+ export const zeroDevice = {
362
+ name: 'zero',
363
+ isBuffered: false,
364
+ read(file, buffer, offset = 0, length = buffer.byteLength) {
365
+ const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
366
+ for (let i = offset; i < offset + length; i++) {
367
+ data[i] = 0;
368
+ }
369
+ file.position += length;
370
+ return length;
371
+ },
372
+ write: defaultWrite,
373
+ };
374
+ /**
375
+ * Simulates the `/dev/full` device.
376
+ * - Reads behave like `/dev/zero` (returns zeroes).
377
+ * - Writes always fail with ENOSPC (no space left on device).
378
+ * @experimental
379
+ */
380
+ export const fullDevice = {
381
+ name: 'full',
382
+ isBuffered: false,
383
+ read(file, buffer, offset = 0, length = buffer.byteLength) {
384
+ const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
385
+ for (let i = offset; i < offset + length; i++) {
386
+ data[i] = 0;
387
+ }
388
+ file.position += length;
389
+ return length;
390
+ },
391
+ write(file) {
392
+ throw ErrnoError.With('ENOSPC', file.path, 'write');
393
+ },
394
+ };
395
+ /**
396
+ * Simulates the `/dev/random` device.
397
+ * - Reads return random bytes.
398
+ * - Writes discard data, advancing the file position.
399
+ * @experimental
400
+ */
401
+ export const randomDevice = {
402
+ name: 'random',
403
+ isBuffered: false,
404
+ read(file, buffer, offset = 0, length = buffer.byteLength) {
405
+ const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
406
+ for (let i = offset; i < offset + length; i++) {
407
+ data[i] = Math.floor(Math.random() * 256);
408
+ }
409
+ file.position += length;
410
+ return length;
411
+ },
412
+ write: defaultWrite,
413
+ };
414
+ /**
415
+ * Shortcuts for importing.
416
+ * @experimental
417
+ */
418
+ export default {
419
+ null: nullDevice,
420
+ zero: zeroDevice,
421
+ full: fullDevice,
422
+ random: randomDevice,
423
+ };