lorehub
Version:
Capture and surface the collective wisdom of your codebase
124 lines • 3.91 kB
JavaScript
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