/* eslint-env serviceworker */
/* global workbox */
/* eslint-disable */ /* ... because old-browser-compatible files in this directory are combined into a single script during `npm run build` */
importScripts (
"https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js" ,
) ;
function logConsoleAndDb ( message , arg1 , arg2 ) {
// in chrome://serviceworker-internals note that the arg1 and arg2 here will show as "[object Object]" in that page but will show as expandable objects in the console
console . log ( ` ${ new Date ( ) . toISOString ( ) } ${ message } ` , arg1 , arg2 ) ;
// appendDailyLog is injected at build time by the vue.config.js configureWebpack apply plugin
// eslint-disable-next-line no-undef
if ( appendDailyLog ) {
let fullMessage = ` ${ new Date ( ) . toISOString ( ) } ${ message } ` ;
if ( arg1 ) {
fullMessage += ` \n ${ JSON . stringify ( arg1 ) } ` ;
}
if ( arg2 ) {
fullMessage += ` \n ${ JSON . stringify ( arg2 ) } ` ;
}
// appendDailyLog is injected from safari-notifications.js at build time by the vue.config.js configureWebpack apply plugin
// eslint-disable-next-line no-undef
appendDailyLog ( fullMessage ) ;
} else {
// sometimes we get the error: "Uncaught TypeError: appendDailyLog is not a function"
console . log (
"Not logging to DB (often because appendDailyLog doesn't exist)." ,
) ;
}
}
self . addEventListener ( "install" , async ( /* event */ ) => {
logConsoleAndDb ( "Service worker finished installation." ) ;
} ) ;
self . addEventListener ( "activate" , ( event ) => {
logConsoleAndDb ( "Service worker is activating..." , event ) ;
// see https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim
// and https://web.dev/articles/service-worker-lifecycle#clientsclaim
event . waitUntil ( clients . claim ( ) ) ;
logConsoleAndDb ( "Service worker is activated." ) ;
} ) ;
self . addEventListener ( "push" , function ( event ) {
let text = null ;
if ( event . data ) {
text = event . data . text ( ) ;
}
logConsoleAndDb ( "Service worker received a push event." , text , event ) ;
event . waitUntil (
( async ( ) => {
try {
let payload ;
if ( text ) {
try {
payload = JSON . parse ( text ) ;
} catch ( e ) {
// don't use payload since it is not JSON
}
}
// This is a special value that tells the service worker to trigger its daily check.
// See https://gitea.anomalistdesign.com/trent_larson/py-push-server/src/commit/c1ed026662e754348a5f91542680bd4f57e5b81e/app.py#L217
const DAILY_UPDATE_TITLE = "DAILY_CHECK" ;
// This is a special value that tells the service worker to send a direct notification to the device, skipping filters.
// This is shared with the notification-test code and should be a constant. Look for the same name in HelpNotificationsView.vue
// Make sure it is something other than the DAILY_UPDATE_TITLE.
const DIRECT_PUSH_TITLE = "DIRECT_NOTIFICATION" ;
let title ;
let message = "Got some empty message." ;
if ( payload && payload . title == DIRECT_PUSH_TITLE ) {
// skip any search logic and show the message directly
title = "Direct Notification" ;
message = payload . message || "No details were provided." ;
} else {
// any other title will run through regular filtering logic
if ( payload && payload . title === DAILY_UPDATE_TITLE ) {
title = "Daily Update" ;
} else {
title = payload . title || "Update" ;
}
// getNotificationCount is injected from safari-notifications.js at build time by the sw_combine.js script
// eslint-disable-next-line no-undef
message = await getNotificationCount ( ) ;
}
if ( message ) {
const options = {
body : message ,
icon : payload ? payload . icon : "icon.png" ,
badge : payload ? payload . badge : "badge.png" ,
} ;
await self . registration . showNotification ( title , options ) ;
logConsoleAndDb ( "Notified user:" , options ) ;
} else {
logConsoleAndDb ( "No notification message." ) ;
}
} catch ( error ) {
logConsoleAndDb ( "Error with push event" , event , error ) ;
}
} ) ( ) ,
) ;
} ) ;
self . addEventListener ( "message" , ( event ) => {
logConsoleAndDb ( "Service worker got a message..." , event ) ;
if ( event . data && event . data . type === "SEND_LOCAL_DATA" ) {
self . secret = event . data . data ;
event . ports [ 0 ] . postMessage ( { success : true } ) ;
}
logConsoleAndDb ( "Service worker posted a message." ) ;
} ) ;
self . addEventListener ( "notificationclick" , ( event ) => {
logConsoleAndDb ( "Notification got clicked." , event ) ;
event . notification . close ( ) ;
// from https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/notificationclick_event
// ... though I don't see any benefit over just "clients.openWindow"
event . waitUntil (
clients
. matchAll ( {
type : "window" ,
} )
. then ( ( clientList ) => {
for ( const client of clientList ) {
if ( client . url === "/" && "focus" in client ) return client . focus ( ) ;
}
if ( clients . openWindow ) return clients . openWindow ( "/" ) ;
} ) ,
) ;
} ) ;
// This is invoked when the user chooses this as a share_target, mapped to share-target in the manifest.
self . addEventListener ( "fetch" , ( event ) => {
logConsoleAndDb ( "Service worker got fetch event." , event ) ;
// Bypass any regular requests not related to Web Share Target
// and also requests that are not exactly to the timesafari.app
// (because Chrome will send subdomain requests like image-api.timesafari.app through this service worker).
if (
event . request . method !== "POST" ||
( event . request . url . hostname !== "timesafari.app" &&
event . request . url . hostname !== "test.timesafari.app" &&
event . request . url . hostname !== "localhost" )
) {
event . respondWith ( fetch ( event . request ) ) ;
return ;
}
// Requests related to Web Share share-target Target.
event . respondWith (
( async ( ) => {
const formData = await event . request . formData ( ) ;
const photo = formData . get ( "photo" ) ;
// savePhoto is injected from safari-notifications.js at build time by the sw_combine.js script
// eslint-disable-next-line no-undef
await savePhoto ( photo ) ;
return Response . redirect ( "/shared-photo" , 303 ) ;
} ) ( ) ,
) ;
} ) ;
self . addEventListener ( "error" , ( event ) => {
logConsoleAndDb ( "Service worker error" , event ) ;
console . error ( "Full Error:" , event ) ;
console . error ( "Message:" , event . message ) ;
console . error ( "File:" , event . filename ) ;
console . error ( "Line:" , event . lineno ) ;
console . error ( "Column:" , event . colno ) ;
console . error ( "Error Object:" , event . error ) ;
} ) ;
workbox . precaching . precacheAndRoute ( self . __ WB_MANIFEST ) ;