@serwist/sw 9.0.0-preview.17 → 9.0.0-preview.18

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 (251) hide show
  1. package/dist/{Serwist.d.ts → abstractions/Serwist.d.ts} +6 -15
  2. package/dist/abstractions/Serwist.d.ts.map +1 -0
  3. package/dist/abstractions/disableDevLogs.d.ts.map +1 -0
  4. package/dist/{fallbacks.d.ts → abstractions/fallbacks.d.ts} +2 -2
  5. package/dist/abstractions/fallbacks.d.ts.map +1 -0
  6. package/dist/{handlePrecaching.d.ts → abstractions/handlePrecaching.d.ts} +1 -1
  7. package/dist/abstractions/handlePrecaching.d.ts.map +1 -0
  8. package/dist/abstractions/installSerwist.d.ts.map +1 -0
  9. package/dist/abstractions/registerRuntimeCaching.d.ts.map +1 -0
  10. package/dist/{types.d.ts → abstractions/types.d.ts} +1 -1
  11. package/dist/abstractions/types.d.ts.map +1 -0
  12. package/dist/chunks/NavigationRoute.js +54 -0
  13. package/dist/chunks/NetworkOnly.js +193 -0
  14. package/dist/chunks/PrecacheFallbackPlugin.js +573 -0
  15. package/dist/chunks/Strategy.js +410 -0
  16. package/dist/chunks/getOrCreatePrecacheController.js +429 -0
  17. package/dist/chunks/precacheAndRoute.js +112 -0
  18. package/dist/chunks/registerRoute.js +408 -0
  19. package/dist/index.d.ts +8 -8
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +11 -9
  22. package/dist/index.plugins.d.ts +40 -11
  23. package/dist/index.plugins.d.ts.map +1 -1
  24. package/dist/index.plugins.js +671 -5
  25. package/dist/index.precaching.d.ts +24 -0
  26. package/dist/index.precaching.d.ts.map +1 -0
  27. package/dist/index.precaching.js +24 -0
  28. package/dist/index.routing.d.ts +13 -0
  29. package/dist/index.routing.d.ts.map +1 -0
  30. package/dist/index.routing.js +21 -0
  31. package/dist/index.strategies.d.ts +19 -2
  32. package/dist/index.strategies.d.ts.map +1 -1
  33. package/dist/index.strategies.js +146 -1
  34. package/dist/plugins/backgroundSync/BackgroundSyncPlugin.d.ts +23 -0
  35. package/dist/plugins/backgroundSync/BackgroundSyncPlugin.d.ts.map +1 -0
  36. package/dist/plugins/backgroundSync/Queue.d.ts +166 -0
  37. package/dist/plugins/backgroundSync/Queue.d.ts.map +1 -0
  38. package/dist/plugins/backgroundSync/QueueDb.d.ts +90 -0
  39. package/dist/plugins/backgroundSync/QueueDb.d.ts.map +1 -0
  40. package/dist/plugins/backgroundSync/QueueStore.d.ts +75 -0
  41. package/dist/plugins/backgroundSync/QueueStore.d.ts.map +1 -0
  42. package/dist/plugins/backgroundSync/StorableRequest.d.ts +51 -0
  43. package/dist/plugins/backgroundSync/StorableRequest.d.ts.map +1 -0
  44. package/dist/plugins/broadcastUpdate/BroadcastCacheUpdate.d.ts +45 -0
  45. package/dist/plugins/broadcastUpdate/BroadcastCacheUpdate.d.ts.map +1 -0
  46. package/dist/plugins/broadcastUpdate/BroadcastUpdatePlugin.d.ts +27 -0
  47. package/dist/plugins/broadcastUpdate/BroadcastUpdatePlugin.d.ts.map +1 -0
  48. package/dist/plugins/broadcastUpdate/constants.d.ts +5 -0
  49. package/dist/plugins/broadcastUpdate/constants.d.ts.map +1 -0
  50. package/dist/plugins/broadcastUpdate/responsesAreSame.d.ts +11 -0
  51. package/dist/plugins/broadcastUpdate/responsesAreSame.d.ts.map +1 -0
  52. package/dist/plugins/broadcastUpdate/types.d.ts +34 -0
  53. package/dist/plugins/broadcastUpdate/types.d.ts.map +1 -0
  54. package/dist/plugins/cacheableResponse/CacheableResponse.d.ts +40 -0
  55. package/dist/plugins/cacheableResponse/CacheableResponse.d.ts.map +1 -0
  56. package/dist/plugins/cacheableResponse/CacheableResponsePlugin.d.ts +27 -0
  57. package/dist/plugins/cacheableResponse/CacheableResponsePlugin.d.ts.map +1 -0
  58. package/dist/plugins/expiration/CacheExpiration.d.ts +66 -0
  59. package/dist/plugins/expiration/CacheExpiration.d.ts.map +1 -0
  60. package/dist/plugins/expiration/ExpirationPlugin.d.ts +116 -0
  61. package/dist/plugins/expiration/ExpirationPlugin.d.ts.map +1 -0
  62. package/dist/plugins/expiration/models/CacheTimestampsModel.d.ts +73 -0
  63. package/dist/plugins/expiration/models/CacheTimestampsModel.d.ts.map +1 -0
  64. package/dist/plugins/googleAnalytics/constants.d.ts +10 -0
  65. package/dist/plugins/googleAnalytics/constants.d.ts.map +1 -0
  66. package/dist/plugins/googleAnalytics/initialize.d.ts +26 -0
  67. package/dist/plugins/googleAnalytics/initialize.d.ts.map +1 -0
  68. package/dist/plugins/precaching/PrecacheFallbackPlugin.d.ts +54 -0
  69. package/dist/plugins/precaching/PrecacheFallbackPlugin.d.ts.map +1 -0
  70. package/dist/plugins/rangeRequests/RangeRequestsPlugin.d.ts +19 -0
  71. package/dist/plugins/rangeRequests/RangeRequestsPlugin.d.ts.map +1 -0
  72. package/dist/plugins/rangeRequests/createPartialResponse.d.ts +18 -0
  73. package/dist/plugins/rangeRequests/createPartialResponse.d.ts.map +1 -0
  74. package/dist/plugins/rangeRequests/utils/calculateEffectiveBoundaries.d.ts +14 -0
  75. package/dist/plugins/rangeRequests/utils/calculateEffectiveBoundaries.d.ts.map +1 -0
  76. package/dist/plugins/rangeRequests/utils/parseRangeHeader.d.ts +12 -0
  77. package/dist/plugins/rangeRequests/utils/parseRangeHeader.d.ts.map +1 -0
  78. package/dist/precaching/PrecacheController.d.ts +145 -0
  79. package/dist/precaching/PrecacheController.d.ts.map +1 -0
  80. package/dist/precaching/PrecacheRoute.d.ts +20 -0
  81. package/dist/precaching/PrecacheRoute.d.ts.map +1 -0
  82. package/dist/precaching/PrecacheStrategy.d.ts +68 -0
  83. package/dist/precaching/PrecacheStrategy.d.ts.map +1 -0
  84. package/dist/precaching/addPlugins.d.ts +8 -0
  85. package/dist/precaching/addPlugins.d.ts.map +1 -0
  86. package/dist/precaching/addRoute.d.ts +15 -0
  87. package/dist/precaching/addRoute.d.ts.map +1 -0
  88. package/dist/precaching/cleanupOutdatedCaches.d.ts +6 -0
  89. package/dist/precaching/cleanupOutdatedCaches.d.ts.map +1 -0
  90. package/dist/precaching/createHandlerBoundToURL.d.ts +17 -0
  91. package/dist/precaching/createHandlerBoundToURL.d.ts.map +1 -0
  92. package/dist/precaching/getCacheKeyForURL.d.ts +20 -0
  93. package/dist/precaching/getCacheKeyForURL.d.ts.map +1 -0
  94. package/dist/precaching/matchPrecache.d.ts +14 -0
  95. package/dist/precaching/matchPrecache.d.ts.map +1 -0
  96. package/dist/precaching/precache.d.ts +19 -0
  97. package/dist/precaching/precache.d.ts.map +1 -0
  98. package/dist/precaching/precacheAndRoute.d.ts +14 -0
  99. package/dist/precaching/precacheAndRoute.d.ts.map +1 -0
  100. package/dist/precaching/types.d.ts +37 -0
  101. package/dist/precaching/types.d.ts.map +1 -0
  102. package/dist/precaching/utils/PrecacheCacheKeyPlugin.d.ts +17 -0
  103. package/dist/precaching/utils/PrecacheCacheKeyPlugin.d.ts.map +1 -0
  104. package/dist/precaching/utils/PrecacheInstallReportPlugin.d.ts +15 -0
  105. package/dist/precaching/utils/PrecacheInstallReportPlugin.d.ts.map +1 -0
  106. package/dist/precaching/utils/createCacheKey.d.ts +16 -0
  107. package/dist/precaching/utils/createCacheKey.d.ts.map +1 -0
  108. package/dist/precaching/utils/deleteOutdatedCaches.d.ts +18 -0
  109. package/dist/precaching/utils/deleteOutdatedCaches.d.ts.map +1 -0
  110. package/dist/precaching/utils/generateURLVariations.d.ts +12 -0
  111. package/dist/precaching/utils/generateURLVariations.d.ts.map +1 -0
  112. package/dist/precaching/utils/getCacheKeyForURL.d.ts +14 -0
  113. package/dist/precaching/utils/getCacheKeyForURL.d.ts.map +1 -0
  114. package/dist/precaching/utils/getOrCreatePrecacheController.d.ts +7 -0
  115. package/dist/precaching/utils/getOrCreatePrecacheController.d.ts.map +1 -0
  116. package/dist/precaching/utils/printCleanupDetails.d.ts +6 -0
  117. package/dist/precaching/utils/printCleanupDetails.d.ts.map +1 -0
  118. package/dist/precaching/utils/printInstallDetails.d.ts +7 -0
  119. package/dist/precaching/utils/printInstallDetails.d.ts.map +1 -0
  120. package/dist/precaching/utils/removeIgnoredSearchParams.d.ts +12 -0
  121. package/dist/precaching/utils/removeIgnoredSearchParams.d.ts.map +1 -0
  122. package/dist/routing/NavigationRoute.d.ts +57 -0
  123. package/dist/routing/NavigationRoute.d.ts.map +1 -0
  124. package/dist/routing/RegExpRoute.d.ts +24 -0
  125. package/dist/routing/RegExpRoute.d.ts.map +1 -0
  126. package/dist/routing/Route.d.ts +33 -0
  127. package/dist/routing/Route.d.ts.map +1 -0
  128. package/dist/routing/Router.d.ts +124 -0
  129. package/dist/routing/Router.d.ts.map +1 -0
  130. package/dist/routing/registerRoute.d.ts +15 -0
  131. package/dist/routing/registerRoute.d.ts.map +1 -0
  132. package/dist/routing/setCatchHandler.d.ts +9 -0
  133. package/dist/routing/setCatchHandler.d.ts.map +1 -0
  134. package/dist/routing/setDefaultHandler.d.ts +12 -0
  135. package/dist/routing/setDefaultHandler.d.ts.map +1 -0
  136. package/dist/routing/unregisterRoute.d.ts +8 -0
  137. package/dist/routing/unregisterRoute.d.ts.map +1 -0
  138. package/dist/routing/utils/constants.d.ts +15 -0
  139. package/dist/routing/utils/constants.d.ts.map +1 -0
  140. package/dist/routing/utils/getOrCreateDefaultRouter.d.ts +10 -0
  141. package/dist/routing/utils/getOrCreateDefaultRouter.d.ts.map +1 -0
  142. package/dist/routing/utils/normalizeHandler.d.ts +10 -0
  143. package/dist/routing/utils/normalizeHandler.d.ts.map +1 -0
  144. package/dist/routing/utils/parseRoute.d.ts +5 -0
  145. package/dist/routing/utils/parseRoute.d.ts.map +1 -0
  146. package/dist/strategies/CacheFirst.d.ts +23 -0
  147. package/dist/strategies/CacheFirst.d.ts.map +1 -0
  148. package/dist/strategies/CacheOnly.d.ts +20 -0
  149. package/dist/strategies/CacheOnly.d.ts.map +1 -0
  150. package/dist/strategies/NetworkFirst.d.ts +61 -0
  151. package/dist/strategies/NetworkFirst.d.ts.map +1 -0
  152. package/dist/strategies/NetworkOnly.d.ts +32 -0
  153. package/dist/strategies/NetworkOnly.d.ts.map +1 -0
  154. package/dist/strategies/StaleWhileRevalidate.d.ts +35 -0
  155. package/dist/strategies/StaleWhileRevalidate.d.ts.map +1 -0
  156. package/dist/strategies/Strategy.d.ts +83 -0
  157. package/dist/strategies/Strategy.d.ts.map +1 -0
  158. package/dist/strategies/StrategyHandler.d.ts +189 -0
  159. package/dist/strategies/StrategyHandler.d.ts.map +1 -0
  160. package/dist/strategies/plugins/cacheOkAndOpaquePlugin.d.ts +3 -0
  161. package/dist/strategies/plugins/cacheOkAndOpaquePlugin.d.ts.map +1 -0
  162. package/dist/strategies/utils/messages.d.ts +5 -0
  163. package/dist/strategies/utils/messages.d.ts.map +1 -0
  164. package/package.json +20 -14
  165. package/src/{Serwist.ts → abstractions/Serwist.ts} +16 -19
  166. package/src/{fallbacks.ts → abstractions/fallbacks.ts} +5 -5
  167. package/src/{handlePrecaching.ts → abstractions/handlePrecaching.ts} +6 -3
  168. package/src/{installSerwist.ts → abstractions/installSerwist.ts} +2 -2
  169. package/src/{registerRuntimeCaching.ts → abstractions/registerRuntimeCaching.ts} +1 -1
  170. package/src/{types.ts → abstractions/types.ts} +1 -1
  171. package/src/index.plugins.ts +65 -16
  172. package/src/index.precaching.ts +38 -0
  173. package/src/index.routing.ts +14 -0
  174. package/src/index.strategies.ts +22 -2
  175. package/src/index.ts +8 -8
  176. package/src/plugins/backgroundSync/BackgroundSyncPlugin.ts +39 -0
  177. package/src/plugins/backgroundSync/Queue.ts +438 -0
  178. package/src/plugins/backgroundSync/QueueDb.ts +176 -0
  179. package/src/plugins/backgroundSync/QueueStore.ts +161 -0
  180. package/src/plugins/backgroundSync/StorableRequest.ts +142 -0
  181. package/src/plugins/broadcastUpdate/BroadcastCacheUpdate.ts +159 -0
  182. package/src/plugins/broadcastUpdate/BroadcastUpdatePlugin.ts +43 -0
  183. package/src/plugins/broadcastUpdate/constants.ts +12 -0
  184. package/src/plugins/broadcastUpdate/responsesAreSame.ts +48 -0
  185. package/src/plugins/broadcastUpdate/types.ts +37 -0
  186. package/src/plugins/cacheableResponse/CacheableResponse.ts +141 -0
  187. package/src/plugins/cacheableResponse/CacheableResponsePlugin.ts +46 -0
  188. package/src/plugins/expiration/CacheExpiration.ts +192 -0
  189. package/src/plugins/expiration/ExpirationPlugin.ts +297 -0
  190. package/src/plugins/expiration/models/CacheTimestampsModel.ts +184 -0
  191. package/src/plugins/googleAnalytics/constants.ts +22 -0
  192. package/src/plugins/googleAnalytics/initialize.ts +200 -0
  193. package/src/plugins/precaching/PrecacheFallbackPlugin.ts +86 -0
  194. package/src/plugins/rangeRequests/RangeRequestsPlugin.ts +39 -0
  195. package/src/plugins/rangeRequests/createPartialResponse.ts +92 -0
  196. package/src/plugins/rangeRequests/utils/calculateEffectiveBoundaries.ts +58 -0
  197. package/src/plugins/rangeRequests/utils/parseRangeHeader.ts +54 -0
  198. package/src/precaching/PrecacheController.ts +332 -0
  199. package/src/precaching/PrecacheRoute.ts +50 -0
  200. package/src/precaching/PrecacheStrategy.ts +238 -0
  201. package/src/precaching/addPlugins.ts +21 -0
  202. package/src/precaching/addRoute.ts +30 -0
  203. package/src/precaching/cleanupOutdatedCaches.ts +33 -0
  204. package/src/precaching/createHandlerBoundToURL.ts +30 -0
  205. package/src/precaching/getCacheKeyForURL.ts +33 -0
  206. package/src/precaching/matchPrecache.ts +26 -0
  207. package/src/precaching/precache.ts +31 -0
  208. package/src/precaching/precacheAndRoute.ts +27 -0
  209. package/src/precaching/types.ts +46 -0
  210. package/src/precaching/utils/PrecacheCacheKeyPlugin.ts +36 -0
  211. package/src/precaching/utils/PrecacheInstallReportPlugin.ts +49 -0
  212. package/src/precaching/utils/createCacheKey.ts +68 -0
  213. package/src/precaching/utils/deleteOutdatedCaches.ts +40 -0
  214. package/src/precaching/utils/generateURLVariations.ts +55 -0
  215. package/src/precaching/utils/getCacheKeyForURL.ts +36 -0
  216. package/src/precaching/utils/getOrCreatePrecacheController.ts +22 -0
  217. package/src/precaching/utils/printCleanupDetails.ts +38 -0
  218. package/src/precaching/utils/printInstallDetails.ts +53 -0
  219. package/src/precaching/utils/removeIgnoredSearchParams.ts +29 -0
  220. package/src/routing/NavigationRoute.ts +119 -0
  221. package/src/routing/RegExpRoute.ts +74 -0
  222. package/src/routing/Route.ts +68 -0
  223. package/src/routing/Router.ts +432 -0
  224. package/src/routing/registerRoute.ts +33 -0
  225. package/src/routing/setCatchHandler.ts +22 -0
  226. package/src/routing/setDefaultHandler.ts +25 -0
  227. package/src/routing/unregisterRoute.ts +12 -0
  228. package/src/routing/utils/constants.ts +24 -0
  229. package/src/routing/utils/getOrCreateDefaultRouter.ts +29 -0
  230. package/src/routing/utils/normalizeHandler.ts +40 -0
  231. package/src/routing/utils/parseRoute.ts +67 -0
  232. package/src/strategies/CacheFirst.ts +87 -0
  233. package/src/strategies/CacheOnly.ts +58 -0
  234. package/src/strategies/NetworkFirst.ts +228 -0
  235. package/src/strategies/NetworkOnly.ts +96 -0
  236. package/src/strategies/StaleWhileRevalidate.ts +109 -0
  237. package/src/strategies/Strategy.ts +202 -0
  238. package/src/strategies/StrategyHandler.ts +557 -0
  239. package/src/strategies/plugins/cacheOkAndOpaquePlugin.ts +26 -0
  240. package/src/strategies/utils/messages.ts +20 -0
  241. package/dist/Serwist.d.ts.map +0 -1
  242. package/dist/disableDevLogs.d.ts.map +0 -1
  243. package/dist/fallbacks.d.ts.map +0 -1
  244. package/dist/handlePrecaching.d.ts.map +0 -1
  245. package/dist/installSerwist.d.ts.map +0 -1
  246. package/dist/registerRuntimeCaching.d.ts.map +0 -1
  247. package/dist/types.d.ts.map +0 -1
  248. /package/dist/{disableDevLogs.d.ts → abstractions/disableDevLogs.d.ts} +0 -0
  249. /package/dist/{installSerwist.d.ts → abstractions/installSerwist.d.ts} +0 -0
  250. /package/dist/{registerRuntimeCaching.d.ts → abstractions/registerRuntimeCaching.d.ts} +0 -0
  251. /package/src/{disableDevLogs.ts → abstractions/disableDevLogs.ts} +0 -0
