1importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.3/workbox-sw.js'); 2importScripts('https://www.livehindustan.com/lh-img/smart/specials/firebase/prod/ht-webpush-sdk.js'); 3 4 5/* AMP Notification Code */ 6self.addEventListener('message', function(event) { 7 if (!event.data || !event.data.command || !event.ports || !event.ports[0]) return; 8 var port = event.ports[0]; 9 if (event.data.command === 'amp-web-push-subscription-state') { 10 if (Notification.permission === 'denied') { 11 port.postMessage(true); 12 } else { 13 self.registration.pushManager.getSubscription().then(function(sub) { 14 port.postMessage(sub ? true : false); 15 }); 16 } 17 } else if (event.data.command === 'amp-web-push-subscribe') { 18 self.registration.pushManager.getSubscription().then(function(sub) { 19 port.postMessage(sub ? true : false); 20 }); 21 } else if (event.data.command === 'amp-web-push-unsubscribe') { 22 self.registration.pushManager.getSubscription().then(function(sub) { 23 if (sub) sub.unsubscribe(); 24 port.postMessage(true); 25 }); 26 } 27 }); 28/* AMP Notification Code */ 29 30 31 32if (self.workbox) { 33 if (workbox.navigationPreload) { 34 workbox.navigationPreload.enable(); 35 } 36 37 // Offline analytics âââ‰â¬Â moved inside guard so it doesn't throw when workbox is absent 38 // workbox.googleAnalytics.initialize({ 39 // parameterOverrides: { 40 // cd13: 'offline', 41 // }, 42 // hitFilter: (params) => { 43 // const queueTimeInSeconds = Math.round(params.get('qt') / 1000); 44 // params.set('cm3', queueTimeInSeconds); 45 // }, 46 // }); 47 48 // Storage quota management 49 const checkStorageQuota = async () => { 50 if ('storage' in navigator && 'estimate' in navigator.storage) { 51 const estimate = await navigator.storage.estimate(); 52 const percentUsed = (estimate.usage / estimate.quota) * 100; 53 console.log(`Storage quota: ${percentUsed.toFixed(2)}% used`); 54 55 // If storage is over 80% full, clean up caches 56 if (percentUsed > 80) { 57 console.log('Storage quota high, cleaning up old caches'); 58 const cacheNames = await caches.keys(); 59 const oldCaches = cacheNames.filter(name => 60 !name.includes('v3') && ( 61 name.includes('cache') || 62 name.includes('image') || 63 name.includes('pages') 64 ) 65 ); 66 await Promise.all(oldCaches.map(cache => caches.delete(cache))); 67 } 68 } 69 }; 70 71 // Check quota on startup 72 self.addEventListener('install', (event) => { 73 event.waitUntil(checkStorageQuota()); 74 }); 75 76 // Cache CSS files âââ‰â¬Â StaleWhileRevalidate serves from cache instantly on 77 // repeat visits (eliminates render-blocking delay for LCP) while refreshing 78 // the cache in the background for the next load. 79 workbox.routing.registerRoute( 80 ({ request }) => request.destination === 'style', 81 new workbox.strategies.StaleWhileRevalidate({ 82 cacheName: 'css-cache-v3', 83 plugins: [ 84 new workbox.expiration.ExpirationPlugin({ 85 maxEntries: 20, // Reduced from 50 86 maxAgeSeconds: 3 * 24 * 60 * 60, // Reduced to 3 days 87 purgeOnQuotaError: true, // Auto-cleanup on quota error 88 }), 89 new workbox.cacheableResponse.CacheableResponsePlugin({ 90 statuses: [0, 200], 91 }), 92 ], 93 }) 94 ); 95 96 // Cache images with reduced limits and size restrictions 97 workbox.routing.registerRoute(
98 new RegExp('^https://www.livehindustan.com/(.*)\\.(?:png|webp|jpg|jpeg|svg|gif|ico|pdf|JPG|JPEG|avif)'), 99 new workbox.strategies.CacheFirst({ 100 cacheName: 'lh-image-cache-v3', 101 plugins: [ 102 new workbox.expiration.ExpirationPlugin({ 103 maxEntries: 200, 104 maxAgeSeconds: 7 * 24 * 60 * 60, 105 purgeOnQuotaError: true, // Auto-cleanup on quota error 106 }), 107 new workbox.cacheableResponse.CacheableResponsePlugin({ 108 statuses: [0, 200], 109 }), 110 ], 111 }) 112 ); 113 114 workbox.routing.registerRoute( 115 new RegExp('^https://images.livehindustan.com/(.*)\\.(?:png|webp|jpg|jpeg|svg|gif|ico|pdf|JPG|JPEG|avif)'), 116 new workbox.strategies.CacheFirst({ 117 cacheName: 'image1-cache-v3', 118 plugins: [ 119 new workbox.expiration.ExpirationPlugin({ 120 maxEntries: 50, // Reduced from 200 121 maxAgeSeconds: 3 * 24 * 60 * 60, // Reduced to 3 days 122 purgeOnQuotaError: true, // Auto-cleanup on quota error 123 }), 124 new workbox.cacheableResponse.CacheableResponsePlugin({ 125 statuses: [0, 200], 126 }), 127 ], 128 }) 129 ); 130 131 // Next.js JS files are content-hashed (immutable), so serving from cache 132 // is safe. StaleWhileRevalidate avoids the network-first delay that adds 133 // to TBT on repeat visits. 134 workbox.routing.registerRoute( 135 ({ url }) => 136 (url.pathname.includes('/_next/') && url.pathname.endsWith('.js')) || 137 url.origin === 'https://cdn.ampproject.org', 138 new workbox.strategies.StaleWhileRevalidate({ 139 cacheName: 'www-next-js-cache', 140 plugins: [ 141 new workbox.expiration.ExpirationPlugin({ 142 maxEntries: 50, 143 maxAgeSeconds: 3 * 24 * 60 * 60, // 3 days 144 purgeOnQuotaError: true, 145 }), 146 new workbox.cacheableResponse.CacheableResponsePlugin({ 147 statuses: [0, 200], 148 }), 149 ], 150 }) 151 ); 152 153 workbox.precaching.precacheAndRoute([ 154 { 155 url: '/static-content/1y/lh/img/lh-logo-m.webp', 156 revision: '1', 157 }, 158 { 159 url: '/static-content/1y/lh/img/favicon-96x96.ico', 160 revision: '1', 161 }, 162 ]); 163 164 165 166 167 const pageHandler = new workbox.strategies.NetworkFirst({ 168 cacheName: 'pages-cache-v3', 169 plugins: [ 170 new workbox.expiration.ExpirationPlugin({ 171 maxEntries: 50, 172 maxAgeSeconds: 1 * 24 * 60 * 60, // 1day 173 purgeOnQuotaError: true, // Auto-cleanup on quota error 174 }), 175 ], 176 }); 177 178 // Defining URL patterns for general page routes to cache. 179 const pageRoutes = [ 180 '/', 181 '/entertainment', 182 '/national', 183 '/state', 184 '/international', 185 '/cricket', 186 '/sports', 187 '/astrology', 188 '/business', 189 '/gallery', 190 '/career', 191 '/health', 192 '/lifestyle', 193 '/blog', 194 '/gadgets', 195 '/auto', 196 '/crime', 197 '/weather', 198 '/uttar-pradesh/news' 199 ]; 200 201 // Register routes for caching general page routes. 202 pageRoutes.forEach((route) => workbox.routing.registerRoute(route, pageHandler)); 203 204 // Activate new SW immediately so perf fixes reach users without 205 // waiting for all tabs to close. 206 self.addEventListener('install', (event) => { 207 self.skipWaiting(); 208 }); 209 210 // Handle activating and deleting old caches (cleanup) 211 self.addEventListener('activate', (event) => { 212 const currentCaches = [ 213 'css-cache-v3', 214 'image1-cache-v3', 215 'lh-image-cache-v3', 216 'pages-cache-v3', 217 'www-next-js-cache', 218 ]; 219 event.waitUntil( 220 Promise.all([ 221 self.clients.claim(), 222 caches.keys().then((cacheNames) => { 223 return Promise.all( 224 cacheNames.map((cacheName) => { 225 if (!currentCaches.includes(cacheName)) { 226 console.log('Deleting old cache: ', cacheName); 227 return caches.delete(cacheName); 228 } 229 }) 230 ); 231 }), 232 ]) 233 ); 234 }); 235 236 // Add quota management 237 self.addEventListener('message', (event) => { 238 if (event.data && event.data.type === 'CLEAR_CACHE') { 239 event.waitUntil( 240 caches.keys().then((cacheNames) => { 241 return Promise.all( 242 cacheNames.map((cacheName) => { 243 console.log('Clearing cache: ', cacheName); 244 return caches.delete(cacheName); 245 }) 246 ); 247 }) 248 ); 249 } 250 }); 251 252 // Handle quota exceeded errors 253 self.addEventListener('error', (event) => { 254 if (event.error && event.error.name === 'QuotaExceededError') { 255 console.log('Quota exceeded, cleaning up caches'); 256 event.waitUntil( 257 caches.keys().then((cacheNames) => { 258 // Delete oldest caches first 259 const oldCaches = cacheNames.filter(name => 260 !name.includes('v3') && ( 261 name.includes('cache') || 262 name.includes('image') || 263 name.includes('pages') 264 ) 265 ); 266 return Promise.all( 267 oldCaches.map(cacheName => { 268 console.log('Emergency cleanup: ', cacheName); 269 return caches.delete(cacheName); 270 }) 271 ); 272 }) 273 ); 274 } 275 }); 276} else { 277 console.log('Workbox could not be loaded'); 278}
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.