@zenfs/core 1.3.6 → 1.4.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/memory.d.ts +4 -4
  2. package/dist/backends/memory.js +4 -4
  3. package/dist/backends/overlay.d.ts +5 -2
  4. package/dist/backends/overlay.js +7 -10
  5. package/dist/backends/port/fs.js +1 -4
  6. package/dist/config.js +4 -8
  7. package/dist/context.d.ts +32 -0
  8. package/dist/context.js +23 -0
  9. package/dist/credentials.d.ts +5 -5
  10. package/dist/credentials.js +10 -6
  11. package/dist/emulation/async.d.ts +90 -89
  12. package/dist/emulation/async.js +76 -75
  13. package/dist/emulation/dir.d.ts +3 -1
  14. package/dist/emulation/dir.js +6 -7
  15. package/dist/emulation/index.d.ts +1 -1
  16. package/dist/emulation/index.js +1 -1
  17. package/dist/emulation/promises.d.ts +50 -48
  18. package/dist/emulation/promises.js +78 -77
  19. package/dist/emulation/shared.d.ts +35 -8
  20. package/dist/emulation/shared.js +37 -11
  21. package/dist/emulation/sync.d.ts +63 -62
  22. package/dist/emulation/sync.js +72 -73
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/stats.d.ts +2 -1
  26. package/dist/stats.js +5 -4
  27. package/package.json +3 -5
  28. package/scripts/test.js +78 -17
  29. package/tests/assignment.ts +1 -1
  30. package/tests/common/context.test.ts +19 -0
  31. package/tests/{devices.test.ts → common/devices.test.ts} +3 -3
  32. package/tests/{handle.test.ts → common/handle.test.ts} +1 -1
  33. package/tests/common/mounts.test.ts +36 -0
  34. package/tests/{mutex.test.ts → common/mutex.test.ts} +3 -3
  35. package/tests/common/path.test.ts +34 -0
  36. package/tests/common.ts +4 -3
  37. package/tests/fs/dir.test.ts +11 -11
  38. package/tests/fs/directory.test.ts +17 -17
  39. package/tests/fs/errors.test.ts +29 -39
  40. package/tests/fs/watch.test.ts +2 -2
  41. package/tests/setup/context.ts +9 -0
  42. package/tests/setup/cow+fetch.ts +1 -1
  43. package/tests/setup/memory.ts +1 -1
  44. package/tests/{setup/common.ts → setup.ts} +6 -5
  45. package/src/backends/backend.ts +0 -161
  46. package/src/backends/fetch.ts +0 -180
  47. package/src/backends/file_index.ts +0 -206
  48. package/src/backends/memory.ts +0 -45
  49. package/src/backends/overlay.ts +0 -560
  50. package/src/backends/port/fs.ts +0 -329
  51. package/src/backends/port/readme.md +0 -54
  52. package/src/backends/port/rpc.ts +0 -167
  53. package/src/backends/readme.md +0 -3
  54. package/src/backends/store/fs.ts +0 -667
  55. package/src/backends/store/readme.md +0 -9
  56. package/src/backends/store/simple.ts +0 -154
  57. package/src/backends/store/store.ts +0 -189
  58. package/src/config.ts +0 -227
  59. package/src/credentials.ts +0 -49
  60. package/src/devices.ts +0 -521
  61. package/src/emulation/async.ts +0 -834
  62. package/src/emulation/cache.ts +0 -86
  63. package/src/emulation/config.ts +0 -21
  64. package/src/emulation/constants.ts +0 -182
  65. package/src/emulation/dir.ts +0 -138
  66. package/src/emulation/index.ts +0 -8
  67. package/src/emulation/path.ts +0 -440
  68. package/src/emulation/promises.ts +0 -1140
  69. package/src/emulation/shared.ts +0 -172
  70. package/src/emulation/streams.ts +0 -34
  71. package/src/emulation/sync.ts +0 -863
  72. package/src/emulation/watchers.ts +0 -194
  73. package/src/error.ts +0 -307
  74. package/src/file.ts +0 -631
  75. package/src/filesystem.ts +0 -174
  76. package/src/index.ts +0 -35
  77. package/src/inode.ts +0 -128
  78. package/src/mixins/async.ts +0 -230
  79. package/src/mixins/index.ts +0 -5
  80. package/src/mixins/mutexed.ts +0 -257
  81. package/src/mixins/readonly.ts +0 -96
  82. package/src/mixins/shared.ts +0 -25
  83. package/src/mixins/sync.ts +0 -58
  84. package/src/polyfills.ts +0 -21
  85. package/src/stats.ts +0 -405
  86. package/src/utils.ts +0 -276
  87. package/tests/mounts.test.ts +0 -18
  88. package/tests/path.test.ts +0 -34