@@ -0,0 +1,38 @@
1
+ import { PrecacheController } from "./precaching/PrecacheController.js";
2
+ import { PrecacheRoute } from "./precaching/PrecacheRoute.js";
3
+ import { PrecacheStrategy } from "./precaching/PrecacheStrategy.js";
4
+ import { addPlugins } from "./precaching/addPlugins.js";
5
+ import { addRoute } from "./precaching/addRoute.js";
6
+ import { cleanupOutdatedCaches } from "./precaching/cleanupOutdatedCaches.js";
7
+ import { createHandlerBoundToURL } from "./precaching/createHandlerBoundToURL.js";
8
+ import { getCacheKeyForURL } from "./precaching/getCacheKeyForURL.js";
9
+ import { matchPrecache } from "./precaching/matchPrecache.js";
10
+ import { precache } from "./precaching/precache.js";
11
+ import { precacheAndRoute } from "./precaching/precacheAndRoute.js";
12
+
13
+ /**
14
+ * Most consumers of this module will want to use the
15
+ * `@serwist/sw/precaching.precacheAndRoute`
16
+ * method to add assets to the cache and respond to network requests with these
17
+ * cached assets.
18
+ *
19
+ * If you require more control over caching and routing, you can use the
20
+ * `@serwist/precaching.PrecacheController`
21
+ * interface.
22
+ */
23
+
24
+ export {
25
+ addPlugins,
26
+ addRoute,
27
+ cleanupOutdatedCaches,
28
+ createHandlerBoundToURL,
29
+ getCacheKeyForURL,
30
+ matchPrecache,
31
+ precache,
32
+ precacheAndRoute,
33
+ PrecacheController,
34
+ PrecacheRoute,
35
+ PrecacheStrategy,
36
+ };
37
+
38
+ export type * from "./precaching/types.js";
@@ -0,0 +1,14 @@
1
+ import type { NavigationRouteMatchOptions } from "./routing/NavigationRoute.js";
2
+ import { NavigationRoute } from "./routing/NavigationRoute.js";
3
+ import { RegExpRoute } from "./routing/RegExpRoute.js";
4
+ import { Route } from "./routing/Route.js";
5
+ import { Router } from "./routing/Router.js";
6
+ import { registerRoute } from "./routing/registerRoute.js";
7
+ import { setCatchHandler } from "./routing/setCatchHandler.js";
8
+ import { setDefaultHandler } from "./routing/setDefaultHandler.js";
9
+ import { unregisterRoute } from "./routing/unregisterRoute.js";
10
+ import type { HTTPMethod } from "./routing/utils/constants.js";
11
+
12
+ export { NavigationRoute, RegExpRoute, registerRoute, Route, Router, setCatchHandler, setDefaultHandler, unregisterRoute };
13
+
14
+ export type { HTTPMethod, NavigationRouteMatchOptions };
@@ -1,6 +1,26 @@
1
- import type { NetworkFirstOptions, NetworkOnlyOptions, StrategyOptions } from "@serwist/strategies";
2
- import { CacheFirst, CacheOnly, NetworkFirst, NetworkOnly, StaleWhileRevalidate, Strategy, StrategyHandler } from "@serwist/strategies";
1
+ import { CacheFirst } from "./strategies/CacheFirst.js";
2
+ import { CacheOnly } from "./strategies/CacheOnly.js";
3
+ import type { NetworkFirstOptions } from "./strategies/NetworkFirst.js";
4
+ import { NetworkFirst } from "./strategies/NetworkFirst.js";
5
+ import type { NetworkOnlyOptions } from "./strategies/NetworkOnly.js";
6
+ import { NetworkOnly } from "./strategies/NetworkOnly.js";
7
+ import { StaleWhileRevalidate } from "./strategies/StaleWhileRevalidate.js";
8
+ import type { StrategyOptions } from "./strategies/Strategy.js";
9
+ import { Strategy } from "./strategies/Strategy.js";
10
+ import { StrategyHandler } from "./strategies/StrategyHandler.js";
3
11
 
