171 lines
4.5 KiB
TypeScript
171 lines
4.5 KiB
TypeScript
import { precacheAndRoute } from 'workbox-precaching';
|
|
import { registerRoute } from 'workbox-routing';
|
|
import { NetworkFirst, CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';
|
|
import { BackgroundSyncPlugin } from 'workbox-background-sync';
|
|
import { ExpirationPlugin } from 'workbox-expiration';
|
|
|
|
declare const self: ServiceWorkerGlobalScope;
|
|
|
|
// Precache all build assets
|
|
precacheAndRoute(self.__WB_MANIFEST);
|
|
|
|
// API requests - Network first, cache fallback
|
|
registerRoute(
|
|
({ url }) => url.pathname.startsWith('/api/'),
|
|
new NetworkFirst({
|
|
cacheName: 'api-cache',
|
|
plugins: [
|
|
new ExpirationPlugin({
|
|
maxEntries: 50,
|
|
maxAgeSeconds: 5 * 60, // 5 minutes
|
|
}),
|
|
],
|
|
})
|
|
);
|
|
|
|
// Images - Cache first
|
|
registerRoute(
|
|
({ request }) => request.destination === 'image',
|
|
new CacheFirst({
|
|
cacheName: 'images',
|
|
plugins: [
|
|
new ExpirationPlugin({
|
|
maxEntries: 100,
|
|
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
|
|
}),
|
|
],
|
|
})
|
|
);
|
|
|
|
// Fonts - Cache first
|
|
registerRoute(
|
|
({ request }) => request.destination === 'font',
|
|
new CacheFirst({
|
|
cacheName: 'fonts',
|
|
plugins: [
|
|
new ExpirationPlugin({
|
|
maxEntries: 20,
|
|
maxAgeSeconds: 365 * 24 * 60 * 60, // 1 year
|
|
}),
|
|
],
|
|
})
|
|
);
|
|
|
|
// Background sync for failed POST requests
|
|
const bgSyncPlugin = new BackgroundSyncPlugin('message-queue', {
|
|
maxRetentionTime: 24 * 60, // Retry for 24 hours
|
|
});
|
|
|
|
registerRoute(
|
|
({ url }) => url.pathname.startsWith('/api/messages'),
|
|
new NetworkFirst({
|
|
plugins: [bgSyncPlugin],
|
|
}),
|
|
'POST'
|
|
);
|
|
|
|
// Push notifications
|
|
self.addEventListener('push', (event) => {
|
|
const data = event.data?.json() || {};
|
|
|
|
const options: NotificationOptions = {
|
|
body: data.body || 'You have a new message',
|
|
icon: data.icon || '/icon-192.png',
|
|
badge: '/badge-96.png',
|
|
tag: data.tag || 'notification',
|
|
data: data.data || {},
|
|
actions: data.actions || [
|
|
{ action: 'open', title: 'Open' },
|
|
{ action: 'dismiss', title: 'Dismiss' },
|
|
],
|
|
vibrate: [200, 100, 200],
|
|
requireInteraction: data.requireInteraction || false,
|
|
};
|
|
|
|
event.waitUntil(
|
|
self.registration.showNotification(data.title || 'AeThex Connect', options)
|
|
);
|
|
});
|
|
|
|
// Notification click handler
|
|
self.addEventListener('notificationclick', (event) => {
|
|
event.notification.close();
|
|
|
|
if (event.action === 'open' || !event.action) {
|
|
const urlToOpen = event.notification.data?.url || '/';
|
|
|
|
event.waitUntil(
|
|
self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
|
|
// Check if there's already a window open
|
|
for (const client of clientList) {
|
|
if (client.url === urlToOpen && 'focus' in client) {
|
|
return client.focus();
|
|
}
|
|
}
|
|
// Open new window if none exists
|
|
if (self.clients.openWindow) {
|
|
return self.clients.openWindow(urlToOpen);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
});
|
|
|
|
// Handle notification actions (reply, etc.)
|
|
self.addEventListener('notificationclick', (event) => {
|
|
if (event.action === 'reply' && event.reply) {
|
|
// Send reply via background sync
|
|
event.waitUntil(
|
|
fetch('/api/messages', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
conversationId: event.notification.data.conversationId,
|
|
content: event.reply,
|
|
contentType: 'text',
|
|
}),
|
|
})
|
|
);
|
|
}
|
|
});
|
|
|
|
// Periodic background sync (for checking new messages when offline)
|
|
self.addEventListener('periodicsync', (event: any) => {
|
|
if (event.tag === 'check-messages') {
|
|
event.waitUntil(checkForNewMessages());
|
|
}
|
|
});
|
|
|
|
async function checkForNewMessages() {
|
|
try {
|
|
const response = await fetch('/api/messages/unread');
|
|
const data = await response.json();
|
|
|
|
if (data.count > 0) {
|
|
self.registration.showNotification('New Messages', {
|
|
body: `You have ${data.count} unread messages`,
|
|
icon: '/icon-192.png',
|
|
badge: '/badge-96.png',
|
|
tag: 'unread-messages',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error checking messages:', error);
|
|
}
|
|
}
|
|
|
|
// Skip waiting and claim clients immediately
|
|
self.addEventListener('message', (event) => {
|
|
if (event.data && event.data.type === 'SKIP_WAITING') {
|
|
self.skipWaiting();
|
|
}
|
|
});
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil(self.clients.claim());
|
|
});
|
|
|
|
// Log service worker version
|
|
console.log('AeThex Connect Service Worker v1.0.0');
|