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) {
|
function createPayload (notification) {
|
||||||
// https://web.dev/push-notifications-display-a-notification/#visual-options
|
// 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
|
let { title, body, ...options } = notification
|
||||||
if (body) body = removeMd(body)
|
if (body) body = removeMd(body)
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
title,
|
web_push: 8030, // Declarative Web Push JSON format
|
||||||
options: {
|
notification: {
|
||||||
|
title,
|
||||||
body,
|
body,
|
||||||
timestamp: Date.now(),
|
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
|
...options
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -58,6 +63,10 @@ async function sendNotification (subscription, payload) {
|
|||||||
subject: process.env.VAPID_MAILTO,
|
subject: process.env.VAPID_MAILTO,
|
||||||
publicKey: process.env.NEXT_PUBLIC_VAPID_PUBKEY,
|
publicKey: process.env.NEXT_PUBLIC_VAPID_PUBKEY,
|
||||||
privateKey: process.env.VAPID_PRIVKEY
|
privateKey: process.env.VAPID_PRIVKEY
|
||||||
|
},
|
||||||
|
// conformant to declarative web push spec
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/notification+json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(async (err) => {
|
.catch(async (err) => {
|
||||||
@ -95,7 +104,10 @@ async function sendUserNotification (userId, notification) {
|
|||||||
}
|
}
|
||||||
notification.data ??= {}
|
notification.data ??= {}
|
||||||
if (notification.itemId) {
|
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)
|
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
|
delete notification.itemId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
sw/index.js
12
sw/index.js
@ -73,13 +73,17 @@ setDefaultHandler(new NetworkOnly({
|
|||||||
offlineFallback({ pageFallback: '/offline' })
|
offlineFallback({ pageFallback: '/offline' })
|
||||||
|
|
||||||
self.addEventListener('push', function (event) {
|
self.addEventListener('push', function (event) {
|
||||||
let payload
|
let title, options
|
||||||
|
|
||||||
try {
|
try {
|
||||||
payload = event.data?.json()
|
const { notification } = event.data?.json()
|
||||||
if (!payload) {
|
if (!notification) {
|
||||||
throw new Error('no payload in push event')
|
throw new Error('no payload in push event')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adapt declarative payload for legacy Push API
|
||||||
|
options = notification || {}
|
||||||
|
title = notification.title
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// we show a default nofication on any error because we *must* show a notification
|
// 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
|
// 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(
|
event.waitUntil(
|
||||||
self.registration.showNotification(payload.title, payload.options)
|
self.registration.showNotification(title, options)
|
||||||
.then(() => self.registration.getNotifications())
|
.then(() => self.registration.getNotifications())
|
||||||
.then(notifications => self.navigator.setAppBadge?.(notifications.length))
|
.then(notifications => self.navigator.setAppBadge?.(notifications.length))
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user