// DAARION Service Worker v1.0 const CACHE_VERSION = 'v1'; const STATIC_CACHE = `daarion-static-${CACHE_VERSION}`; const PAGES_CACHE = `daarion-pages-${CACHE_VERSION}`; // Files to precache const PRECACHE_URLS = [ '/', '/city', '/offline', '/manifest.json', '/icons/icon-192x192.png', '/icons/icon-512x512.png' ]; // Install event - precache static assets self.addEventListener('install', (event) => { console.log('[SW] Installing...'); event.waitUntil( caches.open(STATIC_CACHE) .then((cache) => { console.log('[SW] Precaching app shell'); return cache.addAll(PRECACHE_URLS); }) .then(() => self.skipWaiting()) ); }); // Activate event - clean old caches self.addEventListener('activate', (event) => { console.log('[SW] Activating...'); event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames .filter((name) => name.startsWith('daarion-') && name !== STATIC_CACHE && name !== PAGES_CACHE) .map((name) => { console.log('[SW] Deleting old cache:', name); return caches.delete(name); }) ); }).then(() => self.clients.claim()) ); }); // Fetch event - handle requests self.addEventListener('fetch', (event) => { const { request } = event; const url = new URL(request.url); // Skip non-GET requests if (request.method !== 'GET') return; // Skip API and WebSocket requests if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/ws/') || url.pathname.startsWith('/_matrix/')) { return; } // Static assets - Cache First if (url.pathname.startsWith('/_next/static/') || url.pathname.match(/\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2)$/)) { event.respondWith(cacheFirst(request, STATIC_CACHE)); return; } // HTML pages - Network First with fallback if (request.headers.get('accept')?.includes('text/html')) { event.respondWith(networkFirstWithFallback(request, PAGES_CACHE)); return; } // Default - try network event.respondWith(fetch(request)); }); // Cache First strategy async function cacheFirst(request, cacheName) { const cachedResponse = await caches.match(request); if (cachedResponse) { // Update cache in background fetch(request).then((response) => { if (response.ok) { caches.open(cacheName).then((cache) => cache.put(request, response)); } }).catch(() => {}); return cachedResponse; } try { const response = await fetch(request); if (response.ok) { const cache = await caches.open(cacheName); cache.put(request, response.clone()); } return response; } catch (error) { console.log('[SW] Cache first failed:', request.url); throw error; } } // Network First with fallback strategy async function networkFirstWithFallback(request, cacheName) { try { const response = await fetch(request); if (response.ok) { const cache = await caches.open(cacheName); cache.put(request, response.clone()); } return response; } catch (error) { console.log('[SW] Network failed, trying cache:', request.url); const cachedResponse = await caches.match(request); if (cachedResponse) { return cachedResponse; } // Return offline page for navigation requests const offlineResponse = await caches.match('/offline'); if (offlineResponse) { return offlineResponse; } // Return a basic offline response return new Response( '
Перевірте підключення до інтернету
', { status: 503, headers: { 'Content-Type': 'text/html; charset=utf-8' } } ); } }