serwist 9.1.1 → 10.0.0-preview.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/dist/chunks/waitUntil.js +141 -134
  2. package/dist/index.d.ts +22 -49
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.internal.d.ts +16 -16
  5. package/dist/index.internal.d.ts.map +1 -1
  6. package/dist/index.internal.js +25 -3
  7. package/dist/index.js +2231 -452
  8. package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncPlugin.d.ts +2 -2
  9. package/dist/lib/background-sync/BackgroundSyncPlugin.d.ts.map +1 -0
  10. package/dist/lib/background-sync/BackgroundSyncQueue.d.ts.map +1 -0
  11. package/dist/lib/background-sync/BackgroundSyncQueueDb.d.ts.map +1 -0
  12. package/dist/lib/background-sync/BackgroundSyncQueueStore.d.ts.map +1 -0
  13. package/dist/lib/{backgroundSync → background-sync}/StorableRequest.d.ts +1 -1
  14. package/dist/lib/background-sync/StorableRequest.d.ts.map +1 -0
  15. package/dist/lib/background-sync/index.d.ts +6 -0
  16. package/dist/lib/background-sync/index.d.ts.map +1 -0
  17. package/dist/lib/{broadcastUpdate → broadcast-update}/BroadcastCacheUpdate.d.ts +1 -1
  18. package/dist/lib/broadcast-update/BroadcastCacheUpdate.d.ts.map +1 -0
  19. package/dist/lib/{broadcastUpdate → broadcast-update}/BroadcastUpdatePlugin.d.ts +2 -2
  20. package/dist/lib/broadcast-update/BroadcastUpdatePlugin.d.ts.map +1 -0
  21. package/dist/lib/broadcast-update/constants.d.ts.map +1 -0
  22. package/dist/lib/broadcast-update/index.d.ts +6 -0
  23. package/dist/lib/broadcast-update/index.d.ts.map +1 -0
  24. package/dist/lib/broadcast-update/responsesAreSame.d.ts.map +1 -0
  25. package/dist/lib/{broadcastUpdate → broadcast-update}/types.d.ts +1 -1
  26. package/dist/lib/broadcast-update/types.d.ts.map +1 -0
  27. package/dist/{cacheNames.d.ts → lib/cache-name.d.ts} +1 -1
  28. package/dist/lib/cache-name.d.ts.map +1 -0
  29. package/dist/lib/cacheable-response/CacheableResponse.d.ts.map +1 -0
  30. package/dist/lib/{cacheableResponse → cacheable-response}/CacheableResponsePlugin.d.ts +3 -3
  31. package/dist/lib/cacheable-response/CacheableResponsePlugin.d.ts.map +1 -0
  32. package/dist/lib/cacheable-response/index.d.ts +4 -0
  33. package/dist/lib/cacheable-response/index.d.ts.map +1 -0
  34. package/dist/{constants.d.ts → lib/constants.d.ts} +1 -1
  35. package/dist/lib/constants.d.ts.map +1 -0
  36. package/dist/lib/core.d.ts +62 -0
  37. package/dist/lib/core.d.ts.map +1 -0
  38. package/dist/lib/expiration/ExpirationPlugin.d.ts +2 -2
  39. package/dist/lib/expiration/ExpirationPlugin.d.ts.map +1 -1
  40. package/dist/lib/expiration/index.d.ts +4 -0
  41. package/dist/lib/expiration/index.d.ts.map +1 -0
  42. package/dist/lib/extension.d.ts +30 -0
  43. package/dist/lib/extension.d.ts.map +1 -0
  44. package/dist/lib/extensions/google-analytics/constants.d.ts.map +1 -0
  45. package/dist/lib/extensions/google-analytics/extension.d.ts +79 -0
  46. package/dist/lib/extensions/google-analytics/extension.d.ts.map +1 -0
  47. package/dist/lib/extensions/google-analytics/index.d.ts +2 -0
  48. package/dist/lib/extensions/google-analytics/index.d.ts.map +1 -0
  49. package/dist/lib/extensions/google-analytics/initialize.d.ts +12 -0
  50. package/dist/lib/extensions/google-analytics/initialize.d.ts.map +1 -0
  51. package/dist/lib/extensions/index.d.ts +14 -0
  52. package/dist/lib/extensions/index.d.ts.map +1 -0
  53. package/dist/{legacy/PrecacheController.d.ts → lib/extensions/precache/extension.d.ts} +56 -66
  54. package/dist/lib/extensions/precache/extension.d.ts.map +1 -0
  55. package/dist/lib/extensions/precache/options.d.ts +26 -0
  56. package/dist/lib/extensions/precache/options.d.ts.map +1 -0
  57. package/dist/lib/extensions/precache/plugin-cache-key.d.ts +16 -0
  58. package/dist/lib/extensions/precache/plugin-cache-key.d.ts.map +1 -0
  59. package/dist/lib/{precaching/PrecacheFallbackPlugin.d.ts → extensions/precache/plugin-fallback.d.ts} +4 -4
  60. package/dist/lib/extensions/precache/plugin-fallback.d.ts.map +1 -0
  61. package/dist/lib/extensions/precache/plugin-install-report.d.ts +14 -0
  62. package/dist/lib/extensions/precache/plugin-install-report.d.ts.map +1 -0
  63. package/dist/lib/extensions/precache/route.d.ts +42 -0
  64. package/dist/lib/extensions/precache/route.d.ts.map +1 -0
  65. package/dist/lib/{strategies/PrecacheStrategy.d.ts → extensions/precache/strategy.d.ts} +7 -7
  66. package/dist/lib/extensions/precache/strategy.d.ts.map +1 -0
  67. package/dist/lib/extensions/runtime-cache.d.ts +71 -0
  68. package/dist/lib/extensions/runtime-cache.d.ts.map +1 -0
  69. package/dist/lib/functions/handlers.d.ts +60 -0
  70. package/dist/lib/functions/handlers.d.ts.map +1 -0
  71. package/dist/lib/functions/router.d.ts +60 -0
  72. package/dist/lib/functions/router.d.ts.map +1 -0
  73. package/dist/{navigationPreload.d.ts → lib/navigation-preload.d.ts} +1 -1
  74. package/dist/lib/navigation-preload.d.ts.map +1 -0
  75. package/dist/lib/{rangeRequests → range-requests}/RangeRequestsPlugin.d.ts +3 -3
  76. package/dist/lib/range-requests/RangeRequestsPlugin.d.ts.map +1 -0
  77. package/dist/lib/range-requests/createPartialResponse.d.ts.map +1 -0
  78. package/dist/lib/range-requests/index.d.ts +3 -0
  79. package/dist/lib/range-requests/index.d.ts.map +1 -0
  80. package/dist/lib/range-requests/utils/calculateEffectiveBoundaries.d.ts.map +1 -0
  81. package/dist/lib/range-requests/utils/parseRangeHeader.d.ts.map +1 -0
  82. package/dist/lib/route.d.ts +106 -0
  83. package/dist/lib/route.d.ts.map +1 -0
  84. package/dist/{Serwist.d.ts → lib/serwist.d.ts} +71 -62
  85. package/dist/lib/serwist.d.ts.map +1 -0
  86. package/dist/lib/strategies/NetworkFirst.d.ts.map +1 -1
  87. package/dist/lib/strategies/StaleWhileRevalidate.d.ts.map +1 -1
  88. package/dist/lib/strategies/Strategy.d.ts +3 -3
  89. package/dist/lib/strategies/Strategy.d.ts.map +1 -1
  90. package/dist/lib/strategies/StrategyHandler.d.ts +4 -4
  91. package/dist/lib/strategies/StrategyHandler.d.ts.map +1 -1
  92. package/dist/lib/strategies/index.d.ts +11 -0
  93. package/dist/lib/strategies/index.d.ts.map +1 -0
  94. package/dist/lib/strategies/plugins/cacheOkAndOpaquePlugin.d.ts +2 -2
  95. package/dist/lib/strategies/plugins/cacheOkAndOpaquePlugin.d.ts.map +1 -1
  96. package/dist/{types.d.ts → lib/types.d.ts} +7 -65
  97. package/dist/lib/types.d.ts.map +1 -0
  98. package/dist/{copyResponse.d.ts → lib/utils.d.ts} +22 -1
  99. package/dist/lib/utils.d.ts.map +1 -0
  100. package/dist/models/messages/messageGenerator.d.ts +1 -1
  101. package/dist/models/messages/messageGenerator.d.ts.map +1 -1
  102. package/dist/utils/SerwistError.d.ts +2 -2
  103. package/dist/utils/SerwistError.d.ts.map +1 -1
  104. package/dist/utils/assert.d.ts +1 -1
  105. package/dist/utils/assert.d.ts.map +1 -1
  106. package/dist/utils/createCacheKey.d.ts +1 -1
  107. package/dist/utils/createCacheKey.d.ts.map +1 -1
  108. package/dist/utils/generateURLVariations.d.ts +1 -1
  109. package/dist/utils/generateURLVariations.d.ts.map +1 -1
  110. package/dist/utils/logger.d.ts +1 -1
  111. package/dist/utils/logger.d.ts.map +1 -1
  112. package/dist/utils/normalizeHandler.d.ts +1 -1
  113. package/dist/utils/normalizeHandler.d.ts.map +1 -1
  114. package/dist/utils/parseRoute.d.ts +3 -3
  115. package/dist/utils/parseRoute.d.ts.map +1 -1
  116. package/dist/utils/pluginUtils.d.ts +2 -2
  117. package/dist/utils/pluginUtils.d.ts.map +1 -1
  118. package/package.json +28 -11
  119. package/src/index.internal.ts +16 -16
  120. package/src/index.ts +100 -107
  121. package/src/lib/{backgroundSync → background-sync}/BackgroundSyncPlugin.ts +2 -2
  122. package/src/lib/{backgroundSync → background-sync}/BackgroundSyncQueue.ts +4 -4
  123. package/src/lib/{backgroundSync → background-sync}/BackgroundSyncQueueStore.ts +1 -1
  124. package/src/lib/{backgroundSync → background-sync}/StorableRequest.ts +2 -2
  125. package/src/lib/background-sync/index.ts +5 -0
  126. package/src/lib/{broadcastUpdate → broadcast-update}/BroadcastCacheUpdate.ts +5 -5
  127. package/src/lib/{broadcastUpdate → broadcast-update}/BroadcastUpdatePlugin.ts +2 -2
  128. package/src/lib/broadcast-update/index.ts +5 -0
  129. package/src/lib/{broadcastUpdate → broadcast-update}/responsesAreSame.ts +2 -2
  130. package/src/lib/{broadcastUpdate → broadcast-update}/types.ts +1 -1
  131. package/src/{cacheNames.ts → lib/cache-name.ts} +1 -1
  132. package/src/lib/{cacheableResponse → cacheable-response}/CacheableResponse.ts +4 -4
  133. package/src/lib/{cacheableResponse → cacheable-response}/CacheableResponsePlugin.ts +3 -3
  134. package/src/lib/cacheable-response/index.ts +3 -0
  135. package/src/lib/core.ts +128 -0
  136. package/src/lib/expiration/CacheExpiration.ts +3 -3
  137. package/src/lib/expiration/ExpirationPlugin.ts +9 -10
  138. package/src/lib/expiration/index.ts +3 -0
  139. package/src/lib/extension.ts +37 -0
  140. package/src/lib/{googleAnalytics/initializeGoogleAnalytics.ts → extensions/google-analytics/extension.ts} +42 -48
  141. package/src/lib/extensions/google-analytics/index.ts +0 -0
  142. package/src/lib/extensions/google-analytics/initialize.ts +48 -0
  143. package/src/lib/extensions/index.ts +13 -0
  144. package/src/lib/extensions/precache/extension.ts +306 -0
  145. package/src/lib/extensions/precache/options.ts +49 -0
  146. package/src/{legacy/utils/PrecacheCacheKeyPlugin.ts → lib/extensions/precache/plugin-cache-key.ts} +7 -8
  147. package/src/lib/{precaching/PrecacheFallbackPlugin.ts → extensions/precache/plugin-fallback.ts} +19 -8
  148. package/src/{utils/PrecacheInstallReportPlugin.ts → lib/extensions/precache/plugin-install-report.ts} +5 -5
  149. package/src/lib/extensions/precache/route.ts +72 -0
  150. package/src/lib/{strategies/PrecacheStrategy.ts → extensions/precache/strategy.ts} +12 -12
  151. package/src/lib/extensions/runtime-cache.ts +126 -0
  152. package/src/lib/functions/handlers.ts +149 -0
  153. package/src/lib/functions/router.ts +314 -0
  154. package/src/{navigationPreload.ts → lib/navigation-preload.ts} +1 -1
  155. package/src/lib/{rangeRequests → range-requests}/RangeRequestsPlugin.ts +3 -3
  156. package/src/lib/{rangeRequests → range-requests}/createPartialResponse.ts +3 -3
  157. package/src/lib/range-requests/index.ts +2 -0
  158. package/src/lib/{rangeRequests → range-requests}/utils/calculateEffectiveBoundaries.ts +2 -2
  159. package/src/lib/{rangeRequests → range-requests}/utils/parseRangeHeader.ts +2 -2
  160. package/src/lib/route.ts +234 -0
  161. package/src/lib/serwist.ts +443 -0
  162. package/src/lib/strategies/CacheFirst.ts +3 -3
  163. package/src/lib/strategies/CacheOnly.ts +3 -3
  164. package/src/lib/strategies/NetworkFirst.ts +4 -4
  165. package/src/lib/strategies/NetworkOnly.ts +4 -4
  166. package/src/lib/strategies/StaleWhileRevalidate.ts +4 -4
  167. package/src/lib/strategies/Strategy.ts +7 -7
  168. package/src/lib/strategies/StrategyHandler.ts +18 -18
  169. package/src/lib/strategies/index.ts +10 -0
  170. package/src/lib/strategies/plugins/cacheOkAndOpaquePlugin.ts +2 -2
  171. package/src/lib/strategies/utils/messages.ts +2 -2
  172. package/src/{types.ts → lib/types.ts} +17 -70
  173. package/src/lib/utils.ts +137 -0
  174. package/src/models/messages/messageGenerator.ts +1 -1
  175. package/src/models/messages/messages.ts +3 -3
  176. package/src/utils/SerwistError.ts +3 -3
  177. package/src/utils/assert.ts +1 -1
  178. package/src/utils/createCacheKey.ts +1 -2
  179. package/src/utils/executeQuotaErrorCallbacks.ts +1 -1
  180. package/src/utils/generateURLVariations.ts +1 -1
  181. package/src/utils/logger.ts +1 -1
  182. package/src/utils/normalizeHandler.ts +1 -1
  183. package/src/utils/parseRoute.ts +4 -5
  184. package/src/utils/pluginUtils.ts +2 -2
  185. package/dist/NavigationRoute.d.ts +0 -56
  186. package/dist/NavigationRoute.d.ts.map +0 -1
  187. package/dist/PrecacheRoute.d.ts +0 -16
  188. package/dist/PrecacheRoute.d.ts.map +0 -1
  189. package/dist/RegExpRoute.d.ts +0 -24
  190. package/dist/RegExpRoute.d.ts.map +0 -1
  191. package/dist/Route.d.ts +0 -33
  192. package/dist/Route.d.ts.map +0 -1
  193. package/dist/Serwist.d.ts.map +0 -1
  194. package/dist/cacheNames.d.ts.map +0 -1
  195. package/dist/chunks/printInstallDetails.js +0 -1601
  196. package/dist/chunks/resultingClientExists.js +0 -32
  197. package/dist/constants.d.ts.map +0 -1
  198. package/dist/copyResponse.d.ts.map +0 -1
  199. package/dist/disableDevLogs.d.ts +0 -7
  200. package/dist/disableDevLogs.d.ts.map +0 -1
  201. package/dist/index.legacy.d.ts +0 -28
  202. package/dist/index.legacy.d.ts.map +0 -1
  203. package/dist/index.legacy.js +0 -790
  204. package/dist/legacy/PrecacheController.d.ts.map +0 -1
  205. package/dist/legacy/PrecacheFallbackPlugin.d.ts +0 -61
  206. package/dist/legacy/PrecacheFallbackPlugin.d.ts.map +0 -1
  207. package/dist/legacy/PrecacheRoute.d.ts +0 -19
  208. package/dist/legacy/PrecacheRoute.d.ts.map +0 -1
  209. package/dist/legacy/Router.d.ts +0 -151
  210. package/dist/legacy/Router.d.ts.map +0 -1
  211. package/dist/legacy/addPlugins.d.ts +0 -9
  212. package/dist/legacy/addPlugins.d.ts.map +0 -1
  213. package/dist/legacy/addRoute.d.ts +0 -14
  214. package/dist/legacy/addRoute.d.ts.map +0 -1
  215. package/dist/legacy/constants.d.ts.map +0 -1
  216. package/dist/legacy/createHandlerBoundToURL.d.ts +0 -17
  217. package/dist/legacy/createHandlerBoundToURL.d.ts.map +0 -1
  218. package/dist/legacy/fallbacks.d.ts +0 -59
  219. package/dist/legacy/fallbacks.d.ts.map +0 -1
  220. package/dist/legacy/getCacheKeyForURL.d.ts +0 -20
  221. package/dist/legacy/getCacheKeyForURL.d.ts.map +0 -1
  222. package/dist/legacy/handlePrecaching.d.ts +0 -54
  223. package/dist/legacy/handlePrecaching.d.ts.map +0 -1
  224. package/dist/legacy/initializeGoogleAnalytics.d.ts +0 -38
  225. package/dist/legacy/initializeGoogleAnalytics.d.ts.map +0 -1
  226. package/dist/legacy/installSerwist.d.ts +0 -81
  227. package/dist/legacy/installSerwist.d.ts.map +0 -1
  228. package/dist/legacy/matchPrecache.d.ts +0 -15
  229. package/dist/legacy/matchPrecache.d.ts.map +0 -1
  230. package/dist/legacy/precache.d.ts +0 -20
  231. package/dist/legacy/precache.d.ts.map +0 -1
  232. package/dist/legacy/precacheAndRoute.d.ts +0 -14
  233. package/dist/legacy/precacheAndRoute.d.ts.map +0 -1
  234. package/dist/legacy/registerRoute.d.ts +0 -16
  235. package/dist/legacy/registerRoute.d.ts.map +0 -1
  236. package/dist/legacy/registerRuntimeCaching.d.ts +0 -11
  237. package/dist/legacy/registerRuntimeCaching.d.ts.map +0 -1
  238. package/dist/legacy/setCatchHandler.d.ts +0 -10
  239. package/dist/legacy/setCatchHandler.d.ts.map +0 -1
  240. package/dist/legacy/setDefaultHandler.d.ts +0 -13
  241. package/dist/legacy/setDefaultHandler.d.ts.map +0 -1
  242. package/dist/legacy/singletonPrecacheController.d.ts +0 -34
  243. package/dist/legacy/singletonPrecacheController.d.ts.map +0 -1
  244. package/dist/legacy/singletonRouter.d.ts +0 -41
  245. package/dist/legacy/singletonRouter.d.ts.map +0 -1
  246. package/dist/legacy/unregisterRoute.d.ts +0 -9
  247. package/dist/legacy/unregisterRoute.d.ts.map +0 -1
  248. package/dist/legacy/utils/PrecacheCacheKeyPlugin.d.ts +0 -16
  249. package/dist/legacy/utils/PrecacheCacheKeyPlugin.d.ts.map +0 -1
  250. package/dist/legacy/utils/getCacheKeyForURL.d.ts +0 -14
  251. package/dist/legacy/utils/getCacheKeyForURL.d.ts.map +0 -1
  252. package/dist/lib/backgroundSync/BackgroundSyncPlugin.d.ts.map +0 -1
  253. package/dist/lib/backgroundSync/BackgroundSyncQueue.d.ts.map +0 -1
  254. package/dist/lib/backgroundSync/BackgroundSyncQueueDb.d.ts.map +0 -1
  255. package/dist/lib/backgroundSync/BackgroundSyncQueueStore.d.ts.map +0 -1
  256. package/dist/lib/backgroundSync/StorableRequest.d.ts.map +0 -1
  257. package/dist/lib/broadcastUpdate/BroadcastCacheUpdate.d.ts.map +0 -1
  258. package/dist/lib/broadcastUpdate/BroadcastUpdatePlugin.d.ts.map +0 -1
  259. package/dist/lib/broadcastUpdate/constants.d.ts.map +0 -1
  260. package/dist/lib/broadcastUpdate/responsesAreSame.d.ts.map +0 -1
  261. package/dist/lib/broadcastUpdate/types.d.ts.map +0 -1
  262. package/dist/lib/cacheableResponse/CacheableResponse.d.ts.map +0 -1
  263. package/dist/lib/cacheableResponse/CacheableResponsePlugin.d.ts.map +0 -1
  264. package/dist/lib/googleAnalytics/constants.d.ts +0 -10
  265. package/dist/lib/googleAnalytics/constants.d.ts.map +0 -1
  266. package/dist/lib/googleAnalytics/initializeGoogleAnalytics.d.ts +0 -30
  267. package/dist/lib/googleAnalytics/initializeGoogleAnalytics.d.ts.map +0 -1
  268. package/dist/lib/precaching/PrecacheFallbackPlugin.d.ts.map +0 -1
  269. package/dist/lib/rangeRequests/RangeRequestsPlugin.d.ts.map +0 -1
  270. package/dist/lib/rangeRequests/createPartialResponse.d.ts.map +0 -1
  271. package/dist/lib/rangeRequests/utils/calculateEffectiveBoundaries.d.ts.map +0 -1
  272. package/dist/lib/rangeRequests/utils/parseRangeHeader.d.ts.map +0 -1
  273. package/dist/lib/strategies/PrecacheStrategy.d.ts.map +0 -1
  274. package/dist/navigationPreload.d.ts.map +0 -1
  275. package/dist/registerQuotaErrorCallback.d.ts +0 -8
  276. package/dist/registerQuotaErrorCallback.d.ts.map +0 -1
  277. package/dist/setCacheNameDetails.d.ts +0 -9
  278. package/dist/setCacheNameDetails.d.ts.map +0 -1
  279. package/dist/types.d.ts.map +0 -1
  280. package/dist/utils/PrecacheCacheKeyPlugin.d.ts +0 -16
  281. package/dist/utils/PrecacheCacheKeyPlugin.d.ts.map +0 -1
  282. package/dist/utils/PrecacheInstallReportPlugin.d.ts +0 -14
  283. package/dist/utils/PrecacheInstallReportPlugin.d.ts.map +0 -1
  284. package/dist/utils/parsePrecacheOptions.d.ts +0 -26
  285. package/dist/utils/parsePrecacheOptions.d.ts.map +0 -1
  286. package/src/NavigationRoute.ts +0 -118
  287. package/src/PrecacheRoute.ts +0 -45
  288. package/src/RegExpRoute.ts +0 -74
  289. package/src/Route.ts +0 -67
  290. package/src/Serwist.ts +0 -867
  291. package/src/copyResponse.ts +0 -58
  292. package/src/disableDevLogs.ts +0 -10
  293. package/src/index.legacy.ts +0 -62
  294. package/src/legacy/PrecacheController.ts +0 -337
  295. package/src/legacy/PrecacheFallbackPlugin.ts +0 -92
  296. package/src/legacy/PrecacheRoute.ts +0 -48
  297. package/src/legacy/Router.ts +0 -484
  298. package/src/legacy/addPlugins.ts +0 -21
  299. package/src/legacy/addRoute.ts +0 -27
  300. package/src/legacy/createHandlerBoundToURL.ts +0 -30
  301. package/src/legacy/fallbacks.ts +0 -94
  302. package/src/legacy/getCacheKeyForURL.ts +0 -32
  303. package/src/legacy/handlePrecaching.ts +0 -86
  304. package/src/legacy/initializeGoogleAnalytics.ts +0 -218
  305. package/src/legacy/installSerwist.ts +0 -170
  306. package/src/legacy/matchPrecache.ts +0 -27
  307. package/src/legacy/precache.ts +0 -33
  308. package/src/legacy/precacheAndRoute.ts +0 -27
  309. package/src/legacy/registerRoute.ts +0 -28
  310. package/src/legacy/registerRuntimeCaching.ts +0 -17
  311. package/src/legacy/setCatchHandler.ts +0 -21
  312. package/src/legacy/setDefaultHandler.ts +0 -24
  313. package/src/legacy/singletonPrecacheController.ts +0 -53
  314. package/src/legacy/singletonRouter.ts +0 -70
  315. package/src/legacy/unregisterRoute.ts +0 -13
  316. package/src/legacy/utils/getCacheKeyForURL.ts +0 -36
  317. package/src/lib/googleAnalytics/constants.ts +0 -22
  318. package/src/registerQuotaErrorCallback.ts +0 -34
  319. package/src/setCacheNameDetails.ts +0 -53
  320. package/src/utils/PrecacheCacheKeyPlugin.ts +0 -33
  321. package/src/utils/parsePrecacheOptions.ts +0 -47
  322. /package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncQueue.d.ts +0 -0
  323. /package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncQueueDb.d.ts +0 -0
  324. /package/dist/lib/{backgroundSync → background-sync}/BackgroundSyncQueueStore.d.ts +0 -0
  325. /package/dist/lib/{broadcastUpdate → broadcast-update}/constants.d.ts +0 -0
  326. /package/dist/lib/{broadcastUpdate → broadcast-update}/responsesAreSame.d.ts +0 -0
  327. /package/dist/lib/{cacheableResponse → cacheable-response}/CacheableResponse.d.ts +0 -0
  328. /package/dist/{legacy → lib/extensions/google-analytics}/constants.d.ts +0 -0
  329. /package/dist/lib/{rangeRequests → range-requests}/createPartialResponse.d.ts +0 -0
  330. /package/dist/lib/{rangeRequests → range-requests}/utils/calculateEffectiveBoundaries.d.ts +0 -0
  331. /package/dist/lib/{rangeRequests → range-requests}/utils/parseRangeHeader.d.ts +0 -0
  332. /package/src/lib/{backgroundSync → background-sync}/BackgroundSyncQueueDb.ts +0 -0
  333. /package/src/lib/{broadcastUpdate → broadcast-update}/constants.ts +0 -0
  334. /package/src/{constants.ts → lib/constants.ts} +0 -0
  335. /package/src/{legacy → lib/extensions/google-analytics}/constants.ts +0 -0
