From 2630f54782858ed8c9a3d86a8c7a9c8db2bc8c08 Mon Sep 17 00:00:00 2001 From: Pablo Date: Tue, 1 Sep 2026 15:44:11 -0500 Subject: [PATCH] feat(frontend): add client-side result caching (5min TTL) - Caches analysis results by repo URL + branch - 5 minute TTL prevents duplicate API calls - Cache key is case-insensitive and trimmed - Improves UX when re-analyzing the same repo --- frontend/src/api.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 97a82d8..ba5320b 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -2,6 +2,9 @@ const API_URL = import.meta.env.VITE_API_URL || ""; +const CACHE_TTL_MS = 5 * 60 * 1000; +const cache = new Map(); + export interface Violation { rule: string; kind: string; @@ -34,7 +37,29 @@ export interface AnalysisResult { metrics: Metrics; } +function cacheKey(repoUrl: string, branch: string): string { + return `${repoUrl.trim().toLowerCase()}@${branch.trim()}` +} + +function getCached(repoUrl: string, branch: string): AnalysisResult | null { + const key = cacheKey(repoUrl, branch) + const entry = cache.get(key) + if (entry && Date.now() - entry.timestamp < CACHE_TTL_MS) { + return entry.data + } + cache.delete(key) + return null +} + +function setCache(repoUrl: string, branch: string, data: AnalysisResult): void { + const key = cacheKey(repoUrl, branch) + cache.set(key, { data, timestamp: Date.now() }) +} + export async function analyze(repoUrl: string, branch: string): Promise { + const cached = getCached(repoUrl, branch) + if (cached) return cached + const resp = await fetch(`${API_URL}/api/analyze`, { method: "POST", headers: { "Content-Type": "application/json" }, @@ -44,5 +69,7 @@ export async function analyze(repoUrl: string, branch: string): Promise ({ detail: resp.statusText })); throw new Error(error.detail || `HTTP ${resp.status}`); } - return resp.json(); + const data: AnalysisResult = await resp.json() + setCache(repoUrl, branch, data) + return data }