1// sw.js 2const VC_VERSION = 'vc-pwa-2026-09-10'; 3const STATIC_CACHE = `static-${VC_VERSION}`; 4const RUNTIME_CACHE = `runtime-${VC_VERSION}`; 5 6const PRECACHE = [ 7 '/', '/index.html', '/style.css', '/main.js', 8 '/manifest.json', '/favicon.ico', '/icon-192x192.png', '/icon-512x512.png', 9 '/offline.html' 10]; 11 12self.addEventListener('install', (e) => { 13 e.waitUntil((async () => { 14 const c = await caches.open(STATIC_CACHE); 15 await c.addAll(PRECACHE); 16 self.skipWaiting(); // ð¸ listo para activar ya 17 })()); 18}); 19 20self.addEventListener('activate', (e) => { 21 e.waitUntil((async () => { 22 const keys = await caches.keys(); 23 await Promise.all(keys.map(k => { 24 if (!k.includes(VC_VERSION)) return caches.delete(k); 25 })); 26 await self.clients.claim(); // ð¸ controlar todas las pestañas 27 })()); 28}); 29 30self.addEventListener('message', (event) => { 31 if (event.data && event.data.type === 'SKIP_WAITING') { 32 self.skipWaiting(); 33 } 34}); 35 36// Utilidades simples 37const isHTML = (req) => req.destination === 'document' || req.headers.get('accept')?.includes('text/html'); 38const isStatic = (req) => ['script','style','image','font'].includes(req.destination); 39const isFeed = (url) => /feed-proxy\.php/i.test(url) || url.endsWith('.json'); 40 41// Estrategias 42self.addEventListener('fetch', (e) => { 43 const req = e.request; 44 const url = new URL(req.url); 45 46 // No cachear peticiones con no-store 47 if (req.cache === 'no-store') return; 48 49 // 1) FEED/JSON: NETWORK-FIRST (sin cachear) 50 if (isFeed(url.href) || url.pathname.startsWith('/api/') || url.pathname.endsWith('.json')) { 51 e.respondWith((async () => { 52 try { 53 const net = await fetch(req, { cache: 'no-store' }); 54 return net; 55 } catch { 56 // fallback: intenta cache (por si hay algo) 57 const c = await caches.match(req); 58 return c || new Response(JSON.stringify({ error:true, message:'offline' }), { headers:{'Content-Type':'application/json'} }); 59 } 60 })()); 61 return; 62 } 63 64 // 2) HTML: NETWORK-FIRST con fallback a caché/offline 65 if (isHTML(req)) { 66 e.respondWith((async () => { 67 try { 68 const net = await fetch(req, { cache: 'no-store' }); 69 const cache = await caches.open(RUNTIME_CACHE); 70 cache.put(req, net.clone()); 71 return net; 72 } catch { 73 const cached = await caches.match(req); 74 return cached || caches.match('/offline.html'); 75 } 76 })()); 77 return; 78 } 79 80 // 3) Estáticos: STALE-WHILE-REVALIDATE 81 if (isStatic(req)) { 82 e.respondWith((async () => { 83 const cache = await caches.open(RUNTIME_CACHE); 84 const cached = await cache.match(req); 85 const fetchPromise = fetch(req).then(res => { 86 cache.put(req, res.clone()); 87 return res; 88 }).catch(()=>null); 89 return cached || fetchPromise || fetch(req); 90 })()); 91 return; 92 } 93 94 // Por defecto: pasar 95});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.