import { encodeHex } from '@std/encoding/hex'; import { LRUCache } from 'lru-cache'; import type { AudioToken } from '../domain/types.ts'; import { TOKEN_CACHE_MAX_ITEMS, TOKEN_TTL_MS } from '../shared/constants.ts'; /** * Token store service for managing short-lived audio streaming tokens */ export class TokenStoreService { private readonly tokenCache: LRUCache; constructor(ttlMs: number = TOKEN_TTL_MS) { this.tokenCache = new LRUCache({ max: TOKEN_CACHE_MAX_ITEMS, ttl: ttlMs, ttlAutopurge: true, allowStale: false, updateAgeOnGet: false, updateAgeOnHas: false, }); } /** * Generate a random token */ private generateToken(): string { const bytes = new Uint8Array(16); crypto.getRandomValues(bytes); return encodeHex(bytes); } /** * Create and store a new token */ putToken(value: AudioToken, ttlMs?: number): string { const token = this.generateToken(); const options = ttlMs ? { ttl: Math.max(1000, ttlMs) } : undefined; this.tokenCache.set(token, value, options); return token; } /** * Retrieve token data */ getToken(token: string): AudioToken | undefined { if (!token) return undefined; return this.tokenCache.get(token); } /** * Remove a token */ deleteToken(token: string): boolean { return this.tokenCache.delete(token); } /** * Clear all tokens */ clearAll(): void { this.tokenCache.clear(); } /** * Get cache size */ getSize(): number { return this.tokenCache.size; } }