UNPKG

react-native-avo-inspector

Version:

[![npm version](https://badge.fury.io/js/react-native-avo-inspector.svg)](https://badge.fury.io/js/react-native-avo-inspector)

182 lines (181 loc) 6.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventSpecCache = void 0; /** * EventSpecCache implements a dual-condition cache with LRU eviction. * * Cache Policy: * - TTL: Entries expire after 60 seconds * - Per-entry eviction: Entries retrieved 50+ times evicted immediately on next get * - Global sweep: Runs every 50 cache operations (get/set) * - Capacity: LRU eviction when size > 50 entries * - Null spec responses: cached (to avoid re-fetching) * - branchId flush: cache cleared when branchId changes (handled externally) * * Cache Key Format: ${apiKey}:${streamId}:${eventName} */ var EventSpecCache = /** @class */ (function () { function EventSpecCache(shouldLog) { if (shouldLog === void 0) { shouldLog = false; } /** Time-to-live in milliseconds (60 seconds) */ this.TTL_MS = 60 * 1000; /** Maximum cache hit count before per-entry eviction (50 hits) */ this.MAX_EVENT_COUNT = 50; /** Maximum number of cache entries */ this.MAX_ENTRIES = 50; /** Global cache operation counter to track when to sweep */ this.globalEventCount = 0; this.cache = new Map(); this.shouldLog = shouldLog; } /** * Generates a cache key from the provided parameters. */ EventSpecCache.prototype.generateKey = function (apiKey, streamId, eventName) { return "".concat(apiKey, ":").concat(streamId, ":").concat(eventName); }; /** * Retrieves an event spec response from the cache if it exists and is valid. * Returns undefined (cache miss) if the entry is missing. * Returns null if a null spec was cached (known absent). * Returns the spec if valid. * * On cache hit, increments the hit count for this entry and the global counter. */ EventSpecCache.prototype.get = function (apiKey, streamId, eventName) { var key = this.generateKey(apiKey, streamId, eventName); var entry = this.cache.get(key); if (!entry) { return undefined; } // Check if entry has expired by TTL if (this.isExpiredByTTL(entry)) { this.cache.delete(key); return undefined; } // Check per-entry eviction (50+ accesses) if (entry.eventCount >= this.MAX_EVENT_COUNT) { this.cache.delete(key); return undefined; } if (this.shouldLog) { console.log("[Avo Inspector] Cache hit for key: ".concat(key)); } // Update lastAccessed for LRU eviction entry.lastAccessed = Date.now(); // Increment hit count for this entry entry.eventCount++; this.globalEventCount++; // Global sweep every 50 operations if (this.globalEventCount >= this.MAX_EVENT_COUNT) { this.sweep(); this.globalEventCount = 0; } return entry.spec; }; /** * Stores an event spec response in the cache. * Null responses are cached to prevent re-fetching for known absent specs. */ EventSpecCache.prototype.set = function (apiKey, streamId, eventName, spec) { var key = this.generateKey(apiKey, streamId, eventName); // Enforce capacity limit with LRU eviction if (!this.cache.has(key) && this.cache.size >= this.MAX_ENTRIES) { this.evictLRU(); } var now = Date.now(); var entry = { spec: spec, timestamp: now, lastAccessed: now, eventCount: 0 }; this.cache.set(key, entry); this.globalEventCount++; // Global sweep every 50 operations if (this.globalEventCount >= this.MAX_EVENT_COUNT) { this.sweep(); this.globalEventCount = 0; } }; /** * Checks if a cache entry has expired by TTL (older than 60s). */ EventSpecCache.prototype.isExpiredByTTL = function (entry) { var age = Date.now() - entry.timestamp; return age > this.TTL_MS; }; /** * Sweeps the cache: removes all entries expired by TTL. */ EventSpecCache.prototype.sweep = function () { var _this = this; var keysToDelete = []; this.cache.forEach(function (entry, key) { if (_this.isExpiredByTTL(entry)) { keysToDelete.push(key); } }); for (var _i = 0, keysToDelete_1 = keysToDelete; _i < keysToDelete_1.length; _i++) { var key = keysToDelete_1[_i]; this.cache.delete(key); } }; /** * Evicts the least recently used cache entry based on lastAccessed timestamp. */ EventSpecCache.prototype.evictLRU = function () { if (this.cache.size === 0) { return; } var lruKey = null; var oldestAccessTime = Infinity; this.cache.forEach(function (entry, key) { if (entry.lastAccessed < oldestAccessTime) { oldestAccessTime = entry.lastAccessed; lruKey = key; } }); if (lruKey !== null) { this.cache.delete(lruKey); } }; /** * Clears all cached entries. */ EventSpecCache.prototype.clear = function () { this.cache.clear(); this.globalEventCount = 0; if (this.shouldLog) { console.log("[Avo Inspector] Cache cleared"); } }; /** * Returns the current size of the cache. */ EventSpecCache.prototype.size = function () { return this.cache.size; }; /** * Returns cache statistics for debugging. */ EventSpecCache.prototype.getStats = function () { var entries = []; var now = Date.now(); this.cache.forEach(function (entry, key) { entries.push({ key: key, age: now - entry.timestamp, lastAccessedAgo: now - entry.lastAccessed, eventCount: entry.eventCount }); }); return { size: this.cache.size, globalEventCount: this.globalEventCount, entries: entries }; }; return EventSpecCache; }()); exports.EventSpecCache = EventSpecCache;