@componentor/fs 3.0.51 → 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/dist/index.d.mts +23 -0
- package/dist/index.js +86 -11
- package/dist/index.js.map +1 -1
- package/dist/workers/async-relay.worker.js +5 -2
- package/dist/workers/async-relay.worker.js.map +1 -1
- package/dist/workers/server.worker.js.map +1 -1
- package/dist/workers/sync-relay.worker.js +17 -2
- package/dist/workers/sync-relay.worker.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +38 -0
package/package.json
CHANGED
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,19 @@ 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
|
+
|
|
638
|
+
### v3.0.52 (2026)
|
|
639
|
+
|
|
640
|
+
**Fixes:**
|
|
641
|
+
- Sync FS calls on the browser main thread (which can't use `Atomics.wait` and so spin on `Atomics.load`) no longer abort a legitimately slow operation. The old fixed timeout (10 s, briefly 60 s) killed in-flight `rename`/`copy` over large trees — e.g. `create-strapi-app`'s git init over a fresh `node_modules` — while a genuinely dead worker still blocked for the whole timeout. The relay worker now pulses a heartbeat counter in the control SAB every 1 s (it keeps ticking even while parked on an `await` inside a long op), and the spin-wait aborts only if that heartbeat stalls for 20 s — no upper bound on a progressing op
|
|
642
|
+
- Fix corruption/hang on large sync writes. A `writeFileSync`/`writeSync`/`appendFileSync` of more than ~2 MB (the default SAB data window) is chunked over the SAB; the response-wait afterward waited on the wrong control-word sentinel (`REQUEST` instead of the last chunk's `CHUNK`), so it fell through immediately and read stale request bytes as the response, then wedged. Now waits on the frame it actually wrote last, matching the async path
|
|
643
|
+
- Add a Playwright regression test round-tripping ≈2 MB / ≈5 MB payloads through the sync and promises write APIs with byte-for-byte verification; `playwright-report/` and `test-results/` are now gitignored
|
|
644
|
+
|
|
607
645
|
### v3.0.51 (2026)
|
|
608
646
|
|
|
609
647
|
**Fixes:**
|