11/**
22 * Chamilo Service Worker
33 * Handles:
4- * - Offline caching
54 * - Push notifications
5+ * - (Optional) Network fallback response when offline
66 *
77 * Notes:
8- * - We avoid caching or intercepting dynamic endpoints (/api, /themes) to prevent noisy console logs
8+ * - We avoid intercepting dynamic endpoints (/api, /themes) to prevent noisy console logs
99 * when responses are 404 (expected in strict checks) or 202 (async endpoints).
10- * - We only cache successful GET responses (res.ok) .
10+ * - We do NOT store responses. This prevents stale navigation/session issues .
1111 */
1212
13- const CACHE_NAME = "chamilo-cache-v1"
1413const PRECACHE_URLS = [
1514 "/" ,
1615 "/manifest.json" ,
1716 "/img/pwa-icons/icon-192.png" ,
1817 "/img/pwa-icons/icon-512.png" ,
1918]
2019
21- // PWA: Cache basic files on install
20+ // PWA: Keep install/activate flow (no persistent storage)
2221self . addEventListener ( "install" , ( event ) => {
2322 console . log ( "[Service Worker] Install event" )
2423
24+ // Validate basic URLs at install time to fail fast if something is missing.
25+ // We intentionally do not store anything.
2526 event . waitUntil (
26- caches . open ( CACHE_NAME ) . then ( ( cache ) => {
27- return cache . addAll ( PRECACHE_URLS )
28- } )
27+ Promise . all (
28+ PRECACHE_URLS . map ( async ( url ) => {
29+ try {
30+ await fetch ( url , { cache : "no-store" } )
31+ } catch ( e ) {
32+ // Best-effort: do not block SW install if a non-critical asset fails
33+ }
34+ } )
35+ )
2936 )
3037
3138 // Activate updated SW ASAP
@@ -35,22 +42,7 @@ self.addEventListener("install", (event) => {
3542self . addEventListener ( "activate" , ( event ) => {
3643 console . log ( "[Service Worker] Activate event" )
3744
38- event . waitUntil (
39- ( async ( ) => {
40- // Cleanup old caches if cache name changes in the future
41- const keys = await caches . keys ( )
42- await Promise . all (
43- keys . map ( ( key ) => {
44- if ( key !== CACHE_NAME ) {
45- return caches . delete ( key )
46- }
47- return Promise . resolve ( )
48- } )
49- )
50-
51- await self . clients . claim ( )
52- } ) ( )
53- )
45+ event . waitUntil ( self . clients . claim ( ) )
5446} )
5547
5648/**
@@ -60,28 +52,32 @@ self.addEventListener("activate", (event) => {
6052function shouldBypass ( request ) {
6153 const url = new URL ( request . url )
6254
55+ // Do not handle non-GET requests
56+ if ( request . method !== "GET" ) return true
57+
6358 // Ignore internal redirect helper routes
6459 if ( url . pathname . startsWith ( "/r/" ) ) return true
6560
66- // Avoid intercepting theme assets (prevents console noise for strict 404 checks)
61+ // Avoid intercepting theme assets/endpoints
6762 if ( url . pathname . startsWith ( "/themes/" ) ) return true
6863
69- // Avoid intercepting API calls (can return 202 or other statuses that shouldn't be cached)
64+ // Avoid intercepting API calls
7065 if ( url . pathname . startsWith ( "/api/" ) ) return true
7166
72- // Avoid strict probing calls anywhere (expected 404 should not produce SW noise)
67+ // Avoid strict probing calls anywhere
7368 if ( url . searchParams . has ( "strict" ) ) return true
7469
75- // Do not handle non-GET requests
76- if ( request . method !== "GET" ) return true
70+ // Never intercept HTML navigations/documents (prevents any navigation impact)
71+ if ( request . mode === "navigate" || request . destination === "document" ) return true
72+ const accept = request . headers . get ( "accept" ) || ""
73+ if ( accept . includes ( "text/html" ) ) return true
7774
7875 return false
7976}
8077
8178/**
82- * Cache-first for static navigations/assets, network fallback.
83- * - Only caches successful responses (res.ok).
84- * - If network fails, returns cache if available.
79+ * Network-first (no storage), with graceful offline responses.
80+ * This avoids stale resources while still providing a friendly offline fallback.
8581 */
8682self . addEventListener ( "fetch" , ( event ) => {
8783 const request = event . request
@@ -94,37 +90,21 @@ self.addEventListener("fetch", (event) => {
9490 event . respondWith (
9591 ( async ( ) => {
9692 try {
97- const cachedResponse = await caches . match ( request )
98- if ( cachedResponse ) {
99- return cachedResponse
100- }
101-
102- const response = await fetch ( request )
103-
104- // Cache only successful responses
105- if ( response && response . ok ) {
106- const cache = await caches . open ( CACHE_NAME )
107- await cache . put ( request , response . clone ( ) )
108- }
109-
110- return response
93+ // Always go to network (no SW storage)
94+ return await fetch ( request )
11195 } catch ( err ) {
112- // Network failure: try cache
113- const cachedResponse = await caches . match ( request )
114- if ( cachedResponse ) {
115- return cachedResponse
116- }
117-
118- // As last resort, provide a friendly offline response for navigations
96+ // Offline fallback
11997 const accept = request . headers . get ( "accept" ) || ""
98+
99+ // If someone requested HTML (rare here because we bypass HTML), return a friendly page anyway
120100 if ( accept . includes ( "text/html" ) ) {
121101 return new Response (
122102 "<h1>Offline</h1><p>The application is currently offline.</p>" ,
123103 { headers : { "Content-Type" : "text/html; charset=utf-8" } , status : 503 }
124104 )
125105 }
126106
127- // For other assets, just fail gracefully
107+ // For assets, fail gracefully
128108 return new Response ( "Offline" , { status : 503 , statusText : "Service Unavailable" } )
129109 }
130110 } ) ( )
0 commit comments