/**
* Simple in-memory cache with TTL support
*/
interface CacheEntry<T> {
value: T;
expiry: number;
}
export class Cache<T> {
private cache: Map<string, CacheEntry<T>> = new Map();
private readonly defaultTTL: number;
constructor(defaultTTLSeconds: number = 3600) {
this.defaultTTL = defaultTTLSeconds * 1000; // Convert to milliseconds
}
/**
* Get a value from the cache
* @param key The cache key
* @returns The cached value or undefined if not found or expired
*/
get(key: string): T | undefined {
const entry = this.cache.get(key);
if (!entry) {
return undefined;
}
// Check if entry has expired
if (Date.now() > entry.expiry) {
this.cache.delete(key);
return undefined;
}
return entry.value;
}
/**
* Set a value in the cache
* @param key The cache key
* @param value The value to cache
* @param ttlSeconds Optional TTL in seconds (defaults to constructor TTL)
*/
set(key: string, value: T, ttlSeconds?: number): void {
const ttl = ttlSeconds ? ttlSeconds * 1000 : this.defaultTTL;
this.cache.set(key, {
value,
expiry: Date.now() + ttl
});
}
/**
* Check if a key exists and is not expired
* @param key The cache key
* @returns True if the key exists and is not expired
*/
has(key: string): boolean {
return this.get(key) !== undefined;
}
/**
* Delete a key from the cache
* @param key The cache key
*/
delete(key: string): void {
this.cache.delete(key);
}
/**
* Clear all entries from the cache
*/
clear(): void {
this.cache.clear();
}
/**
* Get the number of entries in the cache (including expired)
*/
get size(): number {
return this.cache.size;
}
/**
* Clean up expired entries
*/
cleanup(): void {
const now = Date.now();
for (const [key, entry] of this.cache.entries()) {
if (now > entry.expiry) {
this.cache.delete(key);
}
}
}
}
// Global cache instances
export const videoInfoCache = new Cache<{ metadata: any; captionTracks: any[] }>(3600); // 1 hour TTL
export const transcriptCache = new Cache<any>(7200); // 2 hours TTL