| |
| |
| |
| const STABLE_CONTENT_MONTHS = 3 |
|
|
| const SHORT_TTL_MS = 20_000 |
| const LONG_TTL_MS = 30 * 60_000 |
| const MAX_ENTRIES = 500 |
|
|
| const resultsCache = new Map() |
| const inflight = new Map() |
|
|
| function pruneExpired() { |
| const now = Date.now() |
|
|
| for (const [key, entry] of resultsCache.entries()) { |
| if (entry.expires <= now) { |
| resultsCache.delete(key) |
| } |
| } |
|
|
| while (resultsCache.size > MAX_ENTRIES) { |
| const oldestKey = resultsCache.keys().next().value |
| if (oldestKey !== undefined) resultsCache.delete(oldestKey) |
| } |
| } |
|
|
| |
| |
| |
| |
| function isStableContent(releaseDate) { |
| if (!releaseDate) return false |
|
|
| const release = new Date(releaseDate) |
| if (isNaN(release.getTime())) return false |
|
|
| const threshold = new Date() |
| threshold.setMonth(threshold.getMonth() - STABLE_CONTENT_MONTHS) |
|
|
| return release < threshold |
| } |
|
|
| |
| |
| |
| |
| |
| async function dedupeRequest(key, factory, { releaseDate = null, cacheErrors = false } = {}) { |
| if (!key || typeof key !== 'string') { |
| return factory() |
| } |
|
|
| pruneExpired() |
|
|
| const cached = resultsCache.get(key) |
| if (cached && cached.expires > Date.now()) { |
| return cached.value |
| } |
|
|
| if (inflight.has(key)) { |
| return inflight.get(key) |
| } |
|
|
| const promise = (async () => factory())() |
| inflight.set(key, promise) |
|
|
| try { |
| const value = await promise |
|
|
| |
| const hasResults = Array.isArray(value) && value.length > 0 |
| const stable = isStableContent(releaseDate) |
| const ttl = (stable && hasResults) ? LONG_TTL_MS : SHORT_TTL_MS |
|
|
| resultsCache.set(key, { |
| value, |
| expires: Date.now() + ttl, |
| }) |
|
|
| pruneExpired() |
| return value |
| } catch (error) { |
| if (cacheErrors) { |
| resultsCache.set(key, { |
| value: { error: error.message || String(error) }, |
| expires: Date.now() + Math.min(SHORT_TTL_MS, 5_000), |
| }) |
| } |
| throw error |
| } finally { |
| inflight.delete(key) |
| } |
| } |
|
|
| function clearRequestDedupCache() { |
| resultsCache.clear() |
| inflight.clear() |
| } |
|
|
| module.exports = { |
| dedupeRequest, |
| clearRequestDedupCache, |
| isStableContent, |
| STABLE_CONTENT_MONTHS, |
| } |
|
|