@zenfs/core 0.9.7 → 0.10.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 (71) hide show
  1. package/dist/backends/AsyncStore.js +29 -29
  2. package/dist/backends/Fetch.d.ts +84 -0
  3. package/dist/backends/Fetch.js +171 -0
  4. package/dist/backends/Index.js +19 -19
  5. package/dist/backends/Locked.d.ts +11 -11
  6. package/dist/backends/Locked.js +50 -49
  7. package/dist/backends/Overlay.js +21 -21
  8. package/dist/backends/SyncStore.js +27 -27
  9. package/dist/backends/backend.js +4 -4
  10. package/dist/backends/port/fs.d.ts +124 -0
  11. package/dist/backends/port/fs.js +241 -0
  12. package/dist/backends/port/rpc.d.ts +60 -0
  13. package/dist/backends/port/rpc.js +71 -0
  14. package/dist/backends/port/store.d.ts +30 -0
  15. package/dist/backends/port/store.js +142 -0
  16. package/dist/browser.min.js +4 -4
  17. package/dist/browser.min.js.map +4 -4
  18. package/dist/config.d.ts +8 -10
  19. package/dist/config.js +11 -11
  20. package/dist/emulation/async.js +6 -6
  21. package/dist/emulation/dir.js +2 -2
  22. package/dist/emulation/index.d.ts +1 -1
  23. package/dist/emulation/index.js +1 -1
  24. package/dist/emulation/path.d.ts +3 -2
  25. package/dist/emulation/path.js +19 -45
  26. package/dist/emulation/promises.d.ts +7 -12
  27. package/dist/emulation/promises.js +144 -146
  28. package/dist/emulation/shared.d.ts +5 -10
  29. package/dist/emulation/shared.js +8 -8
  30. package/dist/emulation/streams.js +3 -3
  31. package/dist/emulation/sync.js +25 -25
  32. package/dist/{ApiError.d.ts → error.d.ts} +13 -14
  33. package/dist/error.js +292 -0
  34. package/dist/file.d.ts +2 -0
  35. package/dist/file.js +10 -4
  36. package/dist/filesystem.js +15 -15
  37. package/dist/index.d.ts +4 -1
  38. package/dist/index.js +4 -1
  39. package/dist/mutex.js +2 -1
  40. package/dist/utils.d.ts +8 -7
  41. package/dist/utils.js +11 -12
  42. package/package.json +3 -3
  43. package/readme.md +17 -9
  44. package/src/backends/AsyncStore.ts +29 -29
  45. package/src/backends/Fetch.ts +230 -0
  46. package/src/backends/Index.ts +19 -19
  47. package/src/backends/Locked.ts +50 -49
  48. package/src/backends/Overlay.ts +23 -23
  49. package/src/backends/SyncStore.ts +27 -27
  50. package/src/backends/backend.ts +6 -6
  51. package/src/backends/port/fs.ts +308 -0
  52. package/src/backends/port/readme.md +59 -0
  53. package/src/backends/port/rpc.ts +144 -0
  54. package/src/backends/port/store.ts +187 -0
  55. package/src/config.ts +20 -24
  56. package/src/emulation/async.ts +6 -6
  57. package/src/emulation/dir.ts +2 -2
  58. package/src/emulation/index.ts +1 -1
  59. package/src/emulation/path.ts +25 -49
  60. package/src/emulation/promises.ts +150 -159
  61. package/src/emulation/shared.ts +12 -14
  62. package/src/emulation/streams.ts +3 -3
  63. package/src/emulation/sync.ts +28 -28
  64. package/src/{ApiError.ts → error.ts} +89 -89
  65. package/src/file.ts +12 -4
  66. package/src/filesystem.ts +15 -15
  67. package/src/index.ts +4 -1
  68. package/src/mutex.ts +3 -1
  69. package/src/utils.ts +16 -18
  70. package/tsconfig.json +2 -2
  71. package/dist/ApiError.js +0 -292
@@ -1,5 +1,5 @@
1
1
  import { Readable, Writable } from 'readable-stream';
2
- import { ApiError, ErrorCode } from '../ApiError.js';
2
+ import { ErrnoError, Errno } from '../error.js';
3
3
  export class ReadStream extends Readable {
4
4
  close(callback = () => null) {
5
5
  try {
@@ -8,7 +8,7 @@ export class ReadStream extends Readable {
8
8
  callback();
9
9
  }
10
10
  catch (err) {
11
- callback(new ApiError(ErrorCode.EIO, err.toString()));
11
+ callback(new ErrnoError(Errno.EIO, err.toString()));
12
12
  }
13
13
  }
14
14
  }
@@ -20,7 +20,7 @@ export class WriteStream extends Writable {
20
20
  callback();
21
21
  }
22
22
  catch (err) {
23
- callback(new ApiError(ErrorCode.EIO, err.toString()));
23
+ callback(new ErrnoError(Errno.EIO, err.toString()));
24
24
  }
25
25
  }