12
+ // See https://github.com/GoogleChrome/workbox/issues/2946
13
+ declare global {
14
+ interface FetchEvent {
15
+ // See https://github.com/GoogleChrome/workbox/issues/2974
16
+ readonly preloadResponse: Promise<any>;
17
+ }
18
+ }
19
+
20
+ /**
21
+ * There are common caching strategies that most service workers will need
22
+ * and use. This module provides simple implementations of these strategies.
23
+ */
4
24
  export { CacheFirst, CacheOnly, NetworkFirst, NetworkOnly, StaleWhileRevalidate, Strategy, StrategyHandler };
5
25
 
6
26
  export type { NetworkFirstOptions, NetworkOnlyOptions, StrategyOptions };
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { Serwist, type SerwistOptions, type SerwistInstallOptions } from "./Serwist.js";
2
- import { disableDevLogs } from "./disableDevLogs.js";
3
- import type { FallbackEntry, FallbackMatcher, FallbacksOptions } from "./fallbacks.js";
4
- import { fallbacks } from "./fallbacks.js";
5
- import { type HandlePrecachingOptions, handlePrecaching } from "./handlePrecaching.js";
6
- import { type InstallSerwistOptions, installSerwist } from "./installSerwist.js";
7
- import { registerRuntimeCaching } from "./registerRuntimeCaching.js";
8
- import type { RuntimeCaching } from "./types.js";
1
+ import { Serwist, type SerwistInstallOptions, type SerwistOptions } from "./abstractions/Serwist.js";
2
+ import { disableDevLogs } from "./abstractions/disableDevLogs.js";
3
+ import type { FallbackEntry, FallbackMatcher, FallbacksOptions } from "./abstractions/fallbacks.js";
4
+ import { fallbacks } from "./abstractions/fallbacks.js";
5
+ import { type HandlePrecachingOptions, handlePrecaching } from "./abstractions/handlePrecaching.js";
6
+ import { type InstallSerwistOptions, installSerwist } from "./abstractions/installSerwist.js";
7
+ import { registerRuntimeCaching } from "./abstractions/registerRuntimeCaching.js";
8
+ import type { RuntimeCaching } from "./abstractions/types.js";
9
9
 
