diff --git a/.github/pr-assets/data-page-cache-global-stats.webp b/.github/pr-assets/data-page-cache-global-stats.webp new file mode 100644 index 000000000..7fa92b20f Binary files /dev/null and b/.github/pr-assets/data-page-cache-global-stats.webp differ diff --git a/apps/web/src/pages/data.astro b/apps/web/src/pages/data.astro index 6e2fae647..aca9908bd 100644 --- a/apps/web/src/pages/data.astro +++ b/apps/web/src/pages/data.astro @@ -304,19 +304,57 @@ const content = { } } - async function loadMetrics() { + const METRICS_CACHE_KEY = 'capgo-live-update-metrics-v1' + const METRICS_CACHE_TTL_MS = 5 * 60 * 1000 + + function readCachedMetrics(): Metrics | null { + try { + const raw = sessionStorage.getItem(METRICS_CACHE_KEY) + if (!raw) return null + const parsed = JSON.parse(raw) as { savedAt?: unknown; payload?: unknown } + if (typeof parsed.savedAt !== 'number' || Date.now() - parsed.savedAt > METRICS_CACHE_TTL_MS) return null + return normalizeMetrics(parsed.payload) + } catch { + return null + } + } + + function writeCachedMetrics(payload: unknown) { + try { + sessionStorage.setItem(METRICS_CACHE_KEY, JSON.stringify({ savedAt: Date.now(), payload })) + } catch { + // Ignore quota / private-mode failures. + } + } + + async function fetchMetrics() { + if (!endpoint) throw new Error('Missing metrics endpoint') const controller = new AbortController() const timeoutId = window.setTimeout(() => controller.abort(), 10_000) try { - if (!endpoint) throw new Error('Missing metrics endpoint') const response = await fetch(endpoint, { headers: { Accept: 'application/json' }, signal: controller.signal }) - const metrics = response.ok ? normalizeMetrics(await response.json()) : null + const payload = response.ok ? await response.json() : null + const metrics = normalizeMetrics(payload) if (!metrics) throw new Error('Invalid metrics response') + writeCachedMetrics(payload) + return metrics + } finally { + window.clearTimeout(timeoutId) + } + } + + async function loadMetrics() { + const cached = readCachedMetrics() + if (cached) { + renderMetrics(cached) + page?.setAttribute('aria-busy', 'false') + } + try { + const metrics = await fetchMetrics() renderMetrics(metrics) } catch { - renderUnavailable() + if (!cached) renderUnavailable() } finally { - window.clearTimeout(timeoutId) page?.setAttribute('aria-busy', 'false') } }