@serwist/precaching 9.0.0-preview.0 → 9.0.0-preview.10

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.
package/dist/index.js CHANGED
@@ -3,15 +3,33 @@ import { copyResponse } from '@serwist/core';
3
3
  import { Strategy } from '@serwist/strategies';
4
4
  import { Route, registerRoute } from '@serwist/routing';
5
5
 
6
- /**
7
- * A `@serwist/strategies.Strategy` implementation
8
- * specifically designed to work with
9
- * `@serwist/precaching.PrecacheController`
10
- * to both cache and fetch precached assets.
11
- *
12
- * Note: an instance of this class is created automatically when creating a
13
- * `PrecacheController`; it's generally not necessary to create this yourself.
14
- */ class PrecacheStrategy extends Strategy {
6
+ const parallel = async (limit, array, func)=>{
7
+ const work = array.map((item, index)=>({
8
+ index,
9
+ item
10
+ }));
11
+ const processor = async (res)=>{
12
+ const results = [];
13
+ while(true){
14
+ const next = work.pop();
15
+ if (!next) {
16
+ return res(results);
17
+ }
18
+ const result = await func(next.item);
19
+ results.push({
20
+ result: result,
21
+ index: next.index
22
+ });
23
+ }
24
+ };
25
+ const queues = Array.from({
26
+ length: limit
27
+ }, ()=>new Promise(processor));
28
+ const results = (await Promise.all(queues)).flat().sort((a, b)=>a.index < b.index ? -1 : 1).map((res)=>res.result);
29
+ return results;
30
+ };
31
+
32
+ class PrecacheStrategy extends Strategy {
15
33
  _fallbackToNetwork;
16
34
  static defaultPrecacheCacheabilityPlugin = {
17
35
  async cacheWillUpdate ({ response }) {
@@ -26,41 +44,25 @@ import { Route, registerRoute } from '@serwist/routing';
26
44
  return response.redirected ? await copyResponse(response) : response;
27
45
  }
28
46
  };
29
- /**
30
- * @param options
31
- */ constructor(options = {}){
47
+ constructor(options = {}){
32
48
  options.cacheName = privateCacheNames.getPrecacheName(options.cacheName);
33
49
  super(options);
34
50
  this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true;
35
- // Redirected responses cannot be used to satisfy a navigation request, so
36
- // any redirected response must be "copied" rather than cloned, so the new
37
- // response doesn't contain the `redirected` flag. See:
38
- // https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1
39
51
  this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);
40
52
  }
41
- /**
42
- * @private
43
- * @param request A request to run this strategy for.
44
- * @param handler The event that triggered the request.
45
- * @returns
46
- */ async _handle(request, handler) {
53
+ async _handle(request, handler) {
47
54
  const response = await handler.cacheMatch(request);
48
55
  if (response) {
49
56
  return response;
50
57
  }
51
- // If this is an `install` event for an entry that isn't already cached,
52
- // then populate the cache.
53
58
  if (handler.event && handler.event.type === "install") {
54
59
  return await this._handleInstall(request, handler);
55
60
  }
56
- // Getting here means something went wrong. An entry that should have been
57
- // precached wasn't found in the cache.
58
61
  return await this._handleFetch(request, handler);
59
62
  }
60
63
  async _handleFetch(request, handler) {
61
64
  let response = undefined;
62
65
  const params = handler.params || {};
63
- // Fallback to the network if we're configured to do so.
64
66
  if (this._fallbackToNetwork) {
65
67
  if (process.env.NODE_ENV !== "production") {
66
68
  logger.warn(`The precached response for ${getFriendlyURL(request.url)} in ${this.cacheName} was not found. Falling back to the network.`);
@@ -68,18 +70,9 @@ import { Route, registerRoute } from '@serwist/routing';
68
70
  const integrityInManifest = params.integrity;
69
71
  const integrityInRequest = request.integrity;
70
72
  const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest;
71
- // Do not add integrity if the original request is no-cors
72
- // See https://github.com/GoogleChrome/workbox/issues/3096
73
73
  response = await handler.fetch(new Request(request, {
74
74
  integrity: request.mode !== "no-cors" ? integrityInRequest || integrityInManifest : undefined
75
75
  }));
76
- // It's only "safe" to repair the cache if we're using SRI to guarantee
77
- // that the response matches the precache manifest's expectations,
78
- // and there's either a) no integrity property in the incoming request
79
- // or b) there is an integrity, and it matches the precache manifest.
80
- // See https://github.com/GoogleChrome/workbox/issues/2858
81
- // Also if the original request users no-cors we don't use integrity.
82
- // See https://github.com/GoogleChrome/workbox/issues/3096
83
76
  if (integrityInManifest && noIntegrityConflict && request.mode !== "no-cors") {
84
77
  this._useDefaultCacheabilityPluginIfNeeded();
85
78
  const wasCached = await handler.cachePut(request, response.clone());
@@ -90,8 +83,6 @@ import { Route, registerRoute } from '@serwist/routing';
90
83
  }
91
84
  }
92
85
  } else {
93
- // This shouldn't normally happen, but there are edge cases:
94
- // https://github.com/GoogleChrome/workbox/issues/1441
95
86
  throw new SerwistError("missing-precache-entry", {
96
87
  cacheName: this.cacheName,
97
88
  url: request.url
@@ -99,8 +90,6 @@ import { Route, registerRoute } from '@serwist/routing';
99
90
  }
100
91
  if (process.env.NODE_ENV !== "production") {
101
92
  const cacheKey = params.cacheKey || await handler.getCacheKey(request, "read");
102
- // Serwist is going to handle the route.
103
- // print the routing details to the console.
104
93
  logger.groupCollapsed(`Precaching is responding to: ${getFriendlyURL(request.url)}`);
105
94
  logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`);
106
95
  logger.groupCollapsed("View request details here.");
@@ -116,12 +105,8 @@ import { Route, registerRoute } from '@serwist/routing';
116
105
  async _handleInstall(request, handler) {
117
106
  this._useDefaultCacheabilityPluginIfNeeded();
118
107
  const response = await handler.fetch(request);
119
- // Make sure we defer cachePut() until after we know the response
120
- // should be cached; see https://github.com/GoogleChrome/workbox/issues/2737
121
108
  const wasCached = await handler.cachePut(request, response.clone());
122
109
  if (!wasCached) {
123
- // Throwing here will lead to the `install` handler failing, which
124
- // we want to do if *any* of the responses aren't safe to cache.
125
110
  throw new SerwistError("bad-precaching-response", {
126
111
  url: request.url,
127
112
  status: response.status
@@ -129,41 +114,13 @@ import { Route, registerRoute } from '@serwist/routing';
129
114
  }
130
115
  return response;
131
116
  }
132
- /**
133
- * This method is complex, as there a number of things to account for:
134
- *
135
- * The `plugins` array can be set at construction, and/or it might be added to
136
- * to at any time before the strategy is used.
137
- *
138
- * At the time the strategy is used (i.e. during an `install` event), there
139
- * needs to be at least one plugin that implements `cacheWillUpdate` in the
140
- * array, other than `copyRedirectedCacheableResponsesPlugin`.
141
- *
142
- * - If this method is called and there are no suitable `cacheWillUpdate`
143
- * plugins, we need to add `defaultPrecacheCacheabilityPlugin`.
144
- *
145
- * - If this method is called and there is exactly one `cacheWillUpdate`, then
146
- * we don't have to do anything (this might be a previously added
147
- * `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin).
148
- *
149
- * - If this method is called and there is more than one `cacheWillUpdate`,
150
- * then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so,
151
- * we need to remove it. (This situation is unlikely, but it could happen if
152
- * the strategy is used multiple times, the first without a `cacheWillUpdate`,
153
- * and then later on after manually adding a custom `cacheWillUpdate`.)
154
- *
155
- * See https://github.com/GoogleChrome/workbox/issues/2737 for more context.
156
- *
157
- * @private
158
- */ _useDefaultCacheabilityPluginIfNeeded() {
117
+ _useDefaultCacheabilityPluginIfNeeded() {
159
118
  let defaultPluginIndex = null;
160
119
  let cacheWillUpdatePluginCount = 0;
161
120
  for (const [index, plugin] of this.plugins.entries()){
162
- // Ignore the copy redirected plugin when determining what to do.
163
121
  if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) {
164
122
  continue;
165
123
  }
166
- // Save the default plugin's index, in case it needs to be removed.
167
124
  if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
168
125
  defaultPluginIndex = index;
169
126
  }
@@ -174,54 +131,28 @@ import { Route, registerRoute } from '@serwist/routing';
174
131
  if (cacheWillUpdatePluginCount === 0) {
175
132
  this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);
176
133
  } else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {
177
- // Only remove the default plugin; multiple custom plugins are allowed.
178
134
  this.plugins.splice(defaultPluginIndex, 1);
179
135
  }
180
- // Nothing needs to be done if cacheWillUpdatePluginCount is 1
181
136
  }
182
137
  }
183
138
 
184
- /*
185
- Copyright 2020 Google LLC
186
-
187
- Use of this source code is governed by an MIT-style
188
- license that can be found in the LICENSE file or at
189
- https://opensource.org/licenses/MIT.
190
- */ /**
191
- * A plugin, designed to be used with PrecacheController, to translate URLs into
192
- * the corresponding cache key, based on the current revision info.
193
- *
194
- * @private
195
- */ class PrecacheCacheKeyPlugin {
139
+ class PrecacheCacheKeyPlugin {
196
140
  _precacheController;
197
141
  constructor({ precacheController }){
198
142
  this._precacheController = precacheController;
199
143
  }
200
144
  cacheKeyWillBeUsed = async ({ request, params })=>{
201
- // Params is type any, can't change right now.
202
- /* eslint-disable */ const cacheKey = params?.cacheKey || this._precacheController.getCacheKeyForURL(request.url);
203
- /* eslint-enable */ return cacheKey ? new Request(cacheKey, {
145
+ const cacheKey = params?.cacheKey || this._precacheController.getCacheKeyForURL(request.url);
146
+ return cacheKey ? new Request(cacheKey, {
204
147
  headers: request.headers
205
148
  }) : request;
206
149
  };
207
150
  }
208
151
 
209
- /*
210
- Copyright 2020 Google LLC
211
-
212
- Use of this source code is governed by an MIT-style
213
- license that can be found in the LICENSE file or at
214
- https://opensource.org/licenses/MIT.
215
- */ /**
216
- * A plugin, designed to be used with PrecacheController, to determine the
217
- * of assets that were updated (or not updated) during the install event.
218
- *
219
- * @private
220
- */ class PrecacheInstallReportPlugin {
152
+ class PrecacheInstallReportPlugin {
221
153
  updatedURLs = [];
222
154
  notUpdatedURLs = [];
223
155
  handlerWillStart = async ({ request, state })=>{
224
- // TODO: `state` should never be undefined...
225
156
  if (state) {
226
157
  state.originalRequest = request;
227
158
  }
@@ -229,7 +160,6 @@ import { Route, registerRoute } from '@serwist/routing';
229
160
  cachedResponseWillBeUsed = async ({ event, state, cachedResponse })=>{
230
161
  if (event.type === "install") {
231
162
  if (state?.originalRequest && state.originalRequest instanceof Request) {
232
- // TODO: `state` should never be undefined...
233
163
  const url = state.originalRequest.url;
234
164
  if (cachedResponse) {
235
165
  this.notUpdatedURLs.push(url);
@@ -242,23 +172,13 @@ import { Route, registerRoute } from '@serwist/routing';
242
172
  };
243
173
  }
244
174
 
245
- // Name of the search parameter used to store revision info.
246
175
  const REVISION_SEARCH_PARAM = "__WB_REVISION__";
247
- /**
248
- * Converts a manifest entry into a versioned URL suitable for precaching.
249
- *
250
- * @param entry
251
- * @returns A URL with versioning info.
252
- *
253
- * @private
254
- */ function createCacheKey(entry) {
176
+ function createCacheKey(entry) {
255
177
  if (!entry) {
256
178
  throw new SerwistError("add-to-cache-list-unexpected-type", {
257
179
  entry
258
180
  });
259
181
  }
260
- // If a precache manifest entry is a string, it's assumed to be a versioned
261
- // URL, like '/app.abcd1234.js'. Return as-is.
262
182
  if (typeof entry === "string") {
263
183
  const urlObject = new URL(entry, location.href);
264
184
  return {
@@ -272,8 +192,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
272
192
  entry
273
193
  });
274
194
  }
275
- // If there's just a URL and no revision, then it's also assumed to be a
276
- // versioned URL.
277
195
  if (!revision) {
278
196
  const urlObject = new URL(url, location.href);
279
197
  return {
@@ -281,8 +199,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
281
199
  url: urlObject.href
282
200
  };
283
201
  }
284
- // Otherwise, construct a properly versioned URL using the custom Serwist
285
- // search parameter along with the revision info.
286
202
  const cacheKeyURL = new URL(url, location.href);
287
203
  const originalURL = new URL(url, location.href);
288
204
  cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
@@ -292,22 +208,14 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
292
208
  };
293
209
  }
294
210
 
295
- /**
296
- * @param groupTitle
297
- * @param deletedURLs
298
- *
299
- * @private
300
- */ const logGroup = (groupTitle, deletedURLs)=>{
211
+ const logGroup = (groupTitle, deletedURLs)=>{
301
212
  logger.groupCollapsed(groupTitle);
302
213
  for (const url of deletedURLs){
303
214
  logger.log(url);
304
215
  }
305
216
  logger.groupEnd();
306
217
  };
307
- /**
308
- * @param deletedURLs
309
- * @private
310
- */ function printCleanupDetails(deletedURLs) {
218
+ function printCleanupDetails(deletedURLs) {
311
219
  const deletionCount = deletedURLs.length;
312
220
  if (deletionCount > 0) {
313
221
  logger.groupCollapsed(`During precaching cleanup, ${deletionCount} cached request${deletionCount === 1 ? " was" : "s were"} deleted.`);
@@ -316,12 +224,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
316
224
  }
317
225
  }
318
226
 
319
- /**
320
- * @param groupTitle
321
- * @param urls
322
- *
323
- * @private
324
- */ function _nestedGroup(groupTitle, urls) {
227
+ function _nestedGroup(groupTitle, urls) {
325
228
  if (urls.length === 0) {
326
229
  return;
327
230
  }
@@ -331,11 +234,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
331
234
  }
332
235
  logger.groupEnd();
333
236
  }
334
- /**
335
- * @param urlsToPrecache
336
- * @param urlsAlreadyPrecached
337
- * @private
338
- */ function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) {
237
+ function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) {
339
238
  const precachedCount = urlsToPrecache.length;
340
239
  const alreadyPrecachedCount = urlsAlreadyPrecached.length;
341
240
  if (precachedCount || alreadyPrecachedCount) {
@@ -350,19 +249,14 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
350
249
  }
351
250
  }
352
251
 
353
- /**
354
- * Performs efficient precaching of assets.
355
- */ class PrecacheController {
252
+ class PrecacheController {
356
253
  _installAndActiveListenersAdded;
254
+ _concurrentPrecaching;
357
255
  _strategy;
358
256
  _urlsToCacheKeys = new Map();
359
257
  _urlsToCacheModes = new Map();
360
258
  _cacheKeysToIntegrities = new Map();
361
- /**
362
- * Create a new PrecacheController.
363
- *
364
- * @param options
365
- */ constructor({ cacheName, plugins = [], fallbackToNetwork = true } = {}){
259
+ constructor({ cacheName, plugins = [], fallbackToNetwork = true, concurrentPrecaching } = {}){
366
260
  this._strategy = new PrecacheStrategy({
367
261
  cacheName: privateCacheNames.getPrecacheName(cacheName),
368
262
  plugins: [
@@ -373,25 +267,14 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
373
267
  ],
374
268
  fallbackToNetwork
375
269
  });
376
- // Bind the install and activate methods to the instance.
270
+ this._concurrentPrecaching = concurrentPrecaching;
377
271
  this.install = this.install.bind(this);
378
272
  this.activate = this.activate.bind(this);
379
273
  }
380
- /**
381
- * The strategy created by this controller and
382
- * used to cache assets and respond to fetch events.
383
- */ get strategy() {
274
+ get strategy() {
384
275
  return this._strategy;
385
276
  }
386
- /**
387
- * Adds items to the precache list, removing any duplicates and
388
- * stores the files in the precache cache when the service
389
- * worker installs.
390
- *
391
- * This method can be called multiple times.
392
- *
393
- * @param entries Array of entries to precache.
394
- */ precache(entries) {
277
+ precache(entries) {
395
278
  this.addToCacheList(entries);
396
279
  if (!this._installAndActiveListenersAdded) {
397
280
  self.addEventListener("install", this.install);
@@ -399,12 +282,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
399
282
  this._installAndActiveListenersAdded = true;
400
283
  }
401
284
  }
402
- /**
403
- * This method will add items to the precache list, removing duplicates
404
- * and ensuring the information is valid.
405
- *
406
- * @param entries Array of entries to precache.
407
- */ addToCacheList(entries) {
285
+ addToCacheList(entries) {
408
286
  if (process.env.NODE_ENV !== "production") {
409
287
  assert.isArray(entries, {
410
288
  moduleName: "@serwist/precaching",
@@ -415,7 +293,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
415
293
  }
416
294
  const urlsToWarnAbout = [];
417
295
  for (const entry of entries){
418
- // See https://github.com/GoogleChrome/workbox/issues/2259
419
296
  if (typeof entry === "string") {
420
297
  urlsToWarnAbout.push(entry);
421
298
  } else if (entry && entry.revision === undefined) {
@@ -442,8 +319,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
442
319
  if (urlsToWarnAbout.length > 0) {
443
320
  const warningMessage = `Serwist is precaching URLs without revision info: ${urlsToWarnAbout.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;
444
321
  if (process.env.NODE_ENV === "production") {
445
- // Use console directly to display this warning without bloating
446
- // bundle sizes by pulling in all of the logger codebase in prod.
447
322
  console.warn(warningMessage);
448
323
  } else {
449
324
  logger.warn(warningMessage);
@@ -451,24 +326,18 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
451
326
  }
452
327
  }
453
328
  }
454
- /**
455
- * Precaches new and updated assets. Call this method from the service worker
456
- * install event.
457
- *
458
- * Note: this method calls `event.waitUntil()` for you, so you do not need
459
- * to call it yourself in your event handlers.
460
- *
461
- * @param event
462
- * @returns
463
- */ install(event) {
464
- // waitUntil returns Promise<any>
465
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
329
+ install(event) {
466
330
  return waitUntil(event, async ()=>{
467
331
  const installReportPlugin = new PrecacheInstallReportPlugin();
468
332
  this.strategy.plugins.push(installReportPlugin);
469
- // Cache entries one at a time.
470
- // See https://github.com/GoogleChrome/workbox/issues/2528
471
- for (const [url, cacheKey] of this._urlsToCacheKeys){
333
+ let concurrents = this._concurrentPrecaching;
334
+ if (concurrents === undefined) {
335
+ if (!("__WB_CONCURRENT_PRECACHING" in globalThis)) {
336
+ self.__WB_CONCURRENT_PRECACHING = 1;
337
+ }
338
+ concurrents = self.__WB_CONCURRENT_PRECACHING;
339
+ }
340
+ await parallel(concurrents, Array.from(this._urlsToCacheKeys.entries()), async ([url, cacheKey])=>{
472
341
  const integrity = this._cacheKeysToIntegrities.get(cacheKey);
473
342
  const cacheMode = this._urlsToCacheModes.get(url);
474
343
  const request = new Request(url, {
@@ -483,7 +352,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
483
352
  request,
484
353
  event
485
354
  }));
486
- }
355
+ });
487
356
  const { updatedURLs, notUpdatedURLs } = installReportPlugin;
488
357
  if (process.env.NODE_ENV !== "production") {
489
358
  printInstallDetails(updatedURLs, notUpdatedURLs);
@@ -494,92 +363,42 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
494
363
  };
495
364
  });
496
365
  }
497
- /**
498
- * Deletes assets that are no longer present in the current precache manifest.
499
- * Call this method from the service worker activate event.
500
- *
501
- * Note: this method calls `event.waitUntil()` for you, so you do not need
502
- * to call it yourself in your event handlers.
503
- *
504
- * @param event
505
- * @returns
506
- */ activate(event) {
507
- // waitUntil returns Promise<any>
508
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
366
+ activate(event) {
509
367
  return waitUntil(event, async ()=>{
510
368
  const cache = await self.caches.open(this.strategy.cacheName);
511
369
  const currentlyCachedRequests = await cache.keys();
512
370
  const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());
513
- const deletedURLs = [];
371
+ const deletedCacheRequests = [];
514
372
  for (const request of currentlyCachedRequests){
515
373
  if (!expectedCacheKeys.has(request.url)) {
516
374
  await cache.delete(request);
517
- deletedURLs.push(request.url);
375
+ deletedCacheRequests.push(request.url);
518
376
  }
519
377
  }
520
378
  if (process.env.NODE_ENV !== "production") {
521
- printCleanupDetails(deletedURLs);
379
+ printCleanupDetails(deletedCacheRequests);
522
380
  }
523
381
  return {
524
- deletedURLs
382
+ deletedCacheRequests
525
383
  };
526
384
  });
527
385
  }
528
- /**
529
- * Returns a mapping of a precached URL to the corresponding cache key, taking
530
- * into account the revision information for the URL.
531
- *
532
- * @returns A URL to cache key mapping.
533
- */ getURLsToCacheKeys() {
386
+ getURLsToCacheKeys() {
534
387
  return this._urlsToCacheKeys;
535
388
  }
536
- /**
537
- * Returns a list of all the URLs that have been precached by the current
538
- * service worker.
539
- *
540
- * @returns The precached URLs.
541
- */ getCachedURLs() {
389
+ getCachedURLs() {
542
390
  return [
543
391
  ...this._urlsToCacheKeys.keys()
544
392
  ];
545
393
  }
546
- /**
547
- * Returns the cache key used for storing a given URL. If that URL is
548
- * unversioned, like `/index.html', then the cache key will be the original
549
- * URL with a search parameter appended to it.
550
- *
551
- * @param url A URL whose cache key you want to look up.
552
- * @returns The versioned URL that corresponds to a cache key
553
- * for the original URL, or undefined if that URL isn't precached.
554
- */ getCacheKeyForURL(url) {
394
+ getCacheKeyForURL(url) {
555
395
  const urlObject = new URL(url, location.href);
556
396
  return this._urlsToCacheKeys.get(urlObject.href);
557
397
  }
558
- /**
559
- * @param url A cache key whose SRI you want to look up.
560
- * @returns The subresource integrity associated with the cache key,
561
- * or undefined if it's not set.
562
- */ getIntegrityForCacheKey(cacheKey) {
398
+ getIntegrityForCacheKey(cacheKey) {
563
399
  return this._cacheKeysToIntegrities.get(cacheKey);
564
400
  }
565
- /**
566
- * This acts as a drop-in replacement for
567
- * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)
568
- * with the following differences:
569
- *
570
- * - It knows what the name of the precache is, and only checks in that cache.
571
- * - It allows you to pass in an "original" URL without versioning parameters,
572
- * and it will automatically look up the correct cache key for the currently
573
- * active revision of that URL.
574
- *
575
- * E.g., `matchPrecache('index.html')` will find the correct precached
576
- * response for the currently active service worker, even if the actual cache
577
- * key is `'/index.html?__WB_REVISION__=1234abcd'`.
578
- *
579
- * @param request The key (without revisioning parameters)
580
- * to look up in the precache.
581
- * @returns
582
- */ async matchPrecache(request) {
401
+ async matchPrecache(request) {
583
402
  const url = request instanceof Request ? request.url : request;
584
403
  const cacheKey = this.getCacheKeyForURL(url);
585
404
  if (cacheKey) {
@@ -588,13 +407,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
588
407
  }
589
408
  return undefined;
590
409
  }
591
- /**
592
- * Returns a function that looks up `url` in the precache (taking into
593
- * account revision information), and returns the corresponding `Response`.
594
- *
595
- * @param url The precached URL which will be used to lookup the response.
596
- * @return
597
- */ createHandlerBoundToURL(url) {
410
+ createHandlerBoundToURL(url) {
598
411
  const cacheKey = this.getCacheKeyForURL(url);
599
412
  if (!cacheKey) {
600
413
  throw new SerwistError("non-precached-url", {
@@ -613,62 +426,39 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
613
426
  }
614
427
 
615
428
  let precacheController;
616
- /**
617
- * @returns
618
- * @private
619
- */ const getOrCreatePrecacheController = ()=>{
429
+ const getOrCreatePrecacheController = ()=>{
620
430
  if (!precacheController) {
621
431
  precacheController = new PrecacheController();
622
432
  }
623
433
  return precacheController;
624
434
  };
625
435
 
626
- /**
627
- * `PrecacheFallbackPlugin` allows you to specify an "offline fallback"
628
- * response to be used when a given strategy is unable to generate a response.
629
- *
630
- * It does this by intercepting the `handlerDidError` plugin callback
631
- * and returning a precached response, taking the expected revision parameter
632
- * into account automatically.
633
- *
634
- * Unless you explicitly pass in a `PrecacheController` instance to the
635
- * constructor, the default instance will be used. Generally speaking, most
636
- * developers will end up using the default.
637
- */ class PrecacheFallbackPlugin {
638
- _fallbackURL;
436
+ class PrecacheFallbackPlugin {
437
+ _fallbackUrls;
639
438
  _precacheController;
640
- /**
641
- * Constructs a new PrecacheFallbackPlugin with the associated fallbackURL.
642
- *
643
- * @param config
644
- */ constructor({ fallbackURL, precacheController }){
645
- this._fallbackURL = fallbackURL;
439
+ constructor({ fallbackUrls, precacheController }){
440
+ this._fallbackUrls = fallbackUrls;
646
441
  this._precacheController = precacheController || getOrCreatePrecacheController();
647
442
  }
648
- /**
649
- * @returns The precache response for the fallback URL.
650
- * @private
651
- */ handlerDidError = ()=>this._precacheController.matchPrecache(this._fallbackURL);
443
+ async handlerDidError(param) {
444
+ for (const fallback of this._fallbackUrls){
445
+ if (typeof fallback === "string") {
446
+ const fallbackResponse = await this._precacheController.matchPrecache(fallback);
447
+ if (fallbackResponse !== undefined) {
448
+ return fallbackResponse;
449
+ }
450
+ } else if (fallback.matcher(param)) {
451
+ const fallbackResponse = await this._precacheController.matchPrecache(fallback.url);
452
+ if (fallbackResponse !== undefined) {
453
+ return fallbackResponse;
454
+ }
455
+ }
456
+ }
457
+ return undefined;
458
+ }
652
459
  }
653
460
 
654
- /*
655
- Copyright 2018 Google LLC
656
-
657
- Use of this source code is governed by an MIT-style
658
- license that can be found in the LICENSE file or at
659
- https://opensource.org/licenses/MIT.
660
- */ /**
661
- * Removes any URL search parameters that should be ignored.
662
- *
663
- * @param urlObject The original URL.
664
- * @param ignoreURLParametersMatching RegExps to test against
665
- * each search parameter name. Matches mean that the search parameter should be
666
- * ignored.
667
- * @returns The URL with any ignored search parameters removed.
668
- * @private
669
- */ function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {
670
- // Convert the iterable into an array at the start of the loop to make sure
671
- // deletion doesn't mess up iteration.
461
+ function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {
672
462
  for (const paramName of [
673
463
  ...urlObject.searchParams.keys()
674
464
  ]){
@@ -679,15 +469,7 @@ let precacheController;
679
469
  return urlObject;
680
470
  }
681
471
 
682
- /**
683
- * Generator function that yields possible variations on the original URL to
684
- * check, one at a time.
685
- *
686
- * @param url
687
- * @param options
688
- *
689
- * @private
690
- */ function* generateURLVariations(url, { ignoreURLParametersMatching = [
472
+ function* generateURLVariations(url, { ignoreURLParametersMatching = [
691
473
  /^utm_/,
692
474
  /^fbclid$/
693
475
  ], directoryIndex = "index.html", cleanURLs = true, urlManipulation } = {}) {
@@ -716,18 +498,8 @@ let precacheController;
716
498
  }
717
499
  }
718
500
 
719
- /**
720
- * A subclass of `@serwist/routing.Route` that takes a
721
- * `@serwist/precaching.PrecacheController`
722
- * instance and uses it to match incoming requests and handle fetching
723
- * responses from the precache.
724
- */ class PrecacheRoute extends Route {
725
- /**
726
- * @param precacheController A `PrecacheController`
727
- * instance used to both match requests and respond to fetch events.
728
- * @param options Options to control how requests are matched
729
- * against the list of precached URLs.
730
- */ constructor(precacheController, options){
501
+ class PrecacheRoute extends Route {
502
+ constructor(precacheController, options){
731
503
  const match = ({ request })=>{
732
504
  const urlsToCacheKeys = precacheController.getURLsToCacheKeys();
733
505
  for (const possibleURL of generateURLVariations(request.url, options)){
@@ -749,56 +521,19 @@ let precacheController;
749
521
  }
750
522
  }
751
523
 
752
- /**
753
- * Adds plugins to the precaching strategy.
754
- *
755
- * @param plugins
756
- */ function addPlugins(plugins) {
524
+ function addPlugins(plugins) {
757
525
  const precacheController = getOrCreatePrecacheController();
758
526
  precacheController.strategy.plugins.push(...plugins);
759
527
  }
760
528
 
761
- /**
762
- * Add a `fetch` listener to the service worker that will
763
- * respond to
764
- * [network requests](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests)
765
- * with precached assets.
766
- *
767
- * Requests for assets that aren't precached, the `FetchEvent` will not be
768
- * responded to, allowing the event to fall through to other `fetch` event
769
- * listeners.
770
- *
771
- * @param options See the `@serwist/precaching.PrecacheRoute` options.
772
- */ function addRoute(options) {
529
+ const addRoute = (options)=>{
773
530
  const precacheController = getOrCreatePrecacheController();
774
531
  const precacheRoute = new PrecacheRoute(precacheController, options);
775
532
  registerRoute(precacheRoute);
776
- }
777
-
778
- /*
779
- Copyright 2018 Google LLC
533
+ };
780
534
 
781
- Use of this source code is governed by an MIT-style
782
- license that can be found in the LICENSE file or at
783
- https://opensource.org/licenses/MIT.
784
- */ // Give TypeScript the correct global.
785
535
  const SUBSTRING_TO_FIND = "-precache-";
786
- /**
787
- * Cleans up incompatible precaches that were created by older versions of
788
- * Serwist, by a service worker registered under the current scope.
789
- *
790
- * This is meant to be called as part of the `activate` event.
791
- *
792
- * This should be safe to use as long as you don't include `substringToFind`
793
- * (defaulting to `-precache-`) in your non-precache cache names.
794
- *
795
- * @param currentPrecacheName The cache name currently in use for
796
- * precaching. This cache won't be deleted.
797
- * @param substringToFind Cache names which include this
798
- * substring will be deleted (excluding `currentPrecacheName`).
799
- * @returns A list of all the cache names that were deleted.
800
- * @private
801
- */ const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND)=>{
536
+ const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND)=>{
802
537
  const cacheNames = await self.caches.keys();
803
538
  const cacheNamesToDelete = cacheNames.filter((cacheName)=>{
804
539
  return cacheName.includes(substringToFind) && cacheName.includes(self.registration.scope) && cacheName !== currentPrecacheName;
@@ -807,111 +542,42 @@ const SUBSTRING_TO_FIND = "-precache-";
807
542
  return cacheNamesToDelete;
808
543
  };
809
544
 
810
- /**
811
- * Adds an `activate` event listener which will clean up incompatible
812
- * precaches that were created by older versions of Serwist.
813
- */ function cleanupOutdatedCaches() {
814
- // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
545
+ const cleanupOutdatedCaches = ()=>{
815
546
  self.addEventListener("activate", (event)=>{
816
547
  const cacheName = privateCacheNames.getPrecacheName();
817
548
  event.waitUntil(deleteOutdatedCaches(cacheName).then((cachesDeleted)=>{
818
549
  if (process.env.NODE_ENV !== "production") {
819
550
  if (cachesDeleted.length > 0) {
820
- logger.log("The following out-of-date precaches were cleaned up " + "automatically:", cachesDeleted);
551
+ logger.log("The following out-of-date precaches were cleaned up automatically:", cachesDeleted);
821
552
  }
822
553
  }
823
554
  }));
824
555
  });
825
- }
556
+ };
826
557
 
827
- /**
828
- * Helper function that calls `PrecacheController#createHandlerBoundToURL`
829
- * on the default `PrecacheController` instance.
830
- *
831
- * If you are creating your own `PrecacheController`, then call the
832
- * `PrecacheController#createHandlerBoundToURL` on that instance,
833
- * instead of using this function.
834
- *
835
- * @param url The precached URL which will be used to lookup the
836
- * `Response`.
837
- * @param fallbackToNetwork Whether to attempt to get the
838
- * response from the network if there's a precache miss.
839
- * @return
840
- */ function createHandlerBoundToURL(url) {
558
+ const createHandlerBoundToURL = (url)=>{
841
559
  const precacheController = getOrCreatePrecacheController();
842
560
  return precacheController.createHandlerBoundToURL(url);
843
- }
561
+ };
844
562
 
845
- /**
846
- * Takes in a URL, and returns the corresponding URL that could be used to
847
- * lookup the entry in the precache.
848
- *
849
- * If a relative URL is provided, the location of the service worker file will
850
- * be used as the base.
851
- *
852
- * For precached entries without revision information, the cache key will be the
853
- * same as the original URL.
854
- *
855
- * For precached entries with revision information, the cache key will be the
856
- * original URL with the addition of a query parameter used for keeping track of
857
- * the revision info.
858
- *
859
- * @param url The URL whose cache key to look up.
860
- * @returns The cache key that corresponds to that URL.
861
- */ function getCacheKeyForURL(url) {
563
+ function getCacheKeyForURL(url) {
862
564
  const precacheController = getOrCreatePrecacheController();
863
565
  return precacheController.getCacheKeyForURL(url);
864
566
  }
865
567
 
866
- /**
867
- * Helper function that calls `PrecacheController#matchPrecache`
868
- * on the default `PrecacheController` instance.
869
- *
870
- * If you are creating your own `PrecacheController`, then call
871
- * `PrecacheController#matchPrecache` on that instance,
872
- * instead of using this function.
873
- *
874
- * @param request The key (without revisioning parameters)
875
- * to look up in the precache.
876
- * @returns
877
- */ function matchPrecache(request) {
568
+ function matchPrecache(request) {
878
569
  const precacheController = getOrCreatePrecacheController();
879
570
  return precacheController.matchPrecache(request);
880
571
  }
881
572
 
882
- /**
883
- * Adds items to the precache list, removing any duplicates and
884
- * stores the files in the precache cache when the service
885
- * worker installs.
886
- *
887
- * This method can be called multiple times.
888
- *
889
- * Please note: This method **will not** serve any of the cached files for you.
890
- * It only precaches files. To respond to a network request you call
891
- * `@serwist/precaching.addRoute`.
892
- *
893
- * If you have a single array of files to precache, you can just call
894
- * `@serwist/precaching.precacheAndRoute`.
895
- *
896
- * @param entries Array of entries to precache.
897
- */ function precache(entries) {
573
+ const precache = (entries)=>{
898
574
  const precacheController = getOrCreatePrecacheController();
899
575
  precacheController.precache(entries);
900
- }
576
+ };
901
577
 
902
- /**
903
- * This method will add entries to the precache list and add a route to
904
- * respond to fetch events.
905
- *
906
- * This is a convenience method that will call
907
- * `@serwist/precaching.precache` and
908
- * `@serwist/precaching.addRoute` in a single call.
909
- *
910
- * @param entries Array of entries to precache.
911
- * @param options See the `@serwist/precaching.PrecacheRoute` options.
912
- */ function precacheAndRoute(entries, options) {
578
+ const precacheAndRoute = (entries, options)=>{
913
579
  precache(entries);
914
580
  addRoute(options);
915
- }
581
+ };
916
582
 
917
583
  export { PrecacheController, PrecacheFallbackPlugin, PrecacheRoute, PrecacheStrategy, addPlugins, addRoute, cleanupOutdatedCaches, createHandlerBoundToURL, getCacheKeyForURL, matchPrecache, precache, precacheAndRoute };