mirror of
https://github.com/Shineii86/MiruroAPI.git
synced 2026-10-22 10:15:10 +00:00
135 lines
4.5 KiB
JavaScript
135 lines
4.5 KiB
JavaScript
/*
|
|
* ======= • ======= • ======= • ======= • =======• =======
|
|
* MiruroAPI — cache.js
|
|
* Repository: https://github.com/Shineii86/MiruroAPI
|
|
*
|
|
* @description
|
|
* In-memory caching utility for storing and retrieving API responses.
|
|
* Implements TTL-based cache invalidation to prevent stale data
|
|
* while reducing unnecessary requests to AniList/Miruro backends.
|
|
*
|
|
* @exports
|
|
* getCached, setCache, clearCache
|
|
*
|
|
* @author Shinei Nouzen
|
|
* @license MIT
|
|
* ======= • ======= • ======= • ======= • =======• =======
|
|
*/
|
|
|
|
// ══════════════════════════════════════════════════════════════
|
|
// CACHE STORAGE & CONFIGURATION
|
|
// ══════════════════════════════════════════════════════════════
|
|
|
|
// ---- FEATURE: In-memory Map-based cache storage ----
|
|
/**
|
|
* Internal cache storage using JavaScript Map object.
|
|
* Stores data with expiry timestamps for TTL-based expiration.
|
|
*
|
|
* @type {Map<string, {data: any, expiry: number}>}
|
|
*/
|
|
const cache = new Map();
|
|
|
|
// ---- FEATURE: Cache time-to-live configuration (1 minute) ----
|
|
/**
|
|
* Default cache TTL (Time-To-Live) in milliseconds.
|
|
* Default: 1 minute (60,000 ms).
|
|
* After this duration, cached items are considered stale
|
|
* and will be removed on next access.
|
|
*
|
|
* @type {number}
|
|
* @default 60000
|
|
*/
|
|
const DEFAULT_TTL = 60 * 1000;
|
|
|
|
// ---- FEATURE: Maximum cache size limit ----
|
|
/**
|
|
* Maximum number of entries allowed in the cache.
|
|
* When exceeded, the oldest entry is evicted (FIFO).
|
|
* Prevents unbounded memory growth on long-running instances.
|
|
*
|
|
* @type {number}
|
|
* @default 100
|
|
*/
|
|
const MAX_CACHE_SIZE = 100;
|
|
|
|
// ══════════════════════════════════════════════════════════════
|
|
// CACHE OPERATIONS
|
|
// ══════════════════════════════════════════════════════════════
|
|
|
|
// ---- FEATURE: Retrieve cached data by key with TTL validation ----
|
|
/**
|
|
* Retrieves data from cache if it exists and hasn't expired.
|
|
* Automatically removes stale entries on access (lazy eviction).
|
|
*
|
|
* @param {string} key - The cache key to lookup
|
|
* @returns {any|null} Cached data if valid, null if expired or missing
|
|
*
|
|
* @example
|
|
* const data = getCached("search:naruto:1:20");
|
|
* if (data) {
|
|
* // Use cached data
|
|
* }
|
|
*/
|
|
const getCached = (key) => {
|
|
const entry = cache.get(key);
|
|
if (!entry) return null;
|
|
|
|
// NOTE: Lazy eviction — delete stale entries on access
|
|
if (Date.now() > entry.expiry) {
|
|
cache.delete(key);
|
|
return null;
|
|
}
|
|
|
|
return entry.data;
|
|
};
|
|
|
|
// ---- FEATURE: Store data in cache with TTL expiry ----
|
|
/**
|
|
* Stores data in cache with TTL-based expiry.
|
|
* Evicts oldest entry if cache is at max capacity (FIFO).
|
|
*
|
|
* @param {string} key - The cache key to store under
|
|
* @param {any} data - The data to cache (any serializable type)
|
|
* @param {number} [ttl=DEFAULT_TTL] - Time-to-live in milliseconds
|
|
* @returns {void}
|
|
*
|
|
* @example
|
|
* // Cache search results for 2 minutes
|
|
* setCache("search:one-piece", results, 120000);
|
|
*/
|
|
const setCache = (key, data, ttl = DEFAULT_TTL) => {
|
|
// NOTE: FIFO eviction — remove oldest entry when cache is full
|
|
if (cache.size >= MAX_CACHE_SIZE) {
|
|
const firstKey = cache.keys().next().value;
|
|
cache.delete(firstKey);
|
|
}
|
|
|
|
// NOTE: Periodic cleanup — prune all expired entries when cache reaches 80% capacity
|
|
// Prevents unbounded memory growth from stale entries that were never accessed
|
|
if (cache.size >= MAX_CACHE_SIZE * 0.8) {
|
|
const now = Date.now();
|
|
for (const [k, v] of cache) {
|
|
if (now > v.expiry) cache.delete(k);
|
|
}
|
|
}
|
|
|
|
cache.set(key, { data, expiry: Date.now() + ttl });
|
|
};
|
|
|
|
// ---- FEATURE: Clear all cached entries from memory ----
|
|
/**
|
|
* Clears all entries from the cache. Use when:
|
|
* - Memory cleanup is needed
|
|
* - Force-refreshing all data
|
|
* - Application restart/reset
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
const clearCache = () => {
|
|
cache.clear();
|
|
};
|
|
|
|
module.exports = { getCached, setCache, clearCache };
|
|
|
|
// ══════════════════════════════════════════════════════════════ END: cache.js
|