Newer
Older
gn-synapse / frontend / public / sw.js
/* Сервис-воркер Synapse: пуш-уведомления и клики по ним.
 *
 * Специально минималистичный: кэширование статики (offline shell) не делаем —
 * приложение гоняется через API и протухший кэш хуже плохого оффлайна;
 * fetch — pass-through (Chrome требует обработчик для installable, не перехватываем).
 * Захват только push/notificationclick: payload {title, body, event_id, url} (docs/06).
 */

// При выпуске новой версии SW менять строку — активация вытеснит старую на activate.
const VERSION = "synapse-sw-v1";

self.addEventListener("install", () => self.skipWaiting());

self.addEventListener("activate", (event) => {
  event.waitUntil(
    (async () => {
      // подчищаем старые версии воркера
      for (const key of await caches.keys()) await caches.delete(key);
      await self.clients.claim();
    })(),
  );
});

// Chrome требует fetch-обработчик для installable-страниц; ничего не кэшируем.
self.addEventListener("fetch", () => {});

self.addEventListener("push", (event) => {
  let data = {};
  try {
    data = event.data ? event.data.json() : {};
  } catch {
    // текстовый payload не по нашему формату: показываем сырой текст
    data = { body: event.data ? event.data.text() : "" };
  }
  const payload = {
    title: data.title || "Synapse",
    body: data.body || "",
    url: data.url || "/my-events",
    tag: data.event_id || undefined, // дедуп показов одного события
  };
  event.waitUntil(
    self.registration.showNotification(payload.title, {
      body: payload.body,
      tag: payload.tag,
      icon: "/assets/imgs/synapse-icon-192.png",
      badge: "/assets/imgs/synapse-icon-192.png",
      data: { url: payload.url },
    }),
  );
});

self.addEventListener("notificationclick", (event) => {
  const url = (event.notification.data && event.notification.data.url) || "/my-events";
  event.notification.close();
  event.waitUntil(
    (async () => {
      const clients = await self.clients.matchAll({ type: "window", includeUncontrolled: true });
      for (const client of clients) {
        if ("focus" in client) {
          await client.focus();
          if (client.navigate) await client.navigate(url);
          return;
        }
      }
      await self.clients.openWindow(url);
    })(),
  );
});