Created
May 31, 2017 06:44
-
-
Save ymichael/6f0e2b78add837f2fa9fc32ff677a167 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* AUTOGENERATED FROM GENERATE-SERVICE-WORKER | |
*/ | |
const $VERSION = '26f8b6b6d92f0e7d7b7dc5ccae53d58f'; | |
const $DEBUG = false; | |
const $Cache = { | |
"precache": [ | |
"https://s.pinimg.com/webapp/js/entryChunk-react-common-5c5fb1fe655d0e4956c2.js", | |
"https://s.pinimg.com/webapp/js/vendor-react-6f23018b1ba21a553ff6.js", | |
"https://s.pinimg.com/webapp/js/entryChunk-core-83d9ab9b588db714a657.js", | |
"https://s.pinimg.com/webapp/js/external-core-2-05e6d3187f10f7f103ab.js", | |
"https://s.pinimg.com/webapp/js/external-core-1-95974d515de8fc25ba4e.js", | |
"https://s.pinimg.com/webapp/js/external-core-1-slim-345a3f71f5ea89c81fd7.js" | |
], | |
"strategy": [ | |
{ | |
"type": "prefer-cache", | |
"matches": [ | |
"webapp/js/.*\\.js", | |
".*\\.css" | |
] | |
} | |
] | |
}; | |
const $Notifications = { | |
"fallbackURL": "_/_/push/web_push_content/", | |
"default": { | |
"title": "Fresh Pins!", | |
"body": "You’ve got new Pins waiting for you on Pinterest.", | |
"icon": "https://s.pinimg.com/images/favicon_red_192.png", | |
"tag": "pinterest-push-notification-tag" | |
} | |
}; | |
const $Log = { | |
"notificationClicked": "_/_/push/web_push_click/" | |
}; | |
if (!$Cache) { | |
self.addEventListener('install', (event) => { | |
event.waitUntil(self.skipWaiting()); | |
}); | |
} | |
function print(fn) { | |
return function (message, group) { | |
if ($DEBUG) { | |
if (group && logger.groups[group]) { | |
logger.groups[group].push({ | |
fn: fn, | |
message: message | |
}); | |
} else { | |
console[fn].call(console, message); | |
} | |
} | |
}; | |
} | |
const logger = { | |
groups: {}, | |
group: group => { | |
logger.groups[group] = []; | |
}, | |
groupEnd: group => { | |
const groupLogs = logger.groups[group]; | |
if (groupLogs && groupLogs.length > 0) { | |
console.groupCollapsed(group); | |
groupLogs.forEach(log => { | |
console[log.fn].call(console, log.message); | |
}); | |
console.groupEnd(); | |
} | |
delete logger.groups[group]; | |
}, | |
log: print('log'), | |
warn: print('warn'), | |
error: print('error') | |
}; | |
/* -------- CACHE --------- */ | |
const CURRENT_CACHE = `SW_CACHE:${$VERSION}`; | |
const STATIC_CACHE = 'static'; | |
const AVAILABLE_CACHES = [CURRENT_CACHE, STATIC_CACHE]; | |
const isValidResponse = res => (res.ok || (res.status === 0 && res.type === 'opaque')); | |
/* -------- CACHE LISTENERS --------- */ | |
self.addEventListener('install', handleInstall); | |
self.addEventListener('activate', handleActivate); | |
if ($Cache.precache || $Cache.strategy) { | |
self.addEventListener('fetch', handleFetch); | |
} | |
/* -------- CACHE HANDLERS --------- */ | |
function handleInstall(event) { | |
logger.log('Entering install handler.'); | |
self.skipWaiting(); | |
if ($Cache.precache) { | |
event.waitUntil(precache()); | |
} | |
} | |
function handleActivate(event) { | |
logger.log('Entering activate handler.'); | |
const cachesCleared = caches.keys().then(cacheNames => { | |
logger.group('cleanup'); | |
return Promise.all(cacheNames.map(cacheName => { | |
if (!AVAILABLE_CACHES.includes(cacheName)) { | |
logger.log(`Deleting cache key: ${cacheName}`, 'cleanup'); | |
return caches.delete(cacheName); | |
} | |
return Promise.resolve(); | |
})).then(() => logger.groupEnd('cleanup')); | |
}); | |
event.waitUntil(cachesCleared); | |
} | |
function handleFetch(event) { | |
if (event.request.method === 'GET') { | |
const strategy = getStrategyForUrl(event.request.url); | |
if (strategy) { | |
logger.group(event.request.url); | |
logger.log(`Using strategy ${strategy.type}.`, event.request.url); | |
event.respondWith( | |
applyEventStrategy(strategy, event).then(response => { | |
logger.groupEnd(event.request.url); | |
return response; | |
}) | |
); | |
} | |
} | |
} | |
/* -------- CACHE HELPERS --------- */ | |
function applyEventStrategy(strategy, event) { | |
const request = event.request; | |
switch (strategy.type) { | |
case 'offline-only': | |
return fetchAndCache(request, strategy)().catch(getFromCache(request)); | |
case 'fallback-only': | |
return fetchAndCache(request, strategy)().then(fallbackToCache(request)); | |
case 'prefer-cache': | |
return getFromCache(request)().catch(fetchAndCache(request, strategy)); | |
case 'race': | |
return getFromFastest(request, strategy)(); | |
default: | |
return Promise.reject(`Strategy not supported: ${strategy.type}`); | |
} | |
} | |
function insertInCache(request, response, strategy) { | |
logger.log('Inserting in cache.', request.url); | |
const cacheName = strategy.keepAlive ? STATIC_CACHE : CURRENT_CACHE; | |
return caches.open(cacheName) | |
.then(cache => cache.put(request, response)); | |
} | |
function getFromCache(request) { | |
return () => { | |
return caches.match(request).then(response => { | |
if (response) { | |
logger.log('Found entry in cache.', request.url); | |
return response; | |
} | |
logger.log('No entry found in cache.', request.url); | |
throw new Error(`No cache entry found for ${request.url}`); | |
}); | |
}; | |
} | |
function getStrategyForUrl(url) { | |
if ($Cache.strategy) { | |
return $Cache.strategy.find(strategy => { | |
return strategy.matches.some(match => { | |
const regex = new RegExp(match); | |
return regex.test(url); | |
}); | |
}); | |
} | |
return null; | |
} | |
function fetchAndCache(request, strategy) { | |
return () => { | |
logger.log('Fetching remote data.', request.url); | |
return fetch(request).then(response => { | |
if (isValidResponse(response)) { | |
logger.log('Caching remote response.', request.url); | |
insertInCache(request, response.clone(), strategy); | |
} else { | |
logger.log('Fetch error.', request.url); | |
} | |
return response; | |
}); | |
}; | |
} | |
function fallbackToCache(request) { | |
return (response) => { | |
if (!isValidResponse(response)) { | |
return getFromCache(request)(); | |
} | |
return response; | |
}; | |
} | |
function getFromFastest(request, strategy) { | |
return () => new Promise((resolve, reject) => { | |
var errors = 0; | |
function raceReject() { | |
errors += 1; | |
if (errors === 2) { | |
reject(new Error('Network and cache both failed.')); | |
} | |
} | |
function raceResolve(response) { | |
if (response instanceof Response) { | |
resolve(response); | |
} else { | |
raceReject(); | |
} | |
} | |
getFromCache(request)() | |
.then(raceResolve, raceReject); | |
fetchAndCache(request, strategy)() | |
.then(raceResolve, raceReject); | |
}); | |
} | |
function precache() { | |
logger.group('precaching'); | |
return caches.open(CURRENT_CACHE).then(cache => { | |
return Promise.all( | |
$Cache.precache.map(urlToPrefetch => { | |
logger.log(urlToPrefetch, 'precaching'); | |
const cacheBustedUrl = new URL(urlToPrefetch, location.href); | |
cacheBustedUrl.search += (cacheBustedUrl.search ? '&' : '?') + `cache-bust=${Date.now()}`; | |
const request = new Request(cacheBustedUrl, { mode: 'no-cors' }); | |
return fetch(request).then(response => { | |
if (!isValidResponse(response)) { | |
logger.error(`Failed for ${urlToPrefetch}.`, 'precaching'); | |
return undefined; | |
} | |
return cache.put(urlToPrefetch, response); | |
}); | |
}) | |
); | |
}).then(() => logger.groupEnd('precaching')); | |
} | |
'use strict'; | |
/* -------- NOTIFICATIONS --------- */ | |
self.addEventListener('push', handleNotificationPush); | |
self.addEventListener('notificationclick', handleNotificationClick); | |
/* -------- NOTIFICATIONS HANDLERS --------- */ | |
function handleNotificationPush(event) { | |
logger.log('Push notification received'); | |
if ($Log.notificationReceived) { | |
event.waitUntil(logNotificationReceived(event)); | |
} | |
// Show notification or fallback | |
if (event.data && event.data.title) { | |
event.waitUntil(showNotification(event.data)); | |
} else if ($Notifications.fallbackURL) { | |
event.waitUntil( | |
self.registration.pushManager.getSubscription() | |
.then(fetchNotification) | |
.then(convertResponseToJson) | |
.then(showNotification) | |
.catch(showNotification) | |
); | |
} else { | |
logger.warn('No notification.data and no fallbackURL.'); | |
event.waitUntil(showNotification()); | |
} | |
} | |
function handleNotificationClick(event) { | |
logger.log('Push notification clicked.', event.notification.tag); | |
if ($Log.notificationClicked) { | |
event.waitUntil(logNotificationClick(event)); | |
} | |
// Open the url if provided | |
if (event.notification.data && event.notification.data.url) { | |
const url = event.notification.data.url; | |
event.waitUntil(openWindow(url)); | |
} else if (event.notification.tag.indexOf(':') !== -1) { | |
// TODO: Deprecate | |
const url = event.notification.tag.split(':')[2] || '/'; | |
event.waitUntil(openWindow(url)); | |
} else { | |
logger.warn('Cannot route click with no data.url property. Using "/".', event.notification.tag); | |
event.waitUntil(openWindow('/')); | |
} | |
event.notification.close(); | |
logger.groupEnd(event.notification.tag); | |
} | |
/* -------- NOTIFICATIONS HELPERS --------- */ | |
function showNotification(data) { | |
if (!data || !data.tag) { | |
// eslint-disable-next-line no-param-reassign | |
data = $Notifications.default; | |
} | |
logger.group(data.tag); | |
logger.log('Show notification.', data.tag); | |
return self.registration | |
.showNotification(data.title, data) | |
.then(delayDismissNotification); | |
} | |
function fetchNotification(subscription) { | |
if (!subscription) { | |
logger.warn('No subscription found.'); | |
throw new Error('No subscription found.'); | |
} | |
logger.log('Fetching remote notification data.'); | |
const queries = { | |
endpoint: subscription.endpoint | |
}; | |
const url = formatUrl($Notifications.fallbackURL, queries); | |
return fetch(url, { credentials: 'include' }); | |
} | |
function convertResponseToJson(response) { | |
if (response.status !== 200) { | |
throw new Error('Notification data fetch failed.'); | |
} | |
return response.json(); | |
} | |
function delayDismissNotification() { | |
setTimeout(function serviceWorkerDismissNotification() { | |
self.registration.getNotifications() | |
.then(notifications => { | |
notifications.forEach(notification => { | |
notification.close(); | |
logger.log('Dismissing notification.', notification.tag); | |
logger.groupEnd(notification.tag); | |
}); | |
}); | |
}, $Notifications.duration || 5000); | |
} | |
function openWindow(url) { | |
if (clients.openWindow) { | |
return clients.openWindow(url); | |
} | |
return Promise.resolve(); | |
} | |
function logNotificationReceived(event) { | |
return logAction(event, $Log.notificationReceived); | |
} | |
function logNotificationClick(event) { | |
return logAction(event.notification, $Log.notificationClicked); | |
} | |
function logAction(notification, url) { | |
logger.log(`Send log event to ${url}.`, notification.tag); | |
return self.registration.pushManager.getSubscription().then((subscription) => { | |
const query = { | |
endpoint: subscription.endpoint, | |
tag: notification.tag | |
}; | |
return fetch(formatUrl(url, query), { credentials: 'include' }); | |
}); | |
} | |
function formatUrl(url, queries) { | |
const prefix = url.includes('?') ? '&' : '?'; | |
const query = Object.keys(queries).map(function (key) { | |
return `${key}=${queries[key]}`; | |
}).join('&'); | |
return url + prefix + query; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment