109 lines
3.7 KiB
JavaScript
109 lines
3.7 KiB
JavaScript
const CACHE_NAME = 'l484-pwa-v14'
|
|
const APP_SHELL = [
|
|
'/',
|
|
'/manifest.webmanifest',
|
|
]
|
|
|
|
self.addEventListener('install', (event) => {
|
|
event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)))
|
|
self.skipWaiting()
|
|
})
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
event.waitUntil(
|
|
(async () => {
|
|
const keys = await caches.keys()
|
|
await Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))
|
|
await self.clients.claim()
|
|
})(),
|
|
)
|
|
})
|
|
|
|
self.addEventListener('fetch', (event) => {
|
|
const url = new URL(event.request.url)
|
|
if (!['http:', 'https:'].includes(url.protocol)) return
|
|
if (url.pathname.startsWith('/api/')) return
|
|
|
|
if (event.request.mode === 'navigate') {
|
|
if (['/admin', '/edit'].includes(url.pathname)) {
|
|
event.respondWith(fetch(event.request).catch(() => Response.error()))
|
|
return
|
|
}
|
|
event.respondWith(
|
|
fetch(event.request)
|
|
.then((response) => {
|
|
if (response.ok && response.type === 'basic') {
|
|
const clone = response.clone()
|
|
caches.open(CACHE_NAME).then((cache) => cache.put('/', clone))
|
|
}
|
|
return response
|
|
})
|
|
.catch(async () => (await caches.match('/')) || (await caches.match(event.request)) || Response.error()),
|
|
)
|
|
return
|
|
}
|
|
|
|
if (event.request.method !== 'GET') return
|
|
|
|
event.respondWith(
|
|
caches.match(event.request).then((cached) =>
|
|
cached || fetch(event.request).then((response) => {
|
|
if (event.request.method === 'GET' && response.ok && response.type === 'basic') {
|
|
const clone = response.clone()
|
|
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone))
|
|
}
|
|
return response
|
|
}).catch(() => Response.error()),
|
|
),
|
|
)
|
|
})
|
|
|
|
self.addEventListener('pushsubscriptionchange', (event) => {
|
|
event.waitUntil((async () => {
|
|
const response = await fetch('/api/notifications/vapid-public-key', { cache: 'no-store' })
|
|
const { publicKey } = response.ok ? await response.json() : {}
|
|
if (!publicKey) return
|
|
const padding = '='.repeat((4 - publicKey.length % 4) % 4)
|
|
const base64 = (publicKey + padding).replace(/-/g, '+').replace(/_/g, '/')
|
|
const rawData = atob(base64)
|
|
const applicationServerKey = new Uint8Array([...rawData].map((char) => char.charCodeAt(0)))
|
|
const subscription = await self.registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
|
|
await fetch('/api/notifications/subscribe', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ subscription: subscription.toJSON() }),
|
|
})
|
|
})())
|
|
})
|
|
|
|
self.addEventListener('push', (event) => {
|
|
let data = {}
|
|
try {
|
|
data = event.data ? event.data.json() : {}
|
|
} catch {
|
|
data = { title: 'L484', message: event.data?.text() || 'New L484 update.' }
|
|
}
|
|
const title = data.title || 'L484'
|
|
const options = {
|
|
body: data.message || data.body || 'New L484 update.',
|
|
icon: data.icon || '/images/small-logo.svg',
|
|
badge: '/images/small-logo.svg',
|
|
tag: data.tag || 'l484-update',
|
|
data: { url: data.data?.url || '/' },
|
|
}
|
|
event.waitUntil(self.registration.showNotification(title, options))
|
|
})
|
|
|
|
self.addEventListener('notificationclick', (event) => {
|
|
event.notification.close()
|
|
const urlToOpen = event.notification.data?.url || '/'
|
|
event.waitUntil(
|
|
clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
|
|
const existing = clientList.find((client) => new URL(client.url).pathname === urlToOpen && 'focus' in client)
|
|
if (existing) return existing.focus()
|
|
if (clients.openWindow) return clients.openWindow(urlToOpen)
|
|
return null
|
|
}),
|
|
)
|
|
})
|