- PeerFiles.vue reads the SAME `cloud.peer-browse:<onion>` entry Cloud.vue's
per-peer fan-in fills, so Cloud → peer files paints instantly from cache
and revalidates behind it; catalog/error/loading/transport are now
computed views over the store entry.
- preview-peer fan-out is capped at 3 concurrent with a queue (was one 30s
RPC per media item, all at once, unbounded) and aborts on unmount.
- browse + preview RPCs drop to maxRetries:1 — retry×3 turned one slow
peer into a 90s spinner.
- fix useCachedResource's interface types: `ReturnType<typeof computed<T>>`
resolves to the writable overload (WritableComputedRef), which broke
vue-tsc against the plain computed() returns; use ComputedRef<T>.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part B1+B2 of docs/FIPS-UPTIME-AND-UI-STATE-PLAN.md. Foundation for pages
that render instantly from cache on revisit and revalidate in the
background, instead of unmount-refetch-spinner on every navigation.
- stores/resources.ts: keyed {data, loadState, fetchedAt, error} entries
with sticky-ready (never regress ready→loading), keep-last-value on
error, per-key in-flight dedup, sessionStorage snapshot hydrate,
debounced invalidate() fan-out, optimistic-update-with-rollback
- composables/useCachedResource.ts: SWR hook over the store — synchronous
hydrate, TTL-gated background revalidate, revalidate-on-focus,
abort-on-unmount fetcher signal
- rpc-client: AbortSignal support (aborts pending retries too), opt-in
in-flight dedup keyed method+params, per-call maxRetries override
- 10 tests covering the SWR semantics
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>