/** * GoingsOn - View Cache Module * Generation-based invalidation cache for view switches. * Prevents redundant fetches when switching back to an already-loaded view. * * Usage: * if (GoingsOn.cache.isFresh('tasks')) return; * // ... fetch data ... * GoingsOn.cache.markLoaded('tasks'); * * // After a mutation: * GoingsOn.cache.invalidate('tasks'); */ (function() { 'use strict'; const STALE_MS = 30000; // 30-second max staleness // Generation counters per entity type — incremented by mutations const generations = {}; // Cache entries: { generation, timestamp } const entries = {}; /** * Check if cached data for an entity type is still fresh. * @param {string} entity - Entity type ('tasks', 'emails', etc.) * @returns {boolean} True if data is fresh and a refetch can be skipped */ function isFresh(entity) { const entry = entries[entity]; if (!entry) return false; if (entry.generation !== (generations[entity] || 0)) return false; if (Date.now() - entry.timestamp > STALE_MS) return false; return true; } /** * Mark an entity type as freshly loaded. Call after a successful data fetch. * @param {string} entity - Entity type */ function markLoaded(entity) { entries[entity] = { generation: generations[entity] || 0, timestamp: Date.now(), }; } /** * Invalidate one or more entity types, forcing the next load to refetch. * @param {...string} entities - Entity types to invalidate */ function invalidate(...entities) { for (const entity of entities) { generations[entity] = (generations[entity] || 0) + 1; } } /** * Invalidate all cached entity types (full cache bust). */ function invalidateAll() { for (const key of Object.keys(generations)) { generations[key]++; } for (const key of Object.keys(entries)) { if (!(key in generations)) { generations[key] = 1; } } } GoingsOn.cache = { isFresh, markLoaded, invalidate, invalidateAll, }; })();