UNPKG

@sethdouglasford/claude-flow

Version:

Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology

231 lines 6.2 kB
/** * TTL Map Implementation * Map with time-to-live for automatic entry expiration */ export class TTLMap { items = new Map(); cleanupTimer; defaultTTL; cleanupInterval; maxSize; onExpire; stats = { hits: 0, misses: 0, evictions: 0, expirations: 0, }; constructor(options = {}) { this.defaultTTL = options.defaultTTL ?? 3600000; // 1 hour default this.cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute default this.maxSize = options.maxSize; this.onExpire = options.onExpire; this.startCleanup(); } set(key, value, ttl) { const now = Date.now(); const expiry = now + (ttl ?? this.defaultTTL); // Check if we need to evict items due to size limit if (this.maxSize && this.items.size >= this.maxSize && !this.items.has(key)) { this.evictLRU(); } this.items.set(key, { value, expiry, createdAt: now, accessCount: 0, lastAccessedAt: now, }); } get(key) { const item = this.items.get(key); if (!item) { this.stats.misses++; return undefined; } const now = Date.now(); if (now > item.expiry) { this.items.delete(key); this.stats.expirations++; this.stats.misses++; if (this.onExpire) { this.onExpire(key, item.value); } return undefined; } // Update access stats item.accessCount++; item.lastAccessedAt = now; this.stats.hits++; return item.value; } has(key) { const item = this.items.get(key); if (!item) { return false; } if (Date.now() > item.expiry) { this.items.delete(key); this.stats.expirations++; if (this.onExpire) { this.onExpire(key, item.value); } return false; } return true; } delete(key) { return this.items.delete(key); } clear() { this.items.clear(); } /** * Update TTL for an existing key */ touch(key, ttl) { const item = this.items.get(key); if (!item || Date.now() > item.expiry) { return false; } item.expiry = Date.now() + (ttl ?? this.defaultTTL); item.lastAccessedAt = Date.now(); return true; } /** * Get remaining TTL for a key */ getTTL(key) { const item = this.items.get(key); if (!item) { return -1; } const remaining = item.expiry - Date.now(); return remaining > 0 ? remaining : -1; } /** * Get all keys (excluding expired ones) */ keys() { const now = Date.now(); const validKeys = []; for (const [key, item] of this.items) { if (now <= item.expiry) { validKeys.push(key); } } return validKeys; } /** * Get all values (excluding expired ones) */ values() { const now = Date.now(); const validValues = []; for (const item of this.items.values()) { if (now <= item.expiry) { validValues.push(item.value); } } return validValues; } /** * Get all entries (excluding expired ones) */ entries() { const now = Date.now(); const validEntries = []; for (const [key, item] of this.items) { if (now <= item.expiry) { validEntries.push([key, item.value]); } } return validEntries; } /** * Get size (excluding expired items) */ get size() { this.cleanup(); // Clean up expired items first return this.items.size; } startCleanup() { this.cleanupTimer = setInterval(() => { this.cleanup(); }, this.cleanupInterval); } cleanup() { const now = Date.now(); let cleaned = 0; for (const [key, item] of this.items) { if (now > item.expiry) { this.items.delete(key); cleaned++; this.stats.expirations++; if (this.onExpire) { this.onExpire(key, item.value); } } } if (cleaned > 0) { // Optional: Log cleanup stats } } evictLRU() { let lruKey; let lruTime = Infinity; // Find least recently used item for (const [key, item] of this.items) { if (item.lastAccessedAt < lruTime) { lruTime = item.lastAccessedAt; lruKey = key; } } if (lruKey !== undefined) { this.items.delete(lruKey); this.stats.evictions++; } } /** * Stop the cleanup timer */ destroy() { if (this.cleanupTimer) { clearInterval(this.cleanupTimer); this.cleanupTimer = undefined; } this.items.clear(); } /** * Get statistics about the map */ getStats() { return { ...this.stats, size: this.items.size, hitRate: this.stats.hits + this.stats.misses > 0 ? this.stats.hits / (this.stats.hits + this.stats.misses) : 0, }; } /** * Get detailed information about all items */ inspect() { const now = Date.now(); const result = new Map(); for (const [key, item] of this.items) { if (now <= item.expiry) { result.set(key, { value: item.value, ttl: item.expiry - now, age: now - item.createdAt, accessCount: item.accessCount, lastAccessed: now - item.lastAccessedAt, }); } } return result; } } //# sourceMappingURL=ttl-map.js.map