/// /// /// /// // Because of this line, this service worker won't run in dev mode in Firefox. // Only Safari, Edge, Chrome can run it at the moment, because only they // support modules in service workers. // // That's okay! If you run `tools/run` with PILCROW_DEV unset, you will get the // bundled version, and can work on it. Or just use Safari. import { build, files, version } from '$service-worker'; // Create a unique cache name for this deployment const CACHE = `cache-${version}`; const ASSETS = [ ...build, // the app itself ...files, // everything in `static` ]; self.addEventListener('install', (event) => { // Create a new cache and add all files to it async function addFilesToCache() { const cache = await caches.open(CACHE); await cache.addAll(ASSETS); } event.waitUntil(addFilesToCache()); }); self.addEventListener('activate', (event) => { // Remove previous cached data from disk async function deleteOldCaches() { for (const key of await caches.keys()) { if (key !== CACHE) await caches.delete(key); } } event.waitUntil(deleteOldCaches()); }); // The simplest possible use of the caches above: async function cacheFirst(request) { const responseFromCache = await caches.match(request); if (responseFromCache) { return responseFromCache; } return fetch(request); } self.addEventListener('fetch', (event) => { event.respondWith(cacheFirst(event.request)); }); const conversationReadStatus = { // Format: // conversationId: { lastRead: Optional(Datetime), lastMessage: Datetime } }; function countUnreadChannels() { return Object.values(conversationReadStatus) .map(({ lastRead, lastMessage }) => { return !lastRead || lastRead < lastMessage ? 1 : 0; }) .reduce((total, current) => total + current, 0); } self.addEventListener('push', (event) => { // Let's show a notification right away so Safari doesn't tell Apple to be // mad at us: event.waitUntil( self.registration.showNotification('Test notification', { actions: [], body: event.data.text(), }), ); // Now we can do slower things that might fail: conversationReadStatus[event.conversationId] ||= { lastRead: null, lastMessage: null }; conversationReadStatus[event.conversationId].lastMessage = new Date(); event.waitUntil( (async () => { if (navigator.setAppBadge) { navigator.setAppBadge(countUnreadChannels()); } })(), ); }); // The client has to tell us when it has read a conversation: self.addEventListener('message', (event) => { switch (event.data?.type) { case 'CONVERSATION_READ': conversationReadStatus[event.data.conversationId] ||= { lastRead: null, lastMessage: null }; conversationReadStatus[event.data.conversationId].lastMessage = event.data.at || new Date(); event.waitUntil( (async () => { if (navigator.setAppBadge) { navigator.setAppBadge(countUnreadChannels()); } })(), ); break; default: break; } });