UNPKG

48.3 kBJavaScriptView Raw
1this.workbox = this.workbox || {};
2this.workbox.core = (function (exports) {
3 'use strict';
4
5 try {
6 self['workbox:core:4.3.0'] && _();
7 } catch (e) {} // eslint-disable-line
8
9 /*
10 Copyright 2019 Google LLC
11 Use of this source code is governed by an MIT-style
12 license that can be found in the LICENSE file or at
13 https://opensource.org/licenses/MIT.
14 */
15 const logger = (() => {
16 let inGroup = false;
17 const methodToColorMap = {
18 debug: `#7f8c8d`,
19 // Gray
20 log: `#2ecc71`,
21 // Green
22 warn: `#f39c12`,
23 // Yellow
24 error: `#c0392b`,
25 // Red
26 groupCollapsed: `#3498db`,
27 // Blue
28 groupEnd: null // No colored prefix on groupEnd
29
30 };
31
32 const print = function (method, args) {
33 if (method === 'groupCollapsed') {
34 // Safari doesn't print all console.groupCollapsed() arguments:
35 // https://bugs.webkit.org/show_bug.cgi?id=182754
36 if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
37 console[method](...args);
38 return;
39 }
40 }
41
42 const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; // When in a group, the workbox prefix is not displayed.
43
44 const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];
45 console[method](...logPrefix, ...args);
46
47 if (method === 'groupCollapsed') {
48 inGroup = true;
49 }
50
51 if (method === 'groupEnd') {
52 inGroup = false;
53 }
54 };
55
56 const api = {};
57
58 for (const method of Object.keys(methodToColorMap)) {
59 api[method] = (...args) => {
60 print(method, args);
61 };
62 }
63
64 return api;
65 })();
66
67 /*
68 Copyright 2018 Google LLC
69
70 Use of this source code is governed by an MIT-style
71 license that can be found in the LICENSE file or at
72 https://opensource.org/licenses/MIT.
73 */
74 const messages = {
75 'invalid-value': ({
76 paramName,
77 validValueDescription,
78 value
79 }) => {
80 if (!paramName || !validValueDescription) {
81 throw new Error(`Unexpected input to 'invalid-value' error.`);
82 }
83
84 return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`;
85 },
86 'not-in-sw': ({
87 moduleName
88 }) => {
89 if (!moduleName) {
90 throw new Error(`Unexpected input to 'not-in-sw' error.`);
91 }
92
93 return `The '${moduleName}' must be used in a service worker.`;
94 },
95 'not-an-array': ({
96 moduleName,
97 className,
98 funcName,
99 paramName
100 }) => {
101 if (!moduleName || !className || !funcName || !paramName) {
102 throw new Error(`Unexpected input to 'not-an-array' error.`);
103 }
104
105 return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`;
106 },
107 'incorrect-type': ({
108 expectedType,
109 paramName,
110 moduleName,
111 className,
112 funcName
113 }) => {
114 if (!expectedType || !paramName || !moduleName || !funcName) {
115 throw new Error(`Unexpected input to 'incorrect-type' error.`);
116 }
117
118 return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className ? className + '.' : ''}` + `${funcName}()' must be of type ${expectedType}.`;
119 },
120 'incorrect-class': ({
121 expectedClass,
122 paramName,
123 moduleName,
124 className,
125 funcName,
126 isReturnValueProblem
127 }) => {
128 if (!expectedClass || !moduleName || !funcName) {
129 throw new Error(`Unexpected input to 'incorrect-class' error.`);
130 }
131
132 if (isReturnValueProblem) {
133 return `The return value from ` + `'${moduleName}.${className ? className + '.' : ''}${funcName}()' ` + `must be an instance of class ${expectedClass.name}.`;
134 }
135
136 return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className ? className + '.' : ''}${funcName}()' ` + `must be an instance of class ${expectedClass.name}.`;
137 },
138 'missing-a-method': ({
139 expectedMethod,
140 paramName,
141 moduleName,
142 className,
143 funcName
144 }) => {
145 if (!expectedMethod || !paramName || !moduleName || !className || !funcName) {
146 throw new Error(`Unexpected input to 'missing-a-method' error.`);
147 }
148
149 return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`;
150 },
151 'add-to-cache-list-unexpected-type': ({
152 entry
153 }) => {
154 return `An unexpected entry was passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' The entry ` + `'${JSON.stringify(entry)}' isn't supported. You must supply an array of ` + `strings with one or more characters, objects with a url property or ` + `Request objects.`;
155 },
156 'add-to-cache-list-conflicting-entries': ({
157 firstEntry,
158 secondEntry
159 }) => {
160 if (!firstEntry || !secondEntry) {
161 throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`);
162 }
163
164 return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry._entryId} but different revision details. Workbox is ` + `is unable to cache and version the asset correctly. Please remove one ` + `of the entries.`;
165 },
166 'plugin-error-request-will-fetch': ({
167 thrownError
168 }) => {
169 if (!thrownError) {
170 throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`);
171 }
172
173 return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownError.message}'.`;
174 },
175 'invalid-cache-name': ({
176 cacheNameId,
177 value
178 }) => {
179 if (!cacheNameId) {
180 throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`);
181 }
182
183 return `You must provide a name containing at least one character for ` + `setCacheDeatils({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`;
184 },
185 'unregister-route-but-not-found-with-method': ({
186 method
187 }) => {
188 if (!method) {
189 throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`);
190 }
191
192 return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`;
193 },
194 'unregister-route-route-not-registered': () => {
195 return `The route you're trying to unregister was not previously ` + `registered.`;
196 },
197 'queue-replay-failed': ({
198 name
199 }) => {
200 return `Replaying the background sync queue '${name}' failed.`;
201 },
202 'duplicate-queue-name': ({
203 name
204 }) => {
205 return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`;
206 },
207 'expired-test-without-max-age': ({
208 methodName,
209 paramName
210 }) => {
211 return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`;
212 },
213 'unsupported-route-type': ({
214 moduleName,
215 className,
216 funcName,
217 paramName
218 }) => {
219 return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`;
220 },
221 'not-array-of-class': ({
222 value,
223 expectedClass,
224 moduleName,
225 className,
226 funcName,
227 paramName
228 }) => {
229 return `The supplied '${paramName}' parameter must be an array of ` + `'${expectedClass}' objects. Received '${JSON.stringify(value)},'. ` + `Please check the call to ${moduleName}.${className}.${funcName}() ` + `to fix the issue.`;
230 },
231 'max-entries-or-age-required': ({
232 moduleName,
233 className,
234 funcName
235 }) => {
236 return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`;
237 },
238 'statuses-or-headers-required': ({
239 moduleName,
240 className,
241 funcName
242 }) => {
243 return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`;
244 },
245 'invalid-string': ({
246 moduleName,
247 className,
248 funcName,
249 paramName
250 }) => {
251 if (!paramName || !moduleName || !funcName) {
252 throw new Error(`Unexpected input to 'invalid-string' error.`);
253 }
254
255 return `When using strings, the '${paramName}' parameter must start with ` + `'http' (for cross-origin matches) or '/' (for same-origin matches). ` + `Please see the docs for ${moduleName}.${funcName}() for ` + `more info.`;
256 },
257 'channel-name-required': () => {
258 return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`;
259 },
260 'invalid-responses-are-same-args': () => {
261 return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`;
262 },
263 'expire-custom-caches-only': () => {
264 return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`;
265 },
266 'unit-must-be-bytes': ({
267 normalizedRangeHeader
268 }) => {
269 if (!normalizedRangeHeader) {
270 throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`);
271 }
272
273 return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`;
274 },
275 'single-range-only': ({
276 normalizedRangeHeader
277 }) => {
278 if (!normalizedRangeHeader) {
279 throw new Error(`Unexpected input to 'single-range-only' error.`);
280 }
281
282 return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`;
283 },
284 'invalid-range-values': ({
285 normalizedRangeHeader
286 }) => {
287 if (!normalizedRangeHeader) {
288 throw new Error(`Unexpected input to 'invalid-range-values' error.`);
289 }
290
291 return `The Range header is missing both start and end values. At least ` + `one of those values is needed. The Range header provided was ` + `"${normalizedRangeHeader}"`;
292 },
293 'no-range-header': () => {
294 return `No Range header was found in the Request provided.`;
295 },
296 'range-not-satisfiable': ({
297 size,
298 start,
299 end
300 }) => {
301 return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`;
302 },
303 'attempt-to-cache-non-get-request': ({
304 url,
305 method
306 }) => {
307 return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`;
308 },
309 'cache-put-with-no-response': ({
310 url
311 }) => {
312 return `There was an attempt to cache '${url}' but the response was not ` + `defined.`;
313 },
314 'no-response': ({
315 url,
316 error
317 }) => {
318 let message = `The strategy could not generate a response for '${url}'.`;
319
320 if (error) {
321 message += ` The underlying error is ${error}.`;
322 }
323
324 return message;
325 },
326 'bad-precaching-response': ({
327 url,
328 status
329 }) => {
330 return `The precaching request for '${url}' failed with an HTTP ` + `status of ${status}.`;
331 }
332 };
333
334 /*
335 Copyright 2018 Google LLC
336
337 Use of this source code is governed by an MIT-style
338 license that can be found in the LICENSE file or at
339 https://opensource.org/licenses/MIT.
340 */
341
342 const generatorFunction = (code, ...args) => {
343 const message = messages[code];
344
345 if (!message) {
346 throw new Error(`Unable to find message for code '${code}'.`);
347 }
348
349 return message(...args);
350 };
351
352 const messageGenerator = generatorFunction;
353
354 /*
355 Copyright 2018 Google LLC
356
357 Use of this source code is governed by an MIT-style
358 license that can be found in the LICENSE file or at
359 https://opensource.org/licenses/MIT.
360 */
361 /**
362 * Workbox errors should be thrown with this class.
363 * This allows use to ensure the type easily in tests,
364 * helps developers identify errors from workbox
365 * easily and allows use to optimise error
366 * messages correctly.
367 *
368 * @private
369 */
370
371 class WorkboxError extends Error {
372 /**
373 *
374 * @param {string} errorCode The error code that
375 * identifies this particular error.
376 * @param {Object=} details Any relevant arguments
377 * that will help developers identify issues should
378 * be added as a key on the context object.
379 */
380 constructor(errorCode, details) {
381 let message = messageGenerator(errorCode, details);
382 super(message);
383 this.name = errorCode;
384 this.details = details;
385 }
386
387 }
388
389 /*
390 Copyright 2018 Google LLC
391
392 Use of this source code is governed by an MIT-style
393 license that can be found in the LICENSE file or at
394 https://opensource.org/licenses/MIT.
395 */
396 /*
397 * This method returns true if the current context is a service worker.
398 */
399
400 const isSWEnv = moduleName => {
401 if (!('ServiceWorkerGlobalScope' in self)) {
402 throw new WorkboxError('not-in-sw', {
403 moduleName
404 });
405 }
406 };
407 /*
408 * This method throws if the supplied value is not an array.
409 * The destructed values are required to produce a meaningful error for users.
410 * The destructed and restructured object is so it's clear what is
411 * needed.
412 */
413
414
415 const isArray = (value, {
416 moduleName,
417 className,
418 funcName,
419 paramName
420 }) => {
421 if (!Array.isArray(value)) {
422 throw new WorkboxError('not-an-array', {
423 moduleName,
424 className,
425 funcName,
426 paramName
427 });
428 }
429 };
430
431 const hasMethod = (object, expectedMethod, {
432 moduleName,
433 className,
434 funcName,
435 paramName
436 }) => {
437 const type = typeof object[expectedMethod];
438
439 if (type !== 'function') {
440 throw new WorkboxError('missing-a-method', {
441 paramName,
442 expectedMethod,
443 moduleName,
444 className,
445 funcName
446 });
447 }
448 };
449
450 const isType = (object, expectedType, {
451 moduleName,
452 className,
453 funcName,
454 paramName
455 }) => {
456 if (typeof object !== expectedType) {
457 throw new WorkboxError('incorrect-type', {
458 paramName,
459 expectedType,
460 moduleName,
461 className,
462 funcName
463 });
464 }
465 };
466
467 const isInstance = (object, expectedClass, {
468 moduleName,
469 className,
470 funcName,
471 paramName,
472 isReturnValueProblem
473 }) => {
474 if (!(object instanceof expectedClass)) {
475 throw new WorkboxError('incorrect-class', {
476 paramName,
477 expectedClass,
478 moduleName,
479 className,
480 funcName,
481 isReturnValueProblem
482 });
483 }
484 };
485
486 const isOneOf = (value, validValues, {
487 paramName
488 }) => {
489 if (!validValues.includes(value)) {
490 throw new WorkboxError('invalid-value', {
491 paramName,
492 value,
493 validValueDescription: `Valid values are ${JSON.stringify(validValues)}.`
494 });
495 }
496 };
497
498 const isArrayOfClass = (value, expectedClass, {
499 moduleName,
500 className,
501 funcName,
502 paramName
503 }) => {
504 const error = new WorkboxError('not-array-of-class', {
505 value,
506 expectedClass,
507 moduleName,
508 className,
509 funcName,
510 paramName
511 });
512
513 if (!Array.isArray(value)) {
514 throw error;
515 }
516
517 for (let item of value) {
518 if (!(item instanceof expectedClass)) {
519 throw error;
520 }
521 }
522 };
523
524 const finalAssertExports = {
525 hasMethod,
526 isArray,
527 isInstance,
528 isOneOf,
529 isSWEnv,
530 isType,
531 isArrayOfClass
532 };
533
534 /*
535 Copyright 2018 Google LLC
536
537 Use of this source code is governed by an MIT-style
538 license that can be found in the LICENSE file or at
539 https://opensource.org/licenses/MIT.
540 */
541 const callbacks = new Set();
542 /**
543 * Adds a function to the set of callbacks that will be executed when there's
544 * a quota error.
545 *
546 * @param {Function} callback
547 * @memberof workbox.core
548 */
549
550 function registerQuotaErrorCallback(callback) {
551 {
552 finalAssertExports.isType(callback, 'function', {
553 moduleName: 'workbox-core',
554 funcName: 'register',
555 paramName: 'callback'
556 });
557 }
558
559 callbacks.add(callback);
560
561 {
562 logger.log('Registered a callback to respond to quota errors.', callback);
563 }
564 }
565 /**
566 * Runs all of the callback functions, one at a time sequentially, in the order
567 * in which they were registered.
568 *
569 * @memberof workbox.core
570 * @private
571 */
572
573
574 async function executeQuotaErrorCallbacks() {
575 {
576 logger.log(`About to run ${callbacks.size} callbacks to clean up caches.`);
577 }
578
579 for (const callback of callbacks) {
580 await callback();
581
582 {
583 logger.log(callback, 'is complete.');
584 }
585 }
586
587 {
588 logger.log('Finished running callbacks.');
589 }
590 }
591
592 /*
593 Copyright 2019 Google LLC
594
595 Use of this source code is governed by an MIT-style
596 license that can be found in the LICENSE file or at
597 https://opensource.org/licenses/MIT.
598 */
599
600 /*
601 Copyright 2018 Google LLC
602
603 Use of this source code is governed by an MIT-style
604 license that can be found in the LICENSE file or at
605 https://opensource.org/licenses/MIT.
606 */
607 /**
608 * A class that wraps common IndexedDB functionality in a promise-based API.
609 * It exposes all the underlying power and functionality of IndexedDB, but
610 * wraps the most commonly used features in a way that's much simpler to use.
611 *
612 * @private
613 */
614
615 class DBWrapper {
616 /**
617 * @param {string} name
618 * @param {number} version
619 * @param {Object=} [callback]
620 * @param {!Function} [callbacks.onupgradeneeded]
621 * @param {!Function} [callbacks.onversionchange] Defaults to
622 * DBWrapper.prototype._onversionchange when not specified.
623 * @private
624 */
625 constructor(name, version, {
626 onupgradeneeded,
627 onversionchange = this._onversionchange
628 } = {}) {
629 this._name = name;
630 this._version = version;
631 this._onupgradeneeded = onupgradeneeded;
632 this._onversionchange = onversionchange; // If this is null, it means the database isn't open.
633
634 this._db = null;
635 }
636 /**
637 * Returns the IDBDatabase instance (not normally needed).
638 *
639 * @private
640 */
641
642
643 get db() {
644 return this._db;
645 }
646 /**
647 * Opens a connected to an IDBDatabase, invokes any onupgradedneeded
648 * callback, and added an onversionchange callback to the database.
649 *
650 * @return {IDBDatabase}
651 * @private
652 */
653
654
655 async open() {
656 if (this._db) return;
657 this._db = await new Promise((resolve, reject) => {
658 // This flag is flipped to true if the timeout callback runs prior
659 // to the request failing or succeeding. Note: we use a timeout instead
660 // of an onblocked handler since there are cases where onblocked will
661 // never never run. A timeout better handles all possible scenarios:
662 // https://github.com/w3c/IndexedDB/issues/223
663 let openRequestTimedOut = false;
664 setTimeout(() => {
665 openRequestTimedOut = true;
666 reject(new Error('The open request was blocked and timed out'));
667 }, this.OPEN_TIMEOUT);
668 const openRequest = indexedDB.open(this._name, this._version);
669
670 openRequest.onerror = () => reject(openRequest.error);
671
672 openRequest.onupgradeneeded = evt => {
673 if (openRequestTimedOut) {
674 openRequest.transaction.abort();
675 evt.target.result.close();
676 } else if (this._onupgradeneeded) {
677 this._onupgradeneeded(evt);
678 }
679 };
680
681 openRequest.onsuccess = ({
682 target
683 }) => {
684 const db = target.result;
685
686 if (openRequestTimedOut) {
687 db.close();
688 } else {
689 db.onversionchange = this._onversionchange.bind(this);
690 resolve(db);
691 }
692 };
693 });
694 return this;
695 }
696 /**
697 * Polyfills the native `getKey()` method. Note, this is overridden at
698 * runtime if the browser supports the native method.
699 *
700 * @param {string} storeName
701 * @param {*} query
702 * @return {Array}
703 * @private
704 */
705
706
707 async getKey(storeName, query) {
708 return (await this.getAllKeys(storeName, query, 1))[0];
709 }
710 /**
711 * Polyfills the native `getAll()` method. Note, this is overridden at
712 * runtime if the browser supports the native method.
713 *
714 * @param {string} storeName
715 * @param {*} query
716 * @param {number} count
717 * @return {Array}
718 * @private
719 */
720
721
722 async getAll(storeName, query, count) {
723 return await this.getAllMatching(storeName, {
724 query,
725 count
726 });
727 }
728 /**
729 * Polyfills the native `getAllKeys()` method. Note, this is overridden at
730 * runtime if the browser supports the native method.
731 *
732 * @param {string} storeName
733 * @param {*} query
734 * @param {number} count
735 * @return {Array}
736 * @private
737 */
738
739
740 async getAllKeys(storeName, query, count) {
741 return (await this.getAllMatching(storeName, {
742 query,
743 count,
744 includeKeys: true
745 })).map(({
746 key
747 }) => key);
748 }
749 /**
750 * Supports flexible lookup in an object store by specifying an index,
751 * query, direction, and count. This method returns an array of objects
752 * with the signature .
753 *
754 * @param {string} storeName
755 * @param {Object} [opts]
756 * @param {string} [opts.index] The index to use (if specified).
757 * @param {*} [opts.query]
758 * @param {IDBCursorDirection} [opts.direction]
759 * @param {number} [opts.count] The max number of results to return.
760 * @param {boolean} [opts.includeKeys] When true, the structure of the
761 * returned objects is changed from an array of values to an array of
762 * objects in the form {key, primaryKey, value}.
763 * @return {Array}
764 * @private
765 */
766
767
768 async getAllMatching(storeName, {
769 index,
770 query = null,
771 // IE errors if query === `undefined`.
772 direction = 'next',
773 count,
774 includeKeys
775 } = {}) {
776 return await this.transaction([storeName], 'readonly', (txn, done) => {
777 const store = txn.objectStore(storeName);
778 const target = index ? store.index(index) : store;
779 const results = [];
780
781 target.openCursor(query, direction).onsuccess = ({
782 target
783 }) => {
784 const cursor = target.result;
785
786 if (cursor) {
787 const {
788 primaryKey,
789 key,
790 value
791 } = cursor;
792 results.push(includeKeys ? {
793 primaryKey,
794 key,
795 value
796 } : value);
797
798 if (count && results.length >= count) {
799 done(results);
800 } else {
801 cursor.continue();
802 }
803 } else {
804 done(results);
805 }
806 };
807 });
808 }
809 /**
810 * Accepts a list of stores, a transaction type, and a callback and
811 * performs a transaction. A promise is returned that resolves to whatever
812 * value the callback chooses. The callback holds all the transaction logic
813 * and is invoked with two arguments:
814 * 1. The IDBTransaction object
815 * 2. A `done` function, that's used to resolve the promise when
816 * when the transaction is done, if passed a value, the promise is
817 * resolved to that value.
818 *
819 * @param {Array<string>} storeNames An array of object store names
820 * involved in the transaction.
821 * @param {string} type Can be `readonly` or `readwrite`.
822 * @param {!Function} callback
823 * @return {*} The result of the transaction ran by the callback.
824 * @private
825 */
826
827
828 async transaction(storeNames, type, callback) {
829 await this.open();
830 return await new Promise((resolve, reject) => {
831 const txn = this._db.transaction(storeNames, type);
832
833 txn.onabort = ({
834 target
835 }) => reject(target.error);
836
837 txn.oncomplete = () => resolve();
838
839 callback(txn, value => resolve(value));
840 });
841 }
842 /**
843 * Delegates async to a native IDBObjectStore method.
844 *
845 * @param {string} method The method name.
846 * @param {string} storeName The object store name.
847 * @param {string} type Can be `readonly` or `readwrite`.
848 * @param {...*} args The list of args to pass to the native method.
849 * @return {*} The result of the transaction.
850 * @private
851 */
852
853
854 async _call(method, storeName, type, ...args) {
855 const callback = (txn, done) => {
856 txn.objectStore(storeName)[method](...args).onsuccess = ({
857 target
858 }) => {
859 done(target.result);
860 };
861 };
862
863 return await this.transaction([storeName], type, callback);
864 }
865 /**
866 * The default onversionchange handler, which closes the database so other
867 * connections can open without being blocked.
868 *
869 * @private
870 */
871
872
873 _onversionchange() {
874 this.close();
875 }
876 /**
877 * Closes the connection opened by `DBWrapper.open()`. Generally this method
878 * doesn't need to be called since:
879 * 1. It's usually better to keep a connection open since opening
880 * a new connection is somewhat slow.
881 * 2. Connections are automatically closed when the reference is
882 * garbage collected.
883 * The primary use case for needing to close a connection is when another
884 * reference (typically in another tab) needs to upgrade it and would be
885 * blocked by the current, open connection.
886 *
887 * @private
888 */
889
890
891 close() {
892 if (this._db) {
893 this._db.close();
894
895 this._db = null;
896 }
897 }
898
899 } // Exposed to let users modify the default timeout on a per-instance
900 // or global basis.
901
902 DBWrapper.prototype.OPEN_TIMEOUT = 2000; // Wrap native IDBObjectStore methods according to their mode.
903
904 const methodsToWrap = {
905 'readonly': ['get', 'count', 'getKey', 'getAll', 'getAllKeys'],
906 'readwrite': ['add', 'put', 'clear', 'delete']
907 };
908
909 for (const [mode, methods] of Object.entries(methodsToWrap)) {
910 for (const method of methods) {
911 if (method in IDBObjectStore.prototype) {
912 // Don't use arrow functions here since we're outside of the class.
913 DBWrapper.prototype[method] = async function (storeName, ...args) {
914 return await this._call(method, storeName, mode, ...args);
915 };
916 }
917 }
918 }
919
920 /*
921 Copyright 2018 Google LLC
922
923 Use of this source code is governed by an MIT-style
924 license that can be found in the LICENSE file or at
925 https://opensource.org/licenses/MIT.
926 */
927 /**
928 * Deletes the database.
929 * Note: this is exported separately from the DBWrapper module because most
930 * usages of IndexedDB in workbox dont need deleting, and this way it can be
931 * reused in tests to delete databases without creating DBWrapper instances.
932 *
933 * @param {string} name The database name.
934 * @private
935 */
936
937 const deleteDatabase = async name => {
938 await new Promise((resolve, reject) => {
939 const request = indexedDB.deleteDatabase(name);
940
941 request.onerror = ({
942 target
943 }) => {
944 reject(target.error);
945 };
946
947 request.onblocked = () => {
948 reject(new Error('Delete blocked'));
949 };
950
951 request.onsuccess = () => {
952 resolve();
953 };
954 });
955 };
956
957 /*
958 Copyright 2018 Google LLC
959
960 Use of this source code is governed by an MIT-style
961 license that can be found in the LICENSE file or at
962 https://opensource.org/licenses/MIT.
963 */
964 const _cacheNameDetails = {
965 googleAnalytics: 'googleAnalytics',
966 precache: 'precache-v2',
967 prefix: 'workbox',
968 runtime: 'runtime',
969 suffix: self.registration.scope
970 };
971
972 const _createCacheName = cacheName => {
973 return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value.length > 0).join('-');
974 };
975
976 const cacheNames = {
977 updateDetails: details => {
978 Object.keys(_cacheNameDetails).forEach(key => {
979 if (typeof details[key] !== 'undefined') {
980 _cacheNameDetails[key] = details[key];
981 }
982 });
983 },
984 getGoogleAnalyticsName: userCacheName => {
985 return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics);
986 },
987 getPrecacheName: userCacheName => {
988 return userCacheName || _createCacheName(_cacheNameDetails.precache);
989 },
990 getPrefix: () => {
991 return _cacheNameDetails.prefix;
992 },
993 getRuntimeName: userCacheName => {
994 return userCacheName || _createCacheName(_cacheNameDetails.runtime);
995 },
996 getSuffix: () => {
997 return _cacheNameDetails.suffix;
998 }
999 };
1000
1001 /*
1002 Copyright 2018 Google LLC
1003
1004 Use of this source code is governed by an MIT-style
1005 license that can be found in the LICENSE file or at
1006 https://opensource.org/licenses/MIT.
1007 */
1008 const pluginEvents = {
1009 CACHE_DID_UPDATE: 'cacheDidUpdate',
1010 CACHE_KEY_WILL_BE_USED: 'cacheKeyWillBeUsed',
1011 CACHE_WILL_UPDATE: 'cacheWillUpdate',
1012 CACHED_RESPONSE_WILL_BE_USED: 'cachedResponseWillBeUsed',
1013 FETCH_DID_FAIL: 'fetchDidFail',
1014 FETCH_DID_SUCCEED: 'fetchDidSucceed',
1015 REQUEST_WILL_FETCH: 'requestWillFetch'
1016 };
1017
1018 /*
1019 Copyright 2018 Google LLC
1020
1021 Use of this source code is governed by an MIT-style
1022 license that can be found in the LICENSE file or at
1023 https://opensource.org/licenses/MIT.
1024 */
1025 const pluginUtils = {
1026 filter: (plugins, callbackName) => {
1027 return plugins.filter(plugin => callbackName in plugin);
1028 }
1029 };
1030
1031 /*
1032 Copyright 2018 Google LLC
1033
1034 Use of this source code is governed by an MIT-style
1035 license that can be found in the LICENSE file or at
1036 https://opensource.org/licenses/MIT.
1037 */
1038
1039 const getFriendlyURL = url => {
1040 const urlObj = new URL(url, location);
1041
1042 if (urlObj.origin === location.origin) {
1043 return urlObj.pathname;
1044 }
1045
1046 return urlObj.href;
1047 };
1048
1049 /*
1050 Copyright 2018 Google LLC
1051
1052 Use of this source code is governed by an MIT-style
1053 license that can be found in the LICENSE file or at
1054 https://opensource.org/licenses/MIT.
1055 */
1056 /**
1057 * Wrapper around cache.put().
1058 *
1059 * Will call `cacheDidUpdate` on plugins if the cache was updated, using
1060 * `matchOptions` when determining what the old entry is.
1061 *
1062 * @param {Object} options
1063 * @param {string} options.cacheName
1064 * @param {Request} options.request
1065 * @param {Response} options.response
1066 * @param {Event} [options.event]
1067 * @param {Array<Object>} [options.plugins=[]]
1068 * @param {Object} [options.matchOptions]
1069 *
1070 * @private
1071 * @memberof module:workbox-core
1072 */
1073
1074 const putWrapper = async ({
1075 cacheName,
1076 request,
1077 response,
1078 event,
1079 plugins = [],
1080 matchOptions
1081 } = {}) => {
1082 {
1083 if (request.method && request.method !== 'GET') {
1084 throw new WorkboxError('attempt-to-cache-non-get-request', {
1085 url: getFriendlyURL(request.url),
1086 method: request.method
1087 });
1088 }
1089 }
1090
1091 const effectiveRequest = await _getEffectiveRequest({
1092 plugins,
1093 request,
1094 mode: 'write'
1095 });
1096
1097 if (!response) {
1098 {
1099 logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`);
1100 }
1101
1102 throw new WorkboxError('cache-put-with-no-response', {
1103 url: getFriendlyURL(effectiveRequest.url)
1104 });
1105 }
1106
1107 let responseToCache = await _isResponseSafeToCache({
1108 event,
1109 plugins,
1110 response,
1111 request: effectiveRequest
1112 });
1113
1114 if (!responseToCache) {
1115 {
1116 logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' will ` + `not be cached.`, responseToCache);
1117 }
1118
1119 return;
1120 }
1121
1122 const cache = await caches.open(cacheName);
1123 const updatePlugins = pluginUtils.filter(plugins, pluginEvents.CACHE_DID_UPDATE);
1124 let oldResponse = updatePlugins.length > 0 ? await matchWrapper({
1125 cacheName,
1126 matchOptions,
1127 request: effectiveRequest
1128 }) : null;
1129
1130 {
1131 logger.debug(`Updating the '${cacheName}' cache with a new Response for ` + `${getFriendlyURL(effectiveRequest.url)}.`);
1132 }
1133
1134 try {
1135 await cache.put(effectiveRequest, responseToCache);
1136 } catch (error) {
1137 // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError
1138 if (error.name === 'QuotaExceededError') {
1139 await executeQuotaErrorCallbacks();
1140 }
1141
1142 throw error;
1143 }
1144
1145 for (let plugin of updatePlugins) {
1146 await plugin[pluginEvents.CACHE_DID_UPDATE].call(plugin, {
1147 cacheName,
1148 event,
1149 oldResponse,
1150 newResponse: responseToCache,
1151 request: effectiveRequest
1152 });
1153 }
1154 };
1155 /**
1156 * This is a wrapper around cache.match().
1157 *
1158 * @param {Object} options
1159 * @param {string} options.cacheName Name of the cache to match against.
1160 * @param {Request} options.request The Request that will be used to look up
1161 * cache entries.
1162 * @param {Event} [options.event] The event that propted the action.
1163 * @param {Object} [options.matchOptions] Options passed to cache.match().
1164 * @param {Array<Object>} [options.plugins=[]] Array of plugins.
1165 * @return {Response} A cached response if available.
1166 *
1167 * @private
1168 * @memberof module:workbox-core
1169 */
1170
1171
1172 const matchWrapper = async ({
1173 cacheName,
1174 request,
1175 event,
1176 matchOptions,
1177 plugins = []
1178 }) => {
1179 const cache = await caches.open(cacheName);
1180 const effectiveRequest = await _getEffectiveRequest({
1181 plugins,
1182 request,
1183 mode: 'read'
1184 });
1185 let cachedResponse = await cache.match(effectiveRequest, matchOptions);
1186
1187 {
1188 if (cachedResponse) {
1189 logger.debug(`Found a cached response in '${cacheName}'.`);
1190 } else {
1191 logger.debug(`No cached response found in '${cacheName}'.`);
1192 }
1193 }
1194
1195 for (const plugin of plugins) {
1196 if (pluginEvents.CACHED_RESPONSE_WILL_BE_USED in plugin) {
1197 cachedResponse = await plugin[pluginEvents.CACHED_RESPONSE_WILL_BE_USED].call(plugin, {
1198 cacheName,
1199 event,
1200 matchOptions,
1201 cachedResponse,
1202 request: effectiveRequest
1203 });
1204
1205 {
1206 if (cachedResponse) {
1207 finalAssertExports.isInstance(cachedResponse, Response, {
1208 moduleName: 'Plugin',
1209 funcName: pluginEvents.CACHED_RESPONSE_WILL_BE_USED,
1210 isReturnValueProblem: true
1211 });
1212 }
1213 }
1214 }
1215 }
1216
1217 return cachedResponse;
1218 };
1219 /**
1220 * This method will call cacheWillUpdate on the available plugins (or use
1221 * status === 200) to determine if the Response is safe and valid to cache.
1222 *
1223 * @param {Object} options
1224 * @param {Request} options.request
1225 * @param {Response} options.response
1226 * @param {Event} [options.event]
1227 * @param {Array<Object>} [options.plugins=[]]
1228 * @return {Promise<Response>}
1229 *
1230 * @private
1231 * @memberof module:workbox-core
1232 */
1233
1234
1235 const _isResponseSafeToCache = async ({
1236 request,
1237 response,
1238 event,
1239 plugins
1240 }) => {
1241 let responseToCache = response;
1242 let pluginsUsed = false;
1243
1244 for (let plugin of plugins) {
1245 if (pluginEvents.CACHE_WILL_UPDATE in plugin) {
1246 pluginsUsed = true;
1247 responseToCache = await plugin[pluginEvents.CACHE_WILL_UPDATE].call(plugin, {
1248 request,
1249 response: responseToCache,
1250 event
1251 });
1252
1253 {
1254 if (responseToCache) {
1255 finalAssertExports.isInstance(responseToCache, Response, {
1256 moduleName: 'Plugin',
1257 funcName: pluginEvents.CACHE_WILL_UPDATE,
1258 isReturnValueProblem: true
1259 });
1260 }
1261 }
1262
1263 if (!responseToCache) {
1264 break;
1265 }
1266 }
1267 }
1268
1269 if (!pluginsUsed) {
1270 {
1271 if (!responseToCache.status === 200) {
1272 if (responseToCache.status === 0) {
1273 logger.warn(`The response for '${request.url}' is an opaque ` + `response. The caching strategy that you're using will not ` + `cache opaque responses by default.`);
1274 } else {
1275 logger.debug(`The response for '${request.url}' returned ` + `a status code of '${response.status}' and won't be cached as a ` + `result.`);
1276 }
1277 }
1278 }
1279
1280 responseToCache = responseToCache.status === 200 ? responseToCache : null;
1281 }
1282
1283 return responseToCache ? responseToCache : null;
1284 };
1285 /**
1286 * Checks the list of plugins for the cacheKeyWillBeUsed callback, and
1287 * executes any of those callbacks found in sequence. The final `Request` object
1288 * returned by the last plugin is treated as the cache key for cache reads
1289 * and/or writes.
1290 *
1291 * @param {Object} options
1292 * @param {Request} options.request
1293 * @param {string} options.mode
1294 * @param {Array<Object>} [options.plugins=[]]
1295 * @return {Promise<Request>}
1296 *
1297 * @private
1298 * @memberof module:workbox-core
1299 */
1300
1301
1302 const _getEffectiveRequest = async ({
1303 request,
1304 mode,
1305 plugins
1306 }) => {
1307 const cacheKeyWillBeUsedPlugins = pluginUtils.filter(plugins, pluginEvents.CACHE_KEY_WILL_BE_USED);
1308 let effectiveRequest = request;
1309
1310 for (const plugin of cacheKeyWillBeUsedPlugins) {
1311 effectiveRequest = await plugin[pluginEvents.CACHE_KEY_WILL_BE_USED].call(plugin, {
1312 mode,
1313 request: effectiveRequest
1314 });
1315
1316 if (typeof effectiveRequest === 'string') {
1317 effectiveRequest = new Request(effectiveRequest);
1318 }
1319
1320 {
1321 finalAssertExports.isInstance(effectiveRequest, Request, {
1322 moduleName: 'Plugin',
1323 funcName: pluginEvents.CACHE_KEY_WILL_BE_USED,
1324 isReturnValueProblem: true
1325 });
1326 }
1327 }
1328
1329 return effectiveRequest;
1330 };
1331
1332 const cacheWrapper = {
1333 put: putWrapper,
1334 match: matchWrapper
1335 };
1336
1337 /*
1338 Copyright 2018 Google LLC
1339
1340 Use of this source code is governed by an MIT-style
1341 license that can be found in the LICENSE file or at
1342 https://opensource.org/licenses/MIT.
1343 */
1344 /**
1345 * Wrapper around the fetch API.
1346 *
1347 * Will call requestWillFetch on available plugins.
1348 *
1349 * @param {Object} options
1350 * @param {Request|string} options.request
1351 * @param {Object} [options.fetchOptions]
1352 * @param {Event} [options.event]
1353 * @param {Array<Object>} [options.plugins=[]]
1354 * @return {Promise<Response>}
1355 *
1356 * @private
1357 * @memberof module:workbox-core
1358 */
1359
1360 const wrappedFetch = async ({
1361 request,
1362 fetchOptions,
1363 event,
1364 plugins = []
1365 }) => {
1366 // We *should* be able to call `await event.preloadResponse` even if it's
1367 // undefined, but for some reason, doing so leads to errors in our Node unit
1368 // tests. To work around that, explicitly check preloadResponse's value first.
1369 if (event && event.preloadResponse) {
1370 const possiblePreloadResponse = await event.preloadResponse;
1371
1372 if (possiblePreloadResponse) {
1373 {
1374 logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`);
1375 }
1376
1377 return possiblePreloadResponse;
1378 }
1379 }
1380
1381 if (typeof request === 'string') {
1382 request = new Request(request);
1383 }
1384
1385 {
1386 finalAssertExports.isInstance(request, Request, {
1387 paramName: request,
1388 expectedClass: 'Request',
1389 moduleName: 'workbox-core',
1390 className: 'fetchWrapper',
1391 funcName: 'wrappedFetch'
1392 });
1393 }
1394
1395 const failedFetchPlugins = pluginUtils.filter(plugins, pluginEvents.FETCH_DID_FAIL); // If there is a fetchDidFail plugin, we need to save a clone of the
1396 // original request before it's either modified by a requestWillFetch
1397 // plugin or before the original request's body is consumed via fetch().
1398
1399 const originalRequest = failedFetchPlugins.length > 0 ? request.clone() : null;
1400
1401 try {
1402 for (let plugin of plugins) {
1403 if (pluginEvents.REQUEST_WILL_FETCH in plugin) {
1404 request = await plugin[pluginEvents.REQUEST_WILL_FETCH].call(plugin, {
1405 request: request.clone(),
1406 event
1407 });
1408
1409 {
1410 if (request) {
1411 finalAssertExports.isInstance(request, Request, {
1412 moduleName: 'Plugin',
1413 funcName: pluginEvents.CACHED_RESPONSE_WILL_BE_USED,
1414 isReturnValueProblem: true
1415 });
1416 }
1417 }
1418 }
1419 }
1420 } catch (err) {
1421 throw new WorkboxError('plugin-error-request-will-fetch', {
1422 thrownError: err
1423 });
1424 } // The request can be altered by plugins with `requestWillFetch` making
1425 // the original request (Most likely from a `fetch` event) to be different
1426 // to the Request we make. Pass both to `fetchDidFail` to aid debugging.
1427
1428
1429 let pluginFilteredRequest = request.clone();
1430
1431 try {
1432 let fetchResponse; // See https://github.com/GoogleChrome/workbox/issues/1796
1433
1434 if (request.mode === 'navigate') {
1435 fetchResponse = await fetch(request);
1436 } else {
1437 fetchResponse = await fetch(request, fetchOptions);
1438 }
1439
1440 {
1441 logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`);
1442 }
1443
1444 for (const plugin of plugins) {
1445 if (pluginEvents.FETCH_DID_SUCCEED in plugin) {
1446 fetchResponse = await plugin[pluginEvents.FETCH_DID_SUCCEED].call(plugin, {
1447 event,
1448 request: pluginFilteredRequest,
1449 response: fetchResponse
1450 });
1451
1452 {
1453 if (fetchResponse) {
1454 finalAssertExports.isInstance(fetchResponse, Response, {
1455 moduleName: 'Plugin',
1456 funcName: pluginEvents.FETCH_DID_SUCCEED,
1457 isReturnValueProblem: true
1458 });
1459 }
1460 }
1461 }
1462 }
1463
1464 return fetchResponse;
1465 } catch (error) {
1466 {
1467 logger.error(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error);
1468 }
1469
1470 for (const plugin of failedFetchPlugins) {
1471 await plugin[pluginEvents.FETCH_DID_FAIL].call(plugin, {
1472 error,
1473 event,
1474 originalRequest: originalRequest.clone(),
1475 request: pluginFilteredRequest.clone()
1476 });
1477 }
1478
1479 throw error;
1480 }
1481 };
1482
1483 const fetchWrapper = {
1484 fetch: wrappedFetch
1485 };
1486
1487 /*
1488 Copyright 2018 Google LLC
1489
1490 Use of this source code is governed by an MIT-style
1491 license that can be found in the LICENSE file or at
1492 https://opensource.org/licenses/MIT.
1493 */
1494
1495 var _private = /*#__PURE__*/Object.freeze({
1496 DBWrapper: DBWrapper,
1497 deleteDatabase: deleteDatabase,
1498 WorkboxError: WorkboxError,
1499 assert: finalAssertExports,
1500 cacheNames: cacheNames,
1501 cacheWrapper: cacheWrapper,
1502 fetchWrapper: fetchWrapper,
1503 getFriendlyURL: getFriendlyURL,
1504 logger: logger
1505 });
1506
1507 /*
1508 Copyright 2019 Google LLC
1509
1510 Use of this source code is governed by an MIT-style
1511 license that can be found in the LICENSE file or at
1512 https://opensource.org/licenses/MIT.
1513 */
1514 /**
1515 * Claim any currently available clients once the service worker
1516 * becomes active. This is normally used in conjunction with `skipWaiting()`.
1517 *
1518 * @alias workbox.core.clientsClaim
1519 */
1520
1521 const clientsClaim = () => {
1522 addEventListener('activate', () => clients.claim());
1523 };
1524
1525 /*
1526 Copyright 2019 Google LLC
1527
1528 Use of this source code is governed by an MIT-style
1529 license that can be found in the LICENSE file or at
1530 https://opensource.org/licenses/MIT.
1531 */
1532 /**
1533 * Get the current cache names and prefix/suffix used by Workbox.
1534 *
1535 * `cacheNames.precache` is used for precached assets,
1536 * `cacheNames.googleAnalytics` is used by `workbox-google-analytics` to
1537 * store `analytics.js`, and `cacheNames.runtime` is used for everything else.
1538 *
1539 * `cacheNames.prefix` can be used to retrieve just the current prefix value.
1540 * `cacheNames.suffix` can be used to retrieve just the current suffix value.
1541 *
1542 * @return {Object} An object with `precache`, `runtime`, `prefix`, and
1543 * `googleAnalytics` properties.
1544 *
1545 * @alias workbox.core.cacheNames
1546 */
1547
1548 const cacheNames$1 = {
1549 get googleAnalytics() {
1550 return cacheNames.getGoogleAnalyticsName();
1551 },
1552
1553 get precache() {
1554 return cacheNames.getPrecacheName();
1555 },
1556
1557 get prefix() {
1558 return cacheNames.getPrefix();
1559 },
1560
1561 get runtime() {
1562 return cacheNames.getRuntimeName();
1563 },
1564
1565 get suffix() {
1566 return cacheNames.getSuffix();
1567 }
1568
1569 };
1570
1571 /*
1572 Copyright 2019 Google LLC
1573
1574 Use of this source code is governed by an MIT-style
1575 license that can be found in the LICENSE file or at
1576 https://opensource.org/licenses/MIT.
1577 */
1578 /**
1579 * Modifies the default cache names used by the Workbox packages.
1580 * Cache names are generated as `<prefix>-<Cache Name>-<suffix>`.
1581 *
1582 * @param {Object} details
1583 * @param {Object} [details.prefix] The string to add to the beginning of
1584 * the precache and runtime cache names.
1585 * @param {Object} [details.suffix] The string to add to the end of
1586 * the precache and runtime cache names.
1587 * @param {Object} [details.precache] The cache name to use for precache
1588 * caching.
1589 * @param {Object} [details.runtime] The cache name to use for runtime caching.
1590 * @param {Object} [details.googleAnalytics] The cache name to use for
1591 * `workbox-google-analytics` caching.
1592 *
1593 * @alias workbox.core.setCacheNameDetails
1594 */
1595
1596 const setCacheNameDetails = details => {
1597 {
1598 Object.keys(details).forEach(key => {
1599 finalAssertExports.isType(details[key], 'string', {
1600 moduleName: 'workbox-core',
1601 funcName: 'setCacheNameDetails',
1602 paramName: `details.${key}`
1603 });
1604 });
1605
1606 if ('precache' in details && details.precache.length === 0) {
1607 throw new WorkboxError('invalid-cache-name', {
1608 cacheNameId: 'precache',
1609 value: details.precache
1610 });
1611 }
1612
1613 if ('runtime' in details && details.runtime.length === 0) {
1614 throw new WorkboxError('invalid-cache-name', {
1615 cacheNameId: 'runtime',
1616 value: details.runtime
1617 });
1618 }
1619
1620 if ('googleAnalytics' in details && details.googleAnalytics.length === 0) {
1621 throw new WorkboxError('invalid-cache-name', {
1622 cacheNameId: 'googleAnalytics',
1623 value: details.googleAnalytics
1624 });
1625 }
1626 }
1627
1628 cacheNames.updateDetails(details);
1629 };
1630
1631 /*
1632 Copyright 2019 Google LLC
1633
1634 Use of this source code is governed by an MIT-style
1635 license that can be found in the LICENSE file or at
1636 https://opensource.org/licenses/MIT.
1637 */
1638 /**
1639 * Force a service worker to become active, instead of waiting. This is
1640 * normally used in conjunction with `clientsClaim()`.
1641 *
1642 * @alias workbox.core.skipWaiting
1643 */
1644
1645 const skipWaiting = () => {
1646 // We need to explicitly call `self.skipWaiting()` here because we're
1647 // shadowing `skipWaiting` with this local function.
1648 addEventListener('install', () => self.skipWaiting());
1649 };
1650
1651 /*
1652 Copyright 2018 Google LLC
1653
1654 Use of this source code is governed by an MIT-style
1655 license that can be found in the LICENSE file or at
1656 https://opensource.org/licenses/MIT.
1657 */
1658
1659 try {
1660 self.workbox.v = self.workbox.v || {};
1661 } catch (errer) {} // NOOP
1662
1663 exports._private = _private;
1664 exports.clientsClaim = clientsClaim;
1665 exports.cacheNames = cacheNames$1;
1666 exports.registerQuotaErrorCallback = registerQuotaErrorCallback;
1667 exports.setCacheNameDetails = setCacheNameDetails;
1668 exports.skipWaiting = skipWaiting;
1669
1670 return exports;
1671
1672}({}));
1673