From 4cff0c621d6b0764db50d5bc8f4d83c2767ec537 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Fri, 27 Feb 2026 09:17:51 +0100 Subject: [PATCH] feat: implement request deduplication and caching in API client for improved performance --- lib/api/client.ts | 59 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/api/client.ts b/lib/api/client.ts index 10643e1..506a5d5 100644 --- a/lib/api/client.ts +++ b/lib/api/client.ts @@ -58,6 +58,57 @@ function onRefreshFailed(err: unknown) { refreshSubscribers = [] } +// * ============================================================================ +// * Request Deduplication & Caching +// * ============================================================================ + +/** Cache TTL in milliseconds (2 seconds) */ +const CACHE_TTL_MS = 2_000 + +/** Stores in-flight requests for deduplication */ +interface PendingRequest { + promise: Promise + timestamp: number +} +const pendingRequests = new Map() + +/** Stores cached responses */ +interface CachedResponse { + data: unknown + timestamp: number +} +const responseCache = new Map() + +/** + * Generate a unique key for a request based on endpoint and options + */ +function getRequestKey(endpoint: string, options: RequestInit): string { + const method = options.method || 'GET' + const body = options.body || '' + return `${method}:${endpoint}:${body}` +} + +/** + * Clean up expired entries from pending requests and response cache + */ +function cleanupExpiredEntries(): void { + const now = Date.now() + + // * Clean up stale pending requests (older than 30 seconds) + for (const [key, pending] of pendingRequests.entries()) { + if (now - pending.timestamp > 30_000) { + pendingRequests.delete(key) + } + } + + // * Clean up stale cached responses (older than CACHE_TTL_MS) + for (const [key, cached] of responseCache.entries()) { + if (now - cached.timestamp > CACHE_TTL_MS) { + responseCache.delete(key) + } + } +} + /** * Base API client with error handling, request deduplication, and short-term caching */ @@ -78,15 +129,15 @@ async function apiRequest( const requestKey = getRequestKey(endpoint, options) // * Check if we have a recent cached response (within 2 seconds) - const cached = responseCache.get(requestKey) as CachedResponse | undefined + const cached = responseCache.get(requestKey) if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) { - return cached.data + return cached.data as T } // * Check if there's an identical request in flight - const pending = pendingRequests.get(requestKey) as PendingRequest | undefined + const pending = pendingRequests.get(requestKey) if (pending && Date.now() - pending.timestamp < 30000) { - return pending.promise + return pending.promise as Promise } }