UNPKG

@jay-js/system

Version:

A powerful and flexible TypeScript library for UI, state management, lazy loading, routing and managing draggable elements in modern web applications.

242 lines 6.68 kB
/** * Global query cache singleton * Manages cached data across all queries with automatic garbage collection */ class QueryCache { constructor() { this.cache = new Map(); this.gcTimers = new Map(); this.listeners = new Map(); } /** * Get cached data for a key * * @param key Query key * @returns Cache entry or undefined if not found */ get(key) { return this.cache.get(key); } /** * Set cached data for a key * * @param key Query key * @param data Data to cache * @param cacheTime Time in ms before garbage collection */ set(key, data, cacheTime) { const existing = this.cache.get(key); this.cache.set(key, { data, timestamp: Date.now(), subscribers: existing ? existing.subscribers : 1, }); this.scheduleGC(key, cacheTime); const listeners = this.listeners.get(key); if (listeners) { for (const callback of listeners) { callback(data); } } } /** * Check if data is stale * * @param key Query key * @param staleTime Time in ms before data is considered stale * @returns True if data is stale or not found */ isStale(key, staleTime) { const entry = this.cache.get(key); if (!entry) return true; const age = Date.now() - entry.timestamp; return age > staleTime; } /** * Delete cache entry * * @param key Query key */ delete(key) { this.cache.delete(key); const timer = this.gcTimers.get(key); if (timer) { clearTimeout(timer); this.gcTimers.delete(key); } } /** * Increment subscriber count * * @param key Query key */ subscribe(key) { const entry = this.cache.get(key); if (entry) { entry.subscribers++; } } /** * Decrement subscriber count * * @param key Query key */ unsubscribe(key) { const entry = this.cache.get(key); if (entry) { entry.subscribers = Math.max(0, entry.subscribers - 1); } } /** * Register a listener for cache changes on a specific key * * @param key Query key to watch * @param callback Function to call when cache is updated * @returns Cleanup function to remove the listener */ onChange(key, callback) { var _a; if (!this.listeners.has(key)) { this.listeners.set(key, new Set()); } (_a = this.listeners.get(key)) === null || _a === void 0 ? void 0 : _a.add(callback); return () => this.offChange(key, callback); } /** * Remove a listener for a specific key * * @param key Query key * @param callback Callback to remove */ offChange(key, callback) { var _a, _b; (_a = this.listeners.get(key)) === null || _a === void 0 ? void 0 : _a.delete(callback); if (((_b = this.listeners.get(key)) === null || _b === void 0 ? void 0 : _b.size) === 0) { this.listeners.delete(key); } } /** * Schedule garbage collection for inactive query * * @param key Query key * @param cacheTime Time in ms before garbage collection */ scheduleGC(key, cacheTime) { const existing = this.gcTimers.get(key); if (existing) { clearTimeout(existing); } const timer = setTimeout(() => { const entry = this.cache.get(key); if (entry && entry.subscribers === 0) { this.delete(key); } }, cacheTime); this.gcTimers.set(key, timer); } /** * Clear all cache */ clear() { this.cache.clear(); for (const timer of this.gcTimers.values()) { clearTimeout(timer); } this.gcTimers.clear(); this.listeners.clear(); } /** * Invalidate queries matching a pattern * Supports glob patterns (* and ?) and RegExp * * @param pattern Glob pattern string or RegExp to match keys * @returns Array of invalidated keys * * @example * ```typescript * // Invalidate all user queries * queryCache.invalidatePattern('user-*'); * * // Invalidate with regex * queryCache.invalidatePattern(/^user-\d+$/); * ``` */ invalidatePattern(pattern) { const keysToInvalidate = []; for (const [key] of this.cache) { if (this.matchesPattern(key, pattern)) { keysToInvalidate.push(key); } } for (const key of keysToInvalidate) { this.delete(key); } return keysToInvalidate; } /** * Invalidate queries matching a predicate function * * @param predicate Function that returns true for keys to invalidate * @returns Array of invalidated keys * * @example * ```typescript * // Invalidate all stale queries * queryCache.invalidateQueries((key, entry) => { * const age = Date.now() - entry.timestamp; * return age > 60000; // 1 minute * }); * ``` */ invalidateQueries(predicate) { const keysToInvalidate = []; for (const [key, entry] of this.cache) { if (predicate(key, entry)) { keysToInvalidate.push(key); } } for (const key of keysToInvalidate) { this.delete(key); } return keysToInvalidate; } /** * Get all cache keys * * @returns Array of all cached query keys */ getKeys() { return Array.from(this.cache.keys()); } /** * Match key against pattern * * @param key Query key * @param pattern String glob pattern or RegExp * @returns True if key matches pattern */ matchesPattern(key, pattern) { if (pattern instanceof RegExp) { return pattern.test(key); } const regexPattern = pattern .replace(/\*/g, "__STAR__") .replace(/\?/g, "__QUESTION__") .replace(/[.+^${}()|[\]\\]/g, "\\$&") .replace(/__STAR__/g, ".*") .replace(/__QUESTION__/g, "."); return new RegExp(`^${regexPattern}$`).test(key); } /** * Get cache size */ get size() { return this.cache.size; } } /** * Global cache singleton instance */ export const queryCache = new QueryCache(); //# sourceMappingURL=cache.js.map