@componentor/fs 3.0.52 → 3.0.53

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@componentor/fs",
3
- "version": "3.0.52",
3
+ "version": "3.0.53",
4
4
  "description": "High-performance OPFS-based Node.js fs polyfill with true sync API, VFS binary format, and bidirectional OPFS mirroring",
5
5
  "license": "MIT",
6
6
  "author": "Componentor",
package/readme.md CHANGED
@@ -400,6 +400,31 @@ await fs.setMode('hybrid' | 'vfs' | 'opfs'): Promise<void>
400
400
 
401
401
  // Non-blocking async init (waits for VFS to be ready)
402
402
  await fs.init(): Promise<void>
403
+
404
+ // Moment-in-time readiness: true only when ready AND no leader transition is
405
+ // in flight (equivalent to isReady && !transitioning)
406
+ fs.ready: boolean
407
+
408
+ // Await readiness reliably, INCLUDING through an in-flight leader promotion.
409
+ // Resolves immediately if already ready; otherwise resolves on the next time
410
+ // the sync-relay signals 'ready'. Use this to coordinate with another
411
+ // navigator.locks-based leader election running independently of the FS:
412
+ await fs.whenReady(): Promise<void>
413
+ ```
414
+
415
+ The `fs.ready` / `fs.whenReady()` pair exists because the FS elects its own
416
+ multi-tab leader via `navigator.locks`. When the leader tab dies and this tab is
417
+ promoted, there's a window where the new sync-relay worker isn't looping yet —
418
+ issuing a sync op then stalls until the worker's heartbeat watchdog fires. If
419
+ your app also does its own leader election, await `fs.whenReady()` *after*
420
+ acquiring your own lock to be sure the FS has finished any promotion first:
421
+
422
+ ```typescript
423
+ navigator.locks.request('my-app-leader', async () => {
424
+ await fs.whenReady(); // FS promotion (if any) has completed
425
+ fs.writeFileSync('/state.json', data); // safe — won't stall the relay worker
426
+ await new Promise(() => {}); // hold the lock
427
+ });
403
428
  ```
404
429
 
405
430
  ### Watch API
@@ -604,6 +629,12 @@ Make sure `opfsSync` is enabled (it's `true` by default). Files are mirrored to
604
629
 
605
630
  See [CHANGELOG.md](./CHANGELOG.md) for the full version history.
606
631
 
632
+ ### v3.0.53 (2026)
633
+
634
+ **Features:**
635
+ - Leader-transition readiness tracking. New `fs.whenReady()` resolves once the filesystem is fully ready *including* any in-flight promotion-to-leader, and a new `fs.ready` getter reports the moment-in-time state. Lets an embedding app that runs its own `navigator.locks` leader election coordinate with the FS's independent election — without it, the app can win its lock and issue sync calls while the FS is still mid-promotion, stalling against the 20 s heartbeat watchdog
636
+ - During `promoteToLeader` the existing `readyPromise` is stale (resolved by the prior lifecycle), so awaiting it would return immediately even though the new sync-relay hasn't signalled `ready`. A `transitioning` flag now guards this: while set, `whenReady()` waits for the *next* `ready` rather than the stale promise. All three `ready` handlers (bootstrap, `promoteToLeader`, `setMode`) clear the flag and flush waiting callers consistently
637
+
607
638
  ### v3.0.52 (2026)
608
639
 
609
640
  **Fixes:**