package/dist/index.js CHANGED
@@ -1,29 +1,1487 @@
1
- import { R as Route, g as generateURLVariations, B as BackgroundSyncPlugin, N as NetworkFirst, a as NetworkOnly, P as PrecacheStrategy, e as enableNavigationPreload, s as setCacheNameDetails, b as NavigationRoute, S as Strategy, d as disableDevLogs, c as createCacheKey, f as defaultMethod, n as normalizeHandler, p as parseRoute, h as PrecacheInstallReportPlugin, i as parallel, j as printInstallDetails, k as printCleanupDetails, m as messages, l as cacheOkAndOpaquePlugin } from './chunks/printInstallDetails.js';
2
- export { v as BackgroundSyncQueue, w as BackgroundSyncQueueStore, u as RegExpRoute, x as StorableRequest, t as StrategyHandler, o as copyResponse, q as disableNavigationPreload, r as isNavigationPreloadSupported } from './chunks/printInstallDetails.js';
3
- import { l as logger, g as getFriendlyURL, c as cacheNames$1, a as clientsClaim, b as cleanupOutdatedCaches, f as finalAssertExports, S as SerwistError, w as waitUntil, t as timeout, q as quotaErrorCallbacks } from './chunks/waitUntil.js';
4
- import { r as resultingClientExists } from './chunks/resultingClientExists.js';
5
- import { deleteDB, openDB } from 'idb';
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';
2
+ import { openDB, deleteDB } from 'idb';
3
+ import { parallel } from '@serwist/utils';
6
4
 
