@zenfs/core 1.8.7 → 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 (118) 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 +33 -49
  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/mixins/sync.js +6 -0
  56. package/dist/stats.d.ts +2 -3
  57. package/dist/stats.js +7 -5
  58. package/dist/utils.d.ts +2 -15
  59. package/dist/utils.js +10 -47
  60. package/dist/vfs/async.d.ts +2 -2
  61. package/dist/vfs/async.js +3 -3
  62. package/dist/vfs/dir.js +1 -1
  63. package/dist/vfs/promises.d.ts +6 -6
  64. package/dist/vfs/promises.js +54 -49
  65. package/dist/vfs/shared.d.ts +3 -3
  66. package/dist/vfs/shared.js +16 -10
  67. package/dist/vfs/streams.js +1 -1
  68. package/dist/vfs/sync.d.ts +1 -2
  69. package/dist/vfs/sync.js +14 -15
  70. package/dist/vfs/types.d.ts +1 -0
  71. package/dist/vfs/watchers.d.ts +5 -1
  72. package/dist/vfs/watchers.js +16 -19
  73. package/package.json +3 -3
  74. package/readme.md +12 -12
  75. package/scripts/test.js +15 -3
  76. package/tests/backend/fetch.test.ts +49 -0
  77. package/tests/backend/port.test.ts +130 -0
  78. package/tests/common/context.test.ts +9 -4
  79. package/tests/common.ts +21 -3
  80. package/tests/data/image.jpg +0 -0
  81. package/tests/data/utf8.txt +1 -0
  82. package/tests/fetch/config.js +40 -0
  83. package/tests/fetch/fetch.ts +20 -0
  84. package/tests/fetch/run.sh +3 -3
  85. package/tests/fetch/{server.ts → server.js} +15 -11
  86. package/tests/fs/directory.test.ts +1 -1
  87. package/tests/fs/errors.test.ts +1 -1
  88. package/tests/fs/links.test.ts +1 -1
  89. package/tests/fs/open.test.ts +1 -1
  90. package/tests/fs/permissions.test.ts +2 -3
  91. package/tests/fs/rename.test.ts +1 -1
  92. package/tests/fs/stat.test.ts +1 -1
  93. package/tests/fs/times.test.ts +1 -1
  94. package/tests/fs/watch.test.ts +21 -22
  95. package/tests/fs/write.test.ts +1 -1
  96. package/tests/fs/writeFile.test.ts +8 -7
  97. package/tests/readme.md +3 -3
  98. package/tests/setup/_overlay.ts +7 -0
  99. package/tests/setup/context.ts +2 -2
  100. package/tests/setup/index.ts +3 -3
  101. package/tests/setup/memory.ts +2 -2
  102. package/tests/setup/port.ts +2 -2
  103. package/tests/setup.ts +25 -5
  104. package/tests/tsconfig.json +3 -2
  105. package/dist/backends/store/index_fs.d.ts +0 -34
  106. package/dist/backends/store/index_fs.js +0 -67
  107. package/dist/filesystem.js +0 -52
  108. package/tests/fetch/cow+fetch.ts +0 -13
  109. package/tests/port/channel.test.ts +0 -39
  110. package/tests/port/config.test.ts +0 -30
  111. package/tests/port/remote.test.ts +0 -32
  112. package/tests/port/timeout.test.ts +0 -48
  113. /package/dist/{credentials.d.ts → internal/credentials.d.ts} +0 -0
  114. /package/dist/{credentials.js → internal/credentials.js} +0 -0
  115. /package/dist/{error.d.ts → internal/error.d.ts} +0 -0
  116. /package/dist/{error.js → internal/error.js} +0 -0
  117. /package/tests/{port → backend}/config.worker.js +0 -0
  118. /package/tests/{port → backend}/remote.worker.js +0 -0
@@ -1,10 +1,10 @@
1
1
  import { pick } from 'utilium';
2
2
  import { resolveMountConfig } from '../../config.js';
3
- import { Errno, ErrnoError } from '../../error.js';
4
- import { FileSystem } from '../../filesystem.js';
3
+ import { Errno, ErrnoError } from '../../internal/error.js';
4
+ import { FileSystem } from '../../internal/filesystem.js';
5
+ import { err, info } from '../../internal/log.js';
5
6
  import { Async } from '../../mixins/async.js';
6
7
  import { Stats } from '../../stats.js';
