1 2// Service Worker for Whisper Chat 3const CACHE_NAME = 'whisper-chat-v1.2'; // Updated version 4const RUNTIME = 'runtime'; 5const SECURITY_HEADERS = { 6 'Content-Security-Policy': "default-src 'self'", 7 'X-Content-Type-Options': 'nosniff', 8 'X-Frame-Options': 'DENY', 9 'Referrer-Policy': 'no-referrer' 10}; 11 12const urlsToCache = [ 13 '/', 14 '/index.html', 15 '/manifest.json', 16 '/favicon.ico' 17]; 18 19// Force HTTPS for all requests in production 20const secureRequest = (request) => { 21 // Skip localhost for development 22 if (self.location.hostname === 'localhost') { 23 return request; 24 } 25 26 // Check if the URL is HTTP and not HTTPS 27 const url = new URL(request.url); 28 if (url.protocol === 'http:' && url.hostname !== 'localhost') { 29 // Replace with HTTPS version of the same URL 30 url.protocol = 'https:'; 31 return new Request(url.toString(), request); 32 } 33 34 return request; 35}; 36 37// Install event - cache basic resources 38self.addEventListener('install', event => { 39 // Skip waiting to avoid blocking the app 40 self.skipWaiting(); 41 42 event.waitUntil( 43 caches.open(CACHE_NAME) 44 .then(cache => { 45 console.log('Cache opened'); 46 return cache.addAll(urlsToCache); 47 }) 48 .catch(error => { 49 console.error('Error during service worker install:', error); 50 }) 51 ); 52}); 53 54// Activate event - clean up old caches and take control 55self.addEventListener('activate', event => { 56 // Take control immediately 57 event.waitUntil(self.clients.claim()); 58 59 // Clean up old caches 60 event.waitUntil( 61 caches.keys().then(cacheNames => { 62 return Promise.all( 63 cacheNames.map(cacheName => { 64 if (cacheName !== CACHE_NAME) { 65 console.log('Deleting old cache:', cacheName); 66 return caches.delete(cacheName); 67 } 68 }) 69 ); 70 }) 71 ); 72}); 73 74// Helper function to add security headers to response 75const addSecurityHeaders = (response) => { 76 if (!response || !response.headers) { 77 return response; 78 } 79 80 // Clone the response to make it mutable 81 const responseWithHeaders = response.clone(); 82 const headers = new Headers(responseWithHeaders.headers); 83 84 // Add security headers 85 Object.keys(SECURITY_HEADERS).forEach(key => { 86 headers.set(key, SECURITY_HEADERS[key]); 87 }); 88 89 // Create new Response with the enhanced headers 90 return new Response(responseWithHeaders.body, { 91 status: responseWithHeaders.status, 92 statusText: responseWithHeaders.statusText, 93 headers: headers 94 }); 95}; 96 97// Simplified fetch event handler to prevent blocking app loading 98self.addEventListener('fetch', event => { 99 // Only handle GET requests 100 if (event.request.method !== 'GET') { 101 return; 102 } 103 104 // Try to serve from cache first, fallback to network 105 event.respondWith( 106 caches.match(event.request) 107 .then(response => { 108 if (response) { 109 return response; 110 } 111 112 // Try network and cache result 113 return fetch(event.request) 114 .then(networkResponse => { 115 if (!networkResponse || networkResponse.status !== 200) { 116 return networkResponse; 117 } 118 119 // Cache a copy of the response 120 const responseToCache = networkResponse.clone(); 121 122 caches.open(RUNTIME) 123 .then(cache => { 124 cache.put(event.request, responseToCache); 125 }) 126 .catch(() => { 127 // Fail silently if cache put fails 128 }); 129 130 return networkResponse; 131 }) 132 .catch(() => { 133 // Fallback for navigation requests 134 if (event.request.mode === 'navigate') { 135 return caches.match('/index.html'); 136 } 137 138 // Let the error bubble up for other requests 139 return new Response('Network error', { status: 408 }); 140 }); 141 }) 142 ); 143}); 144 145// Add event listener for messages from clients 146self.addEventListener('message', event => { 147 if (event.data && event.data.type === 'SKIP_WAITING') {
148 self.skipWaiting(); 149 } 150});
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.