@zenfs/core 1.8.8 → 1.9.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 +1 -1
  2. package/dist/backends/backend.js +7 -4
  3. package/dist/backends/fetch.d.ts +23 -32
  4. package/dist/backends/fetch.js +94 -134
  5. package/dist/backends/index.d.ts +1 -4
  6. package/dist/backends/index.js +1 -4
  7. package/dist/backends/memory.d.ts +7 -5
  8. package/dist/backends/memory.js +6 -4
  9. package/dist/backends/overlay.d.ts +4 -5
  10. package/dist/backends/overlay.js +16 -20
  11. package/dist/backends/passthrough.d.ts +3 -3
  12. package/dist/backends/passthrough.js +4 -6
  13. package/dist/backends/port/fs.d.ts +4 -5
  14. package/dist/backends/port/fs.js +7 -12
  15. package/dist/backends/port/rpc.d.ts +1 -1
  16. package/dist/backends/port/rpc.js +15 -13
  17. package/dist/backends/store/fs.d.ts +51 -40
  18. package/dist/backends/store/fs.js +347 -241
  19. package/dist/backends/store/map.d.ts +41 -0
  20. package/dist/backends/store/map.js +45 -0
  21. package/dist/backends/store/simple.d.ts +10 -58
  22. package/dist/backends/store/simple.js +8 -115
  23. package/dist/backends/store/store.d.ts +111 -44
  24. package/dist/backends/store/store.js +230 -38
  25. package/dist/config.d.ts +7 -3
  26. package/dist/config.js +17 -14
  27. package/dist/context.d.ts +1 -1
  28. package/dist/context.js +1 -1
  29. package/dist/index.d.ts +1 -5
  30. package/dist/index.js +1 -5
  31. package/dist/{devices.d.ts → internal/devices.d.ts} +4 -4
  32. package/dist/{devices.js → internal/devices.js} +18 -14
  33. package/dist/{file.d.ts → internal/file.d.ts} +3 -2
  34. package/dist/{file.js → internal/file.js} +17 -12
  35. package/dist/{backends/store → internal}/file_index.d.ts +13 -3
  36. package/dist/{backends/store → internal}/file_index.js +28 -5
  37. package/dist/{filesystem.d.ts → internal/filesystem.d.ts} +99 -32
  38. package/dist/internal/filesystem.js +83 -0
  39. package/dist/internal/index.d.ts +9 -0
  40. package/dist/internal/index.js +9 -0
  41. package/dist/internal/index_fs.d.ts +56 -0
  42. package/dist/internal/index_fs.js +184 -0
  43. package/dist/{backends/store → internal}/inode.d.ts +6 -1
  44. package/dist/{backends/store → internal}/inode.js +14 -6
  45. package/dist/internal/log.d.ts +132 -0
  46. package/dist/internal/log.js +177 -0
  47. package/dist/mixins/async.d.ts +2 -2
  48. package/dist/mixins/async.js +19 -16
  49. package/dist/mixins/mutexed.d.ts +9 -3
  50. package/dist/mixins/mutexed.js +22 -3
  51. package/dist/mixins/readonly.d.ts +2 -2
  52. package/dist/mixins/readonly.js +4 -3
  53. package/dist/mixins/shared.d.ts +1 -1
  54. package/dist/mixins/sync.d.ts +2 -2
  55. package/dist/stats.d.ts +2 -3
  56. package/dist/stats.js +7 -5
  57. package/dist/utils.d.ts +2 -15
  58. package/dist/utils.js +10 -47
  59. package/dist/vfs/async.d.ts +2 -2
  60. package/dist/vfs/async.js +3 -3
  61. package/dist/vfs/dir.js +1 -1
  62. package/dist/vfs/promises.d.ts +6 -6
  63. package/dist/vfs/promises.js +54 -49
  64. package/dist/vfs/shared.d.ts +3 -3
  65. package/dist/vfs/shared.js +16 -10
  66. package/dist/vfs/streams.js +1 -1
  67. package/dist/vfs/sync.d.ts +1 -2
  68. package/dist/vfs/sync.js +14 -15
  69. package/dist/vfs/types.d.ts +1 -0
  70. package/dist/vfs/watchers.d.ts +5 -1
  71. package/dist/vfs/watchers.js +16 -19
  72. package/package.json +3 -3
  73. package/readme.md +12 -12
  74. package/scripts/test.js +15 -3
  75. package/tests/backend/fetch.test.ts +49 -0
  76. package/tests/backend/port.test.ts +130 -0
  77. package/tests/common/context.test.ts +9 -4
  78. package/tests/common.ts +21 -3
  79. package/tests/data/image.jpg +0 -0
  80. package/tests/data/utf8.txt +1 -0
  81. package/tests/fetch/config.js +40 -0
  82. package/tests/fetch/fetch.ts +20 -0
  83. package/tests/fetch/run.sh +3 -3
  84. package/tests/fetch/{server.ts → server.js} +15 -11
  85. package/tests/fs/directory.test.ts +1 -1
  86. package/tests/fs/errors.test.ts +1 -1
  87. package/tests/fs/links.test.ts +1 -1
  88. package/tests/fs/open.test.ts +1 -1
  89. package/tests/fs/permissions.test.ts +2 -3
  90. package/tests/fs/rename.test.ts +1 -1
  91. package/tests/fs/stat.test.ts +1 -1
  92. package/tests/fs/times.test.ts +1 -1
  93. package/tests/fs/watch.test.ts +21 -22
  94. package/tests/fs/writeFile.test.ts +8 -7
  95. package/tests/readme.md +3 -3
  96. package/tests/setup/_overlay.ts +7 -0
  97. package/tests/setup/context.ts +2 -2
  98. package/tests/setup/index.ts +3 -3
  99. package/tests/setup/memory.ts +2 -2
  100. package/tests/setup/port.ts +2 -2
  101. package/tests/setup.ts +25 -5
  102. package/tests/tsconfig.json +3 -2
  103. package/dist/backends/store/index_fs.d.ts +0 -34
  104. package/dist/backends/store/index_fs.js +0 -67
  105. package/dist/filesystem.js +0 -52
  106. package/tests/fetch/cow+fetch.ts +0 -13
  107. package/tests/port/channel.test.ts +0 -39
  108. package/tests/port/config.test.ts +0 -30
  109. package/tests/port/remote.test.ts +0 -32
  110. package/tests/port/timeout.test.ts +0 -48
  111. /package/dist/{credentials.d.ts → internal/credentials.d.ts} +0 -0
  112. /package/dist/{credentials.js → internal/credentials.js} +0 -0
  113. /package/dist/{error.d.ts → internal/error.d.ts} +0 -0
  114. /package/dist/{error.js → internal/error.js} +0 -0
  115. /package/tests/{port → backend}/config.worker.js +0 -0
  116. /package/tests/{port → backend}/remote.worker.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import type { RequiredKeys } from 'utilium';
