1/* 2 * Anahuac RV Park â Portal Service Worker 3 * Handles push notifications, notification clicks, and app badge updates. 4 */ 5 6var CACHE_VERSION = 'portal-v14'; 7 8self.addEventListener('install', () => { self.skipWaiting(); }); 9self.addEventListener('activate', (event) => { 10 event.waitUntil( 11 Promise.all([ 12 // Delete old portal caches only (don't touch admin's rvpark-* caches) 13 caches.keys().then(function(keys) { 14 return Promise.all(keys.filter(function(k) { return k !== CACHE_VERSION && k.startsWith('portal-'); }).map(function(k) { return caches.delete(k); })); 15 }), 16 self.clients.claim() 17 ]) 18 ); 19}); 20 21// Never cache HTML or API â always fetch fresh 22self.addEventListener('fetch', (event) => { 23 var url = new URL(event.request.url); 24 if (url.pathname.endsWith('.html') || url.pathname.startsWith('/api/') || url.pathname === '/portal') { 25 return; // Let the browser handle normally (network only) 26 } 27 // Self-destruct kill switch 28 if (url.searchParams.has('_nuke_sw')) { 29 event.respondWith( 30 self.registration.unregister().then(function() { return caches.keys(); }).then(function(keys) { return Promise.all(keys.map(function(k) { return caches.delete(k); })); }).then(function() { return fetch(event.request); }) 31 ); 32 return; 33 } 34 // All other requests: default browser behavior (no custom caching) 35}); 36 37// Push notification handler 38self.addEventListener('push', (event) => { 39 if (!event.data) return; 40 41 let data; 42 try { data = event.data.json(); } catch { return; } 43 44 const options = { 45 body: data.body || '', 46 icon: data.icon || '/icons/icon-192x192.png', 47 badge: '/icons/favicon-32x32.png', 48 tag: data.tag || 'general', 49 data: { url: data.url || '/portal' }, 50 requireInteraction: data.priority === 'critical', 51 vibrate: data.priority === 'critical' ? [200, 100, 200, 100, 200] : [100], 52 renotify: true, 53 }; 54 55 event.waitUntil( 56 self.registration.showNotification(data.title || 'Anahuac RV Park', options) 57 ); 58 59 // Update badge count on the app icon 60 if (self.navigator && self.navigator.setAppBadge && data.badge_count != null) { 61 try { self.navigator.setAppBadge(data.badge_count); } catch {} 62 } 63}); 64 65// Notification click handler â open or focus the portal 66self.addEventListener('notificationclick', (event) => { 67 event.notification.close(); 68 const targetUrl = event.notification.data?.url || '/portal'; 69 70 event.waitUntil( 71 self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((windowClients) => { 72 for (const client of windowClients) { 73 if (client.url.includes('/portal') && 'focus' in client) { 74 client.navigate(targetUrl); 75 return client.focus(); 76 } 77 } 78 if (self.clients.openWindow) { 79 return self.clients.openWindow(targetUrl); 80 } 81 }) 82 ); 83});
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.