AeThex-Connect/packages/web/public/sw.js

148 lines
3.8 KiB
JavaScript

const CACHE_NAME = 'aethex-connect-v1';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/manifest.json',
];
// Install event
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log('Caching app shell');
return cache.addAll(ASSETS_TO_CACHE).catch(err => {
console.log('Cache addAll error:', err);
// Don't fail installation if some assets can't be cached
});
})
);
self.skipWaiting();
});
// Activate event
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
console.log('Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
self.clients.claim();
});
// Fetch event - Network first, fallback to cache
self.addEventListener('fetch', (event) => {
const { request } = event;
// Skip non-GET requests
if (request.method !== 'GET') {
return;
}
// API requests - network first
if (request.url.includes('/api/')) {
event.respondWith(
fetch(request)
.then((response) => {
if (!response || response.status !== 200) {
return response;
}
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(request, responseClone);
});
return response;
})
.catch(() => {
return caches.match(request);
})
);
} else {
// Static assets - cache first
event.respondWith(
caches.match(request).then((response) => {
if (response) {
return response;
}
return fetch(request).then((response) => {
if (!response || response.status !== 200 || response.type === 'error') {
return response;
}
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(request, responseClone);
});
return response;
});
})
);
}
});
// Background sync for offline messages
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-messages') {
event.waitUntil(syncMessages());
}
});
async function syncMessages() {
try {
const db = await openIndexedDB();
const messages = await getPendingMessages(db);
for (const message of messages) {
try {
await fetch('/api/messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message),
});
await deletePendingMessage(db, message.id);
} catch (error) {
console.error('Failed to sync message:', error);
}
}
} catch (error) {
console.error('Sync error:', error);
}
}
function openIndexedDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('aethex-connect', 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
function getPendingMessages(db) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['pendingMessages'], 'readonly');
const store = transaction.objectStore('pendingMessages');
const request = store.getAll();
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
}
function deletePendingMessage(db, id) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['pendingMessages'], 'readwrite');
const store = transaction.objectStore('pendingMessages');
const request = store.delete(id);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}