UNPKG

lorehub

Version:

Capture and surface the collective wisdom of your codebase

124 lines 3.91 kB
import crypto from 'crypto'; export class SearchCache { embeddingCache = new Map(); resultsCache = new Map(); // Cache TTLs in milliseconds EMBEDDING_TTL = 30 * 60 * 1000; // 30 minutes RESULTS_TTL = 5 * 60 * 1000; // 5 minutes // Maximum cache sizes MAX_EMBEDDING_ENTRIES = 100; MAX_RESULTS_ENTRIES = 50; getEmbedding(query) { const entry = this.embeddingCache.get(query); if (!entry) return null; if (Date.now() > entry.expiresAt) { this.embeddingCache.delete(query); return null; } return entry.data; } setEmbedding(query, embedding) { // Evict oldest entries if cache is full if (this.embeddingCache.size >= this.MAX_EMBEDDING_ENTRIES) { const oldestKey = this.findOldestEntry(this.embeddingCache); if (oldestKey) this.embeddingCache.delete(oldestKey); } this.embeddingCache.set(query, { data: embedding, expiresAt: Date.now() + this.EMBEDDING_TTL }); } getResults(query, options) { const key = this.generateResultsKey(query, options); const entry = this.resultsCache.get(key); if (!entry) return null; if (Date.now() > entry.expiresAt) { this.resultsCache.delete(key); return null; } return entry.data; } setResults(query, options, results) { // Evict oldest entries if cache is full if (this.resultsCache.size >= this.MAX_RESULTS_ENTRIES) { const oldestKey = this.findOldestEntry(this.resultsCache); if (oldestKey) this.resultsCache.delete(oldestKey); } const key = this.generateResultsKey(query, options); this.resultsCache.set(key, { data: results, expiresAt: Date.now() + this.RESULTS_TTL }); } clear() { this.embeddingCache.clear(); this.resultsCache.clear(); } clearExpired() { const now = Date.now(); // Clear expired embeddings for (const [key, entry] of this.embeddingCache) { if (now > entry.expiresAt) { this.embeddingCache.delete(key); } } // Clear expired results for (const [key, entry] of this.resultsCache) { if (now > entry.expiresAt) { this.resultsCache.delete(key); } } } getCacheStats() { return { embeddings: { size: this.embeddingCache.size, maxSize: this.MAX_EMBEDDING_ENTRIES }, results: { size: this.resultsCache.size, maxSize: this.MAX_RESULTS_ENTRIES } }; } generateResultsKey(query, options) { const parts = [ query, options.realmId || 'global', options.threshold?.toString() || 'none', options.limit?.toString() || 'all' ]; return crypto .createHash('sha256') .update(parts.join('|')) .digest('hex'); } findOldestEntry(cache) { let oldestKey = null; let oldestExpiry = Infinity; for (const [key, entry] of cache) { if (entry.expiresAt < oldestExpiry) { oldestExpiry = entry.expiresAt; oldestKey = key; } } return oldestKey; } } // Singleton instance let cacheInstance = null; export function getSearchCache() { if (!cacheInstance) { cacheInstance = new SearchCache(); // Set up periodic cleanup setInterval(() => { cacheInstance?.clearExpired(); }, 60 * 1000); // Clean up every minute } return cacheInstance; } //# sourceMappingURL=search-cache.js.map