mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-25 09:38:22 +03:00
* Fix iOS having notification token revoked * Try to handle iOS stacked notifications * Fix typo * Improve updating of notification script
97 lines
2.8 KiB
JavaScript
97 lines
2.8 KiB
JavaScript
// Notifications Worker
|
|
|
|
self.addEventListener("push", function (event) {
|
|
// @ts-expect-error we know this exists
|
|
if (event.data) {
|
|
// @ts-expect-error we know this exists
|
|
const data = event.data.json();
|
|
|
|
let actions = [];
|
|
|
|
switch (data.type ?? "unknown") {
|
|
case "alert":
|
|
actions = [
|
|
{
|
|
action: "markReviewed",
|
|
title: "Mark as Reviewed",
|
|
},
|
|
];
|
|
break;
|
|
}
|
|
|
|
const notificationOptions = {
|
|
body: data.message,
|
|
icon: "/images/maskable-icon.png",
|
|
image: data.image,
|
|
badge: "/images/maskable-badge.png",
|
|
tag: data.id,
|
|
data: { id: data.id, link: data.direct_url },
|
|
actions,
|
|
};
|
|
|
|
// iOS Safari does not auto-coalesce notifications by tag (WebKit bug #258922).
|
|
// On iOS 18.3+ close() works, so we manually close duplicates before showing.
|
|
// On other platforms, tag-based replacement works natively — skip the extra work.
|
|
const isIOS =
|
|
/iPad|iPhone|iPod/.test(navigator.userAgent) && !self.MSStream;
|
|
|
|
const show = () =>
|
|
// @ts-expect-error we know this exists
|
|
self.registration.showNotification(data.title, notificationOptions);
|
|
|
|
// event.waitUntil is required on iOS Safari — without it, the browser
|
|
// may consider this a "silent push" and revoke the subscription after 3 occurrences.
|
|
event.waitUntil(
|
|
isIOS
|
|
? // @ts-expect-error we know this exists
|
|
self.registration
|
|
.getNotifications({ tag: data.id })
|
|
.then((existing) => {
|
|
for (const n of existing) {
|
|
n.close();
|
|
}
|
|
})
|
|
.then(show)
|
|
: show(), // eslint-disable-line comma-dangle
|
|
);
|
|
} else {
|
|
// pass
|
|
// This push event has no data
|
|
}
|
|
});
|
|
|
|
self.addEventListener("notificationclick", (event) => {
|
|
// @ts-expect-error we know this exists
|
|
if (event.notification) {
|
|
// @ts-expect-error we know this exists
|
|
event.notification.close();
|
|
|
|
switch (event.action ?? "default") {
|
|
case "markReviewed":
|
|
if (event.notification.data) {
|
|
event.waitUntil(
|
|
fetch("/api/reviews/viewed", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"X-CSRF-TOKEN": 1,
|
|
},
|
|
body: JSON.stringify({ ids: [event.notification.data.id] }),
|
|
}), // eslint-disable-line comma-dangle
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
// @ts-expect-error we know this exists
|
|
if (event.notification.data) {
|
|
const url = event.notification.data.link;
|
|
// eslint-disable-next-line no-undef
|
|
if (clients.openWindow) {
|
|
// eslint-disable-next-line no-undef
|
|
event.waitUntil(clients.openWindow(url));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|