UNPKG

restifyx.js

Version:

Advanced API endpoint handler system with automatic documentation

148 lines 5.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.memoryCache = void 0; exports.cacheMiddleware = cacheMiddleware; const logger_1 = require("./logger"); class MemoryCache { constructor(options = {}) { this.cache = new Map(); this.logger = (0, logger_1.getLogger)(); this.maxSize = Number.POSITIVE_INFINITY; this.cleanupInterval = null; if (options.maxSize) { this.maxSize = options.maxSize; } if (options.cleanupInterval) { this.startCleanupInterval(options.cleanupInterval); } } set(key, value, duration) { const expiry = Date.now() + duration * 1000; if (this.cache.size >= this.maxSize) { this.evictLeastRecentlyUsed(); } this.cache.set(key, { data: value, expiry, lastAccessed: Date.now(), }); this.logger.debug(`Cache set: ${key} (expires in ${duration}s)`); } get(key) { const item = this.cache.get(key); if (!item) { return undefined; } if (Date.now() > item.expiry) { this.logger.debug(`Cache expired: ${key}`); this.cache.delete(key); return undefined; } item.lastAccessed = Date.now(); this.cache.set(key, item); this.logger.debug(`Cache hit: ${key}`); return item.data; } delete(key) { this.cache.delete(key); this.logger.debug(`Cache deleted: ${key}`); } clear() { this.cache.clear(); this.logger.debug("Cache cleared"); } size() { return this.cache.size; } keys() { return Array.from(this.cache.keys()); } has(key) { return this.cache.has(key); } evictLeastRecentlyUsed() { let oldestKey = null; let oldestTime = Number.POSITIVE_INFINITY; for (const [key, item] of this.cache.entries()) { if (item.lastAccessed < oldestTime) { oldestTime = item.lastAccessed; oldestKey = key; } } if (oldestKey) { this.cache.delete(oldestKey); this.logger.debug(`Cache evicted LRU item: ${oldestKey}`); } } startCleanupInterval(intervalMs) { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); } this.cleanupInterval = setInterval(() => { const now = Date.now(); let expiredCount = 0; for (const [key, item] of this.cache.entries()) { if (now > item.expiry) { this.cache.delete(key); expiredCount++; } } if (expiredCount > 0) { this.logger.debug(`Cache cleanup: removed ${expiredCount} expired items`); } }, intervalMs); } stopCleanupInterval() { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); this.cleanupInterval = null; } } } const memoryCache = new MemoryCache({ cleanupInterval: 60000 }); exports.memoryCache = memoryCache; function cacheMiddleware(options) { return (req, res, next) => { if (req.method !== "GET" && req.method !== "HEAD") { return next(); } const key = options.keyGenerator ? options.keyGenerator(req) : `${req.originalUrl || req.url}`; const cachedResponse = memoryCache.get(key); if (cachedResponse) { return res.json(cachedResponse); } const originalJson = res.json; const originalSend = res.send; const originalEnd = res.end; res.json = function (body) { if ((res.statusCode >= 200 && res.statusCode < 300) || (options.cacheErrorResponses && res.statusCode >= 400)) { if (body !== null || options.cacheNullValues) { memoryCache.set(key, body, options.duration); } } return originalJson.call(this, body); }; res.send = function (body) { if ((res.statusCode >= 200 && res.statusCode < 300) || (options.cacheErrorResponses && res.statusCode >= 400)) { if (body !== null || options.cacheNullValues) { memoryCache.set(key, body, options.duration); } } return originalSend.call(this, body); }; res.end = function (chunk, encoding, cb) { if ((res.statusCode >= 200 && res.statusCode < 300) || (options.cacheErrorResponses && res.statusCode >= 400)) { if ((chunk !== null && chunk !== undefined) || options.cacheNullValues) { let data = chunk; if (chunk && typeof chunk !== "string") { data = chunk.toString(encoding); } memoryCache.set(key, data, options.duration); } } return originalEnd.call(this, chunk, encoding, cb); }; next(); }; } //# sourceMappingURL=cache.js.map