a demonstration replicated social networking web app built with anproto wiredove.net/
social ed25519 protocols
at master 142 lines 3.9 kB view raw
1self.addEventListener('install', (event) => { 2 event.waitUntil((async () => { 3 const cache = await caches.open(APP_SHELL_CACHE) 4 await cache.addAll(APP_SHELL_ASSETS) 5 await self.skipWaiting() 6 })()) 7}) 8 9self.addEventListener('activate', (event) => { 10 event.waitUntil((async () => { 11 const keys = await caches.keys() 12 await Promise.all( 13 keys 14 .filter((key) => key.startsWith('wiredove-') && key !== APP_SHELL_CACHE) 15 .map((key) => caches.delete(key)) 16 ) 17 await self.clients.claim() 18 })()) 19}) 20 21const CACHE_VERSION = 'v1' 22const APP_SHELL_CACHE = `wiredove-app-shell-${CACHE_VERSION}` 23const APP_SHELL_ASSETS = [ 24 '/', 25 '/index.html', 26 '/style.css', 27 '/app.js', 28 '/manifest.json', 29 '/favicon.ico', 30 '/dovepurple_sm.png', 31 '/dovepurple.png', 32 '/dove_sm.png', 33] 34 35const isCacheableRequest = (request) => { 36 if (!request || request.method !== 'GET') { return false } 37 const url = new URL(request.url) 38 if (url.origin !== self.location.origin) { return false } 39 return true 40} 41 42const isNavigationRequest = (request) => request.mode === 'navigate' 43 44const isStaticAssetRequest = (request) => { 45 const url = new URL(request.url) 46 return /\.(?:js|css|png|jpg|jpeg|svg|ico|webmanifest|json)$/i.test(url.pathname) 47} 48 49const canCacheResponse = (response) => Boolean(response && response.ok) 50 51const staleWhileRevalidate = async (request) => { 52 const cache = await caches.open(APP_SHELL_CACHE) 53 const cached = await cache.match(request) 54 const networkPromise = fetch(request).then(async (response) => { 55 if (canCacheResponse(response)) { 56 await cache.put(request, response.clone()) 57 } 58 return response 59 }).catch(() => null) 60 if (cached) { 61 void networkPromise 62 return cached 63 } 64 const fresh = await networkPromise 65 if (fresh) { return fresh } 66 return Response.error() 67} 68 69const networkFirst = async (request) => { 70 const cache = await caches.open(APP_SHELL_CACHE) 71 try { 72 const response = await fetch(request) 73 if (canCacheResponse(response)) { 74 await cache.put(request, response.clone()) 75 } 76 return response 77 } catch { 78 const cached = await cache.match(request) 79 if (cached) { return cached } 80 if (isNavigationRequest(request)) { 81 const fallback = await cache.match('/index.html') 82 if (fallback) { return fallback } 83 } 84 return Response.error() 85 } 86} 87 88self.addEventListener('fetch', (event) => { 89 const { request } = event 90 if (!isCacheableRequest(request)) { return } 91 if (isNavigationRequest(request)) { 92 event.respondWith(networkFirst(request)) 93 return 94 } 95 if (isStaticAssetRequest(request)) { 96 event.respondWith(staleWhileRevalidate(request)) 97 } 98}) 99 100self.addEventListener('push', (event) => { 101 let payload = { title: 'wiredove', body: 'New message', url: '/' } 102 if (event.data) { 103 try { 104 payload = event.data.json() 105 } catch { 106 try { 107 payload = JSON.parse(event.data.text()) 108 } catch { 109 payload.body = event.data.text() 110 } 111 } 112 } 113 114 const hash = payload.hash 115 const targetUrl = payload.url || 116 (typeof hash === 'string' && hash.length > 0 117 ? `https://wiredove.net/#${hash}` 118 : '/') 119 const options = { 120 body: payload.body, 121 data: { url: targetUrl }, 122 icon: payload.icon || '/dovepurple_sm.png', 123 badge: payload.badge, 124 } 125 126 event.waitUntil(self.registration.showNotification(payload.title, options)) 127}) 128 129self.addEventListener('notificationclick', (event) => { 130 event.notification.close() 131 const target = event.notification.data?.url || '/' 132 133 event.waitUntil( 134 self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clients) => { 135 for (const client of clients) { 136 if (client.url.includes(target) && 'focus' in client) return client.focus() 137 } 138 if (self.clients.openWindow) return self.clients.openWindow(target) 139 return undefined 140 }), 141 ) 142})