@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,432 @@
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 { RouteHandler, RouteHandlerCallbackOptions, RouteHandlerObject, RouteMatchCallbackOptions } from "@serwist/core";
10
+ import { assert, SerwistError, getFriendlyURL, logger } from "@serwist/core/internal";
11
+
12
+ import type { Route } from "./Route.js";
13
+ import type { HTTPMethod } from "./utils/constants.js";
14
+ import { defaultMethod } from "./utils/constants.js";
15
+ import { normalizeHandler } from "./utils/normalizeHandler.js";
16
+
17
+ declare const self: ServiceWorkerGlobalScope;
18
+
19
+ type RequestArgs = string | [string, RequestInit?];
20
+
21
+ interface CacheURLsMessageData {
22
+ type: string;
23
+ payload: {
24
+ urlsToCache: RequestArgs[];
25
+ };
26
+ }
27
+
28
+ /**
29
+ * The Router can be used to process a `FetchEvent` using one or more `@serwist/routing` Route(s),
30
+ * responding with a `Response` if a matching route exists.
31
+ *
32
+ * If no route matches a given a request, the Router will use a "default" handler if one is defined.
33
+ *
34
+ * Should the matching Route throw an error, the Router will use a "catch" handler if one is defined to
35
+ * gracefully deal with issues and respond with a Request.
36
+ *
37
+ * If a request matches multiple routes, the **earliest** registered route will
38
+ * be used to respond to the request.
39
+ */
40
+ export class Router {
41
+ private readonly _routes: Map<HTTPMethod, Route[]>;
42
+ private readonly _defaultHandlerMap: Map<HTTPMethod, RouteHandlerObject>;
43
+ private _catchHandler?: RouteHandlerObject;
44
+
45
+ /**
46
+ * Initializes a new Router.
47
+ */
48
+ constructor() {
49
+ this._routes = new Map();
50
+ this._defaultHandlerMap = new Map();
51
+ }
52
+
53
+ /**
54
+ * @returns routes A `Map` of HTTP method name ('GET', etc.) to an array of all the corresponding `Route`
55
+ * instances that are registered.
56
+ */
57
+ get routes(): Map<HTTPMethod, Route[]> {
58
+ return this._routes;
59
+ }
60
+
61
+ /**
62
+ * Adds a fetch event listener to respond to events when a route matches
63
+ * the event's request.
64
+ */
65
+ addFetchListener(): void {
66
+ self.addEventListener("fetch", (event) => {
67
+ const { request } = event;
68
+ const responsePromise = this.handleRequest({ request, event });
69
+ if (responsePromise) {
70
+ event.respondWith(responsePromise);
71
+ }
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Adds a message event listener for URLs to cache from the window.
77
+ * This is useful to cache resources loaded on the page prior to when the
78
+ * service worker started controlling it.
79
+ *
80
+ * The format of the message data sent from the window should be as follows.
81
+ * Where the `urlsToCache` array may consist of URL strings or an array of
82
+ * URL string + `requestInit` object (the same as you'd pass to `fetch()`).
83
+ *
84
+ * ```
85
+ * {
86
+ * type: 'CACHE_URLS',
87
+ * payload: {
88
+ * urlsToCache: [
89
+ * './script1.js',
90
+ * './script2.js',
91
+ * ['./script3.js', {mode: 'no-cors'}],
92
+ * ],
93
+ * },
94
+ * }
95
+ * ```
96
+ */
97
+ addCacheListener(): void {
98
+ self.addEventListener("message", (event) => {
99
+ if (event.data && event.data.type === "CACHE_URLS") {
100
+ const { payload }: CacheURLsMessageData = event.data;
101
+
102
+ if (process.env.NODE_ENV !== "production") {
103
+ logger.debug("Caching URLs from the window", payload.urlsToCache);
104
+ }
105
+
106
+ const requestPromises = Promise.all(
107
+ payload.urlsToCache.map((entry: string | [string, RequestInit?]) => {
108
+ if (typeof entry === "string") {
109
+ entry = [entry];
110
+ }
111
+
112
+ const request = new Request(...entry);
113
+ return this.handleRequest({ request, event });
114
+ }),
115
+ );
116
+
117
+ event.waitUntil(requestPromises);
118
+
119
+ // If a MessageChannel was used, reply to the message on success.
120
+ if (event.ports?.[0]) {
121
+ void requestPromises.then(() => event.ports[0].postMessage(true));
122
+ }
123
+ }
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Apply the routing rules to a FetchEvent object to get a Response from an
129
+ * appropriate Route's handler.
130
+ *
131
+ * @param options
132
+ * @returns A promise is returned if a registered route can handle the request.
133
+ * If there is no matching route and there's no `defaultHandler`, `undefined`
134
+ * is returned.
135
+ */
136
+ handleRequest({
137
+ request,
138
+ event,
139
+ }: {
140
+ /**
141
+ * The request to handle.
142
+ */
143
+ request: Request;
144
+ /**
145
+ * The event that triggered the request.
146
+ */
147
+ event: ExtendableEvent;
148
+ }): Promise<Response> | undefined {
149
+ if (process.env.NODE_ENV !== "production") {
150
+ assert!.isInstance(request, Request, {
151
+ moduleName: "@serwist/routing",
152
+ className: "Router",
153
+ funcName: "handleRequest",
154
+ paramName: "options.request",
155
+ });
156
+ }
157
+
158
+ const url = new URL(request.url, location.href);
159
+ if (!url.protocol.startsWith("http")) {
160
+ if (process.env.NODE_ENV !== "production") {
161
+ logger.debug("The Serwist router only supports URLs that start with 'http'.");
162
+ }
163
+ return;
164
+ }
165
+
166
+ const sameOrigin = url.origin === location.origin;
167
+ const { params, route } = this.findMatchingRoute({
168
+ event,
169
+ request,
170
+ sameOrigin,
171
+ url,
172
+ });
173
+ let handler = route?.handler;
174
+
175
+ const debugMessages = [];
176
+ if (process.env.NODE_ENV !== "production") {
177
+ if (handler) {
178
+ debugMessages.push(["Found a route to handle this request:", route]);
179
+
180
+ if (params) {
181
+ debugMessages.push([`Passing the following params to the route's handler:`, params]);
182
+ }
183
+ }
184
+ }
185
+
186
+ // If we don't have a handler because there was no matching route, then
187
+ // fall back to defaultHandler if that's defined.
188
+ const method = request.method as HTTPMethod;
189
+ if (!handler && this._defaultHandlerMap.has(method)) {
190
+ if (process.env.NODE_ENV !== "production") {
191
+ debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);
192
+ }
193
+ handler = this._defaultHandlerMap.get(method);
194
+ }
195
+
196
+ if (!handler) {
197
+ if (process.env.NODE_ENV !== "production") {
198
+ // No handler so Serwist will do nothing. If logs is set of debug
199
+ // i.e. verbose, we should print out this information.
200
+ logger.debug(`No route found for: ${getFriendlyURL(url)}`);
201
+ }
202
+ return;
203
+ }
204
+
205
+ if (process.env.NODE_ENV !== "production") {
206
+ // We have a handler, meaning Serwist is going to handle the route.
207
+ // print the routing details to the console.
208
+ logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
209
+
210
+ for (const msg of debugMessages) {
211
+ if (Array.isArray(msg)) {
212
+ logger.log(...msg);
213
+ } else {
214
+ logger.log(msg);
215
+ }
216
+ }
217
+
218
+ logger.groupEnd();
219
+ }
220
+
221
+ // Wrap in try and catch in case the handle method throws a synchronous
222
+ // error. It should still callback to the catch handler.
223
+ let responsePromise: Promise<Response>;
224
+ try {
225
+ responsePromise = handler.handle({ url, request, event, params });
226
+ } catch (err) {
227
+ responsePromise = Promise.reject(err);
228
+ }
229
+
230
+ // Get route's catch handler, if it exists
231
+ const catchHandler = route?.catchHandler;
232
+
233
+ if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
234
+ responsePromise = responsePromise.catch(async (err) => {
235
+ // If there's a route catch handler, process that first
236
+ if (catchHandler) {
237
+ if (process.env.NODE_ENV !== "production") {
238
+ // Still include URL here as it will be async from the console group
239
+ // and may not make sense without the URL
240
+ logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
241
+ logger.error("Error thrown by:", route);
242
+ logger.error(err);
243
+ logger.groupEnd();
244
+ }
245
+
246
+ try {
247
+ return await catchHandler.handle({ url, request, event, params });
248
+ } catch (catchErr) {
249
+ if (catchErr instanceof Error) {
250
+ err = catchErr;
251
+ }
252
+ }
253
+ }
254
+
255
+ if (this._catchHandler) {
256
+ if (process.env.NODE_ENV !== "production") {
257
+ // Still include URL here as it will be async from the console group
258
+ // and may not make sense without the URL
259
+ logger.groupCollapsed(`Error thrown when responding to: ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
260
+ logger.error("Error thrown by:", route);
261
+ logger.error(err);
262
+ logger.groupEnd();
263
+ }
264
+ return this._catchHandler.handle({ url, request, event });
265
+ }
266
+
267
+ throw err;
268
+ });
269
+ }
270
+
271
+ return responsePromise;
272
+ }
273
+
274
+ /**
275
+ * Checks a request and URL (and optionally an event) against the list of
276
+ * registered routes, and if there's a match, returns the corresponding
277
+ * route along with any params generated by the match.
278
+ *
279
+ * @param options
280
+ * @returns An object with `route` and `params` properties. They are populated
281
+ * if a matching route was found or `undefined` otherwise.
282
+ */
283
+ findMatchingRoute({ url, sameOrigin, request, event }: RouteMatchCallbackOptions): {
284
+ route?: Route;
285
+ params?: RouteHandlerCallbackOptions["params"];
286
+ } {
287
+ const routes = this._routes.get(request.method as HTTPMethod) || [];
288
+ for (const route of routes) {
289
+ let params: Promise<any> | undefined;
290
+ // route.match returns type any, not possible to change right now.
291
+ const matchResult = route.match({ url, sameOrigin, request, event });
292
+ if (matchResult) {
293
+ if (process.env.NODE_ENV !== "production") {
294
+ // Warn developers that using an async matchCallback is almost always
295
+ // not the right thing to do.
296
+ if (matchResult instanceof Promise) {
297
+ logger.warn(
298
+ `While routing ${getFriendlyURL(
299
+ url,
300
+ )}, an async matchCallback function was used. Please convert the following route to use a synchronous matchCallback function:`,
301
+ route,
302
+ );
303
+ }
304
+ }
305
+
306
+ // See https://github.com/GoogleChrome/workbox/issues/2079
307
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
308
+ params = matchResult;
309
+ if (Array.isArray(params) && params.length === 0) {
310
+ // Instead of passing an empty array in as params, use undefined.
311
+ params = undefined;
312
+ } else if (
313
+ matchResult.constructor === Object && // eslint-disable-line
314
+ Object.keys(matchResult).length === 0
315
+ ) {
316
+ // Instead of passing an empty object in as params, use undefined.
317
+ params = undefined;
318
+ } else if (typeof matchResult === "boolean") {
319
+ // For the boolean value true (rather than just something truth-y),
320
+ // don't set params.
321
+ // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353
322
+ params = undefined;
323
+ }
324
+
325
+ // Return early if have a match.
326
+ return { route, params };
327
+ }
328
+ }
329
+ // If no match was found above, return and empty object.
330
+ return {};
331
+ }
332
+
333
+ /**
334
+ * Define a default `handler` that's called when no routes explicitly
335
+ * match the incoming request.
336
+ *
337
+ * Each HTTP method ('GET', 'POST', etc.) gets its own default handler.
338
+ *
339
+ * Without a default handler, unmatched requests will go against the
340
+ * network as if there were no service worker present.
341
+ *
342
+ * @param handler A callback function that returns a Promise resulting in a Response.
343
+ * @param method The HTTP method to associate with this default handler. Each method
344
+ * has its own default. Defaults to GET.
345
+ */
346
+ setDefaultHandler(handler: RouteHandler, method: HTTPMethod = defaultMethod): void {
347
+ this._defaultHandlerMap.set(method, normalizeHandler(handler));
348
+ }
349
+
350
+ /**
351
+ * If a Route throws an error while handling a request, this `handler`
352
+ * will be called and given a chance to provide a response.
353
+ *
354
+ * @param handler A callback function that returns a Promise resulting
355
+ * in a Response.
356
+ */
357
+ setCatchHandler(handler: RouteHandler): void {
358
+ this._catchHandler = normalizeHandler(handler);
359
+ }
360
+
361
+ /**
362
+ * Registers a route with the router.
363
+ *
364
+ * @param route The route to register.
365
+ */
366
+ registerRoute(route: Route): void {
367
+ if (process.env.NODE_ENV !== "production") {
368
+ assert!.isType(route, "object", {
369
+ moduleName: "@serwist/routing",
370
+ className: "Router",
371
+ funcName: "registerRoute",
372
+ paramName: "route",
373
+ });
374
+
375
+ assert!.hasMethod(route, "match", {
376
+ moduleName: "@serwist/routing",
377
+ className: "Router",
378
+ funcName: "registerRoute",
379
+ paramName: "route",
380
+ });
381
+
382
+ assert!.isType(route.handler, "object", {
383
+ moduleName: "@serwist/routing",
384
+ className: "Router",
385
+ funcName: "registerRoute",
386
+ paramName: "route",
387
+ });
388
+
389
+ assert!.hasMethod(route.handler, "handle", {
390
+ moduleName: "@serwist/routing",
391
+ className: "Router",
392
+ funcName: "registerRoute",
393
+ paramName: "route.handler",
394
+ });
395
+
396
+ assert!.isType(route.method, "string", {
397
+ moduleName: "@serwist/routing",
398
+ className: "Router",
399
+ funcName: "registerRoute",
400
+ paramName: "route.method",
401
+ });
402
+ }
403
+
404
+ if (!this._routes.has(route.method)) {
405
+ this._routes.set(route.method, []);
406
+ }
407
+
408
+ // Give precedence to all of the earlier routes by adding this additional
409
+ // route to the end of the array.
410
+ this._routes.get(route.method)!.push(route);
411
+ }
412
+
413
+ /**
414
+ * Unregisters a route with the router.
415
+ *
416
+ * @param route The route to unregister.
417
+ */
418
+ unregisterRoute(route: Route): void {
419
+ if (!this._routes.has(route.method)) {
420
+ throw new SerwistError("unregister-route-but-not-found-with-method", {
421
+ method: route.method,
422
+ });
423
+ }
424
+
425
+ const routeIndex = this._routes.get(route.method)!.indexOf(route);
426
+ if (routeIndex > -1) {
427
+ this._routes.get(route.method)!.splice(routeIndex, 1);
428
+ } else {
429
+ throw new SerwistError("unregister-route-route-not-registered");
430
+ }
431
+ }
432
+ }
@@ -0,0 +1,33 @@
1
+ /*
2
+ Copyright 2019 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 { RouteHandler, RouteMatchCallback } from "@serwist/core";
10
+
11
+ import { Route } from "./Route.js";
12
+ import type { HTTPMethod } from "./utils/constants.js";
13
+ import { getOrCreateDefaultRouter } from "./utils/getOrCreateDefaultRouter.js";
14
+ import { parseRoute } from "./utils/parseRoute.js";
15
+
16
+ /**
17
+ * Registers a RegExp, string, or function with a caching
18
+ * strategy to a singleton Router instance.
19
+ *
20
+ * @param capture If the capture param is a `Route`, all other arguments will be ignored.
21
+ * @param handler A callback function that returns a Promise resulting in a Response.
22
+ * This parameter is required if `capture` is not a `Route` object.
23
+ * @param method The HTTP method to match the Route against. Defaults to GET.
24
+ * @returns The generated `Route`.
25
+ */
26
+ export const registerRoute = (capture: RegExp | string | RouteMatchCallback | Route, handler?: RouteHandler, method?: HTTPMethod): Route => {
27
+ const route = parseRoute(capture, handler, method);
28
+
29
+ const defaultRouter = getOrCreateDefaultRouter();
30
+ defaultRouter.registerRoute(route);
31
+
32
+ return route;
33
+ };
@@ -0,0 +1,22 @@
1
+ /*
2
+ Copyright 2019 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 { RouteHandler } from "@serwist/core";
10
+
11
+ import { getOrCreateDefaultRouter } from "./utils/getOrCreateDefaultRouter.js";
12
+
13
+ /**
14
+ * If a Route throws an error while handling a request, this `handler`
15
+ * will be called and given a chance to provide a response.
16
+ *
17
+ * @param handler A callback function that returns a Promise resulting in a Response.
18
+ */
19
+ export const setCatchHandler = (handler: RouteHandler): void => {
20
+ const defaultRouter = getOrCreateDefaultRouter();
21
+ defaultRouter.setCatchHandler(handler);
22
+ };
@@ -0,0 +1,25 @@
1
+ /*
2
+ Copyright 2019 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 { RouteHandler } from "@serwist/core";
10
+
11
+ import { getOrCreateDefaultRouter } from "./utils/getOrCreateDefaultRouter.js";
12
+
13
+ /**
14
+ * Defines a default `handler` that's called when no routes explicitly
15
+ * match the incoming request.
16
+ *
17
+ * Without a default handler, unmatched requests will go against the
18
+ * network as if there were no service worker present.
19
+ *
20
+ * @param handler A callback function that returns a Promise resulting in a Response.
21
+ */
22
+ export const setDefaultHandler = (handler: RouteHandler): void => {
23
+ const defaultRouter = getOrCreateDefaultRouter();
24
+ defaultRouter.setDefaultHandler(handler);
25
+ };
@@ -0,0 +1,12 @@
1
+ import type { Route } from "./Route.js";
2
+ import { getOrCreateDefaultRouter } from "./utils/getOrCreateDefaultRouter.js";
3
+
4
+ /**
5
+ * Unregisters a route from the singleton Router instance.
6
+ *
7
+ * @param route The route to unregister.
8
+ */
9
+ export const unregisterRoute = (route: Route): void => {
10
+ const defaultRouter = getOrCreateDefaultRouter();
11
+ defaultRouter.unregisterRoute(route);
12
+ };
@@ -0,0 +1,24 @@
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
+ export type HTTPMethod = "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT";
10
+
11
+ /**
12
+ * The default HTTP method, 'GET', used when there's no specific method
13
+ * configured for a route.
14
+ *
15
+ * @private
16
+ */
17
+ export const defaultMethod = "GET" satisfies HTTPMethod;
18
+
19
+ /**
20
+ * The list of valid HTTP methods associated with requests that could be routed.
21
+ *
22
+ * @private
23
+ */
24
+ export const validMethods = ["DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"] satisfies HTTPMethod[];
@@ -0,0 +1,29 @@
1
+ /*
2
+ Copyright 2019 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 { Router } from "../Router.js";
10
+
11
+ let defaultRouter: Router;
12
+
13
+ /**
14
+ * Creates a new, singleton Router instance if one does not exist. If one
15
+ * does already exist, that instance is returned.
16
+ *
17
+ * @private
18
+ * @returns
19
+ */
20
+ export const getOrCreateDefaultRouter = (): Router => {
21
+ if (!defaultRouter) {
22
+ defaultRouter = new Router();
23
+
24
+ // The helpers that use the default Router assume these listeners exist.
25
+ defaultRouter.addFetchListener();
26
+ defaultRouter.addCacheListener();
27
+ }
28
+ return defaultRouter;
29
+ };
@@ -0,0 +1,40 @@
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 { RouteHandler, RouteHandlerObject } from "@serwist/core";
10
+ import { assert } from "@serwist/core/internal";
11
+
12
+ /**
13
+ * @param handler Either a function, or an object with a
14
+ * 'handle' method.
15
+ * @returns An object with a handle method.
16
+ *
17
+ * @private
18
+ */
19
+ export const normalizeHandler = (handler: RouteHandler): RouteHandlerObject => {
20
+ if (handler && typeof handler === "object") {
21
+ if (process.env.NODE_ENV !== "production") {
22
+ assert!.hasMethod(handler, "handle", {
23
+ moduleName: "@serwist/routing",
24
+ className: "Route",
25
+ funcName: "constructor",
26
+ paramName: "handler",
27
+ });
28
+ }
29
+ return handler;
30
+ }
31
+ if (process.env.NODE_ENV !== "production") {
32
+ assert!.isType(handler, "function", {
33
+ moduleName: "@serwist/routing",
34
+ className: "Route",
35
+ funcName: "constructor",
36
+ paramName: "handler",
37
+ });
38
+ }
39
+ return { handle: handler };
40
+ };
@@ -0,0 +1,67 @@
1
+ import type { RouteHandler, RouteMatchCallback } from "@serwist/core";
2
+ import { SerwistError, logger } from "@serwist/core/internal";
3
+
4
+ import { RegExpRoute } from "../RegExpRoute.js";
5
+ import { Route } from "../Route.js";
6
+ import type { HTTPMethod } from "./constants.js";
7
+
8
+ export const parseRoute = (capture: RegExp | string | RouteMatchCallback | Route, handler?: RouteHandler, method?: HTTPMethod): Route => {
9
+ let route: Route;
10
+
11
+ if (typeof capture === "string") {
12
+ const captureUrl = new URL(capture, location.href);
13
+
14
+ if (process.env.NODE_ENV !== "production") {
15
+ if (!(capture.startsWith("/") || capture.startsWith("http"))) {
16
+ throw new SerwistError("invalid-string", {
17
+ moduleName: "@serwist/routing",
18
+ funcName: "registerRoute",
19
+ paramName: "capture",
20
+ });
21
+ }
22
+
23
+ // We want to check if Express-style wildcards are in the pathname only.
24
+ // TODO: Remove this log message in v4.
25
+ const valueToCheck = capture.startsWith("http") ? captureUrl.pathname : capture;
26
+
27
+ // See https://github.com/pillarjs/path-to-regexp#parameters
28
+ const wildcards = "[*:?+]";
29
+ if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
30
+ logger.debug(
31
+ `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.`,
32
+ );
33
+ }
34
+ }
35
+
36
+ const matchCallback: RouteMatchCallback = ({ url }) => {
37
+ if (process.env.NODE_ENV !== "production") {
38
+ if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
39
+ logger.debug(
40
+ `${capture} only partially matches the cross-origin URL ${url.toString()}. This route will only handle cross-origin requests if they match the entire URL.`,
41
+ );
42
+ }
43
+ }
44
+
45
+ return url.href === captureUrl.href;
46
+ };
47
+
48
+ // If `capture` is a string then `handler` and `method` must be present.
49
+ route = new Route(matchCallback, handler!, method);
50
+ } else if (capture instanceof RegExp) {
51
+ // If `capture` is a `RegExp` then `handler` and `method` must be present.
52
+ route = new RegExpRoute(capture, handler!, method);
53
+ } else if (typeof capture === "function") {
54
+ // If `capture` is a function then `handler` and `method` must be present.
55
+ route = new Route(capture, handler!, method);
56
+ } else if (capture instanceof Route) {
57
+ route = capture;
58
+ } else {
59
+ throw new SerwistError("unsupported-route-type", {
60
+ moduleName: "@serwist/routing",
61
+ funcName: "registerRoute",
62
+ paramName: "capture",
63
+ });
64
+ }
65
+
66
+ return route;
67
+ };