7
- import { decodeUTF8 } from '../../utils.js';
8
8
  import { InMemory } from '../memory.js';
9
9
  import * as RPC from './rpc.js';
10
10
  /**
@@ -18,21 +18,15 @@ export class PortFS extends Async(FileSystem) {
18
18
  * Constructs a new PortFS instance that connects with the FS running on `options.port`.
19
19
  */
20
20
  constructor(options) {
21
- super();
21
+ super(0x706f7274, 'portfs');
22
22
  this.options = options;
23
23
  /**`
24
24
  * @hidden
25
25
  */
26
- this._sync = InMemory.create({ name: 'port-tmpfs' });
26
+ this._sync = InMemory.create({ name: 'tmpfs:port' });
27
27
  this.port = options.port;
28
28
  RPC.attach(this.port, RPC.handleResponse);
29
29
  }
30
- metadata() {
31
- return {
32
- ...super.metadata(),
33
- name: 'PortFS',
34
- };
35
- }
36
30
  rpc(method, ...args) {
37
31
  return RPC.request({ method, args }, {
38
32
  ...this.options,
@@ -130,7 +124,7 @@ const _Port = {
130
124
  validator(port) {
131
125
  // Check for a `postMessage` function.
132
126
  if (typeof (port === null || port === void 0 ? void 0 : port.postMessage) != 'function') {
133
- throw new ErrnoError(Errno.EINVAL, 'option must be a port.');
127
+ throw err(new ErrnoError(Errno.EINVAL, 'option must be a port.'));
134
128
  }
135
129
  },
136
130
  },
@@ -146,5 +140,6 @@ export async function resolveRemoteMount(port, config, _depth = 0) {
146
140
  const fs = await resolveMountConfig(config, _depth);
147
141
  attachFS(port, fs);
148
142
  stopAndReplay(fs);
143
+ info('Resolved remote mount: ' + fs.toString());
149
144
  return fs;
150
145
  }
@@ -1,6 +1,6 @@
1
1
  import type { TransferListItem } from 'node:worker_threads';
2
2
  import type { WithOptional } from 'utilium';
3
- import type { ErrnoErrorJSON } from '../../error.js';
3
+ import type { ErrnoErrorJSON } from '../../internal/error.js';
4
4
  import type { Backend, FilesystemOf } from '../backend.js';
5
5
  import type { PortFS } from './fs.js';
6
6
  import { type StatsLike } from '../../stats.js';
@@ -1,5 +1,6 @@
1
- import { Errno, ErrnoError } from '../../error.js';
2
- import { LazyFile } from '../../file.js';
1
+ import { Errno, ErrnoError } from '../../internal/error.js';
2
+ import { LazyFile } from '../../internal/file.js';
3
+ import { err, info } from '../../internal/log.js';
3
4
  import { Stats } from '../../stats.js';
4
5
  import { handleRequest } from './fs.js';
5
6
  function isFileData(value) {
@@ -12,15 +13,16 @@ export function isMessage(arg) {
12
13
  const executors = new Map();
13
14
  export function request(request, { port, timeout = 1000, fs } = {}) {
14
15
  const stack = '\n' + new Error().stack.slice('Error:'.length);
15
- if (!port) {
16
- throw ErrnoError.With('EINVAL');
17
- }
16
+ if (!port)
17
+ throw err(new ErrnoError(Errno.EINVAL, 'Can not make an RPC request without a port'));
18
18
  return new Promise((resolve, reject) => {
19
19
  const id = Math.random().toString(16).slice(10);
20
20
  executors.set(id, { resolve, reject, fs });
21
21
  port.postMessage({ ...request, _zenfs: true, id, stack });
22
22
  const _ = setTimeout(() => {
23
- const error = new ErrnoError(Errno.EIO, 'RPC Failed', typeof request.args[0] == 'string' ? request.args[0] : '', request.method);
23
+ const error = err(new ErrnoError(Errno.EIO, 'RPC Failed', typeof request.args[0] == 'string' ? request.args[0] : '', request.method), {
24
+ fs,
25
+ });
24
26
  error.stack += stack;
25
27
  reject(error);
26
28
  if (typeof _ == 'object')
@@ -34,7 +36,7 @@ export function handleResponse(response) {
34
36
  }
35
37
  const { id, value, error, stack } = response;
36
38
  if (!executors.has(id)) {
37
- const error = new ErrnoError(Errno.EIO, 'Invalid RPC id:' + id);
39
+ const error = err(new ErrnoError(Errno.EIO, 'Invalid RPC id:' + id));
38
40
  error.stack += stack;
39
41
  throw error;
40
42
  }
@@ -58,17 +60,17 @@ export function handleResponse(response) {
58
60
  return;
59
61
  }
60
62
  export function attach(port, handler) {
61
- if (!port) {
62
- throw ErrnoError.With('EINVAL');
63
- }
63
+ if (!port)
64
+ throw err(new ErrnoError(Errno.EINVAL, 'Cannot attach to non-existent port'));
65
+ info('Attached handler to port: ' + handler.name);
64
66
  port['on' in port ? 'on' : 'addEventListener']('message', (message) => {
65
67
  handler('data' in message ? message.data : message);
66
68
  });
67
69
  }
68
70
  export function detach(port, handler) {
69
- if (!port) {
70
- throw ErrnoError.With('EINVAL');
71
- }
71
+ if (!port)
72
+ throw err(new ErrnoError(Errno.EINVAL, 'Cannot detach from non-existent port'));
73
+ info('Detached handler from port: ' + handler.name);
72
74
  port['off' in port ? 'off' : 'removeEventListener']('message', (message) => {
73
75
  handler('data' in message ? message.data : message);
74
76
  });
@@ -1,10 +1,10 @@
1
- import type { File } from '../../file.js';
2
- import type { CreationOptions, FileSystemMetadata, PureCreationOptions } from '../../filesystem.js';
3
- import { FileSystem } from '../../filesystem.js';
4
- import type { FileType, Stats } from '../../stats.js';
5
- import { Index } from './file_index.js';
6
- import { Inode, type InodeLike } from './inode.js';
7
- import type { Store, Transaction } from './store.js';
1
+ import type { File } from '../../internal/file.js';
2
+ import { Index } from '../../internal/file_index.js';
3
+ import type { CreationOptions, PureCreationOptions } from '../../internal/filesystem.js';
4
+ import { FileSystem } from '../../internal/filesystem.js';
5
+ import { Inode, type InodeLike } from '../../internal/inode.js';
6
+ import type { Stats } from '../../stats.js';
7
+ import { WrappedTransaction, type Store } from './store.js';
8
8
  /**
9
9
  * A file system which uses a key-value store.
10
10
  *
@@ -16,10 +16,35 @@ import type { Store, Transaction } from './store.js';
16
16
  */
17
17
  export declare class StoreFS<T extends Store = Store> extends FileSystem {
18
18
  protected readonly store: T;
19
+ /**
20
+ * A map of paths to inode IDs
21
+ * @internal @hidden
22
+ */
23
+ readonly _ids: Map<string, number>;
24
+ /**
25
+ * A map of inode IDs to paths
26
+ * @internal @hidden
27
+ */
28
+ readonly _paths: Map<number, Set<string>>;
29
+ /**
30
+ * Gets the first path associated with an inode
31
+ */
32
+ _path(id: number): string | undefined;
33
+ /**
34
+ * Add a inode/path pair
35
+ */
36
+ _add(ino: number, path: string): void;
37
+ /**
38
+ * Remove a inode/path pair
39
+ */
40
+ _remove(ino: number): void;
41
+ /**
42
+ * Move paths in the tables
43
+ */
44
+ _move(from: string, to: string): void;
19
45
  protected _initialized: boolean;
20
46
  ready(): Promise<void>;
21
47
  constructor(store: T);
22
- metadata(): FileSystemMetadata;
23
48
  /**
24
49
  * Delete all contents stored in the file system.
25
50
  * @deprecated
@@ -77,6 +102,11 @@ export declare class StoreFS<T extends Store = Store> extends FileSystem {
77
102
  readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
78
103
  write(path: string, data: Uint8Array, offset: number): Promise<void>;
79
104
  writeSync(path: string, data: Uint8Array, offset: number): void;
105
+ /**
106
+ * Wraps a transaction
107
+ * @internal @hidden
108
+ */
109
+ transaction(): WrappedTransaction;
80
110
  /**
81
111
  * Checks if the root directory exists. Creates it if it doesn't.
82
112
  */
@@ -86,75 +116,56 @@ export declare class StoreFS<T extends Store = Store> extends FileSystem {
86
116
  */
87
117
  checkRootSync(): void;
88
118
  /**
89
- * Helper function for findINode.
90
- * @param parent The parent directory of the file we are attempting to find.
91
- * @param filename The filename of the inode we are attempting to find, minus
92
- * the parent.
119
+ * Populates the `_ids` and `_paths` maps with all existing files stored in the underlying `Store`.
93
120
  */
94
- private _findInode;
95
- /**
96
- * Helper function for findINode.
97
- * @param parent The parent directory of the file we are attempting to find.
98
- * @param filename The filename of the inode we are attempting to find, minus
99
- * the parent.
100
- * @return string The ID of the file's inode in the file system.
101
- */
102
- private _findInodeSync;
121
+ private _populate;
103
122
  /**
104
123
  * Finds the Inode of `path`.
105
124
  * @param path The path to look up.
106
125
  * @todo memoize/cache
107
126
  */
108
- private findInode;
127
+ protected findInode(tx: WrappedTransaction, path: string, syscall: string): Promise<Inode>;
109
128
  /**
110
129
  * Finds the Inode of `path`.
111
130
  * @param path The path to look up.
112
131
  * @return The Inode of the path p.
113
132
  * @todo memoize/cache
114
133
  */
115
- protected findInodeSync(tx: Transaction, path: string, syscall: string, visited?: Set<string>): Inode;
116
- /**
117
- * Adds a new node under a random ID. Retries before giving up in
118
- * the exceedingly unlikely chance that we try to reuse a random id.
119
- */
120
- protected allocNew(tx: Transaction, path: string, syscall: string): Promise<number>;
134
+ protected findInodeSync(tx: WrappedTransaction, path: string, syscall: string): Inode;
135
+ private _lastID?;
121
136
  /**
122
- * Creates a new node under a random ID. Retries before giving up in
123
- * the exceedingly unlikely chance that we try to reuse a random id.
124
- * @return The ino that the data was stored under.
137
+ * Allocates a new ID and adds the ID/path
125
138
  */
126
- protected allocNewSync(tx: Transaction, path: string, syscall: string): number;
139
+ protected allocNew(path: string, syscall: string): number;
127
140
  /**
128
141
  * Commits a new file (well, a FILE or a DIRECTORY) to the file system with `mode`.
129
142
  * Note: This will commit the transaction.
130
143
  * @param path The path to the new file.
131
- * @param type The type of the new file.
132
- * @param mode The mode to create the new file with.
144
+ * @param options The options to create the new file with.
133
145
  * @param data The data to store at the file's data node.
134
146
  */
135
- protected commitNew(path: string, type: FileType, options: PureCreationOptions, data: Uint8Array, syscall: string): Promise<Inode>;
147
+ protected commitNew(path: string, options: PureCreationOptions, data: Uint8Array, syscall: string): Promise<Inode>;
136
148
  /**
137
149
  * Commits a new file (well, a FILE or a DIRECTORY) to the file system with `mode`.
138
150
  * Note: This will commit the transaction.
139
151
  * @param path The path to the new file.
140
- * @param type The type of the new file.
141
- * @param mode The mode to create the new file with.
152
+ * @param options The options to create the new file with.
142
153
  * @param data The data to store at the file's data node.
143
154
  * @return The Inode for the new file.
144
155
  */
145
- protected commitNewSync(path: string, type: FileType, options: PureCreationOptions, data: Uint8Array, syscall: string): Inode;
156
+ protected commitNewSync(path: string, options: PureCreationOptions, data: Uint8Array, syscall: string): Inode;
146
157
  /**
147
158
  * Remove all traces of `path` from the file system.
148
159
  * @param path The path to remove from the file system.
149
160
  * @param isDir Does the path belong to a directory, or a file?
150
161
  * @todo Update mtime.
151
162
  */
152
- protected remove(path: string, isDir: boolean, syscall: string): Promise<void>;
163
+ protected remove(path: string, isDir: boolean): Promise<void>;
153
164
  /**
154
165
  * Remove all traces of `path` from the file system.
155
166
  * @param path The path to remove from the file system.
156
167
  * @param isDir Does the path belong to a directory, or a file?
157
168
  * @todo Update mtime.
158
169
  */
159
- protected removeSync(path: string, isDir: boolean, syscall: string): void;
170
+ protected removeSync(path: string, isDir: boolean): void;
160
171
  }