UNPKG

@nanggo/social-preview

Version:

Generate beautiful social media preview images from any URL

149 lines (148 loc) 4.28 kB
"use strict"; /** * LRU Cache implementation with TTL support * Used for caching metadata extraction results * * @example * ```typescript * import { metadataCache, stopCacheCleanup, startCacheCleanup } from './cache'; * * // For graceful server shutdown * process.on('SIGTERM', () => { * stopCacheCleanup(); * // ... other cleanup * }); * * // For testing environments * afterAll(() => { * stopCacheCleanup(); * }); * * // Custom cleanup interval (5 minutes) * stopCacheCleanup(); * startCacheCleanup(5 * 60 * 1000); * ``` */ Object.defineProperty(exports, "__esModule", { value: true }); exports.previewCache = exports.metadataCache = exports.LRUCache = void 0; exports.startCacheCleanup = startCacheCleanup; exports.stopCacheCleanup = stopCacheCleanup; exports.isCacheCleanupRunning = isCacheCleanupRunning; class LRUCache { cache = new Map(); maxSize; defaultTTL; constructor(maxSize = 100, defaultTTL = 5 * 60 * 1000) { this.maxSize = maxSize; this.defaultTTL = defaultTTL; } set(key, value, ttl) { const now = Date.now(); const entryTTL = ttl ?? this.defaultTTL; // Remove existing entry if present (for LRU ordering) if (this.cache.has(key)) { this.cache.delete(key); } // Remove oldest entries if cache is full if (this.cache.size >= this.maxSize) { const firstKey = this.cache.keys().next().value; if (firstKey) { this.cache.delete(firstKey); } } // Add new entry (will be most recently used) this.cache.set(key, { value, timestamp: now, ttl: entryTTL }); } get(key) { const entry = this.cache.get(key); if (!entry) { return undefined; } const now = Date.now(); // Check if entry has expired if (now - entry.timestamp > entry.ttl) { this.cache.delete(key); return undefined; } // Move to end (most recently used) this.cache.delete(key); this.cache.set(key, entry); return entry.value; } has(key) { return this.get(key) !== undefined; } delete(key) { return this.cache.delete(key); } clear() { this.cache.clear(); } size() { return this.cache.size; } // Clean expired entries cleanup() { const now = Date.now(); let removedCount = 0; for (const [key, entry] of this.cache.entries()) { if (now - entry.timestamp > entry.ttl) { this.cache.delete(key); removedCount++; } } return removedCount; } // Get cache statistics getStats() { return { size: this.cache.size, maxSize: this.maxSize, defaultTTL: this.defaultTTL }; } } exports.LRUCache = LRUCache; exports.metadataCache = new LRUCache(100, 5 * 60 * 1000); // 100 entries, 5 minutes TTL exports.previewCache = new LRUCache(50, 5 * 60 * 1000); // 50 entries, 5 minutes TTL // Cache cleanup management let cleanupInterval = null; const CLEANUP_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes /** * Starts automatic cache cleanup if not already running. * @param intervalMs - Cleanup interval in milliseconds (default: 10 minutes) */ function startCacheCleanup(intervalMs = CLEANUP_INTERVAL_MS) { if (cleanupInterval) { return; // Already running } cleanupInterval = setInterval(() => { exports.metadataCache.cleanup(); exports.previewCache.cleanup(); }, intervalMs); // Don't prevent Node.js process from exiting cleanupInterval.unref(); } /** * Stops the automatic cache cleanup interval. * Useful for graceful shutdown in applications and testing environments. */ function stopCacheCleanup() { if (cleanupInterval) { clearInterval(cleanupInterval); cleanupInterval = null; } } /** * Checks if automatic cache cleanup is currently running. * @returns true if cleanup interval is active */ function isCacheCleanupRunning() { return cleanupInterval !== null; } // Start automatic cleanup by default startCacheCleanup();