148 lines
3.8 KiB
JavaScript
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();
|
|
});
|
|
}
|