98 lines
3.4 KiB
JavaScript
98 lines
3.4 KiB
JavaScript
import { precacheAndRoute } from 'workbox-precaching'
|
|
import { offlineFallback } from 'workbox-recipes'
|
|
import { setDefaultHandler } from 'workbox-routing'
|
|
import { NetworkOnly } from 'workbox-strategies'
|
|
import manifest from './precache-manifest.json'
|
|
|
|
// ignore precache manifest generated by InjectManifest
|
|
// self.__WB_MANIFEST
|
|
|
|
precacheAndRoute(manifest)
|
|
|
|
self.addEventListener('install', () => {
|
|
self.skipWaiting()
|
|
})
|
|
|
|
// Using network-only as the default strategy ensures that we fallback
|
|
// to the browser as if the service worker wouldn't exist.
|
|
// The browser may use own caching (HTTP cache).
|
|
// Also, the offline fallback only works if request matched a route
|
|
setDefaultHandler(new NetworkOnly())
|
|
|
|
// This won't work in dev because pages are never cached.
|
|
// See https://github.com/vercel/next.js/blob/337fb6a9aadb61c916f0121c899e463819cd3f33/server/render.js#L181-L185
|
|
offlineFallback({ pageFallback: '/offline' })
|
|
|
|
self.addEventListener('push', async function (event) {
|
|
const payload = event.data?.json()
|
|
if (!payload) return
|
|
const { tag } = payload.options
|
|
event.waitUntil((async () => {
|
|
if (!['REPLY', 'MENTION'].includes(tag)) {
|
|
return self.registration.showNotification(payload.title, payload.options)
|
|
}
|
|
|
|
const notifications = await self.registration.getNotifications({ tag })
|
|
// since we used a tag filter, there should only be zero or one notification
|
|
if (notifications.length > 1) {
|
|
console.error(`more than one notification with tag ${tag} found`)
|
|
return null
|
|
}
|
|
if (notifications.length === 0) {
|
|
return self.registration.showNotification(payload.title, payload.options)
|
|
}
|
|
const currentNotification = notifications[0]
|
|
const amount = currentNotification.data?.amount ? currentNotification.data.amount + 1 : 2
|
|
let title = ''
|
|
if (tag === 'REPLY') {
|
|
title = `You have ${amount} new replies`
|
|
} else if (tag === 'MENTION') {
|
|
title = `You were mentioned ${amount} times`
|
|
}
|
|
currentNotification.close()
|
|
const { icon } = currentNotification
|
|
return self.registration.showNotification(title, { icon, tag, data: { url: '/notifications', amount } })
|
|
})())
|
|
})
|
|
|
|
self.addEventListener('notificationclick', (event) => {
|
|
const url = event.notification.data?.url
|
|
if (url) {
|
|
event.waitUntil(self.clients.openWindow(url))
|
|
}
|
|
event.notification.close()
|
|
})
|
|
|
|
self.addEventListener('pushsubscriptionchange', (event) => {
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/pushsubscriptionchange_event
|
|
const query = `
|
|
mutation savePushSubscription($endpoint: String!, $p256dh: String!, $auth: String!, $oldEndpoint: String!) {
|
|
savePushSubscription(endpoint: $endpoint, p256dh: $p256dh, auth: $auth, oldEndpoint: $oldEndpoint) {
|
|
id
|
|
}
|
|
}`
|
|
const subscription = self.registration.pushManager
|
|
.subscribe(event.oldSubscription.options)
|
|
.then((subscription) => {
|
|
// convert keys from ArrayBuffer to string
|
|
subscription = JSON.parse(JSON.stringify(subscription))
|
|
const variables = {
|
|
endpoint: subscription.endpoint,
|
|
p256dh: subscription.keys.p256dh,
|
|
auth: subscription.keys.auth,
|
|
oldEndpoint: event.oldSubscription.endpoint
|
|
}
|
|
const body = JSON.stringify({ query, variables })
|
|
return fetch('/api/graphql', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-type': 'application/json'
|
|
},
|
|
body
|
|
})
|
|
})
|
|
event.waitUntil(subscription)
|
|
},
|
|
false
|
|
)
|