7
- class PrecacheRoute extends Route {
8
- constructor(serwist, options){
9
- const match = ({ request })=>{
10
- const urlsToCacheKeys = serwist.getUrlsToPrecacheKeys();
11
- for (const possibleURL of generateURLVariations(request.url, options)){
12
- const cacheKey = urlsToCacheKeys.get(possibleURL);
13
- if (cacheKey) {
14
- const integrity = serwist.getIntegrityForPrecacheKey(cacheKey);
15
- return {
16
- cacheKey,
17
- integrity
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
+ };
59
+
60
+ const normalizeHandler = (handler)=>{
61
+ if (handler && typeof handler === "object") {
62
+ if (process.env.NODE_ENV !== "production") {
63
+ finalAssertExports.hasMethod(handler, "handle", {
64
+ moduleName: "serwist",
65
+ className: "Route",
66
+ funcName: "constructor",
67
+ paramName: "handler"
68
+ });
69
+ }
70
+ return handler;
71
+ }
72
+ if (process.env.NODE_ENV !== "production") {
73
+ finalAssertExports.isType(handler, "function", {
74
+ moduleName: "serwist",
75
+ className: "Route",
76
+ funcName: "constructor",
77
+ paramName: "handler"
78
+ });
79
+ }
80
+ return {
81
+ handle: handler
82
+ };
83
+ };
84
+
85
+ const defaultMethod = "GET";
86
+ const validMethods = [
87
+ "DELETE",
88
+ "GET",
89
+ "HEAD",
90
+ "PATCH",
91
+ "POST",
92
+ "PUT"
93
+ ];
94
+
95
+ class Route {
96
+ handler;
97
+ match;
98
+ method;
99
+ catchHandler;
100
+ constructor(match, handler, method = defaultMethod){
101
+ if (process.env.NODE_ENV !== "production") {
102
+ finalAssertExports.isType(match, "function", {
103
+ moduleName: "serwist",
104
+ className: "Route",
105
+ funcName: "constructor",
106
+ paramName: "match"
107
+ });
108
+ if (method) {
109
+ finalAssertExports.isOneOf(method, validMethods, {
110
+ paramName: "method"
111
+ });
112
+ }
113
+ }
114
+ this.handler = normalizeHandler(handler);
115
+ this.match = match;
116
+ this.method = method;
117
+ }
118
+ setCatchHandler(handler) {
119
+ this.catchHandler = normalizeHandler(handler);
120
+ }
121
+ }
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
+ }
148
+ class NavigationRoute extends Route {
149
+ _allowlist;
150
+ _denylist;
151
+ constructor(handler, { allowlist = [
152
+ /./
153
+ ], denylist = [] } = {}){
154
+ if (process.env.NODE_ENV !== "production") {
155
+ finalAssertExports.isArrayOfClass(allowlist, RegExp, {
156
+ moduleName: "serwist",
157
+ className: "NavigationRoute",
158
+ funcName: "constructor",
159
+ paramName: "options.allowlist"
160
+ });
161
+ finalAssertExports.isArrayOfClass(denylist, RegExp, {
162
+ moduleName: "serwist",
163
+ className: "NavigationRoute",
164
+ funcName: "constructor",
165
+ paramName: "options.denylist"
166
+ });
167
+ }
168
+ super((options)=>this._match(options), handler);
169
+ this._allowlist = allowlist;
170
+ this._denylist = denylist;
171
+ }
172
+ _match({ url, request }) {
173
+ if (request && request.mode !== "navigate") {
174
+ return false;
175
+ }
176
+ const pathnameAndSearch = url.pathname + url.search;
177
+ for (const regExp of this._denylist){
178
+ if (regExp.test(pathnameAndSearch)) {
179
+ if (process.env.NODE_ENV !== "production") {
180
+ logger.log(`The navigation route ${pathnameAndSearch} is not being used, since the URL matches this denylist pattern: ${regExp.toString()}`);
181
+ }
182
+ return false;
183
+ }
184
+ }
185
+ if (this._allowlist.some((regExp)=>regExp.test(pathnameAndSearch))) {
186
+ if (process.env.NODE_ENV !== "production") {
187
+ logger.debug(`The navigation route ${pathnameAndSearch} is being used.`);
188
+ }
189
+ return true;
190
+ }
191
+ if (process.env.NODE_ENV !== "production") {
192
+ logger.log(`The navigation route ${pathnameAndSearch} is not being used, since the URL being navigated to doesn't match the allowlist.`);
193
+ }
194
+ return false;
195
+ }
196
+ }
197
+
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"
208
+ });
209
+ await tx.store.add(entry);
210
+ await tx.done;
211
+ }
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;
216
+ }
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 : [];
221
+ }
222
+ async getEntryCountByQueueName(queueName) {
223
+ const db = await this.getDb();
224
+ return db.countFromIndex(REQUEST_OBJECT_STORE_NAME, QUEUE_NAME_INDEX, IDBKeyRange.only(queueName));
225
+ }
226
+ async deleteEntry(id) {
227
+ const db = await this.getDb();
228
+ await db.delete(REQUEST_OBJECT_STORE_NAME, id);
229
+ }
230
+ async getFirstEntryByQueueName(queueName) {
231
+ return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), "next");
232
+ }
233
+ async getLastEntryByQueueName(queueName) {
234
+ return await this.getEndEntryFromIndex(IDBKeyRange.only(queueName), "prev");
235
+ }
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;
240
+ }
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
+ });
246
+ }
247
+ return this._db;
248
+ }
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);
253
+ }
254
+ }
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
+ }
263
+ }
264
+
265
+ class BackgroundSyncQueueStore {
266
+ _queueName;
267
+ _queueDb;
268
+ constructor(queueName){
269
+ this._queueName = queueName;
270
+ this._queueDb = new BackgroundSyncQueueDb();
271
+ }
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);
290
+ }
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;
311
+ }
312
+ entry.queueName = this._queueName;
313
+ await this._queueDb.addEntry(entry);
314
+ }
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;
335
+ }
336
+ }
337
+
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;
361
+ });
362
+ for (const prop of serializableProperties){
363
+ if (request[prop] !== undefined) {
364
+ requestData[prop] = request[prop];
365
+ }
366
+ }
367
+ return new StorableRequest(requestData);
368
+ }
369
+ constructor(requestData){
370
+ if (process.env.NODE_ENV !== "production") {
371
+ finalAssertExports.isType(requestData, "object", {
372
+ moduleName: "serwist",
373
+ className: "StorableRequest",
374
+ funcName: "constructor",
375
+ paramName: "requestData"
376
+ });
377
+ finalAssertExports.isType(requestData.url, "string", {
378
+ moduleName: "serwist",
379
+ className: "StorableRequest",
380
+ funcName: "constructor",
381
+ paramName: "requestData.url"
382
+ });
383
+ }
384
+ if (requestData.mode === "navigate") {
385
+ requestData.mode = "same-origin";
386
+ }
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);
394
+ }
395
+ return requestData;
396
+ }
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
+ });
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();
439
+ }
440
+ get name() {
441
+ return this._name;
442
+ }
443
+ async pushRequest(entry) {
444
+ if (process.env.NODE_ENV !== "production") {
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
+ });
457
+ }
458
+ await this._addRequest(entry, "push");
459
+ }
460
+ async unshiftRequest(entry) {
461
+ if (process.env.NODE_ENV !== "production") {
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"
473
+ });
474
+ }
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));
493
+ }
494
+ }
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;
508
+ }
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;
516
+ }
517
+ if (process.env.NODE_ENV !== "production") {
518
+ logger.log(`Request for '${getFriendlyURL(request.url)}' has ` + `been added to background sync queue '${this._name}'.`);
519
+ }
520
+ if (this._syncInProgress) {
521
+ this._requestsAddedDuringSync = true;
522
+ } else {
523
+ await this.registerSync();
524
+ }
525
+ }
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);
541
+ }
542
+ return convertEntry(entry);
543
+ }
544
+ return undefined;
545
+ }
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
+ });
562
+ }
563
+ }
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
+ }
567
+ }
568
+ async registerSync() {
569
+ if ("sync" in self.registration && !this._forceSyncFallback) {
570
+ try {
571
+ await self.registration.sync.register(`${TAG_PREFIX}:${this._name}`);
572
+ } catch (err) {
573
+ if (process.env.NODE_ENV !== "production") {
574
+ logger.warn(`Unable to register sync event for '${this._name}'.`, err);
575
+ }
576
+ }
577
+ }
578
+ }
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`);
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());
607
+ }
608
+ });
609
+ } else {
610
+ if (process.env.NODE_ENV !== "production") {
611
+ logger.log("Background sync replaying without background sync event");
612
+ }
613
+ void this._onSync({
614
+ queue: this
615
+ });
616
+ }
617
+ }
618
+ static get _queueNames() {
619
+ return queueNames;
620
+ }
621
+ }
622
+
623
+ class BackgroundSyncPlugin {
624
+ _queue;
625
+ constructor(name, options){
626
+ this._queue = new BackgroundSyncQueue(name, options);
627
+ }
628
+ async fetchDidFail({ request }) {
629
+ await this._queue.pushRequest({
630
+ request
631
+ });
632
+ }
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"
644
+ });
645
+ }
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.`);
650
+ }
651
+ }
652
+ const matchCallback = ({ url })=>{
653
+ if (process.env.NODE_ENV !== "production") {
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
+ }
657
+ }
658
+ return url.href === captureUrl.href;
659
+ };
660
+ return new Route(matchCallback, handler, method);
661
+ }
662
+ if (capture instanceof RegExp) {
663
+ return new RegExpRoute(capture, handler, method);
664
+ }
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
+ };
677
+
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
+ });
715
+ }
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'.");
747
+ }
748
+ return;
749
+ }
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
+ ]);
770
+ }
771
+ }
772
+ }
773
+ const method = request.method;
774
+ if (!handler && state.defaultHandlerMap.has(method)) {
775
+ if (process.env.NODE_ENV !== "production") {
776
+ debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);
777
+ }
778
+ handler = state.defaultHandlerMap.get(method);
779
+ }
780
+ if (!handler) {
781
+ if (process.env.NODE_ENV !== "production") {
782
+ logger.debug(`No route found for: ${getFriendlyURL(url)}`);
783
+ }
784
+ return;
785
+ }
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);
793
+ }
794
+ }
795
+ logger.groupEnd();
796
+ }
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);
807
+ }
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
+ }
830
+ }
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
842
+ });
843
+ }
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);
863
+ }
864
+ }
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;
872
+ }
873
+ return {
874
+ route,
875
+ params
876
+ };
877
+ }
878
+ }
879
+ return {};
880
+ };
881
+
882
+ const cacheOkAndOpaquePlugin = {
883
+ cacheWillUpdate: async ({ response })=>{
884
+ if (response.status === 200 || response.status === 0) {
885
+ return response;
886
+ }
887
+ return null;
888
+ }
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){
906
+ if (process.env.NODE_ENV !== "production") {
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
+ });
919
+ }
920
+ this.event = options.event;
921
+ this.request = options.request;
922
+ if (options.url) {
923
+ this.url = options.url;
924
+ this.params = options.params;
925
+ }
926
+ this._strategy = strategy;
927
+ this._handlerDeferred = new Deferred();
928
+ this._extendLifetimePromises = [];
929
+ this._plugins = [
930
+ ...strategy.plugins
931
+ ];
932
+ this._pluginStateMap = new Map();
933
+ for (const plugin of this._plugins){
934
+ this._pluginStateMap.set(plugin, {});
935
+ }
936
+ this.event.waitUntil(this._handlerDeferred.promise);
937
+ }
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;
944
+ }
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
+ }
959
+ }
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
+ });
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;
988
+ }
989
+ }
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;
995
+ }
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
+ }
1014
+ }
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;
1023
+ }
1024
+ return cachedResponse;
1025
+ }
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
1035
+ });
1036
+ }
1037
+ }
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)
1044
+ });
1045
+ }
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);
1050
+ }
1051
+ return false;
1052
+ }
1053
+ const { cacheName, matchOptions } = this._strategy;
1054
+ const cache = await self.caches.open(cacheName);
1055
+ if (process.env.NODE_ENV !== "production") {
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
1085
+ });
1086
+ }
1087
+ return true;
1088
+ }
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;
1102
+ }
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
+ }
1110
+ }
1111
+ return false;
1112
+ }
1113
+ async runCallbacks(name, param) {
1114
+ for (const callback of this.iterateCallbacks(name)){
1115
+ await callback(param);
1116
+ }
1117
+ }
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
18
1126
  };
