| 1 | // g1t's service worker: browser notifications, nothing else. It caches |
| 2 | // nothing and answers no requests, so pages load exactly as without it. |
| 3 | // Pushes come from the notify service (services/notify), encrypted for |
| 4 | // this browser: { title, body, href, tag, kind, urgent }. |
| 5 | |
| 6 | self.addEventListener("install", () => self.skipWaiting()); |
| 7 | self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim())); |
| 8 | |
| 9 | self.addEventListener("push", (event) => { |
| 10 | let data = {}; |
| 11 | try { |
| 12 | data = event.data ? event.data.json() : {}; |
| 13 | } catch { |
| 14 | data = { title: "g1t", body: event.data ? event.data.text() : "" }; |
| 15 | } |
| 16 | const title = data.title || "g1t"; |
| 17 | event.waitUntil( |
| 18 | self.registration.showNotification(title, { |
| 19 | body: data.body || "", |
| 20 | icon: "/icon-192.png", |
| 21 | badge: "/badge-96.png", |
| 22 | // One notification per conversation: a newer message replaces the last. |
| 23 | tag: data.tag || undefined, |
| 24 | renotify: Boolean(data.tag), |
| 25 | data: { href: typeof data.href === "string" && data.href.startsWith("/") && !data.href.startsWith("//") ? data.href : "/" }, |
| 26 | }), |
| 27 | ); |
| 28 | }); |
| 29 | |
| 30 | self.addEventListener("notificationclick", (event) => { |
| 31 | event.notification.close(); |
| 32 | const href = (event.notification.data && event.notification.data.href) || "/"; |
| 33 | const target = new URL(href, self.location.origin).href; |
| 34 | event.waitUntil( |
| 35 | (async () => { |
| 36 | const open = await self.clients.matchAll({ type: "window", includeUncontrolled: true }); |
| 37 | // A tab already on g1t: brought forward and moved there. |
| 38 | const tab = open.find((client) => new URL(client.url).origin === self.location.origin); |
| 39 | if (tab) { |
| 40 | await tab.focus(); |
| 41 | if ("navigate" in tab) { |
| 42 | try { |
| 43 | await tab.navigate(target); |
| 44 | return; |
| 45 | } catch { |
| 46 | // Not ours to navigate (uncontrolled): told instead. |
| 47 | } |
| 48 | } |
| 49 | tab.postMessage({ type: "g1t:navigate", href }); |
| 50 | return; |
| 51 | } |
| 52 | await self.clients.openWindow(target); |
| 53 | })(), |
| 54 | ); |
| 55 | }); |