sw.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /* eslint-disable import/no-extraneous-dependencies */
  2. import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from "workbox-precaching";
  3. import { NavigationRoute, registerRoute } from "workbox-routing";
  4. import { NetworkFirst } from "workbox-strategies";
  5. import { getDbAsync } from "../src/app/getDb";
  6. // See WebPushWorker, this is to play a sound on supported browsers,
  7. // if the app is in the foreground
  8. const broadcastChannel = new BroadcastChannel("web-push-broadcast");
  9. self.addEventListener("install", () => {
  10. console.log("[ServiceWorker] Installed");
  11. self.skipWaiting();
  12. });
  13. self.addEventListener("activate", () => {
  14. console.log("[ServiceWorker] Activated");
  15. self.skipWaiting();
  16. });
  17. // There's no good way to test this, and Chrome doesn't seem to implement this,
  18. // so leaving it for now
  19. self.addEventListener("pushsubscriptionchange", (event) => {
  20. console.log("[ServiceWorker] PushSubscriptionChange");
  21. console.log(event);
  22. });
  23. self.addEventListener("push", (event) => {
  24. console.log("[ServiceWorker] Received Web Push Event", { event });
  25. // server/types.go webPushPayload
  26. const data = event.data.json();
  27. const { formatted_title: formattedTitle, subscription_id: subscriptionId, message } = data;
  28. broadcastChannel.postMessage(message);
  29. event.waitUntil(
  30. (async () => {
  31. const db = await getDbAsync();
  32. await Promise.all([
  33. (async () => {
  34. await db.notifications.add({
  35. ...message,
  36. subscriptionId,
  37. // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation
  38. new: 1,
  39. });
  40. const badgeCount = await db.notifications.where({ new: 1 }).count();
  41. console.log("[ServiceWorker] Setting new app badge count", { badgeCount });
  42. self.navigator.setAppBadge?.(badgeCount);
  43. })(),
  44. db.subscriptions.update(subscriptionId, {
  45. last: message.id,
  46. }),
  47. self.registration.showNotification(formattedTitle, {
  48. tag: subscriptionId,
  49. body: message.message,
  50. icon: "/static/images/ntfy.png",
  51. data,
  52. }),
  53. ]);
  54. })()
  55. );
  56. });
  57. self.addEventListener("notificationclick", (event) => {
  58. event.notification.close();
  59. const { message } = event.notification.data;
  60. if (message.click) {
  61. self.clients.openWindow(message.click);
  62. return;
  63. }
  64. const rootUrl = new URL(self.location.origin);
  65. const topicUrl = new URL(message.topic, self.location.origin);
  66. event.waitUntil(
  67. (async () => {
  68. const clients = await self.clients.matchAll({ type: "window" });
  69. const topicClient = clients.find((client) => client.url === topicUrl.toString());
  70. if (topicClient) {
  71. topicClient.focus();
  72. return;
  73. }
  74. const rootClient = clients.find((client) => client.url === rootUrl.toString());
  75. if (rootClient) {
  76. rootClient.focus();
  77. return;
  78. }
  79. self.clients.openWindow(topicUrl);
  80. })()
  81. );
  82. });
  83. // self.__WB_MANIFEST is default injection point
  84. // eslint-disable-next-line no-underscore-dangle
  85. precacheAndRoute(self.__WB_MANIFEST);
  86. // clean old assets
  87. cleanupOutdatedCaches();
  88. // to allow work offline
  89. registerRoute(new NavigationRoute(createHandlerBoundToURL("/")));
  90. registerRoute(({ url }) => url.pathname === "/config.js", new NetworkFirst());