@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 +74 -16
- package/dist/index.js +1773 -29
- package/dist/index.js.map +1 -1
- package/dist/workers/server.worker.js +88 -13
- package/dist/workers/server.worker.js.map +1 -1
- package/dist/workers/sync-relay.worker.js +167 -33
- package/dist/workers/sync-relay.worker.js.map +1 -1
- package/package.json +1 -1
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
|
|
316
|
-
|
|
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
|
|
417
|
-
│ │ │ (.vfs.bin OPFS)
|
|
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 (
|
|
590
|
+
npm test # Run unit tests (97 tests)
|
|
533
591
|
npm run benchmark:open # Run benchmarks in browser
|
|
534
592
|
```
|
|
535
593
|
|