@componentor/fs 3.0.2 → 3.0.4

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/README.md CHANGED
@@ -311,17 +311,23 @@ await writer.close();
311
311
  ### Watch API
312
312
 
313
313
  ```typescript
314
- // Watch for changes
315
- const watcher = fs.watch('/dir', { recursive: true }, (eventType, filename) => {
316
- console.log(eventType, filename); // 'change' 'file.txt'
314
+ // Watch for changes (supports recursive + AbortSignal)
315
+ const ac = new AbortController();
316
+ const watcher = fs.watch('/dir', { recursive: true, signal: ac.signal }, (eventType, filename) => {
317
+ console.log(eventType, filename); // 'rename' 'newfile.txt' or 'change' 'file.txt'
317
318
  });
318
- watcher.close();
319
+ watcher.close(); // or ac.abort()
319
320
 
320
- // Watch specific file with polling
321
+ // Watch specific file with stat polling
321
322
  fs.watchFile('/file.txt', { interval: 1000 }, (curr, prev) => {
322
323
  console.log('File changed:', curr.mtimeMs !== prev.mtimeMs);
323
324
  });
324
325
  fs.unwatchFile('/file.txt');
326
+
327
+ // Async iterable (promises API)
328
+ for await (const event of fs.promises.watch('/dir', { recursive: true })) {
329
+ console.log(event.eventType, event.filename);
330
+ }
325
331
  ```
326
332
 
327
333
  ### Path Utilities
@@ -362,6 +368,33 @@ constants.O_TRUNC // 512
362
368
  constants.O_APPEND // 1024
363
369
  ```
364
370
 
371
+ ## Maintenance Helpers
372
+
373
+ Standalone utilities for VFS maintenance, recovery, and migration. Must be called from a Worker context (sync access handle requirement). Close any running `VFSFileSystem` instance first.
374
+
375
+ ```typescript
376
+ import { unpackToOPFS, loadFromOPFS, repairVFS } from '@componentor/fs';
377
+
378
+ // Export VFS contents to real OPFS files (clears existing OPFS files first)
379
+ const { files, directories } = await unpackToOPFS('/my-app');
380
+
381
+ // Rebuild VFS from real OPFS files (deletes .vfs.bin, creates fresh VFS)
382
+ const { files, directories } = await loadFromOPFS('/my-app');
383
+
384
+ // Attempt to recover files from a corrupt VFS binary
385
+ const { recovered, lost, entries } = await repairVFS('/my-app');
386
+ console.log(`Recovered ${recovered} entries, lost ${lost}`);
387
+ for (const entry of entries) {
388
+ console.log(` ${entry.type} ${entry.path} (${entry.size} bytes)`);
389
+ }
390
+ ```
391
+
392
+ | Function | Description |
393
+ |----------|-------------|
394
+ | `unpackToOPFS(root?)` | Read all files from VFS, write to real OPFS paths |
395
+ | `loadFromOPFS(root?)` | Read all OPFS files, create fresh VFS with their contents |
396
+ | `repairVFS(root?)` | Scan corrupt `.vfs.bin` for recoverable inodes, rebuild fresh VFS |
397
+
365
398
  ## isomorphic-git Integration
366
399
 
367
400
  ```typescript
