const VER = 6 self.addEventListener('message', async (event) => { event.waitUntil(debug(event.source, Object.assign({ answer: true }, event.data))) }) self.addEventListener('install', (event) => { console.log('install event:', event) // The promise that skipWaiting() returns can be safely ignored. event.waitUntil(self.skipWaiting().then(() => debug(event.source, { installed: true }))) // Perform any other actions required for your // service worker to install, potentially inside // of event.waitUntil(); }) self.addEventListener('activate', (event) => { event.waitUntil( // Привязка нового сервис-воркера к текущим клиентам clients.claim().then(() => debug(event.source, { activated: true })), ) }) self.addEventListener('push', (event) => { // PushData keys structure standart https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification let pushData = event.data.json() if (!pushData || !pushData.notification.title) { console.error('Received WebPush with an empty title. Received body: ', pushData) } self.registration .showNotification(pushData.notification.title, pushData.notification.options) .then(function () { // You can save to your analytics fact that push was shown // fetch('https://your_backend_server.com/track_show?message_id=' + pushData.data.message_id); }) }) async function handleNotificationClick(event) { event.notification.close() if (!event.notification.data) { await debug(null, { error: 'Click on WebPush with empty data, where url should be. Notification', }) console.error( 'Click on WebPush with empty data, where url should be. Notification: ', event.notification, ) return } if (!event.notification.data.url) { await debug(null, { error: 'Click on WebPush without url. Notification' }) console.error('Click on WebPush without url. Notification: ', event.notification) return } await openURL(event.notification.data.url) } self.addEventListener('notificationclick', (event) => { event.waitUntil(handleNotificationClick(event)) }) async function openURL(urlToOpen) { let matchedClients try { const urlToOpenObj = new URL(urlToOpen, location.origin) matchedClients = await clients.matchAll({ type: 'window', includeUncontrolled: true }) try { for (const client of matchedClients) { const clientUrlObj = new URL(client.url) try { if ( urlToOpenObj.pathname + urlToOpenObj.search !== clientUrlObj.pathname + clientUrlObj.search ) { await debug(client, { urlToOpenObj: urlToOpenObj.pathname + urlToOpenObj.search, clientUrlObj: clientUrlObj.pathname + clientUrlObj.search, }) continue } if (client.focused) { return } await client.focus() return } catch (error) { await debug({ error: error.message }) } } } catch (error) { console.error('get client error', error) } } catch (error) { console.error('openURL error', error) } try { const client = await clients.openWindow(urlToOpen) if (!client) { await debug(client, { error: 'client is null' }) throw new Error('client is null') } } catch (error) { await debug(matchedClients && matchedClients[0], { error: error.message }) console.error(error) } } async function debug(client, data) { try { if (!client) { const matchedClients = await clients.matchAll({ type: 'window', includeUncontrolled: true }) for (const matchedClient of matchedClients) { if (matchedClient.focused) { client = matchedClient break } } if (!client && matchedClients.length) { return Promise.all(matchedClients.map((client) => debug(client, data))) } } if (!client) { throw new Error('not found client for debug') } if (!client.postMessage) { console.error('not found client.postMessage for debug', client) return } await client.postMessage({ type: 'debug', debug: Object.assign({ VER }, data || {}), }) } catch (error) { console.error(error) } }