// High-Performance Service Worker for "מה אברך" PWA - v3.0
const CACHE_NAME = 'ma-avarech-v4.0-assets';
const APP_SHELL_CACHE = 'ma-avarech-v4.0-app-shell';
const APP_SHELL_URLS = [
'/',
'/Foods',
'/Shacharit',
'/AiHelper',
'/Tehillim',
'/BirkatHamazon',
'/Holidays',
'/HalachaLibrary',
];
self.addEventListener('install', (event) => {
console.log('[SW] Installing Service Worker v3.0');
event.waitUntil(
caches.open(APP_SHELL_CACHE)
.then((cache) => {
console.log('[SW] Caching App Shell');
return cache.addAll(APP_SHELL_URLS);
})
.then(() => self.skipWaiting())
.catch((error) => {
console.error('[SW] Failed to cache App Shell:', error);
})
);
});
self.addEventListener('activate', (event) => {
console.log('[SW] Activating Service Worker v3.0');
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME && cacheName !== APP_SHELL_CACHE) {
console.log('[SW] Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
}).then(() => self.clients.claim())
);
});
self.addEventListener('fetch', (event) => {
const { request } = event;
if (request.method !== 'GET') return;
const url = new URL(request.url);
// Never cache JS/CSS chunks, Vite internals, or API calls
const skipCache =
url.pathname.includes('/src/') ||
url.pathname.includes('/node_modules/') ||
url.pathname.includes('/@vite') ||
url.pathname.includes('/@react-refresh') ||
url.pathname.includes('/api/') ||
url.pathname.startsWith('/functions/') ||
url.searchParams.has('v') ||
url.pathname.endsWith('.js') ||
url.pathname.endsWith('.jsx') ||
url.pathname.endsWith('.css') ||
url.hostname !== self.location.hostname;
if (skipCache) return; // let browser handle it normally
if (APP_SHELL_URLS.includes(url.pathname)) {
event.respondWith(
caches.match(request).then((cachedResponse) => {
return fetch(request).then(res => {
caches.open(APP_SHELL_CACHE).then(c => c.put(request, res.clone()));
return res;
}).catch(() => cachedResponse);
})
);
return;
}
event.respondWith(
caches.open(CACHE_NAME).then((cache) => {
return cache.match(request).then((cachedResponse) => {
const fetchPromise = fetch(request).then((networkResponse) => {
if (networkResponse && networkResponse.status === 200) {
cache.put(request, networkResponse.clone());
}
return networkResponse;
}).catch(() => cachedResponse);
return cachedResponse || fetchPromise;
});
})
);
});
self.addEventListener('push', (event) => {
if (!event.data) return;
try {
const data = event.data.json();
const options = {
body: data.body || 'יש לך הודעה חדשה',
icon: '/icon-192x192.png',
badge: '/icon-72x72.png',
tag: 'ma-avarech-notification',
requireInteraction: false,
dir: 'rtl',
lang: 'he',
silent: false,
vibrate: [200, 100, 200]
};
event.waitUntil(
self.registration.showNotification(data.title || 'מה אברך', options)
);
} catch (error) {
console.error('[SW] Push notification error:', error);
}
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
event.waitUntil(
self.clients.matchAll({ type: 'window', includeUncontrolled: true })
.then((clients) => {
for (const client of clients) {
if (client.url.includes(self.location.origin) && 'focus' in client) {
return client.focus();
}
}
if (self.clients.openWindow) {
return self.clients.openWindow('/');
}
})
);
});
console.log('[SW] Service Worker v3.0 loaded successfully.');