10
10
  export { disableDevLogs, fallbacks, handlePrecaching, installSerwist, Serwist, registerRuntimeCaching };
11
11
  export type {
@@ -0,0 +1,39 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { FetchDidFailCallbackParam, SerwistPlugin } from "@serwist/core";
10
+
11
+ import type { QueueOptions } from "./Queue.js";
12
+ import { Queue } from "./Queue.js";
13
+
14
+ /**
15
+ * A class implementing the `fetchDidFail` lifecycle callback. This makes it
16
+ * easier to add failed requests to a background sync Queue.
17
+ */
18
+ export class BackgroundSyncPlugin implements SerwistPlugin {
19
+ private readonly _queue: Queue;
20
+
21
+ /**
22
+ * @param name See the `@serwist/sw/plugins.BackgroundSyncQueue`
23
+ * documentation for parameter details.
24
+ * @param options See the `@serwist/sw/plugins.BackgroundSyncQueue`
25
+ * documentation for parameter details.
26
+ * @see https://serwist.pages.dev/docs/background-sync/queue
27
+ */
28
+ constructor(name: string, options?: QueueOptions) {
29
+ this._queue = new Queue(name, options);
30
+ }
31
+
32
+ /**
33
+ * @param options
34
+ * @private
35
+ */
36
+ async fetchDidFail({ request }: FetchDidFailCallbackParam) {
37
+ await this._queue.pushRequest({ request });
38
+ }
39
+ }
@@ -0,0 +1,438 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+ import { assert, SerwistError, getFriendlyURL, logger } from "@serwist/core/internal";
9
+
10
+ import type { QueueStoreEntry, UnidentifiedQueueStoreEntry } from "./QueueDb.js";
11
+ import { QueueStore } from "./QueueStore.js";
12
+ import { StorableRequest } from "./StorableRequest.js";
13
+
14
+ // Give TypeScript the correct global.
15
+ declare let self: ServiceWorkerGlobalScope;
16
+
17
+ interface OnSyncCallbackOptions {
18
+ queue: Queue;
19
+ }
20
+
21
+ type OnSyncCallback = (options: OnSyncCallbackOptions) => void | Promise<void>;
22
+
23
+ export interface QueueOptions {
24
+ /**
25
+ * If `true`, instead of attempting to use background sync events, always attempt
26
+ * to replay queued request at service worker startup. Most folks will not need
27
+ * this, unless you explicitly target a runtime like Electron that exposes the
28
+ * interfaces for background sync, but does not have a working implementation.
29
+ *
30
+ * @default false
31
+ */
32
+ forceSyncFallback?: boolean;
33
+ /**
34
+ * The amount of time (in minutes) a request may be retried. After this amount
35
+ * of time has passed, the request will be deleted from the queue.
36
+ *
37
+ * @default 60 * 24 * 7
38
+ */
39
+ maxRetentionTime?: number;
40
+ /**
41
+ * A function that gets invoked whenever the 'sync' event fires. The function
42
+ * is invoked with an object containing the `queue` property (referencing this
43
+ * instance), and you can use the callback to customize the replay behavior of
44
+ * the queue. When not set the `replayRequests()` method is called. Note: if the
45
+ * replay fails after a sync event, make sure you throw an error, so the browser
46
+ * knows to retry the sync event later.
47
+ */
48
+ onSync?: OnSyncCallback;
49
+ }
50
+
51
+ export interface QueueEntry {
52
+ /**
53
+ * The request to store in the queue.
54
+ */
55
+ request: Request;
56
+ /**
57
+ * The timestamp (Epoch time in milliseconds) when the request was first added
58
+ * to the queue. This is used along with `maxRetentionTime` to remove outdated
59
+ * requests. In general you don't need to set this value, as it's automatically
60
+ * set for you (defaulting to `Date.now()`), but you can update it if you don't
61
+ * want particular requests to expire.
62
+ */
63
+ timestamp?: number;
64
+ /**
65
+ * Any metadata you want associated with the stored request. When requests are
66
+ * replayed you'll have access to this metadata object in case you need to modify
67
+ * the request beforehand.
68
+ */
69
+ metadata?: Record<string, unknown>;
70
+ }
71
+
72
+ const TAG_PREFIX = "serwist-background-sync";
73
+ const MAX_RETENTION_TIME = 60 * 24 * 7; // 7 days in minutes
74
+
75
+ const queueNames = new Set<string>();
76
+
77
+ /**
78
+ * Converts a QueueStore entry into the format exposed by Queue. This entails
79
+ * converting the request data into a real request and omitting the `id` and
80
+ * `queueName` properties.
81
+ *
82
+ * @param queueStoreEntry
83
+ * @returns
84
+ * @private
85
+ */
86
+ const convertEntry = (queueStoreEntry: UnidentifiedQueueStoreEntry): QueueEntry => {
87
+ const queueEntry: QueueEntry = {
88
+ request: new StorableRequest(queueStoreEntry.requestData).toRequest(),
89
+ timestamp: queueStoreEntry.timestamp,
90
+ };
91
+ if (queueStoreEntry.metadata) {
92
+ queueEntry.metadata = queueStoreEntry.metadata;
93
+ }
94
+ return queueEntry;
95
+ };
96
+
97
+ /**
98
+ * A class to manage storing failed requests in IndexedDB and retrying them
99
+ * later. All parts of the storing and replaying process are observable via
100
+ * callbacks.
101
+ */
102
+ export class Queue {
103
+ private readonly _name: string;
104
+ private readonly _onSync: OnSyncCallback;
105
+ private readonly _maxRetentionTime: number;
106
+ private readonly _queueStore: QueueStore;
107
+ private readonly _forceSyncFallback: boolean;
108
+ private _syncInProgress = false;
109
+ private _requestsAddedDuringSync = false;
110
+
111
+ /**
112
+ * Creates an instance of Queue with the given options
113
+ *
114
+ * @param name The unique name for this queue. This name must be
115
+ * unique as it's used to register sync events and store requests
116
+ * in IndexedDB specific to this instance. An error will be thrown if
117
+ * a duplicate name is detected.
118
+ * @param options
119
+ */
120
+ constructor(name: string, { forceSyncFallback, onSync, maxRetentionTime }: QueueOptions = {}) {
121
+ // Ensure the store name is not already being used
122
+ if (queueNames.has(name)) {
123
+ throw new SerwistError("duplicate-queue-name", { name });
124
+ }
125
+ queueNames.add(name);
126
+
127
+ this._name = name;
128
+ this._onSync = onSync || this.replayRequests;
129
+ this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME;
130
+ this._forceSyncFallback = Boolean(forceSyncFallback);
131
+ this._queueStore = new QueueStore(this._name);
132
+
133
+ this._addSyncListener();
134
+ }
135
+
136
+ /**
137
+ * @returns
138
+ */
139
+ get name(): string {
140
+ return this._name;
141
+ }
142
+
143
+ /**
144
+ * Stores the passed request in IndexedDB (with its timestamp and any
145
+ * metadata) at the end of the queue.
146
+ *
147
+ * @param entry
148
+ */
149
+ async pushRequest(entry: QueueEntry): Promise<void> {
150
+ if (process.env.NODE_ENV !== "production") {
151
+ assert!.isType(entry, "object", {
152
+ moduleName: "@serwist/sw/plugins",
153
+ className: "BackgroundSyncQueue",
154
+ funcName: "pushRequest",
155
+ paramName: "entry",
156
+ });
157
+ assert!.isInstance(entry.request, Request, {
158
+ moduleName: "@serwist/sw/plugins",
159
+ className: "BackgroundSyncQueue",
160
+ funcName: "pushRequest",
161
+ paramName: "entry.request",
162
+ });
163
+ }
164
+
165
+ await this._addRequest(entry, "push");
166
+ }
167
+
168
+ /**
169
+ * Stores the passed request in IndexedDB (with its timestamp and any
170
+ * metadata) at the beginning of the queue.
171
+ *
172
+ * @param entry
173
+ */
174
+ async unshiftRequest(entry: QueueEntry): Promise<void> {
175
+ if (process.env.NODE_ENV !== "production") {
176
+ assert!.isType(entry, "object", {
177
+ moduleName: "@serwist/sw/plugins",
178
+ className: "BackgroundSyncQueue",
179
+ funcName: "unshiftRequest",
180
+ paramName: "entry",
181
+ });
182
+ assert!.isInstance(entry.request, Request, {
183
+ moduleName: "@serwist/sw/plugins",
184
+ className: "BackgroundSyncQueue",
185
+ funcName: "unshiftRequest",
186
+ paramName: "entry.request",
187
+ });
188
+ }
189
+
190
+ await this._addRequest(entry, "unshift");
191
+ }
192
+
193
+ /**
194
+ * Removes and returns the last request in the queue (along with its
195
+ * timestamp and any metadata).
196
+ *
197
+ * @returns
198
+ */
199
+ async popRequest(): Promise<QueueEntry | undefined> {
200
+ return this._removeRequest("pop");
201
+ }
202
+
203
+ /**
204
+ * Removes and returns the first request in the queue (along with its
205
+ * timestamp and any metadata).
206
+ *
207
+ * @returns
208
+ */
209
+ async shiftRequest(): Promise<QueueEntry | undefined> {
210
+ return this._removeRequest("shift");
211
+ }
212
+
213
+ /**
214
+ * Returns all the entries that have not expired (per `maxRetentionTime`).
215
+ * Any expired entries are removed from the queue.
216
+ *
217
+ * @returns
218
+ */
219
+ async getAll(): Promise<QueueEntry[]> {
220
+ const allEntries = await this._queueStore.getAll();
221
+ const now = Date.now();
222
+
223
+ const unexpiredEntries = [];
224
+ for (const entry of allEntries) {
225
+ // Ignore requests older than maxRetentionTime. Call this function
226
+ // recursively until an unexpired request is found.
227
+ const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
228
+ if (now - entry.timestamp > maxRetentionTimeInMs) {
229
+ await this._queueStore.deleteEntry(entry.id);
230
+ } else {
231
+ unexpiredEntries.push(convertEntry(entry));
232
+ }
233
+ }
234
+
235
+ return unexpiredEntries;
236
+ }
237
+
238
+ /**
239
+ * Returns the number of entries present in the queue.
240
+ * Note that expired entries (per `maxRetentionTime`) are also included in this count.
241
+ *
242
+ * @returns
243
+ */
244
+ async size(): Promise<number> {
245
+ return await this._queueStore.size();
246
+ }
247
+
248
+ /**
249
+ * Adds the entry to the QueueStore and registers for a sync event.
250
+ *
251
+ * @param entry
252
+ * @param operation
253
+ * @private
254
+ */
255
+ async _addRequest({ request, metadata, timestamp = Date.now() }: QueueEntry, operation: "push" | "unshift"): Promise<void> {
256
+ const storableRequest = await StorableRequest.fromRequest(request.clone());
257
+ const entry: UnidentifiedQueueStoreEntry = {
258
+ requestData: storableRequest.toObject(),
259
+ timestamp,
260
+ };
261
+
262
+ // Only include metadata if it's present.
263
+ if (metadata) {
264
+ entry.metadata = metadata;
265
+ }
266
+
267
+ switch (operation) {
268
+ case "push":
269
+ await this._queueStore.pushEntry(entry);
270
+ break;
271
+ case "unshift":
272
+ await this._queueStore.unshiftEntry(entry);
273
+ break;
274
+ }
275
+
276
+ if (process.env.NODE_ENV !== "production") {
277
+ logger.log(`Request for '${getFriendlyURL(request.url)}' has ` + `been added to background sync queue '${this._name}'.`);
278
+ }
279
+
280
+ // Don't register for a sync if we're in the middle of a sync. Instead,
281
+ // we wait until the sync is complete and call register if
282
+ // `this._requestsAddedDuringSync` is true.
283
+ if (this._syncInProgress) {
284
+ this._requestsAddedDuringSync = true;
285
+ } else {
286
+ await this.registerSync();
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Removes and returns the first or last (depending on `operation`) entry
292
+ * from the QueueStore that's not older than the `maxRetentionTime`.
293
+ *
294
+ * @param operation
295
+ * @returns
296
+ * @private
297
+ */
298
+ async _removeRequest(operation: "pop" | "shift"): Promise<QueueEntry | undefined> {
299
+ const now = Date.now();
300
+ let entry: QueueStoreEntry | undefined;
301
+ switch (operation) {
302
+ case "pop":
303
+ entry = await this._queueStore.popEntry();
304
+ break;
305
+ case "shift":
306
+ entry = await this._queueStore.shiftEntry();
307
+ break;
308
+ }
309
+
310
+ if (entry) {
311
+ // Ignore requests older than maxRetentionTime. Call this function
312
+ // recursively until an unexpired request is found.
313
+ const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
314
+ if (now - entry.timestamp > maxRetentionTimeInMs) {
315
+ return this._removeRequest(operation);
316
+ }
317
+
318
+ return convertEntry(entry);
319
+ }
320
+
321
+ return undefined;
322
+ }
323
+
324
+ /**
325
+ * Loops through each request in the queue and attempts to re-fetch it.
326
+ * If any request fails to re-fetch, it's put back in the same position in
327
+ * the queue (which registers a retry for the next sync event).
328
+ */
329
+ async replayRequests(): Promise<void> {
330
+ let entry: QueueEntry | undefined = undefined;
331
+ while ((entry = await this.shiftRequest())) {
332
+ try {
333
+ await fetch(entry.request.clone());
334
+
335
+ if (process.env.NODE_ENV !== "production") {
336
+ logger.log(`Request for '${getFriendlyURL(entry.request.url)}' ` + `has been replayed in queue '${this._name}'`);
337
+ }
338
+ } catch (error) {
339
+ await this.unshiftRequest(entry);
340
+
341
+ if (process.env.NODE_ENV !== "production") {
342
+ logger.log(`Request for '${getFriendlyURL(entry.request.url)}' ` + `failed to replay, putting it back in queue '${this._name}'`);
343
+ }
344
+ throw new SerwistError("queue-replay-failed", { name: this._name });
345
+ }
346
+ }
347
+ if (process.env.NODE_ENV !== "production") {
348
+ logger.log(`All requests in queue '${this.name}' have successfully replayed; the queue is now empty!`);
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Registers a sync event with a tag unique to this instance.
354
+ */
355
+ async registerSync(): Promise<void> {
356
+ // See https://github.com/GoogleChrome/workbox/issues/2393
357
+ if ("sync" in self.registration && !this._forceSyncFallback) {
358
+ try {
359
+ await self.registration.sync.register(`${TAG_PREFIX}:${this._name}`);
360
+ } catch (err) {
361
+ // This means the registration failed for some reason, possibly due to
362
+ // the user disabling it.
363
+ if (process.env.NODE_ENV !== "production") {
364
+ logger.warn(`Unable to register sync event for '${this._name}'.`, err);
365
+ }
366
+ }
367
+ }
368
+ }
369
+
370
+ /**
371
+ * In sync-supporting browsers, this adds a listener for the sync event.
372
+ * In non-sync-supporting browsers, or if _forceSyncFallback is true, this
373
+ * will retry the queue on service worker startup.
374
+ *
375
+ * @private
376
+ */
377
+ private _addSyncListener() {
378
+ // See https://github.com/GoogleChrome/workbox/issues/2393
379
+ if ("sync" in self.registration && !this._forceSyncFallback) {
380
+ self.addEventListener("sync", (event: SyncEvent) => {
381
+ if (event.tag === `${TAG_PREFIX}:${this._name}`) {
382
+ if (process.env.NODE_ENV !== "production") {
383
+ logger.log(`Background sync for tag '${event.tag}' has been received`);
384
+ }
385
+
386
+ const syncComplete = async () => {
387
+ this._syncInProgress = true;
388
+
389
+ let syncError: Error | undefined = undefined;
390
+ try {
391
+ await this._onSync({ queue: this });
392
+ } catch (error) {
393
+ if (error instanceof Error) {
394
+ syncError = error;
395
+
396
+ // Rethrow the error. Note: the logic in the finally clause
397
+ // will run before this gets rethrown.
398
+ throw syncError;
399
+ }
400
+ } finally {
401
+ // New items may have been added to the queue during the sync,
402
+ // so we need to register for a new sync if that's happened...
403
+ // Unless there was an error during the sync, in which
404
+ // case the browser will automatically retry later, as long
405
+ // as `event.lastChance` is not true.
406
+ if (this._requestsAddedDuringSync && !(syncError && !event.lastChance)) {
407
+ await this.registerSync();
408
+ }
409
+
410
+ this._syncInProgress = false;
411
+ this._requestsAddedDuringSync = false;
412
+ }
413
+ };
414
+ event.waitUntil(syncComplete());
415
+ }
416
+ });
417
+ } else {
418
+ if (process.env.NODE_ENV !== "production") {
419
+ logger.log("Background sync replaying without background sync event");
420
+ }
421
+ // If the browser doesn't support background sync, or the developer has
422
+ // opted-in to not using it, retry every time the service worker starts up
423
+ // as a fallback.
424
+ void this._onSync({ queue: this });
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Returns the set of queue names. This is primarily used to reset the list
430
+ * of queue names in tests.
431
+ *
432
+ * @returns
433
+ * @private
434
+ */
435
+ static get _queueNames(): Set<string> {
436
+ return queueNames;
437
+ }
438
+ }