package/src/filesystem.ts DELETED
@@ -1,174 +0,0 @@
1
- import type { ErrnoError } from './error.js';
2
- import type { File } from './file.js';
3
- import { ZenFsType, type Stats } from './stats.js';
4
-
5
- export type FileContents = ArrayBufferView | string;
6
-
7
- /**
8
- * Metadata about a FileSystem
9
- */
10
- export interface FileSystemMetadata {
11
- /**
12
- * The name of the FS
13
- */
14
- name: string;
15
-
16
- /**
17
- * Whether the FS is readonly or not
18
- */
19
- readonly: boolean;
20
-
21
- /**
22
- * The total space
23
- */
24
- totalSpace: number;
25
-
26
- /**
27
- * The available space
28
- */
29
- freeSpace: number;
30
-
31
- /**
32
- * If set, disables File from using a resizable array buffer.
33
- * @default false
34
- */
35
- noResizableBuffers: boolean;
36
-
37
- /**
38
- * If set, disables caching on async file systems.
39
- * This means *sync operations will not work*.
40
- * It has no affect on sync file systems.
41
- * @default false
42
- */
43
- noAsyncCache: boolean;
44
-
45
- /**
46
- * The optimal block size to use with the file system
47
- * @default 4096
48
- */
49
- blockSize?: number;
50
-
51
- /**
52
- * Total number of (file) nodes available
53
- */
54
- totalNodes?: number;
55
-
56
- /**
57
- * Number of free (file) nodes available
58
- */
59
- freeNodes?: number;
60
-
61
- /**
62
- * The type of the FS
63
- */
64
- type: number;
65
- }
66
-
67
- /**
68
- * Provides a consistent and easy to use internal API.
69
- * Default implementations for `exists` and `existsSync` are included.
70
- * If you are extending this class, note that every path is an absolute path and all arguments are present.
71
- * @internal
72
- */
73
- export abstract class FileSystem {
74
- /**
75
- * Get metadata about the current file system
76
- */
77
- public metadata(): FileSystemMetadata {
78
- return {
79
- name: this.constructor.name.toLowerCase(),
80
- readonly: false,
81
- totalSpace: 0,
82
- freeSpace: 0,
83
- noResizableBuffers: false,
84
- noAsyncCache: this._disableSync ?? false,
85
- type: ZenFsType,
86
- };
87
- }
88
-
89
- /**
90
- * Whether the sync cache should be disabled.
91
- * Only affects async things.
92
- * @internal @protected
93
- */
94
- _disableSync?: boolean;
95
-
96
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
97
- public constructor(...args: any[]) {}
98
-
99
- public async ready(): Promise<void> {}
100
-
101
- public abstract rename(oldPath: string, newPath: string): Promise<void>;
102
- public abstract renameSync(oldPath: string, newPath: string): void;
103
-
104
- public abstract stat(path: string): Promise<Stats>;
105
- public abstract statSync(path: string): Stats;
106
-
107
- /**
108
- * Opens the file at `path` with `flag`. The file must exist.
109
- * @param path The path to open.
110
- * @param flag The flag to use when opening the file.
111
- */
112
- public abstract openFile(path: string, flag: string): Promise<File>;
113
-
114
- /**
115
- * Opens the file at `path` with `flag`. The file must exist.
116
- * @param path The path to open.
117
- * @param flag The flag to use when opening the file.
118
- */
119
- public abstract openFileSync(path: string, flag: string): File;
120
-
121
- /**
122
- * Create the file at `path` with `mode`. Then, open it with `flag`.
123
- */
124
- public abstract createFile(path: string, flag: string, mode: number): Promise<File>;
125
-
126
- /**
127
- * Create the file at `path` with `mode`. Then, open it with `flag`.
128
- */
129
- public abstract createFileSync(path: string, flag: string, mode: number): File;
130
-
131
- public abstract unlink(path: string): Promise<void>;
132
- public abstract unlinkSync(path: string): void;
133
-
134
- // Directory operations
135
-
136
- public abstract rmdir(path: string): Promise<void>;
137
- public abstract rmdirSync(path: string): void;
138
-
139
- public abstract mkdir(path: string, mode: number): Promise<void>;
140
- public abstract mkdirSync(path: string, mode: number): void;
141
-
142
- public abstract readdir(path: string): Promise<string[]>;
143
- public abstract readdirSync(path: string): string[];
144
-
145
- /**
146
- * Test whether or not `path` exists.
147
- */
148
- public async exists(path: string): Promise<boolean> {
149
- try {
150
- await this.stat(path);
151
- return true;
152
- } catch (e) {
153
- return (e as ErrnoError).code != 'ENOENT';
154
- }
155
- }
156
-
157
- /**
158
- * Test whether or not `path` exists.
159
- */
160
- public existsSync(path: string): boolean {
161
- try {
162
- this.statSync(path);
163
- return true;
164
- } catch (e) {
165
- return (e as ErrnoError).code != 'ENOENT';
166
- }
167
- }
168
-
169
- public abstract link(target: string, link: string): Promise<void>;
170
- public abstract linkSync(target: string, link: string): void;
171
-
172
- public abstract sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
173
- public abstract syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
174
- }
package/src/index.ts DELETED
@@ -1,35 +0,0 @@
1
- export * from './error.js';
2
- export * from './backends/port/fs.js';
3
- export * from './backends/fetch.js';
4
- export * from './backends/memory.js';
5
- export * from './backends/file_index.js';
6
- export * from './backends/overlay.js';
7
- export * from './backends/store/fs.js';
8
- export * from './backends/store/simple.js';
9
- export * from './backends/store/store.js';
10
- export * from './backends/backend.js';
11
- export * from './config.js';
12
- export * from './credentials.js';
13
- export * from './devices.js';
14
- export { default as devices } from './devices.js';
15
- export * from './file.js';
16
- export * from './filesystem.js';
17
- export * from './inode.js';
18
- export * from './mixins/index.js';
19
- export * from './stats.js';
20
- export * from './utils.js';
21
-
22
- export * from './emulation/index.js';
23
- import * as fs from './emulation/index.js';
24
- export { fs };
25
- export default fs;
26
-
27
- declare global {
28
- /**
29
- * Global FS emulation. Do not use unless absolutely needed.
30
- * @hidden
31
- */
32
- // eslint-disable-next-line no-var
33
- var __zenfs__: typeof fs;
34
- }
35
- globalThis.__zenfs__ = fs;
package/src/inode.ts DELETED
@@ -1,128 +0,0 @@
1
- import { deserialize, sizeof, struct, types as t } from 'utilium';
2
- import { Stats, type StatsLike } from './stats.js';
3
- import { randomBigInt } from './utils.js';
4
-
5
- /**
6
- * Room inode
7
- * @hidden
8
- */
9
- export const rootIno = 0n;
10
-
11
- /**
12
- * Generic inode definition that can easily be serialized.
13
- * @internal
14
- * @todo [BREAKING]
15
- */
16
- @struct()
17
- export class Inode implements StatsLike {
18
- public constructor(buffer?: ArrayBufferLike | ArrayBufferView) {
19
- if (buffer) {
20
- const sz_inode = sizeof(Inode);
21
- const oldSize = sz_inode - sizeof('uint64');
22
- if (buffer.byteLength < oldSize) {
23
- throw new RangeError(`Can not create an inode from a buffer less than ${oldSize} bytes`);
24
- }
25
-
26
- // Expand the buffer so it is the right size
27
- if (buffer.byteLength < sz_inode) {
28
- const newBuffer = new Uint8Array(sz_inode);
29
- // Fill the new buffer with current data
30
- newBuffer.set(new Uint8Array(ArrayBuffer.isView(buffer) ? buffer.buffer : buffer));
31
- /* Add a random ino.
32
- This will be different from the actual one,
33
- but `ino` isn't used anywhere so it should be fine.
34
- */
35
- const randomIno = crypto.getRandomValues(new Uint32Array(2));
36
- newBuffer.set(randomIno, sz_inode - 2);
37
- buffer = newBuffer;
38
- }
39
-
40
- deserialize(this, buffer);
41
- return;
42
- }
43
-
44
- // set defaults on a fresh inode
45
- this.ino = randomBigInt();
46
- this.data = randomBigInt();
47
- this.nlink = 1;
48
- this.size = 4096;
49
- const now = Date.now();
50
- this.atimeMs = now;
51
- this.mtimeMs = now;
52
- this.ctimeMs = now;
53
- this.birthtimeMs = now;
54
- }
55
-
56
- @t.uint64 public data!: bigint;
57
- @t.uint32 public size!: number;
58
- @t.uint16 public mode!: number;
59
- @t.uint32 public nlink!: number;
60
- @t.uint32 public uid!: number;
61
- @t.uint32 public gid!: number;
62
- @t.float64 public atimeMs!: number;
63
- @t.float64 public birthtimeMs!: number;
64
- @t.float64 public mtimeMs!: number;
65
- @t.float64 public ctimeMs!: number;
66
- @t.uint64 public ino!: bigint;
67
-
68
- /**
69
- * Handy function that converts the Inode to a Node Stats object.
70
- */
71
- public toStats(): Stats {
72
- return new Stats(this);
73
- }
74
-
75
- /**
76
- * Updates the Inode using information from the stats object. Used by file
77
- * systems at sync time, e.g.:
78
- * - Program opens file and gets a File object.
79
- * - Program mutates file. File object is responsible for maintaining
80
- * metadata changes locally -- typically in a Stats object.
81
- * - Program closes file. File object's metadata changes are synced with the
82
- * file system.
83
- * @return True if any changes have occurred.
84
- */
85
- public update(stats: Readonly<Stats>): boolean {
86
- let hasChanged = false;
87
- if (this.size !== stats.size) {
88
- this.size = stats.size;
89
- hasChanged = true;
90
- }
91
-
92
- if (this.mode !== stats.mode) {
93
- this.mode = stats.mode;
94
- hasChanged = true;
95
- }
96
-
97
- if (this.nlink !== stats.nlink) {
98
- this.nlink = stats.nlink;
99
- hasChanged = true;
100
- }
101
-
102
- if (this.uid !== stats.uid) {
103
- this.uid = stats.uid;
104
- hasChanged = true;
105
- }
106
-
107
- if (this.gid !== stats.gid) {
108
- this.gid = stats.gid;
109
- hasChanged = true;
110
- }
111
-
112
- if (this.atimeMs !== stats.atimeMs) {
113
- this.atimeMs = stats.atimeMs;
114
- hasChanged = true;
115
- }
116
- if (this.mtimeMs !== stats.mtimeMs) {
117
- this.mtimeMs = stats.mtimeMs;
118
- hasChanged = true;
119
- }
120
-
121
- if (this.ctimeMs !== stats.ctimeMs) {
122
- this.ctimeMs = stats.ctimeMs;
123
- hasChanged = true;
124
- }
125
-
126
- return hasChanged;
127
- }
128
- }
@@ -1,230 +0,0 @@
1
- import { StoreFS } from '../backends/store/fs.js';
2
- import type { Store } from '../backends/store/store.js';
3
- import { join } from '../emulation/path.js';
4
- import { Errno, ErrnoError } from '../error.js';
5
- import { parseFlag, PreloadFile, type File } from '../file.js';
6
- import type { FileSystem } from '../filesystem.js';
7
- import type { Stats } from '../stats.js';
8
- import type { AsyncFSMethods, Mixin } from './shared.js';
9
-
10
- /** @internal */
11
- export type AsyncOperation = {
12
- [K in keyof AsyncFSMethods]: [K, ...Parameters<FileSystem[K]>];
13
- }[keyof AsyncFSMethods];
14
-
15
- /**
16
- * @internal
17
- */
18
- export interface Async {
19
- /**
20
- * @internal @protected
21
- */
22
- _sync?: FileSystem;
23
- queueDone(): Promise<void>;
24
- ready(): Promise<void>;
25
- renameSync(oldPath: string, newPath: string): void;
26
- statSync(path: string): Stats;
27
- createFileSync(path: string, flag: string, mode: number): File;
28
- openFileSync(path: string, flag: string): File;
29
- unlinkSync(path: string): void;
30
- rmdirSync(path: string): void;
31
- mkdirSync(path: string, mode: number): void;
32
- readdirSync(path: string): string[];
33
- linkSync(srcpath: string, dstpath: string): void;
34
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
35
- }
36
-
37
- /**
38
- * Async() implements synchronous methods on an asynchronous file system
39
- *
40
- * Implementing classes must define `_sync` for the synchronous file system used as a cache.
41
- *
42
- * Synchronous methods on an asynchronous FS are implemented by performing operations over the in-memory copy,
43
- * while asynchronously pipelining them to the backing store.
44
- * During loading, the contents of the async file system are preloaded into the synchronous store.
45
- *
46
- */
47
- export function Async<const T extends typeof FileSystem>(FS: T): Mixin<T, Async> {
48
- abstract class AsyncFS extends FS {
49
- /**
50
- * Queue of pending asynchronous operations.
51
- */
52
- private _queue: AsyncOperation[] = [];
53
- private get _queueRunning(): boolean {
54
- return !!this._queue.length;
55
- }
56
-
57
- public queueDone(): Promise<void> {
58
- return new Promise(resolve => {
59
- const check = (): unknown => (this._queueRunning ? setTimeout(check) : resolve());
60
- check();
61
- });
62
- }
63
-
64
- private _isInitialized: boolean = false;
65
-
66
- abstract _sync?: FileSystem;
67
-
68
- public async ready(): Promise<void> {
69
- await super.ready();
70
- await this.queueDone();
71
- if (this._isInitialized || this._disableSync) {
72
- return;
73
- }
74
- this.checkSync();
75
-
76
- await this._sync.ready();
77
-
78
- // optimization: for 2 storeFS', we copy at a lower abstraction level.
79
- if (this._sync instanceof StoreFS && this instanceof StoreFS) {
80
- const sync = (this._sync as StoreFS<Store>)['store'].transaction();
81
- const async = (this as StoreFS<Store>)['store'].transaction();
82
-
83
- const promises = [];
84
- for (const key of await async.keys()) {
85
- promises.push(async.get(key).then(data => sync.setSync(key, data)));
86
- }
87
-
88
- await Promise.all(promises);
89
-
90
- this._isInitialized = true;
91
- return;
92
- }
93
-
94
- try {
95
- await this.crossCopy('/');
96
- this._isInitialized = true;
97
- } catch (e) {
98
- this._isInitialized = false;
99
- throw e;
100
- }
101
- }
102
-
103
- protected checkSync(path?: string, syscall?: string): asserts this is { _sync: FileSystem } {
104
- if (this._disableSync) {
105
- throw new ErrnoError(Errno.ENOTSUP, 'Sync caching has been disabled for this async file system', path, syscall);
106
- }
107
- if (!this._sync) {
108
- throw new ErrnoError(Errno.ENOTSUP, 'No sync cache is attached to this async file system', path, syscall);
109
- }
110
- }
111
-
112
- public renameSync(oldPath: string, newPath: string): void {
113
- this.checkSync(oldPath, 'rename');
114
- this._sync.renameSync(oldPath, newPath);
115
- this.queue('rename', oldPath, newPath);
116
- }
117
-
118
- public statSync(path: string): Stats {
119
- this.checkSync(path, 'stat');
120
- return this._sync.statSync(path);
121
- }
122
-
123
- public createFileSync(path: string, flag: string, mode: number): PreloadFile<this> {
124
- this.checkSync(path, 'createFile');
125
- this._sync.createFileSync(path, flag, mode);
126
- this.queue('createFile', path, flag, mode);
127
- return this.openFileSync(path, flag);
128
- }
129
-
130
- public openFileSync(path: string, flag: string): PreloadFile<this> {
131
- this.checkSync(path, 'openFile');
132
- const file = this._sync.openFileSync(path, flag + '+');
133
- const stats = file.statSync();
134
- const buffer = new Uint8Array(stats.size);
135
- file.readSync(buffer);
136
- return new PreloadFile(this, path, flag, stats, buffer);
137
- }
138
-
139
- public unlinkSync(path: string): void {
140
- this.checkSync(path, 'unlinkSync');
141
- this._sync.unlinkSync(path);
142
- this.queue('unlink', path);
143
- }
144
-
145
- public rmdirSync(path: string): void {
146
- this.checkSync(path, 'rmdir');
147
- this._sync.rmdirSync(path);
148
- this.queue('rmdir', path);
149
- }
150
-
151
- public mkdirSync(path: string, mode: number): void {
152
- this.checkSync(path, 'mkdir');
153
- this._sync.mkdirSync(path, mode);
154
- this.queue('mkdir', path, mode);
155
- }
156
-
157
- public readdirSync(path: string): string[] {
158
- this.checkSync(path, 'readdir');
159
- return this._sync.readdirSync(path);
160
- }
161
-
162
- public linkSync(srcpath: string, dstpath: string): void {
163
- this.checkSync(srcpath, 'link');
164
- this._sync.linkSync(srcpath, dstpath);
165
- this.queue('link', srcpath, dstpath);
166
- }
167
-
168
- public syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void {
169
- this.checkSync(path, 'sync');
170
- this._sync.syncSync(path, data, stats);
171
- this.queue('sync', path, data, stats);
172
- }
173
-
174
- public existsSync(path: string): boolean {
175
- this.checkSync(path, 'exists');
176
- return this._sync.existsSync(path);
177
- }
178
-
179
- /**
180
- * @internal
181
- */
182
- protected async crossCopy(path: string): Promise<void> {
183
- this.checkSync(path, 'crossCopy');
184
- const stats = await this.stat(path);
185
- if (!stats.isDirectory()) {
186
- await using asyncFile = await this.openFile(path, parseFlag('r'));
187
- using syncFile = this._sync.createFileSync(path, parseFlag('w'), stats.mode);
188
- const buffer = new Uint8Array(stats.size);
189
- await asyncFile.read(buffer);
190
- syncFile.writeSync(buffer, 0, stats.size);
191
- return;
192
- }
193
- if (path !== '/') {
194
- const stats = await this.stat(path);
195
- this._sync.mkdirSync(path, stats.mode);
196
- }
197
- const promises = [];
198
- for (const file of await this.readdir(path)) {
199
- promises.push(this.crossCopy(join(path, file)));
200
- }
201
- await Promise.all(promises);
202
- }
203
-
204
- /**
205
- * @internal
206
- */
207
- private async _next(): Promise<void> {
208
- if (!this._queueRunning) {
209
- return;
210
- }
211
-
212
- const [method, ...args] = this._queue.shift()!;
213
- // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
214
- await this[method](...args);
215
- await this._next();
216
- }
217
-
218
- /**
219
- * @internal
220
- */
221
- private queue(...op: AsyncOperation) {
222
- this._queue.push(op);
223
- void this._next();
224
- }
225
- }
226
-
227
- return AsyncFS;
228
- }
229
-
230
- export function asyncPatch<T extends typeof FileSystem>(fs: Mixin<T, Async>) {}
@@ -1,5 +0,0 @@
1
- export * from './async.js';
2
- export * from './mutexed.js';
3
- export * from './readonly.js';
4
- export * from './shared.js';
5
- export * from './sync.js';