Files
mono/components/desktop/public/push-sw.js
T
coopops 7c01011a51 [@ant] fix(push): обработчик push в генерируемом SW + видимые логи доставки
Корень «push отправлен, но не виден»: workboxMode GenerateSW игнорирует
sourceFiles.serviceWorker, поэтому push/notificationclick из
custom-service-worker.ts в прод не попадали — браузер push получал, но SW его
не показывал (бэкенд честно «sent to N subscription(s)»). Доказано: прод
/service-worker.js содержит 0 push-обработчиков.

- desktop: public/push-sw.js (push → showNotification, notificationclick →
  focus/openWindow) + importScripts('push-sw.js') в extendGenerateSWOptions
- controller: «Доставлено»/«Канал пропущен» debug→info + сводка
  «web-push → user: N подписок» — чтобы доставка была видна в логах без БД
2026-06-09 15:25:31 +00:00

78 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* eslint-disable */
/*
* Push-обработчик service worker'а.
*
* Подключается в СГЕНЕРИРОВАННЫЙ Workbox'ом service-worker.js через
* `importScripts` (см. quasar.config.cjs → pwa.extendGenerateSWOptions →
* cfg.importScripts). Это единственный РАБОЧИЙ источник push-логики на проде:
* режим `workboxMode: 'GenerateSW'` игнорирует sourceFiles.serviceWorker, из-за
* чего обработчик в src-pwa/custom-service-worker.ts в прод НЕ попадал и push
* приходил в браузер, но не показывался (бэкенд при этом честно «sent»).
*
* Файл в public/ → Quasar кладёт его в корень сборки, importScripts видит как
* /push-sw.js. Это обычный SW-скрипт (не ES-модуль): только self.addEventListener.
*/
self.addEventListener('push', (event) => {
let data = {};
try {
if (event.data) {
// web-push шлёт JSON-строку {title, body, icon, badge, image, url, tag, ...}
data = event.data.json();
}
} catch (e) {
try {
data = { body: event.data && event.data.text() };
} catch (e2) {
data = {};
}
}
const title = data.title || 'Новое уведомление';
const options = {
body: data.body || '',
icon: data.icon || '/icons/icon-192x192.png',
badge: data.badge || '/icons/icon-192x192.png',
image: data.image,
tag: data.tag || 'general',
requireInteraction: !!data.requireInteraction,
silent: !!data.silent,
data: {
url: data.url || '/',
timestamp: data.timestamp || Date.now(),
},
};
if (Array.isArray(data.actions) && data.actions.length) {
options.actions = data.actions;
}
event.waitUntil(self.registration.showNotification(title, options));
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
const url = (event.notification.data && event.notification.data.url) || '/';
event.waitUntil(
self.clients
.matchAll({ type: 'window', includeUncontrolled: true })
.then((clients) => {
// Если вкладка приложения уже открыта — фокусируем и навигируем её.
for (const client of clients) {
if ('focus' in client) {
client.focus();
if ('navigate' in client && url !== '/') {
try {
client.navigate(url);
} catch (e) {
/* navigate доступен не всегда — не критично */
}
}
return;
}
}
// Иначе открываем новую вкладку.
if (self.clients.openWindow) return self.clients.openWindow(url);
}),
);
});