1127
+ return plugin[name](statefulParam);
1128
+ };
1129
+ yield statefulCallback;
1130
+ }
1131
+ }
1132
+ }
1133
+ waitUntil(promise) {
1134
+ this._extendLifetimePromises.push(promise);
1135
+ return promise;
1136
+ }
1137
+ async doneWaiting() {
1138
+ let promise;
1139
+ while(promise = this._extendLifetimePromises.shift()){
1140
+ await promise;
1141
+ }
1142
+ }
1143
+ destroy() {
1144
+ this._handlerDeferred.resolve(null);
1145
+ }
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
+ }
1162
+ }
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;
1192
+ }
1193
+ }
1194
+
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
+ };
1216
+ }
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
1227
+ });
1228
+ const responseDone = this._getResponse(handler, request, event);
1229
+ const handlerDone = this._awaitComplete(responseDone, handler, request, event);
1230
+ return [
1231
+ responseDone,
1232
+ handlerDone
1233
+ ];
1234
+ }
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
+ }
19
1259
  }
20
1260
  }
1261
+ if (!response) {
1262
+ throw error;
1263
+ }
21
1264
  if (process.env.NODE_ENV !== "production") {
22
- logger.debug(`Precaching did not find a match for ${getFriendlyURL(request.url)}.`);
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.`);
23
1266
  }
24
- return;
1267
+ }
1268
+ for (const callback of handler.iterateCallbacks("handlerWillRespond")){
1269
+ response = await callback({
1270
+ event,
1271
+ request,
1272
+ response
1273
+ });
1274
+ }
1275
+ return response;
1276
+ }
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;
1304
+ }
1305
+ }
1306
+ }
1307
+
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
+ }
1316
+ }
1317
+ };
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
+ }
1336
+ }
1337
+ }
1338
+ async _handle(request, handler) {
1339
+ const logs = [];
1340
+ if (process.env.NODE_ENV !== "production") {
1341
+ finalAssertExports.isInstance(request, Request, {
1342
+ moduleName: "serwist",
1343
+ className: this.constructor.name,
1344
+ funcName: "handle",
1345
+ paramName: "makeRequest"
1346
+ });
1347
+ }
1348
+ const promises = [];
1349
+ let timeoutId;
1350
+ if (this._networkTimeoutSeconds) {
1351
+ const { id, promise } = this._getTimeoutPromise({
1352
+ request,
1353
+ logs,
1354
+ handler
1355
+ });
1356
+ timeoutId = id;
1357
+ promises.push(promise);
1358
+ }
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
+ })());
1369
+ if (process.env.NODE_ENV !== "production") {
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
1380
+ });
1381
+ }
1382
+ return response;
1383
+ }
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
25
1398
  };
26
- super(match, serwist.precacheStrategy);
1399
+ }
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.");
1416
+ } else {
1417
+ logs.push("Unable to get a response from the network. Will respond " + "with a cached response.");
1418
+ }
1419
+ }
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;
1431
+ }
1432
+ }
1433
+
1434
+ class NetworkOnly extends Strategy {
1435
+ _networkTimeoutSeconds;
1436
+ constructor(options = {}){
1437
+ super(options);
1438
+ this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
1439
+ }
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
+ });
1448
+ }
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
+ }
1467
+ }
1468
+ if (process.env.NODE_ENV !== "production") {
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();
1477
+ }
1478
+ if (!response) {
1479
+ throw new SerwistError("no-response", {
1480
+ url: request.url,
1481
+ error
1482
+ });
1483
+ }
1484
+ return response;
27
1485
  }
28
1486
  }
29
1487
 
@@ -114,6 +1572,29 @@ const createGtmJsRoute = (cacheName)=>{
114
1572
  });
115
1573
  return new Route(match, handler, "GET");
116
1574
  };
1575
+ class GoogleAnalytics {
1576
+ _options;
1577
+ constructor(options = {}){
1578
+ this._options = options;
1579
+ }
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);
1594
+ }
1595
+ }
1596
+ }
1597
+
117
1598
  const initializeGoogleAnalytics = ({ serwist, cacheName, ...options })=>{
118
1599
  const resolvedCacheName = cacheNames$1.getGoogleAnalyticsName(cacheName);
119
1600
  const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {
@@ -131,30 +1612,82 @@ const initializeGoogleAnalytics = ({ serwist, cacheName, ...options })=>{
131
1612
  }
132
1613
  };
133
1614
 
134
- class PrecacheFallbackPlugin {
135
- _fallbackUrls;
136
- _serwist;
137
- constructor({ fallbackUrls, serwist }){
138
- this._fallbackUrls = fallbackUrls;
139
- this._serwist = serwist;
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
+ });
140
1621
  }
141
- async handlerDidError(param) {
142
- for (const fallback of this._fallbackUrls){
143
- if (typeof fallback === "string") {
144
- const fallbackResponse = await this._serwist.matchPrecache(fallback);
145
- if (fallbackResponse !== undefined) {
146
- return fallbackResponse;
147
- }
148
- } else if (fallback.matcher(param)) {
149
- const fallbackResponse = await this._serwist.matchPrecache(fallback.url);
150
- if (fallbackResponse !== undefined) {
151
- return fallbackResponse;
152
- }
153
- }
154
- }
155
- return undefined;
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();
1664
+ }
1665
+ };
1666
+
1667
+ function _nestedGroup(groupTitle, urls) {
1668
+ if (urls.length === 0) {
1669
+ return;
1670
+ }
1671
+ logger.groupCollapsed(groupTitle);
1672
+ for (const url of urls){
1673
+ logger.log(url);
156
1674
  }
1675
+ logger.groupEnd();
157
1676
  }
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.`;
1684
+ }
1685
+ logger.groupCollapsed(message);
1686
+ _nestedGroup("View newly precached URLs.", urlsToPrecache);
1687
+ _nestedGroup("View previously precached URLs.", urlsAlreadyPrecached);
1688
+ logger.groupEnd();
1689
+ }
1690
+ };
158
1691
 
