Description
src/currencyConverter.ts fetches exchange rates on every invocation, making repeated conversions in a single invoice rendering session unnecessarily expensive and slow. Rates fetched from external oracles rarely change within a minute, so a time-to-live cache should store fetched rates and serve subsequent requests from memory until the TTL expires, with background refresh to avoid cold-fetch latency on expiry.
Technical Context
Add src/rateCache.ts. Integrates with src/currencyConverter.ts and any price oracle adapter. Implements a Map<string, { rate: number; fetchedAt: number }> store keyed by "${fromAsset}:${toAsset}". Uses src/cache.ts eviction patterns. Background refresh implemented with a setInterval owned by RateCache lifecycle methods start() / stop(). Ties into src/gracefulShutdown.ts pattern from src/index.ts.
Acceptance Criteria
Description
src/currencyConverter.tsfetches exchange rates on every invocation, making repeated conversions in a single invoice rendering session unnecessarily expensive and slow. Rates fetched from external oracles rarely change within a minute, so a time-to-live cache should store fetched rates and serve subsequent requests from memory until the TTL expires, with background refresh to avoid cold-fetch latency on expiry.Technical Context
Add
src/rateCache.ts. Integrates withsrc/currencyConverter.tsand any price oracle adapter. Implements aMap<string, { rate: number; fetchedAt: number }>store keyed by"${fromAsset}:${toAsset}". Usessrc/cache.tseviction patterns. Background refresh implemented with asetIntervalowned byRateCachelifecycle methodsstart()/stop(). Ties intosrc/gracefulShutdown.tspattern fromsrc/index.ts.Acceptance Criteria
RateCache.getRate(from, to): Promise<number>serves from cache whenDate.now() - fetchedAt < ttlMsttlMs * 0.8to pre-warm the cache before expiryinvalidate(from, to)removes a specific pair;invalidateAll()clears the entire cache