2
- import type { FileSystem } from '../filesystem.js';
2
+ import type { FileSystem } from '../internal/filesystem.js';
3
3
  type OptionType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | (abstract new (...args: any[]) => any);
4
4
  /**
5
5
  * Resolves the type of Backend.options from the options interface
@@ -1,4 +1,5 @@
1
- import { Errno, ErrnoError } from '../error.js';
1
+ import { Errno, ErrnoError } from '../internal/error.js';
2
+ import { debug, err } from '../internal/log.js';
2
3
  /** @internal */
3
4
  export function isBackend(arg) {
4
5
  return arg != null && typeof arg == 'object' && 'create' in arg && typeof arg.create == 'function';
@@ -9,16 +10,17 @@ export function isBackend(arg) {
9
10
  */
10
11
  export async function checkOptions(backend, options) {
11
12
  if (typeof options != 'object' || options === null) {
12
- throw new ErrnoError(Errno.EINVAL, 'Invalid options');
13
+ throw err(new ErrnoError(Errno.EINVAL, 'Invalid options'));
13
14
  }
14
15
  // Check for required options.
15
16
  for (const [optName, opt] of Object.entries(backend.options)) {
16
17
  const value = options === null || options === void 0 ? void 0 : options[optName];
17
18
  if (value === undefined || value === null) {
18
19
  if (!opt.required) {
20
+ debug('Missing non-required option: ' + optName);
19
21
  continue;
20
22
  }
21
- throw new ErrnoError(Errno.EINVAL, 'Missing required option: ' + optName);
23
+ throw err(new ErrnoError(Errno.EINVAL, 'Missing required option: ' + optName));
22
24
  }
23
25
  const isType = (type, _ = value) => (typeof type == 'function' ? value instanceof type : typeof value === type);
24
26
  if (Array.isArray(opt.type) ? !opt.type.some(v => isType(v)) : !isType(opt.type)) {
@@ -27,8 +29,9 @@ export async function checkOptions(backend, options) {
27
29
  // The expected type (as a string)
28
30
  const name = (type) => (typeof type == 'function' ? type.name : type);
29
31
  const expected = Array.isArray(opt.type) ? `one of ${opt.type.map(name).join(', ')}` : name(opt.type);
30
- throw new ErrnoError(Errno.EINVAL, `Incorrect type for "${optName}": ${type} (expected ${expected})`);
32
+ throw err(new ErrnoError(Errno.EINVAL, `Incorrect type for "${optName}": ${type} (expected ${expected})`));
31
33
  }
34
+ debug('Using custom validator for option: ' + optName);
32
35
  if (opt.validator)
33
36
  await opt.validator(value);
34
37
  // Otherwise: All good!
@@ -1,10 +1,11 @@
1
- import { StoreFS } from './store/fs.js';
2
- import { type IndexData } from './store/file_index.js';
3
- import type { Store } from './store/store.js';
1
+ import type { IndexData } from '../internal/file_index.js';
2
+ import { Index } from '../internal/file_index.js';
3
+ import { IndexFS } from '../internal/index_fs.js';
4
+ import type { SharedConfig } from './backend.js';
4
5
  /**
5
6
  * Configuration options for FetchFS.
6
7
  */
7
- export interface FetchOptions {
8
+ export interface FetchOptions extends SharedConfig {
8
9
  /**
9
10
  * Options to pass through to fetch calls
10
11
  */
@@ -19,36 +20,26 @@ export interface FetchOptions {
19
20
  */
20
21
  baseUrl?: string;
21
22
  /**
22
- * A store to use for caching content.
23
- * Defaults to an in-memory store
23
+ * If true, enables writing to the remote (using post and delete)
24
+ * @default false
24
25
  */
25
- cache?: Store;
26
+ remoteWrite?: boolean;
26
27
  }
27
28
  /**
28
29
  * A simple filesystem backed by HTTP using the `fetch` API.
29
- *
30
- *
31
- * Index objects look like the following:
32
- *
33
- * ```json
34
- * {
35
- * "version": 1,
36
- * "entries": {
37
- * "/home": { ... },
38
- * "/home/john": { ... },
39
- * "/home/james": { ... }
40
- * }
41
- * }
42
- * ```
43
- *
44
- * Each entry contains the stats associated with the file.
30
+ * @internal
45
31
  */
46
- export declare class FetchFS extends StoreFS {
47
- readonly baseUrl: string;
48
- readonly requestInit?: RequestInit | undefined;
49
- private indexData;
50
- ready(): Promise<void>;
51
- constructor(index?: IndexData | string, cache?: Store, baseUrl?: string, requestInit?: RequestInit | undefined);
32
+ export declare class FetchFS extends IndexFS {
33
+ protected baseUrl: string;
34
+ protected requestInit: RequestInit;
35
+ protected remoteWrite?: boolean | undefined;
36
+ constructor(index: Index, baseUrl: string, requestInit?: RequestInit, remoteWrite?: boolean | undefined);
37
+ protected remove(path: string): Promise<void>;
38
+ protected removeSync(path: string): void;
39
+ read(path: string, buffer: Uint8Array, offset: number | undefined, end: number): Promise<void>;
40
+ readSync(path: string, buffer: Uint8Array, offset: number | undefined, end: number): void;
41
+ write(path: string, data: Uint8Array, offset: number): Promise<void>;
42
+ writeSync(path: string, data: Uint8Array, offset: number): void;
52
43
  }
53
44
  declare const _Fetch: {
54
45
  readonly name: "Fetch";
@@ -65,13 +56,13 @@ declare const _Fetch: {
65
56
  readonly type: "object";
66
57
  readonly required: false;
67
58
  };
68
- readonly cache: {
69
- readonly type: "object";
59
+ readonly remoteWrite: {
60
+ readonly type: "boolean";
70
61
  readonly required: false;
71
62
  };
72
63
  };
73
64
  readonly isAvailable: () => boolean;
74
- readonly create: (options: FetchOptions) => FetchFS;
65
+ readonly create: (options: FetchOptions) => Promise<FetchFS>;
75
66
  };
76
67
  type _Fetch = typeof _Fetch;
77
68
  export interface Fetch extends _Fetch {
@@ -1,142 +1,80 @@
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
- var r, s = 0;
30
- function next() {
31
- while (r = env.stack.pop()) {
32
- try {
33
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
- if (r.dispose) {
35
- var result = r.dispose.call(r.value);
36
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
- }
38
- else s |= 1;
39
- }
40
- catch (e) {
41
- fail(e);
42
- }
43
- }
44
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
- if (env.hasError) throw env.error;
46
- }
47
- return next();
48
- };
49
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
- var e = new Error(message);
51
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
- });
53
- import { Errno, ErrnoError } from '../error.js';
1
+ import * as requests from 'utilium/requests.js';
2
+ import { Errno, ErrnoError } from '../internal/error.js';
3
+ import { Index } from '../internal/file_index.js';
4
+ import { IndexFS } from '../internal/index_fs.js';
5
+ import { err, warn } from '../internal/log.js';
6
+ import { decodeUTF8, normalizePath } from '../utils.js';
54
7
  import { S_IFREG } from '../vfs/constants.js';
55
- import { InMemoryStore } from './memory.js';
56
- import { StoreFS } from './store/fs.js';
57
- import { Index } from './store/file_index.js';
58
- import { normalizePath } from '../utils.js';
59
- async function fetchFile(path, type, init) {
60
- const response = await fetch(path, init).catch((e) => {
61
- throw new ErrnoError(Errno.EIO, e.message, path);
62
- });
63
- if (!response.ok) {
64
- throw new ErrnoError(Errno.EIO, 'fetch failed: response returned code ' + response.status, path);
65
- }
66
- switch (type) {
67
- case 'buffer': {
68
- const arrayBuffer = await response.arrayBuffer().catch((e) => {
69
- throw new ErrnoError(Errno.EIO, e.message, path);
70
- });
71
- return new Uint8Array(arrayBuffer);
8
+ /** Parse and throw */
9
+ function parseError(path, fs) {
10
+ return (error) => {
11
+ if (!('tag' in error))
12
+ throw err(new ErrnoError(Errno.EIO, error.stack, path), { fs });
13
+ switch (error.tag) {
14
+ case 'fetch':
15
+ throw err(new ErrnoError(Errno.EREMOTEIO, error.message, path), { fs });
16
+ case 'status':
17
+ throw err(new ErrnoError(error.response.status > 500 ? Errno.EREMOTEIO : Errno.EIO, 'Response status code is ' + error.response.status, path), { fs });
18
+ case 'size':
19
+ throw err(new ErrnoError(Errno.EBADE, error.message, path), { fs });
20
+ case 'buffer':
21
+ throw err(new ErrnoError(Errno.EIO, 'Failed to decode buffer', path), { fs });
72
22
  }
73
- case 'json':
74
- return response.json().catch((e) => {
75
- throw new ErrnoError(Errno.EIO, e.message, path);
76
- });
77
- default:
78
- throw new ErrnoError(Errno.EINVAL, 'Invalid download type: ' + type);
79
- }
23
+ };
80
24
  }
81
25
  /**
82
26
  * A simple filesystem backed by HTTP using the `fetch` API.
83
- *
84
- *
85
- * Index objects look like the following:
86
- *
87
- * ```json
88
- * {
89
- * "version": 1,
90
- * "entries": {
91
- * "/home": { ... },
92
- * "/home/john": { ... },
93
- * "/home/james": { ... }
94
- * }
95
- * }
96
- * ```
97
- *
98
- * Each entry contains the stats associated with the file.
27
+ * @internal
99
28
  */
100
- export class FetchFS extends StoreFS {
101
- async ready() {
102
- const env_1 = { stack: [], error: void 0, hasError: false };
103
- try {
104
- if (this._initialized)
105
- return;
106
- await super.ready();
107
- const index = new Index();
108
- index.fromJSON(await this.indexData);
109
- await this.loadIndex(index);
110
- if (this._disableSync)
111
- return;
112
- const tx = __addDisposableResource(env_1, this.store.transaction(), true);
113
- // Iterate over all of the files and cache their contents
114
- for (const [path, node] of index) {
115
- if (!(node.mode & S_IFREG))
116
- continue;
117
- const content = await fetchFile(this.baseUrl + path, 'buffer', this.requestInit);
118
- await tx.set(node.data, content);
119
- }
120
- await tx.commit();
121
- }
122
- catch (e_1) {
123
- env_1.error = e_1;
124
- env_1.hasError = true;
125
- }
126
- finally {
127
- const result_1 = __disposeResources(env_1);
128
- if (result_1)
129
- await result_1;
130
- }
131
- }
132
- constructor(index = 'index.json', cache = new InMemoryStore('fetch'), baseUrl = '', requestInit) {
133
- super(cache);
29
+ export class FetchFS extends IndexFS {
30
+ constructor(index, baseUrl, requestInit = {}, remoteWrite) {
31
+ super(0x206e6673, 'nfs', index);
134
32
  this.baseUrl = baseUrl;
135
33
  this.requestInit = requestInit;
136
- // prefix url must end in a directory separator.
137
- if (baseUrl.at(-1) == '/')
138
- this.baseUrl = baseUrl.slice(0, -1);
139
- this.indexData = typeof index != 'string' ? index : fetchFile(index, 'json', requestInit);
34
+ this.remoteWrite = remoteWrite;
35
+ }
36
+ async remove(path) {
37
+ await requests.remove(this.baseUrl + path, { warn, cacheOnly: !this.remoteWrite }, this.requestInit);
38
+ }
39
+ removeSync(path) {
40
+ void requests.remove(this.baseUrl + path, { warn, cacheOnly: !this.remoteWrite }, this.requestInit);
41
+ }
42
+ async read(path, buffer, offset = 0, end) {
43
+ const inode = this.index.get(path);
44
+ if (!inode)
45
+ throw ErrnoError.With('ENOENT', path, 'read');
46
+ end !== null && end !== void 0 ? end : (end = inode.size);
47
+ if (end - offset == 0)
48
+ return;
49
+ const data = await requests
50
+ .get(this.baseUrl + path, { start: offset, end, size: inode.size, warn }, this.requestInit)
51
+ .catch(parseError(path, this))
52
+ .catch(() => undefined);
53
+ if (!data)
54
+ throw ErrnoError.With('ENODATA', path, 'read');
55
+ buffer.set(data);
56
+ }
57
+ readSync(path, buffer, offset = 0, end) {
58
+ const inode = this.index.get(path);
59
+ if (!inode)
60
+ throw ErrnoError.With('ENOENT', path, 'read');
61
+ end !== null && end !== void 0 ? end : (end = inode.size);
62
+ if (end - offset == 0)
63
+ return;
64
+ const { data, missing } = requests.getCached(this.baseUrl + path, { start: offset, end, size: inode.size, warn });
65
+ if (!data)
66
+ throw ErrnoError.With('ENODATA', path, 'read');
67
+ if (missing.length) {
68
+ void requests.get(this.baseUrl + path, { start: offset, end, size: inode.size, warn });
69
+ throw ErrnoError.With('EAGAIN', path, 'read');
70
+ }
71
+ buffer.set(data);
72
+ }
73
+ async write(path, data, offset) {
74
+ await requests.set(this.baseUrl + path, data, { offset, warn, cacheOnly: !this.remoteWrite }, this.requestInit).catch(parseError(path, this));
75
+ }
76
+ writeSync(path, data, offset) {
77
+ void requests.set(this.baseUrl + path, data, { offset, warn, cacheOnly: !this.remoteWrite }, this.requestInit).catch(parseError(path, this));
140
78
  }
141
79
  }
142
80
  const _Fetch = {
@@ -145,15 +83,37 @@ const _Fetch = {
145
83
  index: { type: ['string', 'object'], required: false },
146
84
  baseUrl: { type: 'string', required: false },
147
85
  requestInit: { type: 'object', required: false },
148
- cache: { type: 'object', required: false },
86
+ remoteWrite: { type: 'boolean', required: false },
149
87
  },
150
88
  isAvailable() {
151
89
  return typeof globalThis.fetch == 'function';
152
90
  },
153
- create(options) {
91
+ async create(options) {
92
+ var _a;
154
93
  const url = new URL(options.baseUrl || '');
155
94
  url.pathname = normalizePath(url.pathname);
156
- return new FetchFS(options.index, options.cache, url.toString(), options.requestInit);
95
+ let baseUrl = url.toString();
96
+ if (baseUrl.at(-1) == '/')
97
+ baseUrl = baseUrl.slice(0, -1);
98
+ (_a = options.index) !== null && _a !== void 0 ? _a : (options.index = 'index.json');
99
+ const index = new Index();
100
+ if (typeof options.index != 'string') {
101
+ index.fromJSON(options.index);
102
+ }
103
+ else {
104
+ const data = await requests.get(options.index, { warn }, options.requestInit).catch(parseError());
105
+ index.fromJSON(JSON.parse(decodeUTF8(data)));
106
+ }
107
+ const fs = new FetchFS(index, baseUrl, options.requestInit, options.remoteWrite);
108
+ if (options.disableAsyncCache)
109
+ return fs;
110
+ // Iterate over all of the files and cache their contents
111
+ for (const [path, node] of index) {
112
+ if (!(node.mode & S_IFREG))
113
+ continue;
114
+ await requests.get(baseUrl + path, { warn }, options.requestInit).catch(parseError(path, fs));
115
+ }
116
+ return fs;
157
117
  },
158
118
  };
159
119
  export const Fetch = _Fetch;
@@ -5,8 +5,5 @@ export * from './overlay.js';
5
5
  export * from './passthrough.js';
6
6
  export * from './port/fs.js';
7
7
  export * from './store/fs.js';
8
- export * from './store/file_index.js';
9
- export * from './store/index_fs.js';
10
- export * from './store/inode.js';
11
- export * from './store/simple.js';
8
+ export * from './store/map.js';
12
9
  export * from './store/store.js';
@@ -5,8 +5,5 @@ export * from './overlay.js';
5
5
  export * from './passthrough.js';
6
6
  export * from './port/fs.js';
7
7
  export * from './store/fs.js';
8
- export * from './store/file_index.js';
9
- export * from './store/index_fs.js';
10
- export * from './store/inode.js';
11
- export * from './store/simple.js';
8
+ export * from './store/map.js';
12
9
  export * from './store/store.js';
@@ -1,14 +1,16 @@
1
1
  import { StoreFS } from './store/fs.js';
2
- import { SimpleTransaction, type SimpleSyncStore } from './store/simple.js';
2
+ import { SyncMapTransaction, type SyncMapStore } from './store/map.js';
3
3
  /**
4
4
  * A simple in-memory store
5
5
  */
6
- export declare class InMemoryStore extends Map<number, Uint8Array> implements SimpleSyncStore {
7
- name: string;
8
- constructor(name?: string);
6
+ export declare class InMemoryStore extends Map<number, Uint8Array> implements SyncMapStore {
7
+ readonly label?: string | undefined;
8
+ readonly flags: readonly [];
9
+ readonly name = "tmpfs";
10
+ constructor(label?: string | undefined);
9
11
  sync(): Promise<void>;
10
12
  clearSync(): void;
11
- transaction(): SimpleTransaction;
13
+ transaction(): SyncMapTransaction;
12
14
  }
13
15
  declare const _InMemory: {
14
16
  readonly name: "InMemory";
@@ -1,19 +1,21 @@
1
1
  import { StoreFS } from './store/fs.js';
2
- import { SimpleTransaction } from './store/simple.js';
2
+ import { SyncMapTransaction } from './store/map.js';
3
3
  /**
4
4
  * A simple in-memory store
5
5
  */
6
6
  export class InMemoryStore extends Map {
7
- constructor(name = 'tmp') {
7
+ constructor(label) {
8
8
  super();
9
- this.name = name;
9
+ this.label = label;
10
+ this.flags = [];
11
+ this.name = 'tmpfs';
10
12
  }
11
13
  async sync() { }
12
14
  clearSync() {
13
15
  this.clear();
14
16
  }
15
17
  transaction() {
16
- return new SimpleTransaction(this);
18
+ return new SyncMapTransaction(this);
17
19
  }
18
20
  }
19
21
  const _InMemory = {
@@ -1,8 +1,8 @@
1
- import type { File } from '../file.js';
2
- import type { CreationOptions, FileSystemMetadata } from '../filesystem.js';
1
+ import type { File } from '../internal/file.js';
2
+ import type { CreationOptions } from '../internal/filesystem.js';
3
3
  import type { Stats } from '../stats.js';
4
- import type { InodeLike } from './store/inode.js';
5
- import { FileSystem } from '../filesystem.js';
4
+ import type { InodeLike } from '../internal/inode.js';
5
+ import { FileSystem } from '../internal/filesystem.js';
6
6
  /**
7
7
  * Configuration options for OverlayFS instances.
8
8
  */
@@ -36,7 +36,6 @@ export declare class OverlayFS extends FileSystem {
36
36
  private _deleteLogError?;
37
37
  private _ready;
38
38
  constructor({ writable, readable }: OverlayOptions);
39
- metadata(): FileSystemMetadata;
40
39
  sync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): Promise<void>;
41
40
  syncSync(path: string, data: Uint8Array, stats: Readonly<InodeLike>): void;
42
41
  read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
@@ -50,10 +50,12 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
50
50
  var e = new Error(message);
51
51
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
52
  });
53
- import { Errno, ErrnoError } from '../error.js';
54
- import { LazyFile, parseFlag } from '../file.js';
55
- import { FileSystem } from '../filesystem.js';
56
- import { canary, decodeUTF8, encodeUTF8 } from '../utils.js';
53
+ import { canary } from 'utilium';
54
+ import { Errno, ErrnoError } from '../internal/error.js';
55
+ import { LazyFile, parseFlag } from '../internal/file.js';
56
+ import { FileSystem } from '../internal/filesystem.js';
57
+ import { crit, err, info } from '../internal/log.js';
58
+ import { decodeUTF8, encodeUTF8 } from '../utils.js';
57
59
  import { dirname, join } from '../vfs/path.js';
58
60
  /** @internal */
59
61
  const deletionLogPath = '/.deleted';
@@ -72,7 +74,7 @@ export class OverlayFS extends FileSystem {
72
74
  await this._ready;
73
75
  }
74
76
  constructor({ writable, readable }) {
75
- super();
77
+ super(0x62756c6c, readable.name);
76
78
  this._isInitialized = false;
77
79
  this._deletedFiles = new Set();
78
80
  this._deleteLog = '';
@@ -83,17 +85,11 @@ export class OverlayFS extends FileSystem {
83
85
  this._deleteLogUpdateNeeded = false;
84
86
  this.writable = writable;
85
87
  this.readable = readable;
86
- if (this.writable.metadata().readonly) {
87
- throw new ErrnoError(Errno.EINVAL, 'Writable file system must be writable.');
88
+ if (this.writable.attributes.has('no_write')) {
89
+ throw err(new ErrnoError(Errno.EINVAL, 'Writable file can not be written to'));
88
90
  }
89
91
  this._ready = this._initialize();
90
92
  }
91
- metadata() {
92
- return {
93
- ...super.metadata(),
94
- name: OverlayFS.name,
95
- };
96
- }
97
93
  async sync(path, data, stats) {
98
94
  await this.copyForWrite(path);
99
95
  await this.writable.sync(path, data, stats);
@@ -133,10 +129,10 @@ export class OverlayFS extends FileSystem {
133
129
  const { buffer } = await file.read(new Uint8Array(size));
134
130
  this._deleteLog = decodeUTF8(buffer);
135
131
  }
136
- catch (err) {
137
- if (err.errno !== Errno.ENOENT) {
138
- throw err;
139
- }
132
+ catch (error) {
133
+ if (error.errno !== Errno.ENOENT)
134
+ throw err(error);
135
+ info('Overlay does not have a deletion log');
140
136
  }
141
137
  this._isInitialized = true;
142
138
  this._reparseDeletionLog();
@@ -405,7 +401,7 @@ export class OverlayFS extends FileSystem {
405
401
  }
406
402
  checkInitialized() {
407
403
  if (!this._isInitialized) {
408
- throw new ErrnoError(Errno.EPERM, 'Overlay is not initialized');
404
+ throw crit(new ErrnoError(Errno.EPERM, 'Overlay is not initialized'), { fs: this });
409
405
  }
410
406
  if (!this._deleteLogError) {
411
407
  return;
@@ -426,7 +422,7 @@ export class OverlayFS extends FileSystem {
426
422
  createParentDirectoriesSync(path) {
427
423
  let parent = dirname(path);
428
424
  const toCreate = [];
429
- const silence = canary(path);
425
+ const silence = canary(ErrnoError.With('EDEADLK', path));
430
426
  while (!this.writable.existsSync(parent)) {
431
427
  toCreate.push(parent);
432
428
  parent = dirname(parent);
@@ -444,7 +440,7 @@ export class OverlayFS extends FileSystem {
444
440
  async createParentDirectories(path) {
445
441
  let parent = dirname(path);
446
442
  const toCreate = [];
447
- const silence = canary(path);
443
+ const silence = canary(ErrnoError.With('EDEADLK', path));
448
444
  while (!(await this.writable.exists(parent))) {
449
445
  toCreate.push(parent);
450
446
  parent = dirname(parent);
@@ -1,8 +1,8 @@
1
1
  import type * as fs from 'node:fs';
2
- import { File } from '../file.js';
3
- import { FileSystem } from '../filesystem.js';
2
+ import { File } from '../internal/file.js';
3
+ import { FileSystem } from '../internal/filesystem.js';
4
+ import type { InodeLike } from '../internal/inode.js';
4
5
  import { Stats } from '../stats.js';
5
- import type { InodeLike } from './store/inode.js';
6
6
  export type NodeFS = typeof fs;
7
7
  export interface PassthroughOptions {
8
8
  fs: NodeFS;
@@ -50,9 +50,9 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
50
50
  var e = new Error(message);
51
51
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
52
  });
53
- import { ErrnoError } from '../error.js';
54
- import { File } from '../file.js';
55
- import { FileSystem } from '../filesystem.js';
53
+ import { ErrnoError } from '../internal/error.js';
54
+ import { File } from '../internal/file.js';
55
+ import { FileSystem } from '../internal/filesystem.js';
56
56
  import { Stats } from '../stats.js';
57
57
  import { join, resolve } from '../vfs/path.js';
58
58
  class PassthroughFile extends File {
@@ -137,7 +137,7 @@ class PassthroughFile extends File {
137
137
  }
138
138
  export class PassthroughFS extends FileSystem {
139
139
  constructor(nodeFS, prefix) {
140
- super();
140
+ super(0x6e6f6465, 'nodefs');
141
141
  this.nodeFS = nodeFS;
142
142
  this.prefix = prefix;
143
143
  }
@@ -426,8 +426,6 @@ export class PassthroughFS extends FileSystem {
426
426
  if (fd)
427
427
  this.nodeFS.closeSync(fd);
428
428
  }
429
- // unreachable
430
- throw ErrnoError.With('EIO', path, 'read');
431
429
  }
432
430
  async write(path, buffer, offset) {
433
431
  try {
@@ -1,10 +1,10 @@
1
1
  import type { ExtractProperties } from 'utilium';
2
+ import type { Inode, InodeLike } from '../..//internal/inode.js';
2
3
  import type { MountConfiguration } from '../../config.js';
3
- import type { CreationOptions, FileSystemMetadata } from '../../filesystem.js';
4
+ import type { File } from '../../internal/file.js';
5
+ import type { CreationOptions, FileSystemMetadata } from '../../internal/filesystem.js';
4
6
  import type { Backend, FilesystemOf } from '../backend.js';
5
- import type { Inode, InodeLike } from '../store/inode.js';
6
- import type { File } from '../../file.js';
7
- import { FileSystem } from '../../filesystem.js';
7
+ import { FileSystem } from '../../internal/filesystem.js';
8
8
  import { Stats } from '../../stats.js';
9
9
  import * as RPC from './rpc.js';
10
10
  type FSMethods = ExtractProperties<FileSystem, (...args: any[]) => Promise<any> | FileSystemMetadata>;
@@ -33,7 +33,6 @@ export declare class PortFS extends PortFS_base {
33
33
  * Constructs a new PortFS instance that connects with the FS running on `options.port`.
34
34
  */
35
35
  constructor(options: RPC.Options);
36
- metadata(): FileSystemMetadata;
37
36
  protected rpc<const T extends FSMethod>(method: T, ...args: Parameters<FSMethods[T]>): Promise<Awaited<ReturnType<FSMethods[T]>>>;
38
37
  ready(): Promise<void>;
39
38
  rename(oldPath: string, newPath: string): Promise<void>;