159
1692
  class PrecacheCacheKeyPlugin {
160
1693
  _precacheController;
@@ -169,134 +1702,323 @@ class PrecacheCacheKeyPlugin {
169
1702
  };
170
1703
  }
171
1704
 
172
- const parsePrecacheOptions = (serwist, precacheOptions = {})=>{
173
- const { cacheName: precacheCacheName, plugins: precachePlugins = [], fetchOptions: precacheFetchOptions, matchOptions: precacheMatchOptions, fallbackToNetwork: precacheFallbackToNetwork, directoryIndex: precacheDirectoryIndex, ignoreURLParametersMatching: precacheIgnoreUrls, cleanURLs: precacheCleanUrls, urlManipulation: precacheUrlManipulation, cleanupOutdatedCaches, concurrency = 10, navigateFallback, navigateFallbackAllowlist, navigateFallbackDenylist } = precacheOptions ?? {};
174
- return {
175
- precacheStrategyOptions: {
176
- cacheName: cacheNames$1.getPrecacheName(precacheCacheName),
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),
177
1709
  plugins: [
178
- ...precachePlugins,
1710
+ ...plugins ?? [],
179
1711
  new PrecacheCacheKeyPlugin({
180
- precacheController: serwist
1712
+ precacheController: controller
181
1713
  })
182
1714
  ],
183
- fetchOptions: precacheFetchOptions,
184
- matchOptions: precacheMatchOptions,
185
- fallbackToNetwork: precacheFallbackToNetwork
1715
+ fetchOptions,
1716
+ matchOptions,
1717
+ fallbackToNetwork
186
1718
  },
187
- precacheRouteOptions: {
188
- directoryIndex: precacheDirectoryIndex,
189
- ignoreURLParametersMatching: precacheIgnoreUrls,
190
- cleanURLs: precacheCleanUrls,
191
- urlManipulation: precacheUrlManipulation
1719
+ routeOptions: {
1720
+ directoryIndex,
1721
+ ignoreURLParametersMatching,
1722
+ cleanURLs,
1723
+ urlManipulation
192
1724
  },
193
- precacheMiscOptions: {
1725
+ extensionOptions: {
194
1726
  cleanupOutdatedCaches,
195
- concurrency,
1727
+ concurrency: concurrency ?? 10,
196
1728
  navigateFallback,
197
1729
  navigateFallbackAllowlist,
198
1730
  navigateFallbackDenylist
199
1731
  }
1732
+ });
1733
+
1734
+ class PrecacheInstallReportPlugin {
1735
+ updatedURLs = [];
1736
+ notUpdatedURLs = [];
1737
+ handlerWillStart = async ({ request, state })=>{
1738
+ if (state) {
1739
+ state.originalRequest = request;
1740
+ }
200
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);
1763
+ }
1764
+ }
1765
+ return urlObject;
201
1766
  };
