@ashwin-pc/pi-web 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3645 @@
1
+ define(['exports'], (function (exports) { 'use strict';
2
+
3
+ // @ts-ignore
4
+ try {
5
+ self['workbox:core:7.4.0'] && _();
6
+ } catch (e) {}
7
+
8
+ /*
9
+ Copyright 2019 Google LLC
10
+ Use of this source code is governed by an MIT-style
11
+ license that can be found in the LICENSE file or at
12
+ https://opensource.org/licenses/MIT.
13
+ */
14
+ const logger = (() => {
15
+ // Don't overwrite this value if it's already set.
16
+ // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923
17
+ if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) {
18
+ self.__WB_DISABLE_DEV_LOGS = false;
19
+ }
20
+ let inGroup = false;
21
+ const methodToColorMap = {
22
+ debug: `#7f8c8d`,
23
+ log: `#2ecc71`,
24
+ warn: `#f39c12`,
25
+ error: `#c0392b`,
26
+ groupCollapsed: `#3498db`,
27
+ groupEnd: null // No colored prefix on groupEnd
28
+ };
29
+ const print = function (method, args) {
30
+ if (self.__WB_DISABLE_DEV_LOGS) {
31
+ return;
32
+ }
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
+ const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`];
42
+ // When in a group, the workbox prefix is not displayed.
43
+ const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];
44
+ console[method](...logPrefix, ...args);
45
+ if (method === 'groupCollapsed') {
46
+ inGroup = true;
47
+ }
48
+ if (method === 'groupEnd') {
49
+ inGroup = false;
50
+ }
51
+ };
52
+ // eslint-disable-next-line @typescript-eslint/ban-types
53
+ const api = {};
54
+ const loggerMethods = Object.keys(methodToColorMap);
55
+ for (const key of loggerMethods) {
56
+ const method = key;
57
+ api[method] = (...args) => {
58
+ print(method, args);
59
+ };
60
+ }
61
+ return api;
62
+ })();
63
+
64
+ /*
65
+ Copyright 2018 Google LLC
66
+
67
+ Use of this source code is governed by an MIT-style
68
+ license that can be found in the LICENSE file or at
69
+ https://opensource.org/licenses/MIT.
70
+ */
71
+ const messages$1 = {
72
+ 'invalid-value': ({
73
+ paramName,
74
+ validValueDescription,
75
+ value
76
+ }) => {
77
+ if (!paramName || !validValueDescription) {
78
+ throw new Error(`Unexpected input to 'invalid-value' error.`);
79
+ }
80
+ return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`;
81
+ },
82
+ 'not-an-array': ({
83
+ moduleName,
84
+ className,
85
+ funcName,
86
+ paramName
87
+ }) => {
88
+ if (!moduleName || !className || !funcName || !paramName) {
89
+ throw new Error(`Unexpected input to 'not-an-array' error.`);
90
+ }
91
+ return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`;
92
+ },
93
+ 'incorrect-type': ({
94
+ expectedType,
95
+ paramName,
96
+ moduleName,
97
+ className,
98
+ funcName
99
+ }) => {
100
+ if (!expectedType || !paramName || !moduleName || !funcName) {
101
+ throw new Error(`Unexpected input to 'incorrect-type' error.`);
102
+ }
103
+ const classNameStr = className ? `${className}.` : '';
104
+ return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}` + `${funcName}()' must be of type ${expectedType}.`;
105
+ },
106
+ 'incorrect-class': ({
107
+ expectedClassName,
108
+ paramName,
109
+ moduleName,
110
+ className,
111
+ funcName,
112
+ isReturnValueProblem
113
+ }) => {
114
+ if (!expectedClassName || !moduleName || !funcName) {
115
+ throw new Error(`Unexpected input to 'incorrect-class' error.`);
116
+ }
117
+ const classNameStr = className ? `${className}.` : '';
118
+ if (isReturnValueProblem) {
119
+ return `The return value from ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`;
120
+ }
121
+ return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`;
122
+ },
123
+ 'missing-a-method': ({
124
+ expectedMethod,
125
+ paramName,
126
+ moduleName,
127
+ className,
128
+ funcName
129
+ }) => {
130
+ if (!expectedMethod || !paramName || !moduleName || !className || !funcName) {
131
+ throw new Error(`Unexpected input to 'missing-a-method' error.`);
132
+ }
133
+ return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`;
134
+ },
135
+ 'add-to-cache-list-unexpected-type': ({
136
+ entry
137
+ }) => {
138
+ 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.`;
139
+ },
140
+ 'add-to-cache-list-conflicting-entries': ({
141
+ firstEntry,
142
+ secondEntry
143
+ }) => {
144
+ if (!firstEntry || !secondEntry) {
145
+ throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`);
146
+ }
147
+ return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`;
148
+ },
149
+ 'plugin-error-request-will-fetch': ({
150
+ thrownErrorMessage
151
+ }) => {
152
+ if (!thrownErrorMessage) {
153
+ throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`);
154
+ }
155
+ return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownErrorMessage}'.`;
156
+ },
157
+ 'invalid-cache-name': ({
158
+ cacheNameId,
159
+ value
160
+ }) => {
161
+ if (!cacheNameId) {
162
+ throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`);
163
+ }
164
+ return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`;
165
+ },
166
+ 'unregister-route-but-not-found-with-method': ({
167
+ method
168
+ }) => {
169
+ if (!method) {
170
+ throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`);
171
+ }
172
+ return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`;
173
+ },
174
+ 'unregister-route-route-not-registered': () => {
175
+ return `The route you're trying to unregister was not previously ` + `registered.`;
176
+ },
177
+ 'queue-replay-failed': ({
178
+ name
179
+ }) => {
180
+ return `Replaying the background sync queue '${name}' failed.`;
181
+ },
182
+ 'duplicate-queue-name': ({
183
+ name
184
+ }) => {
185
+ return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`;
186
+ },
187
+ 'expired-test-without-max-age': ({
188
+ methodName,
189
+ paramName
190
+ }) => {
191
+ return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`;
192
+ },
193
+ 'unsupported-route-type': ({
194
+ moduleName,
195
+ className,
196
+ funcName,
197
+ paramName
198
+ }) => {
199
+ return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`;
200
+ },
201
+ 'not-array-of-class': ({
202
+ value,
203
+ expectedClass,
204
+ moduleName,
205
+ className,
206
+ funcName,
207
+ paramName
208
+ }) => {
209
+ 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.`;
210
+ },
211
+ 'max-entries-or-age-required': ({
212
+ moduleName,
213
+ className,
214
+ funcName
215
+ }) => {
216
+ return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`;
217
+ },
218
+ 'statuses-or-headers-required': ({
219
+ moduleName,
220
+ className,
221
+ funcName
222
+ }) => {
223
+ return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`;
224
+ },
225
+ 'invalid-string': ({
226
+ moduleName,
227
+ funcName,
228
+ paramName
229
+ }) => {
230
+ if (!paramName || !moduleName || !funcName) {
231
+ throw new Error(`Unexpected input to 'invalid-string' error.`);
232
+ }
233
+ 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.`;
234
+ },
235
+ 'channel-name-required': () => {
236
+ return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`;
237
+ },
238
+ 'invalid-responses-are-same-args': () => {
239
+ return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`;
240
+ },
241
+ 'expire-custom-caches-only': () => {
242
+ return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`;
243
+ },
244
+ 'unit-must-be-bytes': ({
245
+ normalizedRangeHeader
246
+ }) => {
247
+ if (!normalizedRangeHeader) {
248
+ throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`);
249
+ }
250
+ return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`;
251
+ },
252
+ 'single-range-only': ({
253
+ normalizedRangeHeader
254
+ }) => {
255
+ if (!normalizedRangeHeader) {
256
+ throw new Error(`Unexpected input to 'single-range-only' error.`);
257
+ }
258
+ return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`;
259
+ },
260
+ 'invalid-range-values': ({
261
+ normalizedRangeHeader
262
+ }) => {
263
+ if (!normalizedRangeHeader) {
264
+ throw new Error(`Unexpected input to 'invalid-range-values' error.`);
265
+ }
266
+ 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}"`;
267
+ },
268
+ 'no-range-header': () => {
269
+ return `No Range header was found in the Request provided.`;
270
+ },
271
+ 'range-not-satisfiable': ({
272
+ size,
273
+ start,
274
+ end
275
+ }) => {
276
+ return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`;
277
+ },
278
+ 'attempt-to-cache-non-get-request': ({
279
+ url,
280
+ method
281
+ }) => {
282
+ return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`;
283
+ },
284
+ 'cache-put-with-no-response': ({
285
+ url
286
+ }) => {
287
+ return `There was an attempt to cache '${url}' but the response was not ` + `defined.`;
288
+ },
289
+ 'no-response': ({
290
+ url,
291
+ error
292
+ }) => {
293
+ let message = `The strategy could not generate a response for '${url}'.`;
294
+ if (error) {
295
+ message += ` The underlying error is ${error}.`;
296
+ }
297
+ return message;
298
+ },
299
+ 'bad-precaching-response': ({
300
+ url,
301
+ status
302
+ }) => {
303
+ return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`);
304
+ },
305
+ 'non-precached-url': ({
306
+ url
307
+ }) => {
308
+ return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`;
309
+ },
310
+ 'add-to-cache-list-conflicting-integrities': ({
311
+ url
312
+ }) => {
313
+ return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`;
314
+ },
315
+ 'missing-precache-entry': ({
316
+ cacheName,
317
+ url
318
+ }) => {
319
+ return `Unable to find a precached response in ${cacheName} for ${url}.`;
320
+ },
321
+ 'cross-origin-copy-response': ({
322
+ origin
323
+ }) => {
324
+ return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`;
325
+ },
326
+ 'opaque-streams-source': ({
327
+ type
328
+ }) => {
329
+ const message = `One of the workbox-streams sources resulted in an ` + `'${type}' response.`;
330
+ if (type === 'opaqueredirect') {
331
+ return `${message} Please do not use a navigation request that results ` + `in a redirect as a source.`;
332
+ }
333
+ return `${message} Please ensure your sources are CORS-enabled.`;
334
+ }
335
+ };
336
+
337
+ /*
338
+ Copyright 2018 Google LLC
339
+
340
+ Use of this source code is governed by an MIT-style
341
+ license that can be found in the LICENSE file or at
342
+ https://opensource.org/licenses/MIT.
343
+ */
344
+ const generatorFunction = (code, details = {}) => {
345
+ const message = messages$1[code];
346
+ if (!message) {
347
+ throw new Error(`Unable to find message for code '${code}'.`);
348
+ }
349
+ return message(details);
350
+ };
351
+ const messageGenerator = generatorFunction;
352
+
353
+ /*
354
+ Copyright 2018 Google LLC
355
+
356
+ Use of this source code is governed by an MIT-style
357
+ license that can be found in the LICENSE file or at
358
+ https://opensource.org/licenses/MIT.
359
+ */
360
+ /**
361
+ * Workbox errors should be thrown with this class.
362
+ * This allows use to ensure the type easily in tests,
363
+ * helps developers identify errors from workbox
364
+ * easily and allows use to optimise error
365
+ * messages correctly.
366
+ *
367
+ * @private
368
+ */
369
+ class WorkboxError extends Error {
370
+ /**
371
+ *
372
+ * @param {string} errorCode The error code that
373
+ * identifies this particular error.
374
+ * @param {Object=} details Any relevant arguments
375
+ * that will help developers identify issues should
376
+ * be added as a key on the context object.
377
+ */
378
+ constructor(errorCode, details) {
379
+ const message = messageGenerator(errorCode, details);
380
+ super(message);
381
+ this.name = errorCode;
382
+ this.details = details;
383
+ }
384
+ }
385
+
386
+ /*
387
+ Copyright 2018 Google LLC
388
+
389
+ Use of this source code is governed by an MIT-style
390
+ license that can be found in the LICENSE file or at
391
+ https://opensource.org/licenses/MIT.
392
+ */
393
+ /*
394
+ * This method throws if the supplied value is not an array.
395
+ * The destructed values are required to produce a meaningful error for users.
396
+ * The destructed and restructured object is so it's clear what is
397
+ * needed.
398
+ */
399
+ const isArray = (value, details) => {
400
+ if (!Array.isArray(value)) {
401
+ throw new WorkboxError('not-an-array', details);
402
+ }
403
+ };
404
+ const hasMethod = (object, expectedMethod, details) => {
405
+ const type = typeof object[expectedMethod];
406
+ if (type !== 'function') {
407
+ details['expectedMethod'] = expectedMethod;
408
+ throw new WorkboxError('missing-a-method', details);
409
+ }
410
+ };
411
+ const isType = (object, expectedType, details) => {
412
+ if (typeof object !== expectedType) {
413
+ details['expectedType'] = expectedType;
414
+ throw new WorkboxError('incorrect-type', details);
415
+ }
416
+ };
417
+ const isInstance = (object,
418
+ // Need the general type to do the check later.
419
+ // eslint-disable-next-line @typescript-eslint/ban-types
420
+ expectedClass, details) => {
421
+ if (!(object instanceof expectedClass)) {
422
+ details['expectedClassName'] = expectedClass.name;
423
+ throw new WorkboxError('incorrect-class', details);
424
+ }
425
+ };
426
+ const isOneOf = (value, validValues, details) => {
427
+ if (!validValues.includes(value)) {
428
+ details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`;
429
+ throw new WorkboxError('invalid-value', details);
430
+ }
431
+ };
432
+ const isArrayOfClass = (value,
433
+ // Need general type to do check later.
434
+ expectedClass,
435
+ // eslint-disable-line
436
+ details) => {
437
+ const error = new WorkboxError('not-array-of-class', details);
438
+ if (!Array.isArray(value)) {
439
+ throw error;
440
+ }
441
+ for (const item of value) {
442
+ if (!(item instanceof expectedClass)) {
443
+ throw error;
444
+ }
445
+ }
446
+ };
447
+ const finalAssertExports = {
448
+ hasMethod,
449
+ isArray,
450
+ isInstance,
451
+ isOneOf,
452
+ isType,
453
+ isArrayOfClass
454
+ };
455
+
456
+ // @ts-ignore
457
+ try {
458
+ self['workbox:routing:7.4.0'] && _();
459
+ } catch (e) {}
460
+
461
+ /*
462
+ Copyright 2018 Google LLC
463
+
464
+ Use of this source code is governed by an MIT-style
465
+ license that can be found in the LICENSE file or at
466
+ https://opensource.org/licenses/MIT.
467
+ */
468
+ /**
469
+ * The default HTTP method, 'GET', used when there's no specific method
470
+ * configured for a route.
471
+ *
472
+ * @type {string}
473
+ *
474
+ * @private
475
+ */
476
+ const defaultMethod = 'GET';
477
+ /**
478
+ * The list of valid HTTP methods associated with requests that could be routed.
479
+ *
480
+ * @type {Array<string>}
481
+ *
482
+ * @private
483
+ */
484
+ const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'];
485
+
486
+ /*
487
+ Copyright 2018 Google LLC
488
+
489
+ Use of this source code is governed by an MIT-style
490
+ license that can be found in the LICENSE file or at
491
+ https://opensource.org/licenses/MIT.
492
+ */
493
+ /**
494
+ * @param {function()|Object} handler Either a function, or an object with a
495
+ * 'handle' method.
496
+ * @return {Object} An object with a handle method.
497
+ *
498
+ * @private
499
+ */
500
+ const normalizeHandler = handler => {
501
+ if (handler && typeof handler === 'object') {
502
+ {
503
+ finalAssertExports.hasMethod(handler, 'handle', {
504
+ moduleName: 'workbox-routing',
505
+ className: 'Route',
506
+ funcName: 'constructor',
507
+ paramName: 'handler'
508
+ });
509
+ }
510
+ return handler;
511
+ } else {
512
+ {
513
+ finalAssertExports.isType(handler, 'function', {
514
+ moduleName: 'workbox-routing',
515
+ className: 'Route',
516
+ funcName: 'constructor',
517
+ paramName: 'handler'
518
+ });
519
+ }
520
+ return {
521
+ handle: handler
522
+ };
523
+ }
524
+ };
525
+
526
+ /*
527
+ Copyright 2018 Google LLC
528
+
529
+ Use of this source code is governed by an MIT-style
530
+ license that can be found in the LICENSE file or at
531
+ https://opensource.org/licenses/MIT.
532
+ */
533
+ /**
534
+ * A `Route` consists of a pair of callback functions, "match" and "handler".
535
+ * The "match" callback determine if a route should be used to "handle" a
536
+ * request by returning a non-falsy value if it can. The "handler" callback
537
+ * is called when there is a match and should return a Promise that resolves
538
+ * to a `Response`.
539
+ *
540
+ * @memberof workbox-routing
541
+ */
542
+ class Route {
543
+ /**
544
+ * Constructor for Route class.
545
+ *
546
+ * @param {workbox-routing~matchCallback} match
547
+ * A callback function that determines whether the route matches a given
548
+ * `fetch` event by returning a non-falsy value.
549
+ * @param {workbox-routing~handlerCallback} handler A callback
550
+ * function that returns a Promise resolving to a Response.
551
+ * @param {string} [method='GET'] The HTTP method to match the Route
552
+ * against.
553
+ */
554
+ constructor(match, handler, method = defaultMethod) {
555
+ {
556
+ finalAssertExports.isType(match, 'function', {
557
+ moduleName: 'workbox-routing',
558
+ className: 'Route',
559
+ funcName: 'constructor',
560
+ paramName: 'match'
561
+ });
562
+ if (method) {
563
+ finalAssertExports.isOneOf(method, validMethods, {
564
+ paramName: 'method'
565
+ });
566
+ }
567
+ }
568
+ // These values are referenced directly by Router so cannot be
569
+ // altered by minificaton.
570
+ this.handler = normalizeHandler(handler);
571
+ this.match = match;
572
+ this.method = method;
573
+ }
574
+ /**
575
+ *
576
+ * @param {workbox-routing-handlerCallback} handler A callback
577
+ * function that returns a Promise resolving to a Response
578
+ */
579
+ setCatchHandler(handler) {
580
+ this.catchHandler = normalizeHandler(handler);
581
+ }
582
+ }
583
+
584
+ /*
585
+ Copyright 2018 Google LLC
586
+
587
+ Use of this source code is governed by an MIT-style
588
+ license that can be found in the LICENSE file or at
589
+ https://opensource.org/licenses/MIT.
590
+ */
591
+ /**
592
+ * RegExpRoute makes it easy to create a regular expression based
593
+ * {@link workbox-routing.Route}.
594
+ *
595
+ * For same-origin requests the RegExp only needs to match part of the URL. For
596
+ * requests against third-party servers, you must define a RegExp that matches
597
+ * the start of the URL.
598
+ *
599
+ * @memberof workbox-routing
600
+ * @extends workbox-routing.Route
601
+ */
602
+ class RegExpRoute extends Route {
603
+ /**
604
+ * If the regular expression contains
605
+ * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},
606
+ * the captured values will be passed to the
607
+ * {@link workbox-routing~handlerCallback} `params`
608
+ * argument.
609
+ *
610
+ * @param {RegExp} regExp The regular expression to match against URLs.
611
+ * @param {workbox-routing~handlerCallback} handler A callback
612
+ * function that returns a Promise resulting in a Response.
613
+ * @param {string} [method='GET'] The HTTP method to match the Route
614
+ * against.
615
+ */
616
+ constructor(regExp, handler, method) {
617
+ {
618
+ finalAssertExports.isInstance(regExp, RegExp, {
619
+ moduleName: 'workbox-routing',
620
+ className: 'RegExpRoute',
621
+ funcName: 'constructor',
622
+ paramName: 'pattern'
623
+ });
624
+ }
625
+ const match = ({
626
+ url
627
+ }) => {
628
+ const result = regExp.exec(url.href);
629
+ // Return immediately if there's no match.
630
+ if (!result) {
631
+ return;
632
+ }
633
+ // Require that the match start at the first character in the URL string
634
+ // if it's a cross-origin request.
635
+ // See https://github.com/GoogleChrome/workbox/issues/281 for the context
636
+ // behind this behavior.
637
+ if (url.origin !== location.origin && result.index !== 0) {
638
+ {
639
+ logger.debug(`The regular expression '${regExp.toString()}' only partially matched ` + `against the cross-origin URL '${url.toString()}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`);
640
+ }
641
+ return;
642
+ }
643
+ // If the route matches, but there aren't any capture groups defined, then
644
+ // this will return [], which is truthy and therefore sufficient to
645
+ // indicate a match.
646
+ // If there are capture groups, then it will return their values.
647
+ return result.slice(1);
648
+ };
649
+ super(match, handler, method);
650
+ }
651
+ }
652
+
653
+ /*
654
+ Copyright 2018 Google LLC
655
+
656
+ Use of this source code is governed by an MIT-style
657
+ license that can be found in the LICENSE file or at
658
+ https://opensource.org/licenses/MIT.
659
+ */
660
+ const getFriendlyURL = url => {
661
+ const urlObj = new URL(String(url), location.href);
662
+ // See https://github.com/GoogleChrome/workbox/issues/2323
663
+ // We want to include everything, except for the origin if it's same-origin.
664
+ return urlObj.href.replace(new RegExp(`^${location.origin}`), '');
665
+ };
666
+
667
+ /*
668
+ Copyright 2018 Google LLC
669
+
670
+ Use of this source code is governed by an MIT-style
671
+ license that can be found in the LICENSE file or at
672
+ https://opensource.org/licenses/MIT.
673
+ */
674
+ /**
675
+ * The Router can be used to process a `FetchEvent` using one or more
676
+ * {@link workbox-routing.Route}, responding with a `Response` if
677
+ * a matching route exists.
678
+ *
679
+ * If no route matches a given a request, the Router will use a "default"
680
+ * handler if one is defined.
681
+ *
682
+ * Should the matching Route throw an error, the Router will use a "catch"
683
+ * handler if one is defined to gracefully deal with issues and respond with a
684
+ * Request.
685
+ *
686
+ * If a request matches multiple routes, the **earliest** registered route will
687
+ * be used to respond to the request.
688
+ *
689
+ * @memberof workbox-routing
690
+ */
691
+ class Router {
692
+ /**
693
+ * Initializes a new Router.
694
+ */
695
+ constructor() {
696
+ this._routes = new Map();
697
+ this._defaultHandlerMap = new Map();
698
+ }
699
+ /**
700
+ * @return {Map<string, Array<workbox-routing.Route>>} routes A `Map` of HTTP
701
+ * method name ('GET', etc.) to an array of all the corresponding `Route`
702
+ * instances that are registered.
703
+ */
704
+ get routes() {
705
+ return this._routes;
706
+ }
707
+ /**
708
+ * Adds a fetch event listener to respond to events when a route matches
709
+ * the event's request.
710
+ */
711
+ addFetchListener() {
712
+ // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
713
+ self.addEventListener('fetch', event => {
714
+ const {
715
+ request
716
+ } = event;
717
+ const responsePromise = this.handleRequest({
718
+ request,
719
+ event
720
+ });
721
+ if (responsePromise) {
722
+ event.respondWith(responsePromise);
723
+ }
724
+ });
725
+ }
726
+ /**
727
+ * Adds a message event listener for URLs to cache from the window.
728
+ * This is useful to cache resources loaded on the page prior to when the
729
+ * service worker started controlling it.
730
+ *
731
+ * The format of the message data sent from the window should be as follows.
732
+ * Where the `urlsToCache` array may consist of URL strings or an array of
733
+ * URL string + `requestInit` object (the same as you'd pass to `fetch()`).
734
+ *
735
+ * ```
736
+ * {
737
+ * type: 'CACHE_URLS',
738
+ * payload: {
739
+ * urlsToCache: [
740
+ * './script1.js',
741
+ * './script2.js',
742
+ * ['./script3.js', {mode: 'no-cors'}],
743
+ * ],
744
+ * },
745
+ * }
746
+ * ```
747
+ */
748
+ addCacheListener() {
749
+ // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
750
+ self.addEventListener('message', event => {
751
+ // event.data is type 'any'
752
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
753
+ if (event.data && event.data.type === 'CACHE_URLS') {
754
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
755
+ const {
756
+ payload
757
+ } = event.data;
758
+ {
759
+ logger.debug(`Caching URLs from the window`, payload.urlsToCache);
760
+ }
761
+ const requestPromises = Promise.all(payload.urlsToCache.map(entry => {
762
+ if (typeof entry === 'string') {
763
+ entry = [entry];
764
+ }
765
+ const request = new Request(...entry);
766
+ return this.handleRequest({
767
+ request,
768
+ event
769
+ });
770
+ // TODO(philipwalton): TypeScript errors without this typecast for
771
+ // some reason (probably a bug). The real type here should work but
772
+ // doesn't: `Array<Promise<Response> | undefined>`.
773
+ })); // TypeScript
774
+ event.waitUntil(requestPromises);
775
+ // If a MessageChannel was used, reply to the message on success.
776
+ if (event.ports && event.ports[0]) {
777
+ void requestPromises.then(() => event.ports[0].postMessage(true));
778
+ }
779
+ }
780
+ });
781
+ }
782
+ /**
783
+ * Apply the routing rules to a FetchEvent object to get a Response from an
784
+ * appropriate Route's handler.
785
+ *
786
+ * @param {Object} options
787
+ * @param {Request} options.request The request to handle.
788
+ * @param {ExtendableEvent} options.event The event that triggered the
789
+ * request.
790
+ * @return {Promise<Response>|undefined} A promise is returned if a
791
+ * registered route can handle the request. If there is no matching
792
+ * route and there's no `defaultHandler`, `undefined` is returned.
793
+ */
794
+ handleRequest({
795
+ request,
796
+ event
797
+ }) {
798
+ {
799
+ finalAssertExports.isInstance(request, Request, {
800
+ moduleName: 'workbox-routing',
801
+ className: 'Router',
802
+ funcName: 'handleRequest',
803
+ paramName: 'options.request'
804
+ });
805
+ }
806
+ const url = new URL(request.url, location.href);
807
+ if (!url.protocol.startsWith('http')) {
808
+ {
809
+ logger.debug(`Workbox Router only supports URLs that start with 'http'.`);
810
+ }
811
+ return;
812
+ }
813
+ const sameOrigin = url.origin === location.origin;
814
+ const {
815
+ params,
816
+ route
817
+ } = this.findMatchingRoute({
818
+ event,
819
+ request,
820
+ sameOrigin,
821
+ url
822
+ });
823
+ let handler = route && route.handler;
824
+ const debugMessages = [];
825
+ {
826
+ if (handler) {
827
+ debugMessages.push([`Found a route to handle this request:`, route]);
828
+ if (params) {
829
+ debugMessages.push([`Passing the following params to the route's handler:`, params]);
830
+ }
831
+ }
832
+ }
833
+ // If we don't have a handler because there was no matching route, then
834
+ // fall back to defaultHandler if that's defined.
835
+ const method = request.method;
836
+ if (!handler && this._defaultHandlerMap.has(method)) {
837
+ {
838
+ debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`);
839
+ }
840
+ handler = this._defaultHandlerMap.get(method);
841
+ }
842
+ if (!handler) {
843
+ {
844
+ // No handler so Workbox will do nothing. If logs is set of debug
845
+ // i.e. verbose, we should print out this information.
846
+ logger.debug(`No route found for: ${getFriendlyURL(url)}`);
847
+ }
848
+ return;
849
+ }
850
+ {
851
+ // We have a handler, meaning Workbox is going to handle the route.
852
+ // print the routing details to the console.
853
+ logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
854
+ debugMessages.forEach(msg => {
855
+ if (Array.isArray(msg)) {
856
+ logger.log(...msg);
857
+ } else {
858
+ logger.log(msg);
859
+ }
860
+ });
861
+ logger.groupEnd();
862
+ }
863
+ // Wrap in try and catch in case the handle method throws a synchronous
864
+ // error. It should still callback to the catch handler.
865
+ let responsePromise;
866
+ try {
867
+ responsePromise = handler.handle({
868
+ url,
869
+ request,
870
+ event,
871
+ params
872
+ });
873
+ } catch (err) {
874
+ responsePromise = Promise.reject(err);
875
+ }
876
+ // Get route's catch handler, if it exists
877
+ const catchHandler = route && route.catchHandler;
878
+ if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
879
+ responsePromise = responsePromise.catch(async err => {
880
+ // If there's a route catch handler, process that first
881
+ if (catchHandler) {
882
+ {
883
+ // Still include URL here as it will be async from the console group
884
+ // and may not make sense without the URL
885
+ logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
886
+ logger.error(`Error thrown by:`, route);
887
+ logger.error(err);
888
+ logger.groupEnd();
889
+ }
890
+ try {
891
+ return await catchHandler.handle({
892
+ url,
893
+ request,
894
+ event,
895
+ params
896
+ });
897
+ } catch (catchErr) {
898
+ if (catchErr instanceof Error) {
899
+ err = catchErr;
900
+ }
901
+ }
902
+ }
903
+ if (this._catchHandler) {
904
+ {
905
+ // Still include URL here as it will be async from the console group
906
+ // and may not make sense without the URL
907
+ logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
908
+ logger.error(`Error thrown by:`, route);
909
+ logger.error(err);
910
+ logger.groupEnd();
911
+ }
912
+ return this._catchHandler.handle({
913
+ url,
914
+ request,
915
+ event
916
+ });
917
+ }
918
+ throw err;
919
+ });
920
+ }
921
+ return responsePromise;
922
+ }
923
+ /**
924
+ * Checks a request and URL (and optionally an event) against the list of
925
+ * registered routes, and if there's a match, returns the corresponding
926
+ * route along with any params generated by the match.
927
+ *
928
+ * @param {Object} options
929
+ * @param {URL} options.url
930
+ * @param {boolean} options.sameOrigin The result of comparing `url.origin`
931
+ * against the current origin.
932
+ * @param {Request} options.request The request to match.
933
+ * @param {Event} options.event The corresponding event.
934
+ * @return {Object} An object with `route` and `params` properties.
935
+ * They are populated if a matching route was found or `undefined`
936
+ * otherwise.
937
+ */
938
+ findMatchingRoute({
939
+ url,
940
+ sameOrigin,
941
+ request,
942
+ event
943
+ }) {
944
+ const routes = this._routes.get(request.method) || [];
945
+ for (const route of routes) {
946
+ let params;
947
+ // route.match returns type any, not possible to change right now.
948
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
949
+ const matchResult = route.match({
950
+ url,
951
+ sameOrigin,
952
+ request,
953
+ event
954
+ });
955
+ if (matchResult) {
956
+ {
957
+ // Warn developers that using an async matchCallback is almost always
958
+ // not the right thing to do.
959
+ if (matchResult instanceof Promise) {
960
+ logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route);
961
+ }
962
+ }
963
+ // See https://github.com/GoogleChrome/workbox/issues/2079
964
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
965
+ params = matchResult;
966
+ if (Array.isArray(params) && params.length === 0) {
967
+ // Instead of passing an empty array in as params, use undefined.
968
+ params = undefined;
969
+ } else if (matchResult.constructor === Object &&
970
+ // eslint-disable-line
971
+ Object.keys(matchResult).length === 0) {
972
+ // Instead of passing an empty object in as params, use undefined.
973
+ params = undefined;
974
+ } else if (typeof matchResult === 'boolean') {
975
+ // For the boolean value true (rather than just something truth-y),
976
+ // don't set params.
977
+ // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353
978
+ params = undefined;
979
+ }
980
+ // Return early if have a match.
981
+ return {
982
+ route,
983
+ params
984
+ };
985
+ }
986
+ }
987
+ // If no match was found above, return and empty object.
988
+ return {};
989
+ }
990
+ /**
991
+ * Define a default `handler` that's called when no routes explicitly
992
+ * match the incoming request.
993
+ *
994
+ * Each HTTP method ('GET', 'POST', etc.) gets its own default handler.
995
+ *
996
+ * Without a default handler, unmatched requests will go against the
997
+ * network as if there were no service worker present.
998
+ *
999
+ * @param {workbox-routing~handlerCallback} handler A callback
1000
+ * function that returns a Promise resulting in a Response.
1001
+ * @param {string} [method='GET'] The HTTP method to associate with this
1002
+ * default handler. Each method has its own default.
1003
+ */
1004
+ setDefaultHandler(handler, method = defaultMethod) {
1005
+ this._defaultHandlerMap.set(method, normalizeHandler(handler));
1006
+ }
1007
+ /**
1008
+ * If a Route throws an error while handling a request, this `handler`
1009
+ * will be called and given a chance to provide a response.
1010
+ *
1011
+ * @param {workbox-routing~handlerCallback} handler A callback
1012
+ * function that returns a Promise resulting in a Response.
1013
+ */
1014
+ setCatchHandler(handler) {
1015
+ this._catchHandler = normalizeHandler(handler);
1016
+ }
1017
+ /**
1018
+ * Registers a route with the router.
1019
+ *
1020
+ * @param {workbox-routing.Route} route The route to register.
1021
+ */
1022
+ registerRoute(route) {
1023
+ {
1024
+ finalAssertExports.isType(route, 'object', {
1025
+ moduleName: 'workbox-routing',
1026
+ className: 'Router',
1027
+ funcName: 'registerRoute',
1028
+ paramName: 'route'
1029
+ });
1030
+ finalAssertExports.hasMethod(route, 'match', {
1031
+ moduleName: 'workbox-routing',
1032
+ className: 'Router',
1033
+ funcName: 'registerRoute',
1034
+ paramName: 'route'
1035
+ });
1036
+ finalAssertExports.isType(route.handler, 'object', {
1037
+ moduleName: 'workbox-routing',
1038
+ className: 'Router',
1039
+ funcName: 'registerRoute',
1040
+ paramName: 'route'
1041
+ });
1042
+ finalAssertExports.hasMethod(route.handler, 'handle', {
1043
+ moduleName: 'workbox-routing',
1044
+ className: 'Router',
1045
+ funcName: 'registerRoute',
1046
+ paramName: 'route.handler'
1047
+ });
1048
+ finalAssertExports.isType(route.method, 'string', {
1049
+ moduleName: 'workbox-routing',
1050
+ className: 'Router',
1051
+ funcName: 'registerRoute',
1052
+ paramName: 'route.method'
1053
+ });
1054
+ }
1055
+ if (!this._routes.has(route.method)) {
1056
+ this._routes.set(route.method, []);
1057
+ }
1058
+ // Give precedence to all of the earlier routes by adding this additional
1059
+ // route to the end of the array.
1060
+ this._routes.get(route.method).push(route);
1061
+ }
1062
+ /**
1063
+ * Unregisters a route with the router.
1064
+ *
1065
+ * @param {workbox-routing.Route} route The route to unregister.
1066
+ */
1067
+ unregisterRoute(route) {
1068
+ if (!this._routes.has(route.method)) {
1069
+ throw new WorkboxError('unregister-route-but-not-found-with-method', {
1070
+ method: route.method
1071
+ });
1072
+ }
1073
+ const routeIndex = this._routes.get(route.method).indexOf(route);
1074
+ if (routeIndex > -1) {
1075
+ this._routes.get(route.method).splice(routeIndex, 1);
1076
+ } else {
1077
+ throw new WorkboxError('unregister-route-route-not-registered');
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ /*
1083
+ Copyright 2019 Google LLC
1084
+
1085
+ Use of this source code is governed by an MIT-style
1086
+ license that can be found in the LICENSE file or at
1087
+ https://opensource.org/licenses/MIT.
1088
+ */
1089
+ let defaultRouter;
1090
+ /**
1091
+ * Creates a new, singleton Router instance if one does not exist. If one
1092
+ * does already exist, that instance is returned.
1093
+ *
1094
+ * @private
1095
+ * @return {Router}
1096
+ */
1097
+ const getOrCreateDefaultRouter = () => {
1098
+ if (!defaultRouter) {
1099
+ defaultRouter = new Router();
1100
+ // The helpers that use the default Router assume these listeners exist.
1101
+ defaultRouter.addFetchListener();
1102
+ defaultRouter.addCacheListener();
1103
+ }
1104
+ return defaultRouter;
1105
+ };
1106
+
1107
+ /*
1108
+ Copyright 2019 Google LLC
1109
+
1110
+ Use of this source code is governed by an MIT-style
1111
+ license that can be found in the LICENSE file or at
1112
+ https://opensource.org/licenses/MIT.
1113
+ */
1114
+ /**
1115
+ * Easily register a RegExp, string, or function with a caching
1116
+ * strategy to a singleton Router instance.
1117
+ *
1118
+ * This method will generate a Route for you if needed and
1119
+ * call {@link workbox-routing.Router#registerRoute}.
1120
+ *
1121
+ * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture
1122
+ * If the capture param is a `Route`, all other arguments will be ignored.
1123
+ * @param {workbox-routing~handlerCallback} [handler] A callback
1124
+ * function that returns a Promise resulting in a Response. This parameter
1125
+ * is required if `capture` is not a `Route` object.
1126
+ * @param {string} [method='GET'] The HTTP method to match the Route
1127
+ * against.
1128
+ * @return {workbox-routing.Route} The generated `Route`.
1129
+ *
1130
+ * @memberof workbox-routing
1131
+ */
1132
+ function registerRoute(capture, handler, method) {
1133
+ let route;
1134
+ if (typeof capture === 'string') {
1135
+ const captureUrl = new URL(capture, location.href);
1136
+ {
1137
+ if (!(capture.startsWith('/') || capture.startsWith('http'))) {
1138
+ throw new WorkboxError('invalid-string', {
1139
+ moduleName: 'workbox-routing',
1140
+ funcName: 'registerRoute',
1141
+ paramName: 'capture'
1142
+ });
1143
+ }
1144
+ // We want to check if Express-style wildcards are in the pathname only.
1145
+ // TODO: Remove this log message in v4.
1146
+ const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture;
1147
+ // See https://github.com/pillarjs/path-to-regexp#parameters
1148
+ const wildcards = '[*:?+]';
1149
+ if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
1150
+ logger.debug(`The '$capture' parameter contains an Express-style wildcard ` + `character (${wildcards}). Strings are now always interpreted as ` + `exact matches; use a RegExp for partial or wildcard matches.`);
1151
+ }
1152
+ }
1153
+ const matchCallback = ({
1154
+ url
1155
+ }) => {
1156
+ {
1157
+ if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
1158
+ logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url.toString()}. This route will only handle cross-origin requests ` + `if they match the entire URL.`);
1159
+ }
1160
+ }
1161
+ return url.href === captureUrl.href;
1162
+ };
1163
+ // If `capture` is a string then `handler` and `method` must be present.
1164
+ route = new Route(matchCallback, handler, method);
1165
+ } else if (capture instanceof RegExp) {
1166
+ // If `capture` is a `RegExp` then `handler` and `method` must be present.
1167
+ route = new RegExpRoute(capture, handler, method);
1168
+ } else if (typeof capture === 'function') {
1169
+ // If `capture` is a function then `handler` and `method` must be present.
1170
+ route = new Route(capture, handler, method);
1171
+ } else if (capture instanceof Route) {
1172
+ route = capture;
1173
+ } else {
1174
+ throw new WorkboxError('unsupported-route-type', {
1175
+ moduleName: 'workbox-routing',
1176
+ funcName: 'registerRoute',
1177
+ paramName: 'capture'
1178
+ });
1179
+ }
1180
+ const defaultRouter = getOrCreateDefaultRouter();
1181
+ defaultRouter.registerRoute(route);
1182
+ return route;
1183
+ }
1184
+
1185
+ // @ts-ignore
1186
+ try {
1187
+ self['workbox:strategies:7.4.0'] && _();
1188
+ } catch (e) {}
1189
+
1190
+ /*
1191
+ Copyright 2018 Google LLC
1192
+
1193
+ Use of this source code is governed by an MIT-style
1194
+ license that can be found in the LICENSE file or at
1195
+ https://opensource.org/licenses/MIT.
1196
+ */
1197
+ const cacheOkAndOpaquePlugin = {
1198
+ /**
1199
+ * Returns a valid response (to allow caching) if the status is 200 (OK) or
1200
+ * 0 (opaque).
1201
+ *
1202
+ * @param {Object} options
1203
+ * @param {Response} options.response
1204
+ * @return {Response|null}
1205
+ *
1206
+ * @private
1207
+ */
1208
+ cacheWillUpdate: async ({
1209
+ response
1210
+ }) => {
1211
+ if (response.status === 200 || response.status === 0) {
1212
+ return response;
1213
+ }
1214
+ return null;
1215
+ }
1216
+ };
1217
+
1218
+ /*
1219
+ Copyright 2018 Google LLC
1220
+
1221
+ Use of this source code is governed by an MIT-style
1222
+ license that can be found in the LICENSE file or at
1223
+ https://opensource.org/licenses/MIT.
1224
+ */
1225
+ const _cacheNameDetails = {
1226
+ googleAnalytics: 'googleAnalytics',
1227
+ precache: 'precache-v2',
1228
+ prefix: 'workbox',
1229
+ runtime: 'runtime',
1230
+ suffix: typeof registration !== 'undefined' ? registration.scope : ''
1231
+ };
1232
+ const _createCacheName = cacheName => {
1233
+ return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-');
1234
+ };
1235
+ const eachCacheNameDetail = fn => {
1236
+ for (const key of Object.keys(_cacheNameDetails)) {
1237
+ fn(key);
1238
+ }
1239
+ };
1240
+ const cacheNames = {
1241
+ updateDetails: details => {
1242
+ eachCacheNameDetail(key => {
1243
+ if (typeof details[key] === 'string') {
1244
+ _cacheNameDetails[key] = details[key];
1245
+ }
1246
+ });
1247
+ },
1248
+ getGoogleAnalyticsName: userCacheName => {
1249
+ return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics);
1250
+ },
1251
+ getPrecacheName: userCacheName => {
1252
+ return userCacheName || _createCacheName(_cacheNameDetails.precache);
1253
+ },
1254
+ getPrefix: () => {
1255
+ return _cacheNameDetails.prefix;
1256
+ },
1257
+ getRuntimeName: userCacheName => {
1258
+ return userCacheName || _createCacheName(_cacheNameDetails.runtime);
1259
+ },
1260
+ getSuffix: () => {
1261
+ return _cacheNameDetails.suffix;
1262
+ }
1263
+ };
1264
+
1265
+ /*
1266
+ Copyright 2020 Google LLC
1267
+ Use of this source code is governed by an MIT-style
1268
+ license that can be found in the LICENSE file or at
1269
+ https://opensource.org/licenses/MIT.
1270
+ */
1271
+ function stripParams(fullURL, ignoreParams) {
1272
+ const strippedURL = new URL(fullURL);
1273
+ for (const param of ignoreParams) {
1274
+ strippedURL.searchParams.delete(param);
1275
+ }
1276
+ return strippedURL.href;
1277
+ }
1278
+ /**
1279
+ * Matches an item in the cache, ignoring specific URL params. This is similar
1280
+ * to the `ignoreSearch` option, but it allows you to ignore just specific
1281
+ * params (while continuing to match on the others).
1282
+ *
1283
+ * @private
1284
+ * @param {Cache} cache
1285
+ * @param {Request} request
1286
+ * @param {Object} matchOptions
1287
+ * @param {Array<string>} ignoreParams
1288
+ * @return {Promise<Response|undefined>}
1289
+ */
1290
+ async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) {
1291
+ const strippedRequestURL = stripParams(request.url, ignoreParams);
1292
+ // If the request doesn't include any ignored params, match as normal.
1293
+ if (request.url === strippedRequestURL) {
1294
+ return cache.match(request, matchOptions);
1295
+ }
1296
+ // Otherwise, match by comparing keys
1297
+ const keysOptions = Object.assign(Object.assign({}, matchOptions), {
1298
+ ignoreSearch: true
1299
+ });
1300
+ const cacheKeys = await cache.keys(request, keysOptions);
1301
+ for (const cacheKey of cacheKeys) {
1302
+ const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams);
1303
+ if (strippedRequestURL === strippedCacheKeyURL) {
1304
+ return cache.match(cacheKey, matchOptions);
1305
+ }
1306
+ }
1307
+ return;
1308
+ }
1309
+
1310
+ /*
1311
+ Copyright 2018 Google LLC
1312
+
1313
+ Use of this source code is governed by an MIT-style
1314
+ license that can be found in the LICENSE file or at
1315
+ https://opensource.org/licenses/MIT.
1316
+ */
1317
+ /**
1318
+ * The Deferred class composes Promises in a way that allows for them to be
1319
+ * resolved or rejected from outside the constructor. In most cases promises
1320
+ * should be used directly, but Deferreds can be necessary when the logic to
1321
+ * resolve a promise must be separate.
1322
+ *
1323
+ * @private
1324
+ */
1325
+ class Deferred {
1326
+ /**
1327
+ * Creates a promise and exposes its resolve and reject functions as methods.
1328
+ */
1329
+ constructor() {
1330
+ this.promise = new Promise((resolve, reject) => {
1331
+ this.resolve = resolve;
1332
+ this.reject = reject;
1333
+ });
1334
+ }
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
+ // Callbacks to be executed whenever there's a quota error.
1345
+ // Can't change Function type right now.
1346
+ // eslint-disable-next-line @typescript-eslint/ban-types
1347
+ const quotaErrorCallbacks = new Set();
1348
+
1349
+ /*
1350
+ Copyright 2018 Google LLC
1351
+
1352
+ Use of this source code is governed by an MIT-style
1353
+ license that can be found in the LICENSE file or at
1354
+ https://opensource.org/licenses/MIT.
1355
+ */
1356
+ /**
1357
+ * Runs all of the callback functions, one at a time sequentially, in the order
1358
+ * in which they were registered.
1359
+ *
1360
+ * @memberof workbox-core
1361
+ * @private
1362
+ */
1363
+ async function executeQuotaErrorCallbacks() {
1364
+ {
1365
+ logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`);
1366
+ }
1367
+ for (const callback of quotaErrorCallbacks) {
1368
+ await callback();
1369
+ {
1370
+ logger.log(callback, 'is complete.');
1371
+ }
1372
+ }
1373
+ {
1374
+ logger.log('Finished running callbacks.');
1375
+ }
1376
+ }
1377
+
1378
+ /*
1379
+ Copyright 2019 Google LLC
1380
+ Use of this source code is governed by an MIT-style
1381
+ license that can be found in the LICENSE file or at
1382
+ https://opensource.org/licenses/MIT.
1383
+ */
1384
+ /**
1385
+ * Returns a promise that resolves and the passed number of milliseconds.
1386
+ * This utility is an async/await-friendly version of `setTimeout`.
1387
+ *
1388
+ * @param {number} ms
1389
+ * @return {Promise}
1390
+ * @private
1391
+ */
1392
+ function timeout(ms) {
1393
+ return new Promise(resolve => setTimeout(resolve, ms));
1394
+ }
1395
+
1396
+ /*
1397
+ Copyright 2020 Google LLC
1398
+
1399
+ Use of this source code is governed by an MIT-style
1400
+ license that can be found in the LICENSE file or at
1401
+ https://opensource.org/licenses/MIT.
1402
+ */
1403
+ function toRequest(input) {
1404
+ return typeof input === 'string' ? new Request(input) : input;
1405
+ }
1406
+ /**
1407
+ * A class created every time a Strategy instance calls
1408
+ * {@link workbox-strategies.Strategy~handle} or
1409
+ * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and
1410
+ * cache actions around plugin callbacks and keeps track of when the strategy
1411
+ * is "done" (i.e. all added `event.waitUntil()` promises have resolved).
1412
+ *
1413
+ * @memberof workbox-strategies
1414
+ */
1415
+ class StrategyHandler {
1416
+ /**
1417
+ * Creates a new instance associated with the passed strategy and event
1418
+ * that's handling the request.
1419
+ *
1420
+ * The constructor also initializes the state that will be passed to each of
1421
+ * the plugins handling this request.
1422
+ *
1423
+ * @param {workbox-strategies.Strategy} strategy
1424
+ * @param {Object} options
1425
+ * @param {Request|string} options.request A request to run this strategy for.
1426
+ * @param {ExtendableEvent} options.event The event associated with the
1427
+ * request.
1428
+ * @param {URL} [options.url]
1429
+ * @param {*} [options.params] The return value from the
1430
+ * {@link workbox-routing~matchCallback} (if applicable).
1431
+ */
1432
+ constructor(strategy, options) {
1433
+ this._cacheKeys = {};
1434
+ /**
1435
+ * The request the strategy is performing (passed to the strategy's
1436
+ * `handle()` or `handleAll()` method).
1437
+ * @name request
1438
+ * @instance
1439
+ * @type {Request}
1440
+ * @memberof workbox-strategies.StrategyHandler
1441
+ */
1442
+ /**
1443
+ * The event associated with this request.
1444
+ * @name event
1445
+ * @instance
1446
+ * @type {ExtendableEvent}
1447
+ * @memberof workbox-strategies.StrategyHandler
1448
+ */
1449
+ /**
1450
+ * A `URL` instance of `request.url` (if passed to the strategy's
1451
+ * `handle()` or `handleAll()` method).
1452
+ * Note: the `url` param will be present if the strategy was invoked
1453
+ * from a workbox `Route` object.
1454
+ * @name url
1455
+ * @instance
1456
+ * @type {URL|undefined}
1457
+ * @memberof workbox-strategies.StrategyHandler
1458
+ */
1459
+ /**
1460
+ * A `param` value (if passed to the strategy's
1461
+ * `handle()` or `handleAll()` method).
1462
+ * Note: the `param` param will be present if the strategy was invoked
1463
+ * from a workbox `Route` object and the
1464
+ * {@link workbox-routing~matchCallback} returned
1465
+ * a truthy value (it will be that value).
1466
+ * @name params
1467
+ * @instance
1468
+ * @type {*|undefined}
1469
+ * @memberof workbox-strategies.StrategyHandler
1470
+ */
1471
+ {
1472
+ finalAssertExports.isInstance(options.event, ExtendableEvent, {
1473
+ moduleName: 'workbox-strategies',
1474
+ className: 'StrategyHandler',
1475
+ funcName: 'constructor',
1476
+ paramName: 'options.event'
1477
+ });
1478
+ }
1479
+ Object.assign(this, options);
1480
+ this.event = options.event;
1481
+ this._strategy = strategy;
1482
+ this._handlerDeferred = new Deferred();
1483
+ this._extendLifetimePromises = [];
1484
+ // Copy the plugins list (since it's mutable on the strategy),
1485
+ // so any mutations don't affect this handler instance.
1486
+ this._plugins = [...strategy.plugins];
1487
+ this._pluginStateMap = new Map();
1488
+ for (const plugin of this._plugins) {
1489
+ this._pluginStateMap.set(plugin, {});
1490
+ }
1491
+ this.event.waitUntil(this._handlerDeferred.promise);
1492
+ }
1493
+ /**
1494
+ * Fetches a given request (and invokes any applicable plugin callback
1495
+ * methods) using the `fetchOptions` (for non-navigation requests) and
1496
+ * `plugins` defined on the `Strategy` object.
1497
+ *
1498
+ * The following plugin lifecycle methods are invoked when using this method:
1499
+ * - `requestWillFetch()`
1500
+ * - `fetchDidSucceed()`
1501
+ * - `fetchDidFail()`
1502
+ *
1503
+ * @param {Request|string} input The URL or request to fetch.
1504
+ * @return {Promise<Response>}
1505
+ */
1506
+ async fetch(input) {
1507
+ const {
1508
+ event
1509
+ } = this;
1510
+ let request = toRequest(input);
1511
+ if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) {
1512
+ const possiblePreloadResponse = await event.preloadResponse;
1513
+ if (possiblePreloadResponse) {
1514
+ {
1515
+ logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`);
1516
+ }
1517
+ return possiblePreloadResponse;
1518
+ }
1519
+ }
1520
+ // If there is a fetchDidFail plugin, we need to save a clone of the
1521
+ // original request before it's either modified by a requestWillFetch
1522
+ // plugin or before the original request's body is consumed via fetch().
1523
+ const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null;
1524
+ try {
1525
+ for (const cb of this.iterateCallbacks('requestWillFetch')) {
1526
+ request = await cb({
1527
+ request: request.clone(),
1528
+ event
1529
+ });
1530
+ }
1531
+ } catch (err) {
1532
+ if (err instanceof Error) {
1533
+ throw new WorkboxError('plugin-error-request-will-fetch', {
1534
+ thrownErrorMessage: err.message
1535
+ });
1536
+ }
1537
+ }
1538
+ // The request can be altered by plugins with `requestWillFetch` making
1539
+ // the original request (most likely from a `fetch` event) different
1540
+ // from the Request we make. Pass both to `fetchDidFail` to aid debugging.
1541
+ const pluginFilteredRequest = request.clone();
1542
+ try {
1543
+ let fetchResponse;
1544
+ // See https://github.com/GoogleChrome/workbox/issues/1796
1545
+ fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions);
1546
+ if ("development" !== 'production') {
1547
+ logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`);
1548
+ }
1549
+ for (const callback of this.iterateCallbacks('fetchDidSucceed')) {
1550
+ fetchResponse = await callback({
1551
+ event,
1552
+ request: pluginFilteredRequest,
1553
+ response: fetchResponse
1554
+ });
1555
+ }
1556
+ return fetchResponse;
1557
+ } catch (error) {
1558
+ {
1559
+ logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error);
1560
+ }
1561
+ // `originalRequest` will only exist if a `fetchDidFail` callback
1562
+ // is being used (see above).
1563
+ if (originalRequest) {
1564
+ await this.runCallbacks('fetchDidFail', {
1565
+ error: error,
1566
+ event,
1567
+ originalRequest: originalRequest.clone(),
1568
+ request: pluginFilteredRequest.clone()
1569
+ });
1570
+ }
1571
+ throw error;
1572
+ }
1573
+ }
1574
+ /**
1575
+ * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on
1576
+ * the response generated by `this.fetch()`.
1577
+ *
1578
+ * The call to `this.cachePut()` automatically invokes `this.waitUntil()`,
1579
+ * so you do not have to manually call `waitUntil()` on the event.
1580
+ *
1581
+ * @param {Request|string} input The request or URL to fetch and cache.
1582
+ * @return {Promise<Response>}
1583
+ */
1584
+ async fetchAndCachePut(input) {
1585
+ const response = await this.fetch(input);
1586
+ const responseClone = response.clone();
1587
+ void this.waitUntil(this.cachePut(input, responseClone));
1588
+ return response;
1589
+ }
1590
+ /**
1591
+ * Matches a request from the cache (and invokes any applicable plugin
1592
+ * callback methods) using the `cacheName`, `matchOptions`, and `plugins`
1593
+ * defined on the strategy object.
1594
+ *
1595
+ * The following plugin lifecycle methods are invoked when using this method:
1596
+ * - cacheKeyWillBeUsed()
1597
+ * - cachedResponseWillBeUsed()
1598
+ *
1599
+ * @param {Request|string} key The Request or URL to use as the cache key.
1600
+ * @return {Promise<Response|undefined>} A matching response, if found.
1601
+ */
1602
+ async cacheMatch(key) {
1603
+ const request = toRequest(key);
1604
+ let cachedResponse;
1605
+ const {
1606
+ cacheName,
1607
+ matchOptions
1608
+ } = this._strategy;
1609
+ const effectiveRequest = await this.getCacheKey(request, 'read');
1610
+ const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), {
1611
+ cacheName
1612
+ });
1613
+ cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);
1614
+ {
1615
+ if (cachedResponse) {
1616
+ logger.debug(`Found a cached response in '${cacheName}'.`);
1617
+ } else {
1618
+ logger.debug(`No cached response found in '${cacheName}'.`);
1619
+ }
1620
+ }
1621
+ for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) {
1622
+ cachedResponse = (await callback({
1623
+ cacheName,
1624
+ matchOptions,
1625
+ cachedResponse,
1626
+ request: effectiveRequest,
1627
+ event: this.event
1628
+ })) || undefined;
1629
+ }
1630
+ return cachedResponse;
1631
+ }
1632
+ /**
1633
+ * Puts a request/response pair in the cache (and invokes any applicable
1634
+ * plugin callback methods) using the `cacheName` and `plugins` defined on
1635
+ * the strategy object.
1636
+ *
1637
+ * The following plugin lifecycle methods are invoked when using this method:
1638
+ * - cacheKeyWillBeUsed()
1639
+ * - cacheWillUpdate()
1640
+ * - cacheDidUpdate()
1641
+ *
1642
+ * @param {Request|string} key The request or URL to use as the cache key.
1643
+ * @param {Response} response The response to cache.
1644
+ * @return {Promise<boolean>} `false` if a cacheWillUpdate caused the response
1645
+ * not be cached, and `true` otherwise.
1646
+ */
1647
+ async cachePut(key, response) {
1648
+ const request = toRequest(key);
1649
+ // Run in the next task to avoid blocking other cache reads.
1650
+ // https://github.com/w3c/ServiceWorker/issues/1397
1651
+ await timeout(0);
1652
+ const effectiveRequest = await this.getCacheKey(request, 'write');
1653
+ {
1654
+ if (effectiveRequest.method && effectiveRequest.method !== 'GET') {
1655
+ throw new WorkboxError('attempt-to-cache-non-get-request', {
1656
+ url: getFriendlyURL(effectiveRequest.url),
1657
+ method: effectiveRequest.method
1658
+ });
1659
+ }
1660
+ // See https://github.com/GoogleChrome/workbox/issues/2818
1661
+ const vary = response.headers.get('Vary');
1662
+ if (vary) {
1663
+ logger.debug(`The response for ${getFriendlyURL(effectiveRequest.url)} ` + `has a 'Vary: ${vary}' header. ` + `Consider setting the {ignoreVary: true} option on your strategy ` + `to ensure cache matching and deletion works as expected.`);
1664
+ }
1665
+ }
1666
+ if (!response) {
1667
+ {
1668
+ logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`);
1669
+ }
1670
+ throw new WorkboxError('cache-put-with-no-response', {
1671
+ url: getFriendlyURL(effectiveRequest.url)
1672
+ });
1673
+ }
1674
+ const responseToCache = await this._ensureResponseSafeToCache(response);
1675
+ if (!responseToCache) {
1676
+ {
1677
+ logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache);
1678
+ }
1679
+ return false;
1680
+ }
1681
+ const {
1682
+ cacheName,
1683
+ matchOptions
1684
+ } = this._strategy;
1685
+ const cache = await self.caches.open(cacheName);
1686
+ const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate');
1687
+ const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams(
1688
+ // TODO(philipwalton): the `__WB_REVISION__` param is a precaching
1689
+ // feature. Consider into ways to only add this behavior if using
1690
+ // precaching.
1691
+ cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null;
1692
+ {
1693
+ logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`);
1694
+ }
1695
+ try {
1696
+ await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache);
1697
+ } catch (error) {
1698
+ if (error instanceof Error) {
1699
+ // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError
1700
+ if (error.name === 'QuotaExceededError') {
1701
+ await executeQuotaErrorCallbacks();
1702
+ }
1703
+ throw error;
1704
+ }
1705
+ }
1706
+ for (const callback of this.iterateCallbacks('cacheDidUpdate')) {
1707
+ await callback({
1708
+ cacheName,
1709
+ oldResponse,
1710
+ newResponse: responseToCache.clone(),
1711
+ request: effectiveRequest,
1712
+ event: this.event
1713
+ });
1714
+ }
1715
+ return true;
1716
+ }
1717
+ /**
1718
+ * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and
1719
+ * executes any of those callbacks found in sequence. The final `Request`
1720
+ * object returned by the last plugin is treated as the cache key for cache
1721
+ * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have
1722
+ * been registered, the passed request is returned unmodified
1723
+ *
1724
+ * @param {Request} request
1725
+ * @param {string} mode
1726
+ * @return {Promise<Request>}
1727
+ */
1728
+ async getCacheKey(request, mode) {
1729
+ const key = `${request.url} | ${mode}`;
1730
+ if (!this._cacheKeys[key]) {
1731
+ let effectiveRequest = request;
1732
+ for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) {
1733
+ effectiveRequest = toRequest(await callback({
1734
+ mode,
1735
+ request: effectiveRequest,
1736
+ event: this.event,
1737
+ // params has a type any can't change right now.
1738
+ params: this.params // eslint-disable-line
1739
+ }));
1740
+ }
1741
+ this._cacheKeys[key] = effectiveRequest;
1742
+ }
1743
+ return this._cacheKeys[key];
1744
+ }
1745
+ /**
1746
+ * Returns true if the strategy has at least one plugin with the given
1747
+ * callback.
1748
+ *
1749
+ * @param {string} name The name of the callback to check for.
1750
+ * @return {boolean}
1751
+ */
1752
+ hasCallback(name) {
1753
+ for (const plugin of this._strategy.plugins) {
1754
+ if (name in plugin) {
1755
+ return true;
1756
+ }
1757
+ }
1758
+ return false;
1759
+ }
1760
+ /**
1761
+ * Runs all plugin callbacks matching the given name, in order, passing the
1762
+ * given param object (merged ith the current plugin state) as the only
1763
+ * argument.
1764
+ *
1765
+ * Note: since this method runs all plugins, it's not suitable for cases
1766
+ * where the return value of a callback needs to be applied prior to calling
1767
+ * the next callback. See
1768
+ * {@link workbox-strategies.StrategyHandler#iterateCallbacks}
1769
+ * below for how to handle that case.
1770
+ *
1771
+ * @param {string} name The name of the callback to run within each plugin.
1772
+ * @param {Object} param The object to pass as the first (and only) param
1773
+ * when executing each callback. This object will be merged with the
1774
+ * current plugin state prior to callback execution.
1775
+ */
1776
+ async runCallbacks(name, param) {
1777
+ for (const callback of this.iterateCallbacks(name)) {
1778
+ // TODO(philipwalton): not sure why `any` is needed. It seems like
1779
+ // this should work with `as WorkboxPluginCallbackParam[C]`.
1780
+ await callback(param);
1781
+ }
1782
+ }
1783
+ /**
1784
+ * Accepts a callback and returns an iterable of matching plugin callbacks,
1785
+ * where each callback is wrapped with the current handler state (i.e. when
1786
+ * you call each callback, whatever object parameter you pass it will
1787
+ * be merged with the plugin's current state).
1788
+ *
1789
+ * @param {string} name The name fo the callback to run
1790
+ * @return {Array<Function>}
1791
+ */
1792
+ *iterateCallbacks(name) {
1793
+ for (const plugin of this._strategy.plugins) {
1794
+ if (typeof plugin[name] === 'function') {
1795
+ const state = this._pluginStateMap.get(plugin);
1796
+ const statefulCallback = param => {
1797
+ const statefulParam = Object.assign(Object.assign({}, param), {
1798
+ state
1799
+ });
1800
+ // TODO(philipwalton): not sure why `any` is needed. It seems like
1801
+ // this should work with `as WorkboxPluginCallbackParam[C]`.
1802
+ return plugin[name](statefulParam);
1803
+ };
1804
+ yield statefulCallback;
1805
+ }
1806
+ }
1807
+ }
1808
+ /**
1809
+ * Adds a promise to the
1810
+ * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises}
1811
+ * of the event associated with the request being handled (usually a
1812
+ * `FetchEvent`).
1813
+ *
1814
+ * Note: you can await
1815
+ * {@link workbox-strategies.StrategyHandler~doneWaiting}
1816
+ * to know when all added promises have settled.
1817
+ *
1818
+ * @param {Promise} promise A promise to add to the extend lifetime promises
1819
+ * of the event that triggered the request.
1820
+ */
1821
+ waitUntil(promise) {
1822
+ this._extendLifetimePromises.push(promise);
1823
+ return promise;
1824
+ }
1825
+ /**
1826
+ * Returns a promise that resolves once all promises passed to
1827
+ * {@link workbox-strategies.StrategyHandler~waitUntil}
1828
+ * have settled.
1829
+ *
1830
+ * Note: any work done after `doneWaiting()` settles should be manually
1831
+ * passed to an event's `waitUntil()` method (not this handler's
1832
+ * `waitUntil()` method), otherwise the service worker thread may be killed
1833
+ * prior to your work completing.
1834
+ */
1835
+ async doneWaiting() {
1836
+ while (this._extendLifetimePromises.length) {
1837
+ const promises = this._extendLifetimePromises.splice(0);
1838
+ const result = await Promise.allSettled(promises);
1839
+ const firstRejection = result.find(i => i.status === 'rejected');
1840
+ if (firstRejection) {
1841
+ throw firstRejection.reason;
1842
+ }
1843
+ }
1844
+ }
1845
+ /**
1846
+ * Stops running the strategy and immediately resolves any pending
1847
+ * `waitUntil()` promises.
1848
+ */
1849
+ destroy() {
1850
+ this._handlerDeferred.resolve(null);
1851
+ }
1852
+ /**
1853
+ * This method will call cacheWillUpdate on the available plugins (or use
1854
+ * status === 200) to determine if the Response is safe and valid to cache.
1855
+ *
1856
+ * @param {Request} options.request
1857
+ * @param {Response} options.response
1858
+ * @return {Promise<Response|undefined>}
1859
+ *
1860
+ * @private
1861
+ */
1862
+ async _ensureResponseSafeToCache(response) {
1863
+ let responseToCache = response;
1864
+ let pluginsUsed = false;
1865
+ for (const callback of this.iterateCallbacks('cacheWillUpdate')) {
1866
+ responseToCache = (await callback({
1867
+ request: this.request,
1868
+ response: responseToCache,
1869
+ event: this.event
1870
+ })) || undefined;
1871
+ pluginsUsed = true;
1872
+ if (!responseToCache) {
1873
+ break;
1874
+ }
1875
+ }
1876
+ if (!pluginsUsed) {
1877
+ if (responseToCache && responseToCache.status !== 200) {
1878
+ responseToCache = undefined;
1879
+ }
1880
+ {
1881
+ if (responseToCache) {
1882
+ if (responseToCache.status !== 200) {
1883
+ if (responseToCache.status === 0) {
1884
+ logger.warn(`The response for '${this.request.url}' ` + `is an opaque response. The caching strategy that you're ` + `using will not cache opaque responses by default.`);
1885
+ } else {
1886
+ logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`);
1887
+ }
1888
+ }
1889
+ }
1890
+ }
1891
+ }
1892
+ return responseToCache;
1893
+ }
1894
+ }
1895
+
1896
+ /*
1897
+ Copyright 2020 Google LLC
1898
+
1899
+ Use of this source code is governed by an MIT-style
1900
+ license that can be found in the LICENSE file or at
1901
+ https://opensource.org/licenses/MIT.
1902
+ */
1903
+ /**
1904
+ * An abstract base class that all other strategy classes must extend from:
1905
+ *
1906
+ * @memberof workbox-strategies
1907
+ */
1908
+ class Strategy {
1909
+ /**
1910
+ * Creates a new instance of the strategy and sets all documented option
1911
+ * properties as public instance properties.
1912
+ *
1913
+ * Note: if a custom strategy class extends the base Strategy class and does
1914
+ * not need more than these properties, it does not need to define its own
1915
+ * constructor.
1916
+ *
1917
+ * @param {Object} [options]
1918
+ * @param {string} [options.cacheName] Cache name to store and retrieve
1919
+ * requests. Defaults to the cache names provided by
1920
+ * {@link workbox-core.cacheNames}.
1921
+ * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
1922
+ * to use in conjunction with this caching strategy.
1923
+ * @param {Object} [options.fetchOptions] Values passed along to the
1924
+ * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
1925
+ * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
1926
+ * `fetch()` requests made by this strategy.
1927
+ * @param {Object} [options.matchOptions] The
1928
+ * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}
1929
+ * for any `cache.match()` or `cache.put()` calls made by this strategy.
1930
+ */
1931
+ constructor(options = {}) {
1932
+ /**
1933
+ * Cache name to store and retrieve
1934
+ * requests. Defaults to the cache names provided by
1935
+ * {@link workbox-core.cacheNames}.
1936
+ *
1937
+ * @type {string}
1938
+ */
1939
+ this.cacheName = cacheNames.getRuntimeName(options.cacheName);
1940
+ /**
1941
+ * The list
1942
+ * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
1943
+ * used by this strategy.
1944
+ *
1945
+ * @type {Array<Object>}
1946
+ */
1947
+ this.plugins = options.plugins || [];
1948
+ /**
1949
+ * Values passed along to the
1950
+ * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters}
1951
+ * of all fetch() requests made by this strategy.
1952
+ *
1953
+ * @type {Object}
1954
+ */
1955
+ this.fetchOptions = options.fetchOptions;
1956
+ /**
1957
+ * The
1958
+ * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}
1959
+ * for any `cache.match()` or `cache.put()` calls made by this strategy.
1960
+ *
1961
+ * @type {Object}
1962
+ */
1963
+ this.matchOptions = options.matchOptions;
1964
+ }
1965
+ /**
1966
+ * Perform a request strategy and returns a `Promise` that will resolve with
1967
+ * a `Response`, invoking all relevant plugin callbacks.
1968
+ *
1969
+ * When a strategy instance is registered with a Workbox
1970
+ * {@link workbox-routing.Route}, this method is automatically
1971
+ * called when the route matches.
1972
+ *
1973
+ * Alternatively, this method can be used in a standalone `FetchEvent`
1974
+ * listener by passing it to `event.respondWith()`.
1975
+ *
1976
+ * @param {FetchEvent|Object} options A `FetchEvent` or an object with the
1977
+ * properties listed below.
1978
+ * @param {Request|string} options.request A request to run this strategy for.
1979
+ * @param {ExtendableEvent} options.event The event associated with the
1980
+ * request.
1981
+ * @param {URL} [options.url]
1982
+ * @param {*} [options.params]
1983
+ */
1984
+ handle(options) {
1985
+ const [responseDone] = this.handleAll(options);
1986
+ return responseDone;
1987
+ }
1988
+ /**
1989
+ * Similar to {@link workbox-strategies.Strategy~handle}, but
1990
+ * instead of just returning a `Promise` that resolves to a `Response` it
1991
+ * it will return an tuple of `[response, done]` promises, where the former
1992
+ * (`response`) is equivalent to what `handle()` returns, and the latter is a
1993
+ * Promise that will resolve once any promises that were added to
1994
+ * `event.waitUntil()` as part of performing the strategy have completed.
1995
+ *
1996
+ * You can await the `done` promise to ensure any extra work performed by
1997
+ * the strategy (usually caching responses) completes successfully.
1998
+ *
1999
+ * @param {FetchEvent|Object} options A `FetchEvent` or an object with the
2000
+ * properties listed below.
2001
+ * @param {Request|string} options.request A request to run this strategy for.
2002
+ * @param {ExtendableEvent} options.event The event associated with the
2003
+ * request.
2004
+ * @param {URL} [options.url]
2005
+ * @param {*} [options.params]
2006
+ * @return {Array<Promise>} A tuple of [response, done]
2007
+ * promises that can be used to determine when the response resolves as
2008
+ * well as when the handler has completed all its work.
2009
+ */
2010
+ handleAll(options) {
2011
+ // Allow for flexible options to be passed.
2012
+ if (options instanceof FetchEvent) {
2013
+ options = {
2014
+ event: options,
2015
+ request: options.request
2016
+ };
2017
+ }
2018
+ const event = options.event;
2019
+ const request = typeof options.request === 'string' ? new Request(options.request) : options.request;
2020
+ const params = 'params' in options ? options.params : undefined;
2021
+ const handler = new StrategyHandler(this, {
2022
+ event,
2023
+ request,
2024
+ params
2025
+ });
2026
+ const responseDone = this._getResponse(handler, request, event);
2027
+ const handlerDone = this._awaitComplete(responseDone, handler, request, event);
2028
+ // Return an array of promises, suitable for use with Promise.all().
2029
+ return [responseDone, handlerDone];
2030
+ }
2031
+ async _getResponse(handler, request, event) {
2032
+ await handler.runCallbacks('handlerWillStart', {
2033
+ event,
2034
+ request
2035
+ });
2036
+ let response = undefined;
2037
+ try {
2038
+ response = await this._handle(request, handler);
2039
+ // The "official" Strategy subclasses all throw this error automatically,
2040
+ // but in case a third-party Strategy doesn't, ensure that we have a
2041
+ // consistent failure when there's no response or an error response.
2042
+ if (!response || response.type === 'error') {
2043
+ throw new WorkboxError('no-response', {
2044
+ url: request.url
2045
+ });
2046
+ }
2047
+ } catch (error) {
2048
+ if (error instanceof Error) {
2049
+ for (const callback of handler.iterateCallbacks('handlerDidError')) {
2050
+ response = await callback({
2051
+ error,
2052
+ event,
2053
+ request
2054
+ });
2055
+ if (response) {
2056
+ break;
2057
+ }
2058
+ }
2059
+ }
2060
+ if (!response) {
2061
+ throw error;
2062
+ } else {
2063
+ logger.log(`While responding to '${getFriendlyURL(request.url)}', ` + `an ${error instanceof Error ? error.toString() : ''} error occurred. Using a fallback response provided by ` + `a handlerDidError plugin.`);
2064
+ }
2065
+ }
2066
+ for (const callback of handler.iterateCallbacks('handlerWillRespond')) {
2067
+ response = await callback({
2068
+ event,
2069
+ request,
2070
+ response
2071
+ });
2072
+ }
2073
+ return response;
2074
+ }
2075
+ async _awaitComplete(responseDone, handler, request, event) {
2076
+ let response;
2077
+ let error;
2078
+ try {
2079
+ response = await responseDone;
2080
+ } catch (error) {
2081
+ // Ignore errors, as response errors should be caught via the `response`
2082
+ // promise above. The `done` promise will only throw for errors in
2083
+ // promises passed to `handler.waitUntil()`.
2084
+ }
2085
+ try {
2086
+ await handler.runCallbacks('handlerDidRespond', {
2087
+ event,
2088
+ request,
2089
+ response
2090
+ });
2091
+ await handler.doneWaiting();
2092
+ } catch (waitUntilError) {
2093
+ if (waitUntilError instanceof Error) {
2094
+ error = waitUntilError;
2095
+ }
2096
+ }
2097
+ await handler.runCallbacks('handlerDidComplete', {
2098
+ event,
2099
+ request,
2100
+ response,
2101
+ error: error
2102
+ });
2103
+ handler.destroy();
2104
+ if (error) {
2105
+ throw error;
2106
+ }
2107
+ }
2108
+ }
2109
+ /**
2110
+ * Classes extending the `Strategy` based class should implement this method,
2111
+ * and leverage the {@link workbox-strategies.StrategyHandler}
2112
+ * arg to perform all fetching and cache logic, which will ensure all relevant
2113
+ * cache, cache options, fetch options and plugins are used (per the current
2114
+ * strategy instance).
2115
+ *
2116
+ * @name _handle
2117
+ * @instance
2118
+ * @abstract
2119
+ * @function
2120
+ * @param {Request} request
2121
+ * @param {workbox-strategies.StrategyHandler} handler
2122
+ * @return {Promise<Response>}
2123
+ *
2124
+ * @memberof workbox-strategies.Strategy
2125
+ */
2126
+
2127
+ /*
2128
+ Copyright 2018 Google LLC
2129
+
2130
+ Use of this source code is governed by an MIT-style
2131
+ license that can be found in the LICENSE file or at
2132
+ https://opensource.org/licenses/MIT.
2133
+ */
2134
+ const messages = {
2135
+ strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`,
2136
+ printFinalResponse: response => {
2137
+ if (response) {
2138
+ logger.groupCollapsed(`View the final response here.`);
2139
+ logger.log(response || '[No response returned]');
2140
+ logger.groupEnd();
2141
+ }
2142
+ }
2143
+ };
2144
+
2145
+ /*
2146
+ Copyright 2018 Google LLC
2147
+
2148
+ Use of this source code is governed by an MIT-style
2149
+ license that can be found in the LICENSE file or at
2150
+ https://opensource.org/licenses/MIT.
2151
+ */
2152
+ /**
2153
+ * An implementation of a
2154
+ * [network first](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network-first-falling-back-to-cache)
2155
+ * request strategy.
2156
+ *
2157
+ * By default, this strategy will cache responses with a 200 status code as
2158
+ * well as [opaque responses](https://developer.chrome.com/docs/workbox/caching-resources-during-runtime/#opaque-responses).
2159
+ * Opaque responses are are cross-origin requests where the response doesn't
2160
+ * support [CORS](https://enable-cors.org/).
2161
+ *
2162
+ * If the network request fails, and there is no cache match, this will throw
2163
+ * a `WorkboxError` exception.
2164
+ *
2165
+ * @extends workbox-strategies.Strategy
2166
+ * @memberof workbox-strategies
2167
+ */
2168
+ class NetworkFirst extends Strategy {
2169
+ /**
2170
+ * @param {Object} [options]
2171
+ * @param {string} [options.cacheName] Cache name to store and retrieve
2172
+ * requests. Defaults to cache names provided by
2173
+ * {@link workbox-core.cacheNames}.
2174
+ * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
2175
+ * to use in conjunction with this caching strategy.
2176
+ * @param {Object} [options.fetchOptions] Values passed along to the
2177
+ * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
2178
+ * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
2179
+ * `fetch()` requests made by this strategy.
2180
+ * @param {Object} [options.matchOptions] [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
2181
+ * @param {number} [options.networkTimeoutSeconds] If set, any network requests
2182
+ * that fail to respond within the timeout will fallback to the cache.
2183
+ *
2184
+ * This option can be used to combat
2185
+ * "[lie-fi]{@link https://developers.google.com/web/fundamentals/performance/poor-connectivity/#lie-fi}"
2186
+ * scenarios.
2187
+ */
2188
+ constructor(options = {}) {
2189
+ super(options);
2190
+ // If this instance contains no plugins with a 'cacheWillUpdate' callback,
2191
+ // prepend the `cacheOkAndOpaquePlugin` plugin to the plugins list.
2192
+ if (!this.plugins.some(p => 'cacheWillUpdate' in p)) {
2193
+ this.plugins.unshift(cacheOkAndOpaquePlugin);
2194
+ }
2195
+ this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
2196
+ {
2197
+ if (this._networkTimeoutSeconds) {
2198
+ finalAssertExports.isType(this._networkTimeoutSeconds, 'number', {
2199
+ moduleName: 'workbox-strategies',
2200
+ className: this.constructor.name,
2201
+ funcName: 'constructor',
2202
+ paramName: 'networkTimeoutSeconds'
2203
+ });
2204
+ }
2205
+ }
2206
+ }
2207
+ /**
2208
+ * @private
2209
+ * @param {Request|string} request A request to run this strategy for.
2210
+ * @param {workbox-strategies.StrategyHandler} handler The event that
2211
+ * triggered the request.
2212
+ * @return {Promise<Response>}
2213
+ */
2214
+ async _handle(request, handler) {
2215
+ const logs = [];
2216
+ {
2217
+ finalAssertExports.isInstance(request, Request, {
2218
+ moduleName: 'workbox-strategies',
2219
+ className: this.constructor.name,
2220
+ funcName: 'handle',
2221
+ paramName: 'makeRequest'
2222
+ });
2223
+ }
2224
+ const promises = [];
2225
+ let timeoutId;
2226
+ if (this._networkTimeoutSeconds) {
2227
+ const {
2228
+ id,
2229
+ promise
2230
+ } = this._getTimeoutPromise({
2231
+ request,
2232
+ logs,
2233
+ handler
2234
+ });
2235
+ timeoutId = id;
2236
+ promises.push(promise);
2237
+ }
2238
+ const networkPromise = this._getNetworkPromise({
2239
+ timeoutId,
2240
+ request,
2241
+ logs,
2242
+ handler
2243
+ });
2244
+ promises.push(networkPromise);
2245
+ const response = await handler.waitUntil((async () => {
2246
+ // Promise.race() will resolve as soon as the first promise resolves.
2247
+ return (await handler.waitUntil(Promise.race(promises))) || (
2248
+ // If Promise.race() resolved with null, it might be due to a network
2249
+ // timeout + a cache miss. If that were to happen, we'd rather wait until
2250
+ // the networkPromise resolves instead of returning null.
2251
+ // Note that it's fine to await an already-resolved promise, so we don't
2252
+ // have to check to see if it's still "in flight".
2253
+ await networkPromise);
2254
+ })());
2255
+ {
2256
+ logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
2257
+ for (const log of logs) {
2258
+ logger.log(log);
2259
+ }
2260
+ messages.printFinalResponse(response);
2261
+ logger.groupEnd();
2262
+ }
2263
+ if (!response) {
2264
+ throw new WorkboxError('no-response', {
2265
+ url: request.url
2266
+ });
2267
+ }
2268
+ return response;
2269
+ }
2270
+ /**
2271
+ * @param {Object} options
2272
+ * @param {Request} options.request
2273
+ * @param {Array} options.logs A reference to the logs array
2274
+ * @param {Event} options.event
2275
+ * @return {Promise<Response>}
2276
+ *
2277
+ * @private
2278
+ */
2279
+ _getTimeoutPromise({
2280
+ request,
2281
+ logs,
2282
+ handler
2283
+ }) {
2284
+ let timeoutId;
2285
+ const timeoutPromise = new Promise(resolve => {
2286
+ const onNetworkTimeout = async () => {
2287
+ {
2288
+ logs.push(`Timing out the network response at ` + `${this._networkTimeoutSeconds} seconds.`);
2289
+ }
2290
+ resolve(await handler.cacheMatch(request));
2291
+ };
2292
+ timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000);
2293
+ });
2294
+ return {
2295
+ promise: timeoutPromise,
2296
+ id: timeoutId
2297
+ };
2298
+ }
2299
+ /**
2300
+ * @param {Object} options
2301
+ * @param {number|undefined} options.timeoutId
2302
+ * @param {Request} options.request
2303
+ * @param {Array} options.logs A reference to the logs Array.
2304
+ * @param {Event} options.event
2305
+ * @return {Promise<Response>}
2306
+ *
2307
+ * @private
2308
+ */
2309
+ async _getNetworkPromise({
2310
+ timeoutId,
2311
+ request,
2312
+ logs,
2313
+ handler
2314
+ }) {
2315
+ let error;
2316
+ let response;
2317
+ try {
2318
+ response = await handler.fetchAndCachePut(request);
2319
+ } catch (fetchError) {
2320
+ if (fetchError instanceof Error) {
2321
+ error = fetchError;
2322
+ }
2323
+ }
2324
+ if (timeoutId) {
2325
+ clearTimeout(timeoutId);
2326
+ }
2327
+ {
2328
+ if (response) {
2329
+ logs.push(`Got response from network.`);
2330
+ } else {
2331
+ logs.push(`Unable to get a response from the network. Will respond ` + `with a cached response.`);
2332
+ }
2333
+ }
2334
+ if (error || !response) {
2335
+ response = await handler.cacheMatch(request);
2336
+ {
2337
+ if (response) {
2338
+ logs.push(`Found a cached response in the '${this.cacheName}'` + ` cache.`);
2339
+ } else {
2340
+ logs.push(`No response found in the '${this.cacheName}' cache.`);
2341
+ }
2342
+ }
2343
+ }
2344
+ return response;
2345
+ }
2346
+ }
2347
+
2348
+ /*
2349
+ Copyright 2019 Google LLC
2350
+
2351
+ Use of this source code is governed by an MIT-style
2352
+ license that can be found in the LICENSE file or at
2353
+ https://opensource.org/licenses/MIT.
2354
+ */
2355
+ /**
2356
+ * Claim any currently available clients once the service worker
2357
+ * becomes active. This is normally used in conjunction with `skipWaiting()`.
2358
+ *
2359
+ * @memberof workbox-core
2360
+ */
2361
+ function clientsClaim() {
2362
+ self.addEventListener('activate', () => self.clients.claim());
2363
+ }
2364
+
2365
+ /*
2366
+ Copyright 2020 Google LLC
2367
+ Use of this source code is governed by an MIT-style
2368
+ license that can be found in the LICENSE file or at
2369
+ https://opensource.org/licenses/MIT.
2370
+ */
2371
+ /**
2372
+ * A utility method that makes it easier to use `event.waitUntil` with
2373
+ * async functions and return the result.
2374
+ *
2375
+ * @param {ExtendableEvent} event
2376
+ * @param {Function} asyncFn
2377
+ * @return {Function}
2378
+ * @private
2379
+ */
2380
+ function waitUntil(event, asyncFn) {
2381
+ const returnPromise = asyncFn();
2382
+ event.waitUntil(returnPromise);
2383
+ return returnPromise;
2384
+ }
2385
+
2386
+ // @ts-ignore
2387
+ try {
2388
+ self['workbox:precaching:7.4.0'] && _();
2389
+ } catch (e) {}
2390
+
2391
+ /*
2392
+ Copyright 2018 Google LLC
2393
+
2394
+ Use of this source code is governed by an MIT-style
2395
+ license that can be found in the LICENSE file or at
2396
+ https://opensource.org/licenses/MIT.
2397
+ */
2398
+ // Name of the search parameter used to store revision info.
2399
+ const REVISION_SEARCH_PARAM = '__WB_REVISION__';
2400
+ /**
2401
+ * Converts a manifest entry into a versioned URL suitable for precaching.
2402
+ *
2403
+ * @param {Object|string} entry
2404
+ * @return {string} A URL with versioning info.
2405
+ *
2406
+ * @private
2407
+ * @memberof workbox-precaching
2408
+ */
2409
+ function createCacheKey(entry) {
2410
+ if (!entry) {
2411
+ throw new WorkboxError('add-to-cache-list-unexpected-type', {
2412
+ entry
2413
+ });
2414
+ }
2415
+ // If a precache manifest entry is a string, it's assumed to be a versioned
2416
+ // URL, like '/app.abcd1234.js'. Return as-is.
2417
+ if (typeof entry === 'string') {
2418
+ const urlObject = new URL(entry, location.href);
2419
+ return {
2420
+ cacheKey: urlObject.href,
2421
+ url: urlObject.href
2422
+ };
2423
+ }
2424
+ const {
2425
+ revision,
2426
+ url
2427
+ } = entry;
2428
+ if (!url) {
2429
+ throw new WorkboxError('add-to-cache-list-unexpected-type', {
2430
+ entry
2431
+ });
2432
+ }
2433
+ // If there's just a URL and no revision, then it's also assumed to be a
2434
+ // versioned URL.
2435
+ if (!revision) {
2436
+ const urlObject = new URL(url, location.href);
2437
+ return {
2438
+ cacheKey: urlObject.href,
2439
+ url: urlObject.href
2440
+ };
2441
+ }
2442
+ // Otherwise, construct a properly versioned URL using the custom Workbox
2443
+ // search parameter along with the revision info.
2444
+ const cacheKeyURL = new URL(url, location.href);
2445
+ const originalURL = new URL(url, location.href);
2446
+ cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
2447
+ return {
2448
+ cacheKey: cacheKeyURL.href,
2449
+ url: originalURL.href
2450
+ };
2451
+ }
2452
+
2453
+ /*
2454
+ Copyright 2020 Google LLC
2455
+
2456
+ Use of this source code is governed by an MIT-style
2457
+ license that can be found in the LICENSE file or at
2458
+ https://opensource.org/licenses/MIT.
2459
+ */
2460
+ /**
2461
+ * A plugin, designed to be used with PrecacheController, to determine the
2462
+ * of assets that were updated (or not updated) during the install event.
2463
+ *
2464
+ * @private
2465
+ */
2466
+ class PrecacheInstallReportPlugin {
2467
+ constructor() {
2468
+ this.updatedURLs = [];
2469
+ this.notUpdatedURLs = [];
2470
+ this.handlerWillStart = async ({
2471
+ request,
2472
+ state
2473
+ }) => {
2474
+ // TODO: `state` should never be undefined...
2475
+ if (state) {
2476
+ state.originalRequest = request;
2477
+ }
2478
+ };
2479
+ this.cachedResponseWillBeUsed = async ({
2480
+ event,
2481
+ state,
2482
+ cachedResponse
2483
+ }) => {
2484
+ if (event.type === 'install') {
2485
+ if (state && state.originalRequest && state.originalRequest instanceof Request) {
2486
+ // TODO: `state` should never be undefined...
2487
+ const url = state.originalRequest.url;
2488
+ if (cachedResponse) {
2489
+ this.notUpdatedURLs.push(url);
2490
+ } else {
2491
+ this.updatedURLs.push(url);
2492
+ }
2493
+ }
2494
+ }
2495
+ return cachedResponse;
2496
+ };
2497
+ }
2498
+ }
2499
+
2500
+ /*
2501
+ Copyright 2020 Google LLC
2502
+
2503
+ Use of this source code is governed by an MIT-style
2504
+ license that can be found in the LICENSE file or at
2505
+ https://opensource.org/licenses/MIT.
2506
+ */
2507
+ /**
2508
+ * A plugin, designed to be used with PrecacheController, to translate URLs into
2509
+ * the corresponding cache key, based on the current revision info.
2510
+ *
2511
+ * @private
2512
+ */
2513
+ class PrecacheCacheKeyPlugin {
2514
+ constructor({
2515
+ precacheController
2516
+ }) {
2517
+ this.cacheKeyWillBeUsed = async ({
2518
+ request,
2519
+ params
2520
+ }) => {
2521
+ // Params is type any, can't change right now.
2522
+ /* eslint-disable */
2523
+ const cacheKey = (params === null || params === void 0 ? void 0 : params.cacheKey) || this._precacheController.getCacheKeyForURL(request.url);
2524
+ /* eslint-enable */
2525
+ return cacheKey ? new Request(cacheKey, {
2526
+ headers: request.headers
2527
+ }) : request;
2528
+ };
2529
+ this._precacheController = precacheController;
2530
+ }
2531
+ }
2532
+
2533
+ /*
2534
+ Copyright 2018 Google LLC
2535
+
2536
+ Use of this source code is governed by an MIT-style
2537
+ license that can be found in the LICENSE file or at
2538
+ https://opensource.org/licenses/MIT.
2539
+ */
2540
+ /**
2541
+ * @param {string} groupTitle
2542
+ * @param {Array<string>} deletedURLs
2543
+ *
2544
+ * @private
2545
+ */
2546
+ const logGroup = (groupTitle, deletedURLs) => {
2547
+ logger.groupCollapsed(groupTitle);
2548
+ for (const url of deletedURLs) {
2549
+ logger.log(url);
2550
+ }
2551
+ logger.groupEnd();
2552
+ };
2553
+ /**
2554
+ * @param {Array<string>} deletedURLs
2555
+ *
2556
+ * @private
2557
+ * @memberof workbox-precaching
2558
+ */
2559
+ function printCleanupDetails(deletedURLs) {
2560
+ const deletionCount = deletedURLs.length;
2561
+ if (deletionCount > 0) {
2562
+ logger.groupCollapsed(`During precaching cleanup, ` + `${deletionCount} cached ` + `request${deletionCount === 1 ? ' was' : 's were'} deleted.`);
2563
+ logGroup('Deleted Cache Requests', deletedURLs);
2564
+ logger.groupEnd();
2565
+ }
2566
+ }
2567
+
2568
+ /*
2569
+ Copyright 2018 Google LLC
2570
+
2571
+ Use of this source code is governed by an MIT-style
2572
+ license that can be found in the LICENSE file or at
2573
+ https://opensource.org/licenses/MIT.
2574
+ */
2575
+ /**
2576
+ * @param {string} groupTitle
2577
+ * @param {Array<string>} urls
2578
+ *
2579
+ * @private
2580
+ */
2581
+ function _nestedGroup(groupTitle, urls) {
2582
+ if (urls.length === 0) {
2583
+ return;
2584
+ }
2585
+ logger.groupCollapsed(groupTitle);
2586
+ for (const url of urls) {
2587
+ logger.log(url);
2588
+ }
2589
+ logger.groupEnd();
2590
+ }
2591
+ /**
2592
+ * @param {Array<string>} urlsToPrecache
2593
+ * @param {Array<string>} urlsAlreadyPrecached
2594
+ *
2595
+ * @private
2596
+ * @memberof workbox-precaching
2597
+ */
2598
+ function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) {
2599
+ const precachedCount = urlsToPrecache.length;
2600
+ const alreadyPrecachedCount = urlsAlreadyPrecached.length;
2601
+ if (precachedCount || alreadyPrecachedCount) {
2602
+ let message = `Precaching ${precachedCount} file${precachedCount === 1 ? '' : 's'}.`;
2603
+ if (alreadyPrecachedCount > 0) {
2604
+ message += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? ' is' : 's are'} already cached.`;
2605
+ }
2606
+ logger.groupCollapsed(message);
2607
+ _nestedGroup(`View newly precached URLs.`, urlsToPrecache);
2608
+ _nestedGroup(`View previously precached URLs.`, urlsAlreadyPrecached);
2609
+ logger.groupEnd();
2610
+ }
2611
+ }
2612
+
2613
+ /*
2614
+ Copyright 2019 Google LLC
2615
+
2616
+ Use of this source code is governed by an MIT-style
2617
+ license that can be found in the LICENSE file or at
2618
+ https://opensource.org/licenses/MIT.
2619
+ */
2620
+ let supportStatus;
2621
+ /**
2622
+ * A utility function that determines whether the current browser supports
2623
+ * constructing a new `Response` from a `response.body` stream.
2624
+ *
2625
+ * @return {boolean} `true`, if the current browser can successfully
2626
+ * construct a `Response` from a `response.body` stream, `false` otherwise.
2627
+ *
2628
+ * @private
2629
+ */
2630
+ function canConstructResponseFromBodyStream() {
2631
+ if (supportStatus === undefined) {
2632
+ const testResponse = new Response('');
2633
+ if ('body' in testResponse) {
2634
+ try {
2635
+ new Response(testResponse.body);
2636
+ supportStatus = true;
2637
+ } catch (error) {
2638
+ supportStatus = false;
2639
+ }
2640
+ }
2641
+ supportStatus = false;
2642
+ }
2643
+ return supportStatus;
2644
+ }
2645
+
2646
+ /*
2647
+ Copyright 2019 Google LLC
2648
+
2649
+ Use of this source code is governed by an MIT-style
2650
+ license that can be found in the LICENSE file or at
2651
+ https://opensource.org/licenses/MIT.
2652
+ */
2653
+ /**
2654
+ * Allows developers to copy a response and modify its `headers`, `status`,
2655
+ * or `statusText` values (the values settable via a
2656
+ * [`ResponseInit`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Response/Response#Syntax}
2657
+ * object in the constructor).
2658
+ * To modify these values, pass a function as the second argument. That
2659
+ * function will be invoked with a single object with the response properties
2660
+ * `{headers, status, statusText}`. The return value of this function will
2661
+ * be used as the `ResponseInit` for the new `Response`. To change the values
2662
+ * either modify the passed parameter(s) and return it, or return a totally
2663
+ * new object.
2664
+ *
2665
+ * This method is intentionally limited to same-origin responses, regardless of
2666
+ * whether CORS was used or not.
2667
+ *
2668
+ * @param {Response} response
2669
+ * @param {Function} modifier
2670
+ * @memberof workbox-core
2671
+ */
2672
+ async function copyResponse(response, modifier) {
2673
+ let origin = null;
2674
+ // If response.url isn't set, assume it's cross-origin and keep origin null.
2675
+ if (response.url) {
2676
+ const responseURL = new URL(response.url);
2677
+ origin = responseURL.origin;
2678
+ }
2679
+ if (origin !== self.location.origin) {
2680
+ throw new WorkboxError('cross-origin-copy-response', {
2681
+ origin
2682
+ });
2683
+ }
2684
+ const clonedResponse = response.clone();
2685
+ // Create a fresh `ResponseInit` object by cloning the headers.
2686
+ const responseInit = {
2687
+ headers: new Headers(clonedResponse.headers),
2688
+ status: clonedResponse.status,
2689
+ statusText: clonedResponse.statusText
2690
+ };
2691
+ // Apply any user modifications.
2692
+ const modifiedResponseInit = responseInit;
2693
+ // Create the new response from the body stream and `ResponseInit`
2694
+ // modifications. Note: not all browsers support the Response.body stream,
2695
+ // so fall back to reading the entire body into memory as a blob.
2696
+ const body = canConstructResponseFromBodyStream() ? clonedResponse.body : await clonedResponse.blob();
2697
+ return new Response(body, modifiedResponseInit);
2698
+ }
2699
+
2700
+ /*
2701
+ Copyright 2020 Google LLC
2702
+
2703
+ Use of this source code is governed by an MIT-style
2704
+ license that can be found in the LICENSE file or at
2705
+ https://opensource.org/licenses/MIT.
2706
+ */
2707
+ /**
2708
+ * A {@link workbox-strategies.Strategy} implementation
2709
+ * specifically designed to work with
2710
+ * {@link workbox-precaching.PrecacheController}
2711
+ * to both cache and fetch precached assets.
2712
+ *
2713
+ * Note: an instance of this class is created automatically when creating a
2714
+ * `PrecacheController`; it's generally not necessary to create this yourself.
2715
+ *
2716
+ * @extends workbox-strategies.Strategy
2717
+ * @memberof workbox-precaching
2718
+ */
2719
+ class PrecacheStrategy extends Strategy {
2720
+ /**
2721
+ *
2722
+ * @param {Object} [options]
2723
+ * @param {string} [options.cacheName] Cache name to store and retrieve
2724
+ * requests. Defaults to the cache names provided by
2725
+ * {@link workbox-core.cacheNames}.
2726
+ * @param {Array<Object>} [options.plugins] {@link https://developers.google.com/web/tools/workbox/guides/using-plugins|Plugins}
2727
+ * to use in conjunction with this caching strategy.
2728
+ * @param {Object} [options.fetchOptions] Values passed along to the
2729
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters|init}
2730
+ * of all fetch() requests made by this strategy.
2731
+ * @param {Object} [options.matchOptions] The
2732
+ * {@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions|CacheQueryOptions}
2733
+ * for any `cache.match()` or `cache.put()` calls made by this strategy.
2734
+ * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to
2735
+ * get the response from the network if there's a precache miss.
2736
+ */
2737
+ constructor(options = {}) {
2738
+ options.cacheName = cacheNames.getPrecacheName(options.cacheName);
2739
+ super(options);
2740
+ this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true;
2741
+ // Redirected responses cannot be used to satisfy a navigation request, so
2742
+ // any redirected response must be "copied" rather than cloned, so the new
2743
+ // response doesn't contain the `redirected` flag. See:
2744
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1
2745
+ this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);
2746
+ }
2747
+ /**
2748
+ * @private
2749
+ * @param {Request|string} request A request to run this strategy for.
2750
+ * @param {workbox-strategies.StrategyHandler} handler The event that
2751
+ * triggered the request.
2752
+ * @return {Promise<Response>}
2753
+ */
2754
+ async _handle(request, handler) {
2755
+ const response = await handler.cacheMatch(request);
2756
+ if (response) {
2757
+ return response;
2758
+ }
2759
+ // If this is an `install` event for an entry that isn't already cached,
2760
+ // then populate the cache.
2761
+ if (handler.event && handler.event.type === 'install') {
2762
+ return await this._handleInstall(request, handler);
2763
+ }
2764
+ // Getting here means something went wrong. An entry that should have been
2765
+ // precached wasn't found in the cache.
2766
+ return await this._handleFetch(request, handler);
2767
+ }
2768
+ async _handleFetch(request, handler) {
2769
+ let response;
2770
+ const params = handler.params || {};
2771
+ // Fall back to the network if we're configured to do so.
2772
+ if (this._fallbackToNetwork) {
2773
+ {
2774
+ logger.warn(`The precached response for ` + `${getFriendlyURL(request.url)} in ${this.cacheName} was not ` + `found. Falling back to the network.`);
2775
+ }
2776
+ const integrityInManifest = params.integrity;
2777
+ const integrityInRequest = request.integrity;
2778
+ const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest;
2779
+ // Do not add integrity if the original request is no-cors
2780
+ // See https://github.com/GoogleChrome/workbox/issues/3096
2781
+ response = await handler.fetch(new Request(request, {
2782
+ integrity: request.mode !== 'no-cors' ? integrityInRequest || integrityInManifest : undefined
2783
+ }));
2784
+ // It's only "safe" to repair the cache if we're using SRI to guarantee
2785
+ // that the response matches the precache manifest's expectations,
2786
+ // and there's either a) no integrity property in the incoming request
2787
+ // or b) there is an integrity, and it matches the precache manifest.
2788
+ // See https://github.com/GoogleChrome/workbox/issues/2858
2789
+ // Also if the original request users no-cors we don't use integrity.
2790
+ // See https://github.com/GoogleChrome/workbox/issues/3096
2791
+ if (integrityInManifest && noIntegrityConflict && request.mode !== 'no-cors') {
2792
+ this._useDefaultCacheabilityPluginIfNeeded();
2793
+ const wasCached = await handler.cachePut(request, response.clone());
2794
+ {
2795
+ if (wasCached) {
2796
+ logger.log(`A response for ${getFriendlyURL(request.url)} ` + `was used to "repair" the precache.`);
2797
+ }
2798
+ }
2799
+ }
2800
+ } else {
2801
+ // This shouldn't normally happen, but there are edge cases:
2802
+ // https://github.com/GoogleChrome/workbox/issues/1441
2803
+ throw new WorkboxError('missing-precache-entry', {
2804
+ cacheName: this.cacheName,
2805
+ url: request.url
2806
+ });
2807
+ }
2808
+ {
2809
+ const cacheKey = params.cacheKey || (await handler.getCacheKey(request, 'read'));
2810
+ // Workbox is going to handle the route.
2811
+ // print the routing details to the console.
2812
+ logger.groupCollapsed(`Precaching is responding to: ` + getFriendlyURL(request.url));
2813
+ logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`);
2814
+ logger.groupCollapsed(`View request details here.`);
2815
+ logger.log(request);
2816
+ logger.groupEnd();
2817
+ logger.groupCollapsed(`View response details here.`);
2818
+ logger.log(response);
2819
+ logger.groupEnd();
2820
+ logger.groupEnd();
2821
+ }
2822
+ return response;
2823
+ }
2824
+ async _handleInstall(request, handler) {
2825
+ this._useDefaultCacheabilityPluginIfNeeded();
2826
+ const response = await handler.fetch(request);
2827
+ // Make sure we defer cachePut() until after we know the response
2828
+ // should be cached; see https://github.com/GoogleChrome/workbox/issues/2737
2829
+ const wasCached = await handler.cachePut(request, response.clone());
2830
+ if (!wasCached) {
2831
+ // Throwing here will lead to the `install` handler failing, which
2832
+ // we want to do if *any* of the responses aren't safe to cache.
2833
+ throw new WorkboxError('bad-precaching-response', {
2834
+ url: request.url,
2835
+ status: response.status
2836
+ });
2837
+ }
2838
+ return response;
2839
+ }
2840
+ /**
2841
+ * This method is complex, as there a number of things to account for:
2842
+ *
2843
+ * The `plugins` array can be set at construction, and/or it might be added to
2844
+ * to at any time before the strategy is used.
2845
+ *
2846
+ * At the time the strategy is used (i.e. during an `install` event), there
2847
+ * needs to be at least one plugin that implements `cacheWillUpdate` in the
2848
+ * array, other than `copyRedirectedCacheableResponsesPlugin`.
2849
+ *
2850
+ * - If this method is called and there are no suitable `cacheWillUpdate`
2851
+ * plugins, we need to add `defaultPrecacheCacheabilityPlugin`.
2852
+ *
2853
+ * - If this method is called and there is exactly one `cacheWillUpdate`, then
2854
+ * we don't have to do anything (this might be a previously added
2855
+ * `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin).
2856
+ *
2857
+ * - If this method is called and there is more than one `cacheWillUpdate`,
2858
+ * then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so,
2859
+ * we need to remove it. (This situation is unlikely, but it could happen if
2860
+ * the strategy is used multiple times, the first without a `cacheWillUpdate`,
2861
+ * and then later on after manually adding a custom `cacheWillUpdate`.)
2862
+ *
2863
+ * See https://github.com/GoogleChrome/workbox/issues/2737 for more context.
2864
+ *
2865
+ * @private
2866
+ */
2867
+ _useDefaultCacheabilityPluginIfNeeded() {
2868
+ let defaultPluginIndex = null;
2869
+ let cacheWillUpdatePluginCount = 0;
2870
+ for (const [index, plugin] of this.plugins.entries()) {
2871
+ // Ignore the copy redirected plugin when determining what to do.
2872
+ if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) {
2873
+ continue;
2874
+ }
2875
+ // Save the default plugin's index, in case it needs to be removed.
2876
+ if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
2877
+ defaultPluginIndex = index;
2878
+ }
2879
+ if (plugin.cacheWillUpdate) {
2880
+ cacheWillUpdatePluginCount++;
2881
+ }
2882
+ }
2883
+ if (cacheWillUpdatePluginCount === 0) {
2884
+ this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);
2885
+ } else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {
2886
+ // Only remove the default plugin; multiple custom plugins are allowed.
2887
+ this.plugins.splice(defaultPluginIndex, 1);
2888
+ }
2889
+ // Nothing needs to be done if cacheWillUpdatePluginCount is 1
2890
+ }
2891
+ }
2892
+ PrecacheStrategy.defaultPrecacheCacheabilityPlugin = {
2893
+ async cacheWillUpdate({
2894
+ response
2895
+ }) {
2896
+ if (!response || response.status >= 400) {
2897
+ return null;
2898
+ }
2899
+ return response;
2900
+ }
2901
+ };
2902
+ PrecacheStrategy.copyRedirectedCacheableResponsesPlugin = {
2903
+ async cacheWillUpdate({
2904
+ response
2905
+ }) {
2906
+ return response.redirected ? await copyResponse(response) : response;
2907
+ }
2908
+ };
2909
+
2910
+ /*
2911
+ Copyright 2019 Google LLC
2912
+
2913
+ Use of this source code is governed by an MIT-style
2914
+ license that can be found in the LICENSE file or at
2915
+ https://opensource.org/licenses/MIT.
2916
+ */
2917
+ /**
2918
+ * Performs efficient precaching of assets.
2919
+ *
2920
+ * @memberof workbox-precaching
2921
+ */
2922
+ class PrecacheController {
2923
+ /**
2924
+ * Create a new PrecacheController.
2925
+ *
2926
+ * @param {Object} [options]
2927
+ * @param {string} [options.cacheName] The cache to use for precaching.
2928
+ * @param {string} [options.plugins] Plugins to use when precaching as well
2929
+ * as responding to fetch events for precached assets.
2930
+ * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to
2931
+ * get the response from the network if there's a precache miss.
2932
+ */
2933
+ constructor({
2934
+ cacheName,
2935
+ plugins = [],
2936
+ fallbackToNetwork = true
2937
+ } = {}) {
2938
+ this._urlsToCacheKeys = new Map();
2939
+ this._urlsToCacheModes = new Map();
2940
+ this._cacheKeysToIntegrities = new Map();
2941
+ this._strategy = new PrecacheStrategy({
2942
+ cacheName: cacheNames.getPrecacheName(cacheName),
2943
+ plugins: [...plugins, new PrecacheCacheKeyPlugin({
2944
+ precacheController: this
2945
+ })],
2946
+ fallbackToNetwork
2947
+ });
2948
+ // Bind the install and activate methods to the instance.
2949
+ this.install = this.install.bind(this);
2950
+ this.activate = this.activate.bind(this);
2951
+ }
2952
+ /**
2953
+ * @type {workbox-precaching.PrecacheStrategy} The strategy created by this controller and
2954
+ * used to cache assets and respond to fetch events.
2955
+ */
2956
+ get strategy() {
2957
+ return this._strategy;
2958
+ }
2959
+ /**
2960
+ * Adds items to the precache list, removing any duplicates and
2961
+ * stores the files in the
2962
+ * {@link workbox-core.cacheNames|"precache cache"} when the service
2963
+ * worker installs.
2964
+ *
2965
+ * This method can be called multiple times.
2966
+ *
2967
+ * @param {Array<Object|string>} [entries=[]] Array of entries to precache.
2968
+ */
2969
+ precache(entries) {
2970
+ this.addToCacheList(entries);
2971
+ if (!this._installAndActiveListenersAdded) {
2972
+ self.addEventListener('install', this.install);
2973
+ self.addEventListener('activate', this.activate);
2974
+ this._installAndActiveListenersAdded = true;
2975
+ }
2976
+ }
2977
+ /**
2978
+ * This method will add items to the precache list, removing duplicates
2979
+ * and ensuring the information is valid.
2980
+ *
2981
+ * @param {Array<workbox-precaching.PrecacheController.PrecacheEntry|string>} entries
2982
+ * Array of entries to precache.
2983
+ */
2984
+ addToCacheList(entries) {
2985
+ {
2986
+ finalAssertExports.isArray(entries, {
2987
+ moduleName: 'workbox-precaching',
2988
+ className: 'PrecacheController',
2989
+ funcName: 'addToCacheList',
2990
+ paramName: 'entries'
2991
+ });
2992
+ }
2993
+ const urlsToWarnAbout = [];
2994
+ for (const entry of entries) {
2995
+ // See https://github.com/GoogleChrome/workbox/issues/2259
2996
+ if (typeof entry === 'string') {
2997
+ urlsToWarnAbout.push(entry);
2998
+ } else if (entry && entry.revision === undefined) {
2999
+ urlsToWarnAbout.push(entry.url);
3000
+ }
3001
+ const {
3002
+ cacheKey,
3003
+ url
3004
+ } = createCacheKey(entry);
3005
+ const cacheMode = typeof entry !== 'string' && entry.revision ? 'reload' : 'default';
3006
+ if (this._urlsToCacheKeys.has(url) && this._urlsToCacheKeys.get(url) !== cacheKey) {
3007
+ throw new WorkboxError('add-to-cache-list-conflicting-entries', {
3008
+ firstEntry: this._urlsToCacheKeys.get(url),
3009
+ secondEntry: cacheKey
3010
+ });
3011
+ }
3012
+ if (typeof entry !== 'string' && entry.integrity) {
3013
+ if (this._cacheKeysToIntegrities.has(cacheKey) && this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) {
3014
+ throw new WorkboxError('add-to-cache-list-conflicting-integrities', {
3015
+ url
3016
+ });
3017
+ }
3018
+ this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);
3019
+ }
3020
+ this._urlsToCacheKeys.set(url, cacheKey);
3021
+ this._urlsToCacheModes.set(url, cacheMode);
3022
+ if (urlsToWarnAbout.length > 0) {
3023
+ const warningMessage = `Workbox is precaching URLs without revision ` + `info: ${urlsToWarnAbout.join(', ')}\nThis is generally NOT safe. ` + `Learn more at https://bit.ly/wb-precache`;
3024
+ {
3025
+ logger.warn(warningMessage);
3026
+ }
3027
+ }
3028
+ }
3029
+ }
3030
+ /**
3031
+ * Precaches new and updated assets. Call this method from the service worker
3032
+ * install event.
3033
+ *
3034
+ * Note: this method calls `event.waitUntil()` for you, so you do not need
3035
+ * to call it yourself in your event handlers.
3036
+ *
3037
+ * @param {ExtendableEvent} event
3038
+ * @return {Promise<workbox-precaching.InstallResult>}
3039
+ */
3040
+ install(event) {
3041
+ // waitUntil returns Promise<any>
3042
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
3043
+ return waitUntil(event, async () => {
3044
+ const installReportPlugin = new PrecacheInstallReportPlugin();
3045
+ this.strategy.plugins.push(installReportPlugin);
3046
+ // Cache entries one at a time.
3047
+ // See https://github.com/GoogleChrome/workbox/issues/2528
3048
+ for (const [url, cacheKey] of this._urlsToCacheKeys) {
3049
+ const integrity = this._cacheKeysToIntegrities.get(cacheKey);
3050
+ const cacheMode = this._urlsToCacheModes.get(url);
3051
+ const request = new Request(url, {
3052
+ integrity,
3053
+ cache: cacheMode,
3054
+ credentials: 'same-origin'
3055
+ });
3056
+ await Promise.all(this.strategy.handleAll({
3057
+ params: {
3058
+ cacheKey
3059
+ },
3060
+ request,
3061
+ event
3062
+ }));
3063
+ }
3064
+ const {
3065
+ updatedURLs,
3066
+ notUpdatedURLs
3067
+ } = installReportPlugin;
3068
+ {
3069
+ printInstallDetails(updatedURLs, notUpdatedURLs);
3070
+ }
3071
+ return {
3072
+ updatedURLs,
3073
+ notUpdatedURLs
3074
+ };
3075
+ });
3076
+ }
3077
+ /**
3078
+ * Deletes assets that are no longer present in the current precache manifest.
3079
+ * Call this method from the service worker activate event.
3080
+ *
3081
+ * Note: this method calls `event.waitUntil()` for you, so you do not need
3082
+ * to call it yourself in your event handlers.
3083
+ *
3084
+ * @param {ExtendableEvent} event
3085
+ * @return {Promise<workbox-precaching.CleanupResult>}
3086
+ */
3087
+ activate(event) {
3088
+ // waitUntil returns Promise<any>
3089
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
3090
+ return waitUntil(event, async () => {
3091
+ const cache = await self.caches.open(this.strategy.cacheName);
3092
+ const currentlyCachedRequests = await cache.keys();
3093
+ const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());
3094
+ const deletedURLs = [];
3095
+ for (const request of currentlyCachedRequests) {
3096
+ if (!expectedCacheKeys.has(request.url)) {
3097
+ await cache.delete(request);
3098
+ deletedURLs.push(request.url);
3099
+ }
3100
+ }
3101
+ {
3102
+ printCleanupDetails(deletedURLs);
3103
+ }
3104
+ return {
3105
+ deletedURLs
3106
+ };
3107
+ });
3108
+ }
3109
+ /**
3110
+ * Returns a mapping of a precached URL to the corresponding cache key, taking
3111
+ * into account the revision information for the URL.
3112
+ *
3113
+ * @return {Map<string, string>} A URL to cache key mapping.
3114
+ */
3115
+ getURLsToCacheKeys() {
3116
+ return this._urlsToCacheKeys;
3117
+ }
3118
+ /**
3119
+ * Returns a list of all the URLs that have been precached by the current
3120
+ * service worker.
3121
+ *
3122
+ * @return {Array<string>} The precached URLs.
3123
+ */
3124
+ getCachedURLs() {
3125
+ return [...this._urlsToCacheKeys.keys()];
3126
+ }
3127
+ /**
3128
+ * Returns the cache key used for storing a given URL. If that URL is
3129
+ * unversioned, like `/index.html', then the cache key will be the original
3130
+ * URL with a search parameter appended to it.
3131
+ *
3132
+ * @param {string} url A URL whose cache key you want to look up.
3133
+ * @return {string} The versioned URL that corresponds to a cache key
3134
+ * for the original URL, or undefined if that URL isn't precached.
3135
+ */
3136
+ getCacheKeyForURL(url) {
3137
+ const urlObject = new URL(url, location.href);
3138
+ return this._urlsToCacheKeys.get(urlObject.href);
3139
+ }
3140
+ /**
3141
+ * @param {string} url A cache key whose SRI you want to look up.
3142
+ * @return {string} The subresource integrity associated with the cache key,
3143
+ * or undefined if it's not set.
3144
+ */
3145
+ getIntegrityForCacheKey(cacheKey) {
3146
+ return this._cacheKeysToIntegrities.get(cacheKey);
3147
+ }
3148
+ /**
3149
+ * This acts as a drop-in replacement for
3150
+ * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)
3151
+ * with the following differences:
3152
+ *
3153
+ * - It knows what the name of the precache is, and only checks in that cache.
3154
+ * - It allows you to pass in an "original" URL without versioning parameters,
3155
+ * and it will automatically look up the correct cache key for the currently
3156
+ * active revision of that URL.
3157
+ *
3158
+ * E.g., `matchPrecache('index.html')` will find the correct precached
3159
+ * response for the currently active service worker, even if the actual cache
3160
+ * key is `'/index.html?__WB_REVISION__=1234abcd'`.
3161
+ *
3162
+ * @param {string|Request} request The key (without revisioning parameters)
3163
+ * to look up in the precache.
3164
+ * @return {Promise<Response|undefined>}
3165
+ */
3166
+ async matchPrecache(request) {
3167
+ const url = request instanceof Request ? request.url : request;
3168
+ const cacheKey = this.getCacheKeyForURL(url);
3169
+ if (cacheKey) {
3170
+ const cache = await self.caches.open(this.strategy.cacheName);
3171
+ return cache.match(cacheKey);
3172
+ }
3173
+ return undefined;
3174
+ }
3175
+ /**
3176
+ * Returns a function that looks up `url` in the precache (taking into
3177
+ * account revision information), and returns the corresponding `Response`.
3178
+ *
3179
+ * @param {string} url The precached URL which will be used to lookup the
3180
+ * `Response`.
3181
+ * @return {workbox-routing~handlerCallback}
3182
+ */
3183
+ createHandlerBoundToURL(url) {
3184
+ const cacheKey = this.getCacheKeyForURL(url);
3185
+ if (!cacheKey) {
3186
+ throw new WorkboxError('non-precached-url', {
3187
+ url
3188
+ });
3189
+ }
3190
+ return options => {
3191
+ options.request = new Request(url);
3192
+ options.params = Object.assign({
3193
+ cacheKey
3194
+ }, options.params);
3195
+ return this.strategy.handle(options);
3196
+ };
3197
+ }
3198
+ }
3199
+
3200
+ /*
3201
+ Copyright 2019 Google LLC
3202
+
3203
+ Use of this source code is governed by an MIT-style
3204
+ license that can be found in the LICENSE file or at
3205
+ https://opensource.org/licenses/MIT.
3206
+ */
3207
+ let precacheController;
3208
+ /**
3209
+ * @return {PrecacheController}
3210
+ * @private
3211
+ */
3212
+ const getOrCreatePrecacheController = () => {
3213
+ if (!precacheController) {
3214
+ precacheController = new PrecacheController();
3215
+ }
3216
+ return precacheController;
3217
+ };
3218
+
3219
+ /*
3220
+ Copyright 2018 Google LLC
3221
+
3222
+ Use of this source code is governed by an MIT-style
3223
+ license that can be found in the LICENSE file or at
3224
+ https://opensource.org/licenses/MIT.
3225
+ */
3226
+ /**
3227
+ * Removes any URL search parameters that should be ignored.
3228
+ *
3229
+ * @param {URL} urlObject The original URL.
3230
+ * @param {Array<RegExp>} ignoreURLParametersMatching RegExps to test against
3231
+ * each search parameter name. Matches mean that the search parameter should be
3232
+ * ignored.
3233
+ * @return {URL} The URL with any ignored search parameters removed.
3234
+ *
3235
+ * @private
3236
+ * @memberof workbox-precaching
3237
+ */
3238
+ function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {
3239
+ // Convert the iterable into an array at the start of the loop to make sure
3240
+ // deletion doesn't mess up iteration.
3241
+ for (const paramName of [...urlObject.searchParams.keys()]) {
3242
+ if (ignoreURLParametersMatching.some(regExp => regExp.test(paramName))) {
3243
+ urlObject.searchParams.delete(paramName);
3244
+ }
3245
+ }
3246
+ return urlObject;
3247
+ }
3248
+
3249
+ /*
3250
+ Copyright 2019 Google LLC
3251
+
3252
+ Use of this source code is governed by an MIT-style
3253
+ license that can be found in the LICENSE file or at
3254
+ https://opensource.org/licenses/MIT.
3255
+ */
3256
+ /**
3257
+ * Generator function that yields possible variations on the original URL to
3258
+ * check, one at a time.
3259
+ *
3260
+ * @param {string} url
3261
+ * @param {Object} options
3262
+ *
3263
+ * @private
3264
+ * @memberof workbox-precaching
3265
+ */
3266
+ function* generateURLVariations(url, {
3267
+ ignoreURLParametersMatching = [/^utm_/, /^fbclid$/],
3268
+ directoryIndex = 'index.html',
3269
+ cleanURLs = true,
3270
+ urlManipulation
3271
+ } = {}) {
3272
+ const urlObject = new URL(url, location.href);
3273
+ urlObject.hash = '';
3274
+ yield urlObject.href;
3275
+ const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching);
3276
+ yield urlWithoutIgnoredParams.href;
3277
+ if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) {
3278
+ const directoryURL = new URL(urlWithoutIgnoredParams.href);
3279
+ directoryURL.pathname += directoryIndex;
3280
+ yield directoryURL.href;
3281
+ }
3282
+ if (cleanURLs) {
3283
+ const cleanURL = new URL(urlWithoutIgnoredParams.href);
3284
+ cleanURL.pathname += '.html';
3285
+ yield cleanURL.href;
3286
+ }
3287
+ if (urlManipulation) {
3288
+ const additionalURLs = urlManipulation({
3289
+ url: urlObject
3290
+ });
3291
+ for (const urlToAttempt of additionalURLs) {
3292
+ yield urlToAttempt.href;
3293
+ }
3294
+ }
3295
+ }
3296
+
3297
+ /*
3298
+ Copyright 2020 Google LLC
3299
+
3300
+ Use of this source code is governed by an MIT-style
3301
+ license that can be found in the LICENSE file or at
3302
+ https://opensource.org/licenses/MIT.
3303
+ */
3304
+ /**
3305
+ * A subclass of {@link workbox-routing.Route} that takes a
3306
+ * {@link workbox-precaching.PrecacheController}
3307
+ * instance and uses it to match incoming requests and handle fetching
3308
+ * responses from the precache.
3309
+ *
3310
+ * @memberof workbox-precaching
3311
+ * @extends workbox-routing.Route
3312
+ */
3313
+ class PrecacheRoute extends Route {
3314
+ /**
3315
+ * @param {PrecacheController} precacheController A `PrecacheController`
3316
+ * instance used to both match requests and respond to fetch events.
3317
+ * @param {Object} [options] Options to control how requests are matched
3318
+ * against the list of precached URLs.
3319
+ * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will
3320
+ * check cache entries for a URLs ending with '/' to see if there is a hit when
3321
+ * appending the `directoryIndex` value.
3322
+ * @param {Array<RegExp>} [options.ignoreURLParametersMatching=[/^utm_/, /^fbclid$/]] An
3323
+ * array of regex's to remove search params when looking for a cache match.
3324
+ * @param {boolean} [options.cleanURLs=true] The `cleanURLs` option will
3325
+ * check the cache for the URL with a `.html` added to the end of the end.
3326
+ * @param {workbox-precaching~urlManipulation} [options.urlManipulation]
3327
+ * This is a function that should take a URL and return an array of
3328
+ * alternative URLs that should be checked for precache matches.
3329
+ */
3330
+ constructor(precacheController, options) {
3331
+ const match = ({
3332
+ request
3333
+ }) => {
3334
+ const urlsToCacheKeys = precacheController.getURLsToCacheKeys();
3335
+ for (const possibleURL of generateURLVariations(request.url, options)) {
3336
+ const cacheKey = urlsToCacheKeys.get(possibleURL);
3337
+ if (cacheKey) {
3338
+ const integrity = precacheController.getIntegrityForCacheKey(cacheKey);
3339
+ return {
3340
+ cacheKey,
3341
+ integrity
3342
+ };
3343
+ }
3344
+ }
3345
+ {
3346
+ logger.debug(`Precaching did not find a match for ` + getFriendlyURL(request.url));
3347
+ }
3348
+ return;
3349
+ };
3350
+ super(match, precacheController.strategy);
3351
+ }
3352
+ }
3353
+
3354
+ /*
3355
+ Copyright 2019 Google LLC
3356
+ Use of this source code is governed by an MIT-style
3357
+ license that can be found in the LICENSE file or at
3358
+ https://opensource.org/licenses/MIT.
3359
+ */
3360
+ /**
3361
+ * Add a `fetch` listener to the service worker that will
3362
+ * respond to
3363
+ * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests}
3364
+ * with precached assets.
3365
+ *
3366
+ * Requests for assets that aren't precached, the `FetchEvent` will not be
3367
+ * responded to, allowing the event to fall through to other `fetch` event
3368
+ * listeners.
3369
+ *
3370
+ * @param {Object} [options] See the {@link workbox-precaching.PrecacheRoute}
3371
+ * options.
3372
+ *
3373
+ * @memberof workbox-precaching
3374
+ */
3375
+ function addRoute(options) {
3376
+ const precacheController = getOrCreatePrecacheController();
3377
+ const precacheRoute = new PrecacheRoute(precacheController, options);
3378
+ registerRoute(precacheRoute);
3379
+ }
3380
+
3381
+ /*
3382
+ Copyright 2019 Google LLC
3383
+
3384
+ Use of this source code is governed by an MIT-style
3385
+ license that can be found in the LICENSE file or at
3386
+ https://opensource.org/licenses/MIT.
3387
+ */
3388
+ /**
3389
+ * Adds items to the precache list, removing any duplicates and
3390
+ * stores the files in the
3391
+ * {@link workbox-core.cacheNames|"precache cache"} when the service
3392
+ * worker installs.
3393
+ *
3394
+ * This method can be called multiple times.
3395
+ *
3396
+ * Please note: This method **will not** serve any of the cached files for you.
3397
+ * It only precaches files. To respond to a network request you call
3398
+ * {@link workbox-precaching.addRoute}.
3399
+ *
3400
+ * If you have a single array of files to precache, you can just call
3401
+ * {@link workbox-precaching.precacheAndRoute}.
3402
+ *
3403
+ * @param {Array<Object|string>} [entries=[]] Array of entries to precache.
3404
+ *
3405
+ * @memberof workbox-precaching
3406
+ */
3407
+ function precache(entries) {
3408
+ const precacheController = getOrCreatePrecacheController();
3409
+ precacheController.precache(entries);
3410
+ }
3411
+
3412
+ /*
3413
+ Copyright 2019 Google LLC
3414
+
3415
+ Use of this source code is governed by an MIT-style
3416
+ license that can be found in the LICENSE file or at
3417
+ https://opensource.org/licenses/MIT.
3418
+ */
3419
+ /**
3420
+ * This method will add entries to the precache list and add a route to
3421
+ * respond to fetch events.
3422
+ *
3423
+ * This is a convenience method that will call
3424
+ * {@link workbox-precaching.precache} and
3425
+ * {@link workbox-precaching.addRoute} in a single call.
3426
+ *
3427
+ * @param {Array<Object|string>} entries Array of entries to precache.
3428
+ * @param {Object} [options] See the
3429
+ * {@link workbox-precaching.PrecacheRoute} options.
3430
+ *
3431
+ * @memberof workbox-precaching
3432
+ */
3433
+ function precacheAndRoute(entries, options) {
3434
+ precache(entries);
3435
+ addRoute(options);
3436
+ }
3437
+
3438
+ /*
3439
+ Copyright 2018 Google LLC
3440
+
3441
+ Use of this source code is governed by an MIT-style
3442
+ license that can be found in the LICENSE file or at
3443
+ https://opensource.org/licenses/MIT.
3444
+ */
3445
+ const SUBSTRING_TO_FIND = '-precache-';
3446
+ /**
3447
+ * Cleans up incompatible precaches that were created by older versions of
3448
+ * Workbox, by a service worker registered under the current scope.
3449
+ *
3450
+ * This is meant to be called as part of the `activate` event.
3451
+ *
3452
+ * This should be safe to use as long as you don't include `substringToFind`
3453
+ * (defaulting to `-precache-`) in your non-precache cache names.
3454
+ *
3455
+ * @param {string} currentPrecacheName The cache name currently in use for
3456
+ * precaching. This cache won't be deleted.
3457
+ * @param {string} [substringToFind='-precache-'] Cache names which include this
3458
+ * substring will be deleted (excluding `currentPrecacheName`).
3459
+ * @return {Array<string>} A list of all the cache names that were deleted.
3460
+ *
3461
+ * @private
3462
+ * @memberof workbox-precaching
3463
+ */
3464
+ const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND) => {
3465
+ const cacheNames = await self.caches.keys();
3466
+ const cacheNamesToDelete = cacheNames.filter(cacheName => {
3467
+ return cacheName.includes(substringToFind) && cacheName.includes(self.registration.scope) && cacheName !== currentPrecacheName;
3468
+ });
3469
+ await Promise.all(cacheNamesToDelete.map(cacheName => self.caches.delete(cacheName)));
3470
+ return cacheNamesToDelete;
3471
+ };
3472
+
3473
+ /*
3474
+ Copyright 2019 Google LLC
3475
+
3476
+ Use of this source code is governed by an MIT-style
3477
+ license that can be found in the LICENSE file or at
3478
+ https://opensource.org/licenses/MIT.
3479
+ */
3480
+ /**
3481
+ * Adds an `activate` event listener which will clean up incompatible
3482
+ * precaches that were created by older versions of Workbox.
3483
+ *
3484
+ * @memberof workbox-precaching
3485
+ */
3486
+ function cleanupOutdatedCaches() {
3487
+ // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
3488
+ self.addEventListener('activate', event => {
3489
+ const cacheName = cacheNames.getPrecacheName();
3490
+ event.waitUntil(deleteOutdatedCaches(cacheName).then(cachesDeleted => {
3491
+ {
3492
+ if (cachesDeleted.length > 0) {
3493
+ logger.log(`The following out-of-date precaches were cleaned up ` + `automatically:`, cachesDeleted);
3494
+ }
3495
+ }
3496
+ }));
3497
+ });
3498
+ }
3499
+
3500
+ /*
3501
+ Copyright 2018 Google LLC
3502
+
3503
+ Use of this source code is governed by an MIT-style
3504
+ license that can be found in the LICENSE file or at
3505
+ https://opensource.org/licenses/MIT.
3506
+ */
3507
+ /**
3508
+ * NavigationRoute makes it easy to create a
3509
+ * {@link workbox-routing.Route} that matches for browser
3510
+ * [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests}.
3511
+ *
3512
+ * It will only match incoming Requests whose
3513
+ * {@link https://fetch.spec.whatwg.org/#concept-request-mode|mode}
3514
+ * is set to `navigate`.
3515
+ *
3516
+ * You can optionally only apply this route to a subset of navigation requests
3517
+ * by using one or both of the `denylist` and `allowlist` parameters.
3518
+ *
3519
+ * @memberof workbox-routing
3520
+ * @extends workbox-routing.Route
3521
+ */
3522
+ class NavigationRoute extends Route {
3523
+ /**
3524
+ * If both `denylist` and `allowlist` are provided, the `denylist` will
3525
+ * take precedence and the request will not match this route.
3526
+ *
3527
+ * The regular expressions in `allowlist` and `denylist`
3528
+ * are matched against the concatenated
3529
+ * [`pathname`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname}
3530
+ * and [`search`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search}
3531
+ * portions of the requested URL.
3532
+ *
3533
+ * *Note*: These RegExps may be evaluated against every destination URL during
3534
+ * a navigation. Avoid using
3535
+ * [complex RegExps](https://github.com/GoogleChrome/workbox/issues/3077),
3536
+ * or else your users may see delays when navigating your site.
3537
+ *
3538
+ * @param {workbox-routing~handlerCallback} handler A callback
3539
+ * function that returns a Promise resulting in a Response.
3540
+ * @param {Object} options
3541
+ * @param {Array<RegExp>} [options.denylist] If any of these patterns match,
3542
+ * the route will not handle the request (even if a allowlist RegExp matches).
3543
+ * @param {Array<RegExp>} [options.allowlist=[/./]] If any of these patterns
3544
+ * match the URL's pathname and search parameter, the route will handle the
3545
+ * request (assuming the denylist doesn't match).
3546
+ */
3547
+ constructor(handler, {
3548
+ allowlist = [/./],
3549
+ denylist = []
3550
+ } = {}) {
3551
+ {
3552
+ finalAssertExports.isArrayOfClass(allowlist, RegExp, {
3553
+ moduleName: 'workbox-routing',
3554
+ className: 'NavigationRoute',
3555
+ funcName: 'constructor',
3556
+ paramName: 'options.allowlist'
3557
+ });
3558
+ finalAssertExports.isArrayOfClass(denylist, RegExp, {
3559
+ moduleName: 'workbox-routing',
3560
+ className: 'NavigationRoute',
3561
+ funcName: 'constructor',
3562
+ paramName: 'options.denylist'
3563
+ });
3564
+ }
3565
+ super(options => this._match(options), handler);
3566
+ this._allowlist = allowlist;
3567
+ this._denylist = denylist;
3568
+ }
3569
+ /**
3570
+ * Routes match handler.
3571
+ *
3572
+ * @param {Object} options
3573
+ * @param {URL} options.url
3574
+ * @param {Request} options.request
3575
+ * @return {boolean}
3576
+ *
3577
+ * @private
3578
+ */
3579
+ _match({
3580
+ url,
3581
+ request
3582
+ }) {
3583
+ if (request && request.mode !== 'navigate') {
3584
+ return false;
3585
+ }
3586
+ const pathnameAndSearch = url.pathname + url.search;
3587
+ for (const regExp of this._denylist) {
3588
+ if (regExp.test(pathnameAndSearch)) {
3589
+ {
3590
+ logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL matches this denylist pattern: ` + `${regExp.toString()}`);
3591
+ }
3592
+ return false;
3593
+ }
3594
+ }
3595
+ if (this._allowlist.some(regExp => regExp.test(pathnameAndSearch))) {
3596
+ {
3597
+ logger.debug(`The navigation route ${pathnameAndSearch} ` + `is being used.`);
3598
+ }
3599
+ return true;
3600
+ }
3601
+ {
3602
+ logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL being navigated to doesn't ` + `match the allowlist.`);
3603
+ }
3604
+ return false;
3605
+ }
3606
+ }
3607
+
3608
+ /*
3609
+ Copyright 2019 Google LLC
3610
+
3611
+ Use of this source code is governed by an MIT-style
3612
+ license that can be found in the LICENSE file or at
3613
+ https://opensource.org/licenses/MIT.
3614
+ */
3615
+ /**
3616
+ * Helper function that calls
3617
+ * {@link PrecacheController#createHandlerBoundToURL} on the default
3618
+ * {@link PrecacheController} instance.
3619
+ *
3620
+ * If you are creating your own {@link PrecacheController}, then call the
3621
+ * {@link PrecacheController#createHandlerBoundToURL} on that instance,
3622
+ * instead of using this function.
3623
+ *
3624
+ * @param {string} url The precached URL which will be used to lookup the
3625
+ * `Response`.
3626
+ * @param {boolean} [fallbackToNetwork=true] Whether to attempt to get the
3627
+ * response from the network if there's a precache miss.
3628
+ * @return {workbox-routing~handlerCallback}
3629
+ *
3630
+ * @memberof workbox-precaching
3631
+ */
3632
+ function createHandlerBoundToURL(url) {
3633
+ const precacheController = getOrCreatePrecacheController();
3634
+ return precacheController.createHandlerBoundToURL(url);
3635
+ }
3636
+
3637
+ exports.NavigationRoute = NavigationRoute;
3638
+ exports.NetworkFirst = NetworkFirst;
3639
+ exports.cleanupOutdatedCaches = cleanupOutdatedCaches;
3640
+ exports.clientsClaim = clientsClaim;
3641
+ exports.createHandlerBoundToURL = createHandlerBoundToURL;
3642
+ exports.precacheAndRoute = precacheAndRoute;
3643
+ exports.registerRoute = registerRoute;
3644
+
3645
+ }));