@xec-sh/core
Version:
Universal shell execution engine
138 lines • 4.02 kB
JavaScript
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