202
1767
 
203
- class Serwist {
204
- _urlsToCacheKeys = new Map();
205
- _urlsToCacheModes = new Map();
206
- _cacheKeysToIntegrities = new Map();
207
- _concurrentPrecaching;
208
- _precacheStrategy;
209
- _routes;
210
- _defaultHandlerMap;
211
- _catchHandler;
212
- constructor({ precacheEntries, precacheOptions, skipWaiting = false, importScripts, navigationPreload = false, cacheId, clientsClaim: clientsClaim$1 = false, runtimeCaching, offlineAnalyticsConfig, disableDevLogs: disableDevLogs$1 = false, fallbacks } = {}){
213
- const { precacheStrategyOptions, precacheRouteOptions, precacheMiscOptions } = parsePrecacheOptions(this, precacheOptions);
214
- this._concurrentPrecaching = precacheMiscOptions.concurrency;
215
- this._precacheStrategy = new PrecacheStrategy(precacheStrategyOptions);
216
- this._routes = new Map();
217
- this._defaultHandlerMap = new Map();
218
- this.handleInstall = this.handleInstall.bind(this);
219
- this.handleActivate = this.handleActivate.bind(this);
220
- this.handleFetch = this.handleFetch.bind(this);
221
- this.handleCache = this.handleCache.bind(this);
222
- if (!!importScripts && importScripts.length > 0) self.importScripts(...importScripts);
223
- if (navigationPreload) enableNavigationPreload();
224
- if (cacheId !== undefined) {
225
- setCacheNameDetails({
226
- prefix: cacheId
227
- });
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;
228
1793
  }
229
- if (skipWaiting) {
230
- self.skipWaiting();
231
- } else {
232
- self.addEventListener("message", (event)=>{
233
- if (event.data && event.data.type === "SKIP_WAITING") {
234
- self.skipWaiting();
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
+ };
235
1809
  }
1810
+ }
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);
1817
+ }
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}`
236
1830
  });
237
1831
  }
238
- if (clientsClaim$1) clientsClaim();
239
- if (!!precacheEntries && precacheEntries.length > 0) {
240
- this.addToPrecacheList(precacheEntries);
1832
+ if (details.precache?.length === 0) {
1833
+ throw new SerwistError("invalid-cache-name", {
1834
+ cacheNameId: "precache",
1835
+ value: details.precache
1836
+ });
241
1837
  }
242
- if (precacheMiscOptions.cleanupOutdatedCaches) {
243
- cleanupOutdatedCaches(precacheStrategyOptions.cacheName);
1838
+ if (details.runtime?.length === 0) {
1839
+ throw new SerwistError("invalid-cache-name", {
1840
+ cacheNameId: "runtime",
1841
+ value: details.runtime
1842
+ });
244
1843
  }
245
- this.registerRoute(new PrecacheRoute(this, precacheRouteOptions));
246
- if (precacheMiscOptions.navigateFallback) {
247
- this.registerRoute(new NavigationRoute(this.createHandlerBoundToUrl(precacheMiscOptions.navigateFallback), {
248
- allowlist: precacheMiscOptions.navigateFallbackAllowlist,
249
- denylist: precacheMiscOptions.navigateFallbackDenylist
250
- }));
1844
+ if (details.googleAnalytics?.length === 0) {
1845
+ throw new SerwistError("invalid-cache-name", {
1846
+ cacheNameId: "googleAnalytics",
1847
+ value: details.googleAnalytics
1848
+ });
251
1849
  }
252
- if (offlineAnalyticsConfig !== undefined) {
253
- if (typeof offlineAnalyticsConfig === "boolean") {
254
- offlineAnalyticsConfig && initializeGoogleAnalytics({
255
- serwist: this
256
- });
257
- } else {
258
- initializeGoogleAnalytics({
259
- ...offlineAnalyticsConfig,
260
- serwist: this
261
- });
1850
+ }
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
1875
+ });
1876
+ }
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;
262
1894
  }
1895
+ return response;
263
1896
  }
264
- if (runtimeCaching !== undefined) {
265
- if (fallbacks !== undefined) {
266
- const fallbackPlugin = new PrecacheFallbackPlugin({
267
- fallbackUrls: fallbacks.entries,
268
- serwist: this
269
- });
270
- runtimeCaching.forEach((cacheEntry)=>{
271
- if (cacheEntry.handler instanceof Strategy && !cacheEntry.handler.plugins.some((plugin)=>"handlerDidError" in plugin)) {
272
- cacheEntry.handler.plugins.push(fallbackPlugin);
273
- }
274
- });
1897
+ };
1898
+ static copyRedirectedCacheableResponsesPlugin = {
1899
+ async cacheWillUpdate ({ response }) {
1900
+ return response.redirected ? await copyResponse(response) : response;
1901
+ }
1902
+ };
1903
+ constructor(options = {}){
1904
+ options.cacheName = cacheNames$1.getPrecacheName(options.cacheName);
1905
+ super(options);
1906
+ this._fallbackToNetwork = options.fallbackToNetwork !== false;
1907
+ this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);
1908
+ }
1909
+ async _handle(request, handler) {
1910
+ const preloadResponse = await handler.getPreloadResponse();
1911
+ if (preloadResponse) {
1912
+ return preloadResponse;
1913
+ }
1914
+ const response = await handler.cacheMatch(request);
1915
+ if (response) {
1916
+ return response;
1917
+ }
1918
+ if (handler.event && handler.event.type === "install") {
1919
+ return await this._handleInstall(request, handler);
1920
+ }
1921
+ return await this._handleFetch(request, handler);
1922
+ }
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.`);
275
1929
  }
276
- for (const entry of runtimeCaching){
277
- this.registerCapture(entry.matcher, entry.handler, entry.method);
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());
1939
+ if (process.env.NODE_ENV !== "production") {
1940
+ if (wasCached) {
1941
+ logger.log(`A response for ${getFriendlyURL(request.url)} was used to "repair" the precache.`);
1942
+ }
1943
+ }
278
1944
  }
1945
+ } else {
1946
+ throw new SerwistError("missing-precache-entry", {
1947
+ cacheName: this.cacheName,
1948
+ url: request.url
1949
+ });
279
1950
  }
280
- if (disableDevLogs$1) disableDevLogs();
281
- }
282
- get precacheStrategy() {
283
- return this._precacheStrategy;
1951
+ if (process.env.NODE_ENV !== "production") {
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;
284
1964
  }
285
- get routes() {
286
- return this._routes;
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;
287
1976
  }
288
- addEventListeners() {
289
- self.addEventListener("install", this.handleInstall);
290
- self.addEventListener("activate", this.handleActivate);
291
- self.addEventListener("fetch", this.handleFetch);
292
- self.addEventListener("message", this.handleCache);
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;
1983
+ }
1984
+ if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
1985
+ defaultPluginIndex = index;
1986
+ }
1987
+ if (plugin.cacheWillUpdate) {
1988
+ cacheWillUpdatePluginCount++;
1989
+ }
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
+ }
293
1996
  }
294
- addToPrecacheList(entries) {
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;
2012
+ }
2013
+ get strategy() {
2014
+ return this._strategy;
2015
+ }
2016
+ addToCacheList(entries) {
295
2017
  if (process.env.NODE_ENV !== "production") {
296
2018
  finalAssertExports.isArray(entries, {
297
2019
  moduleName: "serwist",
298
- className: "Serwist",
299
- funcName: "addToCacheList",
2020
+ className: "PrecacheController",
2021
+ funcName: "addEntries",
300
2022
  paramName: "entries"
301
2023
  });
302
2024
  }
@@ -323,163 +2045,65 @@ class Serwist {
323
2045
  }
324
2046
  this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);
