first commit
This commit is contained in:
21
build/node_modules/generate-service-worker/LICENSE
generated
vendored
Normal file
21
build/node_modules/generate-service-worker/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Pinterest
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
95
build/node_modules/generate-service-worker/README.md
generated
vendored
Normal file
95
build/node_modules/generate-service-worker/README.md
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
Generate Service Worker
|
||||
=========================
|
||||
A node module for generating service worker files based on provided configuration options.
|
||||
|
||||
## Why?
|
||||
There are several other popular service worker generators out there ([sw-precache](https://github.com/GoogleChrome/sw-precache), [offline-plugin](https://github.com/NekR/offline-plugin/), etc), but they focus only on caching, and are not testable or easy to experiment with. Service workers also include support for other tools like notifications and homescreen installs. This generator attempts to account for a wider variety of configurable options.
|
||||
|
||||
GenerateServiceWorker supports generating a service worker with a root configuration, and any number of other experimental service workers. **This is perfect for experimenting with different caching strategies, or rolling out service worker changes.** The runtime file generated by [service-worker-plugin](https://github.com/pinterest/service-workers/tree/master/packages/service-worker-plugin) makes it particularly easy to utilize your own experiment framework alongside the generated experimental service worker files if you can statically host the service workers.
|
||||
|
||||
Caching strategies inspired by [sw-toolkit](https://github.com/GoogleChrome/sw-toolbox).
|
||||
|
||||
## Use
|
||||
|
||||
```js
|
||||
const generateServiceWorkers = require('generate-service-worker');
|
||||
|
||||
const serviceWorkers = generateServiceWorkers({
|
||||
cache: {
|
||||
offline: true,
|
||||
precache: ['/static/js/bundle-81hj9isadf973adfsh10.js'],
|
||||
strategy: [{
|
||||
type: 'prefer-cache',
|
||||
matches: ['\\.js']
|
||||
}],
|
||||
}
|
||||
}, {
|
||||
'roll_out_notifications': {
|
||||
notifications: {
|
||||
default: {
|
||||
title: 'Pinterest',
|
||||
body: 'You\'ve got new Pins!'
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Configurations
|
||||
GenerateServiceWorker currently supports caching and notifications. The following are the configuration options for each.
|
||||
|
||||
### Caching
|
||||
The `cache` key is used for defining caching strategies. The strings in `precache` will be used to prefetch assets and insert them into the cache. The regexes in `strategy.matches` are used at runtime to determine which strategy to use for a given GET request. All cached items will be removed at installation of a new service worker version. Additionally, you can use your own custom cache template by including the full path in the `template` property. We suggest forking our `templates/cache.js` file to get started and to be familiar with how variable injection works in the codebase. If the `offline` option is set to `true`, the service worker will assume that an html response is an "App Shell". It will cache the html response and return it only in the case of a static route change while offline.
|
||||
```js
|
||||
const CacheType = {
|
||||
offline?: boolean,
|
||||
precache?: Array<string>,
|
||||
strategy?: Array<StrategyType>,
|
||||
template?: string,
|
||||
};
|
||||
const StrategyType = {
|
||||
type: 'offline-only' | 'fallback-only' | 'prefer-cache' | 'race',
|
||||
matches: Array<regex>,
|
||||
};
|
||||
```
|
||||
|
||||
### Strategy Types
|
||||
strategy | description
|
||||
--------------- | -----------
|
||||
`offline-only` | Only serve from cache if browser is offline.
|
||||
`fallback-only` | Only serve from cache if fetch returns an error status (>= 400)
|
||||
`prefer-cache` | Always pull from cache if data is available
|
||||
`race` | Pull from cache and make fetch request. Whichever returns first should be used. (Good for some low-end phones)
|
||||
|
||||
|
||||
### Notifications
|
||||
The `notifications` key is used for including browser notification events in your service worker. To enable the notifications in your app, you can call `runtime.requestNotificationsPermission()` from the generated runtime file. The backend work is not included. You will still need to push notifications to your provider and handle registration. Additionally, you can use your own custom notifications template by including the full path in the `template` property. We suggest forking our `templates/notifications.js` file to get started and to be familiar with how variable injection works in the codebase.
|
||||
```js
|
||||
const NotificationsType = {
|
||||
default: {
|
||||
title: string,
|
||||
body?: string,
|
||||
icon?: string,
|
||||
tag?: string,
|
||||
data?: {
|
||||
url: string
|
||||
}
|
||||
},
|
||||
duration?: number,
|
||||
template?: string,
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### Event Logging
|
||||
The `log` key is used for defining which service worker events your API wants to know about. Each `string` should be a valid url path that will receive a 'GET' request for the corresponding event.
|
||||
```js
|
||||
const LogType = {
|
||||
notificationClicked?: string,
|
||||
notificationReceived?: string
|
||||
};
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
66
build/node_modules/generate-service-worker/index.js
generated
vendored
Normal file
66
build/node_modules/generate-service-worker/index.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const hash = require('./utils/hash');
|
||||
const validate = require('./utils/validators').validate;
|
||||
|
||||
const TEMPLATE_PATH = path.join(__dirname, 'templates');
|
||||
|
||||
function buildMainTemplate(config) {
|
||||
const template = config.template || path.join(TEMPLATE_PATH, 'main.js');
|
||||
return fs.readFileSync(template, 'utf-8');
|
||||
}
|
||||
|
||||
function buildCacheTemplate(config) {
|
||||
if (!config.cache) {
|
||||
return '';
|
||||
}
|
||||
const template = config.cache.template || path.join(TEMPLATE_PATH, 'cache.js');
|
||||
return fs.readFileSync(template, 'utf-8');
|
||||
}
|
||||
|
||||
function buildNotificationsTemplate(config) {
|
||||
if (!config.notifications) {
|
||||
return '';
|
||||
}
|
||||
const template = config.notifications.template || path.join(TEMPLATE_PATH, 'notifications.js');
|
||||
return fs.readFileSync(template, 'utf-8');
|
||||
}
|
||||
|
||||
function buildServiceWorker(config) {
|
||||
const Cache = config.cache ? JSON.stringify(config.cache, null, 2) : 'undefined';
|
||||
const Notifications = config.notifications ? JSON.stringify(config.notifications, null, 2) : 'undefined';
|
||||
const Log = config.log ? JSON.stringify(config.log, null, 2) : '{}';
|
||||
return [
|
||||
'/*\n * AUTOGENERATED FROM GENERATE-SERVICE-WORKER\n */\n',
|
||||
`const $VERSION = '${hash(config)}';`,
|
||||
`const $DEBUG = ${config.debug || false};`,
|
||||
`const $Cache = ${Cache};`,
|
||||
`const $Notifications = ${Notifications};`,
|
||||
`const $Log = ${Log};\n`,
|
||||
buildMainTemplate(config),
|
||||
buildCacheTemplate(config),
|
||||
buildNotificationsTemplate(config)
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* Public API. This method will generate a root service worker and any number of
|
||||
* extended configuration service workers (used for testing/experimentation).
|
||||
* @returns Object { [key]: service-worker }
|
||||
*/
|
||||
module.exports = function generateServiceWorkers(baseConfig, experimentConfigs) {
|
||||
validate(baseConfig);
|
||||
|
||||
const serviceWorkers = {
|
||||
main: buildServiceWorker(baseConfig)
|
||||
};
|
||||
|
||||
Object.keys(experimentConfigs || {}).forEach(key => {
|
||||
validate(experimentConfigs[key]);
|
||||
serviceWorkers[key] = buildServiceWorker(experimentConfigs[key]);
|
||||
});
|
||||
|
||||
return serviceWorkers;
|
||||
};
|
||||
54
build/node_modules/generate-service-worker/package.json
generated
vendored
Normal file
54
build/node_modules/generate-service-worker/package.json
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"_from": "generate-service-worker",
|
||||
"_id": "generate-service-worker@1.7.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-tFWMUBUOrOTREj5HjQ3gAXgamUc=",
|
||||
"_location": "/generate-service-worker",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "tag",
|
||||
"registry": true,
|
||||
"raw": "generate-service-worker",
|
||||
"name": "generate-service-worker",
|
||||
"escapedName": "generate-service-worker",
|
||||
"rawSpec": "",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "latest"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"#USER",
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/generate-service-worker/-/generate-service-worker-1.7.2.tgz",
|
||||
"_shasum": "b4558c50150eace4d1123e478d0de001781a9947",
|
||||
"_spec": "generate-service-worker",
|
||||
"_where": "/Users/asciidisco/Desktop/asciidisco.com/build",
|
||||
"author": {
|
||||
"name": "zackargyle"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/pinterest/service-workers/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"deprecated": false,
|
||||
"description": "Generate Service Worker ========================= A node module for generating service worker files based on provided configuration options.",
|
||||
"files": [
|
||||
"index.js",
|
||||
"templates/*.js",
|
||||
"utils/*.js"
|
||||
],
|
||||
"homepage": "https://github.com/pinterest/service-workers/tree/master/packages/generate-service-worker",
|
||||
"keywords": [
|
||||
"service-workers",
|
||||
"service",
|
||||
"workers"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"name": "generate-service-worker",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pinterest/service-workers.git"
|
||||
},
|
||||
"version": "1.7.2"
|
||||
}
|
||||
198
build/node_modules/generate-service-worker/templates/cache.js
generated
vendored
Normal file
198
build/node_modules/generate-service-worker/templates/cache.js
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
/* -------- CACHE --------- */
|
||||
|
||||
const CURRENT_CACHE = `SW_CACHE:${$VERSION}`;
|
||||
const APP_SHELL_CACHE = 'SW_APP_SHELL';
|
||||
|
||||
const isValidResponse = res => (res.ok || (res.status === 0 && res.type === 'opaque'));
|
||||
const isNavigation = req => req.mode === 'navigate' || (req.method === 'GET' && req.headers.get('accept').includes('text/html'));
|
||||
|
||||
/* -------- CACHE LISTENERS --------- */
|
||||
|
||||
self.addEventListener('install', handleInstall);
|
||||
self.addEventListener('activate', handleActivate);
|
||||
if ($Cache.precache || $Cache.offline || $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 (CURRENT_CACHE !== 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 (isNavigation(event.request)) {
|
||||
if ($Cache.offline) {
|
||||
event.respondWith(
|
||||
fetchAndCacheAppShell(event.request)
|
||||
.catch(() => caches.match(APP_SHELL_CACHE))
|
||||
.catch(() => undefined)
|
||||
);
|
||||
}
|
||||
} else 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;
|
||||
}).catch(() => undefined)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- 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) {
|
||||
logger.log('Inserting in cache.', request.url);
|
||||
return caches.open(CURRENT_CACHE)
|
||||
.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) {
|
||||
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());
|
||||
} else {
|
||||
logger.log('Fetch error.', request.url);
|
||||
}
|
||||
return response;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function fetchAndCacheAppShell(request) {
|
||||
return fetch(request).then(response => {
|
||||
if (isValidResponse(response)) {
|
||||
logger.log('Caching app shell.', request.url);
|
||||
insertInCache(APP_SHELL_CACHE, response.clone());
|
||||
}
|
||||
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)
|
||||
.catch(raceReject);
|
||||
|
||||
fetchAndCache(request, strategy)()
|
||||
.then(raceResolve)
|
||||
.catch(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'));
|
||||
}
|
||||
41
build/node_modules/generate-service-worker/templates/main.js
generated
vendored
Normal file
41
build/node_modules/generate-service-worker/templates/main.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
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')
|
||||
};
|
||||
137
build/node_modules/generate-service-worker/templates/notifications.js
generated
vendored
Normal file
137
build/node_modules/generate-service-worker/templates/notifications.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
'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;
|
||||
}
|
||||
10
build/node_modules/generate-service-worker/utils/hash.js
generated
vendored
Normal file
10
build/node_modules/generate-service-worker/utils/hash.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
const crypto = require('crypto');
|
||||
|
||||
function buildHashFromConfig(config) {
|
||||
return crypto
|
||||
.createHash('md5')
|
||||
.update(JSON.stringify(config))
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
module.exports = buildHashFromConfig;
|
||||
102
build/node_modules/generate-service-worker/utils/validate.js
generated
vendored
Normal file
102
build/node_modules/generate-service-worker/utils/validate.js
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/* eslint-disable no-throw-literal */
|
||||
|
||||
function arrayOfTypeValidation(validator) {
|
||||
return withRequired(function arrayOfType(value) {
|
||||
if (!Array.isArray(value)) {
|
||||
throw `Value ${value} must be an array.`;
|
||||
}
|
||||
value.every(validator);
|
||||
});
|
||||
}
|
||||
|
||||
function oneOfTypeValidation(types) {
|
||||
return withRequired(function oneOf(value) {
|
||||
const isValidType = types.some(function (Type) {
|
||||
try {
|
||||
Type(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (!isValidType) {
|
||||
throw `Value ${value} not a valid type.`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function oneOfValidation(list) {
|
||||
return withRequired(function oneOf(value) {
|
||||
if (list.indexOf(value) === -1) {
|
||||
throw `Value ${value} not a valid option from list: ${list.join(', ')}.`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function shapeValidation(objShape) {
|
||||
return withRequired(function shape(value) {
|
||||
if (value && typeof value !== 'object') {
|
||||
throw `Value <${value}> must be an object.`;
|
||||
}
|
||||
Object.keys(objShape).forEach(function shapeKeyValidation(key) {
|
||||
try {
|
||||
objShape[key](value[key]);
|
||||
} catch (e) {
|
||||
if (objShape[key].name === 'shape') {
|
||||
throw e;
|
||||
} else {
|
||||
throw `Key: "${key}" failed with "${e}"`;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function booleanValidation(value) {
|
||||
if (!value || typeof value !== 'boolean') {
|
||||
throw `Value ${value} must be of type "boolean".`;
|
||||
}
|
||||
}
|
||||
|
||||
function objectValidation(value) {
|
||||
if (!value || typeof value !== 'object') {
|
||||
throw `Value ${value} must be non-null "object".`;
|
||||
}
|
||||
}
|
||||
|
||||
function stringValidation(value) {
|
||||
if (typeof value !== 'string') {
|
||||
throw `Value ${value} must be of type "string".`;
|
||||
}
|
||||
}
|
||||
|
||||
function numberValidation(value) {
|
||||
if (typeof value !== 'number') {
|
||||
throw `Value ${value} must be of type "number".`;
|
||||
}
|
||||
}
|
||||
|
||||
function withRequired(_validator) {
|
||||
function validator(value) {
|
||||
return value === undefined || _validator(value);
|
||||
}
|
||||
|
||||
validator.required = function requiredValidator(value) {
|
||||
if (value === undefined) {
|
||||
throw 'Value cannot be undefined.';
|
||||
}
|
||||
_validator(value);
|
||||
};
|
||||
return validator;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
boolean: withRequired(booleanValidation),
|
||||
object: withRequired(objectValidation),
|
||||
number: withRequired(numberValidation),
|
||||
string: withRequired(stringValidation),
|
||||
arrayOfType: arrayOfTypeValidation,
|
||||
oneOf: oneOfValidation,
|
||||
oneOfType: oneOfTypeValidation,
|
||||
shape: shapeValidation
|
||||
};
|
||||
54
build/node_modules/generate-service-worker/utils/validators.js
generated
vendored
Normal file
54
build/node_modules/generate-service-worker/utils/validators.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
const V = require('./validate');
|
||||
|
||||
const StrategyShape = V.shape({
|
||||
type: V.oneOf(['offline-only', 'fallback-only', 'prefer-cache', 'race']).required,
|
||||
matches: V.arrayOfType(V.string).required
|
||||
});
|
||||
|
||||
const CacheShape = V.shape({
|
||||
offline: V.boolean,
|
||||
precache: V.arrayOfType(V.string),
|
||||
strategy: V.arrayOfType(StrategyShape)
|
||||
});
|
||||
|
||||
const NotificationsShape = V.shape({
|
||||
default: V.shape({
|
||||
title: V.string.required,
|
||||
body: V.string,
|
||||
icon: V.string,
|
||||
tag: V.string,
|
||||
data: V.shape({
|
||||
url: V.string
|
||||
})
|
||||
}).required,
|
||||
duration: V.number,
|
||||
fallbackURL: V.string
|
||||
});
|
||||
|
||||
const LogShape = V.shape({
|
||||
installed: V.string,
|
||||
notificationClicked: V.string,
|
||||
notificationReceived: V.string,
|
||||
requestOptions: V.object
|
||||
});
|
||||
|
||||
function validate(config) {
|
||||
if (!config.template) {
|
||||
if (config.cache && !config.cache.template) {
|
||||
CacheShape(config.cache);
|
||||
}
|
||||
if (config.notifications && !config.notifications.template) {
|
||||
NotificationsShape(config.notifications);
|
||||
}
|
||||
if (config.log) {
|
||||
LogShape(config.log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
CacheShape: CacheShape,
|
||||
NotificationsShape: NotificationsShape,
|
||||
LogShape: LogShape,
|
||||
validate: validate
|
||||
};
|
||||
Reference in New Issue
Block a user