class CacheEntry { public value: T; public expiration: Date; constructor(value: T, expiration: Date) { this.value = value; this.expiration = expiration; } } export type ExpirationSupplier = (v: T) => Date; export class RegionalMarketCache { private cache: Record>>; private expirationSupplier: (v: T) => Date; constructor(expiration: ExpirationSupplier | number) { this.cache = {}; this.expirationSupplier = expiration instanceof Function ? expiration : () => new Date(Date.now() + expiration); } public get(regionId: number, typeId: number): T | undefined { const entry = this.cache[regionId]?.[typeId]; if (entry && entry.expiration > new Date()) { return entry.value; } this.remove(regionId, typeId); return undefined; } public set(regionId: number, typeId: number, value: T): void { this.cache[regionId] = this.cache[regionId] ?? {}; this.cache[regionId][typeId] = new CacheEntry(value, this.expirationSupplier(value)); } public remove(regionId: number, typeId: number): void { delete this.cache[regionId]?.[typeId]; } public async computeIfAbsent(regionId: number, typeId: number, supplier: () => (Promise | T)): Promise { let value = this.get(regionId, typeId); if (!value) { value = await supplier(); this.set(regionId, typeId, value); } return value; } };