325
2047
  }
326
- this._urlsToCacheKeys.set(url, cacheKey);
327
- this._urlsToCacheModes.set(url, cacheMode);
328
- if (urlsToWarnAbout.length > 0) {
329
- const warningMessage = `Serwist is precaching URLs without revision info: ${urlsToWarnAbout.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;
330
- if (process.env.NODE_ENV === "production") {
331
- console.warn(warningMessage);
332
- } else {
333
- logger.warn(warningMessage);
334
- }
335
- }
336
- }
337
- }
338
- handleInstall(event) {
339
- return waitUntil(event, async ()=>{
340
- const installReportPlugin = new PrecacheInstallReportPlugin();
341
- this.precacheStrategy.plugins.push(installReportPlugin);
342
- await parallel(this._concurrentPrecaching, Array.from(this._urlsToCacheKeys.entries()), async ([url, cacheKey])=>{
343
- const integrity = this._cacheKeysToIntegrities.get(cacheKey);
344
- const cacheMode = this._urlsToCacheModes.get(url);
345
- const request = new Request(url, {
346
- integrity,
347
- cache: cacheMode,
348
- credentials: "same-origin"
349
- });
350
- await Promise.all(this.precacheStrategy.handleAll({
351
- event,
352
- request,
353
- url: new URL(request.url),
354
- params: {
355
- cacheKey
356
- }
357
- }));
358
- });
359
- const { updatedURLs, notUpdatedURLs } = installReportPlugin;
360
- if (process.env.NODE_ENV !== "production") {
361
- printInstallDetails(updatedURLs, notUpdatedURLs);
362
- }
363
- return {
364
- updatedURLs,
365
- notUpdatedURLs
366
- };
367
- });
368
- }
369
- handleActivate(event) {
370
- return waitUntil(event, async ()=>{
371
- const cache = await self.caches.open(this.precacheStrategy.cacheName);
372
- const currentlyCachedRequests = await cache.keys();
373
- const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());
374
- const deletedCacheRequests = [];
375
- for (const request of currentlyCachedRequests){
376
- if (!expectedCacheKeys.has(request.url)) {
377
- await cache.delete(request);
378
- deletedCacheRequests.push(request.url);
379
- }
380
- }
381
- if (process.env.NODE_ENV !== "production") {
382
- printCleanupDetails(deletedCacheRequests);
383
- }
384
- return {
385
- deletedCacheRequests
386
- };
387
- });
388
- }
389
- handleFetch(event) {
390
- const { request } = event;
391
- const responsePromise = this.handleRequest({
392
- request,
393
- event
394
- });
395
- if (responsePromise) {
396
- event.respondWith(responsePromise);
397
- }
398
- }
399
- handleCache(event) {
400
- if (event.data && event.data.type === "CACHE_URLS") {
401
- const { payload } = event.data;
402
- if (process.env.NODE_ENV !== "production") {
403
- logger.debug("Caching URLs from the window", payload.urlsToCache);
404
- }
405
- const requestPromises = Promise.all(payload.urlsToCache.map((entry)=>{
406
- let request;
407
- if (typeof entry === "string") {
408
- request = new Request(entry);
409
- } else {
410
- request = new Request(...entry);
411
- }
412
- return this.handleRequest({
413
- request,
414
- event
415
- });
416
- }));
417
- event.waitUntil(requestPromises);
418
- if (event.ports?.[0]) {
419
- void requestPromises.then(()=>event.ports[0].postMessage(true));
420
- }
421
- }
422
- }
423
- setDefaultHandler(handler, method = defaultMethod) {
424
- this._defaultHandlerMap.set(method, normalizeHandler(handler));
425
- }
426
- setCatchHandler(handler) {
427
- this._catchHandler = normalizeHandler(handler);
428
- }
429
- registerCapture(capture, handler, method) {
430
- const route = parseRoute(capture, handler, method);
431
- this.registerRoute(route);
432
- return route;
433
- }
434
- registerRoute(route) {
435
- if (process.env.NODE_ENV !== "production") {
436
- finalAssertExports.isType(route, "object", {
437
- moduleName: "serwist",
438
- className: "Serwist",
439
- funcName: "registerRoute",
440
- paramName: "route"
441
- });
442
- finalAssertExports.hasMethod(route, "match", {
443
- moduleName: "serwist",
444
- className: "Serwist",
445
- funcName: "registerRoute",
446
- paramName: "route"
447
- });
448
- finalAssertExports.isType(route.handler, "object", {
449
- moduleName: "serwist",
450
- className: "Serwist",
451
- funcName: "registerRoute",
452
- paramName: "route"
453
- });
454
- finalAssertExports.hasMethod(route.handler, "handle", {
455
- moduleName: "serwist",
456
- className: "Serwist",
457
- funcName: "registerRoute",
458
- paramName: "route.handler"
459
- });
460
- finalAssertExports.isType(route.method, "string", {
461
- moduleName: "serwist",
462
- className: "Serwist",
463
- funcName: "registerRoute",
464
- paramName: "route.method"
465
- });
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);
2056
+ }
2057
+ }
466
2058
  }
467
- if (!this._routes.has(route.method)) {
468
- this._routes.set(route.method, []);
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
2066
+ }));
469
2067
  }
470
- this._routes.get(route.method).push(route);
471
2068
  }
472
- unregisterRoute(route) {
473
- if (!this._routes.has(route.method)) {
474
- throw new SerwistError("unregister-route-but-not-found-with-method", {
475
- method: route.method
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"
476
2079
  });
2080
+ await Promise.all(this._strategy.handleAll({
2081
+ event,
2082
+ request,
2083
+ url: new URL(request.url),
2084
+ params: {
2085
+ cacheKey
2086
+ }
2087
+ }));
2088
+ });
2089
+ const { updatedURLs, notUpdatedURLs } = installReportPlugin;
2090
+ if (process.env.NODE_ENV !== "production") {
2091
+ printInstallDetails(updatedURLs, notUpdatedURLs);
2092
+ }
2093
+ }
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
+ }
477
2104
  }
478
- const routeIndex = this._routes.get(route.method).indexOf(route);
479
- if (routeIndex > -1) {
480
- this._routes.get(route.method).splice(routeIndex, 1);
481
- } else {
482
- throw new SerwistError("unregister-route-route-not-registered");
2105
+ if (process.env.NODE_ENV !== "production") {
2106
+ printCleanupDetails(deletedCacheRequests);
483
2107
  }
484
2108
  }
485
2109
  getUrlsToPrecacheKeys() {
@@ -501,7 +2125,7 @@ class Serwist {
501
2125
  const url = request instanceof Request ? request.url : request;
502
2126
  const cacheKey = this.getPrecacheKeyForUrl(url);
503
2127
  if (cacheKey) {
504
- const cache = await self.caches.open(this.precacheStrategy.cacheName);
2128
+ const cache = await self.caches.open(this._strategy.cacheName);
505
2129
  return cache.match(cacheKey);
506
2130
  }
507
2131
  return undefined;
@@ -519,175 +2143,344 @@ class Serwist {
519
2143
  cacheKey,
520
2144
  ...options.params
521
2145
  };
522
- return this.precacheStrategy.handle(options);
2146
+ return this._strategy.handle(options);
523
2147
  };
524
2148
  }
525
- handleRequest({ request, event }) {
526
- if (process.env.NODE_ENV !== "production") {
527
- finalAssertExports.isInstance(request, Request, {
528
- moduleName: "serwist",
529
- className: "Serwist",
530
- funcName: "handleRequest",
531
- paramName: "options.request"
532
- });
533
- }
534
- const url = new URL(request.url, location.href);
535
- if (!url.protocol.startsWith("http")) {
536
- if (process.env.NODE_ENV !== "production") {
537
- logger.debug("Router only supports URLs that start with 'http'.");
2149
+ }
2150
+
2151
+ class PrecacheFallbackPlugin {
2152
+ _fallbackUrls;
2153
+ _serwist;
2154
+ constructor({ fallbackUrls, serwist }){
2155
+ this._fallbackUrls = fallbackUrls;
2156
+ this._serwist = 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
+ }
538
2180
  }
539
- return;
540
2181
  }
541
- const sameOrigin = url.origin === location.origin;
542
- const { params, route } = this.findMatchingRoute({
543
- event,
544
- request,
545
- sameOrigin,
546
- url
547
- });
548
- let handler = route?.handler;
549
- const debugMessages = [];
550
- if (process.env.NODE_ENV !== "production") {
551
- if (handler) {
552
- debugMessages.push([
553
- "Found a route to handle this request:",
554
- route
555
- ]);
556
- if (params) {
557
- debugMessages.push([
558
- `Passing the following params to the route's handler:`,
559
- params
560
- ]);
2182
+ return undefined;
2183
+ }
2184
+ }
2185
+
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
2200
+ });
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);
561
2204
  }
562
- }
2205
+ });
563
2206
  }
