Files
MajoorWaldi-ComfyUI-Majoor-…/js/utils/ttlCache.js
T
MajoorWaldi cb171e826d feat: Add runtime bootstrap helpers and search request normalization
- Introduced runtime bootstrap helpers in `mjr_am_backend.features.runtime` for dependency initialization.
- Implemented `apply_startup_settings` to handle various startup configurations.
- Added search request normalization helpers in `mjr_am_backend.features.search` including `SearchRequestContext` and `parse_search_request` for better query handling.
- Created audit logging helpers in `mjr_am_backend.routes.core.audit_log` for state-changing route handlers.
- Developed a quality gate script in `scripts/run_quality_gate.py` to enforce code quality checks.
- Added comprehensive tests for audit routes, scan consistency, vendor routes, and code quality metrics.
2026-03-26 20:42:51 +01:00

122 lines
3.2 KiB
JavaScript

export function createTTLCache({ ttlMs = 0, maxSize = 100, now = () => Date.now() } = {}) {
const map = new Map();
function _resolveNow() {
try {
const value = Number(now());
return Number.isFinite(value) ? value : Date.now();
} catch {
return Date.now();
}
}
function _resolveTTL() {
try {
const value = typeof ttlMs === "function" ? Number(ttlMs()) : Number(ttlMs);
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
} catch {
return 0;
}
}
function _resolveMaxSize() {
try {
const value = Number(maxSize);
return Number.isFinite(value) ? Math.max(1, Math.floor(value)) : 1;
} catch {
return 1;
}
}
function _isExpired(entry, nowValue, ttlValue) {
if (!entry) return true;
if (!(ttlValue > 0)) return false;
return nowValue - Number(entry.at || 0) > ttlValue;
}
function _pruneExpired(nowValue = _resolveNow(), ttlValue = _resolveTTL()) {
if (!(ttlValue > 0)) return;
for (const [key, entry] of map.entries()) {
if (_isExpired(entry, nowValue, ttlValue)) {
map.delete(key);
}
}
}
function _evictOverflow() {
const limit = _resolveMaxSize();
while (map.size > limit) {
const oldestKey = map.keys().next().value;
if (oldestKey === undefined) break;
map.delete(oldestKey);
}
}
function _touch(key, entry) {
map.delete(key);
map.set(key, entry);
}
return {
get(key) {
const nowValue = _resolveNow();
const ttlValue = _resolveTTL();
_pruneExpired(nowValue, ttlValue);
const entry = map.get(key);
if (!entry) return undefined;
if (_isExpired(entry, nowValue, ttlValue)) {
map.delete(key);
return undefined;
}
return entry.value;
},
has(key) {
return this.get(key) !== undefined;
},
set(key, value, options = {}) {
const entryAtRaw = Number(options?.at);
const entryAt = Number.isFinite(entryAtRaw) ? entryAtRaw : _resolveNow();
const entry = { value, at: entryAt };
if (map.has(key)) {
_touch(key, entry);
} else {
map.set(key, entry);
}
_pruneExpired(_resolveNow(), _resolveTTL());
_evictOverflow();
return value;
},
delete(key) {
return map.delete(key);
},
clear() {
map.clear();
},
prune() {
_pruneExpired(_resolveNow(), _resolveTTL());
_evictOverflow();
return map.size;
},
keys() {
this.prune();
return Array.from(map.keys());
},
entries() {
this.prune();
return Array.from(map.entries()).map(([key, entry]) => [key, entry.value]);
},
get size() {
this.prune();
return map.size;
},
};
}