diff --git a/src/lib/providers/cache.ts b/src/lib/providers/cache.ts new file mode 100644 index 00000000..2d373a66 --- /dev/null +++ b/src/lib/providers/cache.ts @@ -0,0 +1,116 @@ +/** + * Model Caching Utility + * + * Simple in-memory cache for model lists from providers. + * Reduces API calls to external providers by caching results with TTL. + * + * Features: + * - 10-minute default TTL + * - Per-provider cache keys + * - Optional search query in cache key + * - Manual invalidation support + * + * Note: Cache is cleared on server restart (no persistence). + */ + +import { ProviderModel } from "./types"; +import { ProviderType } from "@/types"; + +/** + * Cache entry with data and timestamp + */ +interface CacheEntry { + data: T; + timestamp: number; +} + +/** + * Default cache TTL: 10 minutes + */ +const DEFAULT_TTL = 10 * 60 * 1000; + +/** + * In-memory cache storage + */ +const cache: Map> = new Map(); + +/** + * Get cached models for a key if not expired + * + * @param key - Cache key (use getCacheKey to generate) + * @param ttl - Optional custom TTL in milliseconds + * @returns Cached models or null if not in cache or expired + */ +export function getCachedModels( + key: string, + ttl: number = DEFAULT_TTL +): ProviderModel[] | null { + const entry = cache.get(key); + + if (!entry) { + return null; + } + + const now = Date.now(); + if (now - entry.timestamp > ttl) { + // Cache expired, remove entry + cache.delete(key); + return null; + } + + return entry.data; +} + +/** + * Store models in cache with current timestamp + * + * @param key - Cache key (use getCacheKey to generate) + * @param models - Models to cache + */ +export function setCachedModels(key: string, models: ProviderModel[]): void { + cache.set(key, { + data: models, + timestamp: Date.now(), + }); +} + +/** + * Invalidate cache entries + * + * @param key - Optional specific key to invalidate. If not provided, clears entire cache. + */ +export function invalidateCache(key?: string): void { + if (key) { + cache.delete(key); + } else { + cache.clear(); + } +} + +/** + * Generate a cache key for provider models + * + * @param provider - Provider type + * @param search - Optional search query + * @returns Cache key string + * + * @example + * getCacheKey("replicate") // "replicate:models" + * getCacheKey("fal", "flux") // "fal:search:flux" + */ +export function getCacheKey(provider: ProviderType, search?: string): string { + if (search) { + return `${provider}:search:${search}`; + } + return `${provider}:models`; +} + +/** + * Get cache statistics (for debugging) + */ +export function getCacheStats(): { size: number; keys: string[] } { + return { + size: cache.size, + keys: Array.from(cache.keys()), + }; +}