Files

61 lines
1.8 KiB
JavaScript
Raw Permalink Normal View History

/**
* Silo service worker: displays Web Push notifications and routes clicks.
* Payloads arrive end-to-end encrypted (RFC 8291); by the time the push
* event fires the browser has decrypted them for us.
*/
self.addEventListener("install", () => {
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim());
});
self.addEventListener("push", (event) => {
let data = {};
try {
data = event.data ? event.data.json() : {};
} catch {
data = {};
}
const title = data.title || "Silo";
const options = {
body: data.body || "",
icon: data.icon || "/web-app-icon-192.png",
badge: "/web-app-icon-192.png",
tag: data.tag || undefined,
data: { url: data.url || "/notifications" },
};
event.waitUntil(self.registration.showNotification(title, options));
});
self.addEventListener("notificationclick", (event) => {
event.notification.close();
// Notifications navigate same-origin only: payload data is server-built,
// but a notification surface must never become an open redirect.
const rawUrl = (event.notification.data && event.notification.data.url) || "/notifications";
let url = "/notifications";
try {
const parsed = new URL(rawUrl, self.location.origin);
if (parsed.origin === self.location.origin) {
url = `${parsed.pathname}${parsed.search}${parsed.hash}`;
}
} catch {
// keep the safe default
}
event.waitUntil(
self.clients.matchAll({ type: "window", includeUncontrolled: true }).then((clientList) => {
for (const client of clientList) {
if ("focus" in client) {
if ("navigate" in client) {
client.navigate(url);
}
return client.focus();
}
}
return self.clients.openWindow(url);
}),
);
});