stateDiagram-v2 [*] --> empty: Initial state empty --> loading: First request starts loading --> cached: Server responds successfully
& cache predicate passes
& headers allow caching loading --> empty: Server responds but
cache predicate fails OR
headers say dont cache OR
request cancelled loading --> loading: Concurrent request waits cached --> empty: Cache deleted manually
OR storage.remove() called cached --> stale: TTL expires
(createdAt + ttl < now) cached --> must_revalidate: Cache-Control: must-revalidate
& TTL expires stale --> loading: Request with stale data
Adds If-None-Match/If-Modified-Since headers stale --> cached: Request succeeds with new data stale --> stale: staleIfError triggers
on request error stale --> empty: Cache deleted must_revalidate --> loading: Revalidation request starts
Adds If-None-Match/If-Modified-Since headers must_revalidate --> cached: Revalidation succeeds
(200 or 304 response) must_revalidate --> empty: Revalidation fails
& no staleIfError must_revalidate --> stale: Revalidation fails
& staleIfError allows loading --> stale: Previous state was stale
& staleTtl is still valid note right of empty No cached data No TTL No createdAt end note note right of cached Has data Has TTL Has createdAt Response returned from cache No HTTP request made end note note right of stale Has data (old) TTL expired Has createdAt (old) Can be used with staleIfError Request made with conditional headers end note note right of must_revalidate Has data Must revalidate with server Cannot use without revalidation Requires fresh validation end note note right of loading Request in progress May have previous data Has deferred promise Other requests wait for this Can have previous: 'empty', 'stale', or 'must-revalidate' end note