UNPKG

@xec-sh/core

Version:

Universal shell execution engine

138 lines 4.02 kB
import crypto from 'crypto'; export class ResultCache { constructor(cleanupIntervalMs = 60000, eventEmitter) { this.cache = new Map(); this.inflight = new Map(); this.eventEmitter = eventEmitter; this.cleanupInterval = setInterval(() => { this.cleanup(); }, cleanupIntervalMs); this.cleanupInterval.unref(); } generateKey(command, cwd, env) { const data = { command, cwd: cwd || process.cwd(), env: env || {} }; return crypto .createHash('sha256') .update(JSON.stringify(data)) .digest('hex'); } getInflight(key) { return this.inflight.get(key) || null; } setInflight(key, promise) { this.inflight.set(key, promise); } clearInflight(key) { this.inflight.delete(key); } get(key) { const cached = this.cache.get(key); if (!cached) { if (this.eventEmitter) { this.eventEmitter.emitEnhanced('cache:miss', { key }, 'cache'); } return null; } const now = Date.now(); const age = now - cached.timestamp; if (cached.ttl > 0 && age > cached.ttl) { this.cache.delete(key); if (this.eventEmitter) { this.eventEmitter.emitEnhanced('cache:evict', { key, reason: 'ttl' }, 'cache'); } if (this.eventEmitter) { this.eventEmitter.emitEnhanced('cache:miss', { key }, 'cache'); } return null; } if (this.eventEmitter) { this.eventEmitter.emitEnhanced('cache:hit', { key, ttl: cached.ttl, size: JSON.stringify(cached.result).length }, 'cache'); } return cached.result; } set(key, result, ttl = 0) { this.cache.set(key, { result, timestamp: Date.now(), ttl, key }); if (this.eventEmitter) { this.eventEmitter.emitEnhanced('cache:set', { key, ttl, size: JSON.stringify(result).length }, 'cache'); } } invalidate(patterns) { if (patterns.length === 0) return; const regexes = patterns.map(p => { const regexPattern = p .replace(/\*/g, '.*') .replace(/\?/g, '.') .replace(/\[/g, '\\[') .replace(/\]/g, '\\]'); return new RegExp(`^${regexPattern}$`); }); for (const [key, cached] of this.cache.entries()) { if (regexes.some(regex => regex.test(key))) { this.cache.delete(key); } } } clear() { this.cache.clear(); this.inflight.clear(); } stats() { const size = this.cache.size; return { size, hits: 0, misses: 0, hitRate: 0 }; } cleanup() { const now = Date.now(); for (const [key, cached] of this.cache.entries()) { if (cached.ttl > 0) { const age = now - cached.timestamp; if (age > cached.ttl) { this.cache.delete(key); if (this.eventEmitter) { this.eventEmitter.emitEnhanced('cache:evict', { key, reason: 'ttl' }, 'cache'); } } } } } dispose() { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); } this.clear(); } } export const globalCache = new ResultCache(); //# sourceMappingURL=cache.js.map