UNPKG

32.3 kBJavaScriptView Raw
1this.workbox = this.workbox || {};
2this.workbox.routing = (function (exports, assert_mjs, logger_mjs, cacheNames_mjs, WorkboxError_mjs, getFriendlyURL_mjs) {
3 'use strict';
4
5 try {
6 self['workbox:routing:4.3.0'] && _();
7 } catch (e) {} // eslint-disable-line
8
9 /*
10 Copyright 2018 Google LLC
11
12 Use of this source code is governed by an MIT-style
13 license that can be found in the LICENSE file or at
14 https://opensource.org/licenses/MIT.
15 */
16 /**
17 * The default HTTP method, 'GET', used when there's no specific method
18 * configured for a route.
19 *
20 * @type {string}
21 *
22 * @private
23 */
24
25 const defaultMethod = 'GET';
26 /**
27 * The list of valid HTTP methods associated with requests that could be routed.
28 *
29 * @type {Array<string>}
30 *
31 * @private
32 */
33
34 const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'];
35
36 /*
37 Copyright 2018 Google LLC
38
39 Use of this source code is governed by an MIT-style
40 license that can be found in the LICENSE file or at
41 https://opensource.org/licenses/MIT.
42 */
43 /**
44 * @param {function()|Object} handler Either a function, or an object with a
45 * 'handle' method.
46 * @return {Object} An object with a handle method.
47 *
48 * @private
49 */
50
51 const normalizeHandler = handler => {
52 if (handler && typeof handler === 'object') {
53 {
54 assert_mjs.assert.hasMethod(handler, 'handle', {
55 moduleName: 'workbox-routing',
56 className: 'Route',
57 funcName: 'constructor',
58 paramName: 'handler'
59 });
60 }
61
62 return handler;
63 } else {
64 {
65 assert_mjs.assert.isType(handler, 'function', {
66 moduleName: 'workbox-routing',
67 className: 'Route',
68 funcName: 'constructor',
69 paramName: 'handler'
70 });
71 }
72
73 return {
74 handle: handler
75 };
76 }
77 };
78
79 /*
80 Copyright 2018 Google LLC
81
82 Use of this source code is governed by an MIT-style
83 license that can be found in the LICENSE file or at
84 https://opensource.org/licenses/MIT.
85 */
86 /**
87 * A `Route` consists of a pair of callback functions, "match" and "handler".
88 * The "match" callback determine if a route should be used to "handle" a
89 * request by returning a non-falsy value if it can. The "handler" callback
90 * is called when there is a match and should return a Promise that resolves
91 * to a `Response`.
92 *
93 * @memberof workbox.routing
94 */
95
96 class Route {
97 /**
98 * Constructor for Route class.
99 *
100 * @param {workbox.routing.Route~matchCallback} match
101 * A callback function that determines whether the route matches a given
102 * `fetch` event by returning a non-falsy value.
103 * @param {workbox.routing.Route~handlerCallback} handler A callback
104 * function that returns a Promise resolving to a Response.
105 * @param {string} [method='GET'] The HTTP method to match the Route
106 * against.
107 */
108 constructor(match, handler, method) {
109 {
110 assert_mjs.assert.isType(match, 'function', {
111 moduleName: 'workbox-routing',
112 className: 'Route',
113 funcName: 'constructor',
114 paramName: 'match'
115 });
116
117 if (method) {
118 assert_mjs.assert.isOneOf(method, validMethods, {
119 paramName: 'method'
120 });
121 }
122 } // These values are referenced directly by Router so cannot be
123 // altered by minifification.
124
125
126 this.handler = normalizeHandler(handler);
127 this.match = match;
128 this.method = method || defaultMethod;
129 }
130
131 }
132
133 /*
134 Copyright 2018 Google LLC
135
136 Use of this source code is governed by an MIT-style
137 license that can be found in the LICENSE file or at
138 https://opensource.org/licenses/MIT.
139 */
140 /**
141 * NavigationRoute makes it easy to create a [Route]{@link
142 * workbox.routing.Route} that matches for browser
143 * [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests}.
144 *
145 * It will only match incoming Requests whose
146 * [`mode`]{@link https://fetch.spec.whatwg.org/#concept-request-mode}
147 * is set to `navigate`.
148 *
149 * You can optionally only apply this route to a subset of navigation requests
150 * by using one or both of the `blacklist` and `whitelist` parameters.
151 *
152 * @memberof workbox.routing
153 * @extends workbox.routing.Route
154 */
155
156 class NavigationRoute extends Route {
157 /**
158 * If both `blacklist` and `whiltelist` are provided, the `blacklist` will
159 * take precedence and the request will not match this route.
160 *
161 * The regular expressions in `whitelist` and `blacklist`
162 * are matched against the concatenated
163 * [`pathname`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname}
164 * and [`search`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search}
165 * portions of the requested URL.
166 *
167 * @param {workbox.routing.Route~handlerCallback} handler A callback
168 * function that returns a Promise resulting in a Response.
169 * @param {Object} options
170 * @param {Array<RegExp>} [options.blacklist] If any of these patterns match,
171 * the route will not handle the request (even if a whitelist RegExp matches).
172 * @param {Array<RegExp>} [options.whitelist=[/./]] If any of these patterns
173 * match the URL's pathname and search parameter, the route will handle the
174 * request (assuming the blacklist doesn't match).
175 */
176 constructor(handler, {
177 whitelist = [/./],
178 blacklist = []
179 } = {}) {
180 {
181 assert_mjs.assert.isArrayOfClass(whitelist, RegExp, {
182 moduleName: 'workbox-routing',
183 className: 'NavigationRoute',
184 funcName: 'constructor',
185 paramName: 'options.whitelist'
186 });
187 assert_mjs.assert.isArrayOfClass(blacklist, RegExp, {
188 moduleName: 'workbox-routing',
189 className: 'NavigationRoute',
190 funcName: 'constructor',
191 paramName: 'options.blacklist'
192 });
193 }
194
195 super(options => this._match(options), handler);
196 this._whitelist = whitelist;
197 this._blacklist = blacklist;
198 }
199 /**
200 * Routes match handler.
201 *
202 * @param {Object} options
203 * @param {URL} options.url
204 * @param {Request} options.request
205 * @return {boolean}
206 *
207 * @private
208 */
209
210
211 _match({
212 url,
213 request
214 }) {
215 if (request.mode !== 'navigate') {
216 return false;
217 }
218
219 const pathnameAndSearch = url.pathname + url.search;
220
221 for (const regExp of this._blacklist) {
222 if (regExp.test(pathnameAndSearch)) {
223 {
224 logger_mjs.logger.log(`The navigation route is not being used, since the ` + `URL matches this blacklist pattern: ${regExp}`);
225 }
226
227 return false;
228 }
229 }
230
231 if (this._whitelist.some(regExp => regExp.test(pathnameAndSearch))) {
232 {
233 logger_mjs.logger.debug(`The navigation route is being used.`);
234 }
235
236 return true;
237 }
238
239 {
240 logger_mjs.logger.log(`The navigation route is not being used, since the URL ` + `being navigated to doesn't match the whitelist.`);
241 }
242
243 return false;
244 }
245
246 }
247
248 /*
249 Copyright 2018 Google LLC
250
251 Use of this source code is governed by an MIT-style
252 license that can be found in the LICENSE file or at
253 https://opensource.org/licenses/MIT.
254 */
255 /**
256 * RegExpRoute makes it easy to create a regular expression based
257 * [Route]{@link workbox.routing.Route}.
258 *
259 * For same-origin requests the RegExp only needs to match part of the URL. For
260 * requests against third-party servers, you must define a RegExp that matches
261 * the start of the URL.
262 *
263 * [See the module docs for info.]{@link https://developers.google.com/web/tools/workbox/modules/workbox-routing}
264 *
265 * @memberof workbox.routing
266 * @extends workbox.routing.Route
267 */
268
269 class RegExpRoute extends Route {
270 /**
271 * If the regulard expression contains
272 * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},
273 * th ecaptured values will be passed to the
274 * [handler's]{@link workbox.routing.Route~handlerCallback} `params`
275 * argument.
276 *
277 * @param {RegExp} regExp The regular expression to match against URLs.
278 * @param {workbox.routing.Route~handlerCallback} handler A callback
279 * function that returns a Promise resulting in a Response.
280 * @param {string} [method='GET'] The HTTP method to match the Route
281 * against.
282 */
283 constructor(regExp, handler, method) {
284 {
285 assert_mjs.assert.isInstance(regExp, RegExp, {
286 moduleName: 'workbox-routing',
287 className: 'RegExpRoute',
288 funcName: 'constructor',
289 paramName: 'pattern'
290 });
291 }
292
293 const match = ({
294 url
295 }) => {
296 const result = regExp.exec(url.href); // Return null immediately if there's no match.
297
298 if (!result) {
299 return null;
300 } // Require that the match start at the first character in the URL string
301 // if it's a cross-origin request.
302 // See https://github.com/GoogleChrome/workbox/issues/281 for the context
303 // behind this behavior.
304
305
306 if (url.origin !== location.origin && result.index !== 0) {
307 {
308 logger_mjs.logger.debug(`The regular expression '${regExp}' only partially matched ` + `against the cross-origin URL '${url}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`);
309 }
310
311 return null;
312 } // If the route matches, but there aren't any capture groups defined, then
313 // this will return [], which is truthy and therefore sufficient to
314 // indicate a match.
315 // If there are capture groups, then it will return their values.
316
317
318 return result.slice(1);
319 };
320
321 super(match, handler, method);
322 }
323
324 }
325
326 /*
327 Copyright 2018 Google LLC
328
329 Use of this source code is governed by an MIT-style
330 license that can be found in the LICENSE file or at
331 https://opensource.org/licenses/MIT.
332 */
333 /**
334 * The Router can be used to process a FetchEvent through one or more
335 * [Routes]{@link workbox.routing.Route} responding with a Request if
336 * a matching route exists.
337 *
338 * If no route matches a given a request, the Router will use a "default"
339 * handler if one is defined.
340 *
341 * Should the matching Route throw an error, the Router will use a "catch"
342 * handler if one is defined to gracefully deal with issues and respond with a
343 * Request.
344 *
345 * If a request matches multiple routes, the **earliest** registered route will
346 * be used to respond to the request.
347 *
348 * @memberof workbox.routing
349 */
350
351 class Router {
352 /**
353 * Initializes a new Router.
354 */
355 constructor() {
356 this._routes = new Map();
357 }
358 /**
359 * @return {Map<string, Array<workbox.routing.Route>>} routes A `Map` of HTTP
360 * method name ('GET', etc.) to an array of all the corresponding `Route`
361 * instances that are registered.
362 */
363
364
365 get routes() {
366 return this._routes;
367 }
368 /**
369 * Adds a fetch event listener to respond to events when a route matches
370 * the event's request.
371 */
372
373
374 addFetchListener() {
375 self.addEventListener('fetch', event => {
376 const {
377 request
378 } = event;
379 const responsePromise = this.handleRequest({
380 request,
381 event
382 });
383
384 if (responsePromise) {
385 event.respondWith(responsePromise);
386 }
387 });
388 }
389 /**
390 * Adds a message event listener for URLs to cache from the window.
391 * This is useful to cache resources loaded on the page prior to when the
392 * service worker started controlling it.
393 *
394 * The format of the message data sent from the window should be as follows.
395 * Where the `urlsToCache` array may consist of URL strings or an array of
396 * URL string + `requestInit` object (the same as you'd pass to `fetch()`).
397 *
398 * ```
399 * {
400 * type: 'CACHE_URLS',
401 * payload: {
402 * urlsToCache: [
403 * './script1.js',
404 * './script2.js',
405 * ['./script3.js', {mode: 'no-cors'}],
406 * ],
407 * },
408 * }
409 * ```
410 */
411
412
413 addCacheListener() {
414 self.addEventListener('message', async event => {
415 if (event.data && event.data.type === 'CACHE_URLS') {
416 const {
417 payload
418 } = event.data;
419
420 {
421 logger_mjs.logger.debug(`Caching URLs from the window`, payload.urlsToCache);
422 }
423
424 const requestPromises = Promise.all(payload.urlsToCache.map(entry => {
425 if (typeof entry === 'string') {
426 entry = [entry];
427 }
428
429 const request = new Request(...entry);
430 return this.handleRequest({
431 request
432 });
433 }));
434 event.waitUntil(requestPromises); // If a MessageChannel was used, reply to the message on success.
435
436 if (event.ports && event.ports[0]) {
437 await requestPromises;
438 event.ports[0].postMessage(true);
439 }
440 }
441 });
442 }
443 /**
444 * Apply the routing rules to a FetchEvent object to get a Response from an
445 * appropriate Route's handler.
446 *
447 * @param {Object} options
448 * @param {Request} options.request The request to handle (this is usually
449 * from a fetch event, but it does not have to be).
450 * @param {FetchEvent} [options.event] The event that triggered the request,
451 * if applicable.
452 * @return {Promise<Response>|undefined} A promise is returned if a
453 * registered route can handle the request. If there is no matching
454 * route and there's no `defaultHandler`, `undefined` is returned.
455 */
456
457
458 handleRequest({
459 request,
460 event
461 }) {
462 {
463 assert_mjs.assert.isInstance(request, Request, {
464 moduleName: 'workbox-routing',
465 className: 'Router',
466 funcName: 'handleRequest',
467 paramName: 'options.request'
468 });
469 }
470
471 const url = new URL(request.url, location);
472
473 if (!url.protocol.startsWith('http')) {
474 {
475 logger_mjs.logger.debug(`Workbox Router only supports URLs that start with 'http'.`);
476 }
477
478 return;
479 }
480
481 let {
482 params,
483 route
484 } = this.findMatchingRoute({
485 url,
486 request,
487 event
488 });
489 let handler = route && route.handler;
490 let debugMessages = [];
491
492 {
493 if (handler) {
494 debugMessages.push([`Found a route to handle this request:`, route]);
495
496 if (params) {
497 debugMessages.push([`Passing the following params to the route's handler:`, params]);
498 }
499 }
500 } // If we don't have a handler because there was no matching route, then
501 // fall back to defaultHandler if that's defined.
502
503
504 if (!handler && this._defaultHandler) {
505 {
506 debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler.`); // This is used for debugging in logs in the case of an error.
507
508 route = '[Default Handler]';
509 }
510
511 handler = this._defaultHandler;
512 }
513
514 if (!handler) {
515 {
516 // No handler so Workbox will do nothing. If logs is set of debug
517 // i.e. verbose, we should print out this information.
518 logger_mjs.logger.debug(`No route found for: ${getFriendlyURL_mjs.getFriendlyURL(url)}`);
519 }
520
521 return;
522 }
523
524 {
525 // We have a handler, meaning Workbox is going to handle the route.
526 // print the routing details to the console.
527 logger_mjs.logger.groupCollapsed(`Router is responding to: ${getFriendlyURL_mjs.getFriendlyURL(url)}`);
528 debugMessages.forEach(msg => {
529 if (Array.isArray(msg)) {
530 logger_mjs.logger.log(...msg);
531 } else {
532 logger_mjs.logger.log(msg);
533 }
534 }); // The Request and Response objects contains a great deal of information,
535 // hide it under a group in case developers want to see it.
536
537 logger_mjs.logger.groupCollapsed(`View request details here.`);
538 logger_mjs.logger.log(request);
539 logger_mjs.logger.groupEnd();
540 logger_mjs.logger.groupEnd();
541 } // Wrap in try and catch in case the handle method throws a synchronous
542 // error. It should still callback to the catch handler.
543
544
545 let responsePromise;
546
547 try {
548 responsePromise = handler.handle({
549 url,
550 request,
551 event,
552 params
553 });
554 } catch (err) {
555 responsePromise = Promise.reject(err);
556 }
557
558 if (responsePromise && this._catchHandler) {
559 responsePromise = responsePromise.catch(err => {
560 {
561 // Still include URL here as it will be async from the console group
562 // and may not make sense without the URL
563 logger_mjs.logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL_mjs.getFriendlyURL(url)}. Falling back to Catch Handler.`);
564 logger_mjs.logger.error(`Error thrown by:`, route);
565 logger_mjs.logger.error(err);
566 logger_mjs.logger.groupEnd();
567 }
568
569 return this._catchHandler.handle({
570 url,
571 event,
572 err
573 });
574 });
575 }
576
577 return responsePromise;
578 }
579 /**
580 * Checks a request and URL (and optionally an event) against the list of
581 * registered routes, and if there's a match, returns the corresponding
582 * route along with any params generated by the match.
583 *
584 * @param {Object} options
585 * @param {URL} options.url
586 * @param {Request} options.request The request to match.
587 * @param {FetchEvent} [options.event] The corresponding event (unless N/A).
588 * @return {Object} An object with `route` and `params` properties.
589 * They are populated if a matching route was found or `undefined`
590 * otherwise.
591 */
592
593
594 findMatchingRoute({
595 url,
596 request,
597 event
598 }) {
599 {
600 assert_mjs.assert.isInstance(url, URL, {
601 moduleName: 'workbox-routing',
602 className: 'Router',
603 funcName: 'findMatchingRoute',
604 paramName: 'options.url'
605 });
606 assert_mjs.assert.isInstance(request, Request, {
607 moduleName: 'workbox-routing',
608 className: 'Router',
609 funcName: 'findMatchingRoute',
610 paramName: 'options.request'
611 });
612 }
613
614 const routes = this._routes.get(request.method) || [];
615
616 for (const route of routes) {
617 let params;
618 let matchResult = route.match({
619 url,
620 request,
621 event
622 });
623
624 if (matchResult) {
625 if (Array.isArray(matchResult) && matchResult.length > 0) {
626 // Instead of passing an empty array in as params, use undefined.
627 params = matchResult;
628 } else if (matchResult.constructor === Object && Object.keys(matchResult).length > 0) {
629 // Instead of passing an empty object in as params, use undefined.
630 params = matchResult;
631 } // Return early if have a match.
632
633
634 return {
635 route,
636 params
637 };
638 }
639 } // If no match was found above, return and empty object.
640
641
642 return {};
643 }
644 /**
645 * Define a default `handler` that's called when no routes explicitly
646 * match the incoming request.
647 *
648 * Without a default handler, unmatched requests will go against the
649 * network as if there were no service worker present.
650 *
651 * @param {workbox.routing.Route~handlerCallback} handler A callback
652 * function that returns a Promise resulting in a Response.
653 */
654
655
656 setDefaultHandler(handler) {
657 this._defaultHandler = normalizeHandler(handler);
658 }
659 /**
660 * If a Route throws an error while handling a request, this `handler`
661 * will be called and given a chance to provide a response.
662 *
663 * @param {workbox.routing.Route~handlerCallback} handler A callback
664 * function that returns a Promise resulting in a Response.
665 */
666
667
668 setCatchHandler(handler) {
669 this._catchHandler = normalizeHandler(handler);
670 }
671 /**
672 * Registers a route with the router.
673 *
674 * @param {workbox.routing.Route} route The route to register.
675 */
676
677
678 registerRoute(route) {
679 {
680 assert_mjs.assert.isType(route, 'object', {
681 moduleName: 'workbox-routing',
682 className: 'Router',
683 funcName: 'registerRoute',
684 paramName: 'route'
685 });
686 assert_mjs.assert.hasMethod(route, 'match', {
687 moduleName: 'workbox-routing',
688 className: 'Router',
689 funcName: 'registerRoute',
690 paramName: 'route'
691 });
692 assert_mjs.assert.isType(route.handler, 'object', {
693 moduleName: 'workbox-routing',
694 className: 'Router',
695 funcName: 'registerRoute',
696 paramName: 'route'
697 });
698 assert_mjs.assert.hasMethod(route.handler, 'handle', {
699 moduleName: 'workbox-routing',
700 className: 'Router',
701 funcName: 'registerRoute',
702 paramName: 'route.handler'
703 });
704 assert_mjs.assert.isType(route.method, 'string', {
705 moduleName: 'workbox-routing',
706 className: 'Router',
707 funcName: 'registerRoute',
708 paramName: 'route.method'
709 });
710 }
711
712 if (!this._routes.has(route.method)) {
713 this._routes.set(route.method, []);
714 } // Give precedence to all of the earlier routes by adding this additional
715 // route to the end of the array.
716
717
718 this._routes.get(route.method).push(route);
719 }
720 /**
721 * Unregisters a route with the router.
722 *
723 * @param {workbox.routing.Route} route The route to unregister.
724 */
725
726
727 unregisterRoute(route) {
728 if (!this._routes.has(route.method)) {
729 throw new WorkboxError_mjs.WorkboxError('unregister-route-but-not-found-with-method', {
730 method: route.method
731 });
732 }
733
734 const routeIndex = this._routes.get(route.method).indexOf(route);
735
736 if (routeIndex > -1) {
737 this._routes.get(route.method).splice(routeIndex, 1);
738 } else {
739 throw new WorkboxError_mjs.WorkboxError('unregister-route-route-not-registered');
740 }
741 }
742
743 }
744
745 /*
746 Copyright 2019 Google LLC
747
748 Use of this source code is governed by an MIT-style
749 license that can be found in the LICENSE file or at
750 https://opensource.org/licenses/MIT.
751 */
752 let defaultRouter;
753 /**
754 * Creates a new, singleton Router instance if one does not exist. If one
755 * does already exist, that instance is returned.
756 *
757 * @private
758 * @return {Router}
759 */
760
761 const getOrCreateDefaultRouter = () => {
762 if (!defaultRouter) {
763 defaultRouter = new Router(); // The helpers that use the default Router assume these listeners exist.
764
765 defaultRouter.addFetchListener();
766 defaultRouter.addCacheListener();
767 }
768
769 return defaultRouter;
770 };
771
772 /*
773 Copyright 2019 Google LLC
774
775 Use of this source code is governed by an MIT-style
776 license that can be found in the LICENSE file or at
777 https://opensource.org/licenses/MIT.
778 */
779 /**
780 * Registers a route that will return a precached file for a navigation
781 * request. This is useful for the
782 * [application shell pattern]{@link https://developers.google.com/web/fundamentals/architecture/app-shell}.
783 *
784 * When determining the URL of the precached HTML document, you will likely need
785 * to call `workbox.precaching.getCacheKeyForURL(originalUrl)`, to account for
786 * the fact that Workbox's precaching naming conventions often results in URL
787 * cache keys that contain extra revisioning info.
788 *
789 * This method will generate a
790 * [NavigationRoute]{@link workbox.routing.NavigationRoute}
791 * and call
792 * [Router.registerRoute()]{@link workbox.routing.Router#registerRoute} on a
793 * singleton Router instance.
794 *
795 * @param {string} cachedAssetUrl The cache key to use for the HTML file.
796 * @param {Object} [options]
797 * @param {string} [options.cacheName] Cache name to store and retrieve
798 * requests. Defaults to precache cache name provided by
799 * [workbox-core.cacheNames]{@link workbox.core.cacheNames}.
800 * @param {Array<RegExp>} [options.blacklist=[]] If any of these patterns
801 * match, the route will not handle the request (even if a whitelist entry
802 * matches).
803 * @param {Array<RegExp>} [options.whitelist=[/./]] If any of these patterns
804 * match the URL's pathname and search parameter, the route will handle the
805 * request (assuming the blacklist doesn't match).
806 * @return {workbox.routing.NavigationRoute} Returns the generated
807 * Route.
808 *
809 * @alias workbox.routing.registerNavigationRoute
810 */
811
812 const registerNavigationRoute = (cachedAssetUrl, options = {}) => {
813 {
814 assert_mjs.assert.isType(cachedAssetUrl, 'string', {
815 moduleName: 'workbox-routing',
816 funcName: 'registerNavigationRoute',
817 paramName: 'cachedAssetUrl'
818 });
819 }
820
821 const cacheName = cacheNames_mjs.cacheNames.getPrecacheName(options.cacheName);
822
823 const handler = async () => {
824 try {
825 const response = await caches.match(cachedAssetUrl, {
826 cacheName
827 });
828
829 if (response) {
830 return response;
831 } // This shouldn't normally happen, but there are edge cases:
832 // https://github.com/GoogleChrome/workbox/issues/1441
833
834
835 throw new Error(`The cache ${cacheName} did not have an entry for ` + `${cachedAssetUrl}.`);
836 } catch (error) {
837 // If there's either a cache miss, or the caches.match() call threw
838 // an exception, then attempt to fulfill the navigation request with
839 // a response from the network rather than leaving the user with a
840 // failed navigation.
841 {
842 logger_mjs.logger.debug(`Unable to respond to navigation request with ` + `cached response. Falling back to network.`, error);
843 } // This might still fail if the browser is offline...
844
845
846 return fetch(cachedAssetUrl);
847 }
848 };
849
850 const route = new NavigationRoute(handler, {
851 whitelist: options.whitelist,
852 blacklist: options.blacklist
853 });
854 const defaultRouter = getOrCreateDefaultRouter();
855 defaultRouter.registerRoute(route);
856 return route;
857 };
858
859 /*
860 Copyright 2019 Google LLC
861
862 Use of this source code is governed by an MIT-style
863 license that can be found in the LICENSE file or at
864 https://opensource.org/licenses/MIT.
865 */
866 /**
867 * Easily register a RegExp, string, or function with a caching
868 * strategy to a singleton Router instance.
869 *
870 * This method will generate a Route for you if needed and
871 * call [Router.registerRoute()]{@link
872 * workbox.routing.Router#registerRoute}.
873 *
874 * @param {
875 * RegExp|
876 * string|
877 * workbox.routing.Route~matchCallback|
878 * workbox.routing.Route
879 * } capture
880 * If the capture param is a `Route`, all other arguments will be ignored.
881 * @param {workbox.routing.Route~handlerCallback} handler A callback
882 * function that returns a Promise resulting in a Response.
883 * @param {string} [method='GET'] The HTTP method to match the Route
884 * against.
885 * @return {workbox.routing.Route} The generated `Route`(Useful for
886 * unregistering).
887 *
888 * @alias workbox.routing.registerRoute
889 */
890
891 const registerRoute = (capture, handler, method = 'GET') => {
892 let route;
893
894 if (typeof capture === 'string') {
895 const captureUrl = new URL(capture, location);
896
897 {
898 if (!(capture.startsWith('/') || capture.startsWith('http'))) {
899 throw new WorkboxError_mjs.WorkboxError('invalid-string', {
900 moduleName: 'workbox-routing',
901 funcName: 'registerRoute',
902 paramName: 'capture'
903 });
904 } // We want to check if Express-style wildcards are in the pathname only.
905 // TODO: Remove this log message in v4.
906
907
908 const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; // See https://github.com/pillarjs/path-to-regexp#parameters
909
910 const wildcards = '[*:?+]';
911
912 if (valueToCheck.match(new RegExp(`${wildcards}`))) {
913 logger_mjs.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.`);
914 }
915 }
916
917 const matchCallback = ({
918 url
919 }) => {
920 {
921 if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
922 logger_mjs.logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url}. This route will only handle cross-origin requests ` + `if they match the entire URL.`);
923 }
924 }
925
926 return url.href === captureUrl.href;
927 };
928
929 route = new Route(matchCallback, handler, method);
930 } else if (capture instanceof RegExp) {
931 route = new RegExpRoute(capture, handler, method);
932 } else if (typeof capture === 'function') {
933 route = new Route(capture, handler, method);
934 } else if (capture instanceof Route) {
935 route = capture;
936 } else {
937 throw new WorkboxError_mjs.WorkboxError('unsupported-route-type', {
938 moduleName: 'workbox-routing',
939 funcName: 'registerRoute',
940 paramName: 'capture'
941 });
942 }
943
944 const defaultRouter = getOrCreateDefaultRouter();
945 defaultRouter.registerRoute(route);
946 return route;
947 };
948
949 /*
950 Copyright 2019 Google LLC
951
952 Use of this source code is governed by an MIT-style
953 license that can be found in the LICENSE file or at
954 https://opensource.org/licenses/MIT.
955 */
956 /**
957 * If a Route throws an error while handling a request, this `handler`
958 * will be called and given a chance to provide a response.
959 *
960 * @param {workbox.routing.Route~handlerCallback} handler A callback
961 * function that returns a Promise resulting in a Response.
962 *
963 * @alias workbox.routing.setCatchHandler
964 */
965
966 const setCatchHandler = handler => {
967 const defaultRouter = getOrCreateDefaultRouter();
968 defaultRouter.setCatchHandler(handler);
969 };
970
971 /*
972 Copyright 2019 Google LLC
973
974 Use of this source code is governed by an MIT-style
975 license that can be found in the LICENSE file or at
976 https://opensource.org/licenses/MIT.
977 */
978 /**
979 * Define a default `handler` that's called when no routes explicitly
980 * match the incoming request.
981 *
982 * Without a default handler, unmatched requests will go against the
983 * network as if there were no service worker present.
984 *
985 * @param {workbox.routing.Route~handlerCallback} handler A callback
986 * function that returns a Promise resulting in a Response.
987 *
988 * @alias workbox.routing.setDefaultHandler
989 */
990
991 const setDefaultHandler = handler => {
992 const defaultRouter = getOrCreateDefaultRouter();
993 defaultRouter.setDefaultHandler(handler);
994 };
995
996 /*
997 Copyright 2018 Google LLC
998
999 Use of this source code is governed by an MIT-style
1000 license that can be found in the LICENSE file or at
1001 https://opensource.org/licenses/MIT.
1002 */
1003
1004 {
1005 assert_mjs.assert.isSWEnv('workbox-routing');
1006 }
1007
1008 exports.NavigationRoute = NavigationRoute;
1009 exports.RegExpRoute = RegExpRoute;
1010 exports.registerNavigationRoute = registerNavigationRoute;
1011 exports.registerRoute = registerRoute;
1012 exports.Route = Route;
1013 exports.Router = Router;
1014 exports.setCatchHandler = setCatchHandler;
1015 exports.setDefaultHandler = setDefaultHandler;
1016
1017 return exports;
1018
1019}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
1020