Declarative Web Push support (#2300)
* Declarative Web Push support, standardized JSON format TODOs: - sane app badge count * URL backwards compatibility, add icon to the JSON payload, fix malformed payload recognition on classic push notifications * typo: wrong app_badge placement in JSON payload * adapt declarative JSON payload for legacy Push API using spec-conformant transformations
This commit is contained in:
parent
20147cae15
commit
9c8071339f
@ -15,14 +15,19 @@ function log (...args) {
|
||||
|
||||
function createPayload (notification) {
|
||||
// https://web.dev/push-notifications-display-a-notification/#visual-options
|
||||
// https://webkit.org/blog/16535/meet-declarative-web-push/
|
||||
// DEV: localhost in URLs is not supported by declarative web push
|
||||
let { title, body, ...options } = notification
|
||||
if (body) body = removeMd(body)
|
||||
return JSON.stringify({
|
||||
title,
|
||||
options: {
|
||||
web_push: 8030, // Declarative Web Push JSON format
|
||||
notification: {
|
||||
title,
|
||||
body,
|
||||
timestamp: Date.now(),
|
||||
icon: '/icons/icon_x96.png',
|
||||
icon: process.env.NEXT_PUBLIC_URL + '/icons/icon_x96.png',
|
||||
navigate: process.env.NEXT_PUBLIC_URL + '/notifications', // navigate is required
|
||||
app_badge: 1, // TODO: establish a proper badge count system
|
||||
...options
|
||||
}
|
||||
})
|
||||
@ -58,6 +63,10 @@ async function sendNotification (subscription, payload) {
|
||||
subject: process.env.VAPID_MAILTO,
|
||||
publicKey: process.env.NEXT_PUBLIC_VAPID_PUBKEY,
|
||||
privateKey: process.env.VAPID_PRIVKEY
|
||||
},
|
||||
// conformant to declarative web push spec
|
||||
headers: {
|
||||
'Content-Type': 'application/notification+json'
|
||||
}
|
||||
})
|
||||
.catch(async (err) => {
|
||||
@ -95,7 +104,10 @@ async function sendUserNotification (userId, notification) {
|
||||
}
|
||||
notification.data ??= {}
|
||||
if (notification.itemId) {
|
||||
// legacy Push API notificationclick event needs data.url as the navigate key is consumed by the browser
|
||||
notification.data.url ??= await createItemUrl(notification.itemId)
|
||||
// Declarative Web Push can't use relative paths
|
||||
notification.navigate ??= process.env.NEXT_PUBLIC_URL + notification.data.url
|
||||
delete notification.itemId
|
||||
}
|
||||
|
||||
|
12
sw/index.js
12
sw/index.js
@ -73,13 +73,17 @@ setDefaultHandler(new NetworkOnly({
|
||||
offlineFallback({ pageFallback: '/offline' })
|
||||
|
||||
self.addEventListener('push', function (event) {
|
||||
let payload
|
||||
let title, options
|
||||
|
||||
try {
|
||||
payload = event.data?.json()
|
||||
if (!payload) {
|
||||
const { notification } = event.data?.json()
|
||||
if (!notification) {
|
||||
throw new Error('no payload in push event')
|
||||
}
|
||||
|
||||
// adapt declarative payload for legacy Push API
|
||||
options = notification || {}
|
||||
title = notification.title
|
||||
} catch (err) {
|
||||
// we show a default nofication on any error because we *must* show a notification
|
||||
// else the browser will show one for us or worse, remove our push subscription
|
||||
@ -94,7 +98,7 @@ self.addEventListener('push', function (event) {
|
||||
}
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(payload.title, payload.options)
|
||||
self.registration.showNotification(title, options)
|
||||
.then(() => self.registration.getNotifications())
|
||||
.then(notifications => self.navigator.setAppBadge?.(notifications.length))
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user