UNPKG

@mixxtor/currencyx-js

Version:

Modern TypeScript currency converter with type inference and multiple providers (Google Finance, Fixer.io). Framework agnostic with clean architecture.

149 lines (125 loc) 3.18 kB
/** * Cache implementation for currency rates */ export class RateCache { private cache: Map<string, { value: number, expires: number }> = new Map() private readonly defaultTTL: number constructor(defaultTTL: number = 3600000) { // 1 hour default TTL this.defaultTTL = defaultTTL } /** * Generate cache key for rate pairs */ private getCacheKey(from: string, to: string): string { return `${from}:${to}` } /** * Set a value in cache */ set(from: string, to: string, value: number, ttl: number = this.defaultTTL): void { const key = this.getCacheKey(from, to) this.cache.set(key, { value, expires: Date.now() + ttl }) } /** * Get a value from cache */ get(from: string, to: string): number | null { const key = this.getCacheKey(from, to) const item = this.cache.get(key) if (!item) { return null } if (Date.now() > item.expires) { this.cache.delete(key) return null } return item.value } /** * Clear expired entries */ cleanup(): void { const now = Date.now() for (const [key, item] of this.cache.entries()) { if (now > item.expires) { this.cache.delete(key) } } } } /** * Rate limiter implementation */ export class RateLimiter { private readonly limit: number private readonly interval: number private requests: number[] = [] constructor(limit: number = 60, interval: number = 60000) { // 60 requests per minute default this.limit = limit this.interval = interval } /** * Check if rate limit is exceeded */ isLimited(): boolean { const now = Date.now() this.requests = this.requests.filter(time => now - time < this.interval) if (this.requests.length >= this.limit) { return true } this.requests.push(now) return false } /** * Get remaining requests in current window */ remaining(): number { const now = Date.now() this.requests = this.requests.filter(time => now - time < this.interval) return this.limit - this.requests.length } /** * Reset rate limiter */ reset(): void { this.requests = [] } } /** * Retry mechanism for API calls */ export class RetryMechanism { private readonly maxRetries: number private readonly baseDelay: number private readonly maxDelay: number constructor(maxRetries: number = 3, baseDelay: number = 1000, maxDelay: number = 5000) { this.maxRetries = maxRetries this.baseDelay = baseDelay this.maxDelay = maxDelay } /** * Execute function with retry */ async execute<T>(fn: () => Promise<T>): Promise<T> { let lastError: Error for (let attempt = 1; attempt <= this.maxRetries; attempt++) { try { return await fn() } catch (error) { lastError = error as Error if (attempt === this.maxRetries) { throw error } const delay = Math.min( this.baseDelay * Math.pow(2, attempt - 1), this.maxDelay ) await new Promise(resolve => setTimeout(resolve, delay)) } } throw lastError! } }