1+ // RetroChat Service Worker
2+ const CACHE_NAME = 'retro-chat-v1' ;
3+ const STATIC_ASSETS = [
4+ '/' ,
5+ '/index.html' ,
6+ '/manifest.json' ,
7+ // External dependencies - will be cached when first loaded
8+ 'https://cdn.jsdelivr.net/npm/[email protected] /dist/protobuf.min.js' , 9+ 'https://unpkg.com/@waku/[email protected] /bundle/index.js' , 10+ 'https://fonts.googleapis.com/css2?family=Share+Tech+Mono:wght@400&display=swap'
11+ ] ;
12+
13+ // Install event - cache static assets
14+ self . addEventListener ( 'install' , ( event ) => {
15+ console . log ( '[SW] Installing service worker' ) ;
16+ event . waitUntil (
17+ caches . open ( CACHE_NAME ) . then ( ( cache ) => {
18+ console . log ( '[SW] Caching static assets' ) ;
19+ return cache . addAll ( STATIC_ASSETS . filter ( url => ! url . startsWith ( 'http' ) ) ) ;
20+ } ) . then ( ( ) => {
21+ // Force the waiting service worker to become the active service worker
22+ return self . skipWaiting ( ) ;
23+ } )
24+ ) ;
25+ } ) ;
26+
27+ // Activate event - clean up old caches
28+ self . addEventListener ( 'activate' , ( event ) => {
29+ console . log ( '[SW] Activating service worker' ) ;
30+ event . waitUntil (
31+ caches . keys ( ) . then ( ( cacheNames ) => {
32+ return Promise . all (
33+ cacheNames . map ( ( cacheName ) => {
34+ if ( cacheName !== CACHE_NAME ) {
35+ console . log ( '[SW] Deleting old cache:' , cacheName ) ;
36+ return caches . delete ( cacheName ) ;
37+ }
38+ } )
39+ ) ;
40+ } ) . then ( ( ) => {
41+ // Ensure the service worker takes control immediately
42+ return self . clients . claim ( ) ;
43+ } )
44+ ) ;
45+ } ) ;
46+
47+ // Fetch event - serve from cache first, then network
48+ self . addEventListener ( 'fetch' , ( event ) => {
49+ // Skip non-GET requests
50+ if ( event . request . method !== 'GET' ) {
51+ return ;
52+ }
53+
54+ // Skip WebSocket and other non-HTTP requests
55+ if ( ! event . request . url . startsWith ( 'http' ) ) {
56+ return ;
57+ }
58+
59+ // Skip Waku network requests
60+ if ( event . request . url . includes ( 'waku' ) && event . request . url . includes ( 'wss://' ) ) {
61+ return ;
62+ }
63+
64+ event . respondWith (
65+ caches . match ( event . request ) . then ( ( cachedResponse ) => {
66+ if ( cachedResponse ) {
67+ console . log ( '[SW] Serving from cache:' , event . request . url ) ;
68+ return cachedResponse ;
69+ }
70+
71+ console . log ( '[SW] Fetching from network:' , event . request . url ) ;
72+ return fetch ( event . request ) . then ( ( response ) => {
73+ // Don't cache non-successful responses
74+ if ( ! response || response . status !== 200 || response . type !== 'basic' ) {
75+ return response ;
76+ }
77+
78+ // Clone the response before caching
79+ const responseToCache = response . clone ( ) ;
80+
81+ caches . open ( CACHE_NAME ) . then ( ( cache ) => {
82+ console . log ( '[SW] Caching new resource:' , event . request . url ) ;
83+ cache . put ( event . request , responseToCache ) ;
84+ } ) ;
85+
86+ return response ;
87+ } ) . catch ( ( error ) => {
88+ console . log ( '[SW] Fetch failed, trying cache:' , error ) ;
89+
90+ // If it's the main page and we're offline, serve from cache
91+ if ( event . request . url . endsWith ( '/' ) || event . request . url . endsWith ( 'index.html' ) ) {
92+ return caches . match ( '/index.html' ) ;
93+ }
94+
95+ throw error ;
96+ } ) ;
97+ } )
98+ ) ;
99+ } ) ;
100+
101+ // Handle background sync for offline message queuing (future enhancement)
102+ self . addEventListener ( 'sync' , ( event ) => {
103+ console . log ( '[SW] Background sync triggered:' , event . tag ) ;
104+ if ( event . tag === 'background-sync' ) {
105+ event . waitUntil (
106+ // This could be used to queue messages when offline
107+ console . log ( '[SW] Handling background sync' )
108+ ) ;
109+ }
110+ } ) ;
111+
112+ // Handle push notifications (future enhancement)
113+ self . addEventListener ( 'push' , ( event ) => {
114+ console . log ( '[SW] Push message received' ) ;
115+
116+ const options = {
117+ body : 'New message in RetroChat' ,
118+ icon : 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5NiIgaGVpZ2h0PSI5NiIgdmlld0JveD0iMCAwIDk2IDk2Ij4KICA8cmVjdCB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIGZpbGw9IiMwMDAiLz4KICA8dGV4dCB4PSI0OCIgeT0iNTgiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMwMGZmMDAiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMzIiIGZvbnQtd2VpZ2h0PSJib2xkIj5SQzwvdGV4dD4KPC9zdmc+' ,
119+ badge : 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIj4KICA8cmVjdCB3aWR0aD0iNzIiIGhlaWdodD0iNzIiIGZpbGw9IiMwMGZmMDAiLz4KICA8dGV4dCB4PSIzNiIgeT0iNDUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMwMDAiIGZvbnQtZmFtaWx5PSJtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjQiIGZvbnQtd2VpZ2h0PSJib2xkIj5SQzwvdGV4dD4KPC9zdmc+' ,
120+ tag : 'retro-chat-message' ,
121+ requireInteraction : false
122+ } ;
123+
124+ event . waitUntil (
125+ self . registration . showNotification ( 'RetroChat' , options )
126+ ) ;
127+ } ) ;
128+
129+ // Handle notification click
130+ self . addEventListener ( 'notificationclick' , ( event ) => {
131+ console . log ( '[SW] Notification clicked' ) ;
132+ event . notification . close ( ) ;
133+
134+ event . waitUntil (
135+ clients . openWindow ( '/' )
136+ ) ;
137+ } ) ;
138+
139+ console . log ( '[SW] Service worker loaded' ) ;
0 commit comments