@componentor/fs 1.2.7 → 2.0.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.
package/dist/index.d.ts CHANGED
@@ -1,548 +1,606 @@
1
1
  /**
2
- * File system constants matching Node.js fs.constants
2
+ * File system types matching Node.js fs module interfaces
3
3
  */
4
- interface FSConstants {
5
- F_OK: number;
6
- R_OK: number;
7
- W_OK: number;
8
- X_OK: number;
9
- COPYFILE_EXCL: number;
10
- COPYFILE_FICLONE: number;
11
- COPYFILE_FICLONE_FORCE: number;
12
- O_RDONLY: number;
13
- O_WRONLY: number;
14
- O_RDWR: number;
15
- O_CREAT: number;
16
- O_EXCL: number;
17
- O_TRUNC: number;
18
- O_APPEND: number;
19
- S_IFMT: number;
20
- S_IFREG: number;
21
- S_IFDIR: number;
22
- S_IFLNK: number;
4
+ type Encoding = 'utf8' | 'utf-8' | 'ascii' | 'base64' | 'hex' | 'binary';
5
+ interface ReadOptions {
6
+ encoding?: Encoding | null;
7
+ flag?: string;
23
8
  }
24
- /**
25
- * Configuration options for OPFS instance
26
- */
27
- interface OPFSOptions {
28
- /** Use synchronous access handles when available (default: true) */
29
- useSync?: boolean;
30
- /** Enable verbose logging (default: false) */
31
- verbose?: boolean;
32
- /** Enable compression for batch writes (default: false) */
33
- useCompression?: boolean;
34
- /** Enable CRC32 checksum for batch writes (default: true) */
35
- useChecksum?: boolean;
36
- }
37
- /**
38
- * Options for readFile operation
39
- */
40
- interface ReadFileOptions {
41
- /** Text encoding (e.g., 'utf-8'). If not provided, returns Uint8Array */
42
- encoding?: string;
9
+ interface WriteOptions {
10
+ encoding?: Encoding;
11
+ mode?: number;
12
+ flag?: string;
13
+ /**
14
+ * Whether to flush data to storage after writing.
15
+ * - true (default): Data is immediately persisted - safe but slower
16
+ * - false: Data is written but not flushed - faster but may be lost on crash
17
+ */
18
+ flush?: boolean;
43
19
  }
44
- /**
45
- * Options for writeFile operation
46
- */
47
- interface WriteFileOptions {
48
- /** Text encoding for string data */
49
- encoding?: string;
20
+ interface MkdirOptions {
21
+ recursive?: boolean;
22
+ mode?: number;
50
23
  }
51
- /**
52
- * Entry for batch file write operation
53
- */
54
- interface BatchWriteEntry {
55
- /** File path to write */
56
- path: string;
57
- /** Data to write (string or binary) */
58
- data: string | Uint8Array;
24
+ interface RmdirOptions {
25
+ recursive?: boolean;
59
26
  }
60
- /**
61
- * Result entry for batch file read operation
62
- */
63
- interface BatchReadResult {
64
- /** File path */
65
- path: string;
66
- /** File data (null if file doesn't exist or error occurred) */
67
- data: Uint8Array | null;
68
- /** Error if read failed */
69
- error?: Error;
27
+ interface RmOptions {
28
+ recursive?: boolean;
29
+ force?: boolean;
70
30
  }
71
- /**
72
- * Options for readdir operation
73
- */
74
31
  interface ReaddirOptions {
75
- /** Return Dirent objects instead of strings */
32
+ encoding?: Encoding | null;
76
33
  withFileTypes?: boolean;
77
34
  }
78
- /**
79
- * Directory entry (Dirent-like object)
80
- */
81
- interface Dirent {
82
- name: string;
35
+ interface StatOptions {
36
+ bigint?: boolean;
37
+ }
38
+ interface Stats {
83
39
  isFile(): boolean;
84
40
  isDirectory(): boolean;
41
+ isBlockDevice(): boolean;
42
+ isCharacterDevice(): boolean;
85
43
  isSymbolicLink(): boolean;
86
- }
87
- /**
88
- * File statistics
89
- */
90
- interface Stats {
91
- type: 'file' | 'dir' | 'symlink';
92
- size: number;
44
+ isFIFO(): boolean;
45
+ isSocket(): boolean;
46
+ dev: number;
47
+ ino: number;
93
48
  mode: number;
94
- ctime: Date;
49
+ nlink: number;
50
+ uid: number;
51
+ gid: number;
52
+ rdev: number;
53
+ size: number;
54
+ blksize: number;
55
+ blocks: number;
56
+ atimeMs: number;
57
+ mtimeMs: number;
95
58
  ctimeMs: number;
59
+ birthtimeMs: number;
60
+ atime: Date;
96
61
  mtime: Date;
97
- mtimeMs: number;
98
- target?: string;
62
+ ctime: Date;
63
+ birthtime: Date;
64
+ }
65
+ interface Dirent {
66
+ name: string;
99
67
  isFile(): boolean;
100
68
  isDirectory(): boolean;
69
+ isBlockDevice(): boolean;
70
+ isCharacterDevice(): boolean;
101
71
  isSymbolicLink(): boolean;
72
+ isFIFO(): boolean;
73
+ isSocket(): boolean;
102
74
  }
103
- /**
104
- * Options for rm operation
105
- */
106
- interface RmOptions {
107
- /** Remove directories and their contents recursively */
108
- recursive?: boolean;
109
- /** Ignore if path doesn't exist */
110
- force?: boolean;
111
- }
112
- /**
113
- * Options for cp operation
114
- */
115
- interface CpOptions {
116
- /** Copy directories recursively */
117
- recursive?: boolean;
118
- /** Overwrite existing files */
119
- force?: boolean;
120
- /** Throw if destination exists */
121
- errorOnExist?: boolean;
122
- }
123
- /**
124
- * Options for watch operation
125
- */
126
- interface WatchOptions {
127
- /** Keep the process running while watching (default: true) */
128
- persistent?: boolean;
129
- /** Watch subdirectories recursively */
130
- recursive?: boolean;
131
- /** Abort signal to stop watching */
132
- signal?: AbortSignal;
133
- /** Encoding for filename (default: 'utf8') */
134
- encoding?: string;
135
- }
136
- /**
137
- * Watch event
138
- */
139
- interface WatchEvent {
140
- eventType: 'rename' | 'change';
141
- filename: string;
142
- }
143
- /**
144
- * File watcher
145
- */
146
- interface FSWatcher {
147
- close(): void;
148
- ref(): FSWatcher;
149
- unref(): FSWatcher;
150
- [Symbol.asyncIterator](): AsyncIterator<WatchEvent>;
75
+ interface FileSystemPromises {
76
+ readFile(path: string, options?: ReadOptions | Encoding | null): Promise<Uint8Array | string>;
77
+ writeFile(path: string, data: Uint8Array | string, options?: WriteOptions | Encoding): Promise<void>;
78
+ appendFile(path: string, data: Uint8Array | string, options?: WriteOptions | Encoding): Promise<void>;
79
+ mkdir(path: string, options?: MkdirOptions | number): Promise<string | undefined>;
80
+ rmdir(path: string, options?: RmdirOptions): Promise<void>;
81
+ rm(path: string, options?: RmOptions): Promise<void>;
82
+ unlink(path: string): Promise<void>;
83
+ readdir(path: string, options?: ReaddirOptions | Encoding | null): Promise<string[] | Dirent[]>;
84
+ stat(path: string, options?: StatOptions): Promise<Stats>;
85
+ lstat(path: string, options?: StatOptions): Promise<Stats>;
86
+ access(path: string, mode?: number): Promise<void>;
87
+ rename(oldPath: string, newPath: string): Promise<void>;
88
+ copyFile(src: string, dest: string, mode?: number): Promise<void>;
89
+ truncate(path: string, len?: number): Promise<void>;
90
+ realpath(path: string): Promise<string>;
91
+ /**
92
+ * Check if a path exists.
93
+ * Note: This is not in Node.js fs.promises but is commonly needed.
94
+ */
95
+ exists(path: string): Promise<boolean>;
96
+ /**
97
+ * Change file mode (no-op in OPFS - permissions not supported).
98
+ */
99
+ chmod(path: string, mode: number): Promise<void>;
100
+ /**
101
+ * Change file owner (no-op in OPFS - ownership not supported).
102
+ */
103
+ chown(path: string, uid: number, gid: number): Promise<void>;
104
+ /**
105
+ * Change file timestamps (no-op in OPFS - timestamps are read-only).
106
+ */
107
+ utimes(path: string, atime: Date | number, mtime: Date | number): Promise<void>;
108
+ /**
109
+ * Create a symbolic link.
110
+ * Emulated by storing target path in a special file format.
111
+ */
112
+ symlink(target: string, path: string, type?: string): Promise<void>;
113
+ /**
114
+ * Read a symbolic link target.
115
+ */
116
+ readlink(path: string): Promise<string>;
117
+ /**
118
+ * Create a hard link.
119
+ * Emulated by copying the file (true hard links not supported in OPFS).
120
+ */
121
+ link(existingPath: string, newPath: string): Promise<void>;
122
+ /**
123
+ * Open a file and return a FileHandle.
124
+ */
125
+ open(path: string, flags?: string | number, mode?: number): Promise<FileHandle>;
126
+ /**
127
+ * Open a directory for iteration.
128
+ */
129
+ opendir(path: string): Promise<Dir>;
130
+ /**
131
+ * Create a unique temporary directory.
132
+ */
133
+ mkdtemp(prefix: string): Promise<string>;
134
+ /**
135
+ * Watch a file or directory for changes.
136
+ */
137
+ watch(path: string, options?: WatchOptions): AsyncIterable<WatchEventType>;
138
+ /**
139
+ * Flush all pending writes to storage.
140
+ * Use after writes with { flush: false } to ensure data is persisted.
141
+ */
142
+ flush(): Promise<void>;
143
+ /**
144
+ * Purge all kernel caches.
145
+ * Use between major operations to ensure clean state.
146
+ */
147
+ purge(): Promise<void>;
151
148
  }
152
- /**
153
- * Read stream options
154
- */
149
+ type PathLike = string;
155
150
  interface ReadStreamOptions {
156
- /** Start reading from this byte position */
151
+ flags?: string;
152
+ encoding?: Encoding | null;
153
+ fd?: number | null;
154
+ mode?: number;
155
+ autoClose?: boolean;
156
+ emitClose?: boolean;
157
157
  start?: number;
158
- /** Stop reading at this byte position */
159
158
  end?: number;
160
- /** Chunk size for reading (default: 64KB) */
161
159
  highWaterMark?: number;
162
160
  }
163
- /**
164
- * Write stream options
165
- */
166
161
  interface WriteStreamOptions {
167
- /** File open flags (default: 'w') */
168
162
  flags?: string;
169
- /** Start writing at this byte position */
163
+ encoding?: Encoding;
164
+ fd?: number | null;
165
+ mode?: number;
166
+ autoClose?: boolean;
167
+ emitClose?: boolean;
170
168
  start?: number;
169
+ highWaterMark?: number;
170
+ flush?: boolean;
171
171
  }
172
- /**
173
- * Symlink definition for batch operations
174
- */
175
- interface SymlinkDefinition {
176
- target: string;
177
- path: string;
172
+ interface WatchOptions {
173
+ persistent?: boolean;
174
+ recursive?: boolean;
175
+ encoding?: Encoding;
176
+ signal?: AbortSignal;
178
177
  }
179
- /**
180
- * Result of read operation on FileHandle
181
- */
182
- interface ReadResult {
183
- bytesRead: number;
184
- buffer: Uint8Array;
178
+ interface WatchFileOptions {
179
+ persistent?: boolean;
180
+ interval?: number;
185
181
  }
186
- /**
187
- * Result of write operation on FileHandle
188
- */
189
- interface WriteResult {
190
- bytesWritten: number;
191
- buffer: Uint8Array;
182
+ interface WatchEventType {
183
+ eventType: 'rename' | 'change';
184
+ filename: string | null;
192
185
  }
193
- /**
194
- * FileHandle interface (returned by open())
195
- */
196
186
  interface FileHandle {
197
187
  fd: number;
198
- read(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): Promise<ReadResult>;
199
- write(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): Promise<WriteResult>;
200
- close(): Promise<void>;
201
- stat(): Promise<Stats>;
188
+ read(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): Promise<{
189
+ bytesRead: number;
190
+ buffer: Uint8Array;
191
+ }>;
192
+ write(buffer: Uint8Array, offset?: number, length?: number, position?: number | null): Promise<{
193
+ bytesWritten: number;
194
+ buffer: Uint8Array;
195
+ }>;
196
+ readFile(options?: ReadOptions | Encoding | null): Promise<Uint8Array | string>;
197
+ writeFile(data: Uint8Array | string, options?: WriteOptions | Encoding): Promise<void>;
202
198
  truncate(len?: number): Promise<void>;
199
+ stat(): Promise<Stats>;
203
200
  sync(): Promise<void>;
204
201
  datasync(): Promise<void>;
205
- readFile(options?: ReadFileOptions): Promise<string | Uint8Array>;
206
- writeFile(data: string | Uint8Array, options?: WriteFileOptions): Promise<void>;
207
- appendFile(data: string | Uint8Array, options?: WriteFileOptions): Promise<void>;
208
- [Symbol.asyncDispose](): Promise<void>;
202
+ close(): Promise<void>;
209
203
  }
210
- /**
211
- * Directory handle (returned by opendir())
212
- */
213
204
  interface Dir {
214
205
  path: string;
215
206
  read(): Promise<Dirent | null>;
216
207
  close(): Promise<void>;
217
208
  [Symbol.asyncIterator](): AsyncIterableIterator<Dirent>;
218
209
  }
219
- /**
220
- * Disk usage result
221
- */
222
- interface DiskUsage {
223
- path: string;
224
- size: number;
210
+ interface FSWatcher {
211
+ close(): void;
212
+ ref(): this;
213
+ unref(): this;
225
214
  }
226
- /**
227
- * Filesystem statistics (similar to Node.js fs.statfs)
228
- */
229
- interface StatFs {
230
- /** Filesystem type (always 0 for OPFS) */
231
- type: number;
232
- /** Optimal transfer block size (simulated as 4096) */
233
- bsize: number;
234
- /** Total blocks in filesystem */
235
- blocks: number;
236
- /** Free blocks in filesystem */
237
- bfree: number;
238
- /** Available blocks for unprivileged users */
239
- bavail: number;
240
- /** Total file nodes (0 - not available in browser) */
241
- files: number;
242
- /** Free file nodes (0 - not available in browser) */
243
- ffree: number;
244
- /** Bytes used by origin (from Storage API) */
245
- usage: number;
246
- /** Total bytes available to origin (from Storage API) */
247
- quota: number;
215
+ interface StatWatcher {
216
+ ref(): this;
217
+ unref(): this;
248
218
  }
249
- /**
250
- * Internal symlink cache structure
251
- */
252
- type SymlinkCache = Record<string, string>;
253
- /**
254
- * Watch callback function
255
- */
256
- type WatchCallback = (eventType: string, filename: string) => void;
257
- /**
258
- * Internal watch registration
259
- */
260
- interface WatchRegistration {
261
- path: string;
262
- callbacks: Set<WatchCallback>;
263
- recursive: boolean;
219
+ type WatchListener = (eventType: 'rename' | 'change', filename: string | null) => void;
220
+ type WatchFileListener = (curr: Stats, prev: Stats) => void;
221
+ interface FileSystemChangeRecord {
222
+ changedHandle: FileSystemHandle | null;
223
+ relativePathComponents: string[];
224
+ relativePathMovedFrom: string[] | null;
225
+ root: FileSystemHandle;
226
+ type: 'appeared' | 'disappeared' | 'modified' | 'moved' | 'errored' | 'unknown';
264
227
  }
265
-
266
- /**
267
- * File system constants matching Node.js fs.constants
268
- */
269
- declare const constants: FSConstants;
270
-
271
- type Backend = 'main' | 'worker';
272
- interface OPFSHybridOptions {
273
- /** Backend for read operations (default: 'main') */
274
- read?: Backend;
275
- /** Backend for write operations (default: 'worker') */
276
- write?: Backend;
277
- /** Worker URL (required if using worker backend) */
278
- workerUrl?: URL | string;
279
- /** Enable verbose logging */
280
- verbose?: boolean;
228
+ type FileSystemObserverCallback = (records: FileSystemChangeRecord[], observer: FileSystemObserverInterface) => void;
229
+ interface FileSystemObserverInterface {
230
+ observe(handle: FileSystemHandle, options?: {
231
+ recursive?: boolean;
232
+ }): Promise<void>;
233
+ disconnect(): void;
281
234
  }
282
- /**
283
- * Hybrid OPFS implementation that routes operations to optimal backends
284
- */
285
- declare class OPFSHybrid {
286
- private mainFs;
287
- private workerFs;
288
- private readBackend;
289
- private writeBackend;
290
- private workerUrl?;
291
- private workerReady;
292
- private verbose;
293
- constructor(options?: OPFSHybridOptions);
294
- /**
295
- * Wait for all backends to be ready
296
- */
297
- ready(): Promise<void>;
298
- /**
299
- * Terminate worker if active
300
- */
301
- terminate(): void;
302
- private getReadFs;
303
- private getWriteFs;
304
- readFile(path: string, options?: ReadFileOptions): Promise<Uint8Array | string>;
305
- readFileBatch(paths: string[]): Promise<BatchReadResult[]>;
306
- readdir(path: string, options?: ReaddirOptions): Promise<string[] | Dirent[]>;
307
- stat(path: string): Promise<Stats>;
308
- lstat(path: string): Promise<Stats>;
309
- exists(path: string): Promise<boolean>;
310
- access(path: string, mode?: number): Promise<void>;
311
- readlink(path: string): Promise<string>;
312
- realpath(path: string): Promise<string>;
313
- statfs(path?: string): Promise<StatFs>;
314
- du(path: string): Promise<DiskUsage>;
315
- writeFile(path: string, data: string | Uint8Array, options?: WriteFileOptions): Promise<void>;
316
- writeFileBatch(entries: BatchWriteEntry[]): Promise<void>;
317
- appendFile(path: string, data: string | Uint8Array, options?: WriteFileOptions): Promise<void>;
318
- mkdir(path: string): Promise<void>;
319
- rmdir(path: string): Promise<void>;
320
- unlink(path: string): Promise<void>;
321
- truncate(path: string, len?: number): Promise<void>;
322
- symlink(target: string, path: string): Promise<void>;
323
- symlinkBatch(symlinks: SymlinkDefinition[]): Promise<void>;
324
- rename(oldPath: string, newPath: string): Promise<void>;
325
- copyFile(src: string, dest: string, mode?: number): Promise<void>;
326
- cp(src: string, dest: string, options?: CpOptions): Promise<void>;
327
- rm(path: string, options?: RmOptions): Promise<void>;
328
- chmod(path: string, mode: number): Promise<void>;
329
- chown(path: string, uid: number, gid: number): Promise<void>;
330
- utimes(path: string, atime: Date | number, mtime: Date | number): Promise<void>;
331
- lutimes(path: string, atime: Date | number, mtime: Date | number): Promise<void>;
332
- mkdtemp(prefix: string): Promise<string>;
333
- /**
334
- * Reset internal caches on both backends
335
- */
336
- resetCache(): Promise<void>;
337
- /**
338
- * Force full garbage collection on both backends
339
- * More aggressive than resetCache() - reinitializes the worker's OPFS instance
340
- */
341
- gc(): Promise<void>;
235
+ declare global {
236
+ interface Window {
237
+ FileSystemObserver?: new (callback: FileSystemObserverCallback) => FileSystemObserverInterface;
238
+ }
239
+ var FileSystemObserver: (new (callback: FileSystemObserverCallback) => FileSystemObserverInterface) | undefined;
342
240
  }
343
241
 
344
- /** Extended options that include hybrid mode support */
345
- interface OPFSExtendedOptions extends OPFSOptions {
346
- /** Worker script URL - when provided, enables hybrid mode (reads on main, writes on worker) */
347
- workerUrl?: URL | string;
348
- /** Override read backend when using hybrid mode (default: 'main') */
349
- read?: Backend;
350
- /** Override write backend when using hybrid mode (default: 'worker') */
351
- write?: Backend;
352
- }
353
242
  /**
354
- * OPFS-based filesystem implementation compatible with Node.js fs/promises API
355
- *
356
- * When `workerUrl` is provided, automatically uses hybrid mode for optimal performance:
357
- * - Reads on main thread (no message passing overhead)
358
- * - Writes on worker (sync access handles are faster)
243
+ * OPFS FileSystem - Node.js fs-compatible API
244
+ * Supports two performance tiers:
245
+ * - Tier 1 (Sync): SharedArrayBuffer + Atomics - requires crossOriginIsolated (COOP/COEP headers)
246
+ * - Tier 2 (Async): Promises API using Worker kernel - always available
359
247
  */
360
- declare class OPFS {
361
- private useSync;
362
- private verbose;
363
- private handleManager;
364
- private symlinkManager;
365
- private packedStorage;
366
- private watchCallbacks;
367
- private tmpCounter;
368
- /** Hybrid instance when workerUrl is provided */
369
- private hybrid;
370
- /** File system constants */
371
- readonly constants: FSConstants;
372
- constructor(options?: OPFSExtendedOptions);
373
- /**
374
- * Wait for the filesystem to be ready (only needed for hybrid mode)
375
- */
376
- ready(): Promise<void>;
377
- /**
378
- * Terminate any background workers (only needed for hybrid mode)
379
- */
380
- terminate(): void;
381
- private log;
382
- private logError;
383
- /**
384
- * Execute tasks with limited concurrency to avoid overwhelming the system
385
- * @param items - Array of items to process
386
- * @param maxConcurrent - Maximum number of concurrent operations (default: 10)
387
- * @param taskFn - Function to execute for each item
388
- */
389
- private limitConcurrency;
390
- /**
391
- * Read file contents
392
- */
393
- readFile(path: string, options?: ReadFileOptions): Promise<string | Uint8Array>;
394
- /**
395
- * Read multiple files efficiently in a batch operation
396
- * Uses packed storage batch read (single index load), falls back to individual files
397
- * Returns results in the same order as input paths
398
- */
399
- readFileBatch(paths: string[]): Promise<BatchReadResult[]>;
400
- /**
401
- * Write data to a file
402
- */
403
- writeFile(path: string, data: string | Uint8Array, options?: WriteFileOptions): Promise<void>;
404
- /**
405
- * Write multiple files efficiently in a batch operation
406
- * Uses packed storage (single file) for maximum performance
407
- */
408
- writeFileBatch(entries: BatchWriteEntry[]): Promise<void>;
409
- /**
410
- * Create a directory
411
- */
412
- mkdir(path: string): Promise<void>;
413
- /**
414
- * Remove a directory
415
- */
416
- rmdir(path: string): Promise<void>;
417
- /**
418
- * Remove a file or symlink
419
- */
420
- unlink(path: string): Promise<void>;
421
- /**
422
- * Read directory contents
423
- */
424
- readdir(path: string, options?: ReaddirOptions): Promise<string[] | Dirent[]>;
425
- /**
426
- * Get file/directory statistics (follows symlinks)
427
- */
428
- stat(path: string): Promise<Stats>;
429
- /**
430
- * Get file/directory statistics (does not follow symlinks)
431
- */
432
- lstat(path: string): Promise<Stats>;
433
- /**
434
- * Rename a file or directory
435
- */
436
- rename(oldPath: string, newPath: string): Promise<void>;
437
- /**
438
- * Create a symbolic link
439
- */
440
- symlink(target: string, path: string): Promise<void>;
441
- /**
442
- * Read symlink target
443
- */
444
- readlink(path: string): Promise<string>;
445
- /**
446
- * Create multiple symlinks efficiently
447
- */
448
- symlinkBatch(links: SymlinkDefinition[]): Promise<void>;
449
- /**
450
- * Check file accessibility
451
- */
452
- access(path: string, mode?: number): Promise<void>;
453
- /**
454
- * Append data to a file
455
- */
456
- appendFile(path: string, data: string | Uint8Array, options?: WriteFileOptions): Promise<void>;
457
- /**
458
- * Copy a file
459
- */
460
- copyFile(src: string, dest: string, mode?: number): Promise<void>;
461
- /**
462
- * Copy files/directories recursively
463
- */
464
- cp(src: string, dest: string, options?: CpOptions): Promise<void>;
465
- /**
466
- * Check if path exists
467
- */
468
- exists(path: string): Promise<boolean>;
469
- /**
470
- * Resolve symlinks to get real path
471
- */
472
- realpath(path: string): Promise<string>;
473
- /**
474
- * Remove files and directories
475
- */
476
- rm(path: string, options?: RmOptions): Promise<void>;
477
- /**
478
- * Truncate file to specified length
479
- */
480
- truncate(path: string, len?: number): Promise<void>;
481
- /**
482
- * Create a unique temporary directory
483
- */
484
- mkdtemp(prefix: string): Promise<string>;
485
- /**
486
- * Change file mode (no-op for OPFS compatibility)
487
- */
488
- chmod(path: string, mode: number): Promise<void>;
489
- /**
490
- * Change file owner (no-op for OPFS compatibility)
491
- */
492
- chown(path: string, uid: number, gid: number): Promise<void>;
493
- /**
494
- * Update file timestamps (no-op for OPFS compatibility)
495
- */
496
- utimes(path: string, atime: Date | number, mtime: Date | number): Promise<void>;
497
- /**
498
- * Update symlink timestamps (no-op)
499
- */
500
- lutimes(path: string, atime: Date | number, mtime: Date | number): Promise<void>;
501
- /**
502
- * Open file and return FileHandle
503
- */
504
- open(path: string, flags?: string | number, mode?: number): Promise<FileHandle>;
505
- /**
506
- * Open directory for iteration
507
- */
508
- opendir(path: string): Promise<Dir>;
509
- /**
510
- * Watch for file changes
511
- */
512
- watch(path: string, options?: WatchOptions): FSWatcher;
513
- /**
514
- * Create read stream
515
- */
516
- createReadStream(path: string, options?: ReadStreamOptions): ReadableStream<Uint8Array>;
248
+
249
+ declare class OPFSFileSystem {
250
+ private worker;
251
+ private pending;
252
+ private initialized;
253
+ private initPromise;
254
+ private fdTable;
255
+ private nextFd;
256
+ private statCache;
257
+ constructor();
258
+ private invalidateStat;
259
+ private invalidateStatsUnder;
260
+ private initWorker;
261
+ private asyncCall;
262
+ private syncKernel;
263
+ private syncKernelReady;
264
+ /**
265
+ * Initialize sync operations with a kernel worker loaded from URL.
266
+ * Required for Tier 1 (SharedArrayBuffer + Atomics) to work in nested Workers.
267
+ * @param kernelUrl URL to the kernel.js file (defaults to '/kernel.js')
268
+ */
269
+ initSync(kernelUrl?: string): Promise<void>;
270
+ private static readonly META_SIZE;
271
+ private static readonly DEFAULT_DATA_SIZE;
272
+ private static readonly MAX_CHUNK_SIZE;
273
+ private syncBufferPool;
274
+ private getSyncBuffers;
275
+ private syncCallTier1;
276
+ private asyncOperationPromise;
277
+ private syncCallTier1Async;
278
+ private syncCallTier1AsyncImpl;
279
+ private syncStatTier1Async;
280
+ private syncCallTier1ChunkedAsync;
281
+ private syncCallTier1ChunkedReadAsync;
282
+ private syncCallTier1Chunked;
283
+ private syncCallTier1ChunkedRead;
284
+ private syncStatTier1;
285
+ private syncCall;
286
+ readFileSync(filePath: string, options?: ReadOptions | Encoding | null): Uint8Array | string;
287
+ writeFileSync(filePath: string, data: Uint8Array | string, options?: WriteOptions | Encoding): void;
288
+ appendFileSync(filePath: string, data: Uint8Array | string, options?: WriteOptions | Encoding): void;
289
+ existsSync(filePath: string): boolean;
290
+ mkdirSync(filePath: string, options?: MkdirOptions | number): string | undefined;
291
+ rmdirSync(filePath: string, options?: RmdirOptions): void;
292
+ rmSync(filePath: string, options?: RmOptions): void;
293
+ unlinkSync(filePath: string): void;
294
+ readdirSync(filePath: string, options?: ReaddirOptions | Encoding | null): string[] | Dirent[];
295
+ statSync(filePath: string): Stats;
296
+ lstatSync(filePath: string): Stats;
297
+ /**
298
+ * Create stats object for a symlink file.
299
+ */
300
+ private createSymlinkStats;
301
+ renameSync(oldPath: string, newPath: string): void;
302
+ copyFileSync(src: string, dest: string): void;
303
+ truncateSync(filePath: string, len?: number): void;
304
+ /**
305
+ * Flush all pending writes to storage.
306
+ * Use this after writes with { flush: false } to ensure data is persisted.
307
+ */
308
+ flushSync(): void;
309
+ /**
310
+ * Alias for flushSync() - matches Node.js fdatasync behavior
311
+ */
312
+ fdatasyncSync(): void;
313
+ /**
314
+ * Purge all kernel caches (sync handles, directory handles).
315
+ * Use between major operations to ensure clean state.
316
+ */
317
+ purgeSync(): void;
318
+ accessSync(filePath: string, _mode?: number): void;
319
+ openSync(filePath: string, flags?: string | number): number;
320
+ closeSync(fd: number): void;
321
+ readSync(fd: number, buffer: Uint8Array, offset: number, length: number, position: number | null): number;
322
+ writeSync(fd: number, buffer: Uint8Array, offset: number, length: number, position: number | null): number;
323
+ fstatSync(fd: number): Stats;
324
+ ftruncateSync(fd: number, len?: number): void;
325
+ /**
326
+ * Resolve a path to an absolute path.
327
+ * OPFS doesn't support symlinks, so this just normalizes the path.
328
+ */
329
+ realpathSync(filePath: string): string;
330
+ /**
331
+ * Change file mode (no-op in OPFS - permissions not supported).
332
+ */
333
+ chmodSync(_filePath: string, _mode: number): void;
334
+ /**
335
+ * Change file owner (no-op in OPFS - ownership not supported).
336
+ */
337
+ chownSync(_filePath: string, _uid: number, _gid: number): void;
338
+ /**
339
+ * Change file timestamps (no-op in OPFS - timestamps are read-only).
340
+ */
341
+ utimesSync(_filePath: string, _atime: Date | number, _mtime: Date | number): void;
342
+ private static readonly SYMLINK_MAGIC;
343
+ /**
344
+ * Create a symbolic link.
345
+ * Emulated by storing target path in a special file format.
346
+ */
347
+ symlinkSync(target: string, filePath: string, _type?: string): void;
348
+ /**
349
+ * Read a symbolic link target.
350
+ */
351
+ readlinkSync(filePath: string): string;
352
+ /**
353
+ * Check if a file is a symlink (sync).
354
+ */
355
+ private isSymlinkSync;
356
+ /**
357
+ * Check if a file is a symlink (async).
358
+ */
359
+ private isSymlinkAsync;
360
+ /**
361
+ * Create a hard link.
362
+ * Emulated by copying the file (true hard links not supported in OPFS).
363
+ */
364
+ linkSync(existingPath: string, newPath: string): void;
365
+ private parseFlags;
366
+ private fastCall;
367
+ promises: FileSystemPromises;
368
+ /**
369
+ * Async flush - use after promises.writeFile with { flush: false }
370
+ */
371
+ flush(): Promise<void>;
372
+ /**
373
+ * Async purge - clears all kernel caches
374
+ */
375
+ purge(): Promise<void>;
376
+ constants: {
377
+ readonly F_OK: 0;
378
+ readonly R_OK: 4;
379
+ readonly W_OK: 2;
380
+ readonly X_OK: 1;
381
+ readonly COPYFILE_EXCL: 1;
382
+ readonly COPYFILE_FICLONE: 2;
383
+ readonly COPYFILE_FICLONE_FORCE: 4;
384
+ readonly O_RDONLY: 0;
385
+ readonly O_WRONLY: 1;
386
+ readonly O_RDWR: 2;
387
+ readonly O_CREAT: 64;
388
+ readonly O_EXCL: 128;
389
+ readonly O_TRUNC: 512;
390
+ readonly O_APPEND: 1024;
391
+ readonly O_SYNC: 4096;
392
+ readonly S_IFMT: 61440;
393
+ readonly S_IFREG: 32768;
394
+ readonly S_IFDIR: 16384;
395
+ readonly S_IFCHR: 8192;
396
+ readonly S_IFBLK: 24576;
397
+ readonly S_IFIFO: 4096;
398
+ readonly S_IFLNK: 40960;
399
+ readonly S_IFSOCK: 49152;
400
+ readonly S_IRWXU: 448;
401
+ readonly S_IRUSR: 256;
402
+ readonly S_IWUSR: 128;
403
+ readonly S_IXUSR: 64;
404
+ readonly S_IRWXG: 56;
405
+ readonly S_IRGRP: 32;
406
+ readonly S_IWGRP: 16;
407
+ readonly S_IXGRP: 8;
408
+ readonly S_IRWXO: 7;
409
+ readonly S_IROTH: 4;
410
+ readonly S_IWOTH: 2;
411
+ readonly S_IXOTH: 1;
412
+ };
413
+ private createFileHandle;
414
+ private createDir;
415
+ private watchedFiles;
416
+ private static readonly hasNativeObserver;
417
+ private getDirectoryHandle;
418
+ private getFileHandle;
419
+ private mapChangeType;
420
+ private createAsyncWatcher;
421
+ private createNativeAsyncWatcher;
422
+ private createPollingAsyncWatcher;
517
423
  /**
518
- * Create write stream
424
+ * Watch a file or directory for changes.
425
+ * Uses native FileSystemObserver when available, falls back to polling.
519
426
  */
520
- createWriteStream(path: string, options?: WriteStreamOptions): WritableStream<Uint8Array>;
427
+ watch(filePath: string, options?: WatchOptions | WatchListener, listener?: WatchListener): FSWatcher;
428
+ private createNativeWatcher;
429
+ private createPollingWatcher;
521
430
  /**
522
- * Get file statistics (alias for stat)
431
+ * Watch a file for changes using native FileSystemObserver or stat polling.
523
432
  */
524
- backFile(path: string): Promise<Stats>;
433
+ watchFile(filePath: string, options?: WatchFileOptions | WatchFileListener, listener?: WatchFileListener): StatWatcher;
525
434
  /**
526
- * Get disk usage for a path
435
+ * Stop watching a file.
527
436
  */
528
- du(path: string): Promise<DiskUsage>;
437
+ unwatchFile(filePath: string, listener?: WatchFileListener): void;
529
438
  /**
530
- * Get filesystem statistics (similar to Node.js fs.statfs)
531
- * Uses the Storage API to get quota and usage information
532
- * Note: Values are estimates for the entire origin, not per-path
439
+ * Create a readable stream for a file.
533
440
  */
534
- statfs(path?: string): Promise<StatFs>;
441
+ createReadStream(filePath: string, options?: ReadStreamOptions | string): ReadableStream<Uint8Array>;
535
442
  /**
536
- * Reset internal caches
537
- * Useful when external processes modify the filesystem
443
+ * Create a writable stream for a file.
538
444
  */
539
- resetCache(): void;
445
+ createWriteStream(filePath: string, options?: WriteStreamOptions | string): WritableStream<Uint8Array>;
540
446
  /**
541
- * Force full garbage collection
542
- * Releases all handles and caches, reinitializes the worker in hybrid mode
543
- * Use this for long-running operations to prevent memory leaks
447
+ * Open a directory for iteration (sync).
544
448
  */
545
- gc(): Promise<void>;
449
+ opendirSync(dirPath: string): Dir;
450
+ /**
451
+ * Create a unique temporary directory (sync).
452
+ */
453
+ mkdtempSync(prefix: string): string;
546
454
  }
547
455
 
548
- export { type Backend, type BatchReadResult, type BatchWriteEntry, type CpOptions, type Dir, type Dirent, type DiskUsage, type FSConstants, type FSWatcher, type FileHandle, type OPFSExtendedOptions, OPFSHybrid, type OPFSHybridOptions, type OPFSOptions, type ReadFileOptions, type ReadResult, type ReadStreamOptions, type ReaddirOptions, type RmOptions, type StatFs, type Stats, type SymlinkCache, type SymlinkDefinition, type WatchCallback, type WatchEvent, type WatchOptions, type WatchRegistration, type WriteFileOptions, type WriteResult, type WriteStreamOptions, constants, OPFS as default };
456
+ /**
457
+ * File system constants matching Node.js fs.constants
458
+ */
459
+ declare const constants: {
460
+ readonly F_OK: 0;
461
+ readonly R_OK: 4;
462
+ readonly W_OK: 2;
463
+ readonly X_OK: 1;
464
+ readonly COPYFILE_EXCL: 1;
465
+ readonly COPYFILE_FICLONE: 2;
466
+ readonly COPYFILE_FICLONE_FORCE: 4;
467
+ readonly O_RDONLY: 0;
468
+ readonly O_WRONLY: 1;
469
+ readonly O_RDWR: 2;
470
+ readonly O_CREAT: 64;
471
+ readonly O_EXCL: 128;
472
+ readonly O_TRUNC: 512;
473
+ readonly O_APPEND: 1024;
474
+ readonly O_SYNC: 4096;
475
+ readonly S_IFMT: 61440;
476
+ readonly S_IFREG: 32768;
477
+ readonly S_IFDIR: 16384;
478
+ readonly S_IFCHR: 8192;
479
+ readonly S_IFBLK: 24576;
480
+ readonly S_IFIFO: 4096;
481
+ readonly S_IFLNK: 40960;
482
+ readonly S_IFSOCK: 49152;
483
+ readonly S_IRWXU: 448;
484
+ readonly S_IRUSR: 256;
485
+ readonly S_IWUSR: 128;
486
+ readonly S_IXUSR: 64;
487
+ readonly S_IRWXG: 56;
488
+ readonly S_IRGRP: 32;
489
+ readonly S_IWGRP: 16;
490
+ readonly S_IXGRP: 8;
491
+ readonly S_IRWXO: 7;
492
+ readonly S_IROTH: 4;
493
+ readonly S_IWOTH: 2;
494
+ readonly S_IXOTH: 1;
495
+ };
496
+
497
+ /**
498
+ * Node.js compatible filesystem error classes
499
+ */
500
+ declare class FSError extends Error {
501
+ code: string;
502
+ errno: number;
503
+ syscall?: string;
504
+ path?: string;
505
+ constructor(code: string, errno: number, message: string, syscall?: string, path?: string);
506
+ }
507
+ declare function createENOENT(syscall: string, path: string): FSError;
508
+ declare function createEEXIST(syscall: string, path: string): FSError;
509
+ declare function createEISDIR(syscall: string, path: string): FSError;
510
+ declare function createENOTDIR(syscall: string, path: string): FSError;
511
+ declare function createENOTEMPTY(syscall: string, path: string): FSError;
512
+ declare function createEACCES(syscall: string, path: string): FSError;
513
+ declare function createEINVAL(syscall: string, path: string): FSError;
514
+ declare function mapErrorCode(errorName: string, syscall: string, path: string): FSError;
515
+
516
+ /**
517
+ * POSIX-style path utilities for OPFS
518
+ * Mirrors Node.js path module behavior
519
+ */
520
+ declare const sep = "/";
521
+ declare const delimiter = ":";
522
+ declare function normalize(p: string): string;
523
+ declare function join(...paths: string[]): string;
524
+ declare function resolve(...paths: string[]): string;
525
+ declare function isAbsolute(p: string): boolean;
526
+ declare function dirname(p: string): string;
527
+ declare function basename(p: string, ext?: string): string;
528
+ declare function extname(p: string): string;
529
+ declare function relative(from: string, to: string): string;
530
+ declare function parse(p: string): {
531
+ root: string;
532
+ dir: string;
533
+ base: string;
534
+ ext: string;
535
+ name: string;
536
+ };
537
+ declare function format(pathObject: {
538
+ root?: string;
539
+ dir?: string;
540
+ base?: string;
541
+ ext?: string;
542
+ name?: string;
543
+ }): string;
544
+ declare const posix: {
545
+ sep: string;
546
+ delimiter: string;
547
+ normalize: typeof normalize;
548
+ join: typeof join;
549
+ resolve: typeof resolve;
550
+ isAbsolute: typeof isAbsolute;
551
+ dirname: typeof dirname;
552
+ basename: typeof basename;
553
+ extname: typeof extname;
554
+ relative: typeof relative;
555
+ parse: typeof parse;
556
+ format: typeof format;
557
+ };
558
+
559
+ declare const path_basename: typeof basename;
560
+ declare const path_delimiter: typeof delimiter;
561
+ declare const path_dirname: typeof dirname;
562
+ declare const path_extname: typeof extname;
563
+ declare const path_format: typeof format;
564
+ declare const path_isAbsolute: typeof isAbsolute;
565
+ declare const path_join: typeof join;
566
+ declare const path_normalize: typeof normalize;
567
+ declare const path_parse: typeof parse;
568
+ declare const path_posix: typeof posix;
569
+ declare const path_relative: typeof relative;
570
+ declare const path_resolve: typeof resolve;
571
+ declare const path_sep: typeof sep;
572
+ declare namespace path {
573
+ export { path_basename as basename, posix as default, path_delimiter as delimiter, path_dirname as dirname, path_extname as extname, path_format as format, path_isAbsolute as isAbsolute, path_join as join, path_normalize as normalize, path_parse as parse, path_posix as posix, path_relative as relative, path_resolve as resolve, path_sep as sep };
574
+ }
575
+
576
+ /**
577
+ * OPFS-FS: Battle-tested OPFS-based Node.js fs polyfill
578
+ *
579
+ * Provides a Node.js-compatible filesystem API that works in browsers using OPFS.
580
+ *
581
+ * Features:
582
+ * - Synchronous API: fs.readFileSync, fs.writeFileSync, etc. (requires crossOriginIsolated)
583
+ * - Async Promises API: fs.promises.readFile, fs.promises.writeFile, etc.
584
+ * - Cross-tab safety via navigator.locks
585
+ *
586
+ * Performance Tiers:
587
+ * - Tier 1 (Sync): SharedArrayBuffer + Atomics - requires crossOriginIsolated (COOP/COEP headers)
588
+ * - Tier 2 (Async): Promises API - always available
589
+ *
590
+ * @example
591
+ * ```typescript
592
+ * import { fs } from '@componentor/fs';
593
+ *
594
+ * // Sync API (requires crossOriginIsolated)
595
+ * fs.writeFileSync('/hello.txt', 'Hello World!');
596
+ * const data = fs.readFileSync('/hello.txt', 'utf8');
597
+ *
598
+ * // Async API (always available)
599
+ * await fs.promises.writeFile('/async.txt', 'Async data');
600
+ * const content = await fs.promises.readFile('/async.txt', 'utf8');
601
+ * ```
602
+ */
603
+
604
+ declare const fs: OPFSFileSystem;
605
+
606
+ export { type Dirent, type Encoding, FSError, type FileSystemPromises, type MkdirOptions, OPFSFileSystem, type PathLike, type ReadOptions, type ReaddirOptions, type RmOptions, type RmdirOptions, type Stats, type WriteOptions, constants, createEACCES, createEEXIST, createEINVAL, createEISDIR, createENOENT, createENOTDIR, createENOTEMPTY, fs as default, fs, mapErrorCode, path };