// Service worker: la app abre sin conexión (shell en caché) y los capítulos guardados "en este // dispositivo" (caché OFFLINE, la llena app.js) se leen sin red. const SHELL = 'shell-v1' const OFFLINE = 'offline-v1' const SHELL_FILES = ['/', '/app.js', '/style.css', '/icon.svg', '/manifest.webmanifest', '/icon-192.png', '/icon-512.png'] self.addEventListener('install', e => { e.waitUntil(caches.open(SHELL).then(c => c.addAll(SHELL_FILES)).then(() => self.skipWaiting())) }) self.addEventListener('activate', e => { e.waitUntil(caches.keys() .then(keys => Promise.all(keys.filter(k => k !== SHELL && k !== OFFLINE).map(k => caches.delete(k)))) .then(() => self.clients.claim())) }) // Red primero (así siempre se ve la última versión) y la caché si no hay conexión. async function networkFirst(req, cacheName, { store = true, ignoreSearch = false, fallback } = {}) { try { const res = await fetch(req) if (store && res.ok) { const c = await caches.open(cacheName) if (store === true || (await c.match(req, { ignoreSearch }))) c.put(req, res.clone()) } return res } catch (err) { const hit = await caches.match(req, { ignoreSearch, cacheName }) || (fallback && await caches.match(fallback)) if (hit) return hit throw err } } self.addEventListener('fetch', e => { const req = e.request if (req.method !== 'GET') return const url = new URL(req.url) if (url.origin !== location.origin) return const p = url.pathname if (req.mode === 'navigate') return e.respondWith(networkFirst(req, SHELL, { fallback: '/' })) if (SHELL_FILES.includes(p) || p === '/sw.js') return e.respondWith(networkFirst(req, SHELL)) if (p === '/api/me') return e.respondWith(networkFirst(req, SHELL)) // Ficha y capítulo: solo se guardan si el usuario los guardó (store: 'existing' = refrescar si ya estaban). if (p.startsWith('/api/manga/')) return e.respondWith(networkFirst(req, OFFLINE, { store: 'existing', ignoreSearch: true })) if (p.startsWith('/api/chapter/')) return e.respondWith(networkFirst(req, OFFLINE, { store: false, ignoreSearch: true })) // Imágenes: si están guardadas, sin red (más rápido y sin gastar datos). if (p.startsWith('/api/local/') || p.startsWith('/api/img') || p.startsWith('/api/local-cover/')) { e.respondWith(caches.open(OFFLINE).then(c => c.match(req)).then(hit => hit || fetch(req))) } })