serwist 10.0.0-preview.7 → 10.0.0-preview.9
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/chunks/waitUntil.js +129 -129
- package/dist/index.d.ts +19 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.internal.d.ts +2 -2
- package/dist/index.internal.d.ts.map +1 -1
- package/dist/index.internal.js +3 -3
- package/dist/index.js +2026 -1917
- package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncPlugin.d.ts +1 -1
- package/dist/lib/background-sync/BackgroundSyncPlugin.d.ts.map +1 -0
- package/dist/lib/background-sync/BackgroundSyncQueue.d.ts.map +1 -0
- package/dist/lib/background-sync/BackgroundSyncQueueDb.d.ts.map +1 -0
- package/dist/lib/background-sync/BackgroundSyncQueueStore.d.ts.map +1 -0
- package/dist/lib/{backgroundSync → background-sync}/StorableRequest.d.ts +1 -1
- package/dist/lib/background-sync/StorableRequest.d.ts.map +1 -0
- package/dist/lib/background-sync/index.d.ts.map +1 -0
- package/dist/lib/{broadcastUpdate → broadcast-update}/BroadcastCacheUpdate.d.ts +1 -1
- package/dist/lib/broadcast-update/BroadcastCacheUpdate.d.ts.map +1 -0
- package/dist/lib/{broadcastUpdate → broadcast-update}/BroadcastUpdatePlugin.d.ts +1 -1
- package/dist/lib/broadcast-update/BroadcastUpdatePlugin.d.ts.map +1 -0
- package/dist/lib/broadcast-update/constants.d.ts.map +1 -0
- package/dist/lib/broadcast-update/index.d.ts.map +1 -0
- package/dist/lib/broadcast-update/responsesAreSame.d.ts.map +1 -0
- package/dist/lib/{broadcastUpdate → broadcast-update}/types.d.ts +1 -1
- package/dist/lib/broadcast-update/types.d.ts.map +1 -0
- package/dist/{cacheNames.d.ts → lib/cache-name.d.ts} +1 -1
- package/dist/lib/cache-name.d.ts.map +1 -0
- package/dist/lib/cacheable-response/CacheableResponse.d.ts.map +1 -0
- package/dist/lib/{cacheableResponse → cacheable-response}/CacheableResponsePlugin.d.ts +1 -1
- package/dist/lib/cacheable-response/CacheableResponsePlugin.d.ts.map +1 -0
- package/dist/lib/{cacheableResponse → cacheable-response}/index.d.ts +1 -1
- package/dist/lib/cacheable-response/index.d.ts.map +1 -0
- package/dist/{constants.d.ts → lib/constants.d.ts} +1 -1
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/core.d.ts +62 -0
- package/dist/lib/core.d.ts.map +1 -0
- package/dist/lib/expiration/ExpirationPlugin.d.ts +1 -1
- package/dist/lib/expiration/ExpirationPlugin.d.ts.map +1 -1
- package/dist/lib/extension.d.ts +30 -0
- package/dist/lib/extension.d.ts.map +1 -0
- package/dist/lib/extensions/google-analytics/constants.d.ts.map +1 -0
- package/dist/lib/extensions/google-analytics/extension.d.ts +79 -0
- package/dist/lib/extensions/google-analytics/extension.d.ts.map +1 -0
- package/dist/lib/extensions/google-analytics/index.d.ts +2 -0
- package/dist/lib/extensions/google-analytics/index.d.ts.map +1 -0
- package/dist/lib/extensions/google-analytics/initialize.d.ts +12 -0
- package/dist/lib/extensions/google-analytics/initialize.d.ts.map +1 -0
- package/dist/lib/extensions/index.d.ts +14 -0
- package/dist/lib/extensions/index.d.ts.map +1 -0
- package/dist/lib/{controllers/PrecacheController/PrecacheController.d.ts → extensions/precache/extension.d.ts} +11 -34
- package/dist/lib/extensions/precache/extension.d.ts.map +1 -0
- package/dist/lib/extensions/precache/options.d.ts +26 -0
- package/dist/lib/extensions/precache/options.d.ts.map +1 -0
- package/dist/lib/{controllers/PrecacheController/PrecacheCacheKeyPlugin.d.ts → extensions/precache/plugin-cache-key.d.ts} +4 -4
- package/dist/lib/extensions/precache/plugin-cache-key.d.ts.map +1 -0
- package/dist/lib/{precaching/PrecacheFallbackPlugin.d.ts → extensions/precache/plugin-fallback.d.ts} +7 -12
- package/dist/lib/extensions/precache/plugin-fallback.d.ts.map +1 -0
- package/dist/lib/{controllers/PrecacheController/PrecacheInstallReportPlugin.d.ts → extensions/precache/plugin-install-report.d.ts} +2 -2
- package/dist/lib/extensions/precache/plugin-install-report.d.ts.map +1 -0
- package/dist/lib/extensions/precache/route.d.ts +42 -0
- package/dist/lib/extensions/precache/route.d.ts.map +1 -0
- package/dist/lib/{controllers/PrecacheController/PrecacheStrategy.d.ts → extensions/precache/strategy.d.ts} +2 -2
- package/dist/lib/extensions/precache/strategy.d.ts.map +1 -0
- package/dist/lib/{controllers/RuntimeCacheController.d.ts → extensions/runtime-cache.d.ts} +9 -8
- package/dist/lib/extensions/runtime-cache.d.ts.map +1 -0
- package/dist/lib/functions/handlers.d.ts +60 -0
- package/dist/lib/functions/handlers.d.ts.map +1 -0
- package/dist/lib/functions/router.d.ts +60 -0
- package/dist/lib/functions/router.d.ts.map +1 -0
- package/dist/{navigationPreload.d.ts → lib/navigation-preload.d.ts} +1 -1
- package/dist/lib/navigation-preload.d.ts.map +1 -0
- package/dist/lib/{rangeRequests → range-requests}/RangeRequestsPlugin.d.ts +1 -1
- package/dist/lib/range-requests/RangeRequestsPlugin.d.ts.map +1 -0
- package/dist/lib/range-requests/createPartialResponse.d.ts.map +1 -0
- package/dist/lib/{rangeRequests → range-requests}/index.d.ts +1 -1
- package/dist/lib/range-requests/index.d.ts.map +1 -0
- package/dist/lib/range-requests/utils/calculateEffectiveBoundaries.d.ts.map +1 -0
- package/dist/lib/range-requests/utils/parseRangeHeader.d.ts.map +1 -0
- package/dist/lib/route.d.ts +106 -0
- package/dist/lib/route.d.ts.map +1 -0
- package/dist/{Serwist.d.ts → lib/serwist.d.ts} +27 -40
- package/dist/lib/serwist.d.ts.map +1 -0
- package/dist/lib/strategies/NetworkFirst.d.ts.map +1 -1
- package/dist/lib/strategies/StaleWhileRevalidate.d.ts.map +1 -1
- package/dist/lib/strategies/Strategy.d.ts +1 -1
- package/dist/lib/strategies/Strategy.d.ts.map +1 -1
- package/dist/lib/strategies/StrategyHandler.d.ts +1 -1
- package/dist/lib/strategies/StrategyHandler.d.ts.map +1 -1
- package/dist/lib/strategies/plugins/cacheOkAndOpaquePlugin.d.ts +1 -1
- package/dist/lib/strategies/plugins/cacheOkAndOpaquePlugin.d.ts.map +1 -1
- package/dist/{types.d.ts → lib/types.d.ts} +15 -43
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/{copyResponse.d.ts → lib/utils.d.ts} +22 -1
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/models/messages/messageGenerator.d.ts +1 -1
- package/dist/models/messages/messageGenerator.d.ts.map +1 -1
- package/dist/utils/SerwistError.d.ts +1 -1
- package/dist/utils/SerwistError.d.ts.map +1 -1
- package/dist/utils/assert.d.ts +1 -1
- package/dist/utils/assert.d.ts.map +1 -1
- package/dist/utils/cacheNames.d.ts.map +1 -1
- package/dist/utils/createCacheKey.d.ts +1 -1
- package/dist/utils/createCacheKey.d.ts.map +1 -1
- package/dist/utils/generateURLVariations.d.ts +1 -1
- package/dist/utils/generateURLVariations.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/normalizeHandler.d.ts +1 -1
- package/dist/utils/normalizeHandler.d.ts.map +1 -1
- package/dist/utils/parseRoute.d.ts +3 -3
- package/dist/utils/parseRoute.d.ts.map +1 -1
- package/dist/utils/pluginUtils.d.ts +1 -1
- package/dist/utils/pluginUtils.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/index.internal.ts +2 -2
- package/src/index.ts +51 -33
- package/src/lib/{backgroundSync → background-sync}/BackgroundSyncPlugin.ts +1 -1
- package/src/lib/{backgroundSync → background-sync}/BackgroundSyncQueue.ts +4 -4
- package/src/lib/{backgroundSync → background-sync}/BackgroundSyncQueueDb.ts +1 -1
- package/src/lib/{backgroundSync → background-sync}/BackgroundSyncQueueStore.ts +0 -2
- package/src/lib/{backgroundSync → background-sync}/StorableRequest.ts +1 -1
- package/src/lib/{broadcastUpdate → broadcast-update}/BroadcastCacheUpdate.ts +1 -1
- package/src/lib/{broadcastUpdate → broadcast-update}/BroadcastUpdatePlugin.ts +1 -1
- package/src/lib/{broadcastUpdate → broadcast-update}/types.ts +1 -1
- package/src/lib/{cacheableResponse → cacheable-response}/CacheableResponsePlugin.ts +1 -1
- package/src/lib/core.ts +128 -0
- package/src/lib/expiration/CacheExpiration.ts +1 -1
- package/src/lib/expiration/ExpirationPlugin.ts +4 -5
- package/src/lib/extension.ts +37 -0
- package/src/lib/{googleAnalytics/initializeGoogleAnalytics.ts → extensions/google-analytics/extension.ts} +40 -46
- package/src/lib/extensions/google-analytics/index.ts +0 -0
- package/src/lib/extensions/google-analytics/initialize.ts +48 -0
- package/src/lib/extensions/index.ts +13 -0
- package/src/lib/{controllers/PrecacheController/PrecacheController.ts → extensions/precache/extension.ts} +23 -45
- package/src/lib/{controllers/PrecacheController/parsePrecacheOptions.ts → extensions/precache/options.ts} +11 -8
- package/src/lib/{controllers/PrecacheController/PrecacheCacheKeyPlugin.ts → extensions/precache/plugin-cache-key.ts} +4 -4
- package/src/lib/{precaching/PrecacheFallbackPlugin.ts → extensions/precache/plugin-fallback.ts} +22 -21
- package/src/lib/{controllers/PrecacheController/PrecacheInstallReportPlugin.ts → extensions/precache/plugin-install-report.ts} +1 -1
- package/src/lib/extensions/precache/route.ts +72 -0
- package/src/lib/{controllers/PrecacheController/PrecacheStrategy.ts → extensions/precache/strategy.ts} +5 -5
- package/src/lib/{controllers/RuntimeCacheController.ts → extensions/runtime-cache.ts} +21 -14
- package/src/lib/functions/handlers.ts +149 -0
- package/src/lib/functions/router.ts +314 -0
- package/src/lib/{rangeRequests → range-requests}/RangeRequestsPlugin.ts +1 -1
- package/src/lib/route.ts +234 -0
- package/src/lib/serwist.ts +443 -0
- package/src/lib/strategies/CacheFirst.ts +2 -2
- package/src/lib/strategies/CacheOnly.ts +1 -1
- package/src/lib/strategies/NetworkFirst.ts +4 -4
- package/src/lib/strategies/NetworkOnly.ts +2 -2
- package/src/lib/strategies/StaleWhileRevalidate.ts +3 -3
- package/src/lib/strategies/Strategy.ts +6 -6
- package/src/lib/strategies/StrategyHandler.ts +5 -5
- package/src/lib/strategies/plugins/cacheOkAndOpaquePlugin.ts +1 -1
- package/src/{types.ts → lib/types.ts} +17 -57
- package/src/{copyResponse.ts → lib/utils.ts} +81 -2
- package/src/models/messages/messageGenerator.ts +1 -1
- package/src/utils/SerwistError.ts +1 -1
- package/src/utils/assert.ts +1 -2
- package/src/utils/cacheNames.ts +0 -2
- package/src/utils/canConstructReadableStream.ts +1 -1
- package/src/utils/canConstructResponseFromBodyStream.ts +1 -1
- package/src/utils/createCacheKey.ts +1 -2
- package/src/utils/generateURLVariations.ts +1 -1
- package/src/utils/normalizeHandler.ts +1 -1
- package/src/utils/parseRoute.ts +4 -5
- package/src/utils/pluginUtils.ts +1 -1
- package/src/utils/resultingClientExists.ts +1 -1
- package/dist/NavigationRoute.d.ts +0 -56
- package/dist/NavigationRoute.d.ts.map +0 -1
- package/dist/RegExpRoute.d.ts +0 -24
- package/dist/RegExpRoute.d.ts.map +0 -1
- package/dist/Route.d.ts +0 -33
- package/dist/Route.d.ts.map +0 -1
- package/dist/Serwist.d.ts.map +0 -1
- package/dist/cacheNames.d.ts.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/copyResponse.d.ts.map +0 -1
- package/dist/disableDevLogs.d.ts +0 -7
- package/dist/disableDevLogs.d.ts.map +0 -1
- package/dist/lib/backgroundSync/BackgroundSyncPlugin.d.ts.map +0 -1
- package/dist/lib/backgroundSync/BackgroundSyncQueue.d.ts.map +0 -1
- package/dist/lib/backgroundSync/BackgroundSyncQueueDb.d.ts.map +0 -1
- package/dist/lib/backgroundSync/BackgroundSyncQueueStore.d.ts.map +0 -1
- package/dist/lib/backgroundSync/StorableRequest.d.ts.map +0 -1
- package/dist/lib/backgroundSync/index.d.ts.map +0 -1
- package/dist/lib/broadcastUpdate/BroadcastCacheUpdate.d.ts.map +0 -1
- package/dist/lib/broadcastUpdate/BroadcastUpdatePlugin.d.ts.map +0 -1
- package/dist/lib/broadcastUpdate/constants.d.ts.map +0 -1
- package/dist/lib/broadcastUpdate/index.d.ts.map +0 -1
- package/dist/lib/broadcastUpdate/responsesAreSame.d.ts.map +0 -1
- package/dist/lib/broadcastUpdate/types.d.ts.map +0 -1
- package/dist/lib/cacheableResponse/CacheableResponse.d.ts.map +0 -1
- package/dist/lib/cacheableResponse/CacheableResponsePlugin.d.ts.map +0 -1
- package/dist/lib/cacheableResponse/index.d.ts.map +0 -1
- package/dist/lib/controllers/PrecacheController/PrecacheCacheKeyPlugin.d.ts.map +0 -1
- package/dist/lib/controllers/PrecacheController/PrecacheController.d.ts.map +0 -1
- package/dist/lib/controllers/PrecacheController/PrecacheInstallReportPlugin.d.ts.map +0 -1
- package/dist/lib/controllers/PrecacheController/PrecacheRoute.d.ts +0 -15
- package/dist/lib/controllers/PrecacheController/PrecacheRoute.d.ts.map +0 -1
- package/dist/lib/controllers/PrecacheController/PrecacheStrategy.d.ts.map +0 -1
- package/dist/lib/controllers/PrecacheController/parsePrecacheOptions.d.ts +0 -25
- package/dist/lib/controllers/PrecacheController/parsePrecacheOptions.d.ts.map +0 -1
- package/dist/lib/controllers/RuntimeCacheController.d.ts.map +0 -1
- package/dist/lib/controllers/index.d.ts +0 -4
- package/dist/lib/controllers/index.d.ts.map +0 -1
- package/dist/lib/googleAnalytics/constants.d.ts.map +0 -1
- package/dist/lib/googleAnalytics/index.d.ts +0 -3
- package/dist/lib/googleAnalytics/index.d.ts.map +0 -1
- package/dist/lib/googleAnalytics/initializeGoogleAnalytics.d.ts +0 -30
- package/dist/lib/googleAnalytics/initializeGoogleAnalytics.d.ts.map +0 -1
- package/dist/lib/precaching/PrecacheFallbackPlugin.d.ts.map +0 -1
- package/dist/lib/precaching/index.d.ts +0 -3
- package/dist/lib/precaching/index.d.ts.map +0 -1
- package/dist/lib/rangeRequests/RangeRequestsPlugin.d.ts.map +0 -1
- package/dist/lib/rangeRequests/createPartialResponse.d.ts.map +0 -1
- package/dist/lib/rangeRequests/index.d.ts.map +0 -1
- package/dist/lib/rangeRequests/utils/calculateEffectiveBoundaries.d.ts.map +0 -1
- package/dist/lib/rangeRequests/utils/parseRangeHeader.d.ts.map +0 -1
- package/dist/navigationPreload.d.ts.map +0 -1
- package/dist/registerQuotaErrorCallback.d.ts +0 -8
- package/dist/registerQuotaErrorCallback.d.ts.map +0 -1
- package/dist/setCacheNameDetails.d.ts +0 -9
- package/dist/setCacheNameDetails.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/src/NavigationRoute.ts +0 -118
- package/src/RegExpRoute.ts +0 -74
- package/src/Route.ts +0 -67
- package/src/Serwist.ts +0 -766
- package/src/disableDevLogs.ts +0 -10
- package/src/lib/controllers/PrecacheController/PrecacheRoute.ts +0 -44
- package/src/lib/controllers/index.ts +0 -3
- package/src/lib/googleAnalytics/index.ts +0 -2
- package/src/lib/precaching/index.ts +0 -2
- package/src/registerQuotaErrorCallback.ts +0 -34
- package/src/setCacheNameDetails.ts +0 -53
- package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncQueue.d.ts +0 -0
- package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncQueueDb.d.ts +0 -0
- package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncQueueStore.d.ts +0 -0
- package/dist/lib/{backgroundSync → background-sync}/index.d.ts +0 -0
- package/dist/lib/{broadcastUpdate → broadcast-update}/constants.d.ts +0 -0
- package/dist/lib/{broadcastUpdate → broadcast-update}/index.d.ts +0 -0
- package/dist/lib/{broadcastUpdate → broadcast-update}/responsesAreSame.d.ts +0 -0
- package/dist/lib/{cacheableResponse → cacheable-response}/CacheableResponse.d.ts +0 -0
- package/dist/lib/{googleAnalytics → extensions/google-analytics}/constants.d.ts +0 -0
- package/dist/lib/{rangeRequests → range-requests}/createPartialResponse.d.ts +0 -0
- package/dist/lib/{rangeRequests → range-requests}/utils/calculateEffectiveBoundaries.d.ts +0 -0
- package/dist/lib/{rangeRequests → range-requests}/utils/parseRangeHeader.d.ts +0 -0
- package/src/lib/{backgroundSync → background-sync}/index.ts +0 -0
- package/src/lib/{broadcastUpdate → broadcast-update}/constants.ts +0 -0
- package/src/lib/{broadcastUpdate → broadcast-update}/index.ts +0 -0
- package/src/lib/{broadcastUpdate → broadcast-update}/responsesAreSame.ts +1 -1
- package/src/{cacheNames.ts → lib/cache-name.ts} +0 -0
- package/src/lib/{cacheableResponse → cacheable-response}/CacheableResponse.ts +1 -1
- package/src/lib/{cacheableResponse → cacheable-response}/index.ts +1 -1
- package/src/{constants.ts → lib/constants.ts} +0 -0
- package/src/lib/{googleAnalytics → extensions/google-analytics}/constants.ts +0 -0
- package/src/{navigationPreload.ts → lib/navigation-preload.ts} +0 -0
- package/src/lib/{rangeRequests → range-requests}/createPartialResponse.ts +1 -1
- package/src/lib/{rangeRequests → range-requests}/index.ts +1 -1
- package/src/lib/{rangeRequests → range-requests}/utils/calculateEffectiveBoundaries.ts +1 -1
- package/src/lib/{rangeRequests → range-requests}/utils/parseRangeHeader.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parallel } from '@serwist/utils';
|
|
1
|
+
import { c as cacheNames$1, l as logger, f as finalAssertExports, S as SerwistError, g as getFriendlyURL, D as Deferred, t as timeout, a as cacheMatchIgnoreParams, e as executeQuotaErrorCallbacks, b as canConstructResponseFromBodyStream, q as quotaErrorCallbacks, w as waitUntil, d as clientsClaim, r as resultingClientExists } from './chunks/waitUntil.js';
|
|
3
2
|
import { openDB, deleteDB } from 'idb';
|
|
3
|
+
import { parallel } from '@serwist/utils';
|
|
4
|
+
|
|
5
|
+
const cacheNames = {
|
|
6
|
+
get googleAnalytics () {
|
|
7
|
+
return cacheNames$1.getGoogleAnalyticsName();
|
|
8
|
+
},
|
|
9
|
+
get precache () {
|
|
10
|
+
return cacheNames$1.getPrecacheName();
|
|
11
|
+
},
|
|
12
|
+
get prefix () {
|
|
13
|
+
return cacheNames$1.getPrefix();
|
|
14
|
+
},
|
|
15
|
+
get runtime () {
|
|
16
|
+
return cacheNames$1.getRuntimeName();
|
|
17
|
+
},
|
|
18
|
+
get suffix () {
|
|
19
|
+
return cacheNames$1.getSuffix();
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const isNavigationPreloadSupported = ()=>{
|
|
24
|
+
return Boolean(self.registration?.navigationPreload);
|
|
25
|
+
};
|
|
26
|
+
const enableNavigationPreload = (headerValue)=>{
|
|
27
|
+
if (isNavigationPreloadSupported()) {
|
|
28
|
+
self.addEventListener("activate", (event)=>{
|
|
29
|
+
event.waitUntil(self.registration.navigationPreload.enable().then(()=>{
|
|
30
|
+
if (headerValue) {
|
|
31
|
+
void self.registration.navigationPreload.setHeaderValue(headerValue);
|
|
32
|
+
}
|
|
33
|
+
if (process.env.NODE_ENV !== "production") {
|
|
34
|
+
logger.log("Navigation preloading is enabled.");
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
if (process.env.NODE_ENV !== "production") {
|
|
40
|
+
logger.log("Navigation preloading is not supported in this browser.");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const disableNavigationPreload = ()=>{
|
|
45
|
+
if (isNavigationPreloadSupported()) {
|
|
46
|
+
self.addEventListener("activate", (event)=>{
|
|
47
|
+
event.waitUntil(self.registration.navigationPreload.disable().then(()=>{
|
|
48
|
+
if (process.env.NODE_ENV !== "production") {
|
|
49
|
+
logger.log("Navigation preloading is disabled.");
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
if (process.env.NODE_ENV !== "production") {
|
|
55
|
+
logger.log("Navigation preloading is not supported in this browser.");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
4
59
|
|
|
5
60
|
const normalizeHandler = (handler)=>{
|
|
6
61
|
if (handler && typeof handler === "object") {
|
|
@@ -64,7 +119,32 @@ class Route {
|
|
|
64
119
|
this.catchHandler = normalizeHandler(handler);
|
|
65
120
|
}
|
|
66
121
|
}
|
|
67
|
-
|
|
122
|
+
class RegExpRoute extends Route {
|
|
123
|
+
constructor(regExp, handler, method){
|
|
124
|
+
if (process.env.NODE_ENV !== "production") {
|
|
125
|
+
finalAssertExports.isInstance(regExp, RegExp, {
|
|
126
|
+
moduleName: "serwist",
|
|
127
|
+
className: "RegExpRoute",
|
|
128
|
+
funcName: "constructor",
|
|
129
|
+
paramName: "pattern"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const match = ({ url })=>{
|
|
133
|
+
const result = regExp.exec(url.href);
|
|
134
|
+
if (!result) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (url.origin !== location.origin && result.index !== 0) {
|
|
138
|
+
if (process.env.NODE_ENV !== "production") {
|
|
139
|
+
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.`);
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
return result.slice(1);
|
|
144
|
+
};
|
|
145
|
+
super(match, handler, method);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
68
148
|
class NavigationRoute extends Route {
|
|
69
149
|
_allowlist;
|
|
70
150
|
_denylist;
|
|
@@ -115,1977 +195,2086 @@ class NavigationRoute extends Route {
|
|
|
115
195
|
}
|
|
116
196
|
}
|
|
117
197
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const match = ({ url })=>{
|
|
129
|
-
const result = regExp.exec(url.href);
|
|
130
|
-
if (!result) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (url.origin !== location.origin && result.index !== 0) {
|
|
134
|
-
if (process.env.NODE_ENV !== "production") {
|
|
135
|
-
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.`);
|
|
136
|
-
}
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
return result.slice(1);
|
|
140
|
-
};
|
|
141
|
-
super(match, handler, method);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
146
|
-
const createCacheKey = (entry)=>{
|
|
147
|
-
if (!entry) {
|
|
148
|
-
throw new SerwistError("add-to-cache-list-unexpected-type", {
|
|
149
|
-
entry
|
|
198
|
+
const BACKGROUND_SYNC_DB_VERSION = 3;
|
|
199
|
+
const BACKGROUND_SYNC_DB_NAME = "serwist-background-sync";
|
|
200
|
+
const REQUEST_OBJECT_STORE_NAME = "requests";
|
|
201
|
+
const QUEUE_NAME_INDEX = "queueName";
|
|
202
|
+
class BackgroundSyncQueueDb {
|
|
203
|
+
_db = null;
|
|
204
|
+
async addEntry(entry) {
|
|
205
|
+
const db = await this.getDb();
|
|
206
|
+
const tx = db.transaction(REQUEST_OBJECT_STORE_NAME, "readwrite", {
|
|
207
|
+
durability: "relaxed"
|
|
150
208
|
});
|
|
209
|
+
await tx.store.add(entry);
|
|
210
|
+
await tx.done;
|
|
151
211
|
}
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
url: urlObject.href
|
|
157
|
-
};
|
|
212
|
+
async getFirstEntryId() {
|
|
213
|
+
const db = await this.getDb();
|
|
214
|
+
const cursor = await db.transaction(REQUEST_OBJECT_STORE_NAME).store.openCursor();
|
|
215
|
+
return cursor?.value.id;
|
|
158
216
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
});
|
|
217
|
+
async getAllEntriesByQueueName(queueName) {
|
|
218
|
+
const db = await this.getDb();
|
|
219
|
+
const results = await db.getAllFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
|
|
220
|
+
return results ? results : [];
|
|
164
221
|
}
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
return
|
|
168
|
-
cacheKey: urlObject.href,
|
|
169
|
-
url: urlObject.href
|
|
170
|
-
};
|
|
222
|
+
async getEntryCountByQueueName(queueName) {
|
|
223
|
+
const db = await this.getDb();
|
|
224
|
+
return db.countFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
|
|
171
225
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
cacheKey: cacheKeyURL.href,
|
|
177
|
-
url: originalURL.href
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const logGroup = (groupTitle, deletedURLs)=>{
|
|
182
|
-
logger.groupCollapsed(groupTitle);
|
|
183
|
-
for (const url of deletedURLs){
|
|
184
|
-
logger.log(url);
|
|
226
|
+
async deleteEntry(id) {
|
|
227
|
+
const db = await this.getDb();
|
|
228
|
+
await db.delete(REQUEST_OBJECT_STORE_NAME, id);
|
|
185
229
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const printCleanupDetails = (deletedURLs)=>{
|
|
189
|
-
const deletionCount = deletedURLs.length;
|
|
190
|
-
if (deletionCount > 0) {
|
|
191
|
-
logger.groupCollapsed(`During precaching cleanup, ${deletionCount} cached request${deletionCount === 1 ? " was" : "s were"} deleted.`);
|
|
192
|
-
logGroup("Deleted Cache Requests", deletedURLs);
|
|
193
|
-
logger.groupEnd();
|
|
230
|
+
async getFirstEntryByQueueName(queueName) {
|
|
231
|
+
return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), "next");
|
|
194
232
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
function _nestedGroup(groupTitle, urls) {
|
|
198
|
-
if (urls.length === 0) {
|
|
199
|
-
return;
|
|
233
|
+
async getLastEntryByQueueName(queueName) {
|
|
234
|
+
return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), "prev");
|
|
200
235
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
236
|
+
async getEndEntryFromIndex(query, direction) {
|
|
237
|
+
const db = await this.getDb();
|
|
238
|
+
const cursor = await db.transaction(REQUEST_OBJECT_STORE_NAME).store.index(QUEUE_NAME_INDEX).openCursor(query, direction);
|
|
239
|
+
return cursor?.value;
|
|
204
240
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (precachedCount || alreadyPrecachedCount) {
|
|
211
|
-
let message = `Precaching ${precachedCount} file${precachedCount === 1 ? "" : "s"}.`;
|
|
212
|
-
if (alreadyPrecachedCount > 0) {
|
|
213
|
-
message += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? " is" : "s are"} already cached.`;
|
|
241
|
+
async getDb() {
|
|
242
|
+
if (!this._db) {
|
|
243
|
+
this._db = await openDB(BACKGROUND_SYNC_DB_NAME, BACKGROUND_SYNC_DB_VERSION, {
|
|
244
|
+
upgrade: this._upgradeDb
|
|
245
|
+
});
|
|
214
246
|
}
|
|
215
|
-
|
|
216
|
-
_nestedGroup("View newly precached URLs.", urlsToPrecache);
|
|
217
|
-
_nestedGroup("View previously precached URLs.", urlsAlreadyPrecached);
|
|
218
|
-
logger.groupEnd();
|
|
247
|
+
return this._db;
|
|
219
248
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
notUpdatedURLs = [];
|
|
225
|
-
handlerWillStart = async ({ request, state })=>{
|
|
226
|
-
if (state) {
|
|
227
|
-
state.originalRequest = request;
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
cachedResponseWillBeUsed = async ({ event, state, cachedResponse })=>{
|
|
231
|
-
if (event.type === "install") {
|
|
232
|
-
if (state?.originalRequest && state.originalRequest instanceof Request) {
|
|
233
|
-
const url = state.originalRequest.url;
|
|
234
|
-
if (cachedResponse) {
|
|
235
|
-
this.notUpdatedURLs.push(url);
|
|
236
|
-
} else {
|
|
237
|
-
this.updatedURLs.push(url);
|
|
238
|
-
}
|
|
249
|
+
_upgradeDb(db, oldVersion) {
|
|
250
|
+
if (oldVersion > 0 && oldVersion < BACKGROUND_SYNC_DB_VERSION) {
|
|
251
|
+
if (db.objectStoreNames.contains(REQUEST_OBJECT_STORE_NAME)) {
|
|
252
|
+
db.deleteObjectStore(REQUEST_OBJECT_STORE_NAME);
|
|
239
253
|
}
|
|
240
254
|
}
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
const objStore = db.createObjectStore(REQUEST_OBJECT_STORE_NAME, {
|
|
256
|
+
autoIncrement: true,
|
|
257
|
+
keyPath: "id"
|
|
258
|
+
});
|
|
259
|
+
objStore.createIndex(QUEUE_NAME_INDEX, QUEUE_NAME_INDEX, {
|
|
260
|
+
unique: false
|
|
261
|
+
});
|
|
262
|
+
}
|
|
243
263
|
}
|
|
244
264
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return urlObject;
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
function* generateURLVariations(url, { directoryIndex = "index.html", ignoreURLParametersMatching = [
|
|
257
|
-
/^utm_/,
|
|
258
|
-
/^fbclid$/
|
|
259
|
-
], cleanURLs = true, urlManipulation } = {}) {
|
|
260
|
-
const urlObject = new URL(url, location.href);
|
|
261
|
-
urlObject.hash = "";
|
|
262
|
-
yield urlObject.href;
|
|
263
|
-
const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching);
|
|
264
|
-
yield urlWithoutIgnoredParams.href;
|
|
265
|
-
if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith("/")) {
|
|
266
|
-
const directoryURL = new URL(urlWithoutIgnoredParams.href);
|
|
267
|
-
directoryURL.pathname += directoryIndex;
|
|
268
|
-
yield directoryURL.href;
|
|
265
|
+
class BackgroundSyncQueueStore {
|
|
266
|
+
_queueName;
|
|
267
|
+
_queueDb;
|
|
268
|
+
constructor(queueName){
|
|
269
|
+
this._queueName = queueName;
|
|
270
|
+
this._queueDb = new BackgroundSyncQueueDb();
|
|
269
271
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
async pushEntry(entry) {
|
|
273
|
+
if (process.env.NODE_ENV !== "production") {
|
|
274
|
+
finalAssertExports.isType(entry, "object", {
|
|
275
|
+
moduleName: "serwist",
|
|
276
|
+
className: "BackgroundSyncQueueStore",
|
|
277
|
+
funcName: "pushEntry",
|
|
278
|
+
paramName: "entry"
|
|
279
|
+
});
|
|
280
|
+
finalAssertExports.isType(entry.requestData, "object", {
|
|
281
|
+
moduleName: "serwist",
|
|
282
|
+
className: "BackgroundSyncQueueStore",
|
|
283
|
+
funcName: "pushEntry",
|
|
284
|
+
paramName: "entry.requestData"
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
delete entry.id;
|
|
288
|
+
entry.queueName = this._queueName;
|
|
289
|
+
await this._queueDb.addEntry(entry);
|
|
274
290
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
291
|
+
async unshiftEntry(entry) {
|
|
292
|
+
if (process.env.NODE_ENV !== "production") {
|
|
293
|
+
finalAssertExports.isType(entry, "object", {
|
|
294
|
+
moduleName: "serwist",
|
|
295
|
+
className: "BackgroundSyncQueueStore",
|
|
296
|
+
funcName: "unshiftEntry",
|
|
297
|
+
paramName: "entry"
|
|
298
|
+
});
|
|
299
|
+
finalAssertExports.isType(entry.requestData, "object", {
|
|
300
|
+
moduleName: "serwist",
|
|
301
|
+
className: "BackgroundSyncQueueStore",
|
|
302
|
+
funcName: "unshiftEntry",
|
|
303
|
+
paramName: "entry.requestData"
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
const firstId = await this._queueDb.getFirstEntryId();
|
|
307
|
+
if (firstId) {
|
|
308
|
+
entry.id = firstId - 1;
|
|
309
|
+
} else {
|
|
310
|
+
delete entry.id;
|
|
281
311
|
}
|
|
312
|
+
entry.queueName = this._queueName;
|
|
313
|
+
await this._queueDb.addEntry(entry);
|
|
282
314
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
};
|
|
304
|
-
super(match, controller.strategy);
|
|
315
|
+
async popEntry() {
|
|
316
|
+
return this._removeEntry(await this._queueDb.getLastEntryByQueueName(this._queueName));
|
|
317
|
+
}
|
|
318
|
+
async shiftEntry() {
|
|
319
|
+
return this._removeEntry(await this._queueDb.getFirstEntryByQueueName(this._queueName));
|
|
320
|
+
}
|
|
321
|
+
async getAll() {
|
|
322
|
+
return await this._queueDb.getAllEntriesByQueueName(this._queueName);
|
|
323
|
+
}
|
|
324
|
+
async size() {
|
|
325
|
+
return await this._queueDb.getEntryCountByQueueName(this._queueName);
|
|
326
|
+
}
|
|
327
|
+
async deleteEntry(id) {
|
|
328
|
+
await this._queueDb.deleteEntry(id);
|
|
329
|
+
}
|
|
330
|
+
async _removeEntry(entry) {
|
|
331
|
+
if (entry) {
|
|
332
|
+
await this.deleteEntry(entry.id);
|
|
333
|
+
}
|
|
334
|
+
return entry;
|
|
305
335
|
}
|
|
306
336
|
}
|
|
307
337
|
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
338
|
+
const serializableProperties = [
|
|
339
|
+
"method",
|
|
340
|
+
"referrer",
|
|
341
|
+
"referrerPolicy",
|
|
342
|
+
"mode",
|
|
343
|
+
"credentials",
|
|
344
|
+
"cache",
|
|
345
|
+
"redirect",
|
|
346
|
+
"integrity",
|
|
347
|
+
"keepalive"
|
|
348
|
+
];
|
|
349
|
+
class StorableRequest {
|
|
350
|
+
_requestData;
|
|
351
|
+
static async fromRequest(request) {
|
|
352
|
+
const requestData = {
|
|
353
|
+
url: request.url,
|
|
354
|
+
headers: {}
|
|
355
|
+
};
|
|
356
|
+
if (request.method !== "GET") {
|
|
357
|
+
requestData.body = await request.clone().arrayBuffer();
|
|
358
|
+
}
|
|
359
|
+
request.headers.forEach((value, key)=>{
|
|
360
|
+
requestData.headers[key] = value;
|
|
317
361
|
});
|
|
362
|
+
for (const prop of serializableProperties){
|
|
363
|
+
if (request[prop] !== undefined) {
|
|
364
|
+
requestData[prop] = request[prop];
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return new StorableRequest(requestData);
|
|
318
368
|
}
|
|
319
|
-
|
|
320
|
-
const responseInit = {
|
|
321
|
-
headers: new Headers(clonedResponse.headers),
|
|
322
|
-
status: clonedResponse.status,
|
|
323
|
-
statusText: clonedResponse.statusText
|
|
324
|
-
};
|
|
325
|
-
const modifiedResponseInit = modifier ? modifier(responseInit) : responseInit;
|
|
326
|
-
const body = canConstructResponseFromBodyStream() ? clonedResponse.body : await clonedResponse.blob();
|
|
327
|
-
return new Response(body, modifiedResponseInit);
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
function toRequest(input) {
|
|
331
|
-
return typeof input === "string" ? new Request(input) : input;
|
|
332
|
-
}
|
|
333
|
-
class StrategyHandler {
|
|
334
|
-
event;
|
|
335
|
-
request;
|
|
336
|
-
url;
|
|
337
|
-
params;
|
|
338
|
-
_cacheKeys = {};
|
|
339
|
-
_strategy;
|
|
340
|
-
_handlerDeferred;
|
|
341
|
-
_extendLifetimePromises;
|
|
342
|
-
_plugins;
|
|
343
|
-
_pluginStateMap;
|
|
344
|
-
constructor(strategy, options){
|
|
369
|
+
constructor(requestData){
|
|
345
370
|
if (process.env.NODE_ENV !== "production") {
|
|
346
|
-
finalAssertExports.
|
|
371
|
+
finalAssertExports.isType(requestData, "object", {
|
|
347
372
|
moduleName: "serwist",
|
|
348
|
-
className: "
|
|
373
|
+
className: "StorableRequest",
|
|
349
374
|
funcName: "constructor",
|
|
350
|
-
paramName: "
|
|
375
|
+
paramName: "requestData"
|
|
351
376
|
});
|
|
352
|
-
finalAssertExports.
|
|
377
|
+
finalAssertExports.isType(requestData.url, "string", {
|
|
353
378
|
moduleName: "serwist",
|
|
354
|
-
className: "
|
|
379
|
+
className: "StorableRequest",
|
|
355
380
|
funcName: "constructor",
|
|
356
|
-
paramName: "
|
|
381
|
+
paramName: "requestData.url"
|
|
357
382
|
});
|
|
358
383
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (options.url) {
|
|
362
|
-
this.url = options.url;
|
|
363
|
-
this.params = options.params;
|
|
384
|
+
if (requestData.mode === "navigate") {
|
|
385
|
+
requestData.mode = "same-origin";
|
|
364
386
|
}
|
|
365
|
-
this.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
for (const plugin of this._plugins){
|
|
373
|
-
this._pluginStateMap.set(plugin, {});
|
|
387
|
+
this._requestData = requestData;
|
|
388
|
+
}
|
|
389
|
+
toObject() {
|
|
390
|
+
const requestData = Object.assign({}, this._requestData);
|
|
391
|
+
requestData.headers = Object.assign({}, this._requestData.headers);
|
|
392
|
+
if (requestData.body) {
|
|
393
|
+
requestData.body = requestData.body.slice(0);
|
|
374
394
|
}
|
|
375
|
-
|
|
395
|
+
return requestData;
|
|
376
396
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
return fetchResponse;
|
|
414
|
-
} catch (error) {
|
|
415
|
-
if (process.env.NODE_ENV !== "production") {
|
|
416
|
-
logger.log(`Network request for '${getFriendlyURL(request.url)}' threw an error.`, error);
|
|
417
|
-
}
|
|
418
|
-
if (originalRequest) {
|
|
419
|
-
await this.runCallbacks("fetchDidFail", {
|
|
420
|
-
error: error,
|
|
421
|
-
event,
|
|
422
|
-
originalRequest: originalRequest.clone(),
|
|
423
|
-
request: pluginFilteredRequest.clone()
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
throw error;
|
|
397
|
+
toRequest() {
|
|
398
|
+
return new Request(this._requestData.url, this._requestData);
|
|
399
|
+
}
|
|
400
|
+
clone() {
|
|
401
|
+
return new StorableRequest(this.toObject());
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const TAG_PREFIX = "serwist-background-sync";
|
|
406
|
+
const MAX_RETENTION_TIME$1 = 60 * 24 * 7;
|
|
407
|
+
const queueNames = new Set();
|
|
408
|
+
const convertEntry = (queueStoreEntry)=>{
|
|
409
|
+
const queueEntry = {
|
|
410
|
+
request: new StorableRequest(queueStoreEntry.requestData).toRequest(),
|
|
411
|
+
timestamp: queueStoreEntry.timestamp
|
|
412
|
+
};
|
|
413
|
+
if (queueStoreEntry.metadata) {
|
|
414
|
+
queueEntry.metadata = queueStoreEntry.metadata;
|
|
415
|
+
}
|
|
416
|
+
return queueEntry;
|
|
417
|
+
};
|
|
418
|
+
class BackgroundSyncQueue {
|
|
419
|
+
_name;
|
|
420
|
+
_onSync;
|
|
421
|
+
_maxRetentionTime;
|
|
422
|
+
_queueStore;
|
|
423
|
+
_forceSyncFallback;
|
|
424
|
+
_syncInProgress = false;
|
|
425
|
+
_requestsAddedDuringSync = false;
|
|
426
|
+
constructor(name, { forceSyncFallback, onSync, maxRetentionTime } = {}){
|
|
427
|
+
if (queueNames.has(name)) {
|
|
428
|
+
throw new SerwistError("duplicate-queue-name", {
|
|
429
|
+
name
|
|
430
|
+
});
|
|
427
431
|
}
|
|
432
|
+
queueNames.add(name);
|
|
433
|
+
this._name = name;
|
|
434
|
+
this._onSync = onSync || this.replayRequests;
|
|
435
|
+
this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME$1;
|
|
436
|
+
this._forceSyncFallback = Boolean(forceSyncFallback);
|
|
437
|
+
this._queueStore = new BackgroundSyncQueueStore(this._name);
|
|
438
|
+
this._addSyncListener();
|
|
428
439
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const responseClone = response.clone();
|
|
432
|
-
void this.waitUntil(this.cachePut(input, responseClone));
|
|
433
|
-
return response;
|
|
440
|
+
get name() {
|
|
441
|
+
return this._name;
|
|
434
442
|
}
|
|
435
|
-
async
|
|
436
|
-
const request = toRequest(key);
|
|
437
|
-
let cachedResponse;
|
|
438
|
-
const { cacheName, matchOptions } = this._strategy;
|
|
439
|
-
const effectiveRequest = await this.getCacheKey(request, "read");
|
|
440
|
-
const multiMatchOptions = {
|
|
441
|
-
...matchOptions,
|
|
442
|
-
...{
|
|
443
|
-
cacheName
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);
|
|
443
|
+
async pushRequest(entry) {
|
|
447
444
|
if (process.env.NODE_ENV !== "production") {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
event: this.event
|
|
461
|
-
}) || undefined;
|
|
445
|
+
finalAssertExports.isType(entry, "object", {
|
|
446
|
+
moduleName: "serwist",
|
|
447
|
+
className: "BackgroundSyncQueue",
|
|
448
|
+
funcName: "pushRequest",
|
|
449
|
+
paramName: "entry"
|
|
450
|
+
});
|
|
451
|
+
finalAssertExports.isInstance(entry.request, Request, {
|
|
452
|
+
moduleName: "serwist",
|
|
453
|
+
className: "BackgroundSyncQueue",
|
|
454
|
+
funcName: "pushRequest",
|
|
455
|
+
paramName: "entry.request"
|
|
456
|
+
});
|
|
462
457
|
}
|
|
463
|
-
|
|
458
|
+
await this._addRequest(entry, "push");
|
|
464
459
|
}
|
|
465
|
-
async
|
|
466
|
-
const request = toRequest(key);
|
|
467
|
-
await timeout(0);
|
|
468
|
-
const effectiveRequest = await this.getCacheKey(request, "write");
|
|
460
|
+
async unshiftRequest(entry) {
|
|
469
461
|
if (process.env.NODE_ENV !== "production") {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
throw new SerwistError("cache-put-with-no-response", {
|
|
482
|
-
url: getFriendlyURL(effectiveRequest.url)
|
|
462
|
+
finalAssertExports.isType(entry, "object", {
|
|
463
|
+
moduleName: "serwist",
|
|
464
|
+
className: "BackgroundSyncQueue",
|
|
465
|
+
funcName: "unshiftRequest",
|
|
466
|
+
paramName: "entry"
|
|
467
|
+
});
|
|
468
|
+
finalAssertExports.isInstance(entry.request, Request, {
|
|
469
|
+
moduleName: "serwist",
|
|
470
|
+
className: "BackgroundSyncQueue",
|
|
471
|
+
funcName: "unshiftRequest",
|
|
472
|
+
paramName: "entry.request"
|
|
483
473
|
});
|
|
484
474
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
475
|
+
await this._addRequest(entry, "unshift");
|
|
476
|
+
}
|
|
477
|
+
async popRequest() {
|
|
478
|
+
return this._removeRequest("pop");
|
|
479
|
+
}
|
|
480
|
+
async shiftRequest() {
|
|
481
|
+
return this._removeRequest("shift");
|
|
482
|
+
}
|
|
483
|
+
async getAll() {
|
|
484
|
+
const allEntries = await this._queueStore.getAll();
|
|
485
|
+
const now = Date.now();
|
|
486
|
+
const unexpiredEntries = [];
|
|
487
|
+
for (const entry of allEntries){
|
|
488
|
+
const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
|
|
489
|
+
if (now - entry.timestamp > maxRetentionTimeInMs) {
|
|
490
|
+
await this._queueStore.deleteEntry(entry.id);
|
|
491
|
+
} else {
|
|
492
|
+
unexpiredEntries.push(convertEntry(entry));
|
|
489
493
|
}
|
|
490
|
-
return false;
|
|
491
494
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
495
|
+
return unexpiredEntries;
|
|
496
|
+
}
|
|
497
|
+
async size() {
|
|
498
|
+
return await this._queueStore.size();
|
|
499
|
+
}
|
|
500
|
+
async _addRequest({ request, metadata, timestamp = Date.now() }, operation) {
|
|
501
|
+
const storableRequest = await StorableRequest.fromRequest(request.clone());
|
|
502
|
+
const entry = {
|
|
503
|
+
requestData: storableRequest.toObject(),
|
|
504
|
+
timestamp
|
|
505
|
+
};
|
|
506
|
+
if (metadata) {
|
|
507
|
+
entry.metadata = metadata;
|
|
499
508
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
509
|
+
switch(operation){
|
|
510
|
+
case "push":
|
|
511
|
+
await this._queueStore.pushEntry(entry);
|
|
512
|
+
break;
|
|
513
|
+
case "unshift":
|
|
514
|
+
await this._queueStore.unshiftEntry(entry);
|
|
515
|
+
break;
|
|
506
516
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
} catch (error) {
|
|
510
|
-
if (error instanceof Error) {
|
|
511
|
-
if (error.name === "QuotaExceededError") {
|
|
512
|
-
await executeQuotaErrorCallbacks();
|
|
513
|
-
}
|
|
514
|
-
throw error;
|
|
515
|
-
}
|
|
517
|
+
if (process.env.NODE_ENV !== "production") {
|
|
518
|
+
logger.log(`Request for '${getFriendlyURL(request.url)}' has ` + `been added to background sync queue '${this._name}'.`);
|
|
516
519
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
newResponse: responseToCache.clone(),
|
|
522
|
-
request: effectiveRequest,
|
|
523
|
-
event: this.event
|
|
524
|
-
});
|
|
520
|
+
if (this._syncInProgress) {
|
|
521
|
+
this._requestsAddedDuringSync = true;
|
|
522
|
+
} else {
|
|
523
|
+
await this.registerSync();
|
|
525
524
|
}
|
|
526
|
-
return true;
|
|
527
525
|
}
|
|
528
|
-
async
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
526
|
+
async _removeRequest(operation) {
|
|
527
|
+
const now = Date.now();
|
|
528
|
+
let entry;
|
|
529
|
+
switch(operation){
|
|
530
|
+
case "pop":
|
|
531
|
+
entry = await this._queueStore.popEntry();
|
|
532
|
+
break;
|
|
533
|
+
case "shift":
|
|
534
|
+
entry = await this._queueStore.shiftEntry();
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
if (entry) {
|
|
538
|
+
const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
|
|
539
|
+
if (now - entry.timestamp > maxRetentionTimeInMs) {
|
|
540
|
+
return this._removeRequest(operation);
|
|
539
541
|
}
|
|
540
|
-
|
|
542
|
+
return convertEntry(entry);
|
|
541
543
|
}
|
|
542
|
-
return
|
|
544
|
+
return undefined;
|
|
543
545
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
546
|
+
async replayRequests() {
|
|
547
|
+
let entry;
|
|
548
|
+
while(entry = await this.shiftRequest()){
|
|
549
|
+
try {
|
|
550
|
+
await fetch(entry.request.clone());
|
|
551
|
+
if (process.env.NODE_ENV !== "production") {
|
|
552
|
+
logger.log(`Request for '${getFriendlyURL(entry.request.url)}' ` + `has been replayed in queue '${this._name}'`);
|
|
553
|
+
}
|
|
554
|
+
} catch {
|
|
555
|
+
await this.unshiftRequest(entry);
|
|
556
|
+
if (process.env.NODE_ENV !== "production") {
|
|
557
|
+
logger.log(`Request for '${getFriendlyURL(entry.request.url)}' ` + `failed to replay, putting it back in queue '${this._name}'`);
|
|
558
|
+
}
|
|
559
|
+
throw new SerwistError("queue-replay-failed", {
|
|
560
|
+
name: this._name
|
|
561
|
+
});
|
|
548
562
|
}
|
|
549
563
|
}
|
|
550
|
-
|
|
564
|
+
if (process.env.NODE_ENV !== "production") {
|
|
565
|
+
logger.log(`All requests in queue '${this.name}' have successfully replayed; the queue is now empty!`);
|
|
566
|
+
}
|
|
551
567
|
}
|
|
552
|
-
async
|
|
553
|
-
|
|
554
|
-
await callback(param);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
*iterateCallbacks(name) {
|
|
558
|
-
for (const plugin of this._strategy.plugins){
|
|
559
|
-
if (typeof plugin[name] === "function") {
|
|
560
|
-
const state = this._pluginStateMap.get(plugin);
|
|
561
|
-
const statefulCallback = (param)=>{
|
|
562
|
-
const statefulParam = {
|
|
563
|
-
...param,
|
|
564
|
-
state
|
|
565
|
-
};
|
|
566
|
-
return plugin[name](statefulParam);
|
|
567
|
-
};
|
|
568
|
-
yield statefulCallback;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
waitUntil(promise) {
|
|
573
|
-
this._extendLifetimePromises.push(promise);
|
|
574
|
-
return promise;
|
|
575
|
-
}
|
|
576
|
-
async doneWaiting() {
|
|
577
|
-
let promise = undefined;
|
|
578
|
-
while(promise = this._extendLifetimePromises.shift()){
|
|
579
|
-
await promise;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
destroy() {
|
|
583
|
-
this._handlerDeferred.resolve(null);
|
|
584
|
-
}
|
|
585
|
-
async getPreloadResponse() {
|
|
586
|
-
if (this.event instanceof FetchEvent && this.event.request.mode === "navigate" && "preloadResponse" in this.event) {
|
|
568
|
+
async registerSync() {
|
|
569
|
+
if ("sync" in self.registration && !this._forceSyncFallback) {
|
|
587
570
|
try {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (process.env.NODE_ENV !== "production") {
|
|
591
|
-
logger.log(`Using a preloaded navigation response for '${getFriendlyURL(this.event.request.url)}'`);
|
|
592
|
-
}
|
|
593
|
-
return possiblePreloadResponse;
|
|
594
|
-
}
|
|
595
|
-
} catch (error) {
|
|
571
|
+
await self.registration.sync.register(`${TAG_PREFIX}:${this._name}`);
|
|
572
|
+
} catch (err) {
|
|
596
573
|
if (process.env.NODE_ENV !== "production") {
|
|
597
|
-
logger.
|
|
574
|
+
logger.warn(`Unable to register sync event for '${this._name}'.`, err);
|
|
598
575
|
}
|
|
599
|
-
return undefined;
|
|
600
576
|
}
|
|
601
577
|
}
|
|
602
|
-
return undefined;
|
|
603
578
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
response: responseToCache,
|
|
611
|
-
event: this.event
|
|
612
|
-
}) || undefined;
|
|
613
|
-
pluginsUsed = true;
|
|
614
|
-
if (!responseToCache) {
|
|
615
|
-
break;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
if (!pluginsUsed) {
|
|
619
|
-
if (responseToCache && responseToCache.status !== 200) {
|
|
620
|
-
if (process.env.NODE_ENV !== "production") {
|
|
621
|
-
if (responseToCache.status === 0) {
|
|
622
|
-
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.`);
|
|
623
|
-
} else {
|
|
624
|
-
logger.debug(`The response for '${this.request.url}' returned a status code of '${response.status}' and won't be cached as a result.`);
|
|
579
|
+
_addSyncListener() {
|
|
580
|
+
if ("sync" in self.registration && !this._forceSyncFallback) {
|
|
581
|
+
self.addEventListener("sync", (event)=>{
|
|
582
|
+
if (event.tag === `${TAG_PREFIX}:${this._name}`) {
|
|
583
|
+
if (process.env.NODE_ENV !== "production") {
|
|
584
|
+
logger.log(`Background sync for tag '${event.tag}' has been received`);
|
|
625
585
|
}
|
|
586
|
+
const syncComplete = async ()=>{
|
|
587
|
+
this._syncInProgress = true;
|
|
588
|
+
let syncError;
|
|
589
|
+
try {
|
|
590
|
+
await this._onSync({
|
|
591
|
+
queue: this
|
|
592
|
+
});
|
|
593
|
+
} catch (error) {
|
|
594
|
+
if (error instanceof Error) {
|
|
595
|
+
syncError = error;
|
|
596
|
+
throw syncError;
|
|
597
|
+
}
|
|
598
|
+
} finally{
|
|
599
|
+
if (this._requestsAddedDuringSync && !(syncError && !event.lastChance)) {
|
|
600
|
+
await this.registerSync();
|
|
601
|
+
}
|
|
602
|
+
this._syncInProgress = false;
|
|
603
|
+
this._requestsAddedDuringSync = false;
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
event.waitUntil(syncComplete());
|
|
626
607
|
}
|
|
627
|
-
|
|
608
|
+
});
|
|
609
|
+
} else {
|
|
610
|
+
if (process.env.NODE_ENV !== "production") {
|
|
611
|
+
logger.log("Background sync replaying without background sync event");
|
|
628
612
|
}
|
|
613
|
+
void this._onSync({
|
|
614
|
+
queue: this
|
|
615
|
+
});
|
|
629
616
|
}
|
|
630
|
-
|
|
617
|
+
}
|
|
618
|
+
static get _queueNames() {
|
|
619
|
+
return queueNames;
|
|
631
620
|
}
|
|
632
621
|
}
|
|
633
622
|
|
|
634
|
-
class
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
matchOptions;
|
|
639
|
-
constructor(options = {}){
|
|
640
|
-
this.cacheName = cacheNames$1.getRuntimeName(options.cacheName);
|
|
641
|
-
this.plugins = options.plugins || [];
|
|
642
|
-
this.fetchOptions = options.fetchOptions;
|
|
643
|
-
this.matchOptions = options.matchOptions;
|
|
644
|
-
}
|
|
645
|
-
handle(options) {
|
|
646
|
-
const [responseDone] = this.handleAll(options);
|
|
647
|
-
return responseDone;
|
|
623
|
+
class BackgroundSyncPlugin {
|
|
624
|
+
_queue;
|
|
625
|
+
constructor(name, options){
|
|
626
|
+
this._queue = new BackgroundSyncQueue(name, options);
|
|
648
627
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
options = {
|
|
652
|
-
event: options,
|
|
653
|
-
request: options.request
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
const event = options.event;
|
|
657
|
-
const request = typeof options.request === "string" ? new Request(options.request) : options.request;
|
|
658
|
-
const handler = new StrategyHandler(this, options.url ? {
|
|
659
|
-
event,
|
|
660
|
-
request,
|
|
661
|
-
url: options.url,
|
|
662
|
-
params: options.params
|
|
663
|
-
} : {
|
|
664
|
-
event,
|
|
628
|
+
async fetchDidFail({ request }) {
|
|
629
|
+
await this._queue.pushRequest({
|
|
665
630
|
request
|
|
666
631
|
});
|
|
667
|
-
const responseDone = this._getResponse(handler, request, event);
|
|
668
|
-
const handlerDone = this._awaitComplete(responseDone, handler, request, event);
|
|
669
|
-
return [
|
|
670
|
-
responseDone,
|
|
671
|
-
handlerDone
|
|
672
|
-
];
|
|
673
632
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const parseRoute = (capture, handler, method)=>{
|
|
636
|
+
if (typeof capture === "string") {
|
|
637
|
+
const captureUrl = new URL(capture, location.href);
|
|
638
|
+
if (process.env.NODE_ENV !== "production") {
|
|
639
|
+
if (!(capture.startsWith("/") || capture.startsWith("http"))) {
|
|
640
|
+
throw new SerwistError("invalid-string", {
|
|
641
|
+
moduleName: "serwist",
|
|
642
|
+
funcName: "parseRoute",
|
|
643
|
+
paramName: "capture"
|
|
685
644
|
});
|
|
686
645
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
error,
|
|
692
|
-
event,
|
|
693
|
-
request
|
|
694
|
-
});
|
|
695
|
-
if (response !== undefined) {
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
if (!response) {
|
|
701
|
-
throw error;
|
|
646
|
+
const valueToCheck = capture.startsWith("http") ? captureUrl.pathname : capture;
|
|
647
|
+
const wildcards = "[*:?+]";
|
|
648
|
+
if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
|
|
649
|
+
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.`);
|
|
702
650
|
}
|
|
651
|
+
}
|
|
652
|
+
const matchCallback = ({ url })=>{
|
|
703
653
|
if (process.env.NODE_ENV !== "production") {
|
|
704
|
-
|
|
654
|
+
if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
|
|
655
|
+
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.`);
|
|
656
|
+
}
|
|
705
657
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
event,
|
|
710
|
-
request,
|
|
711
|
-
response
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
return response;
|
|
658
|
+
return url.href === captureUrl.href;
|
|
659
|
+
};
|
|
660
|
+
return new Route(matchCallback, handler, method);
|
|
715
661
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
let error = undefined;
|
|
719
|
-
try {
|
|
720
|
-
response = await responseDone;
|
|
721
|
-
} catch (error) {}
|
|
722
|
-
try {
|
|
723
|
-
await handler.runCallbacks("handlerDidRespond", {
|
|
724
|
-
event,
|
|
725
|
-
request,
|
|
726
|
-
response
|
|
727
|
-
});
|
|
728
|
-
await handler.doneWaiting();
|
|
729
|
-
} catch (waitUntilError) {
|
|
730
|
-
if (waitUntilError instanceof Error) {
|
|
731
|
-
error = waitUntilError;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
await handler.runCallbacks("handlerDidComplete", {
|
|
735
|
-
event,
|
|
736
|
-
request,
|
|
737
|
-
response,
|
|
738
|
-
error
|
|
739
|
-
});
|
|
740
|
-
handler.destroy();
|
|
741
|
-
if (error) {
|
|
742
|
-
throw error;
|
|
743
|
-
}
|
|
662
|
+
if (capture instanceof RegExp) {
|
|
663
|
+
return new RegExpRoute(capture, handler, method);
|
|
744
664
|
}
|
|
745
|
-
|
|
665
|
+
if (typeof capture === "function") {
|
|
666
|
+
return new Route(capture, handler, method);
|
|
667
|
+
}
|
|
668
|
+
if (capture instanceof Route) {
|
|
669
|
+
return capture;
|
|
670
|
+
}
|
|
671
|
+
throw new SerwistError("unsupported-route-type", {
|
|
672
|
+
moduleName: "serwist",
|
|
673
|
+
funcName: "parseRoute",
|
|
674
|
+
paramName: "capture"
|
|
675
|
+
});
|
|
676
|
+
};
|
|
746
677
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
678
|
+
const registerCapture = (state, capture, handler, method)=>{
|
|
679
|
+
const route = parseRoute(capture, handler, method);
|
|
680
|
+
registerRoute(state, route);
|
|
681
|
+
return route;
|
|
682
|
+
};
|
|
683
|
+
const registerRoute = (state, route)=>{
|
|
684
|
+
if (process.env.NODE_ENV !== "production") {
|
|
685
|
+
finalAssertExports.isType(route, "object", {
|
|
686
|
+
moduleName: "serwist",
|
|
687
|
+
className: "Serwist",
|
|
688
|
+
funcName: "registerRoute",
|
|
689
|
+
paramName: "route"
|
|
690
|
+
});
|
|
691
|
+
finalAssertExports.hasMethod(route, "match", {
|
|
692
|
+
moduleName: "serwist",
|
|
693
|
+
className: "Serwist",
|
|
694
|
+
funcName: "registerRoute",
|
|
695
|
+
paramName: "route"
|
|
696
|
+
});
|
|
697
|
+
finalAssertExports.isType(route.handler, "object", {
|
|
698
|
+
moduleName: "serwist",
|
|
699
|
+
className: "Serwist",
|
|
700
|
+
funcName: "registerRoute",
|
|
701
|
+
paramName: "route"
|
|
702
|
+
});
|
|
703
|
+
finalAssertExports.hasMethod(route.handler, "handle", {
|
|
704
|
+
moduleName: "serwist",
|
|
705
|
+
className: "Serwist",
|
|
706
|
+
funcName: "registerRoute",
|
|
707
|
+
paramName: "route.handler"
|
|
708
|
+
});
|
|
709
|
+
finalAssertExports.isType(route.method, "string", {
|
|
710
|
+
moduleName: "serwist",
|
|
711
|
+
className: "Serwist",
|
|
712
|
+
funcName: "registerRoute",
|
|
713
|
+
paramName: "route.method"
|
|
714
|
+
});
|
|
767
715
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
716
|
+
if (!state.routes.has(route.method)) {
|
|
717
|
+
state.routes.set(route.method, []);
|
|
718
|
+
}
|
|
719
|
+
state.routes.get(route.method).push(route);
|
|
720
|
+
};
|
|
721
|
+
const unregisterRoute = (state, route)=>{
|
|
722
|
+
if (!state.routes.has(route.method)) {
|
|
723
|
+
throw new SerwistError("unregister-route-but-not-found-with-method", {
|
|
724
|
+
method: route.method
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
const routeIndex = state.routes.get(route.method).indexOf(route);
|
|
728
|
+
if (routeIndex > -1) {
|
|
729
|
+
state.routes.get(route.method).splice(routeIndex, 1);
|
|
730
|
+
} else {
|
|
731
|
+
throw new SerwistError("unregister-route-route-not-registered");
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
const handleRequest = (state, { request, event })=>{
|
|
735
|
+
if (process.env.NODE_ENV !== "production") {
|
|
736
|
+
finalAssertExports.isInstance(request, Request, {
|
|
737
|
+
moduleName: "serwist",
|
|
738
|
+
className: "Serwist",
|
|
739
|
+
funcName: "handleRequest",
|
|
740
|
+
paramName: "options.request"
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
const url = new URL(request.url, location.href);
|
|
744
|
+
if (!url.protocol.startsWith("http")) {
|
|
745
|
+
if (process.env.NODE_ENV !== "production") {
|
|
746
|
+
logger.debug("Router only supports URLs that start with 'http'.");
|
|
779
747
|
}
|
|
780
|
-
return
|
|
748
|
+
return;
|
|
781
749
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
}
|
|
750
|
+
const sameOrigin = url.origin === location.origin;
|
|
751
|
+
const { params, route } = findMatchingRoute(state, {
|
|
752
|
+
event,
|
|
753
|
+
request,
|
|
754
|
+
sameOrigin,
|
|
755
|
+
url
|
|
756
|
+
});
|
|
757
|
+
let handler = route?.handler;
|
|
758
|
+
const debugMessages = [];
|
|
759
|
+
if (process.env.NODE_ENV !== "production") {
|
|
760
|
+
if (handler) {
|
|
761
|
+
debugMessages.push([
|
|
762
|
+
"Found a route to handle this request:",
|
|
763
|
+
route
|
|
764
|
+
]);
|
|
765
|
+
if (params) {
|
|
766
|
+
debugMessages.push([
|
|
767
|
+
`Passing the following params to the route's handler:`,
|
|
768
|
+
params
|
|
769
|
+
]);
|
|
803
770
|
}
|
|
804
|
-
} else {
|
|
805
|
-
throw new SerwistError("missing-precache-entry", {
|
|
806
|
-
cacheName: this.cacheName,
|
|
807
|
-
url: request.url
|
|
808
|
-
});
|
|
809
771
|
}
|
|
772
|
+
}
|
|
773
|
+
const method = request.method;
|
|
774
|
+
if (!handler && state.defaultHandlerMap.has(method)) {
|
|
810
775
|
if (process.env.NODE_ENV !== "production") {
|
|
811
|
-
|
|
812
|
-
logger.groupCollapsed(`Precaching is responding to: ${getFriendlyURL(request.url)}`);
|
|
813
|
-
logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`);
|
|
814
|
-
logger.groupCollapsed("View request details here.");
|
|
815
|
-
logger.log(request);
|
|
816
|
-
logger.groupEnd();
|
|
817
|
-
logger.groupCollapsed("View response details here.");
|
|
818
|
-
logger.log(response);
|
|
819
|
-
logger.groupEnd();
|
|
820
|
-
logger.groupEnd();
|
|
776
|
+
debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);
|
|
821
777
|
}
|
|
822
|
-
|
|
778
|
+
handler = state.defaultHandlerMap.get(method);
|
|
823
779
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
const wasCached = await handler.cachePut(request, response.clone());
|
|
828
|
-
if (!wasCached) {
|
|
829
|
-
throw new SerwistError("bad-precaching-response", {
|
|
830
|
-
url: request.url,
|
|
831
|
-
status: response.status
|
|
832
|
-
});
|
|
780
|
+
if (!handler) {
|
|
781
|
+
if (process.env.NODE_ENV !== "production") {
|
|
782
|
+
logger.debug(`No route found for: ${getFriendlyURL(url)}`);
|
|
833
783
|
}
|
|
834
|
-
return
|
|
784
|
+
return;
|
|
835
785
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
|
|
844
|
-
defaultPluginIndex = index;
|
|
845
|
-
}
|
|
846
|
-
if (plugin.cacheWillUpdate) {
|
|
847
|
-
cacheWillUpdatePluginCount++;
|
|
786
|
+
if (process.env.NODE_ENV !== "production") {
|
|
787
|
+
logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
|
|
788
|
+
for (const msg of debugMessages){
|
|
789
|
+
if (Array.isArray(msg)) {
|
|
790
|
+
logger.log(...msg);
|
|
791
|
+
} else {
|
|
792
|
+
logger.log(msg);
|
|
848
793
|
}
|
|
849
794
|
}
|
|
850
|
-
|
|
851
|
-
this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);
|
|
852
|
-
} else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {
|
|
853
|
-
this.plugins.splice(defaultPluginIndex, 1);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
class PrecacheCacheKeyPlugin {
|
|
859
|
-
_precacheController;
|
|
860
|
-
constructor({ precacheController }){
|
|
861
|
-
this._precacheController = precacheController;
|
|
862
|
-
}
|
|
863
|
-
cacheKeyWillBeUsed = async ({ request, params })=>{
|
|
864
|
-
const cacheKey = params?.cacheKey || this._precacheController.getPrecacheKeyForUrl(request.url);
|
|
865
|
-
return cacheKey ? new Request(cacheKey, {
|
|
866
|
-
headers: request.headers
|
|
867
|
-
}) : request;
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
const parsePrecacheOptions = (controller, { cacheName, plugins, fetchOptions, matchOptions, fallbackToNetwork, directoryIndex, ignoreURLParametersMatching, cleanURLs, urlManipulation, cleanupOutdatedCaches, concurrency, navigateFallback, navigateFallbackAllowlist, navigateFallbackDenylist } = {})=>({
|
|
872
|
-
strategyOptions: {
|
|
873
|
-
cacheName: cacheNames$1.getPrecacheName(cacheName),
|
|
874
|
-
plugins: [
|
|
875
|
-
...plugins ?? [],
|
|
876
|
-
new PrecacheCacheKeyPlugin({
|
|
877
|
-
precacheController: controller
|
|
878
|
-
})
|
|
879
|
-
],
|
|
880
|
-
fetchOptions,
|
|
881
|
-
matchOptions,
|
|
882
|
-
fallbackToNetwork
|
|
883
|
-
},
|
|
884
|
-
routeOptions: {
|
|
885
|
-
directoryIndex,
|
|
886
|
-
ignoreURLParametersMatching,
|
|
887
|
-
cleanURLs,
|
|
888
|
-
urlManipulation
|
|
889
|
-
},
|
|
890
|
-
controllerOptions: {
|
|
891
|
-
cleanupOutdatedCaches,
|
|
892
|
-
concurrency: concurrency ?? 10,
|
|
893
|
-
navigateFallback,
|
|
894
|
-
navigateFallbackAllowlist,
|
|
895
|
-
navigateFallbackDenylist
|
|
896
|
-
}
|
|
897
|
-
});
|
|
898
|
-
|
|
899
|
-
class PrecacheController {
|
|
900
|
-
_urlsToCacheKeys = new Map();
|
|
901
|
-
_urlsToCacheModes = new Map();
|
|
902
|
-
_cacheKeysToIntegrities = new Map();
|
|
903
|
-
_strategy;
|
|
904
|
-
_options;
|
|
905
|
-
_routeOptions;
|
|
906
|
-
constructor(entries, precacheOptions){
|
|
907
|
-
const { strategyOptions, routeOptions, controllerOptions } = parsePrecacheOptions(this, precacheOptions);
|
|
908
|
-
this.addToCacheList(entries);
|
|
909
|
-
this._strategy = new PrecacheStrategy(strategyOptions);
|
|
910
|
-
this._options = controllerOptions;
|
|
911
|
-
this._routeOptions = routeOptions;
|
|
795
|
+
logger.groupEnd();
|
|
912
796
|
}
|
|
913
|
-
|
|
914
|
-
|
|
797
|
+
let responsePromise;
|
|
798
|
+
try {
|
|
799
|
+
responsePromise = handler.handle({
|
|
800
|
+
url,
|
|
801
|
+
request,
|
|
802
|
+
event,
|
|
803
|
+
params
|
|
804
|
+
});
|
|
805
|
+
} catch (err) {
|
|
806
|
+
responsePromise = Promise.reject(err);
|
|
915
807
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
808
|
+
const catchHandler = route?.catchHandler;
|
|
809
|
+
if (responsePromise instanceof Promise && (state.catchHandler || catchHandler)) {
|
|
810
|
+
responsePromise = responsePromise.catch(async (err)=>{
|
|
811
|
+
if (catchHandler) {
|
|
812
|
+
if (process.env.NODE_ENV !== "production") {
|
|
813
|
+
logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
|
|
814
|
+
logger.error("Error thrown by:", route);
|
|
815
|
+
logger.error(err);
|
|
816
|
+
logger.groupEnd();
|
|
817
|
+
}
|
|
818
|
+
try {
|
|
819
|
+
return await catchHandler.handle({
|
|
820
|
+
url,
|
|
821
|
+
request,
|
|
822
|
+
event,
|
|
823
|
+
params
|
|
824
|
+
});
|
|
825
|
+
} catch (catchErr) {
|
|
826
|
+
if (catchErr instanceof Error) {
|
|
827
|
+
err = catchErr;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
931
830
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
831
|
+
if (state.catchHandler) {
|
|
832
|
+
if (process.env.NODE_ENV !== "production") {
|
|
833
|
+
logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
|
|
834
|
+
logger.error("Error thrown by:", route);
|
|
835
|
+
logger.error(err);
|
|
836
|
+
logger.groupEnd();
|
|
837
|
+
}
|
|
838
|
+
return state.catchHandler.handle({
|
|
839
|
+
url,
|
|
840
|
+
request,
|
|
841
|
+
event
|
|
938
842
|
});
|
|
939
843
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
844
|
+
throw err;
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
return responsePromise;
|
|
848
|
+
};
|
|
849
|
+
const findMatchingRoute = (state, { url, sameOrigin, request, event })=>{
|
|
850
|
+
const routes = state.routes.get(request.method) || [];
|
|
851
|
+
for (const route of routes){
|
|
852
|
+
let params;
|
|
853
|
+
const matchResult = route.match({
|
|
854
|
+
url,
|
|
855
|
+
sameOrigin,
|
|
856
|
+
request,
|
|
857
|
+
event
|
|
858
|
+
});
|
|
859
|
+
if (matchResult) {
|
|
860
|
+
if (process.env.NODE_ENV !== "production") {
|
|
861
|
+
if (matchResult instanceof Promise) {
|
|
862
|
+
logger.warn(`While routing ${getFriendlyURL(url)}, an async matchCallback function was used. Please convert the following route to use a synchronous matchCallback function:`, route);
|
|
945
863
|
}
|
|
946
|
-
this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);
|
|
947
864
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
logger.warn(warningMessage);
|
|
956
|
-
}
|
|
865
|
+
params = matchResult;
|
|
866
|
+
if (Array.isArray(params) && params.length === 0) {
|
|
867
|
+
params = undefined;
|
|
868
|
+
} else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {
|
|
869
|
+
params = undefined;
|
|
870
|
+
} else if (typeof matchResult === "boolean") {
|
|
871
|
+
params = undefined;
|
|
957
872
|
}
|
|
873
|
+
return {
|
|
874
|
+
route,
|
|
875
|
+
params
|
|
876
|
+
};
|
|
958
877
|
}
|
|
959
878
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
879
|
+
return {};
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
const cacheOkAndOpaquePlugin = {
|
|
883
|
+
cacheWillUpdate: async ({ response })=>{
|
|
884
|
+
if (response.status === 200 || response.status === 0) {
|
|
885
|
+
return response;
|
|
967
886
|
}
|
|
887
|
+
return null;
|
|
968
888
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
}
|
|
987
|
-
}));
|
|
988
|
-
});
|
|
989
|
-
const { updatedURLs, notUpdatedURLs } = installReportPlugin;
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
function toRequest(input) {
|
|
892
|
+
return typeof input === "string" ? new Request(input) : input;
|
|
893
|
+
}
|
|
894
|
+
class StrategyHandler {
|
|
895
|
+
event;
|
|
896
|
+
request;
|
|
897
|
+
url;
|
|
898
|
+
params;
|
|
899
|
+
_cacheKeys = {};
|
|
900
|
+
_strategy;
|
|
901
|
+
_handlerDeferred;
|
|
902
|
+
_extendLifetimePromises;
|
|
903
|
+
_plugins;
|
|
904
|
+
_pluginStateMap;
|
|
905
|
+
constructor(strategy, options){
|
|
990
906
|
if (process.env.NODE_ENV !== "production") {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
}
|
|
907
|
+
finalAssertExports.isInstance(options.event, ExtendableEvent, {
|
|
908
|
+
moduleName: "serwist",
|
|
909
|
+
className: "StrategyHandler",
|
|
910
|
+
funcName: "constructor",
|
|
911
|
+
paramName: "options.event"
|
|
912
|
+
});
|
|
913
|
+
finalAssertExports.isInstance(options.request, Request, {
|
|
914
|
+
moduleName: "serwist",
|
|
915
|
+
className: "StrategyHandler",
|
|
916
|
+
funcName: "constructor",
|
|
917
|
+
paramName: "options.request"
|
|
918
|
+
});
|
|
1004
919
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
920
|
+
this.event = options.event;
|
|
921
|
+
this.request = options.request;
|
|
922
|
+
if (options.url) {
|
|
923
|
+
this.url = options.url;
|
|
924
|
+
this.params = options.params;
|
|
1007
925
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
return [
|
|
1014
|
-
...this._urlsToCacheKeys.keys()
|
|
926
|
+
this._strategy = strategy;
|
|
927
|
+
this._handlerDeferred = new Deferred();
|
|
928
|
+
this._extendLifetimePromises = [];
|
|
929
|
+
this._plugins = [
|
|
930
|
+
...strategy.plugins
|
|
1015
931
|
];
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
return this._urlsToCacheKeys.get(urlObject.href);
|
|
1020
|
-
}
|
|
1021
|
-
getIntegrityForPrecacheKey(cacheKey) {
|
|
1022
|
-
return this._cacheKeysToIntegrities.get(cacheKey);
|
|
1023
|
-
}
|
|
1024
|
-
async matchPrecache(request) {
|
|
1025
|
-
const url = request instanceof Request ? request.url : request;
|
|
1026
|
-
const cacheKey = this.getPrecacheKeyForUrl(url);
|
|
1027
|
-
if (cacheKey) {
|
|
1028
|
-
const cache = await self.caches.open(this._strategy.cacheName);
|
|
1029
|
-
return cache.match(cacheKey);
|
|
932
|
+
this._pluginStateMap = new Map();
|
|
933
|
+
for (const plugin of this._plugins){
|
|
934
|
+
this._pluginStateMap.set(plugin, {});
|
|
1030
935
|
}
|
|
1031
|
-
|
|
936
|
+
this.event.waitUntil(this._handlerDeferred.promise);
|
|
1032
937
|
}
|
|
1033
|
-
|
|
1034
|
-
const
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
938
|
+
async fetch(input) {
|
|
939
|
+
const { event } = this;
|
|
940
|
+
let request = toRequest(input);
|
|
941
|
+
const preloadResponse = await this.getPreloadResponse();
|
|
942
|
+
if (preloadResponse) {
|
|
943
|
+
return preloadResponse;
|
|
1039
944
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
constructor({ fallbackUrls, precacheController, serwist }){
|
|
1055
|
-
this._fallbackUrls = fallbackUrls;
|
|
1056
|
-
if (!serwist) {
|
|
1057
|
-
this._precacheController = precacheController;
|
|
1058
|
-
} else {
|
|
1059
|
-
this._precacheController = serwist.precache;
|
|
945
|
+
const originalRequest = this.hasCallback("fetchDidFail") ? request.clone() : null;
|
|
946
|
+
try {
|
|
947
|
+
for (const cb of this.iterateCallbacks("requestWillFetch")){
|
|
948
|
+
request = await cb({
|
|
949
|
+
request: request.clone(),
|
|
950
|
+
event
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
} catch (err) {
|
|
954
|
+
if (err instanceof Error) {
|
|
955
|
+
throw new SerwistError("plugin-error-request-will-fetch", {
|
|
956
|
+
thrownErrorMessage: err.message
|
|
957
|
+
});
|
|
958
|
+
}
|
|
1060
959
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
}
|
|
960
|
+
const pluginFilteredRequest = request.clone();
|
|
961
|
+
try {
|
|
962
|
+
let fetchResponse;
|
|
963
|
+
fetchResponse = await fetch(request, request.mode === "navigate" ? undefined : this._strategy.fetchOptions);
|
|
964
|
+
if (process.env.NODE_ENV !== "production") {
|
|
965
|
+
logger.debug(`Network request for '${getFriendlyURL(request.url)}' returned a response with status '${fetchResponse.status}'.`);
|
|
966
|
+
}
|
|
967
|
+
for (const callback of this.iterateCallbacks("fetchDidSucceed")){
|
|
968
|
+
fetchResponse = await callback({
|
|
969
|
+
event,
|
|
970
|
+
request: pluginFilteredRequest,
|
|
971
|
+
response: fetchResponse
|
|
972
|
+
});
|
|
1074
973
|
}
|
|
974
|
+
return fetchResponse;
|
|
975
|
+
} catch (error) {
|
|
976
|
+
if (process.env.NODE_ENV !== "production") {
|
|
977
|
+
logger.log(`Network request for '${getFriendlyURL(request.url)}' threw an error.`, error);
|
|
978
|
+
}
|
|
979
|
+
if (originalRequest) {
|
|
980
|
+
await this.runCallbacks("fetchDidFail", {
|
|
981
|
+
error: error,
|
|
982
|
+
event,
|
|
983
|
+
originalRequest: originalRequest.clone(),
|
|
984
|
+
request: pluginFilteredRequest.clone()
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
throw error;
|
|
1075
988
|
}
|
|
1076
|
-
return undefined;
|
|
1077
989
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
constructor(entries, options = {}){
|
|
1084
|
-
this._entries = entries;
|
|
1085
|
-
this._options = options;
|
|
1086
|
-
this.init = this.init.bind(this);
|
|
1087
|
-
this.install = this.install.bind(this);
|
|
990
|
+
async fetchAndCachePut(input) {
|
|
991
|
+
const response = await this.fetch(input);
|
|
992
|
+
const responseClone = response.clone();
|
|
993
|
+
void this.waitUntil(this.cachePut(input, responseClone));
|
|
994
|
+
return response;
|
|
1088
995
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
996
|
+
async cacheMatch(key) {
|
|
997
|
+
const request = toRequest(key);
|
|
998
|
+
let cachedResponse;
|
|
999
|
+
const { cacheName, matchOptions } = this._strategy;
|
|
1000
|
+
const effectiveRequest = await this.getCacheKey(request, "read");
|
|
1001
|
+
const multiMatchOptions = {
|
|
1002
|
+
...matchOptions,
|
|
1003
|
+
...{
|
|
1004
|
+
cacheName
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);
|
|
1008
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1009
|
+
if (cachedResponse) {
|
|
1010
|
+
logger.debug(`Found a cached response in '${cacheName}'.`);
|
|
1011
|
+
} else {
|
|
1012
|
+
logger.debug(`No cached response found in '${cacheName}'.`);
|
|
1013
|
+
}
|
|
1100
1014
|
}
|
|
1101
|
-
for (const
|
|
1102
|
-
|
|
1015
|
+
for (const callback of this.iterateCallbacks("cachedResponseWillBeUsed")){
|
|
1016
|
+
cachedResponse = await callback({
|
|
1017
|
+
cacheName,
|
|
1018
|
+
matchOptions,
|
|
1019
|
+
cachedResponse,
|
|
1020
|
+
request: effectiveRequest,
|
|
1021
|
+
event: this.event
|
|
1022
|
+
}) || undefined;
|
|
1103
1023
|
}
|
|
1024
|
+
return cachedResponse;
|
|
1104
1025
|
}
|
|
1105
|
-
async
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
request,
|
|
1115
|
-
event
|
|
1026
|
+
async cachePut(key, response) {
|
|
1027
|
+
const request = toRequest(key);
|
|
1028
|
+
await timeout(0);
|
|
1029
|
+
const effectiveRequest = await this.getCacheKey(request, "write");
|
|
1030
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1031
|
+
if (effectiveRequest.method && effectiveRequest.method !== "GET") {
|
|
1032
|
+
throw new SerwistError("attempt-to-cache-non-get-request", {
|
|
1033
|
+
url: getFriendlyURL(effectiveRequest.url),
|
|
1034
|
+
method: effectiveRequest.method
|
|
1116
1035
|
});
|
|
1117
|
-
}
|
|
1036
|
+
}
|
|
1118
1037
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
const BACKGROUND_SYNC_DB_VERSION = 3;
|
|
1127
|
-
const BACKGROUND_SYNC_DB_NAME = "serwist-background-sync";
|
|
1128
|
-
const REQUEST_OBJECT_STORE_NAME = "requests";
|
|
1129
|
-
const QUEUE_NAME_INDEX = "queueName";
|
|
1130
|
-
class BackgroundSyncQueueDb {
|
|
1131
|
-
_db = null;
|
|
1132
|
-
async addEntry(entry) {
|
|
1133
|
-
const db = await this.getDb();
|
|
1134
|
-
const tx = db.transaction(REQUEST_OBJECT_STORE_NAME, "readwrite", {
|
|
1135
|
-
durability: "relaxed"
|
|
1136
|
-
});
|
|
1137
|
-
await tx.store.add(entry);
|
|
1138
|
-
await tx.done;
|
|
1139
|
-
}
|
|
1140
|
-
async getFirstEntryId() {
|
|
1141
|
-
const db = await this.getDb();
|
|
1142
|
-
const cursor = await db.transaction(REQUEST_OBJECT_STORE_NAME).store.openCursor();
|
|
1143
|
-
return cursor?.value.id;
|
|
1144
|
-
}
|
|
1145
|
-
async getAllEntriesByQueueName(queueName) {
|
|
1146
|
-
const db = await this.getDb();
|
|
1147
|
-
const results = await db.getAllFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
|
|
1148
|
-
return results ? results : new Array();
|
|
1149
|
-
}
|
|
1150
|
-
async getEntryCountByQueueName(queueName) {
|
|
1151
|
-
const db = await this.getDb();
|
|
1152
|
-
return db.countFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
|
|
1153
|
-
}
|
|
1154
|
-
async deleteEntry(id) {
|
|
1155
|
-
const db = await this.getDb();
|
|
1156
|
-
await db.delete(REQUEST_OBJECT_STORE_NAME, id);
|
|
1157
|
-
}
|
|
1158
|
-
async getFirstEntryByQueueName(queueName) {
|
|
1159
|
-
return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), "next");
|
|
1160
|
-
}
|
|
1161
|
-
async getLastEntryByQueueName(queueName) {
|
|
1162
|
-
return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), "prev");
|
|
1163
|
-
}
|
|
1164
|
-
async getEndEntryFromIndex(query, direction) {
|
|
1165
|
-
const db = await this.getDb();
|
|
1166
|
-
const cursor = await db.transaction(REQUEST_OBJECT_STORE_NAME).store.index(QUEUE_NAME_INDEX).openCursor(query, direction);
|
|
1167
|
-
return cursor?.value;
|
|
1168
|
-
}
|
|
1169
|
-
async getDb() {
|
|
1170
|
-
if (!this._db) {
|
|
1171
|
-
this._db = await openDB(BACKGROUND_SYNC_DB_NAME, BACKGROUND_SYNC_DB_VERSION, {
|
|
1172
|
-
upgrade: this._upgradeDb
|
|
1038
|
+
if (!response) {
|
|
1039
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1040
|
+
logger.error(`Cannot cache non-existent response for '${getFriendlyURL(effectiveRequest.url)}'.`);
|
|
1041
|
+
}
|
|
1042
|
+
throw new SerwistError("cache-put-with-no-response", {
|
|
1043
|
+
url: getFriendlyURL(effectiveRequest.url)
|
|
1173
1044
|
});
|
|
1174
1045
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if (db.objectStoreNames.contains(REQUEST_OBJECT_STORE_NAME)) {
|
|
1180
|
-
db.deleteObjectStore(REQUEST_OBJECT_STORE_NAME);
|
|
1046
|
+
const responseToCache = await this._ensureResponseSafeToCache(response);
|
|
1047
|
+
if (!responseToCache) {
|
|
1048
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1049
|
+
logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' will not be cached.`, responseToCache);
|
|
1181
1050
|
}
|
|
1051
|
+
return false;
|
|
1182
1052
|
}
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
keyPath: "id"
|
|
1186
|
-
});
|
|
1187
|
-
objStore.createIndex(QUEUE_NAME_INDEX, QUEUE_NAME_INDEX, {
|
|
1188
|
-
unique: false
|
|
1189
|
-
});
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
class BackgroundSyncQueueStore {
|
|
1194
|
-
_queueName;
|
|
1195
|
-
_queueDb;
|
|
1196
|
-
constructor(queueName){
|
|
1197
|
-
this._queueName = queueName;
|
|
1198
|
-
this._queueDb = new BackgroundSyncQueueDb();
|
|
1199
|
-
}
|
|
1200
|
-
async pushEntry(entry) {
|
|
1053
|
+
const { cacheName, matchOptions } = this._strategy;
|
|
1054
|
+
const cache = await self.caches.open(cacheName);
|
|
1201
1055
|
if (process.env.NODE_ENV !== "production") {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1056
|
+
const vary = response.headers.get("Vary");
|
|
1057
|
+
if (vary && matchOptions?.ignoreVary !== true) {
|
|
1058
|
+
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.`);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
const hasCacheUpdateCallback = this.hasCallback("cacheDidUpdate");
|
|
1062
|
+
const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams(cache, effectiveRequest.clone(), [
|
|
1063
|
+
"__WB_REVISION__"
|
|
1064
|
+
], matchOptions) : null;
|
|
1065
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1066
|
+
logger.debug(`Updating the '${cacheName}' cache with a new Response for ${getFriendlyURL(effectiveRequest.url)}.`);
|
|
1067
|
+
}
|
|
1068
|
+
try {
|
|
1069
|
+
await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache);
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
if (error instanceof Error) {
|
|
1072
|
+
if (error.name === "QuotaExceededError") {
|
|
1073
|
+
await executeQuotaErrorCallbacks();
|
|
1074
|
+
}
|
|
1075
|
+
throw error;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
for (const callback of this.iterateCallbacks("cacheDidUpdate")){
|
|
1079
|
+
await callback({
|
|
1080
|
+
cacheName,
|
|
1081
|
+
oldResponse,
|
|
1082
|
+
newResponse: responseToCache.clone(),
|
|
1083
|
+
request: effectiveRequest,
|
|
1084
|
+
event: this.event
|
|
1213
1085
|
});
|
|
1214
1086
|
}
|
|
1215
|
-
|
|
1216
|
-
entry.queueName = this._queueName;
|
|
1217
|
-
await this._queueDb.addEntry(entry);
|
|
1087
|
+
return true;
|
|
1218
1088
|
}
|
|
1219
|
-
async
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
});
|
|
1089
|
+
async getCacheKey(request, mode) {
|
|
1090
|
+
const key = `${request.url} | ${mode}`;
|
|
1091
|
+
if (!this._cacheKeys[key]) {
|
|
1092
|
+
let effectiveRequest = request;
|
|
1093
|
+
for (const callback of this.iterateCallbacks("cacheKeyWillBeUsed")){
|
|
1094
|
+
effectiveRequest = toRequest(await callback({
|
|
1095
|
+
mode,
|
|
1096
|
+
request: effectiveRequest,
|
|
1097
|
+
event: this.event,
|
|
1098
|
+
params: this.params
|
|
1099
|
+
}));
|
|
1100
|
+
}
|
|
1101
|
+
this._cacheKeys[key] = effectiveRequest;
|
|
1233
1102
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1103
|
+
return this._cacheKeys[key];
|
|
1104
|
+
}
|
|
1105
|
+
hasCallback(name) {
|
|
1106
|
+
for (const plugin of this._strategy.plugins){
|
|
1107
|
+
if (name in plugin) {
|
|
1108
|
+
return true;
|
|
1109
|
+
}
|
|
1239
1110
|
}
|
|
1240
|
-
|
|
1241
|
-
await this._queueDb.addEntry(entry);
|
|
1111
|
+
return false;
|
|
1242
1112
|
}
|
|
1243
|
-
async
|
|
1244
|
-
|
|
1113
|
+
async runCallbacks(name, param) {
|
|
1114
|
+
for (const callback of this.iterateCallbacks(name)){
|
|
1115
|
+
await callback(param);
|
|
1116
|
+
}
|
|
1245
1117
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1118
|
+
*iterateCallbacks(name) {
|
|
1119
|
+
for (const plugin of this._strategy.plugins){
|
|
1120
|
+
if (typeof plugin[name] === "function") {
|
|
1121
|
+
const state = this._pluginStateMap.get(plugin);
|
|
1122
|
+
const statefulCallback = (param)=>{
|
|
1123
|
+
const statefulParam = {
|
|
1124
|
+
...param,
|
|
1125
|
+
state
|
|
1126
|
+
};
|
|
1127
|
+
return plugin[name](statefulParam);
|
|
1128
|
+
};
|
|
1129
|
+
yield statefulCallback;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1248
1132
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1133
|
+
waitUntil(promise) {
|
|
1134
|
+
this._extendLifetimePromises.push(promise);
|
|
1135
|
+
return promise;
|
|
1251
1136
|
}
|
|
1252
|
-
async
|
|
1253
|
-
|
|
1137
|
+
async doneWaiting() {
|
|
1138
|
+
let promise;
|
|
1139
|
+
while(promise = this._extendLifetimePromises.shift()){
|
|
1140
|
+
await promise;
|
|
1141
|
+
}
|
|
1254
1142
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1143
|
+
destroy() {
|
|
1144
|
+
this._handlerDeferred.resolve(null);
|
|
1257
1145
|
}
|
|
1258
|
-
async
|
|
1259
|
-
if (
|
|
1260
|
-
|
|
1146
|
+
async getPreloadResponse() {
|
|
1147
|
+
if (this.event instanceof FetchEvent && this.event.request.mode === "navigate" && "preloadResponse" in this.event) {
|
|
1148
|
+
try {
|
|
1149
|
+
const possiblePreloadResponse = await this.event.preloadResponse;
|
|
1150
|
+
if (possiblePreloadResponse) {
|
|
1151
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1152
|
+
logger.log(`Using a preloaded navigation response for '${getFriendlyURL(this.event.request.url)}'`);
|
|
1153
|
+
}
|
|
1154
|
+
return possiblePreloadResponse;
|
|
1155
|
+
}
|
|
1156
|
+
} catch (error) {
|
|
1157
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1158
|
+
logger.error(error);
|
|
1159
|
+
}
|
|
1160
|
+
return undefined;
|
|
1161
|
+
}
|
|
1261
1162
|
}
|
|
1262
|
-
return
|
|
1163
|
+
return undefined;
|
|
1164
|
+
}
|
|
1165
|
+
async _ensureResponseSafeToCache(response) {
|
|
1166
|
+
let responseToCache = response;
|
|
1167
|
+
let pluginsUsed = false;
|
|
1168
|
+
for (const callback of this.iterateCallbacks("cacheWillUpdate")){
|
|
1169
|
+
responseToCache = await callback({
|
|
1170
|
+
request: this.request,
|
|
1171
|
+
response: responseToCache,
|
|
1172
|
+
event: this.event
|
|
1173
|
+
}) || undefined;
|
|
1174
|
+
pluginsUsed = true;
|
|
1175
|
+
if (!responseToCache) {
|
|
1176
|
+
break;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (!pluginsUsed) {
|
|
1180
|
+
if (responseToCache && responseToCache.status !== 200) {
|
|
1181
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1182
|
+
if (responseToCache.status === 0) {
|
|
1183
|
+
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.`);
|
|
1184
|
+
} else {
|
|
1185
|
+
logger.debug(`The response for '${this.request.url}' returned a status code of '${response.status}' and won't be cached as a result.`);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
responseToCache = undefined;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return responseToCache;
|
|
1263
1192
|
}
|
|
1264
1193
|
}
|
|
1265
1194
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1195
|
+
class Strategy {
|
|
1196
|
+
cacheName;
|
|
1197
|
+
plugins;
|
|
1198
|
+
fetchOptions;
|
|
1199
|
+
matchOptions;
|
|
1200
|
+
constructor(options = {}){
|
|
1201
|
+
this.cacheName = cacheNames$1.getRuntimeName(options.cacheName);
|
|
1202
|
+
this.plugins = options.plugins || [];
|
|
1203
|
+
this.fetchOptions = options.fetchOptions;
|
|
1204
|
+
this.matchOptions = options.matchOptions;
|
|
1205
|
+
}
|
|
1206
|
+
handle(options) {
|
|
1207
|
+
const [responseDone] = this.handleAll(options);
|
|
1208
|
+
return responseDone;
|
|
1209
|
+
}
|
|
1210
|
+
handleAll(options) {
|
|
1211
|
+
if (options instanceof FetchEvent) {
|
|
1212
|
+
options = {
|
|
1213
|
+
event: options,
|
|
1214
|
+
request: options.request
|
|
1215
|
+
};
|
|
1286
1216
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1217
|
+
const event = options.event;
|
|
1218
|
+
const request = typeof options.request === "string" ? new Request(options.request) : options.request;
|
|
1219
|
+
const handler = new StrategyHandler(this, options.url ? {
|
|
1220
|
+
event,
|
|
1221
|
+
request,
|
|
1222
|
+
url: options.url,
|
|
1223
|
+
params: options.params
|
|
1224
|
+
} : {
|
|
1225
|
+
event,
|
|
1226
|
+
request
|
|
1289
1227
|
});
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1228
|
+
const responseDone = this._getResponse(handler, request, event);
|
|
1229
|
+
const handlerDone = this._awaitComplete(responseDone, handler, request, event);
|
|
1230
|
+
return [
|
|
1231
|
+
responseDone,
|
|
1232
|
+
handlerDone
|
|
1233
|
+
];
|
|
1296
1234
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1235
|
+
async _getResponse(handler, request, event) {
|
|
1236
|
+
await handler.runCallbacks("handlerWillStart", {
|
|
1237
|
+
event,
|
|
1238
|
+
request
|
|
1239
|
+
});
|
|
1240
|
+
let response;
|
|
1241
|
+
try {
|
|
1242
|
+
response = await this._handle(request, handler);
|
|
1243
|
+
if (response === undefined || response.type === "error") {
|
|
1244
|
+
throw new SerwistError("no-response", {
|
|
1245
|
+
url: request.url
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
} catch (error) {
|
|
1249
|
+
if (error instanceof Error) {
|
|
1250
|
+
for (const callback of handler.iterateCallbacks("handlerDidError")){
|
|
1251
|
+
response = await callback({
|
|
1252
|
+
error,
|
|
1253
|
+
event,
|
|
1254
|
+
request
|
|
1255
|
+
});
|
|
1256
|
+
if (response !== undefined) {
|
|
1257
|
+
break;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
if (!response) {
|
|
1262
|
+
throw error;
|
|
1263
|
+
}
|
|
1264
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1265
|
+
throw 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.`);
|
|
1266
|
+
}
|
|
1311
1267
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1268
|
+
for (const callback of handler.iterateCallbacks("handlerWillRespond")){
|
|
1269
|
+
response = await callback({
|
|
1270
|
+
event,
|
|
1271
|
+
request,
|
|
1272
|
+
response
|
|
1273
|
+
});
|
|
1314
1274
|
}
|
|
1315
|
-
|
|
1275
|
+
return response;
|
|
1316
1276
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1277
|
+
async _awaitComplete(responseDone, handler, request, event) {
|
|
1278
|
+
let response;
|
|
1279
|
+
let error;
|
|
1280
|
+
try {
|
|
1281
|
+
response = await responseDone;
|
|
1282
|
+
} catch {}
|
|
1283
|
+
try {
|
|
1284
|
+
await handler.runCallbacks("handlerDidRespond", {
|
|
1285
|
+
event,
|
|
1286
|
+
request,
|
|
1287
|
+
response
|
|
1288
|
+
});
|
|
1289
|
+
await handler.doneWaiting();
|
|
1290
|
+
} catch (waitUntilError) {
|
|
1291
|
+
if (waitUntilError instanceof Error) {
|
|
1292
|
+
error = waitUntilError;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
await handler.runCallbacks("handlerDidComplete", {
|
|
1296
|
+
event,
|
|
1297
|
+
request,
|
|
1298
|
+
response,
|
|
1299
|
+
error
|
|
1300
|
+
});
|
|
1301
|
+
handler.destroy();
|
|
1302
|
+
if (error) {
|
|
1303
|
+
throw error;
|
|
1322
1304
|
}
|
|
1323
|
-
return requestData;
|
|
1324
|
-
}
|
|
1325
|
-
toRequest() {
|
|
1326
|
-
return new Request(this._requestData.url, this._requestData);
|
|
1327
|
-
}
|
|
1328
|
-
clone() {
|
|
1329
|
-
return new StorableRequest(this.toObject());
|
|
1330
1305
|
}
|
|
1331
1306
|
}
|
|
1332
1307
|
|
|
1333
|
-
const
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
if (queueStoreEntry.metadata) {
|
|
1342
|
-
queueEntry.metadata = queueStoreEntry.metadata;
|
|
1308
|
+
const messages = {
|
|
1309
|
+
strategyStart: (strategyName, request)=>`Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`,
|
|
1310
|
+
printFinalResponse: (response)=>{
|
|
1311
|
+
if (response) {
|
|
1312
|
+
logger.groupCollapsed("View the final response here.");
|
|
1313
|
+
logger.log(response || "[No response returned]");
|
|
1314
|
+
logger.groupEnd();
|
|
1315
|
+
}
|
|
1343
1316
|
}
|
|
1344
|
-
return queueEntry;
|
|
1345
1317
|
};
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
if (
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1318
|
+
|
|
1319
|
+
class NetworkFirst extends Strategy {
|
|
1320
|
+
_networkTimeoutSeconds;
|
|
1321
|
+
constructor(options = {}){
|
|
1322
|
+
super(options);
|
|
1323
|
+
if (!this.plugins.some((p)=>"cacheWillUpdate" in p)) {
|
|
1324
|
+
this.plugins.unshift(cacheOkAndOpaquePlugin);
|
|
1325
|
+
}
|
|
1326
|
+
this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
|
|
1327
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1328
|
+
if (this._networkTimeoutSeconds) {
|
|
1329
|
+
finalAssertExports.isType(this._networkTimeoutSeconds, "number", {
|
|
1330
|
+
moduleName: "serwist",
|
|
1331
|
+
className: this.constructor.name,
|
|
1332
|
+
funcName: "constructor",
|
|
1333
|
+
paramName: "networkTimeoutSeconds"
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1359
1336
|
}
|
|
1360
|
-
queueNames.add(name);
|
|
1361
|
-
this._name = name;
|
|
1362
|
-
this._onSync = onSync || this.replayRequests;
|
|
1363
|
-
this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME$1;
|
|
1364
|
-
this._forceSyncFallback = Boolean(forceSyncFallback);
|
|
1365
|
-
this._queueStore = new BackgroundSyncQueueStore(this._name);
|
|
1366
|
-
this._addSyncListener();
|
|
1367
|
-
}
|
|
1368
|
-
get name() {
|
|
1369
|
-
return this._name;
|
|
1370
1337
|
}
|
|
1371
|
-
async
|
|
1338
|
+
async _handle(request, handler) {
|
|
1339
|
+
const logs = [];
|
|
1372
1340
|
if (process.env.NODE_ENV !== "production") {
|
|
1373
|
-
finalAssertExports.
|
|
1341
|
+
finalAssertExports.isInstance(request, Request, {
|
|
1374
1342
|
moduleName: "serwist",
|
|
1375
|
-
className:
|
|
1376
|
-
funcName: "
|
|
1377
|
-
paramName: "
|
|
1343
|
+
className: this.constructor.name,
|
|
1344
|
+
funcName: "handle",
|
|
1345
|
+
paramName: "makeRequest"
|
|
1378
1346
|
});
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1347
|
+
}
|
|
1348
|
+
const promises = [];
|
|
1349
|
+
let timeoutId;
|
|
1350
|
+
if (this._networkTimeoutSeconds) {
|
|
1351
|
+
const { id, promise } = this._getTimeoutPromise({
|
|
1352
|
+
request,
|
|
1353
|
+
logs,
|
|
1354
|
+
handler
|
|
1384
1355
|
});
|
|
1356
|
+
timeoutId = id;
|
|
1357
|
+
promises.push(promise);
|
|
1385
1358
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1359
|
+
const networkPromise = this._getNetworkPromise({
|
|
1360
|
+
timeoutId,
|
|
1361
|
+
request,
|
|
1362
|
+
logs,
|
|
1363
|
+
handler
|
|
1364
|
+
});
|
|
1365
|
+
promises.push(networkPromise);
|
|
1366
|
+
const response = await handler.waitUntil((async ()=>{
|
|
1367
|
+
return await handler.waitUntil(Promise.race(promises)) || await networkPromise;
|
|
1368
|
+
})());
|
|
1389
1369
|
if (process.env.NODE_ENV !== "production") {
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
paramName: "entry.request"
|
|
1370
|
+
logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
|
|
1371
|
+
for (const log of logs){
|
|
1372
|
+
logger.log(log);
|
|
1373
|
+
}
|
|
1374
|
+
messages.printFinalResponse(response);
|
|
1375
|
+
logger.groupEnd();
|
|
1376
|
+
}
|
|
1377
|
+
if (!response) {
|
|
1378
|
+
throw new SerwistError("no-response", {
|
|
1379
|
+
url: request.url
|
|
1401
1380
|
});
|
|
1402
1381
|
}
|
|
1403
|
-
|
|
1404
|
-
}
|
|
1405
|
-
async popRequest() {
|
|
1406
|
-
return this._removeRequest("pop");
|
|
1382
|
+
return response;
|
|
1407
1383
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1384
|
+
_getTimeoutPromise({ request, logs, handler }) {
|
|
1385
|
+
let timeoutId;
|
|
1386
|
+
const timeoutPromise = new Promise((resolve)=>{
|
|
1387
|
+
const onNetworkTimeout = async ()=>{
|
|
1388
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1389
|
+
logs.push(`Timing out the network response at ${this._networkTimeoutSeconds} seconds.`);
|
|
1390
|
+
}
|
|
1391
|
+
resolve(await handler.cacheMatch(request));
|
|
1392
|
+
};
|
|
1393
|
+
timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000);
|
|
1394
|
+
});
|
|
1395
|
+
return {
|
|
1396
|
+
promise: timeoutPromise,
|
|
1397
|
+
id: timeoutId
|
|
1398
|
+
};
|
|
1410
1399
|
}
|
|
1411
|
-
async
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
if (
|
|
1418
|
-
|
|
1400
|
+
async _getNetworkPromise({ timeoutId, request, logs, handler }) {
|
|
1401
|
+
let error;
|
|
1402
|
+
let response;
|
|
1403
|
+
try {
|
|
1404
|
+
response = await handler.fetchAndCachePut(request);
|
|
1405
|
+
} catch (fetchError) {
|
|
1406
|
+
if (fetchError instanceof Error) {
|
|
1407
|
+
error = fetchError;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
if (timeoutId) {
|
|
1411
|
+
clearTimeout(timeoutId);
|
|
1412
|
+
}
|
|
1413
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1414
|
+
if (response) {
|
|
1415
|
+
logs.push("Got response from network.");
|
|
1419
1416
|
} else {
|
|
1420
|
-
|
|
1417
|
+
logs.push("Unable to get a response from the network. Will respond " + "with a cached response.");
|
|
1421
1418
|
}
|
|
1422
1419
|
}
|
|
1423
|
-
|
|
1420
|
+
if (error || !response) {
|
|
1421
|
+
response = await handler.cacheMatch(request);
|
|
1422
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1423
|
+
if (response) {
|
|
1424
|
+
logs.push(`Found a cached response in the '${this.cacheName}' cache.`);
|
|
1425
|
+
} else {
|
|
1426
|
+
logs.push(`No response found in the '${this.cacheName}' cache.`);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return response;
|
|
1424
1431
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
class NetworkOnly extends Strategy {
|
|
1435
|
+
_networkTimeoutSeconds;
|
|
1436
|
+
constructor(options = {}){
|
|
1437
|
+
super(options);
|
|
1438
|
+
this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
|
|
1427
1439
|
}
|
|
1428
|
-
async
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1440
|
+
async _handle(request, handler) {
|
|
1441
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1442
|
+
finalAssertExports.isInstance(request, Request, {
|
|
1443
|
+
moduleName: "serwist",
|
|
1444
|
+
className: this.constructor.name,
|
|
1445
|
+
funcName: "_handle",
|
|
1446
|
+
paramName: "request"
|
|
1447
|
+
});
|
|
1436
1448
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1449
|
+
let error;
|
|
1450
|
+
let response;
|
|
1451
|
+
try {
|
|
1452
|
+
const promises = [
|
|
1453
|
+
handler.fetch(request)
|
|
1454
|
+
];
|
|
1455
|
+
if (this._networkTimeoutSeconds) {
|
|
1456
|
+
const timeoutPromise = timeout(this._networkTimeoutSeconds * 1000);
|
|
1457
|
+
promises.push(timeoutPromise);
|
|
1458
|
+
}
|
|
1459
|
+
response = await Promise.race(promises);
|
|
1460
|
+
if (!response) {
|
|
1461
|
+
throw new Error(`Timed out the network response after ${this._networkTimeoutSeconds} seconds.`);
|
|
1462
|
+
}
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
if (err instanceof Error) {
|
|
1465
|
+
error = err;
|
|
1466
|
+
}
|
|
1444
1467
|
}
|
|
1445
1468
|
if (process.env.NODE_ENV !== "production") {
|
|
1446
|
-
logger.
|
|
1469
|
+
logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
|
|
1470
|
+
if (response) {
|
|
1471
|
+
logger.log("Got response from network.");
|
|
1472
|
+
} else {
|
|
1473
|
+
logger.log("Unable to get a response from the network.");
|
|
1474
|
+
}
|
|
1475
|
+
messages.printFinalResponse(response);
|
|
1476
|
+
logger.groupEnd();
|
|
1447
1477
|
}
|
|
1448
|
-
if (
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1478
|
+
if (!response) {
|
|
1479
|
+
throw new SerwistError("no-response", {
|
|
1480
|
+
url: request.url,
|
|
1481
|
+
error
|
|
1482
|
+
});
|
|
1452
1483
|
}
|
|
1484
|
+
return response;
|
|
1453
1485
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
const QUEUE_NAME = "serwist-google-analytics";
|
|
1489
|
+
const MAX_RETENTION_TIME = 60 * 48;
|
|
1490
|
+
const GOOGLE_ANALYTICS_HOST = "www.google-analytics.com";
|
|
1491
|
+
const GTM_HOST = "www.googletagmanager.com";
|
|
1492
|
+
const ANALYTICS_JS_PATH = "/analytics.js";
|
|
1493
|
+
const GTAG_JS_PATH = "/gtag/js";
|
|
1494
|
+
const GTM_JS_PATH = "/gtm.js";
|
|
1495
|
+
const COLLECT_PATHS_REGEX = /^\/(\w+\/)?collect/;
|
|
1496
|
+
|
|
1497
|
+
const createOnSyncCallback = (config)=>{
|
|
1498
|
+
return async ({ queue })=>{
|
|
1456
1499
|
let entry;
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
break;
|
|
1461
|
-
case "shift":
|
|
1462
|
-
entry = await this._queueStore.shiftEntry();
|
|
1463
|
-
break;
|
|
1464
|
-
}
|
|
1465
|
-
if (entry) {
|
|
1466
|
-
const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
|
|
1467
|
-
if (now - entry.timestamp > maxRetentionTimeInMs) {
|
|
1468
|
-
return this._removeRequest(operation);
|
|
1469
|
-
}
|
|
1470
|
-
return convertEntry(entry);
|
|
1471
|
-
}
|
|
1472
|
-
return undefined;
|
|
1473
|
-
}
|
|
1474
|
-
async replayRequests() {
|
|
1475
|
-
let entry = undefined;
|
|
1476
|
-
while(entry = await this.shiftRequest()){
|
|
1500
|
+
while(entry = await queue.shiftRequest()){
|
|
1501
|
+
const { request, timestamp } = entry;
|
|
1502
|
+
const url = new URL(request.url);
|
|
1477
1503
|
try {
|
|
1478
|
-
await
|
|
1504
|
+
const params = request.method === "POST" ? new URLSearchParams(await request.clone().text()) : url.searchParams;
|
|
1505
|
+
const originalHitTime = timestamp - (Number(params.get("qt")) || 0);
|
|
1506
|
+
const queueTime = Date.now() - originalHitTime;
|
|
1507
|
+
params.set("qt", String(queueTime));
|
|
1508
|
+
if (config.parameterOverrides) {
|
|
1509
|
+
for (const param of Object.keys(config.parameterOverrides)){
|
|
1510
|
+
const value = config.parameterOverrides[param];
|
|
1511
|
+
params.set(param, value);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
if (typeof config.hitFilter === "function") {
|
|
1515
|
+
config.hitFilter.call(null, params);
|
|
1516
|
+
}
|
|
1517
|
+
await fetch(new Request(url.origin + url.pathname, {
|
|
1518
|
+
body: params.toString(),
|
|
1519
|
+
method: "POST",
|
|
1520
|
+
mode: "cors",
|
|
1521
|
+
credentials: "omit",
|
|
1522
|
+
headers: {
|
|
1523
|
+
"Content-Type": "text/plain"
|
|
1524
|
+
}
|
|
1525
|
+
}));
|
|
1479
1526
|
if (process.env.NODE_ENV !== "production") {
|
|
1480
|
-
logger.log(`Request for '${getFriendlyURL(
|
|
1527
|
+
logger.log(`Request for '${getFriendlyURL(url.href)}' has been replayed`);
|
|
1481
1528
|
}
|
|
1482
|
-
} catch (
|
|
1483
|
-
await
|
|
1529
|
+
} catch (err) {
|
|
1530
|
+
await queue.unshiftRequest(entry);
|
|
1484
1531
|
if (process.env.NODE_ENV !== "production") {
|
|
1485
|
-
logger.log(`Request for '${getFriendlyURL(
|
|
1532
|
+
logger.log(`Request for '${getFriendlyURL(url.href)}' failed to replay, putting it back in the queue.`);
|
|
1486
1533
|
}
|
|
1487
|
-
throw
|
|
1488
|
-
name: this._name
|
|
1489
|
-
});
|
|
1534
|
+
throw err;
|
|
1490
1535
|
}
|
|
1491
1536
|
}
|
|
1492
1537
|
if (process.env.NODE_ENV !== "production") {
|
|
1493
|
-
logger.log(
|
|
1538
|
+
logger.log("All Google Analytics request successfully replayed; " + "the queue is now empty!");
|
|
1494
1539
|
}
|
|
1540
|
+
};
|
|
1541
|
+
};
|
|
1542
|
+
const createCollectRoutes = (bgSyncPlugin)=>{
|
|
1543
|
+
const match = ({ url })=>url.hostname === GOOGLE_ANALYTICS_HOST && COLLECT_PATHS_REGEX.test(url.pathname);
|
|
1544
|
+
const handler = new NetworkOnly({
|
|
1545
|
+
plugins: [
|
|
1546
|
+
bgSyncPlugin
|
|
1547
|
+
]
|
|
1548
|
+
});
|
|
1549
|
+
return [
|
|
1550
|
+
new Route(match, handler, "GET"),
|
|
1551
|
+
new Route(match, handler, "POST")
|
|
1552
|
+
];
|
|
1553
|
+
};
|
|
1554
|
+
const createAnalyticsJsRoute = (cacheName)=>{
|
|
1555
|
+
const match = ({ url })=>url.hostname === GOOGLE_ANALYTICS_HOST && url.pathname === ANALYTICS_JS_PATH;
|
|
1556
|
+
const handler = new NetworkFirst({
|
|
1557
|
+
cacheName
|
|
1558
|
+
});
|
|
1559
|
+
return new Route(match, handler, "GET");
|
|
1560
|
+
};
|
|
1561
|
+
const createGtagJsRoute = (cacheName)=>{
|
|
1562
|
+
const match = ({ url })=>url.hostname === GTM_HOST && url.pathname === GTAG_JS_PATH;
|
|
1563
|
+
const handler = new NetworkFirst({
|
|
1564
|
+
cacheName
|
|
1565
|
+
});
|
|
1566
|
+
return new Route(match, handler, "GET");
|
|
1567
|
+
};
|
|
1568
|
+
const createGtmJsRoute = (cacheName)=>{
|
|
1569
|
+
const match = ({ url })=>url.hostname === GTM_HOST && url.pathname === GTM_JS_PATH;
|
|
1570
|
+
const handler = new NetworkFirst({
|
|
1571
|
+
cacheName
|
|
1572
|
+
});
|
|
1573
|
+
return new Route(match, handler, "GET");
|
|
1574
|
+
};
|
|
1575
|
+
class GoogleAnalytics {
|
|
1576
|
+
_options;
|
|
1577
|
+
constructor(options = {}){
|
|
1578
|
+
this._options = options;
|
|
1495
1579
|
}
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1580
|
+
init({ serwist }) {
|
|
1581
|
+
const resolvedCacheName = cacheNames$1.getGoogleAnalyticsName(this._options.cacheName);
|
|
1582
|
+
const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
|
|
1583
|
+
maxRetentionTime: MAX_RETENTION_TIME,
|
|
1584
|
+
onSync: createOnSyncCallback(this._options)
|
|
1585
|
+
});
|
|
1586
|
+
const routes = [
|
|
1587
|
+
createGtmJsRoute(resolvedCacheName),
|
|
1588
|
+
createAnalyticsJsRoute(resolvedCacheName),
|
|
1589
|
+
createGtagJsRoute(resolvedCacheName),
|
|
1590
|
+
...createCollectRoutes(bgSyncPlugin)
|
|
1591
|
+
];
|
|
1592
|
+
for (const route of routes){
|
|
1593
|
+
registerRoute(serwist, route);
|
|
1505
1594
|
}
|
|
1506
1595
|
}
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
syncError = error;
|
|
1524
|
-
throw syncError;
|
|
1525
|
-
}
|
|
1526
|
-
} finally{
|
|
1527
|
-
if (this._requestsAddedDuringSync && !(syncError && !event.lastChance)) {
|
|
1528
|
-
await this.registerSync();
|
|
1529
|
-
}
|
|
1530
|
-
this._syncInProgress = false;
|
|
1531
|
-
this._requestsAddedDuringSync = false;
|
|
1532
|
-
}
|
|
1533
|
-
};
|
|
1534
|
-
event.waitUntil(syncComplete());
|
|
1535
|
-
}
|
|
1536
|
-
});
|
|
1537
|
-
} else {
|
|
1538
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1539
|
-
logger.log("Background sync replaying without background sync event");
|
|
1540
|
-
}
|
|
1541
|
-
void this._onSync({
|
|
1542
|
-
queue: this
|
|
1543
|
-
});
|
|
1544
|
-
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
const initializeGoogleAnalytics = ({ serwist, cacheName, ...options })=>{
|
|
1599
|
+
const resolvedCacheName = cacheNames$1.getGoogleAnalyticsName(cacheName);
|
|
1600
|
+
const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
|
|
1601
|
+
maxRetentionTime: MAX_RETENTION_TIME,
|
|
1602
|
+
onSync: createOnSyncCallback(options)
|
|
1603
|
+
});
|
|
1604
|
+
const routes = [
|
|
1605
|
+
createGtmJsRoute(resolvedCacheName),
|
|
1606
|
+
createAnalyticsJsRoute(resolvedCacheName),
|
|
1607
|
+
createGtagJsRoute(resolvedCacheName),
|
|
1608
|
+
...createCollectRoutes(bgSyncPlugin)
|
|
1609
|
+
];
|
|
1610
|
+
for (const route of routes){
|
|
1611
|
+
serwist.registerRoute(route);
|
|
1545
1612
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1613
|
+
};
|
|
1614
|
+
|
|
1615
|
+
const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
1616
|
+
const createCacheKey = (entry)=>{
|
|
1617
|
+
if (!entry) {
|
|
1618
|
+
throw new SerwistError("add-to-cache-list-unexpected-type", {
|
|
1619
|
+
entry
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
if (typeof entry === "string") {
|
|
1623
|
+
const urlObject = new URL(entry, location.href);
|
|
1624
|
+
return {
|
|
1625
|
+
cacheKey: urlObject.href,
|
|
1626
|
+
url: urlObject.href
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
const { revision, url } = entry;
|
|
1630
|
+
if (!url) {
|
|
1631
|
+
throw new SerwistError("add-to-cache-list-unexpected-type", {
|
|
1632
|
+
entry
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
if (!revision) {
|
|
1636
|
+
const urlObject = new URL(url, location.href);
|
|
1637
|
+
return {
|
|
1638
|
+
cacheKey: urlObject.href,
|
|
1639
|
+
url: urlObject.href
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
const cacheKeyURL = new URL(url, location.href);
|
|
1643
|
+
const originalURL = new URL(url, location.href);
|
|
1644
|
+
cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
|
|
1645
|
+
return {
|
|
1646
|
+
cacheKey: cacheKeyURL.href,
|
|
1647
|
+
url: originalURL.href
|
|
1648
|
+
};
|
|
1649
|
+
};
|
|
1650
|
+
|
|
1651
|
+
const logGroup = (groupTitle, deletedURLs)=>{
|
|
1652
|
+
logger.groupCollapsed(groupTitle);
|
|
1653
|
+
for (const url of deletedURLs){
|
|
1654
|
+
logger.log(url);
|
|
1655
|
+
}
|
|
1656
|
+
logger.groupEnd();
|
|
1657
|
+
};
|
|
1658
|
+
const printCleanupDetails = (deletedURLs)=>{
|
|
1659
|
+
const deletionCount = deletedURLs.length;
|
|
1660
|
+
if (deletionCount > 0) {
|
|
1661
|
+
logger.groupCollapsed(`During precaching cleanup, ${deletionCount} cached request${deletionCount === 1 ? " was" : "s were"} deleted.`);
|
|
1662
|
+
logGroup("Deleted Cache Requests", deletedURLs);
|
|
1663
|
+
logger.groupEnd();
|
|
1548
1664
|
}
|
|
1549
|
-
}
|
|
1665
|
+
};
|
|
1550
1666
|
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
this._queue = new BackgroundSyncQueue(name, options);
|
|
1667
|
+
function _nestedGroup(groupTitle, urls) {
|
|
1668
|
+
if (urls.length === 0) {
|
|
1669
|
+
return;
|
|
1555
1670
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
});
|
|
1671
|
+
logger.groupCollapsed(groupTitle);
|
|
1672
|
+
for (const url of urls){
|
|
1673
|
+
logger.log(url);
|
|
1560
1674
|
}
|
|
1675
|
+
logger.groupEnd();
|
|
1561
1676
|
}
|
|
1562
|
-
|
|
1563
|
-
const
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1677
|
+
const printInstallDetails = (urlsToPrecache, urlsAlreadyPrecached)=>{
|
|
1678
|
+
const precachedCount = urlsToPrecache.length;
|
|
1679
|
+
const alreadyPrecachedCount = urlsAlreadyPrecached.length;
|
|
1680
|
+
if (precachedCount || alreadyPrecachedCount) {
|
|
1681
|
+
let message = `Precaching ${precachedCount} file${precachedCount === 1 ? "" : "s"}.`;
|
|
1682
|
+
if (alreadyPrecachedCount > 0) {
|
|
1683
|
+
message += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? " is" : "s are"} already cached.`;
|
|
1567
1684
|
}
|
|
1568
|
-
|
|
1685
|
+
logger.groupCollapsed(message);
|
|
1686
|
+
_nestedGroup("View newly precached URLs.", urlsToPrecache);
|
|
1687
|
+
_nestedGroup("View previously precached URLs.", urlsAlreadyPrecached);
|
|
1688
|
+
logger.groupEnd();
|
|
1569
1689
|
}
|
|
1570
1690
|
};
|
|
1571
1691
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1692
|
+
class PrecacheCacheKeyPlugin {
|
|
1693
|
+
_precacheController;
|
|
1694
|
+
constructor({ precacheController }){
|
|
1695
|
+
this._precacheController = precacheController;
|
|
1696
|
+
}
|
|
1697
|
+
cacheKeyWillBeUsed = async ({ request, params })=>{
|
|
1698
|
+
const cacheKey = params?.cacheKey || this._precacheController.getPrecacheKeyForUrl(request.url);
|
|
1699
|
+
return cacheKey ? new Request(cacheKey, {
|
|
1700
|
+
headers: request.headers
|
|
1701
|
+
}) : request;
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
const parsePrecacheOptions = (controller, { entries, cacheName, plugins, fetchOptions, matchOptions, fallbackToNetwork, directoryIndex, ignoreURLParametersMatching, cleanURLs, urlManipulation, cleanupOutdatedCaches, concurrency, navigateFallback, navigateFallbackAllowlist, navigateFallbackDenylist })=>({
|
|
1706
|
+
entries: entries ?? [],
|
|
1707
|
+
strategyOptions: {
|
|
1708
|
+
cacheName: cacheNames$1.getPrecacheName(cacheName),
|
|
1709
|
+
plugins: [
|
|
1710
|
+
...plugins ?? [],
|
|
1711
|
+
new PrecacheCacheKeyPlugin({
|
|
1712
|
+
precacheController: controller
|
|
1713
|
+
})
|
|
1714
|
+
],
|
|
1715
|
+
fetchOptions,
|
|
1716
|
+
matchOptions,
|
|
1717
|
+
fallbackToNetwork
|
|
1718
|
+
},
|
|
1719
|
+
routeOptions: {
|
|
1720
|
+
directoryIndex,
|
|
1721
|
+
ignoreURLParametersMatching,
|
|
1722
|
+
cleanURLs,
|
|
1723
|
+
urlManipulation
|
|
1724
|
+
},
|
|
1725
|
+
extensionOptions: {
|
|
1726
|
+
cleanupOutdatedCaches,
|
|
1727
|
+
concurrency: concurrency ?? 10,
|
|
1728
|
+
navigateFallback,
|
|
1729
|
+
navigateFallbackAllowlist,
|
|
1730
|
+
navigateFallbackDenylist
|
|
1731
|
+
}
|
|
1732
|
+
});
|
|
1733
|
+
|
|
1734
|
+
class PrecacheInstallReportPlugin {
|
|
1735
|
+
updatedURLs = [];
|
|
1736
|
+
notUpdatedURLs = [];
|
|
1737
|
+
handlerWillStart = async ({ request, state })=>{
|
|
1738
|
+
if (state) {
|
|
1739
|
+
state.originalRequest = request;
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
cachedResponseWillBeUsed = async ({ event, state, cachedResponse })=>{
|
|
1743
|
+
if (event.type === "install") {
|
|
1744
|
+
if (state?.originalRequest && state.originalRequest instanceof Request) {
|
|
1745
|
+
const url = state.originalRequest.url;
|
|
1746
|
+
if (cachedResponse) {
|
|
1747
|
+
this.notUpdatedURLs.push(url);
|
|
1748
|
+
} else {
|
|
1749
|
+
this.updatedURLs.push(url);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
return cachedResponse;
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
const removeIgnoredSearchParams = (urlObject, ignoreURLParametersMatching = [])=>{
|
|
1758
|
+
for (const paramName of [
|
|
1759
|
+
...urlObject.searchParams.keys()
|
|
1760
|
+
]){
|
|
1761
|
+
if (ignoreURLParametersMatching.some((regExp)=>regExp.test(paramName))) {
|
|
1762
|
+
urlObject.searchParams.delete(paramName);
|
|
1579
1763
|
}
|
|
1580
1764
|
}
|
|
1765
|
+
return urlObject;
|
|
1581
1766
|
};
|
|
1582
1767
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1768
|
+
function* generateURLVariations(url, { directoryIndex = "index.html", ignoreURLParametersMatching = [
|
|
1769
|
+
/^utm_/,
|
|
1770
|
+
/^fbclid$/
|
|
1771
|
+
], cleanURLs = true, urlManipulation } = {}) {
|
|
1772
|
+
const urlObject = new URL(url, location.href);
|
|
1773
|
+
urlObject.hash = "";
|
|
1774
|
+
yield urlObject.href;
|
|
1775
|
+
const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching);
|
|
1776
|
+
yield urlWithoutIgnoredParams.href;
|
|
1777
|
+
if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith("/")) {
|
|
1778
|
+
const directoryURL = new URL(urlWithoutIgnoredParams.href);
|
|
1779
|
+
directoryURL.pathname += directoryIndex;
|
|
1780
|
+
yield directoryURL.href;
|
|
1781
|
+
}
|
|
1782
|
+
if (cleanURLs) {
|
|
1783
|
+
const cleanURL = new URL(urlWithoutIgnoredParams.href);
|
|
1784
|
+
cleanURL.pathname += ".html";
|
|
1785
|
+
yield cleanURL.href;
|
|
1786
|
+
}
|
|
1787
|
+
if (urlManipulation) {
|
|
1788
|
+
const additionalURLs = urlManipulation({
|
|
1789
|
+
url: urlObject
|
|
1790
|
+
});
|
|
1791
|
+
for (const urlToAttempt of additionalURLs){
|
|
1792
|
+
yield urlToAttempt.href;
|
|
1589
1793
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
class PrecacheRoute extends Route {
|
|
1798
|
+
constructor(precache, options){
|
|
1799
|
+
const match = ({ request })=>{
|
|
1800
|
+
const urlsToCacheKeys = precache.getUrlsToPrecacheKeys();
|
|
1801
|
+
for (const possibleURL of generateURLVariations(request.url, options)){
|
|
1802
|
+
const cacheKey = urlsToCacheKeys.get(possibleURL);
|
|
1803
|
+
if (cacheKey) {
|
|
1804
|
+
const integrity = precache.getIntegrityForPrecacheKey(cacheKey);
|
|
1805
|
+
return {
|
|
1806
|
+
cacheKey,
|
|
1807
|
+
integrity
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1599
1810
|
}
|
|
1600
|
-
|
|
1811
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1812
|
+
logger.debug(`Precaching did not find a match for ${getFriendlyURL(request.url)}.`);
|
|
1813
|
+
}
|
|
1814
|
+
return;
|
|
1815
|
+
};
|
|
1816
|
+
super(match, precache.strategy);
|
|
1601
1817
|
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
const disableDevLogs = ()=>{
|
|
1821
|
+
self.__WB_DISABLE_DEV_LOGS = true;
|
|
1822
|
+
};
|
|
1823
|
+
const setCacheNameDetails = (details)=>{
|
|
1824
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1825
|
+
for (const key of Object.keys(details)){
|
|
1826
|
+
finalAssertExports.isType(details[key], "string", {
|
|
1827
|
+
moduleName: "@serwist/core",
|
|
1828
|
+
funcName: "setCacheNameDetails",
|
|
1829
|
+
paramName: `details.${key}`
|
|
1610
1830
|
});
|
|
1611
1831
|
}
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
request,
|
|
1617
|
-
logs,
|
|
1618
|
-
handler
|
|
1832
|
+
if (details.precache?.length === 0) {
|
|
1833
|
+
throw new SerwistError("invalid-cache-name", {
|
|
1834
|
+
cacheNameId: "precache",
|
|
1835
|
+
value: details.precache
|
|
1619
1836
|
});
|
|
1620
|
-
timeoutId = id;
|
|
1621
|
-
promises.push(promise);
|
|
1622
1837
|
}
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
});
|
|
1629
|
-
promises.push(networkPromise);
|
|
1630
|
-
const response = await handler.waitUntil((async ()=>{
|
|
1631
|
-
return await handler.waitUntil(Promise.race(promises)) || await networkPromise;
|
|
1632
|
-
})());
|
|
1633
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1634
|
-
logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
|
|
1635
|
-
for (const log of logs){
|
|
1636
|
-
logger.log(log);
|
|
1637
|
-
}
|
|
1638
|
-
messages.printFinalResponse(response);
|
|
1639
|
-
logger.groupEnd();
|
|
1838
|
+
if (details.runtime?.length === 0) {
|
|
1839
|
+
throw new SerwistError("invalid-cache-name", {
|
|
1840
|
+
cacheNameId: "runtime",
|
|
1841
|
+
value: details.runtime
|
|
1842
|
+
});
|
|
1640
1843
|
}
|
|
1641
|
-
if (
|
|
1642
|
-
throw new SerwistError("
|
|
1643
|
-
|
|
1844
|
+
if (details.googleAnalytics?.length === 0) {
|
|
1845
|
+
throw new SerwistError("invalid-cache-name", {
|
|
1846
|
+
cacheNameId: "googleAnalytics",
|
|
1847
|
+
value: details.googleAnalytics
|
|
1644
1848
|
});
|
|
1645
1849
|
}
|
|
1646
|
-
return response;
|
|
1647
1850
|
}
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1851
|
+
cacheNames$1.updateDetails(details);
|
|
1852
|
+
};
|
|
1853
|
+
const registerQuotaErrorCallback = (callback)=>{
|
|
1854
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1855
|
+
finalAssertExports.isType(callback, "function", {
|
|
1856
|
+
moduleName: "@serwist/core",
|
|
1857
|
+
funcName: "register",
|
|
1858
|
+
paramName: "callback"
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
quotaErrorCallbacks.add(callback);
|
|
1862
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1863
|
+
logger.log("Registered a callback to respond to quota errors.", callback);
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
const copyResponse = async (response, modifier)=>{
|
|
1867
|
+
let origin = null;
|
|
1868
|
+
if (response.url) {
|
|
1869
|
+
const responseURL = new URL(response.url);
|
|
1870
|
+
origin = responseURL.origin;
|
|
1871
|
+
}
|
|
1872
|
+
if (origin !== self.location.origin) {
|
|
1873
|
+
throw new SerwistError("cross-origin-copy-response", {
|
|
1874
|
+
origin
|
|
1658
1875
|
});
|
|
1659
|
-
return {
|
|
1660
|
-
promise: timeoutPromise,
|
|
1661
|
-
id: timeoutId
|
|
1662
|
-
};
|
|
1663
1876
|
}
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
logs.push("Unable to get a response from the network. Will respond " + "with a cached response.");
|
|
1877
|
+
const clonedResponse = response.clone();
|
|
1878
|
+
const responseInit = {
|
|
1879
|
+
headers: new Headers(clonedResponse.headers),
|
|
1880
|
+
status: clonedResponse.status,
|
|
1881
|
+
statusText: clonedResponse.statusText
|
|
1882
|
+
};
|
|
1883
|
+
const modifiedResponseInit = modifier ? modifier(responseInit) : responseInit;
|
|
1884
|
+
const body = canConstructResponseFromBodyStream() ? clonedResponse.body : await clonedResponse.blob();
|
|
1885
|
+
return new Response(body, modifiedResponseInit);
|
|
1886
|
+
};
|
|
1887
|
+
|
|
1888
|
+
class PrecacheStrategy extends Strategy {
|
|
1889
|
+
_fallbackToNetwork;
|
|
1890
|
+
static defaultPrecacheCacheabilityPlugin = {
|
|
1891
|
+
async cacheWillUpdate ({ response }) {
|
|
1892
|
+
if (!response || response.status >= 400) {
|
|
1893
|
+
return null;
|
|
1682
1894
|
}
|
|
1895
|
+
return response;
|
|
1683
1896
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
logs.push(`Found a cached response in the '${this.cacheName}' cache.`);
|
|
1689
|
-
} else {
|
|
1690
|
-
logs.push(`No response found in the '${this.cacheName}' cache.`);
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1897
|
+
};
|
|
1898
|
+
static copyRedirectedCacheableResponsesPlugin = {
|
|
1899
|
+
async cacheWillUpdate ({ response }) {
|
|
1900
|
+
return response.redirected ? await copyResponse(response) : response;
|
|
1693
1901
|
}
|
|
1694
|
-
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
class NetworkOnly extends Strategy {
|
|
1699
|
-
_networkTimeoutSeconds;
|
|
1902
|
+
};
|
|
1700
1903
|
constructor(options = {}){
|
|
1904
|
+
options.cacheName = cacheNames$1.getPrecacheName(options.cacheName);
|
|
1701
1905
|
super(options);
|
|
1702
|
-
this.
|
|
1906
|
+
this._fallbackToNetwork = options.fallbackToNetwork !== false;
|
|
1907
|
+
this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);
|
|
1703
1908
|
}
|
|
1704
1909
|
async _handle(request, handler) {
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
className: this.constructor.name,
|
|
1709
|
-
funcName: "_handle",
|
|
1710
|
-
paramName: "request"
|
|
1711
|
-
});
|
|
1712
|
-
}
|
|
1713
|
-
let error = undefined;
|
|
1714
|
-
let response;
|
|
1715
|
-
try {
|
|
1716
|
-
const promises = [
|
|
1717
|
-
handler.fetch(request)
|
|
1718
|
-
];
|
|
1719
|
-
if (this._networkTimeoutSeconds) {
|
|
1720
|
-
const timeoutPromise = timeout(this._networkTimeoutSeconds * 1000);
|
|
1721
|
-
promises.push(timeoutPromise);
|
|
1722
|
-
}
|
|
1723
|
-
response = await Promise.race(promises);
|
|
1724
|
-
if (!response) {
|
|
1725
|
-
throw new Error(`Timed out the network response after ${this._networkTimeoutSeconds} seconds.`);
|
|
1726
|
-
}
|
|
1727
|
-
} catch (err) {
|
|
1728
|
-
if (err instanceof Error) {
|
|
1729
|
-
error = err;
|
|
1730
|
-
}
|
|
1910
|
+
const preloadResponse = await handler.getPreloadResponse();
|
|
1911
|
+
if (preloadResponse) {
|
|
1912
|
+
return preloadResponse;
|
|
1731
1913
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
logger.log("Got response from network.");
|
|
1736
|
-
} else {
|
|
1737
|
-
logger.log("Unable to get a response from the network.");
|
|
1738
|
-
}
|
|
1739
|
-
messages.printFinalResponse(response);
|
|
1740
|
-
logger.groupEnd();
|
|
1914
|
+
const response = await handler.cacheMatch(request);
|
|
1915
|
+
if (response) {
|
|
1916
|
+
return response;
|
|
1741
1917
|
}
|
|
1742
|
-
if (
|
|
1743
|
-
|
|
1744
|
-
url: request.url,
|
|
1745
|
-
error
|
|
1746
|
-
});
|
|
1918
|
+
if (handler.event && handler.event.type === "install") {
|
|
1919
|
+
return await this._handleInstall(request, handler);
|
|
1747
1920
|
}
|
|
1748
|
-
return
|
|
1921
|
+
return await this._handleFetch(request, handler);
|
|
1749
1922
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
const
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
const
|
|
1758
|
-
const
|
|
1759
|
-
const
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
const url = new URL(request.url);
|
|
1767
|
-
try {
|
|
1768
|
-
const params = request.method === "POST" ? new URLSearchParams(await request.clone().text()) : url.searchParams;
|
|
1769
|
-
const originalHitTime = timestamp - (Number(params.get("qt")) || 0);
|
|
1770
|
-
const queueTime = Date.now() - originalHitTime;
|
|
1771
|
-
params.set("qt", String(queueTime));
|
|
1772
|
-
if (config.parameterOverrides) {
|
|
1773
|
-
for (const param of Object.keys(config.parameterOverrides)){
|
|
1774
|
-
const value = config.parameterOverrides[param];
|
|
1775
|
-
params.set(param, value);
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
if (typeof config.hitFilter === "function") {
|
|
1779
|
-
config.hitFilter.call(null, params);
|
|
1780
|
-
}
|
|
1781
|
-
await fetch(new Request(url.origin + url.pathname, {
|
|
1782
|
-
body: params.toString(),
|
|
1783
|
-
method: "POST",
|
|
1784
|
-
mode: "cors",
|
|
1785
|
-
credentials: "omit",
|
|
1786
|
-
headers: {
|
|
1787
|
-
"Content-Type": "text/plain"
|
|
1788
|
-
}
|
|
1789
|
-
}));
|
|
1790
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1791
|
-
logger.log(`Request for '${getFriendlyURL(url.href)}' has been replayed`);
|
|
1792
|
-
}
|
|
1793
|
-
} catch (err) {
|
|
1794
|
-
await queue.unshiftRequest(entry);
|
|
1923
|
+
async _handleFetch(request, handler) {
|
|
1924
|
+
let response;
|
|
1925
|
+
const params = handler.params || {};
|
|
1926
|
+
if (this._fallbackToNetwork) {
|
|
1927
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1928
|
+
logger.warn(`The precached response for ${getFriendlyURL(request.url)} in ${this.cacheName} was not found. Falling back to the network.`);
|
|
1929
|
+
}
|
|
1930
|
+
const integrityInManifest = params.integrity;
|
|
1931
|
+
const integrityInRequest = request.integrity;
|
|
1932
|
+
const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest;
|
|
1933
|
+
response = await handler.fetch(new Request(request, {
|
|
1934
|
+
integrity: request.mode !== "no-cors" ? integrityInRequest || integrityInManifest : undefined
|
|
1935
|
+
}));
|
|
1936
|
+
if (integrityInManifest && noIntegrityConflict && request.mode !== "no-cors") {
|
|
1937
|
+
this._useDefaultCacheabilityPluginIfNeeded();
|
|
1938
|
+
const wasCached = await handler.cachePut(request, response.clone());
|
|
1795
1939
|
if (process.env.NODE_ENV !== "production") {
|
|
1796
|
-
|
|
1940
|
+
if (wasCached) {
|
|
1941
|
+
logger.log(`A response for ${getFriendlyURL(request.url)} was used to "repair" the precache.`);
|
|
1942
|
+
}
|
|
1797
1943
|
}
|
|
1798
|
-
throw err;
|
|
1799
1944
|
}
|
|
1945
|
+
} else {
|
|
1946
|
+
throw new SerwistError("missing-precache-entry", {
|
|
1947
|
+
cacheName: this.cacheName,
|
|
1948
|
+
url: request.url
|
|
1949
|
+
});
|
|
1800
1950
|
}
|
|
1801
1951
|
if (process.env.NODE_ENV !== "production") {
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
new Route(match, handler, "GET"),
|
|
1815
|
-
new Route(match, handler, "POST")
|
|
1816
|
-
];
|
|
1817
|
-
};
|
|
1818
|
-
const createAnalyticsJsRoute = (cacheName)=>{
|
|
1819
|
-
const match = ({ url })=>url.hostname === GOOGLE_ANALYTICS_HOST && url.pathname === ANALYTICS_JS_PATH;
|
|
1820
|
-
const handler = new NetworkFirst({
|
|
1821
|
-
cacheName
|
|
1822
|
-
});
|
|
1823
|
-
return new Route(match, handler, "GET");
|
|
1824
|
-
};
|
|
1825
|
-
const createGtagJsRoute = (cacheName)=>{
|
|
1826
|
-
const match = ({ url })=>url.hostname === GTM_HOST && url.pathname === GTAG_JS_PATH;
|
|
1827
|
-
const handler = new NetworkFirst({
|
|
1828
|
-
cacheName
|
|
1829
|
-
});
|
|
1830
|
-
return new Route(match, handler, "GET");
|
|
1831
|
-
};
|
|
1832
|
-
const createGtmJsRoute = (cacheName)=>{
|
|
1833
|
-
const match = ({ url })=>url.hostname === GTM_HOST && url.pathname === GTM_JS_PATH;
|
|
1834
|
-
const handler = new NetworkFirst({
|
|
1835
|
-
cacheName
|
|
1836
|
-
});
|
|
1837
|
-
return new Route(match, handler, "GET");
|
|
1838
|
-
};
|
|
1839
|
-
const initializeGoogleAnalytics = ({ serwist, cacheName, ...options })=>{
|
|
1840
|
-
const resolvedCacheName = cacheNames$1.getGoogleAnalyticsName(cacheName);
|
|
1841
|
-
const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
|
|
1842
|
-
maxRetentionTime: MAX_RETENTION_TIME,
|
|
1843
|
-
onSync: createOnSyncCallback(options)
|
|
1844
|
-
});
|
|
1845
|
-
const routes = [
|
|
1846
|
-
createGtmJsRoute(resolvedCacheName),
|
|
1847
|
-
createAnalyticsJsRoute(resolvedCacheName),
|
|
1848
|
-
createGtagJsRoute(resolvedCacheName),
|
|
1849
|
-
...createCollectRoutes(bgSyncPlugin)
|
|
1850
|
-
];
|
|
1851
|
-
for (const route of routes){
|
|
1852
|
-
serwist.registerRoute(route);
|
|
1952
|
+
const cacheKey = params.cacheKey || await handler.getCacheKey(request, "read");
|
|
1953
|
+
logger.groupCollapsed(`Precaching is responding to: ${getFriendlyURL(request.url)}`);
|
|
1954
|
+
logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`);
|
|
1955
|
+
logger.groupCollapsed("View request details here.");
|
|
1956
|
+
logger.log(request);
|
|
1957
|
+
logger.groupEnd();
|
|
1958
|
+
logger.groupCollapsed("View response details here.");
|
|
1959
|
+
logger.log(response);
|
|
1960
|
+
logger.groupEnd();
|
|
1961
|
+
logger.groupEnd();
|
|
1962
|
+
}
|
|
1963
|
+
return response;
|
|
1853
1964
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1965
|
+
async _handleInstall(request, handler) {
|
|
1966
|
+
this._useDefaultCacheabilityPluginIfNeeded();
|
|
1967
|
+
const response = await handler.fetch(request);
|
|
1968
|
+
const wasCached = await handler.cachePut(request, response.clone());
|
|
1969
|
+
if (!wasCached) {
|
|
1970
|
+
throw new SerwistError("bad-precaching-response", {
|
|
1971
|
+
url: request.url,
|
|
1972
|
+
status: response.status
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
return response;
|
|
1976
|
+
}
|
|
1977
|
+
_useDefaultCacheabilityPluginIfNeeded() {
|
|
1978
|
+
let defaultPluginIndex = null;
|
|
1979
|
+
let cacheWillUpdatePluginCount = 0;
|
|
1980
|
+
for (const [index, plugin] of this.plugins.entries()){
|
|
1981
|
+
if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) {
|
|
1982
|
+
continue;
|
|
1866
1983
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
|
|
1870
|
-
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.`);
|
|
1984
|
+
if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
|
|
1985
|
+
defaultPluginIndex = index;
|
|
1871
1986
|
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1875
|
-
if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
|
|
1876
|
-
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.`);
|
|
1877
|
-
}
|
|
1987
|
+
if (plugin.cacheWillUpdate) {
|
|
1988
|
+
cacheWillUpdatePluginCount++;
|
|
1878
1989
|
}
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1990
|
+
}
|
|
1991
|
+
if (cacheWillUpdatePluginCount === 0) {
|
|
1992
|
+
this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);
|
|
1993
|
+
} else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {
|
|
1994
|
+
this.plugins.splice(defaultPluginIndex, 1);
|
|
1995
|
+
}
|
|
1885
1996
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
class Precache {
|
|
2000
|
+
_urlsToCacheKeys = new Map();
|
|
2001
|
+
_urlsToCacheModes = new Map();
|
|
2002
|
+
_cacheKeysToIntegrities = new Map();
|
|
2003
|
+
_strategy;
|
|
2004
|
+
_options;
|
|
2005
|
+
_routeOptions;
|
|
2006
|
+
constructor(precacheOptions){
|
|
2007
|
+
const { entries, strategyOptions, routeOptions, extensionOptions: controllerOptions } = parsePrecacheOptions(this, precacheOptions);
|
|
2008
|
+
this.addToCacheList(entries);
|
|
2009
|
+
this._strategy = new PrecacheStrategy(strategyOptions);
|
|
2010
|
+
this._options = controllerOptions;
|
|
2011
|
+
this._routeOptions = routeOptions;
|
|
1888
2012
|
}
|
|
1889
|
-
|
|
1890
|
-
return
|
|
2013
|
+
get strategy() {
|
|
2014
|
+
return this._strategy;
|
|
1891
2015
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2016
|
+
addToCacheList(entries) {
|
|
2017
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2018
|
+
finalAssertExports.isArray(entries, {
|
|
2019
|
+
moduleName: "serwist",
|
|
2020
|
+
className: "PrecacheController",
|
|
2021
|
+
funcName: "addEntries",
|
|
2022
|
+
paramName: "entries"
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
const urlsToWarnAbout = [];
|
|
2026
|
+
for (const entry of entries){
|
|
2027
|
+
if (typeof entry === "string") {
|
|
2028
|
+
urlsToWarnAbout.push(entry);
|
|
2029
|
+
} else if (entry && !entry.integrity && entry.revision === undefined) {
|
|
2030
|
+
urlsToWarnAbout.push(entry.url);
|
|
2031
|
+
}
|
|
2032
|
+
const { cacheKey, url } = createCacheKey(entry);
|
|
2033
|
+
const cacheMode = typeof entry !== "string" && entry.revision ? "reload" : "default";
|
|
2034
|
+
if (this._urlsToCacheKeys.has(url) && this._urlsToCacheKeys.get(url) !== cacheKey) {
|
|
2035
|
+
throw new SerwistError("add-to-cache-list-conflicting-entries", {
|
|
2036
|
+
firstEntry: this._urlsToCacheKeys.get(url),
|
|
2037
|
+
secondEntry: cacheKey
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
if (typeof entry !== "string" && entry.integrity) {
|
|
2041
|
+
if (this._cacheKeysToIntegrities.has(cacheKey) && this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) {
|
|
2042
|
+
throw new SerwistError("add-to-cache-list-conflicting-integrities", {
|
|
2043
|
+
url
|
|
2044
|
+
});
|
|
1912
2045
|
}
|
|
1913
|
-
|
|
1914
|
-
|
|
2046
|
+
this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);
|
|
2047
|
+
}
|
|
2048
|
+
this._urlsToCacheKeys.set(url, cacheKey);
|
|
2049
|
+
this._urlsToCacheModes.set(url, cacheMode);
|
|
2050
|
+
if (urlsToWarnAbout.length > 0) {
|
|
2051
|
+
const warningMessage = `Serwist is precaching URLs without revision info: ${urlsToWarnAbout.join(", ")}\nThis is generally NOT safe, as you risk serving outdated assets.`;
|
|
2052
|
+
if (process.env.NODE_ENV === "production") {
|
|
2053
|
+
console.warn(warningMessage);
|
|
2054
|
+
} else {
|
|
2055
|
+
logger.warn(warningMessage);
|
|
1915
2056
|
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
init({ serwist }) {
|
|
2061
|
+
registerRoute(serwist, new PrecacheRoute(this, this._routeOptions));
|
|
2062
|
+
if (this._options.navigateFallback) {
|
|
2063
|
+
registerRoute(serwist, new NavigationRoute(this.createHandlerBoundToUrl(this._options.navigateFallback), {
|
|
2064
|
+
allowlist: this._options.navigateFallbackAllowlist,
|
|
2065
|
+
denylist: this._options.navigateFallbackDenylist
|
|
1916
2066
|
}));
|
|
1917
|
-
});
|
|
1918
|
-
} else {
|
|
1919
|
-
if (process.env.NODE_ENV !== "production") {
|
|
1920
|
-
logger.log("Navigation preloading is not supported in this browser.");
|
|
1921
2067
|
}
|
|
1922
2068
|
}
|
|
1923
|
-
}
|
|
1924
|
-
const
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
2069
|
+
async install({ event }) {
|
|
2070
|
+
const installReportPlugin = new PrecacheInstallReportPlugin();
|
|
2071
|
+
this._strategy.plugins.push(installReportPlugin);
|
|
2072
|
+
await parallel(this._options.concurrency, Array.from(this._urlsToCacheKeys.entries()), async ([url, cacheKey])=>{
|
|
2073
|
+
const integrity = this._cacheKeysToIntegrities.get(cacheKey);
|
|
2074
|
+
const cacheMode = this._urlsToCacheModes.get(url);
|
|
2075
|
+
const request = new Request(url, {
|
|
2076
|
+
integrity,
|
|
2077
|
+
cache: cacheMode,
|
|
2078
|
+
credentials: "same-origin"
|
|
2079
|
+
});
|
|
2080
|
+
await Promise.all(this._strategy.handleAll({
|
|
2081
|
+
event,
|
|
2082
|
+
request,
|
|
2083
|
+
url: new URL(request.url),
|
|
2084
|
+
params: {
|
|
2085
|
+
cacheKey
|
|
1930
2086
|
}
|
|
1931
2087
|
}));
|
|
1932
2088
|
});
|
|
1933
|
-
|
|
2089
|
+
const { updatedURLs, notUpdatedURLs } = installReportPlugin;
|
|
1934
2090
|
if (process.env.NODE_ENV !== "production") {
|
|
1935
|
-
|
|
2091
|
+
printInstallDetails(updatedURLs, notUpdatedURLs);
|
|
1936
2092
|
}
|
|
1937
2093
|
}
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
const
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
}
|
|
2094
|
+
async activate() {
|
|
2095
|
+
const cache = await self.caches.open(this._strategy.cacheName);
|
|
2096
|
+
const currentlyCachedRequests = await cache.keys();
|
|
2097
|
+
const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());
|
|
2098
|
+
const deletedCacheRequests = [];
|
|
2099
|
+
for (const request of currentlyCachedRequests){
|
|
2100
|
+
if (!expectedCacheKeys.has(request.url)) {
|
|
2101
|
+
await cache.delete(request);
|
|
2102
|
+
deletedCacheRequests.push(request.url);
|
|
2103
|
+
}
|
|
1948
2104
|
}
|
|
1949
|
-
if (
|
|
1950
|
-
|
|
1951
|
-
cacheNameId: "precache",
|
|
1952
|
-
value: details.precache
|
|
1953
|
-
});
|
|
2105
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2106
|
+
printCleanupDetails(deletedCacheRequests);
|
|
1954
2107
|
}
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2108
|
+
}
|
|
2109
|
+
getUrlsToPrecacheKeys() {
|
|
2110
|
+
return this._urlsToCacheKeys;
|
|
2111
|
+
}
|
|
2112
|
+
getPrecachedUrls() {
|
|
2113
|
+
return [
|
|
2114
|
+
...this._urlsToCacheKeys.keys()
|
|
2115
|
+
];
|
|
2116
|
+
}
|
|
2117
|
+
getPrecacheKeyForUrl(url) {
|
|
2118
|
+
const urlObject = new URL(url, location.href);
|
|
2119
|
+
return this._urlsToCacheKeys.get(urlObject.href);
|
|
2120
|
+
}
|
|
2121
|
+
getIntegrityForPrecacheKey(cacheKey) {
|
|
2122
|
+
return this._cacheKeysToIntegrities.get(cacheKey);
|
|
2123
|
+
}
|
|
2124
|
+
async matchPrecache(request) {
|
|
2125
|
+
const url = request instanceof Request ? request.url : request;
|
|
2126
|
+
const cacheKey = this.getPrecacheKeyForUrl(url);
|
|
2127
|
+
if (cacheKey) {
|
|
2128
|
+
const cache = await self.caches.open(this._strategy.cacheName);
|
|
2129
|
+
return cache.match(cacheKey);
|
|
1960
2130
|
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
2131
|
+
return undefined;
|
|
2132
|
+
}
|
|
2133
|
+
createHandlerBoundToUrl(url) {
|
|
2134
|
+
const cacheKey = this.getPrecacheKeyForUrl(url);
|
|
2135
|
+
if (!cacheKey) {
|
|
2136
|
+
throw new SerwistError("non-precached-url", {
|
|
2137
|
+
url
|
|
1965
2138
|
});
|
|
1966
2139
|
}
|
|
2140
|
+
return (options)=>{
|
|
2141
|
+
options.request = new Request(url);
|
|
2142
|
+
options.params = {
|
|
2143
|
+
cacheKey,
|
|
2144
|
+
...options.params
|
|
2145
|
+
};
|
|
2146
|
+
return this._strategy.handle(options);
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
class PrecacheFallbackPlugin {
|
|
2152
|
+
_fallbackUrls;
|
|
2153
|
+
_serwist;
|
|
2154
|
+
constructor({ fallbackUrls, serwist }){
|
|
2155
|
+
this._fallbackUrls = fallbackUrls;
|
|
2156
|
+
this._serwist = serwist instanceof Serwist ? serwist.state : serwist;
|
|
2157
|
+
}
|
|
2158
|
+
async handlerDidError(param) {
|
|
2159
|
+
for (const fallback of this._fallbackUrls){
|
|
2160
|
+
if (typeof fallback === "string") {
|
|
2161
|
+
const fallbackResponse = handleRequest(this._serwist, {
|
|
2162
|
+
request: new Request(fallback, {
|
|
2163
|
+
credentials: "same-origin"
|
|
2164
|
+
}),
|
|
2165
|
+
event: param.event
|
|
2166
|
+
});
|
|
2167
|
+
if (fallbackResponse !== undefined) {
|
|
2168
|
+
return await fallbackResponse;
|
|
2169
|
+
}
|
|
2170
|
+
} else if (fallback.matcher(param)) {
|
|
2171
|
+
const fallbackResponse = handleRequest(this._serwist, {
|
|
2172
|
+
request: new Request(fallback.url, {
|
|
2173
|
+
credentials: "same-origin"
|
|
2174
|
+
}),
|
|
2175
|
+
event: param.event
|
|
2176
|
+
});
|
|
2177
|
+
if (fallbackResponse !== undefined) {
|
|
2178
|
+
return await fallbackResponse;
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
return undefined;
|
|
1967
2183
|
}
|
|
1968
|
-
|
|
1969
|
-
};
|
|
2184
|
+
}
|
|
1970
2185
|
|
|
1971
|
-
class
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
this.
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
this.
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
if (!!importScripts && importScripts.length > 0) self.importScripts(...importScripts);
|
|
1986
|
-
if (navigationPreload) enableNavigationPreload();
|
|
1987
|
-
if (cacheId !== undefined) {
|
|
1988
|
-
setCacheNameDetails({
|
|
1989
|
-
prefix: cacheId
|
|
2186
|
+
class RuntimeCache {
|
|
2187
|
+
_entries;
|
|
2188
|
+
_options;
|
|
2189
|
+
constructor(entries, options = {}){
|
|
2190
|
+
this._entries = entries;
|
|
2191
|
+
this._options = options;
|
|
2192
|
+
this.init = this.init.bind(this);
|
|
2193
|
+
this.install = this.install.bind(this);
|
|
2194
|
+
}
|
|
2195
|
+
init({ serwist }) {
|
|
2196
|
+
if (this._options.fallbacks !== undefined) {
|
|
2197
|
+
const fallbackPlugin = new PrecacheFallbackPlugin({
|
|
2198
|
+
fallbackUrls: this._options.fallbacks.entries,
|
|
2199
|
+
serwist
|
|
1990
2200
|
});
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
} else {
|
|
1995
|
-
self.addEventListener("message", (event)=>{
|
|
1996
|
-
if (event.data && event.data.type === "SKIP_WAITING") {
|
|
1997
|
-
self.skipWaiting();
|
|
2201
|
+
this._entries.forEach((cacheEntry)=>{
|
|
2202
|
+
if (cacheEntry.handler instanceof Strategy && !cacheEntry.handler.plugins.some((plugin)=>"handlerDidError" in plugin)) {
|
|
2203
|
+
cacheEntry.handler.plugins.push(fallbackPlugin);
|
|
1998
2204
|
}
|
|
1999
2205
|
});
|
|
2000
2206
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
if (runtimeCaching) {
|
|
2004
|
-
if (!this._controllers?.some((controller)=>controller instanceof RuntimeCacheController)) {
|
|
2005
|
-
this._controllers.unshift(new RuntimeCacheController(runtimeCaching, {
|
|
2006
|
-
fallbacks
|
|
2007
|
-
}));
|
|
2008
|
-
} else if (process.env.NODE_ENV !== "production") {
|
|
2009
|
-
logger.warn("You have migrated to the Controller pattern, so setting `runtimeCaching` is a no-op.");
|
|
2010
|
-
}
|
|
2207
|
+
for (const entry of this._entries){
|
|
2208
|
+
registerCapture(serwist, entry.matcher, entry.handler, entry.method);
|
|
2011
2209
|
}
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2210
|
+
}
|
|
2211
|
+
async install({ event, serwist }) {
|
|
2212
|
+
const concurrency = this._options.warmOptions?.concurrency ?? 10;
|
|
2213
|
+
if (this._options.warmEntries) {
|
|
2214
|
+
await parallel(concurrency, this._options.warmEntries, async (entry)=>{
|
|
2215
|
+
const request = entry instanceof Request ? entry : typeof entry === "string" ? new Request(entry, {
|
|
2216
|
+
credentials: "same-origin"
|
|
2217
|
+
}) : new Request(entry.url, {
|
|
2218
|
+
integrity: entry.integrity,
|
|
2219
|
+
credentials: "same-origin"
|
|
2017
2220
|
});
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
serwist: this
|
|
2221
|
+
await handleRequest(serwist, {
|
|
2222
|
+
request,
|
|
2223
|
+
event
|
|
2022
2224
|
});
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
for (const callback of this.iterateControllers("init")){
|
|
2026
|
-
callback({
|
|
2027
|
-
serwist: this
|
|
2028
2225
|
});
|
|
2029
2226
|
}
|
|
2030
|
-
if (disableDevLogs$1) disableDevLogs();
|
|
2031
|
-
}
|
|
2032
|
-
*iterateControllers(name) {
|
|
2033
|
-
if (!this._controllers) return;
|
|
2034
|
-
for (const controller of this._controllers){
|
|
2035
|
-
if (typeof controller[name] === "function") {
|
|
2036
|
-
const callback = (param)=>{
|
|
2037
|
-
controller[name](param);
|
|
2038
|
-
};
|
|
2039
|
-
yield callback;
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
get precache() {
|
|
2044
|
-
return this._precacheController;
|
|
2045
|
-
}
|
|
2046
|
-
get precacheStrategy() {
|
|
2047
|
-
return this._precacheController.strategy;
|
|
2048
|
-
}
|
|
2049
|
-
get routes() {
|
|
2050
|
-
return this._routes;
|
|
2051
2227
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
self.addEventListener("fetch", this.handleFetch);
|
|
2056
|
-
self.addEventListener("message", this.handleCache);
|
|
2228
|
+
warmRuntimeCache(entries) {
|
|
2229
|
+
if (!this._options.warmEntries) this._options.warmEntries = [];
|
|
2230
|
+
this._options.warmEntries.push(...entries);
|
|
2057
2231
|
}
|
|
2058
|
-
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
const addEventListeners = (state)=>{
|
|
2235
|
+
self.addEventListener("install", createInstallHandler(state));
|
|
2236
|
+
self.addEventListener("activate", createActivateHandler(state));
|
|
2237
|
+
self.addEventListener("fetch", createFetchHandler(state));
|
|
2238
|
+
self.addEventListener("message", createCacheHandler(state));
|
|
2239
|
+
};
|
|
2240
|
+
const createInstallHandler = (state)=>{
|
|
2241
|
+
return (event)=>{
|
|
2059
2242
|
return waitUntil(event, async ()=>{
|
|
2060
|
-
for (const callback of
|
|
2243
|
+
for (const callback of iterateExtensions(state, "install")){
|
|
2061
2244
|
await callback({
|
|
2062
2245
|
event,
|
|
2063
|
-
serwist:
|
|
2246
|
+
serwist: state
|
|
2064
2247
|
});
|
|
2065
2248
|
}
|
|
2066
2249
|
});
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2250
|
+
};
|
|
2251
|
+
};
|
|
2252
|
+
const createActivateHandler = (state)=>{
|
|
2253
|
+
return (event)=>{
|
|
2069
2254
|
return waitUntil(event, async ()=>{
|
|
2070
|
-
for (const callback of
|
|
2255
|
+
for (const callback of iterateExtensions(state, "activate")){
|
|
2071
2256
|
await callback({
|
|
2072
2257
|
event,
|
|
2073
|
-
serwist:
|
|
2258
|
+
serwist: state
|
|
2074
2259
|
});
|
|
2075
2260
|
}
|
|
2076
2261
|
});
|
|
2077
|
-
}
|
|
2078
|
-
|
|
2262
|
+
};
|
|
2263
|
+
};
|
|
2264
|
+
const createFetchHandler = (state)=>{
|
|
2265
|
+
return (event)=>{
|
|
2079
2266
|
const { request } = event;
|
|
2080
|
-
const responsePromise =
|
|
2267
|
+
const responsePromise = handleRequest(state, {
|
|
2081
2268
|
request,
|
|
2082
2269
|
event
|
|
2083
2270
|
});
|
|
2084
2271
|
if (responsePromise) {
|
|
2085
2272
|
event.respondWith(responsePromise);
|
|
2086
2273
|
}
|
|
2087
|
-
}
|
|
2088
|
-
|
|
2274
|
+
};
|
|
2275
|
+
};
|
|
2276
|
+
const createCacheHandler = (state)=>{
|
|
2277
|
+
return (event)=>{
|
|
2089
2278
|
if (event.data && event.data.type === "CACHE_URLS") {
|
|
2090
2279
|
const { payload } = event.data;
|
|
2091
2280
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -2098,7 +2287,7 @@ class Serwist {
|
|
|
2098
2287
|
} else {
|
|
2099
2288
|
request = new Request(...entry);
|
|
2100
2289
|
}
|
|
2101
|
-
return
|
|
2290
|
+
return handleRequest(state, {
|
|
2102
2291
|
request,
|
|
2103
2292
|
event
|
|
2104
2293
|
});
|
|
@@ -2108,218 +2297,170 @@ class Serwist {
|
|
|
2108
2297
|
void requestPromises.then(()=>event.ports[0].postMessage(true));
|
|
2109
2298
|
}
|
|
2110
2299
|
}
|
|
2300
|
+
};
|
|
2301
|
+
};
|
|
2302
|
+
const setDefaultHandler = (state, handler, method = defaultMethod)=>{
|
|
2303
|
+
state.defaultHandlerMap.set(method, normalizeHandler(handler));
|
|
2304
|
+
};
|
|
2305
|
+
const setCatchHandler = (state, handler)=>{
|
|
2306
|
+
state.catchHandler = normalizeHandler(handler);
|
|
2307
|
+
};
|
|
2308
|
+
function* iterateExtensions(state, name) {
|
|
2309
|
+
if (!state.extensions) return;
|
|
2310
|
+
for (const controller of state.extensions){
|
|
2311
|
+
if (typeof controller[name] === "function") {
|
|
2312
|
+
const callback = (param)=>{
|
|
2313
|
+
controller[name](param);
|
|
2314
|
+
};
|
|
2315
|
+
yield callback;
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
const createSerwist = ({ precache, skipWaiting = false, importScripts, navigationPreload = false, cacheId, clientsClaim: clientsClaim$1 = false, disableDevLogs: disableDevLogs$1 = false, extensions = [] } = {})=>{
|
|
2321
|
+
if (importScripts?.length) self.importScripts(...importScripts);
|
|
2322
|
+
if (navigationPreload) enableNavigationPreload();
|
|
2323
|
+
if (cacheId) setCacheNameDetails({
|
|
2324
|
+
prefix: cacheId
|
|
2325
|
+
});
|
|
2326
|
+
if (skipWaiting) {
|
|
2327
|
+
self.skipWaiting();
|
|
2328
|
+
} else {
|
|
2329
|
+
self.addEventListener("message", (event)=>{
|
|
2330
|
+
if (event.data?.type === "SKIP_WAITING") {
|
|
2331
|
+
self.skipWaiting();
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
if (clientsClaim$1) clientsClaim();
|
|
2336
|
+
const precacheExtension = new Precache(precache ?? {
|
|
2337
|
+
entries: []
|
|
2338
|
+
});
|
|
2339
|
+
const routes = new Map();
|
|
2340
|
+
const defaultHandlerMap = new Map();
|
|
2341
|
+
const exts = [
|
|
2342
|
+
precacheExtension,
|
|
2343
|
+
...extensions
|
|
2344
|
+
];
|
|
2345
|
+
const state = {
|
|
2346
|
+
get routes () {
|
|
2347
|
+
return routes;
|
|
2348
|
+
},
|
|
2349
|
+
get defaultHandlerMap () {
|
|
2350
|
+
return defaultHandlerMap;
|
|
2351
|
+
},
|
|
2352
|
+
get precache () {
|
|
2353
|
+
return precacheExtension;
|
|
2354
|
+
},
|
|
2355
|
+
get extensions () {
|
|
2356
|
+
return exts;
|
|
2357
|
+
}
|
|
2358
|
+
};
|
|
2359
|
+
for (const callback of iterateExtensions(state, "init")){
|
|
2360
|
+
callback({
|
|
2361
|
+
serwist: state
|
|
2362
|
+
});
|
|
2363
|
+
}
|
|
2364
|
+
if (disableDevLogs$1) disableDevLogs();
|
|
2365
|
+
return state;
|
|
2366
|
+
};
|
|
2367
|
+
|
|
2368
|
+
class Serwist {
|
|
2369
|
+
_state;
|
|
2370
|
+
_installHandler;
|
|
2371
|
+
_activateHandler;
|
|
2372
|
+
_fetchHandler;
|
|
2373
|
+
_cacheHandler;
|
|
2374
|
+
constructor({ precacheEntries, precacheOptions, skipWaiting = false, importScripts, navigationPreload = false, cacheId, clientsClaim = false, runtimeCaching, offlineAnalyticsConfig, disableDevLogs = false, fallbacks, extensions } = {}){
|
|
2375
|
+
this.handleInstall = this.handleInstall.bind(this);
|
|
2376
|
+
this.handleActivate = this.handleActivate.bind(this);
|
|
2377
|
+
this.handleFetch = this.handleFetch.bind(this);
|
|
2378
|
+
this.handleCache = this.handleCache.bind(this);
|
|
2379
|
+
this._state = createSerwist({
|
|
2380
|
+
precache: {
|
|
2381
|
+
entries: precacheEntries ?? [],
|
|
2382
|
+
...precacheOptions
|
|
2383
|
+
},
|
|
2384
|
+
extensions: [
|
|
2385
|
+
!extensions?.some((ext)=>ext instanceof RuntimeCache) && runtimeCaching !== undefined ? new RuntimeCache(runtimeCaching, {
|
|
2386
|
+
fallbacks
|
|
2387
|
+
}) : undefined,
|
|
2388
|
+
!extensions?.some((ext)=>ext instanceof GoogleAnalytics) && offlineAnalyticsConfig !== undefined ? typeof offlineAnalyticsConfig === "boolean" ? offlineAnalyticsConfig ? new GoogleAnalytics() : undefined : new GoogleAnalytics(offlineAnalyticsConfig) : undefined,
|
|
2389
|
+
...extensions ?? []
|
|
2390
|
+
].filter((extension)=>extension !== undefined),
|
|
2391
|
+
skipWaiting,
|
|
2392
|
+
importScripts,
|
|
2393
|
+
navigationPreload,
|
|
2394
|
+
cacheId,
|
|
2395
|
+
clientsClaim,
|
|
2396
|
+
disableDevLogs
|
|
2397
|
+
});
|
|
2398
|
+
this._installHandler = createInstallHandler(this._state);
|
|
2399
|
+
this._activateHandler = createActivateHandler(this._state);
|
|
2400
|
+
this._fetchHandler = createFetchHandler(this._state);
|
|
2401
|
+
this._cacheHandler = createCacheHandler(this._state);
|
|
2402
|
+
}
|
|
2403
|
+
get precache() {
|
|
2404
|
+
return this._state.precache;
|
|
2405
|
+
}
|
|
2406
|
+
get precacheStrategy() {
|
|
2407
|
+
return this._state.precache.strategy;
|
|
2408
|
+
}
|
|
2409
|
+
get routes() {
|
|
2410
|
+
return this._state.routes;
|
|
2411
|
+
}
|
|
2412
|
+
get state() {
|
|
2413
|
+
return this._state;
|
|
2414
|
+
}
|
|
2415
|
+
addEventListeners() {
|
|
2416
|
+
self.addEventListener("install", this._installHandler);
|
|
2417
|
+
self.addEventListener("activate", this._activateHandler);
|
|
2418
|
+
self.addEventListener("fetch", this._fetchHandler);
|
|
2419
|
+
self.addEventListener("message", this._cacheHandler);
|
|
2111
2420
|
}
|
|
2112
|
-
|
|
2113
|
-
this.
|
|
2421
|
+
handleInstall(event) {
|
|
2422
|
+
return this._installHandler(event);
|
|
2423
|
+
}
|
|
2424
|
+
handleActivate(event) {
|
|
2425
|
+
return this._activateHandler(event);
|
|
2426
|
+
}
|
|
2427
|
+
handleFetch(event) {
|
|
2428
|
+
return this._fetchHandler(event);
|
|
2429
|
+
}
|
|
2430
|
+
handleCache(event) {
|
|
2431
|
+
return this._cacheHandler(event);
|
|
2432
|
+
}
|
|
2433
|
+
setDefaultHandler(handler, method) {
|
|
2434
|
+
setDefaultHandler(this._state, handler, method);
|
|
2114
2435
|
}
|
|
2115
2436
|
setCatchHandler(handler) {
|
|
2116
|
-
this.
|
|
2437
|
+
setCatchHandler(this._state, handler);
|
|
2117
2438
|
}
|
|
2118
2439
|
registerCapture(capture, handler, method) {
|
|
2119
|
-
|
|
2120
|
-
this.registerRoute(route);
|
|
2121
|
-
return route;
|
|
2440
|
+
return registerCapture(this._state, capture, handler, method);
|
|
2122
2441
|
}
|
|
2123
2442
|
registerRoute(route) {
|
|
2124
|
-
|
|
2125
|
-
finalAssertExports.isType(route, "object", {
|
|
2126
|
-
moduleName: "serwist",
|
|
2127
|
-
className: "Serwist",
|
|
2128
|
-
funcName: "registerRoute",
|
|
2129
|
-
paramName: "route"
|
|
2130
|
-
});
|
|
2131
|
-
finalAssertExports.hasMethod(route, "match", {
|
|
2132
|
-
moduleName: "serwist",
|
|
2133
|
-
className: "Serwist",
|
|
2134
|
-
funcName: "registerRoute",
|
|
2135
|
-
paramName: "route"
|
|
2136
|
-
});
|
|
2137
|
-
finalAssertExports.isType(route.handler, "object", {
|
|
2138
|
-
moduleName: "serwist",
|
|
2139
|
-
className: "Serwist",
|
|
2140
|
-
funcName: "registerRoute",
|
|
2141
|
-
paramName: "route"
|
|
2142
|
-
});
|
|
2143
|
-
finalAssertExports.hasMethod(route.handler, "handle", {
|
|
2144
|
-
moduleName: "serwist",
|
|
2145
|
-
className: "Serwist",
|
|
2146
|
-
funcName: "registerRoute",
|
|
2147
|
-
paramName: "route.handler"
|
|
2148
|
-
});
|
|
2149
|
-
finalAssertExports.isType(route.method, "string", {
|
|
2150
|
-
moduleName: "serwist",
|
|
2151
|
-
className: "Serwist",
|
|
2152
|
-
funcName: "registerRoute",
|
|
2153
|
-
paramName: "route.method"
|
|
2154
|
-
});
|
|
2155
|
-
}
|
|
2156
|
-
if (!this._routes.has(route.method)) {
|
|
2157
|
-
this._routes.set(route.method, []);
|
|
2158
|
-
}
|
|
2159
|
-
this._routes.get(route.method).push(route);
|
|
2443
|
+
registerRoute(this._state, route);
|
|
2160
2444
|
}
|
|
2161
2445
|
unregisterRoute(route) {
|
|
2162
|
-
|
|
2163
|
-
throw new SerwistError("unregister-route-but-not-found-with-method", {
|
|
2164
|
-
method: route.method
|
|
2165
|
-
});
|
|
2166
|
-
}
|
|
2167
|
-
const routeIndex = this._routes.get(route.method).indexOf(route);
|
|
2168
|
-
if (routeIndex > -1) {
|
|
2169
|
-
this._routes.get(route.method).splice(routeIndex, 1);
|
|
2170
|
-
} else {
|
|
2171
|
-
throw new SerwistError("unregister-route-route-not-registered");
|
|
2172
|
-
}
|
|
2446
|
+
unregisterRoute(this._state, route);
|
|
2173
2447
|
}
|
|
2174
2448
|
handleRequest({ request, event }) {
|
|
2175
|
-
|
|
2176
|
-
finalAssertExports.isInstance(request, Request, {
|
|
2177
|
-
moduleName: "serwist",
|
|
2178
|
-
className: "Serwist",
|
|
2179
|
-
funcName: "handleRequest",
|
|
2180
|
-
paramName: "options.request"
|
|
2181
|
-
});
|
|
2182
|
-
}
|
|
2183
|
-
const url = new URL(request.url, location.href);
|
|
2184
|
-
if (!url.protocol.startsWith("http")) {
|
|
2185
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2186
|
-
logger.debug("Router only supports URLs that start with 'http'.");
|
|
2187
|
-
}
|
|
2188
|
-
return;
|
|
2189
|
-
}
|
|
2190
|
-
const sameOrigin = url.origin === location.origin;
|
|
2191
|
-
const { params, route } = this.findMatchingRoute({
|
|
2192
|
-
event,
|
|
2449
|
+
return handleRequest(this._state, {
|
|
2193
2450
|
request,
|
|
2194
|
-
|
|
2195
|
-
url
|
|
2451
|
+
event
|
|
2196
2452
|
});
|
|
2197
|
-
let handler = route?.handler;
|
|
2198
|
-
const debugMessages = [];
|
|
2199
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2200
|
-
if (handler) {
|
|
2201
|
-
debugMessages.push([
|
|
2202
|
-
"Found a route to handle this request:",
|
|
2203
|
-
route
|
|
2204
|
-
]);
|
|
2205
|
-
if (params) {
|
|
2206
|
-
debugMessages.push([
|
|
2207
|
-
`Passing the following params to the route's handler:`,
|
|
2208
|
-
params
|
|
2209
|
-
]);
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
const method = request.method;
|
|
2214
|
-
if (!handler && this._defaultHandlerMap.has(method)) {
|
|
2215
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2216
|
-
debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);
|
|
2217
|
-
}
|
|
2218
|
-
handler = this._defaultHandlerMap.get(method);
|
|
2219
|
-
}
|
|
2220
|
-
if (!handler) {
|
|
2221
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2222
|
-
logger.debug(`No route found for: ${getFriendlyURL(url)}`);
|
|
2223
|
-
}
|
|
2224
|
-
return;
|
|
2225
|
-
}
|
|
2226
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2227
|
-
logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
|
|
2228
|
-
for (const msg of debugMessages){
|
|
2229
|
-
if (Array.isArray(msg)) {
|
|
2230
|
-
logger.log(...msg);
|
|
2231
|
-
} else {
|
|
2232
|
-
logger.log(msg);
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
logger.groupEnd();
|
|
2236
|
-
}
|
|
2237
|
-
let responsePromise;
|
|
2238
|
-
try {
|
|
2239
|
-
responsePromise = handler.handle({
|
|
2240
|
-
url,
|
|
2241
|
-
request,
|
|
2242
|
-
event,
|
|
2243
|
-
params
|
|
2244
|
-
});
|
|
2245
|
-
} catch (err) {
|
|
2246
|
-
responsePromise = Promise.reject(err);
|
|
2247
|
-
}
|
|
2248
|
-
const catchHandler = route?.catchHandler;
|
|
2249
|
-
if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
|
|
2250
|
-
responsePromise = responsePromise.catch(async (err)=>{
|
|
2251
|
-
if (catchHandler) {
|
|
2252
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2253
|
-
logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
|
|
2254
|
-
logger.error("Error thrown by:", route);
|
|
2255
|
-
logger.error(err);
|
|
2256
|
-
logger.groupEnd();
|
|
2257
|
-
}
|
|
2258
|
-
try {
|
|
2259
|
-
return await catchHandler.handle({
|
|
2260
|
-
url,
|
|
2261
|
-
request,
|
|
2262
|
-
event,
|
|
2263
|
-
params
|
|
2264
|
-
});
|
|
2265
|
-
} catch (catchErr) {
|
|
2266
|
-
if (catchErr instanceof Error) {
|
|
2267
|
-
err = catchErr;
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
if (this._catchHandler) {
|
|
2272
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2273
|
-
logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
|
|
2274
|
-
logger.error("Error thrown by:", route);
|
|
2275
|
-
logger.error(err);
|
|
2276
|
-
logger.groupEnd();
|
|
2277
|
-
}
|
|
2278
|
-
return this._catchHandler.handle({
|
|
2279
|
-
url,
|
|
2280
|
-
request,
|
|
2281
|
-
event
|
|
2282
|
-
});
|
|
2283
|
-
}
|
|
2284
|
-
throw err;
|
|
2285
|
-
});
|
|
2286
|
-
}
|
|
2287
|
-
return responsePromise;
|
|
2288
2453
|
}
|
|
2289
2454
|
findMatchingRoute({ url, sameOrigin, request, event }) {
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
request,
|
|
2297
|
-
event
|
|
2298
|
-
});
|
|
2299
|
-
if (matchResult) {
|
|
2300
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2301
|
-
if (matchResult instanceof Promise) {
|
|
2302
|
-
logger.warn(`While routing ${getFriendlyURL(url)}, an async matchCallback function was used. Please convert the following route to use a synchronous matchCallback function:`, route);
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2305
|
-
params = matchResult;
|
|
2306
|
-
if (Array.isArray(params) && params.length === 0) {
|
|
2307
|
-
params = undefined;
|
|
2308
|
-
} else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {
|
|
2309
|
-
params = undefined;
|
|
2310
|
-
} else if (typeof matchResult === "boolean") {
|
|
2311
|
-
params = undefined;
|
|
2312
|
-
}
|
|
2313
|
-
return {
|
|
2314
|
-
route,
|
|
2315
|
-
params
|
|
2316
|
-
};
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
return {};
|
|
2455
|
+
return findMatchingRoute(this._state, {
|
|
2456
|
+
url,
|
|
2457
|
+
sameOrigin,
|
|
2458
|
+
request,
|
|
2459
|
+
event
|
|
2460
|
+
});
|
|
2320
2461
|
}
|
|
2321
2462
|
addToPrecacheList(entries) {
|
|
2322
|
-
this.
|
|
2463
|
+
this.precache.addToCacheList(entries);
|
|
2323
2464
|
}
|
|
2324
2465
|
getUrlsToPrecacheKeys() {
|
|
2325
2466
|
return this.precache.getUrlsToPrecacheKeys();
|
|
@@ -2341,38 +2482,6 @@ class Serwist {
|
|
|
2341
2482
|
}
|
|
2342
2483
|
}
|
|
2343
2484
|
|
|
2344
|
-
const cacheNames = {
|
|
2345
|
-
get googleAnalytics () {
|
|
2346
|
-
return cacheNames$1.getGoogleAnalyticsName();
|
|
2347
|
-
},
|
|
2348
|
-
get precache () {
|
|
2349
|
-
return cacheNames$1.getPrecacheName();
|
|
2350
|
-
},
|
|
2351
|
-
get prefix () {
|
|
2352
|
-
return cacheNames$1.getPrefix();
|
|
2353
|
-
},
|
|
2354
|
-
get runtime () {
|
|
2355
|
-
return cacheNames$1.getRuntimeName();
|
|
2356
|
-
},
|
|
2357
|
-
get suffix () {
|
|
2358
|
-
return cacheNames$1.getSuffix();
|
|
2359
|
-
}
|
|
2360
|
-
};
|
|
2361
|
-
|
|
2362
|
-
const registerQuotaErrorCallback = (callback)=>{
|
|
2363
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2364
|
-
finalAssertExports.isType(callback, "function", {
|
|
2365
|
-
moduleName: "@serwist/core",
|
|
2366
|
-
funcName: "register",
|
|
2367
|
-
paramName: "callback"
|
|
2368
|
-
});
|
|
2369
|
-
}
|
|
2370
|
-
quotaErrorCallbacks.add(callback);
|
|
2371
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2372
|
-
logger.log("Registered a callback to respond to quota errors.", callback);
|
|
2373
|
-
}
|
|
2374
|
-
};
|
|
2375
|
-
|
|
2376
2485
|
const BROADCAST_UPDATE_MESSAGE_TYPE = "CACHE_UPDATED";
|
|
2377
2486
|
const BROADCAST_UPDATE_MESSAGE_META = "serwist-broadcast-update";
|
|
2378
2487
|
const BROADCAST_UPDATE_DEFAULT_NOTIFY = true;
|
|
@@ -2846,7 +2955,7 @@ class ExpirationPlugin {
|
|
|
2846
2955
|
})();
|
|
2847
2956
|
try {
|
|
2848
2957
|
event.waitUntil(done);
|
|
2849
|
-
} catch
|
|
2958
|
+
} catch {
|
|
2850
2959
|
if (process.env.NODE_ENV !== "production") {
|
|
2851
2960
|
if (event instanceof FetchEvent) {
|
|
2852
2961
|
logger.warn(`Unable to ensure service worker stays alive when updating cache entry for '${getFriendlyURL(event.request.url)}'.`);
|
|
@@ -3046,7 +3155,7 @@ class CacheFirst extends Strategy {
|
|
|
3046
3155
|
});
|
|
3047
3156
|
}
|
|
3048
3157
|
let response = await handler.cacheMatch(request);
|
|
3049
|
-
let error
|
|
3158
|
+
let error;
|
|
3050
3159
|
if (!response) {
|
|
3051
3160
|
if (process.env.NODE_ENV !== "production") {
|
|
3052
3161
|
logs.push(`No response found in the '${this.cacheName}' cache. Will respond with a network request.`);
|
|
@@ -3138,7 +3247,7 @@ class StaleWhileRevalidate extends Strategy {
|
|
|
3138
3247
|
const fetchAndCachePromise = handler.fetchAndCachePut(request).catch(()=>{});
|
|
3139
3248
|
void handler.waitUntil(fetchAndCachePromise);
|
|
3140
3249
|
let response = await handler.cacheMatch(request);
|
|
3141
|
-
let error
|
|
3250
|
+
let error;
|
|
3142
3251
|
if (response) {
|
|
3143
3252
|
if (process.env.NODE_ENV !== "production") {
|
|
3144
3253
|
logs.push(`Found a cached response in the '${this.cacheName}' cache. Will update with the network response in the background.`);
|
|
@@ -3173,4 +3282,4 @@ class StaleWhileRevalidate extends Strategy {
|
|
|
3173
3282
|
}
|
|
3174
3283
|
}
|
|
3175
3284
|
|
|
3176
|
-
export { BROADCAST_UPDATE_DEFAULT_HEADERS, BackgroundSyncPlugin, BackgroundSyncQueue, BackgroundSyncQueueStore, BroadcastCacheUpdate, BroadcastUpdatePlugin, CacheExpiration, CacheFirst, CacheOnly, CacheableResponse, CacheableResponsePlugin, ExpirationPlugin, NavigationRoute, NetworkFirst, NetworkOnly, PrecacheFallbackPlugin, PrecacheRoute, PrecacheStrategy, RangeRequestsPlugin, RegExpRoute, Route,
|
|
3285
|
+
export { BROADCAST_UPDATE_DEFAULT_HEADERS, BackgroundSyncPlugin, BackgroundSyncQueue, BackgroundSyncQueueStore, BroadcastCacheUpdate, BroadcastUpdatePlugin, CacheExpiration, CacheFirst, CacheOnly, CacheableResponse, CacheableResponsePlugin, ExpirationPlugin, GoogleAnalytics, NavigationRoute, NetworkFirst, NetworkOnly, PrecacheFallbackPlugin, PrecacheRoute, PrecacheStrategy, RangeRequestsPlugin, RegExpRoute, Route, RuntimeCache, Serwist, StaleWhileRevalidate, StorableRequest, Strategy, StrategyHandler, addEventListeners, cacheNames, copyResponse, createActivateHandler, createCacheHandler, createFetchHandler, createInstallHandler, createPartialResponse, createSerwist, disableDevLogs, disableNavigationPreload, enableNavigationPreload, findMatchingRoute, handleRequest, initializeGoogleAnalytics, isNavigationPreloadSupported, iterateExtensions, registerCapture, registerQuotaErrorCallback, registerRoute, responsesAreSame, setCacheNameDetails, setCatchHandler, setDefaultHandler, unregisterRoute };
|