1self.addEventListener("push", async (event) => { 2 if (!event.data) return 3 4 let notificationData = event.data.json(); 5 6 const allClients = await clients.matchAll({ 7 type: "window", 8 includeUncontrolled: true, 9 }); 10 11 if (!allClients.length) { 12 console.log("No open tabs, skipping the push notification."); 13 return; 14 } 15 16 const title = notificationData.title || "New Cal.com Notification"; 17 const image = notificationData.icon || "https://cal.com/api/logo?type=icon"; 18 19 event.waitUntil( 20 (async () => { 21 try { 22 // Close notifications with the same tag if it exists 23 const existingNotifications = await self.registration.getNotifications({ 24 tag: notificationData.tag 25 }); 26 27 existingNotifications.forEach((notification) => { 28 notification.close(); 29 }); 30 31 // Special handling for instant meetings 32 if (notificationData.data?.type === "INSTANT_MEETING") { 33 allClients.forEach(client => { 34 client.postMessage({ 35 type: 'PLAY_NOTIFICATION_SOUND' 36 }); 37 }); 38 } 39 40 const notificationOptions = { 41 body: notificationData.body, 42 icon: image, 43 badge: image, 44 data: notificationData.data, 45 tag: notificationData.tag || `cal-notification-${Date.now()}`, 46 renotify: true, 47 requireInteraction: notificationData.requireInteraction ?? true, 48 actions: notificationData.actions || [], 49 vibrate: [200, 100, 200], 50 urgency: 'high' 51 }; 52 53 console.log("notificationOptions", notificationOptions); 54 55 await self.registration.showNotification(title, notificationOptions); 56 console.log("Notification shown successfully"); 57 } catch (error) { 58 console.error("Error showing notification:", error); 59 } 60 })() 61 ); 62}); 63 64 65self.addEventListener("notificationclick", (event) => { 66 if (event.notification.data?.type === "INSTANT_MEETING") { 67 const stopSound = async () => { 68 const allClients = await clients.matchAll({ 69 type: "window", 70 includeUncontrolled: true, 71 }); 72 73 allClients.forEach(client => { 74 client.postMessage({ 75 type: 'STOP_NOTIFICATION_SOUND' 76 }); 77 }); 78 }; 79 80 event.waitUntil(stopSound()); 81 } 82 83 if (!event.action) { 84 // Normal Notification Click 85 event.notification.close(); 86 const url = event.notification.data.url; 87 event.waitUntil(self.clients.openWindow(url)); 88 } 89 90 switch (event.action) { 91 case "connect-action": 92 event.notification.close(); 93 const url = event.notification.data.url; 94 event.waitUntil(self.clients.openWindow(url)); 95 break; 96 } 97}); 98 99self.addEventListener('install', (event) => { 100 console.log('Service Worker installing.'); 101}); 102 103self.addEventListener('activate', (event) => { 104 console.log('Service Worker activated.'); 105 106 event.waitUntil( 107 (async () => { 108 const notifications = await self.registration.getNotifications(); 109 notifications.forEach(notification => notification.close()); 110 111 return self.clients.claim(); 112 })() 113 ); 114});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.