ltcache
Version:
A lightweight, in-memory caching library - like Redis but much simpler. Features TTL support, concurrent request handling, and comprehensive statistics. Perfect for Node.js applications that need fast caching without the complexity of Redis.
102 lines • 3.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.cache = void 0;
/* eslint-disable max-lines-per-function */
const logger_1 = require("./logger");
function cache(debug = false) {
const cache = new Map();
const clearTimeouts = new Map();
const pendingGets = new Map();
let hits = 0;
let misses = 0;
const set = (key, value, lifetimeInSeconds) => {
cache.set(key, value);
debug && logger_1.logger.debug(`set: ${key}`);
if (clearTimeouts.has(key))
clearTimeout(clearTimeouts.get(key));
if (lifetimeInSeconds && lifetimeInSeconds > 0) {
clearTimeouts.set(key, setTimeout(() => {
cache.delete(key);
clearTimeouts.delete(key);
}, lifetimeInSeconds * 1000));
}
};
const get = async (key, fn, lifetimeInSeconds) => {
if (cache.has(key)) {
hits++;
debug && logger_1.logger.debug(`hit: ${key}`);
return cache.get(key);
}
misses++;
debug && logger_1.logger.debug(`miss: ${key}`);
if (typeof fn === 'function') {
// Check if there's already a pending request for this key
if (pendingGets.has(key)) {
debug && logger_1.logger.debug(`waiting for pending request: ${key}`);
return pendingGets.get(key);
}
// Create a new pending request
const pendingPromise = (async () => {
try {
const value = await fn();
set(key, value, lifetimeInSeconds);
return value;
}
finally {
pendingGets.delete(key);
}
})();
pendingGets.set(key, pendingPromise);
return pendingPromise;
}
return cache.get(key);
};
const remove = (key) => {
if (key instanceof RegExp) {
for (const [k] of cache) {
if (key.test(k)) {
cache.delete(k);
pendingGets.delete(k);
}
}
}
else {
cache.delete(key);
pendingGets.delete(key);
}
};
const reset = () => {
cache.clear();
pendingGets.clear();
hits = 0;
misses = 0;
};
const getSizeKb = () => {
let totalSize = 0;
for (const [key, value] of cache) {
// Estimate size of key and value
const keySize = new Blob([key]).size;
const valueSize = new Blob([JSON.stringify(value)]).size;
totalSize += keySize + valueSize;
}
return Math.round(totalSize / 1024);
};
const report = () => {
const totalRequests = hits + misses;
const hitRate = totalRequests > 0 ? (hits / totalRequests) * 100 : 0;
return {
numItems: cache.size,
hitRate: Math.round(hitRate * 100) / 100,
sizeKb: getSizeKb(),
};
};
return {
get,
set,
remove,
reset,
report,
};
}
exports.cache = cache;
//# sourceMappingURL=cache.js.map