@@ -412,23 +445,23 @@ await git.commit({
412
445
  │ sync-relay Worker (Leader) │
413
446
  │ ┌────────────────────────────────────────────────────────────┐ │
414
447
  │ │ VFS Engine │ │
415
- │ │ ┌──────────────────┐ ┌─────────────┐ ┌──────────────┐ │ │
416
- │ │ │ VFS Binary File │ │ Inode/Path │ │ Block Data │ │ │
417
- │ │ │ (.vfs.bin OPFS) │ │ Table │ │ Region │ │ │
418
- │ │ └──────────────────┘ └─────────────┘ └──────────────┘ │ │
448
+ │ │ ┌──────────────────┐ ┌─────────────┐ ┌──────────────┐ │ │
449
+ │ │ │ VFS Binary File │ │ Inode/Path │ │ Block Data │ │ │
450
+ │ │ │ (.vfs.bin OPFS) │ │ Table │ │ Region │ │ │
451
+ │ │ └──────────────────┘ └─────────────┘ └──────────────┘ │ │
419
452
  │ └────────────────────────────────────────────────────────────┘ │
420
453
  │ │ │
421
- │ notifyOPFSSync()
422
- │ (fire & forget)
454
+ │ notifyOPFSSync()
455
+ │ (fire & forget)
423
456
  └────────────────────────────┼─────────────────────────────────────┘
424
457
 
425
458
 
426
459
  ┌──────────────────────────────────────────────────────────────────┐
427
- │ opfs-sync Worker
460
+ │ opfs-sync Worker
428
461
  │ ┌────────────────────┐ ┌────────────────────────────────────┐ │
429
- │ │ VFS → OPFS Mirror │ │ FileSystemObserver (OPFS → VFS) │ │
430
- │ │ (queue + echo │ │ External changes detected and │ │
431
- │ │ suppression) │ │ synced back to VFS engine │ │
462
+ │ │ VFS → OPFS Mirror │ │ FileSystemObserver (OPFS → VFS) │ │
463
+ │ │ (queue + echo │ │ External changes detected and │ │
464
+ │ │ suppression) │ │ synced back to VFS engine │ │
432
465
  │ └────────────────────┘ └────────────────────────────────────┘ │
433
466
  └──────────────────────────────────────────────────────────────────┘
434
467
 
@@ -475,6 +508,31 @@ Make sure `opfsSync` is enabled (it's `true` by default). Files are mirrored to
475
508
 
476
509
  ## Changelog
477
510
 
511
+ ### v3.0.4 (2026)
512
+
513
+ **Features:**
514
+ - Add `unpackToOPFS(root?)` — export all VFS contents to real OPFS files
515
+ - Add `loadFromOPFS(root?)` — rebuild VFS from real OPFS files (deletes and recreates `.vfs.bin`)
516
+ - Add `repairVFS(root?)` — scan corrupt VFS binary for recoverable inodes and rebuild a clean VFS
517
+ - Add `VFSEngine.exportAll()` for extracting all files/dirs/symlinks with their data
518
+
519
+ **Bug Fixes:**
520
+ - VFS corruption detection on init — validates magic, version, block size, inode count, section offsets, file size, and root directory existence
521
+ - Release sync access handle on init failure (previously leaked, blocking re-acquisition)
522
+
523
+ ### v3.0.3 (2026)
524
+
525
+ **Features:**
526
+ - Implement `fs.watch()`, `fs.watchFile()`, `fs.unwatchFile()`, and `promises.watch()` as Node.js-compatible polyfills
527
+ - Watch events propagate across all tabs via `BroadcastChannel`
528
+ - `fs.watch()` supports `recursive` option and `AbortSignal` for cleanup
529
+ - `fs.watchFile()` supports stat-based polling with configurable `interval` (default 5007ms per Node.js)
530
+ - `promises.watch()` returns an async iterable of watch events
531
+
532
+ **Internal:**
533
+ - Leader broadcasts `{ eventType, path }` on every successful VFS mutation (no new opcodes or protocol changes)
534
+ - Mutation tracking now runs unconditionally (previously gated on `opfsSync`)
535
+
478
536
  ### v3.0.2 (2026)
479
537
 
480
538
  **Bug Fixes:**
@@ -529,7 +587,7 @@ git clone https://github.com/componentor/fs
529
587
  cd fs
530
588
  npm install
531
589
  npm run build # Build the library
532
- npm test # Run unit tests (77 tests)
590
+ npm test # Run unit tests (97 tests)
533
591
  npm run benchmark:open # Run benchmarks in browser
534
592
  ```
535
593