26
26
  }
@@ -1,5 +1,5 @@
1
1
  import { Buffer } from 'buffer';
2
- import { ApiError, ErrorCode } from '../ApiError.js';
2
+ import { ErrnoError, Errno } from '../error.js';
3
3
  import { ActionType, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js';
4
4
  import { BigIntStats, FileType } from '../stats.js';
5
5
  import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
@@ -52,7 +52,7 @@ export function existsSync(path) {
52
52
  return fs.existsSync(resolvedPath, cred);
53
53
  }
54
54
  catch (e) {
55
- if (e.errno == ErrorCode.ENOENT) {
55
+ if (e.errno == Errno.ENOENT) {
56
56
  return false;
57
57
  }
58
58
  throw e;
@@ -106,22 +106,22 @@ function _openSync(_path, _flag, _mode, resolveSymlinks = true) {
106
106
  // Ensure parent exists.
107
107
  const parentStats = doOp('statSync', resolveSymlinks, dirname(path), cred);
108
108
  if (!parentStats.isDirectory()) {
109
- throw ApiError.With('ENOTDIR', dirname(path), '_open');
109
+ throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
110
110
  }
111
111
  return doOp('createFileSync', resolveSymlinks, path, flag, mode, cred);
112
112
  case ActionType.THROW:
113
- throw ApiError.With('ENOENT', path, '_open');
113
+ throw ErrnoError.With('ENOENT', path, '_open');
114
114
  default:
115
- throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
115
+ throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
116
116
  }
117
117
  }
118
118
  if (!stats.hasAccess(mode, cred)) {
119
- throw ApiError.With('EACCES', path, '_open');
119
+ throw ErrnoError.With('EACCES', path, '_open');
120
120
  }
121
121
  // File exists.
122
122
  switch (pathExistsAction(flag)) {
123
123
  case ActionType.THROW:
124
- throw ApiError.With('EEXIST', path, '_open');
124
+ throw ErrnoError.With('EEXIST', path, '_open');
125
125
  case ActionType.TRUNCATE:
126
126
  // Delete file.
127
127
  doOp('unlinkSync', resolveSymlinks, path, cred);
@@ -135,7 +135,7 @@ function _openSync(_path, _flag, _mode, resolveSymlinks = true) {
135
135
  case ActionType.NOP:
136
136
  return doOp('openFileSync', resolveSymlinks, path, flag, cred);
137
137
  default:
138
- throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
138
+ throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
139
139
  }
140
140
  }
141
141
  /**
@@ -179,7 +179,7 @@ export function readFileSync(path, _options = {}) {
179
179
  const options = normalizeOptions(_options, null, 'r', 0o644);
180
180
  const flag = parseFlag(options.flag);
181
181
  if (!isReadable(flag)) {
182
- throw new ApiError(ErrorCode.EINVAL, 'Flag passed to readFile must allow for reading.');
182
+ throw new ErrnoError(Errno.EINVAL, 'Flag passed to readFile must allow for reading.');
183
183
  }
184
184
  const data = Buffer.from(_readFileSync(typeof path == 'number' ? fd2file(path).path : path.toString(), options.flag, true));
185
185
  return options.encoding ? data.toString(options.encoding) : data;
@@ -204,14 +204,14 @@ export function writeFileSync(path, data, _options = {}) {
204
204
  const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
205
205
  const flag = parseFlag(options.flag);
206
206
  if (!isWriteable(flag)) {
207
- throw new ApiError(ErrorCode.EINVAL, 'Flag passed to writeFile must allow for writing.');
207
+ throw new ErrnoError(Errno.EINVAL, 'Flag passed to writeFile must allow for writing.');
208
208
  }
209
209
  if (typeof data != 'string' && !options.encoding) {
210
- throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
210
+ throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
211
211
  }
212
212
  const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
213
213
  if (!encodedData) {
214
- throw new ApiError(ErrorCode.EINVAL, 'Data not specified');
214
+ throw new ErrnoError(Errno.EINVAL, 'Data not specified');
215
215
  }
216
216
  _writeFileSync(typeof path == 'number' ? fd2file(path).path : path.toString(), encodedData, options.flag, options.mode, true);
217
217
  }
@@ -244,10 +244,10 @@ export function appendFileSync(filename, data, _options = {}) {
244
244
  const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
245
245
  const flag = parseFlag(options.flag);
246
246
  if (!isAppendable(flag)) {
247
- throw new ApiError(ErrorCode.EINVAL, 'Flag passed to appendFile must allow for appending.');
247
+ throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
248
248
  }
249
249
  if (typeof data != 'string' && !options.encoding) {
250
- throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
250
+ throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
251
251
  }
252
252
  const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
253
253
  _appendFileSync(typeof filename == 'number' ? fd2file(filename).path : filename.toString(), encodedData, options.flag, options.mode, true);
@@ -275,7 +275,7 @@ closeSync;
275
275
  export function ftruncateSync(fd, len = 0) {
276
276
  len || (len = 0);
277
277
  if (len < 0) {
278
- throw new ApiError(ErrorCode.EINVAL);
278
+ throw new ErrnoError(Errno.EINVAL);
279
279
  }
280
280
  fd2file(fd).truncateSync(len);
281
281
  }
@@ -350,7 +350,7 @@ fchownSync;
350
350
  export function fchmodSync(fd, mode) {
351
351
  const numMode = normalizeMode(mode, -1);
352
352
  if (numMode < 0) {
353
- throw new ApiError(ErrorCode.EINVAL, `Invalid mode.`);
353
+ throw new ErrnoError(Errno.EINVAL, `Invalid mode.`);
354
354
  }
355
355
  fd2file(fd).chmodSync(numMode);
356
356
  }
@@ -424,10 +424,10 @@ linkSync;
424
424
  */
425
425
  export function symlinkSync(target, path, type = 'file') {
426
426
  if (!['file', 'dir', 'junction'].includes(type)) {
427
- throw new ApiError(ErrorCode.EINVAL, 'Invalid type: ' + type);
427
+ throw new ErrnoError(Errno.EINVAL, 'Invalid type: ' + type);
428
428
  }
429
429
  if (existsSync(path)) {
430
- throw ApiError.With('EEXIST', path.toString(), 'symlink');
430
+ throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
431
431
  }
432
432
  writeFileSync(path, target.toString());
433
433
  const file = _openSync(path, 'r+', 0o644, false);
@@ -539,7 +539,7 @@ realpathSync;
539
539
  export function accessSync(path, mode = 0o600) {
540
540
  const stats = statSync(path);
541
541
  if (!stats.hasAccess(mode, cred)) {
542
- throw new ApiError(ErrorCode.EACCES);
542
+ throw new ErrnoError(Errno.EACCES);
543
543
  }
544
544
  }
545
545
  accessSync;
@@ -568,7 +568,7 @@ export function rmSync(path, options) {
568
568
  case S_IFIFO:
569
569
  case S_IFSOCK:
570
570
  default:
571
- throw new ApiError(ErrorCode.EPERM, 'File type not supported', path, 'rm');
571
+ throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
572
572
  }
573
573
  }
574
574
  rmSync;
@@ -591,7 +591,7 @@ export function copyFileSync(src, dest, flags) {
591
591
  src = normalizePath(src);
592
592
  dest = normalizePath(dest);
593
593
  if (flags && flags & COPYFILE_EXCL && existsSync(dest)) {
594
- throw new ApiError(ErrorCode.EEXIST, 'Destination file already exists.', dest, 'copyFile');
594
+ throw new ErrnoError(Errno.EEXIST, 'Destination file already exists.', dest, 'copyFile');
595
595
  }
596
596
  writeFileSync(dest, readFileSync(src));
597
597
  }
@@ -656,12 +656,12 @@ export function cpSync(source, destination, opts) {
656
656
  destination = normalizePath(destination);
657
657
  const srcStats = lstatSync(source); // Use lstat to follow symlinks if not dereferencing
658
658
  if (opts?.errorOnExist && existsSync(destination)) {
659
- throw new ApiError(ErrorCode.EEXIST, 'Destination file or directory already exists.', destination, 'cp');
659
+ throw new ErrnoError(Errno.EEXIST, 'Destination file or directory already exists.', destination, 'cp');
660
660
  }
661
661
  switch (srcStats.mode & S_IFMT) {
662
662
  case S_IFDIR:
663
663
  if (!opts?.recursive) {
664
- throw new ApiError(ErrorCode.EISDIR, source + ' is a directory (not copied)', source, 'cp');
664
+ throw new ErrnoError(Errno.EISDIR, source + ' is a directory (not copied)', source, 'cp');
665
665
  }
666
666
  mkdirSync(destination, { recursive: true }); // Ensure the destination directory exists
667
667
  for (const dirent of readdirSync(source, { withFileTypes: true })) {
@@ -680,7 +680,7 @@ export function cpSync(source, destination, opts) {
680
680
  case S_IFIFO:
681
681
  case S_IFSOCK:
682
682
  default:
683
- throw new ApiError(ErrorCode.EPERM, 'File type not supported', source, 'rm');
683
+ throw new ErrnoError(Errno.EPERM, 'File type not supported', source, 'rm');
684
684
  }
685
685
  // Optionally preserve timestamps
686
686
  if (opts?.preserveTimestamps) {
@@ -689,5 +689,5 @@ export function cpSync(source, destination, opts) {
689
689
  }
690
690
  cpSync;
691
691
  export function statfsSync(path, options) {
692
- throw ApiError.With('ENOSYS', path.toString(), 'statfs');
692
+ throw ErrnoError.With('ENOSYS', path.toString(), 'statfs');
693
693
  }
@@ -1,10 +1,10 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /**
3
- * Standard libc error codes. More will be added to this enum and ErrorStrings as they are
3
+ * Standard libc error codes. More will be added to this enum and error strings as they are
4
4
  * needed.
5
5
  * @url https://en.wikipedia.org/wiki/Errno.h
6
6
  */
7
- export declare enum ErrorCode {
7
+ export declare enum Errno {
8
8
  /** Operation not permitted */
9
9
  EPERM = 1,
10
10
  /** No such file or directory */
@@ -159,13 +159,13 @@ export declare enum ErrorCode {
159
159
  * @internal
160
160
  */
161
161
  export declare const errorMessages: {
162
- [K in ErrorCode]: string;
162
+ [K in Errno]: string;
163
163
  };
164
- interface ApiErrorJSON {
165
- errno: ErrorCode;
164
+ export interface ErrnoErrorJSON {
165
+ errno: Errno;
166
166
  message: string;
167
167
  path?: string;
168
- code: keyof typeof ErrorCode;
168
+ code: keyof typeof Errno;
169
169
  stack: string;
170
170
  syscall: string;
171
171
  }
@@ -173,13 +173,13 @@ interface ApiErrorJSON {
173
173
  * Represents a ZenFS error. Passed back to applications after a failed
174
174
  * call to the ZenFS API.
175
175
  */
176
- export declare class ApiError extends Error implements NodeJS.ErrnoException {
177
- errno: ErrorCode;
176
+ export declare class ErrnoError extends Error implements NodeJS.ErrnoException {
177
+ errno: Errno;
178
178
  path?: string | undefined;
179
179
  syscall: string;
180
- static fromJSON(json: ApiErrorJSON): ApiError;
181
- static With(code: keyof typeof ErrorCode, path?: string, syscall?: string): ApiError;
182
- code: keyof typeof ErrorCode;
180
+ static fromJSON(json: ErrnoErrorJSON): ErrnoError;
181
+ static With(code: keyof typeof Errno, path?: string, syscall?: string): ErrnoError;
182
+ code: keyof typeof Errno;
183
183
  stack: string;
184
184
  /**
185
185
  * Represents a ZenFS error. Passed back to applications after a failed
@@ -191,15 +191,14 @@ export declare class ApiError extends Error implements NodeJS.ErrnoException {
191
191
  * @param type The type of the error.
192
192
  * @param message A descriptive error message.
193
193
  */
194
- constructor(errno: ErrorCode, message?: string, path?: string | undefined, syscall?: string);
194
+ constructor(errno: Errno, message?: string, path?: string | undefined, syscall?: string);
195
195
  /**
196
196
  * @return A friendly error message.
197
197
  */
198
198
  toString(): string;
199
- toJSON(): ApiErrorJSON;
199
+ toJSON(): ErrnoErrorJSON;
200
200
  /**
201
201
  * The size of the API error in buffer-form in bytes.
202
202
  */
203
203
  bufferSize(): number;
204
204
  }
205
- export {};
package/dist/error.js ADDED
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Standard libc error codes. More will be added to this enum and error strings as they are
3
+ * needed.
4
+ * @url https://en.wikipedia.org/wiki/Errno.h
5
+ */
6
+ export var Errno;
7
+ (function (Errno) {
8
+ /** Operation not permitted */
9
+ Errno[Errno["EPERM"] = 1] = "EPERM";
10
+ /** No such file or directory */
11
+ Errno[Errno["ENOENT"] = 2] = "ENOENT";
12
+ /** Interrupted system call */
13
+ Errno[Errno["EINTR"] = 4] = "EINTR";
14
+ /** Input/output error */
15
+ Errno[Errno["EIO"] = 5] = "EIO";
16
+ /** No such device or address */
17
+ Errno[Errno["ENXIO"] = 6] = "ENXIO";
18
+ /** Bad file descriptor */
19
+ Errno[Errno["EBADF"] = 9] = "EBADF";
20
+ /** Resource temporarily unavailable */
21
+ Errno[Errno["EAGAIN"] = 11] = "EAGAIN";
22
+ /** Cannot allocate memory */
23
+ Errno[Errno["ENOMEM"] = 12] = "ENOMEM";
24
+ /** Permission denied */
25
+ Errno[Errno["EACCES"] = 13] = "EACCES";
26
+ /** Bad address */
27
+ Errno[Errno["EFAULT"] = 14] = "EFAULT";
28
+ /** Block device required */
29
+ Errno[Errno["ENOTBLK"] = 15] = "ENOTBLK";
30
+ /** Resource busy or locked */
31
+ Errno[Errno["EBUSY"] = 16] = "EBUSY";
32
+ /** File exists */
33
+ Errno[Errno["EEXIST"] = 17] = "EEXIST";
34
+ /** Invalid cross-device link */
35
+ Errno[Errno["EXDEV"] = 18] = "EXDEV";
36
+ /** No such device */
37
+ Errno[Errno["ENODEV"] = 19] = "ENODEV";
38
+ /** File is not a directory */
39
+ Errno[Errno["ENOTDIR"] = 20] = "ENOTDIR";
40
+ /** File is a directory */
41
+ Errno[Errno["EISDIR"] = 21] = "EISDIR";
42
+ /** Invalid argument */
43
+ Errno[Errno["EINVAL"] = 22] = "EINVAL";
44
+ /** Too many open files in system */
45
+ Errno[Errno["ENFILE"] = 23] = "ENFILE";
46
+ /** Too many open files */
47
+ Errno[Errno["EMFILE"] = 24] = "EMFILE";
48
+ /** Text file busy */
49
+ Errno[Errno["ETXTBSY"] = 26] = "ETXTBSY";
50
+ /** File is too big */
51
+ Errno[Errno["EFBIG"] = 27] = "EFBIG";
52
+ /** No space left on disk */
53
+ Errno[Errno["ENOSPC"] = 28] = "ENOSPC";
54
+ /** Illegal seek */
55
+ Errno[Errno["ESPIPE"] = 29] = "ESPIPE";
56
+ /** Cannot modify a read-only file system */
57
+ Errno[Errno["EROFS"] = 30] = "EROFS";
58
+ /** Too many links */
59
+ Errno[Errno["EMLINK"] = 31] = "EMLINK";
60
+ /** Broken pipe */
61
+ Errno[Errno["EPIPE"] = 32] = "EPIPE";
62
+ /** Numerical argument out of domain */
63
+ Errno[Errno["EDOM"] = 33] = "EDOM";
64
+ /** Numerical result out of range */
65
+ Errno[Errno["ERANGE"] = 34] = "ERANGE";
66
+ /** Resource deadlock would occur */
67
+ Errno[Errno["EDEADLK"] = 35] = "EDEADLK";
68
+ /** File name too long */
69
+ Errno[Errno["ENAMETOOLONG"] = 36] = "ENAMETOOLONG";
70
+ /** No locks available */
71
+ Errno[Errno["ENOLCK"] = 37] = "ENOLCK";
72
+ /** Function not implemented */
73
+ Errno[Errno["ENOSYS"] = 38] = "ENOSYS";
74
+ /** Directory is not empty */
75
+ Errno[Errno["ENOTEMPTY"] = 39] = "ENOTEMPTY";
76
+ /** Too many levels of symbolic links */
77
+ Errno[Errno["ELOOP"] = 40] = "ELOOP";
78
+ /** No message of desired type */
79
+ Errno[Errno["ENOMSG"] = 42] = "ENOMSG";
80
+ /** Invalid exchange */
81
+ Errno[Errno["EBADE"] = 52] = "EBADE";
82
+ /** Invalid request descriptor */
83
+ Errno[Errno["EBADR"] = 53] = "EBADR";
84
+ /** Exchange full */
85
+ Errno[Errno["EXFULL"] = 54] = "EXFULL";
86
+ /** No anode */
87
+ Errno[Errno["ENOANO"] = 55] = "ENOANO";
88
+ /** Invalid request code */
89
+ Errno[Errno["EBADRQC"] = 56] = "EBADRQC";
90
+ /** Device not a stream */
91
+ Errno[Errno["ENOSTR"] = 60] = "ENOSTR";
92
+ /** No data available */
93
+ Errno[Errno["ENODATA"] = 61] = "ENODATA";
94
+ /** Timer expired */
95
+ Errno[Errno["ETIME"] = 62] = "ETIME";
96
+ /** Out of streams resources */
97
+ Errno[Errno["ENOSR"] = 63] = "ENOSR";
98
+ /** Machine is not on the network */
99
+ Errno[Errno["ENONET"] = 64] = "ENONET";
100
+ /** Object is remote */
101
+ Errno[Errno["EREMOTE"] = 66] = "EREMOTE";
102
+ /** Link has been severed */
103
+ Errno[Errno["ENOLINK"] = 67] = "ENOLINK";
104
+ /** Communication error on send */
105
+ Errno[Errno["ECOMM"] = 70] = "ECOMM";
106
+ /** Protocol error */
107
+ Errno[Errno["EPROTO"] = 71] = "EPROTO";
108
+ /** Bad message */
109
+ Errno[Errno["EBADMSG"] = 74] = "EBADMSG";
110
+ /** Value too large for defined data type */
111
+ Errno[Errno["EOVERFLOW"] = 75] = "EOVERFLOW";
112
+ /** File descriptor in bad state */
113
+ Errno[Errno["EBADFD"] = 77] = "EBADFD";
114
+ /** Streams pipe error */
115
+ Errno[Errno["ESTRPIPE"] = 86] = "ESTRPIPE";
116
+ /** Socket operation on non-socket */
117
+ Errno[Errno["ENOTSOCK"] = 88] = "ENOTSOCK";
118
+ /** Destination address required */
119
+ Errno[Errno["EDESTADDRREQ"] = 89] = "EDESTADDRREQ";
120
+ /** Message too long */
121
+ Errno[Errno["EMSGSIZE"] = 90] = "EMSGSIZE";
122
+ /** Protocol wrong type for socket */
123
+ Errno[Errno["EPROTOTYPE"] = 91] = "EPROTOTYPE";
124
+ /** Protocol not available */
125
+ Errno[Errno["ENOPROTOOPT"] = 92] = "ENOPROTOOPT";
126
+ /** Protocol not supported */
127
+ Errno[Errno["EPROTONOSUPPORT"] = 93] = "EPROTONOSUPPORT";
128
+ /** Socket type not supported */
129
+ Errno[Errno["ESOCKTNOSUPPORT"] = 94] = "ESOCKTNOSUPPORT";
130
+ /** Operation is not supported */
131
+ Errno[Errno["ENOTSUP"] = 95] = "ENOTSUP";
132
+ /** Network is down */
133
+ Errno[Errno["ENETDOWN"] = 100] = "ENETDOWN";
134
+ /** Network is unreachable */
135
+ Errno[Errno["ENETUNREACH"] = 101] = "ENETUNREACH";
136
+ /** Network dropped connection on reset */
137
+ Errno[Errno["ENETRESET"] = 102] = "ENETRESET";
138
+ /** Connection timed out */
139
+ Errno[Errno["ETIMEDOUT"] = 110] = "ETIMEDOUT";
140
+ /** Connection refused */
141
+ Errno[Errno["ECONNREFUSED"] = 111] = "ECONNREFUSED";
142
+ /** Host is down */
143
+ Errno[Errno["EHOSTDOWN"] = 112] = "EHOSTDOWN";
144
+ /** No route to host */
145
+ Errno[Errno["EHOSTUNREACH"] = 113] = "EHOSTUNREACH";
146
+ /** Operation already in progress */
147
+ Errno[Errno["EALREADY"] = 114] = "EALREADY";
148
+ /** Operation now in progress */
149
+ Errno[Errno["EINPROGRESS"] = 115] = "EINPROGRESS";
150
+ /** Stale file handle */
151
+ Errno[Errno["ESTALE"] = 116] = "ESTALE";
152
+ /** Remote I/O error */
153
+ Errno[Errno["EREMOTEIO"] = 121] = "EREMOTEIO";
154
+ /** Disk quota exceeded */
155
+ Errno[Errno["EDQUOT"] = 122] = "EDQUOT";
156
+ })(Errno || (Errno = {}));
157
+ /**
158
+ * Strings associated with each error code.
159
+ * @internal
160
+ */
161
+ export const errorMessages = {
162
+ [Errno.EPERM]: 'Operation not permitted',
163
+ [Errno.ENOENT]: 'No such file or directory',
164
+ [Errno.EINTR]: 'Interrupted system call',
165
+ [Errno.EIO]: 'Input/output error',
166
+ [Errno.ENXIO]: 'No such device or address',
167
+ [Errno.EBADF]: 'Bad file descriptor',
168
+ [Errno.EAGAIN]: 'Resource temporarily unavailable',
169
+ [Errno.ENOMEM]: 'Cannot allocate memory',
170
+ [Errno.EACCES]: 'Permission denied',
171
+ [Errno.EFAULT]: 'Bad address',
172
+ [Errno.ENOTBLK]: 'Block device required',
173
+ [Errno.EBUSY]: 'Resource busy or locked',
174
+ [Errno.EEXIST]: 'File exists',
175
+ [Errno.EXDEV]: 'Invalid cross-device link',
176
+ [Errno.ENODEV]: 'No such device',
177
+ [Errno.ENOTDIR]: 'File is not a directory',
178
+ [Errno.EISDIR]: 'File is a directory',
179
+ [Errno.EINVAL]: 'Invalid argument',
180
+ [Errno.ENFILE]: 'Too many open files in system',
181
+ [Errno.EMFILE]: 'Too many open files',
182
+ [Errno.ETXTBSY]: 'Text file busy',
183
+ [Errno.EFBIG]: 'File is too big',
184
+ [Errno.ENOSPC]: 'No space left on disk',
185
+ [Errno.ESPIPE]: 'Illegal seek',
186
+ [Errno.EROFS]: 'Cannot modify a read-only file system',
187
+ [Errno.EMLINK]: 'Too many links',
188
+ [Errno.EPIPE]: 'Broken pipe',
189
+ [Errno.EDOM]: 'Numerical argument out of domain',
190
+ [Errno.ERANGE]: 'Numerical result out of range',
191
+ [Errno.EDEADLK]: 'Resource deadlock would occur',
192
+ [Errno.ENAMETOOLONG]: 'File name too long',
193
+ [Errno.ENOLCK]: 'No locks available',
194
+ [Errno.ENOSYS]: 'Function not implemented',
195
+ [Errno.ENOTEMPTY]: 'Directory is not empty',
196
+ [Errno.ELOOP]: 'Too many levels of symbolic links',
197
+ [Errno.ENOMSG]: 'No message of desired type',
198
+ [Errno.EBADE]: 'Invalid exchange',
199
+ [Errno.EBADR]: 'Invalid request descriptor',
200
+ [Errno.EXFULL]: 'Exchange full',
201
+ [Errno.ENOANO]: 'No anode',
202
+ [Errno.EBADRQC]: 'Invalid request code',
203
+ [Errno.ENOSTR]: 'Device not a stream',
204
+ [Errno.ENODATA]: 'No data available',
205
+ [Errno.ETIME]: 'Timer expired',
206
+ [Errno.ENOSR]: 'Out of streams resources',
207
+ [Errno.ENONET]: 'Machine is not on the network',
208
+ [Errno.EREMOTE]: 'Object is remote',
209
+ [Errno.ENOLINK]: 'Link has been severed',
210
+ [Errno.ECOMM]: 'Communication error on send',
211
+ [Errno.EPROTO]: 'Protocol error',
212
+ [Errno.EBADMSG]: 'Bad message',
213
+ [Errno.EOVERFLOW]: 'Value too large for defined data type',
214
+ [Errno.EBADFD]: 'File descriptor in bad state',
215
+ [Errno.ESTRPIPE]: 'Streams pipe error',
216
+ [Errno.ENOTSOCK]: 'Socket operation on non-socket',
217
+ [Errno.EDESTADDRREQ]: 'Destination address required',
218
+ [Errno.EMSGSIZE]: 'Message too long',
219
+ [Errno.EPROTOTYPE]: 'Protocol wrong type for socket',
220
+ [Errno.ENOPROTOOPT]: 'Protocol not available',
221
+ [Errno.EPROTONOSUPPORT]: 'Protocol not supported',
222
+ [Errno.ESOCKTNOSUPPORT]: 'Socket type not supported',
223
+ [Errno.ENOTSUP]: 'Operation is not supported',
224
+ [Errno.ENETDOWN]: 'Network is down',
225
+ [Errno.ENETUNREACH]: 'Network is unreachable',
226
+ [Errno.ENETRESET]: 'Network dropped connection on reset',
227
+ [Errno.ETIMEDOUT]: 'Connection timed out',
228
+ [Errno.ECONNREFUSED]: 'Connection refused',
229
+ [Errno.EHOSTDOWN]: 'Host is down',
230
+ [Errno.EHOSTUNREACH]: 'No route to host',
231
+ [Errno.EALREADY]: 'Operation already in progress',
232
+ [Errno.EINPROGRESS]: 'Operation now in progress',
233
+ [Errno.ESTALE]: 'Stale file handle',
234
+ [Errno.EREMOTEIO]: 'Remote I/O error',
235
+ [Errno.EDQUOT]: 'Disk quota exceeded',
236
+ };
237
+ /**
238
+ * Represents a ZenFS error. Passed back to applications after a failed
239
+ * call to the ZenFS API.
240
+ */
241
+ export class ErrnoError extends Error {
242
+ static fromJSON(json) {
243
+ const err = new ErrnoError(json.errno, json.message, json.path, json.syscall);
244
+ err.code = json.code;
245
+ err.stack = json.stack;
246
+ return err;
247
+ }
248
+ static With(code, path, syscall) {
249
+ return new ErrnoError(Errno[code], errorMessages[Errno[code]], path, syscall);
250
+ }
251
+ /**
252
+ * Represents a ZenFS error. Passed back to applications after a failed
253
+ * call to the ZenFS API.
254
+ *
255
+ * Error codes mirror those returned by regular Unix file operations, which is
256
+ * what Node returns.
257
+ * @constructor ApiError
258
+ * @param type The type of the error.
259
+ * @param message A descriptive error message.
260
+ */
261
+ constructor(errno, message = errorMessages[errno], path, syscall = '') {
262
+ super(message);
263
+ this.errno = errno;
264
+ this.path = path;
265
+ this.syscall = syscall;
266
+ this.code = Errno[errno];
267
+ this.message = `${this.code}: ${message}${this.path ? `, '${this.path}'` : ''}`;
268
+ }
269
+ /**
270
+ * @return A friendly error message.
271
+ */
272
+ toString() {
273
+ return this.message;
274
+ }
275
+ toJSON() {
276
+ return {
277
+ errno: this.errno,
278
+ code: this.code,
279
+ path: this.path,
280
+ stack: this.stack,
281
+ message: this.message,
282
+ syscall: this.syscall,
283
+ };
284
+ }
285
+ /**
286
+ * The size of the API error in buffer-form in bytes.
287
+ */
288
+ bufferSize() {
289
+ // 4 bytes for string length.
290
+ return 4 + JSON.stringify(this.toJSON()).length;
291
+ }
292
+ }
package/dist/file.d.ts CHANGED
@@ -70,6 +70,8 @@ export declare abstract class File {
70
70
  * Synchronous close.
71
71
  */
72
72
  abstract closeSync(): void;
73
+ [Symbol.asyncDispose](): Promise<void>;
74
+ [Symbol.dispose](): void;
73
75
  /**
74
76
  * Asynchronous truncate.
75
77
  */
package/dist/file.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ApiError, ErrorCode } from './ApiError.js';
1
+ import { ErrnoError, Errno } from './error.js';
2
2
  import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, S_IFMT } from './emulation/constants.js';
3
3
  import { size_max } from './inode.js';
4
4
  import { Stats } from './stats.js';
@@ -133,6 +133,12 @@ export function pathNotExistsAction(flag) {
133
133
  return ActionType.THROW;
134
134
  }
135
135
  export class File {
136
+ [Symbol.asyncDispose]() {
137
+ return this.close();
138
+ }
139
+ [Symbol.dispose]() {
140
+ return this.closeSync();
141
+ }
136
142
  /**
137
143
  * Asynchronous `datasync`.
138
144
  *
@@ -276,7 +282,7 @@ export class PreloadFile extends File {
276
282
  truncateSync(len) {
277
283
  this._dirty = true;
278
284
  if (!isWriteable(this.flag)) {
279
- throw new ApiError(ErrorCode.EPERM, 'File not opened with a writeable mode.');
285
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
280
286
  }
281
287
  this.stats.mtimeMs = Date.now();
282
288
  if (len > this._buffer.length) {
@@ -329,7 +335,7 @@ export class PreloadFile extends File {
329
335
  this._dirty = true;
330
336
  position ?? (position = this.position);
331
337
  if (!isWriteable(this.flag)) {
332
- throw new ApiError(ErrorCode.EPERM, 'File not opened with a writeable mode.');
338
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
333
339
  }
334
340
  const endFp = position + length;
335
341
  if (endFp > this.stats.size) {
@@ -384,7 +390,7 @@ export class PreloadFile extends File {
384
390
  */
385
391
  readSync(buffer, offset = 0, length = this.stats.size, position) {
386
392
  if (!isReadable(this.flag)) {
387
- throw new ApiError(ErrorCode.EPERM, 'File not opened with a readable mode.');
393
+ throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
388
394
  }
389
395
  position ?? (position = this.position);
390
396
  let end = position + length;