/** * Termix Service Worker * Handles caching for offline PWA support */ const CACHE_NAME = "termix-v1"; const STATIC_ASSETS = [ "/", "/index.html", "/manifest.json", "/favicon.ico", "/icons/48x48.png", "/icons/128x128.png", "/icons/256x256.png", "/icons/512x512.png", ]; // Install event - cache static assets self.addEventListener("install", (event) => { event.waitUntil( caches .open(CACHE_NAME) .then((cache) => { console.log("[SW] Caching static assets"); return cache.addAll(STATIC_ASSETS); }) .then(() => { // Activate immediately without waiting return self.skipWaiting(); }), ); }); // Activate event - clean up old caches self.addEventListener("activate", (event) => { event.waitUntil( caches .keys() .then((cacheNames) => { return Promise.all( cacheNames .filter((name) => name !== CACHE_NAME) .map((name) => { console.log("[SW] Deleting old cache:", name); return caches.delete(name); }), ); }) .then(() => { // Take control of all pages immediately return self.clients.claim(); }), ); }); // Fetch event - serve from cache, fall back to network self.addEventListener("fetch", (event) => { const { request } = event; const url = new URL(request.url); // Skip non-GET requests if (request.method !== "GET") { return; } // Skip API requests - these must be online if (url.pathname.startsWith("/api/") || url.pathname.startsWith("/ws")) { return; } // Skip cross-origin requests if (url.origin !== self.location.origin) { return; } // For navigation requests (HTML), use network-first if (request.mode === "navigate") { event.respondWith( fetch(request) .then((response) => { // Clone and cache the response const responseClone = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone); }); return response; }) .catch(() => { // Offline: return cached index.html return caches.match("/index.html"); }), ); return; } // For all other assets, use cache-first event.respondWith( caches.match(request).then((cachedResponse) => { if (cachedResponse) { return cachedResponse; } // Not in cache, fetch from network return fetch(request).then((response) => { // Don't cache non-successful responses if (!response || response.status !== 200 || response.type !== "basic") { return response; } // Clone and cache the response const responseClone = response.clone(); caches.open(CACHE_NAME).then((cache) => { cache.put(request, responseClone); }); return response; }); }), ); });