564
- const method = request.method;
565
- if (!handler && this._defaultHandlerMap.has(method)) {
566
- if (process.env.NODE_ENV !== "production") {
567
- debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);
2207
+ for (const entry of this._entries){
2208
+ registerCapture(serwist, entry.matcher, entry.handler, entry.method);
2209
+ }
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"
2220
+ });
2221
+ await handleRequest(serwist, {
2222
+ request,
2223
+ event
2224
+ });
2225
+ });
2226
+ }
2227
+ }
2228
+ warmRuntimeCache(entries) {
2229
+ if (!this._options.warmEntries) this._options.warmEntries = [];
2230
+ this._options.warmEntries.push(...entries);
2231
+ }
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)=>{
2242
+ return waitUntil(event, async ()=>{
2243
+ for (const callback of iterateExtensions(state, "install")){
2244
+ await callback({
2245
+ event,
2246
+ serwist: state
2247
+ });
2248
+ }
2249
+ });
2250
+ };
2251
+ };
2252
+ const createActivateHandler = (state)=>{
2253
+ return (event)=>{
2254
+ return waitUntil(event, async ()=>{
2255
+ for (const callback of iterateExtensions(state, "activate")){
2256
+ await callback({
2257
+ event,
2258
+ serwist: state
2259
+ });
568
2260
  }
569
- handler = this._defaultHandlerMap.get(method);
2261
+ });
2262
+ };
2263
+ };
2264
+ const createFetchHandler = (state)=>{
2265
+ return (event)=>{
2266
+ const { request } = event;
2267
+ const responsePromise = handleRequest(state, {
2268
+ request,
2269
+ event
2270
+ });
2271
+ if (responsePromise) {
2272
+ event.respondWith(responsePromise);
570
2273
  }
571
- if (!handler) {
2274
+ };
2275
+ };
2276
+ const createCacheHandler = (state)=>{
2277
+ return (event)=>{
2278
+ if (event.data && event.data.type === "CACHE_URLS") {
2279
+ const { payload } = event.data;
572
2280
  if (process.env.NODE_ENV !== "production") {
573
- logger.debug(`No route found for: ${getFriendlyURL(url)}`);
2281
+ logger.debug("Caching URLs from the window", payload.urlsToCache);
574
2282
  }
575
- return;
576
- }
577
- if (process.env.NODE_ENV !== "production") {
578
- logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
579
- for (const msg of debugMessages){
580
- if (Array.isArray(msg)) {
581
- logger.log(...msg);
2283
+ const requestPromises = Promise.all(payload.urlsToCache.map((entry)=>{
2284
+ let request;
2285
+ if (typeof entry === "string") {
2286
+ request = new Request(entry);
582
2287
  } else {
583
- logger.log(msg);
2288
+ request = new Request(...entry);
584
2289
  }
2290
+ return handleRequest(state, {
2291
+ request,
2292
+ event
2293
+ });
2294
+ }));
2295
+ event.waitUntil(requestPromises);
2296
+ if (event.ports?.[0]) {
2297
+ void requestPromises.then(()=>event.ports[0].postMessage(true));
585
2298
  }
586
- logger.groupEnd();
587
2299
  }
588
- let responsePromise;
589
- try {
590
- responsePromise = handler.handle({
591
- url,
592
- request,
593
- event,
594
- params
595
- });
596
- } catch (err) {
597
- responsePromise = Promise.reject(err);
598
- }
599
- const catchHandler = route?.catchHandler;
600
- if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
601
- responsePromise = responsePromise.catch(async (err)=>{
602
- if (catchHandler) {
603
- if (process.env.NODE_ENV !== "production") {
604
- logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
605
- logger.error("Error thrown by:", route);
606
- logger.error(err);
607
- logger.groupEnd();
608
- }
609
- try {
610
- return await catchHandler.handle({
611
- url,
612
- request,
613
- event,
614
- params
615
- });
616
- } catch (catchErr) {
617
- if (catchErr instanceof Error) {
618
- err = catchErr;
619
- }
620
- }
621
- }
622
- if (this._catchHandler) {
623
- if (process.env.NODE_ENV !== "production") {
624
- logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
625
- logger.error("Error thrown by:", route);
626
- logger.error(err);
627
- logger.groupEnd();
628
- }
629
- return this._catchHandler.handle({
630
- url,
631
- request,
632
- event
633
- });
634
- }
635
- throw err;
636
- });
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;
637
2316
  }
638
- return responsePromise;
639
2317
  }
640
- findMatchingRoute({ url, sameOrigin, request, event }) {
641
- const routes = this._routes.get(request.method) || [];
642
- for (const route of routes){
643
- let params;
644
- const matchResult = route.match({
645
- url,
646
- sameOrigin,
647
- request,
648
- event
649
- });
650
- if (matchResult) {
651
- if (process.env.NODE_ENV !== "production") {
652
- if (matchResult instanceof Promise) {
653
- logger.warn(`While routing ${getFriendlyURL(url)}, an async matchCallback function was used. Please convert the following route to use a synchronous matchCallback function:`, route);
654
- }
655
- }
656
- params = matchResult;
657
- if (Array.isArray(params) && params.length === 0) {
658
- params = undefined;
659
- } else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {
660
- params = undefined;
661
- } else if (typeof matchResult === "boolean") {
662
- params = undefined;
663
- }
664
- return {
665
- route,
666
- params
667
- };
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();
668
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;
669
2357
  }
670
- return {};
2358
+ };
2359
+ for (const callback of iterateExtensions(state, "init")){
2360
+ callback({
2361
+ serwist: state
2362
+ });
671
2363
  }
672
- }
2364
+ if (disableDevLogs$1) disableDevLogs();
2365
+ return state;
2366
+ };
673
2367
 
674
- const cacheNames = {
675
- get googleAnalytics () {
676
- return cacheNames$1.getGoogleAnalyticsName();
677
- },
678
- get precache () {
679
- return cacheNames$1.getPrecacheName();
680
- },
681
- get prefix () {
682
- return cacheNames$1.getPrefix();
683
- },
684
- get runtime () {
685
- return cacheNames$1.getRuntimeName();
686
- },
687
- get suffix () {
688
- return cacheNames$1.getSuffix();
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);
689
2402
  }
690
- };
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);
2420
+ }
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);
2435
+ }
2436
+ setCatchHandler(handler) {
2437
+ setCatchHandler(this._state, handler);
2438
+ }
2439
+ registerCapture(capture, handler, method) {
2440
+ return registerCapture(this._state, capture, handler, method);
2441
+ }
2442
+ registerRoute(route) {
2443
+ registerRoute(this._state, route);
2444
+ }
2445
+ unregisterRoute(route) {
2446
+ unregisterRoute(this._state, route);
2447
+ }
2448
+ handleRequest({ request, event }) {
2449
+ return handleRequest(this._state, {
2450
+ request,
2451
+ event
2452
+ });
2453
+ }
2454
+ findMatchingRoute({ url, sameOrigin, request, event }) {
2455
+ return findMatchingRoute(this._state, {
2456
+ url,
2457
+ sameOrigin,
2458
+ request,
2459
+ event
2460
+ });
2461
+ }
2462
+ addToPrecacheList(entries) {
2463
+ this.precache.addToCacheList(entries);
2464
+ }
2465
+ getUrlsToPrecacheKeys() {
2466
+ return this.precache.getUrlsToPrecacheKeys();
2467
+ }
2468
+ getPrecachedUrls() {
2469
+ return this.precache.getPrecachedUrls();
2470
+ }
2471
+ getPrecacheKeyForUrl(url) {
2472
+ return this.precache.getPrecacheKeyForUrl(url);
2473
+ }
2474
+ getIntegrityForPrecacheKey(cacheKey) {
2475
+ return this.precache.getIntegrityForPrecacheKey(cacheKey);
2476
+ }
2477
+ matchPrecache(request) {
2478
+ return this.precache.matchPrecache(request);
2479
+ }
2480
+ createHandlerBoundToUrl(url) {
2481
+ return this.precache.createHandlerBoundToUrl(url);
2482
+ }
2483
+ }
691
2484
 
692
2485
  const BROADCAST_UPDATE_MESSAGE_TYPE = "CACHE_UPDATED";
693
2486
  const BROADCAST_UPDATE_MESSAGE_META = "serwist-broadcast-update";
@@ -1090,20 +2883,6 @@ class CacheExpiration {
1090
2883
  }
1091
2884
  }
1092
2885
 
1093
- const registerQuotaErrorCallback = (callback)=>{
1094
- if (process.env.NODE_ENV !== "production") {
1095
- finalAssertExports.isType(callback, "function", {
1096
- moduleName: "@serwist/core",
1097
- funcName: "register",
1098
- paramName: "callback"
1099
- });
1100
- }
1101
- quotaErrorCallbacks.add(callback);
1102
- if (process.env.NODE_ENV !== "production") {
1103
- logger.log("Registered a callback to respond to quota errors.", callback);
1104
- }
1105
- };
1106
-
1107
2886
  class ExpirationPlugin {
1108
2887
  _config;
1109
2888
  _cacheExpirations;
@@ -1503,4 +3282,4 @@ class StaleWhileRevalidate extends Strategy {
1503
3282
  }
1504
3283
  }
1505
3284
 
1506
- export { BROADCAST_UPDATE_DEFAULT_HEADERS, BackgroundSyncPlugin, BroadcastCacheUpdate, BroadcastUpdatePlugin, CacheExpiration, CacheFirst, CacheOnly, CacheableResponse, CacheableResponsePlugin, ExpirationPlugin, NavigationRoute, NetworkFirst, NetworkOnly, PrecacheFallbackPlugin, PrecacheRoute, PrecacheStrategy, RangeRequestsPlugin, Route, Serwist, StaleWhileRevalidate, Strategy, cacheNames, createPartialResponse, disableDevLogs, enableNavigationPreload, initializeGoogleAnalytics, registerQuotaErrorCallback, responsesAreSame, setCacheNameDetails };
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 };