1- const CACHE_VERSION = "v18 " ; // Increment this when you have new features
1+ const CACHE_VERSION = "v19 " ; // Increment this when you have new features
22const STATIC_CACHE = `andromeda-static-${ CACHE_VERSION } ` ;
33const DYNAMIC_CACHE = `andromeda-dynamic-${ CACHE_VERSION } ` ;
44
5+ // Detect local development host where we don't want service worker caching
6+ const IS_LOCALHOST_DEV = ( self . location && self . location . hostname === "localhost" && self . location . port === "8000" ) ;
7+
58// Define what to cache
69const STATIC_ASSETS = [
710 // Core pages
@@ -85,6 +88,12 @@ const CACHEABLE_PATTERNS = [
8588// Install event - cache static assets
8689self . addEventListener ( "install" , ( event ) => {
8790 console . log ( "[SW] Installing service worker..." ) ;
91+ if ( IS_LOCALHOST_DEV ) {
92+ console . log ( "[SW] Detected localhost:8000 - skipping precache in dev mode" ) ;
93+ // Just skip waiting so dev reloads aren't blocked by precache
94+ event . waitUntil ( self . skipWaiting ( ) ) ;
95+ return ;
96+ }
8897
8998 event . waitUntil (
9099 Promise . all ( [
@@ -144,23 +153,14 @@ self.addEventListener("install", (event) => {
144153 }
145154 }
146155
147- // Cache discovered documentation pages
148- return caches . open ( DYNAMIC_CACHE )
149- . then ( ( cache ) => {
150- console . log (
151- "[SW] Caching discovered documentation pages:" ,
152- docUrls ,
153- ) ;
154- return Promise . allSettled (
155- docUrls . map ( ( url ) =>
156- fetch ( url )
157- . then ( ( response ) =>
158- response . ok ? cache . put ( url , response ) : null
159- )
160- . catch ( ( ) => null )
161- ) ,
162- ) ;
163- } ) ;
156+ // Cache discovered documentation pages (use cache helper)
157+ return Promise . allSettled (
158+ docUrls . map ( ( url ) =>
159+ fetch ( url )
160+ . then ( ( response ) => ( response . ok ? cacheIfAllowed ( url , response ) : null ) )
161+ . catch ( ( ) => null )
162+ ) ,
163+ ) ;
164164 } )
165165 . catch ( ( ) =>
166166 console . log ( "[SW] Could not discover documentation pages" )
@@ -215,15 +215,20 @@ self.addEventListener("fetch", (event) => {
215215 return ;
216216 }
217217
218+ // If running on localhost:8000 during development, always go to network
219+ if ( IS_LOCALHOST_DEV ) {
220+ event . respondWith ( fetch ( request ) ) ;
221+ return ;
222+ }
223+
218224 // Network-first strategy for dynamic content
219225 if ( NETWORK_FIRST . some ( ( path ) => url . pathname . startsWith ( path ) ) ) {
220226 event . respondWith (
221227 fetch ( request )
222228 . then ( ( response ) => {
223229 if ( response . ok ) {
224230 const responseClone = response . clone ( ) ;
225- caches . open ( DYNAMIC_CACHE )
226- . then ( ( cache ) => cache . put ( request , responseClone ) ) ;
231+ cacheIfAllowed ( request , responseClone ) ;
227232 }
228233 return response ;
229234 } )
@@ -246,8 +251,7 @@ self.addEventListener("fetch", (event) => {
246251 if ( response . ok ) {
247252 // Cache the fresh response
248253 const responseClone = response . clone ( ) ;
249- caches . open ( DYNAMIC_CACHE )
250- . then ( ( cache ) => cache . put ( request , responseClone ) ) ;
254+ cacheIfAllowed ( request , responseClone ) ;
251255 return response ;
252256 }
253257
@@ -323,10 +327,7 @@ self.addEventListener("fetch", (event) => {
323327 const responseClone = response . clone ( ) ;
324328
325329 // Cache the response
326- caches . open ( DYNAMIC_CACHE )
327- . then ( ( cache ) => {
328- cache . put ( request , responseClone ) ;
329- } ) ;
330+ cacheIfAllowed ( request , responseClone ) ;
330331
331332 return response ;
332333 } )
@@ -344,6 +345,36 @@ self.addEventListener("fetch", (event) => {
344345 ) ;
345346} ) ;
346347
348+ // Trim cache helper
349+ async function trimCache ( cacheName , maxItems ) {
350+ const cache = await caches . open ( cacheName ) ;
351+ const keys = await cache . keys ( ) ;
352+ if ( keys . length > maxItems ) {
353+ const deleteCount = keys . length - maxItems ;
354+ for ( let i = 0 ; i < deleteCount ; i ++ ) {
355+ await cache . delete ( keys [ i ] ) ;
356+ }
357+ }
358+ }
359+
360+ // Cache response helper: skip images, videos, fonts to avoid large caches
361+ async function cacheIfAllowed ( request , response , cacheName = DYNAMIC_CACHE , maxItems = 50 ) {
362+ try {
363+ if ( ! response || ! response . ok ) return ;
364+ const ct = ( response . headers && response . headers . get && response . headers . get ( "content-type" ) ) || "" ;
365+ if ( ct . startsWith ( "image/" ) || ct . includes ( "video" ) || ct . includes ( "font" ) || ct . includes ( "audio" ) ) {
366+ // skip caching large media files
367+ return ;
368+ }
369+ const cache = await caches . open ( cacheName ) ;
370+ await cache . put ( request , response . clone ( ) ) ;
371+ await trimCache ( cacheName , maxItems ) ;
372+ } catch ( e ) {
373+ // Don't let caching failures break the response
374+ console . warn ( "[SW] cacheIfAllowed failed" , e ) ;
375+ }
376+ }
377+
347378// Helper function to generate offline pages
348379function generateOfflinePage ( title , message ) {
349380 return new Response (
0 commit comments