@juspay/shooter 1.0.0

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 (327) hide show
  1. package/.claude/hooks/notifier.cjs +1431 -0
  2. package/.claude/settings.json +162 -0
  3. package/README.md +515 -0
  4. package/bin/shooter.cjs +141 -0
  5. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css +1 -0
  6. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.br +0 -0
  7. package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css +1 -0
  9. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.br +1 -0
  10. package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/3.C0uFg0IS.css +1 -0
  12. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.br +0 -0
  13. package/build/client/_app/immutable/assets/3.C0uFg0IS.css.gz +0 -0
  14. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +1 -0
  15. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
  16. package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
  17. package/build/client/_app/immutable/assets/5.DRjApZQW.css +1 -0
  18. package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
  19. package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
  20. package/build/client/_app/immutable/assets/6.AraZrY8I.css +1 -0
  21. package/build/client/_app/immutable/assets/6.AraZrY8I.css.br +0 -0
  22. package/build/client/_app/immutable/assets/6.AraZrY8I.css.gz +0 -0
  23. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css +1 -0
  24. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.br +0 -0
  25. package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.gz +0 -0
  26. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +1 -0
  27. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
  28. package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
  29. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css +1 -0
  30. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.br +0 -0
  31. package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.gz +0 -0
  32. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css +1 -0
  33. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.br +0 -0
  34. package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.gz +0 -0
  35. package/build/client/_app/immutable/chunks/BNJphC1q.js +56 -0
  36. package/build/client/_app/immutable/chunks/BNJphC1q.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/BNJphC1q.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/BTGVxaYV.js +9 -0
  39. package/build/client/_app/immutable/chunks/BTGVxaYV.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/BTGVxaYV.js.gz +0 -0
  41. package/build/client/_app/immutable/chunks/BlxrFPDK.js +1 -0
  42. package/build/client/_app/immutable/chunks/BlxrFPDK.js.br +0 -0
  43. package/build/client/_app/immutable/chunks/BlxrFPDK.js.gz +0 -0
  44. package/build/client/_app/immutable/chunks/Bvk7mfPM.js +1 -0
  45. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.br +0 -0
  46. package/build/client/_app/immutable/chunks/Bvk7mfPM.js.gz +0 -0
  47. package/build/client/_app/immutable/chunks/CAokzuPQ.js +1 -0
  48. package/build/client/_app/immutable/chunks/CAokzuPQ.js.br +0 -0
  49. package/build/client/_app/immutable/chunks/CAokzuPQ.js.gz +0 -0
  50. package/build/client/_app/immutable/chunks/CGLrx-H5.js +1 -0
  51. package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
  52. package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
  53. package/build/client/_app/immutable/chunks/CgCpWzEA.js +1 -0
  54. package/build/client/_app/immutable/chunks/CgCpWzEA.js.br +0 -0
  55. package/build/client/_app/immutable/chunks/CgCpWzEA.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/Cjwk_cGO.js +6 -0
  57. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/Cjwk_cGO.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/CtQ8EED1.js +11 -0
  60. package/build/client/_app/immutable/chunks/CtQ8EED1.js.br +0 -0
  61. package/build/client/_app/immutable/chunks/CtQ8EED1.js.gz +0 -0
  62. package/build/client/_app/immutable/chunks/DERQCisl.js +1 -0
  63. package/build/client/_app/immutable/chunks/DERQCisl.js.br +0 -0
  64. package/build/client/_app/immutable/chunks/DERQCisl.js.gz +0 -0
  65. package/build/client/_app/immutable/chunks/DKrg8TQs.js +1 -0
  66. package/build/client/_app/immutable/chunks/DKrg8TQs.js.br +0 -0
  67. package/build/client/_app/immutable/chunks/DKrg8TQs.js.gz +0 -0
  68. package/build/client/_app/immutable/chunks/DLu6yJIZ.js +1 -0
  69. package/build/client/_app/immutable/chunks/DLu6yJIZ.js.br +0 -0
  70. package/build/client/_app/immutable/chunks/DLu6yJIZ.js.gz +0 -0
  71. package/build/client/_app/immutable/chunks/Dkkpz_4D.js +126 -0
  72. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.br +0 -0
  73. package/build/client/_app/immutable/chunks/Dkkpz_4D.js.gz +0 -0
  74. package/build/client/_app/immutable/chunks/DoczjQhA.js +1 -0
  75. package/build/client/_app/immutable/chunks/DoczjQhA.js.br +0 -0
  76. package/build/client/_app/immutable/chunks/DoczjQhA.js.gz +0 -0
  77. package/build/client/_app/immutable/chunks/PPVm8Dsz.js +1 -0
  78. package/build/client/_app/immutable/chunks/PPVm8Dsz.js.br +0 -0
  79. package/build/client/_app/immutable/chunks/PPVm8Dsz.js.gz +0 -0
  80. package/build/client/_app/immutable/chunks/RpcNruLP.js +2 -0
  81. package/build/client/_app/immutable/chunks/RpcNruLP.js.br +0 -0
  82. package/build/client/_app/immutable/chunks/RpcNruLP.js.gz +0 -0
  83. package/build/client/_app/immutable/chunks/a-St0Zwo.js +1 -0
  84. package/build/client/_app/immutable/chunks/a-St0Zwo.js.br +0 -0
  85. package/build/client/_app/immutable/chunks/a-St0Zwo.js.gz +0 -0
  86. package/build/client/_app/immutable/chunks/bo70OQUZ.js +1 -0
  87. package/build/client/_app/immutable/chunks/bo70OQUZ.js.br +0 -0
  88. package/build/client/_app/immutable/chunks/bo70OQUZ.js.gz +0 -0
  89. package/build/client/_app/immutable/entry/app.QvGgdvTI.js +2 -0
  90. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.br +0 -0
  91. package/build/client/_app/immutable/entry/app.QvGgdvTI.js.gz +0 -0
  92. package/build/client/_app/immutable/entry/start.BntDNRMC.js +1 -0
  93. package/build/client/_app/immutable/entry/start.BntDNRMC.js.br +0 -0
  94. package/build/client/_app/immutable/entry/start.BntDNRMC.js.gz +0 -0
  95. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js +1 -0
  96. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.br +0 -0
  97. package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js +1 -0
  99. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.gz +0 -0
  101. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js +1 -0
  102. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.br +0 -0
  103. package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js +3 -0
  105. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/4.D-cIe70D.js +1 -0
  108. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/4.D-cIe70D.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js +1 -0
  111. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.gz +0 -0
  113. package/build/client/_app/immutable/nodes/6.BB7QE48r.js +2 -0
  114. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.br +0 -0
  115. package/build/client/_app/immutable/nodes/6.BB7QE48r.js.gz +0 -0
  116. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js +2 -0
  117. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.br +0 -0
  118. package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.gz +0 -0
  119. package/build/client/_app/version.json +1 -0
  120. package/build/client/_app/version.json.br +0 -0
  121. package/build/client/_app/version.json.gz +0 -0
  122. package/build/client/app-icon.png +0 -0
  123. package/build/client/apple-touch-icon.png +0 -0
  124. package/build/client/favicon.png +0 -0
  125. package/build/client/favicon.svg +10 -0
  126. package/build/client/favicon.svg.br +0 -0
  127. package/build/client/favicon.svg.gz +0 -0
  128. package/build/client/manifest.webmanifest +1 -0
  129. package/build/client/pwa-192x192.png +0 -0
  130. package/build/client/pwa-512x512.png +0 -0
  131. package/build/client/registerSW.js +1 -0
  132. package/build/client/registerSW.js.br +0 -0
  133. package/build/client/registerSW.js.gz +0 -0
  134. package/build/client/sw.js +222 -0
  135. package/build/client/sw.js.br +0 -0
  136. package/build/client/sw.js.gz +0 -0
  137. package/build/client/workbox-5119daf5.js +3395 -0
  138. package/build/client/workbox-5119daf5.js.br +0 -0
  139. package/build/client/workbox-5119daf5.js.gz +0 -0
  140. package/build/env.js +94 -0
  141. package/build/handler.js +1494 -0
  142. package/build/index.js +345 -0
  143. package/build/pty-holder.cjs +510 -0
  144. package/build/server/chunks/0-q2IUp76Y.js +9 -0
  145. package/build/server/chunks/0-q2IUp76Y.js.map +1 -0
  146. package/build/server/chunks/1-CU50G5wZ.js +9 -0
  147. package/build/server/chunks/1-CU50G5wZ.js.map +1 -0
  148. package/build/server/chunks/2-D01t9s8T.js +9 -0
  149. package/build/server/chunks/2-D01t9s8T.js.map +1 -0
  150. package/build/server/chunks/3-5PUQ04wC.js +9 -0
  151. package/build/server/chunks/3-5PUQ04wC.js.map +1 -0
  152. package/build/server/chunks/4-e7gywnSG.js +9 -0
  153. package/build/server/chunks/4-e7gywnSG.js.map +1 -0
  154. package/build/server/chunks/5-CA1SA6KZ.js +9 -0
  155. package/build/server/chunks/5-CA1SA6KZ.js.map +1 -0
  156. package/build/server/chunks/6-71H221sV.js +9 -0
  157. package/build/server/chunks/6-71H221sV.js.map +1 -0
  158. package/build/server/chunks/7-Bo-vmdyz.js +9 -0
  159. package/build/server/chunks/7-Bo-vmdyz.js.map +1 -0
  160. package/build/server/chunks/_layout.svelte-SFHOxs74.js +132 -0
  161. package/build/server/chunks/_layout.svelte-SFHOxs74.js.map +1 -0
  162. package/build/server/chunks/_page.svelte-B4w-2wD-.js +120 -0
  163. package/build/server/chunks/_page.svelte-B4w-2wD-.js.map +1 -0
  164. package/build/server/chunks/_page.svelte-B_qAXjkh.js +213 -0
  165. package/build/server/chunks/_page.svelte-B_qAXjkh.js.map +1 -0
  166. package/build/server/chunks/_page.svelte-CsF1_TRG.js +50 -0
  167. package/build/server/chunks/_page.svelte-CsF1_TRG.js.map +1 -0
  168. package/build/server/chunks/_page.svelte-DJC6U-P0.js +68 -0
  169. package/build/server/chunks/_page.svelte-DJC6U-P0.js.map +1 -0
  170. package/build/server/chunks/_page.svelte-DQ6HBtsz.js +407 -0
  171. package/build/server/chunks/_page.svelte-DQ6HBtsz.js.map +1 -0
  172. package/build/server/chunks/_page.svelte-LbhhjP21.js +148 -0
  173. package/build/server/chunks/_page.svelte-LbhhjP21.js.map +1 -0
  174. package/build/server/chunks/_server.ts-BL2FGb5Z.js +387 -0
  175. package/build/server/chunks/_server.ts-BL2FGb5Z.js.map +1 -0
  176. package/build/server/chunks/_server.ts-BgdjBZco.js +47 -0
  177. package/build/server/chunks/_server.ts-BgdjBZco.js.map +1 -0
  178. package/build/server/chunks/_server.ts-BihKSdj_.js +59 -0
  179. package/build/server/chunks/_server.ts-BihKSdj_.js.map +1 -0
  180. package/build/server/chunks/_server.ts-BjOJsoy4.js +63 -0
  181. package/build/server/chunks/_server.ts-BjOJsoy4.js.map +1 -0
  182. package/build/server/chunks/_server.ts-C29xzfaw.js +77 -0
  183. package/build/server/chunks/_server.ts-C29xzfaw.js.map +1 -0
  184. package/build/server/chunks/_server.ts-CPa6DgIt.js +71 -0
  185. package/build/server/chunks/_server.ts-CPa6DgIt.js.map +1 -0
  186. package/build/server/chunks/_server.ts-CbDRDIoP.js +36 -0
  187. package/build/server/chunks/_server.ts-CbDRDIoP.js.map +1 -0
  188. package/build/server/chunks/_server.ts-Cl1OEWL4.js +54 -0
  189. package/build/server/chunks/_server.ts-Cl1OEWL4.js.map +1 -0
  190. package/build/server/chunks/_server.ts-ColfDHW8.js +60 -0
  191. package/build/server/chunks/_server.ts-ColfDHW8.js.map +1 -0
  192. package/build/server/chunks/_server.ts-Cv_OrRuL.js +494 -0
  193. package/build/server/chunks/_server.ts-Cv_OrRuL.js.map +1 -0
  194. package/build/server/chunks/_server.ts-D4MNi4cD.js +25 -0
  195. package/build/server/chunks/_server.ts-D4MNi4cD.js.map +1 -0
  196. package/build/server/chunks/_server.ts-DRVbgm6k.js +125 -0
  197. package/build/server/chunks/_server.ts-DRVbgm6k.js.map +1 -0
  198. package/build/server/chunks/_server.ts-DfajWaqh.js +39 -0
  199. package/build/server/chunks/_server.ts-DfajWaqh.js.map +1 -0
  200. package/build/server/chunks/_server.ts-y9-WYDMa.js +35 -0
  201. package/build/server/chunks/_server.ts-y9-WYDMa.js.map +1 -0
  202. package/build/server/chunks/auth-CEgFis71.js +32 -0
  203. package/build/server/chunks/auth-CEgFis71.js.map +1 -0
  204. package/build/server/chunks/client-CxCatAKr.js +255 -0
  205. package/build/server/chunks/client-CxCatAKr.js.map +1 -0
  206. package/build/server/chunks/error.svelte-BqdwMWdK.js +26 -0
  207. package/build/server/chunks/error.svelte-BqdwMWdK.js.map +1 -0
  208. package/build/server/chunks/exports-CJ0Q5XmL.js +4081 -0
  209. package/build/server/chunks/exports-CJ0Q5XmL.js.map +1 -0
  210. package/build/server/chunks/index2-DAxIoAO-.js +36 -0
  211. package/build/server/chunks/index2-DAxIoAO-.js.map +1 -0
  212. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js +137 -0
  213. package/build/server/chunks/jsonl-parser-dmZU_Hyu.js.map +1 -0
  214. package/build/server/chunks/library-apns-BHxLmuIx.js +104 -0
  215. package/build/server/chunks/library-apns-BHxLmuIx.js.map +1 -0
  216. package/build/server/chunks/markdown-Bxrl3cCF.js +1241 -0
  217. package/build/server/chunks/markdown-Bxrl3cCF.js.map +1 -0
  218. package/build/server/chunks/pending-requests-D8UiTw7L.js +44 -0
  219. package/build/server/chunks/pending-requests-D8UiTw7L.js.map +1 -0
  220. package/build/server/chunks/pty-manager-C0FhBiVq.js +1697 -0
  221. package/build/server/chunks/pty-manager-C0FhBiVq.js.map +1 -0
  222. package/build/server/chunks/shared-server-BDY8jh20.js +200 -0
  223. package/build/server/chunks/shared-server-BDY8jh20.js.map +1 -0
  224. package/build/server/chunks/stores-D0HorpgL.js +36 -0
  225. package/build/server/chunks/stores-D0HorpgL.js.map +1 -0
  226. package/build/server/index.js +6466 -0
  227. package/build/server/index.js.map +1 -0
  228. package/build/server/manifest.js +184 -0
  229. package/build/server/manifest.js.map +1 -0
  230. package/build/shims.js +32 -0
  231. package/package.json +94 -0
  232. package/scripts/clipboard-shims/wl-paste +48 -0
  233. package/scripts/clipboard-shims/xclip +31 -0
  234. package/scripts/install.sh +477 -0
  235. package/scripts/setup-node-pty.sh +63 -0
  236. package/scripts/setup.cjs +571 -0
  237. package/scripts/test-runner.ts +243 -0
  238. package/scripts/vercel-env-commands.sh +60 -0
  239. package/server.ts +139 -0
  240. package/src/app.css +1835 -0
  241. package/src/app.d.ts +31 -0
  242. package/src/app.html +24 -0
  243. package/src/generated/types/APN.ts +305 -0
  244. package/src/generated/types/CLI.ts +52 -0
  245. package/src/generated/types/JWT.ts +92 -0
  246. package/src/generated/types/Terminal.ts +2736 -0
  247. package/src/generated/types/index.ts +6 -0
  248. package/src/lib/assets/icons/alert-triangle.svg +5 -0
  249. package/src/lib/assets/icons/bell.svg +4 -0
  250. package/src/lib/assets/icons/check-circle.svg +4 -0
  251. package/src/lib/assets/icons/file.svg +4 -0
  252. package/src/lib/assets/icons/folder.svg +3 -0
  253. package/src/lib/assets/icons/play.svg +3 -0
  254. package/src/lib/assets/icons/refresh.svg +4 -0
  255. package/src/lib/assets/icons/settings.svg +4 -0
  256. package/src/lib/assets/icons/terminal.svg +1 -0
  257. package/src/lib/assets/icons/tool.svg +3 -0
  258. package/src/lib/assets/icons/x-circle.svg +5 -0
  259. package/src/lib/modules/client/common/Card.svelte +26 -0
  260. package/src/lib/modules/client/common/EmptyState.svelte +36 -0
  261. package/src/lib/modules/client/common/Icon.svelte +61 -0
  262. package/src/lib/modules/client/common/StatusBadge.svelte +38 -0
  263. package/src/lib/modules/client/common/cache.ts +31 -0
  264. package/src/lib/modules/client/common/config-guard.ts +18 -0
  265. package/src/lib/modules/client/common/index.ts +12 -0
  266. package/src/lib/modules/client/common/markdown.ts +23 -0
  267. package/src/lib/modules/client/common/native-bridge.ts +50 -0
  268. package/src/lib/modules/client/common/time.ts +22 -0
  269. package/src/lib/modules/client/common/tool-title.ts +28 -0
  270. package/src/lib/modules/client/terminal/ChatView.svelte +400 -0
  271. package/src/lib/modules/client/terminal/CommandPalette.svelte +60 -0
  272. package/src/lib/modules/client/terminal/ConnectionStatus.svelte +99 -0
  273. package/src/lib/modules/client/terminal/LaunchSheet.svelte +294 -0
  274. package/src/lib/modules/client/terminal/QuickKeys.svelte +71 -0
  275. package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +79 -0
  276. package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +70 -0
  277. package/src/lib/modules/client/terminal/xterm-wrapper.ts +243 -0
  278. package/src/lib/modules/server/apn/library-apns.ts +137 -0
  279. package/src/lib/modules/server/apn/notification-history.ts +35 -0
  280. package/src/lib/modules/server/apn/notification-sessions.ts +117 -0
  281. package/src/lib/modules/server/apn/pending-requests.ts +65 -0
  282. package/src/lib/modules/server/apn/types.ts +51 -0
  283. package/src/lib/modules/server/auth.ts +34 -0
  284. package/src/lib/modules/server/cli/index.ts +79 -0
  285. package/src/lib/modules/server/cli/runner.ts +162 -0
  286. package/src/lib/modules/server/fcm/fcm-service.ts +72 -0
  287. package/src/lib/modules/server/sessions/jsonl-parser.ts +197 -0
  288. package/src/lib/modules/server/sessions/jsonl-reader.ts +301 -0
  289. package/src/lib/modules/server/sessions/opencode-reader.ts +264 -0
  290. package/src/lib/modules/server/sessions/types.ts +53 -0
  291. package/src/lib/modules/server/terminal/holder-client.ts +273 -0
  292. package/src/lib/modules/server/terminal/opencode-watcher.ts +661 -0
  293. package/src/lib/modules/server/terminal/pty-holder.cjs +510 -0
  294. package/src/lib/modules/server/terminal/pty-manager.ts +1012 -0
  295. package/src/lib/modules/server/terminal/session-watcher.ts +320 -0
  296. package/src/lib/modules/server/terminal/terminal-store.ts +198 -0
  297. package/src/lib/modules/server/ws/events-handler.ts +73 -0
  298. package/src/lib/modules/server/ws/keepalive.ts +108 -0
  299. package/src/lib/modules/server/ws/server.ts +93 -0
  300. package/src/lib/modules/server/ws/session-handler.ts +462 -0
  301. package/src/lib/modules/server/ws/terminal-handler.ts +197 -0
  302. package/src/lib/modules/server/ws/ticket-store.ts +58 -0
  303. package/src/lib/theme.css +529 -0
  304. package/src/lib/types/config.ts +6 -0
  305. package/src/routes/+layout.svelte +218 -0
  306. package/src/routes/+page.svelte +261 -0
  307. package/src/routes/api/debug/+server.ts +33 -0
  308. package/src/routes/api/device-token/+server.ts +85 -0
  309. package/src/routes/api/health/+server.ts +100 -0
  310. package/src/routes/api/notify/+server.ts +418 -0
  311. package/src/routes/api/qr-config/+server.ts +45 -0
  312. package/src/routes/api/response/+server.ts +73 -0
  313. package/src/routes/api/sessions/+server.ts +120 -0
  314. package/src/routes/api/terminals/+server.ts +141 -0
  315. package/src/routes/api/terminals/[id]/+server.ts +75 -0
  316. package/src/routes/api/terminals/[id]/paste-image/+server.ts +61 -0
  317. package/src/routes/api/terminals/[id]/resize/+server.ts +60 -0
  318. package/src/routes/api/webhook/+server.ts +42 -0
  319. package/src/routes/api/ws-status/+server.ts +23 -0
  320. package/src/routes/api/ws-ticket/+server.ts +86 -0
  321. package/src/routes/config/+page.svelte +600 -0
  322. package/src/routes/project/+page.svelte +274 -0
  323. package/src/routes/session/[id]/+page.svelte +434 -0
  324. package/src/routes/terminals/+page.svelte +618 -0
  325. package/src/routes/terminals/[id]/+page.svelte +968 -0
  326. package/svelte.config.js +18 -0
  327. package/tsconfig.json +14 -0
@@ -0,0 +1,3395 @@
1
+ define(['exports'], (function (exports) { 'use strict';
2
+
3
+ // @ts-ignore
4
+ try {
5
+ self['workbox:core:7.3.0'] && _();
6
+ } catch (e) {}
7
+
8
+ /*
9
+ Copyright 2019 Google LLC
10
+
11
+ Use of this source code is governed by an MIT-style
12
+ license that can be found in the LICENSE file or at
13
+ https://opensource.org/licenses/MIT.
14
+ */
15
+ /**
16
+ * Claim any currently available clients once the service worker
17
+ * becomes active. This is normally used in conjunction with `skipWaiting()`.
18
+ *
19
+ * @memberof workbox-core
20
+ */
21
+ function clientsClaim() {
22
+ self.addEventListener('activate', () => self.clients.claim());
23
+ }
24
+
25
+ /*
26
+ Copyright 2019 Google LLC
27
+ Use of this source code is governed by an MIT-style
28
+ license that can be found in the LICENSE file or at
29
+ https://opensource.org/licenses/MIT.
30
+ */
31
+ const logger = (() => {
32
+ // Don't overwrite this value if it's already set.
33
+ // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923
34
+ if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) {
35
+ self.__WB_DISABLE_DEV_LOGS = false;
36
+ }
37
+ let inGroup = false;
38
+ const methodToColorMap = {
39
+ debug: `#7f8c8d`,
40
+ log: `#2ecc71`,
41
+ warn: `#f39c12`,
42
+ error: `#c0392b`,
43
+ groupCollapsed: `#3498db`,
44
+ groupEnd: null // No colored prefix on groupEnd
45
+ };
46
+ const print = function (method, args) {
47
+ if (self.__WB_DISABLE_DEV_LOGS) {
48
+ return;
49
+ }
50
+ if (method === 'groupCollapsed') {
51
+ // Safari doesn't print all console.groupCollapsed() arguments:
52
+ // https://bugs.webkit.org/show_bug.cgi?id=182754
53
+ if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
54
+ console[method](...args);
55
+ return;
56
+ }
57
+ }
58
+ const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`];
59
+ // When in a group, the workbox prefix is not displayed.
60
+ const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];
61
+ console[method](...logPrefix, ...args);
62
+ if (method === 'groupCollapsed') {
63
+ inGroup = true;
64
+ }
65
+ if (method === 'groupEnd') {
66
+ inGroup = false;
67
+ }
68
+ };
69
+ // eslint-disable-next-line @typescript-eslint/ban-types
70
+ const api = {};
71
+ const loggerMethods = Object.keys(methodToColorMap);
72
+ for (const key of loggerMethods) {
73
+ const method = key;
74
+ api[method] = (...args) => {
75
+ print(method, args);
76
+ };
77
+ }
78
+ return api;
79
+ })();
80
+
81
+ /*
82
+ Copyright 2018 Google LLC
83
+
84
+ Use of this source code is governed by an MIT-style
85
+ license that can be found in the LICENSE file or at
86
+ https://opensource.org/licenses/MIT.
87
+ */
88
+ const messages = {
89
+ 'invalid-value': ({
90
+ paramName,
91
+ validValueDescription,
92
+ value
93
+ }) => {
94
+ if (!paramName || !validValueDescription) {
95
+ throw new Error(`Unexpected input to 'invalid-value' error.`);
96
+ }
97
+ return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`;
98
+ },
99
+ 'not-an-array': ({
100
+ moduleName,
101
+ className,
102
+ funcName,
103
+ paramName
104
+ }) => {
105
+ if (!moduleName || !className || !funcName || !paramName) {
106
+ throw new Error(`Unexpected input to 'not-an-array' error.`);
107
+ }
108
+ return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`;
109
+ },
110
+ 'incorrect-type': ({
111
+ expectedType,
112
+ paramName,
113
+ moduleName,
114
+ className,
115
+ funcName
116
+ }) => {
117
+ if (!expectedType || !paramName || !moduleName || !funcName) {
118
+ throw new Error(`Unexpected input to 'incorrect-type' error.`);
119
+ }
120
+ const classNameStr = className ? `${className}.` : '';
121
+ return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}` + `${funcName}()' must be of type ${expectedType}.`;
122
+ },
123
+ 'incorrect-class': ({
124
+ expectedClassName,
125
+ paramName,
126
+ moduleName,
127
+ className,
128
+ funcName,
129
+ isReturnValueProblem
130
+ }) => {
131
+ if (!expectedClassName || !moduleName || !funcName) {
132
+ throw new Error(`Unexpected input to 'incorrect-class' error.`);
133
+ }
134
+ const classNameStr = className ? `${className}.` : '';
135
+ if (isReturnValueProblem) {
136
+ return `The return value from ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`;
137
+ }
138
+ return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`;
139
+ },
140
+ 'missing-a-method': ({
141
+ expectedMethod,
142
+ paramName,
143
+ moduleName,
144
+ className,
145
+ funcName
146
+ }) => {
147
+ if (!expectedMethod || !paramName || !moduleName || !className || !funcName) {
148
+ throw new Error(`Unexpected input to 'missing-a-method' error.`);
149
+ }
150
+ return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`;
151
+ },
152
+ 'add-to-cache-list-unexpected-type': ({
153
+ entry
154
+ }) => {
155
+ return `An unexpected entry was passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' The entry ` + `'${JSON.stringify(entry)}' isn't supported. You must supply an array of ` + `strings with one or more characters, objects with a url property or ` + `Request objects.`;
156
+ },
157
+ 'add-to-cache-list-conflicting-entries': ({
158
+ firstEntry,
159
+ secondEntry
160
+ }) => {
161
+ if (!firstEntry || !secondEntry) {
162
+ throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`);
163
+ }
164
+ return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`;
165
+ },
166
+ 'plugin-error-request-will-fetch': ({
167
+ thrownErrorMessage
168
+ }) => {
169
+ if (!thrownErrorMessage) {
170
+ throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`);
171
+ }
172
+ return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownErrorMessage}'.`;
173
+ },
174
+ 'invalid-cache-name': ({
175
+ cacheNameId,
176
+ value
177
+ }) => {
178
+ if (!cacheNameId) {
179
+ throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`);
180
+ }
181
+ return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`;
182
+ },
183
+ 'unregister-route-but-not-found-with-method': ({
184
+ method
185
+ }) => {
186
+ if (!method) {
187
+ throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`);
188
+ }
189
+ return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`;
190
+ },
191
+ 'unregister-route-route-not-registered': () => {
192
+ return `The route you're trying to unregister was not previously ` + `registered.`;
193
+ },
194
+ 'queue-replay-failed': ({
195
+ name
196
+ }) => {
197
+ return `Replaying the background sync queue '${name}' failed.`;
198
+ },
199
+ 'duplicate-queue-name': ({
200
+ name
201
+ }) => {
202
+ return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`;
203
+ },
204
+ 'expired-test-without-max-age': ({
205
+ methodName,
206
+ paramName
207
+ }) => {
208
+ return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`;
209
+ },
210
+ 'unsupported-route-type': ({
211
+ moduleName,
212
+ className,
213
+ funcName,
214
+ paramName
215
+ }) => {
216
+ return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`;
217
+ },
218
+ 'not-array-of-class': ({
219
+ value,
220
+ expectedClass,
221
+ moduleName,
222
+ className,
223
+ funcName,
224
+ paramName
225
+ }) => {
226
+ return `The supplied '${paramName}' parameter must be an array of ` + `'${expectedClass}' objects. Received '${JSON.stringify(value)},'. ` + `Please check the call to ${moduleName}.${className}.${funcName}() ` + `to fix the issue.`;
227
+ },
228
+ 'max-entries-or-age-required': ({
229
+ moduleName,
230
+ className,
231
+ funcName
232
+ }) => {
233
+ return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`;
234
+ },
235
+ 'statuses-or-headers-required': ({
236
+ moduleName,
237
+ className,
238
+ funcName
239
+ }) => {
240
+ return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`;
241
+ },
242
+ 'invalid-string': ({
243
+ moduleName,
244
+ funcName,
245
+ paramName
246
+ }) => {
247
+ if (!paramName || !moduleName || !funcName) {
248
+ throw new Error(`Unexpected input to 'invalid-string' error.`);
249
+ }
250
+ return `When using strings, the '${paramName}' parameter must start with ` + `'http' (for cross-origin matches) or '/' (for same-origin matches). ` + `Please see the docs for ${moduleName}.${funcName}() for ` + `more info.`;
251
+ },
252
+ 'channel-name-required': () => {
253
+ return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`;
254
+ },
255
+ 'invalid-responses-are-same-args': () => {
256
+ return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`;
257
+ },
258
+ 'expire-custom-caches-only': () => {
259
+ return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`;
260
+ },
261
+ 'unit-must-be-bytes': ({
262
+ normalizedRangeHeader
263
+ }) => {
264
+ if (!normalizedRangeHeader) {
265
+ throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`);
266
+ }
267
+ return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`;
268
+ },
269
+ 'single-range-only': ({
270
+ normalizedRangeHeader
271
+ }) => {
272
+ if (!normalizedRangeHeader) {
273
+ throw new Error(`Unexpected input to 'single-range-only' error.`);
274
+ }
275
+ return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`;
276
+ },
277
+ 'invalid-range-values': ({
278
+ normalizedRangeHeader
279
+ }) => {
280
+ if (!normalizedRangeHeader) {
281
+ throw new Error(`Unexpected input to 'invalid-range-values' error.`);
282
+ }
283
+ return `The Range header is missing both start and end values. At least ` + `one of those values is needed. The Range header provided was ` + `"${normalizedRangeHeader}"`;
284
+ },
285
+ 'no-range-header': () => {
286
+ return `No Range header was found in the Request provided.`;
287
+ },
288
+ 'range-not-satisfiable': ({
289
+ size,
290
+ start,
291
+ end
292
+ }) => {
293
+ return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`;
294
+ },
295
+ 'attempt-to-cache-non-get-request': ({
296
+ url,
297
+ method
298
+ }) => {
299
+ return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`;
300
+ },
301
+ 'cache-put-with-no-response': ({
302
+ url
303
+ }) => {
304
+ return `There was an attempt to cache '${url}' but the response was not ` + `defined.`;
305
+ },
306
+ 'no-response': ({
307
+ url,
308
+ error
309
+ }) => {
310
+ let message = `The strategy could not generate a response for '${url}'.`;
311
+ if (error) {
312
+ message += ` The underlying error is ${error}.`;
313
+ }
314
+ return message;
315
+ },
316
+ 'bad-precaching-response': ({
317
+ url,
318
+ status
319
+ }) => {
320
+ return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`);
321
+ },
322
+ 'non-precached-url': ({
323
+ url
324
+ }) => {
325
+ return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`;
326
+ },
327
+ 'add-to-cache-list-conflicting-integrities': ({
328
+ url
329
+ }) => {
330
+ return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`;
331
+ },
332
+ 'missing-precache-entry': ({
333
+ cacheName,
334
+ url
335
+ }) => {
336
+ return `Unable to find a precached response in ${cacheName} for ${url}.`;
337
+ },
338
+ 'cross-origin-copy-response': ({
339
+ origin
340
+ }) => {
341
+ return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`;
342
+ },
343
+ 'opaque-streams-source': ({
344
+ type
345
+ }) => {
346
+ const message = `One of the workbox-streams sources resulted in an ` + `'${type}' response.`;
347
+ if (type === 'opaqueredirect') {
348
+ return `${message} Please do not use a navigation request that results ` + `in a redirect as a source.`;
349
+ }
350
+ return `${message} Please ensure your sources are CORS-enabled.`;
351
+ }
352
+ };
353
+
354
+ /*
355
+ Copyright 2018 Google LLC
356
+
357
+ Use of this source code is governed by an MIT-style
358
+ license that can be found in the LICENSE file or at
359
+ https://opensource.org/licenses/MIT.
360
+ */
361
+ const generatorFunction = (code, details = {}) => {
362
+ const message = messages[code];
363
+ if (!message) {
364
+ throw new Error(`Unable to find message for code '${code}'.`);
365
+ }
366
+ return message(details);
367
+ };
368
+ const messageGenerator = generatorFunction;
369
+
370
+ /*
371
+ Copyright 2018 Google LLC
372
+
373
+ Use of this source code is governed by an MIT-style
374
+ license that can be found in the LICENSE file or at
375
+ https://opensource.org/licenses/MIT.
376
+ */
377
+ /**
378
+ * Workbox errors should be thrown with this class.
379
+ * This allows use to ensure the type easily in tests,
380
+ * helps developers identify errors from workbox
381
+ * easily and allows use to optimise error
382
+ * messages correctly.
383
+ *
384
+ * @private
385
+ */
386
+ class WorkboxError extends Error {
387
+ /**
388
+ *
389
+ * @param {string} errorCode The error code that
390
+ * identifies this particular error.
391
+ * @param {Object=} details Any relevant arguments
392
+ * that will help developers identify issues should
393
+ * be added as a key on the context object.
394
+ */
395
+ constructor(errorCode, details) {
396
+ const message = messageGenerator(errorCode, details);
397
+ super(message);
398
+ this.name = errorCode;
399
+ this.details = details;
400
+ }
401
+ }
402
+
403
+ /*
404
+ Copyright 2018 Google LLC
405
+
406
+ Use of this source code is governed by an MIT-style
407
+ license that can be found in the LICENSE file or at
408
+ https://opensource.org/licenses/MIT.
409
+ */
410
+ /*
411
+ * This method throws if the supplied value is not an array.
412
+ * The destructed values are required to produce a meaningful error for users.
413
+ * The destructed and restructured object is so it's clear what is
414
+ * needed.
415
+ */
416
+ const isArray = (value, details) => {
417
+ if (!Array.isArray(value)) {
418
+ throw new WorkboxError('not-an-array', details);
419
+ }
420
+ };
421
+ const hasMethod = (object, expectedMethod, details) => {
422
+ const type = typeof object[expectedMethod];
423
+ if (type !== 'function') {
424
+ details['expectedMethod'] = expectedMethod;
425
+ throw new WorkboxError('missing-a-method', details);
426
+ }
427
+ };
428
+ const isType = (object, expectedType, details) => {
429
+ if (typeof object !== expectedType) {
430
+ details['expectedType'] = expectedType;
431
+ throw new WorkboxError('incorrect-type', details);
432
+ }
433
+ };
434
+ const isInstance = (object,
435
+ // Need the general type to do the check later.
436
+ // eslint-disable-next-line @typescript-eslint/ban-types
437
+ expectedClass, details) => {
438
+ if (!(object instanceof expectedClass)) {
439
+ details['expectedClassName'] = expectedClass.name;
440
+ throw new WorkboxError('incorrect-class', details);
441
+ }
442
+ };
443
+ const isOneOf = (value, validValues, details) => {
444
+ if (!validValues.includes(value)) {
445
+ details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`;
446
+ throw new WorkboxError('invalid-value', details);
447
+ }
448
+ };
449
+ const isArrayOfClass = (value,
450
+ // Need general type to do check later.
451
+ expectedClass,
452
+ // eslint-disable-line
453
+ details) => {
454
+ const error = new WorkboxError('not-array-of-class', details);
455
+ if (!Array.isArray(value)) {
456
+ throw error;
457
+ }
458
+ for (const item of value) {
459
+ if (!(item instanceof expectedClass)) {
460
+ throw error;
461
+ }
462
+ }
463
+ };
464
+ const finalAssertExports = {
465
+ hasMethod,
466
+ isArray,
467
+ isInstance,
468
+ isOneOf,
469
+ isType,
470
+ isArrayOfClass
471
+ };
472
+
473
+ // @ts-ignore
474
+ try {
475
+ self['workbox:routing:7.3.0'] && _();
476
+ } catch (e) {}
477
+
478
+ /*
479
+ Copyright 2018 Google LLC
480
+
481
+ Use of this source code is governed by an MIT-style
482
+ license that can be found in the LICENSE file or at
483
+ https://opensource.org/licenses/MIT.
484
+ */
485
+ /**
486
+ * The default HTTP method, 'GET', used when there's no specific method
487
+ * configured for a route.
488
+ *
489
+ * @type {string}
490
+ *
491
+ * @private
492
+ */
493
+ const defaultMethod = 'GET';
494
+ /**
495
+ * The list of valid HTTP methods associated with requests that could be routed.
496
+ *
497
+ * @type {Array<string>}
498
+ *
499
+ * @private
500
+ */
501
+ const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'];
502
+
503
+ /*
504
+ Copyright 2018 Google LLC
505
+
506
+ Use of this source code is governed by an MIT-style
507
+ license that can be found in the LICENSE file or at
508
+ https://opensource.org/licenses/MIT.
509
+ */
510
+ /**
511
+ * @param {function()|Object} handler Either a function, or an object with a
512
+ * 'handle' method.
513
+ * @return {Object} An object with a handle method.
514
+ *
515
+ * @private
516
+ */
517
+ const normalizeHandler = handler => {
518
+ if (handler && typeof handler === 'object') {
519
+ {
520
+ finalAssertExports.hasMethod(handler, 'handle', {
521
+ moduleName: 'workbox-routing',
522
+ className: 'Route',
523
+ funcName: 'constructor',
524
+ paramName: 'handler'
525
+ });
526
+ }
527
+ return handler;
528
+ } else {
529
+ {
530
+ finalAssertExports.isType(handler, 'function', {
531
+ moduleName: 'workbox-routing',
532
+ className: 'Route',
533
+ funcName: 'constructor',
534
+ paramName: 'handler'
535
+ });
536
+ }
537
+ return {
538
+ handle: handler
539
+ };
540
+ }
541
+ };
542
+
543
+ /*
544
+ Copyright 2018 Google LLC
545
+
546
+ Use of this source code is governed by an MIT-style
547
+ license that can be found in the LICENSE file or at
548
+ https://opensource.org/licenses/MIT.
549
+ */
550
+ /**
551
+ * A `Route` consists of a pair of callback functions, "match" and "handler".
552
+ * The "match" callback determine if a route should be used to "handle" a
553
+ * request by returning a non-falsy value if it can. The "handler" callback
554
+ * is called when there is a match and should return a Promise that resolves
555
+ * to a `Response`.
556
+ *
557
+ * @memberof workbox-routing
558
+ */
559
+ class Route {
560
+ /**
561
+ * Constructor for Route class.
562
+ *
563
+ * @param {workbox-routing~matchCallback} match
564
+ * A callback function that determines whether the route matches a given
565
+ * `fetch` event by returning a non-falsy value.
566
+ * @param {workbox-routing~handlerCallback} handler A callback
567
+ * function that returns a Promise resolving to a Response.
568
+ * @param {string} [method='GET'] The HTTP method to match the Route
569
+ * against.
570
+ */
571
+ constructor(match, handler, method = defaultMethod) {
572
+ {
573
+ finalAssertExports.isType(match, 'function', {
574
+ moduleName: 'workbox-routing',
575
+ className: 'Route',
576
+ funcName: 'constructor',
577
+ paramName: 'match'
578
+ });
579
+ if (method) {
580
+ finalAssertExports.isOneOf(method, validMethods, {
581
+ paramName: 'method'
582
+ });
583
+ }
584
+ }
585
+ // These values are referenced directly by Router so cannot be
586
+ // altered by minificaton.
587
+ this.handler = normalizeHandler(handler);
588
+ this.match = match;
589
+ this.method = method;
590
+ }
591
+ /**
592
+ *
593
+ * @param {workbox-routing-handlerCallback} handler A callback
594
+ * function that returns a Promise resolving to a Response
595
+ */
596
+ setCatchHandler(handler) {
597
+ this.catchHandler = normalizeHandler(handler);
598
+ }
599
+ }
600
+
601
+ /*
602
+ Copyright 2018 Google LLC
603
+
604
+ Use of this source code is governed by an MIT-style
605
+ license that can be found in the LICENSE file or at
606
+ https://opensource.org/licenses/MIT.
607
+ */
608
+ /**
609
+ * RegExpRoute makes it easy to create a regular expression based
610
+ * {@link workbox-routing.Route}.
611
+ *
612
+ * For same-origin requests the RegExp only needs to match part of the URL. For
613
+ * requests against third-party servers, you must define a RegExp that matches
614
+ * the start of the URL.
615
+ *
616
+ * @memberof workbox-routing
617
+ * @extends workbox-routing.Route
618
+ */
619
+ class RegExpRoute extends Route {
620
+ /**
621
+ * If the regular expression contains
622
+ * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},
623
+ * the captured values will be passed to the
624
+ * {@link workbox-routing~handlerCallback} `params`
625
+ * argument.
626
+ *
627
+ * @param {RegExp} regExp The regular expression to match against URLs.
628
+ * @param {workbox-routing~handlerCallback} handler A callback
629
+ * function that returns a Promise resulting in a Response.
630
+ * @param {string} [method='GET'] The HTTP method to match the Route
631
+ * against.
632
+ */
633
+ constructor(regExp, handler, method) {
634
+ {
635
+ finalAssertExports.isInstance(regExp, RegExp, {
636
+ moduleName: 'workbox-routing',
637
+ className: 'RegExpRoute',
638
+ funcName: 'constructor',
639
+ paramName: 'pattern'
640
+ });
641
+ }
642
+ const match = ({
643
+ url
644
+ }) => {
645
+ const result = regExp.exec(url.href);
646
+ // Return immediately if there's no match.
647
+ if (!result) {
648
+ return;
649
+ }
650
+ // Require that the match start at the first character in the URL string
651
+ // if it's a cross-origin request.
652
+ // See https://github.com/GoogleChrome/workbox/issues/281 for the context
653
+ // behind this behavior.
654
+ if (url.origin !== location.origin && result.index !== 0) {
655
+ {
656
+ 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.`);
657
+ }
658
+ return;
659
+ }
660
+ // If the route matches, but there aren't any capture groups defined, then
661
+ // this will return [], which is truthy and therefore sufficient to
662
+ // indicate a match.
663
+ // If there are capture groups, then it will return their values.
664
+ return result.slice(1);
665
+ };
666
+ super(match, handler, method);
667
+ }
668
+ }
669
+
670
+ /*
671
+ Copyright 2018 Google LLC
672
+
673
+ Use of this source code is governed by an MIT-style
674
+ license that can be found in the LICENSE file or at
675
+ https://opensource.org/licenses/MIT.
676
+ */
677
+ const getFriendlyURL = url => {
678
+ const urlObj = new URL(String(url), location.href);
679
+ // See https://github.com/GoogleChrome/workbox/issues/2323
680
+ // We want to include everything, except for the origin if it's same-origin.
681
+ return urlObj.href.replace(new RegExp(`^${location.origin}`), '');
682
+ };
683
+
684
+ /*
685
+ Copyright 2018 Google LLC
686
+
687
+ Use of this source code is governed by an MIT-style
688
+ license that can be found in the LICENSE file or at
689
+ https://opensource.org/licenses/MIT.
690
+ */
691
+ /**
692
+ * The Router can be used to process a `FetchEvent` using one or more
693
+ * {@link workbox-routing.Route}, responding with a `Response` if
694
+ * a matching route exists.
695
+ *
696
+ * If no route matches a given a request, the Router will use a "default"
697
+ * handler if one is defined.
698
+ *
699
+ * Should the matching Route throw an error, the Router will use a "catch"
700
+ * handler if one is defined to gracefully deal with issues and respond with a
701
+ * Request.
702
+ *
703
+ * If a request matches multiple routes, the **earliest** registered route will
704
+ * be used to respond to the request.
705
+ *
706
+ * @memberof workbox-routing
707
+ */
708
+ class Router {
709
+ /**
710
+ * Initializes a new Router.
711
+ */
712
+ constructor() {
713
+ this._routes = new Map();
714
+ this._defaultHandlerMap = new Map();
715
+ }
716
+ /**
717
+ * @return {Map<string, Array<workbox-routing.Route>>} routes A `Map` of HTTP
718
+ * method name ('GET', etc.) to an array of all the corresponding `Route`
719
+ * instances that are registered.
720
+ */
721
+ get routes() {
722
+ return this._routes;
723
+ }
724
+ /**
725
+ * Adds a fetch event listener to respond to events when a route matches
726
+ * the event's request.
727
+ */
728
+ addFetchListener() {
729
+ // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
730
+ self.addEventListener('fetch', event => {
731
+ const {
732
+ request
733
+ } = event;
734
+ const responsePromise = this.handleRequest({
735
+ request,
736
+ event
737
+ });
738
+ if (responsePromise) {
739
+ event.respondWith(responsePromise);
740
+ }
741
+ });
742
+ }
743
+ /**
744
+ * Adds a message event listener for URLs to cache from the window.
745
+ * This is useful to cache resources loaded on the page prior to when the
746
+ * service worker started controlling it.
747
+ *
748
+ * The format of the message data sent from the window should be as follows.
749
+ * Where the `urlsToCache` array may consist of URL strings or an array of
750
+ * URL string + `requestInit` object (the same as you'd pass to `fetch()`).
751
+ *
752
+ * ```
753
+ * {
754
+ * type: 'CACHE_URLS',
755
+ * payload: {
756
+ * urlsToCache: [
757
+ * './script1.js',
758
+ * './script2.js',
759
+ * ['./script3.js', {mode: 'no-cors'}],
760
+ * ],
761
+ * },
762
+ * }
763
+ * ```
764
+ */
765
+ addCacheListener() {
766
+ // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
767
+ self.addEventListener('message', event => {
768
+ // event.data is type 'any'
769
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
770
+ if (event.data && event.data.type === 'CACHE_URLS') {
771
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
772
+ const {
773
+ payload
774
+ } = event.data;
775
+ {
776
+ logger.debug(`Caching URLs from the window`, payload.urlsToCache);
777
+ }
778
+ const requestPromises = Promise.all(payload.urlsToCache.map(entry => {
779
+ if (typeof entry === 'string') {
780
+ entry = [entry];
781
+ }
782
+ const request = new Request(...entry);
783
+ return this.handleRequest({
784
+ request,
785
+ event
786
+ });
787
+ // TODO(philipwalton): TypeScript errors without this typecast for
788
+ // some reason (probably a bug). The real type here should work but
789
+ // doesn't: `Array<Promise<Response> | undefined>`.
790
+ })); // TypeScript
791
+ event.waitUntil(requestPromises);
792
+ // If a MessageChannel was used, reply to the message on success.
793
+ if (event.ports && event.ports[0]) {
794
+ void requestPromises.then(() => event.ports[0].postMessage(true));
795
+ }
796
+ }
797
+ });
798
+ }
799
+ /**
800
+ * Apply the routing rules to a FetchEvent object to get a Response from an
801
+ * appropriate Route's handler.
802
+ *
803
+ * @param {Object} options
804
+ * @param {Request} options.request The request to handle.
805
+ * @param {ExtendableEvent} options.event The event that triggered the
806
+ * request.
807
+ * @return {Promise<Response>|undefined} A promise is returned if a
808
+ * registered route can handle the request. If there is no matching
809
+ * route and there's no `defaultHandler`, `undefined` is returned.
810
+ */
811
+ handleRequest({
812
+ request,
813
+ event
814
+ }) {
815
+ {
816
+ finalAssertExports.isInstance(request, Request, {
817
+ moduleName: 'workbox-routing',
818
+ className: 'Router',
819
+ funcName: 'handleRequest',
820
+ paramName: 'options.request'
821
+ });
822
+ }
823
+ const url = new URL(request.url, location.href);
824
+ if (!url.protocol.startsWith('http')) {
825
+ {
826
+ logger.debug(`Workbox Router only supports URLs that start with 'http'.`);
827
+ }
828
+ return;
829
+ }
830
+ const sameOrigin = url.origin === location.origin;
831
+ const {
832
+ params,
833
+ route
834
+ } = this.findMatchingRoute({
835
+ event,
836
+ request,
837
+ sameOrigin,
838
+ url
839
+ });
840
+ let handler = route && route.handler;
841
+ const debugMessages = [];
842
+ {
843
+ if (handler) {
844
+ debugMessages.push([`Found a route to handle this request:`, route]);
845
+ if (params) {
846
+ debugMessages.push([`Passing the following params to the route's handler:`, params]);
847
+ }
848
+ }
849
+ }
850
+ // If we don't have a handler because there was no matching route, then
851
+ // fall back to defaultHandler if that's defined.
852
+ const method = request.method;
853
+ if (!handler && this._defaultHandlerMap.has(method)) {
854
+ {
855
+ debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`);
856
+ }
857
+ handler = this._defaultHandlerMap.get(method);
858
+ }
859
+ if (!handler) {
860
+ {
861
+ // No handler so Workbox will do nothing. If logs is set of debug
862
+ // i.e. verbose, we should print out this information.
863
+ logger.debug(`No route found for: ${getFriendlyURL(url)}`);
864
+ }
865
+ return;
866
+ }
867
+ {
868
+ // We have a handler, meaning Workbox is going to handle the route.
869
+ // print the routing details to the console.
870
+ logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
871
+ debugMessages.forEach(msg => {
872
+ if (Array.isArray(msg)) {
873
+ logger.log(...msg);
874
+ } else {
875
+ logger.log(msg);
876
+ }
877
+ });
878
+ logger.groupEnd();
879
+ }
880
+ // Wrap in try and catch in case the handle method throws a synchronous
881
+ // error. It should still callback to the catch handler.
882
+ let responsePromise;
883
+ try {
884
+ responsePromise = handler.handle({
885
+ url,
886
+ request,
887
+ event,
888
+ params
889
+ });
890
+ } catch (err) {
891
+ responsePromise = Promise.reject(err);
892
+ }
893
+ // Get route's catch handler, if it exists
894
+ const catchHandler = route && route.catchHandler;
895
+ if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
896
+ responsePromise = responsePromise.catch(async err => {
897
+ // If there's a route catch handler, process that first
898
+ if (catchHandler) {
899
+ {
900
+ // Still include URL here as it will be async from the console group
901
+ // and may not make sense without the URL
902
+ logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
903
+ logger.error(`Error thrown by:`, route);
904
+ logger.error(err);
905
+ logger.groupEnd();
906
+ }
907
+ try {
908
+ return await catchHandler.handle({
909
+ url,
910
+ request,
911
+ event,
912
+ params
913
+ });
914
+ } catch (catchErr) {
915
+ if (catchErr instanceof Error) {
916
+ err = catchErr;
917
+ }
918
+ }
919
+ }
920
+ if (this._catchHandler) {
921
+ {
922
+ // Still include URL here as it will be async from the console group
923
+ // and may not make sense without the URL
924
+ logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
925
+ logger.error(`Error thrown by:`, route);
926
+ logger.error(err);
927
+ logger.groupEnd();
928
+ }
929
+ return this._catchHandler.handle({
930
+ url,
931
+ request,
932
+ event
933
+ });
934
+ }
935
+ throw err;
936
+ });
937
+ }
938
+ return responsePromise;
939
+ }
940
+ /**
941
+ * Checks a request and URL (and optionally an event) against the list of
942
+ * registered routes, and if there's a match, returns the corresponding
943
+ * route along with any params generated by the match.
944
+ *
945
+ * @param {Object} options
946
+ * @param {URL} options.url
947
+ * @param {boolean} options.sameOrigin The result of comparing `url.origin`
948
+ * against the current origin.
949
+ * @param {Request} options.request The request to match.
950
+ * @param {Event} options.event The corresponding event.
951
+ * @return {Object} An object with `route` and `params` properties.
952
+ * They are populated if a matching route was found or `undefined`
953
+ * otherwise.
954
+ */
955
+ findMatchingRoute({
956
+ url,
957
+ sameOrigin,
958
+ request,
959
+ event
960
+ }) {
961
+ const routes = this._routes.get(request.method) || [];
962
+ for (const route of routes) {
963
+ let params;
964
+ // route.match returns type any, not possible to change right now.
965
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
966
+ const matchResult = route.match({
967
+ url,
968
+ sameOrigin,
969
+ request,
970
+ event
971
+ });
972
+ if (matchResult) {
973
+ {
974
+ // Warn developers that using an async matchCallback is almost always
975
+ // not the right thing to do.
976
+ if (matchResult instanceof Promise) {
977
+ logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route);
978
+ }
979
+ }
980
+ // See https://github.com/GoogleChrome/workbox/issues/2079
981
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
982
+ params = matchResult;
983
+ if (Array.isArray(params) && params.length === 0) {
984
+ // Instead of passing an empty array in as params, use undefined.
985
+ params = undefined;
986
+ } else if (matchResult.constructor === Object &&
987
+ // eslint-disable-line
988
+ Object.keys(matchResult).length === 0) {
989
+ // Instead of passing an empty object in as params, use undefined.
990
+ params = undefined;
991
+ } else if (typeof matchResult === 'boolean') {
992
+ // For the boolean value true (rather than just something truth-y),
993
+ // don't set params.
994
+ // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353
995
+ params = undefined;
996
+ }
997
+ // Return early if have a match.
998
+ return {
999
+ route,
1000
+ params
1001
+ };
1002
+ }
1003
+ }
1004
+ // If no match was found above, return and empty object.
1005
+ return {};
1006
+ }
1007
+ /**
1008
+ * Define a default `handler` that's called when no routes explicitly
1009
+ * match the incoming request.
1010
+ *
1011
+ * Each HTTP method ('GET', 'POST', etc.) gets its own default handler.
1012
+ *
1013
+ * Without a default handler, unmatched requests will go against the
1014
+ * network as if there were no service worker present.
1015
+ *
1016
+ * @param {workbox-routing~handlerCallback} handler A callback
1017
+ * function that returns a Promise resulting in a Response.
1018
+ * @param {string} [method='GET'] The HTTP method to associate with this
1019
+ * default handler. Each method has its own default.
1020
+ */
1021
+ setDefaultHandler(handler, method = defaultMethod) {
1022
+ this._defaultHandlerMap.set(method, normalizeHandler(handler));
1023
+ }
1024
+ /**
1025
+ * If a Route throws an error while handling a request, this `handler`
1026
+ * will be called and given a chance to provide a response.
1027
+ *
1028
+ * @param {workbox-routing~handlerCallback} handler A callback
1029
+ * function that returns a Promise resulting in a Response.
1030
+ */
1031
+ setCatchHandler(handler) {
1032
+ this._catchHandler = normalizeHandler(handler);
1033
+ }
1034
+ /**
1035
+ * Registers a route with the router.
1036
+ *
1037
+ * @param {workbox-routing.Route} route The route to register.
1038
+ */
1039
+ registerRoute(route) {
1040
+ {
1041
+ finalAssertExports.isType(route, 'object', {
1042
+ moduleName: 'workbox-routing',
1043
+ className: 'Router',
1044
+ funcName: 'registerRoute',
1045
+ paramName: 'route'
1046
+ });
1047
+ finalAssertExports.hasMethod(route, 'match', {
1048
+ moduleName: 'workbox-routing',
1049
+ className: 'Router',
1050
+ funcName: 'registerRoute',
1051
+ paramName: 'route'
1052
+ });
1053
+ finalAssertExports.isType(route.handler, 'object', {
1054
+ moduleName: 'workbox-routing',
1055
+ className: 'Router',
1056
+ funcName: 'registerRoute',
1057
+ paramName: 'route'
1058
+ });
1059
+ finalAssertExports.hasMethod(route.handler, 'handle', {
1060
+ moduleName: 'workbox-routing',
1061
+ className: 'Router',
1062
+ funcName: 'registerRoute',
1063
+ paramName: 'route.handler'
1064
+ });
1065
+ finalAssertExports.isType(route.method, 'string', {
1066
+ moduleName: 'workbox-routing',
1067
+ className: 'Router',
1068
+ funcName: 'registerRoute',
1069
+ paramName: 'route.method'
1070
+ });
1071
+ }
1072
+ if (!this._routes.has(route.method)) {
1073
+ this._routes.set(route.method, []);
1074
+ }
1075
+ // Give precedence to all of the earlier routes by adding this additional
1076
+ // route to the end of the array.
1077
+ this._routes.get(route.method).push(route);
1078
+ }
1079
+ /**
1080
+ * Unregisters a route with the router.
1081
+ *
1082
+ * @param {workbox-routing.Route} route The route to unregister.
1083
+ */
1084
+ unregisterRoute(route) {
1085
+ if (!this._routes.has(route.method)) {
1086
+ throw new WorkboxError('unregister-route-but-not-found-with-method', {
1087
+ method: route.method
1088
+ });
1089
+ }
1090
+ const routeIndex = this._routes.get(route.method).indexOf(route);
1091
+ if (routeIndex > -1) {
1092
+ this._routes.get(route.method).splice(routeIndex, 1);
1093
+ } else {
1094
+ throw new WorkboxError('unregister-route-route-not-registered');
1095
+ }
1096
+ }
1097
+ }
1098
+
1099
+ /*
1100
+ Copyright 2019 Google LLC
1101
+
1102
+ Use of this source code is governed by an MIT-style
1103
+ license that can be found in the LICENSE file or at
1104
+ https://opensource.org/licenses/MIT.
1105
+ */
1106
+ let defaultRouter;
1107
+ /**
1108
+ * Creates a new, singleton Router instance if one does not exist. If one
1109
+ * does already exist, that instance is returned.
1110
+ *
1111
+ * @private
1112
+ * @return {Router}
1113
+ */
1114
+ const getOrCreateDefaultRouter = () => {
1115
+ if (!defaultRouter) {
1116
+ defaultRouter = new Router();
1117
+ // The helpers that use the default Router assume these listeners exist.
1118
+ defaultRouter.addFetchListener();
1119
+ defaultRouter.addCacheListener();
1120
+ }
1121
+ return defaultRouter;
1122
+ };
1123
+
1124
+ /*
1125
+ Copyright 2019 Google LLC
1126
+
1127
+ Use of this source code is governed by an MIT-style
1128
+ license that can be found in the LICENSE file or at
1129
+ https://opensource.org/licenses/MIT.
1130
+ */
1131
+ /**
1132
+ * Easily register a RegExp, string, or function with a caching
1133
+ * strategy to a singleton Router instance.
1134
+ *
1135
+ * This method will generate a Route for you if needed and
1136
+ * call {@link workbox-routing.Router#registerRoute}.
1137
+ *
1138
+ * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture
1139
+ * If the capture param is a `Route`, all other arguments will be ignored.
1140
+ * @param {workbox-routing~handlerCallback} [handler] A callback
1141
+ * function that returns a Promise resulting in a Response. This parameter
1142
+ * is required if `capture` is not a `Route` object.
1143
+ * @param {string} [method='GET'] The HTTP method to match the Route
1144
+ * against.
1145
+ * @return {workbox-routing.Route} The generated `Route`.
1146
+ *
1147
+ * @memberof workbox-routing
1148
+ */
1149
+ function registerRoute(capture, handler, method) {
1150
+ let route;
1151
+ if (typeof capture === 'string') {
1152
+ const captureUrl = new URL(capture, location.href);
1153
+ {
1154
+ if (!(capture.startsWith('/') || capture.startsWith('http'))) {
1155
+ throw new WorkboxError('invalid-string', {
1156
+ moduleName: 'workbox-routing',
1157
+ funcName: 'registerRoute',
1158
+ paramName: 'capture'
1159
+ });
1160
+ }
1161
+ // We want to check if Express-style wildcards are in the pathname only.
1162
+ // TODO: Remove this log message in v4.
1163
+ const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture;
1164
+ // See https://github.com/pillarjs/path-to-regexp#parameters
1165
+ const wildcards = '[*:?+]';
1166
+ if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
1167
+ 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.`);
1168
+ }
1169
+ }
1170
+ const matchCallback = ({
1171
+ url
1172
+ }) => {
1173
+ {
1174
+ if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
1175
+ 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.`);
1176
+ }
1177
+ }
1178
+ return url.href === captureUrl.href;
1179
+ };
1180
+ // If `capture` is a string then `handler` and `method` must be present.
1181
+ route = new Route(matchCallback, handler, method);
1182
+ } else if (capture instanceof RegExp) {
1183
+ // If `capture` is a `RegExp` then `handler` and `method` must be present.
1184
+ route = new RegExpRoute(capture, handler, method);
1185
+ } else if (typeof capture === 'function') {
1186
+ // If `capture` is a function then `handler` and `method` must be present.
1187
+ route = new Route(capture, handler, method);
1188
+ } else if (capture instanceof Route) {
1189
+ route = capture;
1190
+ } else {
1191
+ throw new WorkboxError('unsupported-route-type', {
1192
+ moduleName: 'workbox-routing',
1193
+ funcName: 'registerRoute',
1194
+ paramName: 'capture'
1195
+ });
1196
+ }
1197
+ const defaultRouter = getOrCreateDefaultRouter();
1198
+ defaultRouter.registerRoute(route);
1199
+ return route;
1200
+ }
1201
+
1202
+ /*
1203
+ Copyright 2018 Google LLC
1204
+
1205
+ Use of this source code is governed by an MIT-style
1206
+ license that can be found in the LICENSE file or at
1207
+ https://opensource.org/licenses/MIT.
1208
+ */
1209
+ const _cacheNameDetails = {
1210
+ googleAnalytics: 'googleAnalytics',
1211
+ precache: 'precache-v2',
1212
+ prefix: 'workbox',
1213
+ runtime: 'runtime',
1214
+ suffix: typeof registration !== 'undefined' ? registration.scope : ''
1215
+ };
1216
+ const _createCacheName = cacheName => {
1217
+ return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-');
1218
+ };
1219
+ const eachCacheNameDetail = fn => {
1220
+ for (const key of Object.keys(_cacheNameDetails)) {
1221
+ fn(key);
1222
+ }
1223
+ };
1224
+ const cacheNames = {
1225
+ updateDetails: details => {
1226
+ eachCacheNameDetail(key => {
1227
+ if (typeof details[key] === 'string') {
1228
+ _cacheNameDetails[key] = details[key];
1229
+ }
1230
+ });
1231
+ },
1232
+ getGoogleAnalyticsName: userCacheName => {
1233
+ return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics);
1234
+ },
1235
+ getPrecacheName: userCacheName => {
1236
+ return userCacheName || _createCacheName(_cacheNameDetails.precache);
1237
+ },
1238
+ getPrefix: () => {
1239
+ return _cacheNameDetails.prefix;
1240
+ },
1241
+ getRuntimeName: userCacheName => {
1242
+ return userCacheName || _createCacheName(_cacheNameDetails.runtime);
1243
+ },
1244
+ getSuffix: () => {
1245
+ return _cacheNameDetails.suffix;
1246
+ }
1247
+ };
1248
+
1249
+ /*
1250
+ Copyright 2020 Google LLC
1251
+ Use of this source code is governed by an MIT-style
1252
+ license that can be found in the LICENSE file or at
1253
+ https://opensource.org/licenses/MIT.
1254
+ */
1255
+ /**
1256
+ * A utility method that makes it easier to use `event.waitUntil` with
1257
+ * async functions and return the result.
1258
+ *
1259
+ * @param {ExtendableEvent} event
1260
+ * @param {Function} asyncFn
1261
+ * @return {Function}
1262
+ * @private
1263
+ */
1264
+ function waitUntil(event, asyncFn) {
1265
+ const returnPromise = asyncFn();
1266
+ event.waitUntil(returnPromise);
1267
+ return returnPromise;
1268
+ }
1269
+
1270
+ // @ts-ignore
1271
+ try {
1272
+ self['workbox:precaching:7.3.0'] && _();
1273
+ } catch (e) {}
1274
+
1275
+ /*
1276
+ Copyright 2018 Google LLC
1277
+
1278
+ Use of this source code is governed by an MIT-style
1279
+ license that can be found in the LICENSE file or at
1280
+ https://opensource.org/licenses/MIT.
1281
+ */
1282
+ // Name of the search parameter used to store revision info.
1283
+ const REVISION_SEARCH_PARAM = '__WB_REVISION__';
1284
+ /**
1285
+ * Converts a manifest entry into a versioned URL suitable for precaching.
1286
+ *
1287
+ * @param {Object|string} entry
1288
+ * @return {string} A URL with versioning info.
1289
+ *
1290
+ * @private
1291
+ * @memberof workbox-precaching
1292
+ */
1293
+ function createCacheKey(entry) {
1294
+ if (!entry) {
1295
+ throw new WorkboxError('add-to-cache-list-unexpected-type', {
1296
+ entry
1297
+ });
1298
+ }
1299
+ // If a precache manifest entry is a string, it's assumed to be a versioned
1300
+ // URL, like '/app.abcd1234.js'. Return as-is.
1301
+ if (typeof entry === 'string') {
1302
+ const urlObject = new URL(entry, location.href);
1303
+ return {
1304
+ cacheKey: urlObject.href,
1305
+ url: urlObject.href
1306
+ };
1307
+ }
1308
+ const {
1309
+ revision,
1310
+ url
1311
+ } = entry;
1312
+ if (!url) {
1313
+ throw new WorkboxError('add-to-cache-list-unexpected-type', {
1314
+ entry
1315
+ });
1316
+ }
1317
+ // If there's just a URL and no revision, then it's also assumed to be a
1318
+ // versioned URL.
1319
+ if (!revision) {
1320
+ const urlObject = new URL(url, location.href);
1321
+ return {
1322
+ cacheKey: urlObject.href,
1323
+ url: urlObject.href
1324
+ };
1325
+ }
1326
+ // Otherwise, construct a properly versioned URL using the custom Workbox
1327
+ // search parameter along with the revision info.
1328
+ const cacheKeyURL = new URL(url, location.href);
1329
+ const originalURL = new URL(url, location.href);
1330
+ cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
1331
+ return {
1332
+ cacheKey: cacheKeyURL.href,
1333
+ url: originalURL.href
1334
+ };
1335
+ }
1336
+
1337
+ /*
1338
+ Copyright 2020 Google LLC
1339
+
1340
+ Use of this source code is governed by an MIT-style
1341
+ license that can be found in the LICENSE file or at
1342
+ https://opensource.org/licenses/MIT.
1343
+ */
1344
+ /**
1345
+ * A plugin, designed to be used with PrecacheController, to determine the
1346
+ * of assets that were updated (or not updated) during the install event.
1347
+ *
1348
+ * @private
1349
+ */
1350
+ class PrecacheInstallReportPlugin {
1351
+ constructor() {
1352
+ this.updatedURLs = [];
1353
+ this.notUpdatedURLs = [];
1354
+ this.handlerWillStart = async ({
1355
+ request,
1356
+ state
1357
+ }) => {
1358
+ // TODO: `state` should never be undefined...
1359
+ if (state) {
1360
+ state.originalRequest = request;
1361
+ }
1362
+ };
1363
+ this.cachedResponseWillBeUsed = async ({
1364
+ event,
1365
+ state,
1366
+ cachedResponse
1367
+ }) => {
1368
+ if (event.type === 'install') {
1369
+ if (state && state.originalRequest && state.originalRequest instanceof Request) {
1370
+ // TODO: `state` should never be undefined...
1371
+ const url = state.originalRequest.url;
1372
+ if (cachedResponse) {
1373
+ this.notUpdatedURLs.push(url);
1374
+ } else {
1375
+ this.updatedURLs.push(url);
1376
+ }
1377
+ }
1378
+ }
1379
+ return cachedResponse;
1380
+ };
1381
+ }
1382
+ }
1383
+
1384
+ /*
1385
+ Copyright 2020 Google LLC
1386
+
1387
+ Use of this source code is governed by an MIT-style
1388
+ license that can be found in the LICENSE file or at
1389
+ https://opensource.org/licenses/MIT.
1390
+ */
1391
+ /**
1392
+ * A plugin, designed to be used with PrecacheController, to translate URLs into
1393
+ * the corresponding cache key, based on the current revision info.
1394
+ *
1395
+ * @private
1396
+ */
1397
+ class PrecacheCacheKeyPlugin {
1398
+ constructor({
1399
+ precacheController
1400
+ }) {
1401
+ this.cacheKeyWillBeUsed = async ({
1402
+ request,
1403
+ params
1404
+ }) => {
1405
+ // Params is type any, can't change right now.
1406
+ /* eslint-disable */
1407
+ const cacheKey = (params === null || params === void 0 ? void 0 : params.cacheKey) || this._precacheController.getCacheKeyForURL(request.url);
1408
+ /* eslint-enable */
1409
+ return cacheKey ? new Request(cacheKey, {
1410
+ headers: request.headers
1411
+ }) : request;
1412
+ };
1413
+ this._precacheController = precacheController;
1414
+ }
1415
+ }
1416
+
1417
+ /*
1418
+ Copyright 2018 Google LLC
1419
+
1420
+ Use of this source code is governed by an MIT-style
1421
+ license that can be found in the LICENSE file or at
1422
+ https://opensource.org/licenses/MIT.
1423
+ */
1424
+ /**
1425
+ * @param {string} groupTitle
1426
+ * @param {Array<string>} deletedURLs
1427
+ *
1428
+ * @private
1429
+ */
1430
+ const logGroup = (groupTitle, deletedURLs) => {
1431
+ logger.groupCollapsed(groupTitle);
1432
+ for (const url of deletedURLs) {
1433
+ logger.log(url);
1434
+ }
1435
+ logger.groupEnd();
1436
+ };
1437
+ /**
1438
+ * @param {Array<string>} deletedURLs
1439
+ *
1440
+ * @private
1441
+ * @memberof workbox-precaching
1442
+ */
1443
+ function printCleanupDetails(deletedURLs) {
1444
+ const deletionCount = deletedURLs.length;
1445
+ if (deletionCount > 0) {
1446
+ logger.groupCollapsed(`During precaching cleanup, ` + `${deletionCount} cached ` + `request${deletionCount === 1 ? ' was' : 's were'} deleted.`);
1447
+ logGroup('Deleted Cache Requests', deletedURLs);
1448
+ logger.groupEnd();
1449
+ }
1450
+ }
1451
+
1452
+ /*
1453
+ Copyright 2018 Google LLC
1454
+
1455
+ Use of this source code is governed by an MIT-style
1456
+ license that can be found in the LICENSE file or at
1457
+ https://opensource.org/licenses/MIT.
1458
+ */
1459
+ /**
1460
+ * @param {string} groupTitle
1461
+ * @param {Array<string>} urls
1462
+ *
1463
+ * @private
1464
+ */
1465
+ function _nestedGroup(groupTitle, urls) {
1466
+ if (urls.length === 0) {
1467
+ return;
1468
+ }
1469
+ logger.groupCollapsed(groupTitle);
1470
+ for (const url of urls) {
1471
+ logger.log(url);
1472
+ }
1473
+ logger.groupEnd();
1474
+ }
1475
+ /**
1476
+ * @param {Array<string>} urlsToPrecache
1477
+ * @param {Array<string>} urlsAlreadyPrecached
1478
+ *
1479
+ * @private
1480
+ * @memberof workbox-precaching
1481
+ */
1482
+ function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) {
1483
+ const precachedCount = urlsToPrecache.length;
1484
+ const alreadyPrecachedCount = urlsAlreadyPrecached.length;
1485
+ if (precachedCount || alreadyPrecachedCount) {
1486
+ let message = `Precaching ${precachedCount} file${precachedCount === 1 ? '' : 's'}.`;
1487
+ if (alreadyPrecachedCount > 0) {
1488
+ message += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? ' is' : 's are'} already cached.`;
1489
+ }
1490
+ logger.groupCollapsed(message);
1491
+ _nestedGroup(`View newly precached URLs.`, urlsToPrecache);
1492
+ _nestedGroup(`View previously precached URLs.`, urlsAlreadyPrecached);
1493
+ logger.groupEnd();
1494
+ }
1495
+ }
1496
+
1497
+ /*
1498
+ Copyright 2019 Google LLC
1499
+
1500
+ Use of this source code is governed by an MIT-style
1501
+ license that can be found in the LICENSE file or at
1502
+ https://opensource.org/licenses/MIT.
1503
+ */
1504
+ let supportStatus;
1505
+ /**
1506
+ * A utility function that determines whether the current browser supports
1507
+ * constructing a new `Response` from a `response.body` stream.
1508
+ *
1509
+ * @return {boolean} `true`, if the current browser can successfully
1510
+ * construct a `Response` from a `response.body` stream, `false` otherwise.
1511
+ *
1512
+ * @private
1513
+ */
1514
+ function canConstructResponseFromBodyStream() {
1515
+ if (supportStatus === undefined) {
1516
+ const testResponse = new Response('');
1517
+ if ('body' in testResponse) {
1518
+ try {
1519
+ new Response(testResponse.body);
1520
+ supportStatus = true;
1521
+ } catch (error) {
1522
+ supportStatus = false;
1523
+ }
1524
+ }
1525
+ supportStatus = false;
1526
+ }
1527
+ return supportStatus;
1528
+ }
1529
+
1530
+ /*
1531
+ Copyright 2019 Google LLC
1532
+
1533
+ Use of this source code is governed by an MIT-style
1534
+ license that can be found in the LICENSE file or at
1535
+ https://opensource.org/licenses/MIT.
1536
+ */
1537
+ /**
1538
+ * Allows developers to copy a response and modify its `headers`, `status`,
1539
+ * or `statusText` values (the values settable via a
1540
+ * [`ResponseInit`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Response/Response#Syntax}
1541
+ * object in the constructor).
1542
+ * To modify these values, pass a function as the second argument. That
1543
+ * function will be invoked with a single object with the response properties
1544
+ * `{headers, status, statusText}`. The return value of this function will
1545
+ * be used as the `ResponseInit` for the new `Response`. To change the values
1546
+ * either modify the passed parameter(s) and return it, or return a totally
1547
+ * new object.
1548
+ *
1549
+ * This method is intentionally limited to same-origin responses, regardless of
1550
+ * whether CORS was used or not.
1551
+ *
1552
+ * @param {Response} response
1553
+ * @param {Function} modifier
1554
+ * @memberof workbox-core
1555
+ */
1556
+ async function copyResponse(response, modifier) {
1557
+ let origin = null;
1558
+ // If response.url isn't set, assume it's cross-origin and keep origin null.
1559
+ if (response.url) {
1560
+ const responseURL = new URL(response.url);
1561
+ origin = responseURL.origin;
1562
+ }
1563
+ if (origin !== self.location.origin) {
1564
+ throw new WorkboxError('cross-origin-copy-response', {
1565
+ origin
1566
+ });
1567
+ }
1568
+ const clonedResponse = response.clone();
1569
+ // Create a fresh `ResponseInit` object by cloning the headers.
1570
+ const responseInit = {
1571
+ headers: new Headers(clonedResponse.headers),
1572
+ status: clonedResponse.status,
1573
+ statusText: clonedResponse.statusText
1574
+ };
1575
+ // Apply any user modifications.
1576
+ const modifiedResponseInit = modifier ? modifier(responseInit) : responseInit;
1577
+ // Create the new response from the body stream and `ResponseInit`
1578
+ // modifications. Note: not all browsers support the Response.body stream,
1579
+ // so fall back to reading the entire body into memory as a blob.
1580
+ const body = canConstructResponseFromBodyStream() ? clonedResponse.body : await clonedResponse.blob();
1581
+ return new Response(body, modifiedResponseInit);
1582
+ }
1583
+
1584
+ /*
1585
+ Copyright 2020 Google LLC
1586
+ Use of this source code is governed by an MIT-style
1587
+ license that can be found in the LICENSE file or at
1588
+ https://opensource.org/licenses/MIT.
1589
+ */
1590
+ function stripParams(fullURL, ignoreParams) {
1591
+ const strippedURL = new URL(fullURL);
1592
+ for (const param of ignoreParams) {
1593
+ strippedURL.searchParams.delete(param);
1594
+ }
1595
+ return strippedURL.href;
1596
+ }
1597
+ /**
1598
+ * Matches an item in the cache, ignoring specific URL params. This is similar
1599
+ * to the `ignoreSearch` option, but it allows you to ignore just specific
1600
+ * params (while continuing to match on the others).
1601
+ *
1602
+ * @private
1603
+ * @param {Cache} cache
1604
+ * @param {Request} request
1605
+ * @param {Object} matchOptions
1606
+ * @param {Array<string>} ignoreParams
1607
+ * @return {Promise<Response|undefined>}
1608
+ */
1609
+ async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) {
1610
+ const strippedRequestURL = stripParams(request.url, ignoreParams);
1611
+ // If the request doesn't include any ignored params, match as normal.
1612
+ if (request.url === strippedRequestURL) {
1613
+ return cache.match(request, matchOptions);
1614
+ }
1615
+ // Otherwise, match by comparing keys
1616
+ const keysOptions = Object.assign(Object.assign({}, matchOptions), {
1617
+ ignoreSearch: true
1618
+ });
1619
+ const cacheKeys = await cache.keys(request, keysOptions);
1620
+ for (const cacheKey of cacheKeys) {
1621
+ const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams);
1622
+ if (strippedRequestURL === strippedCacheKeyURL) {
1623
+ return cache.match(cacheKey, matchOptions);
1624
+ }
1625
+ }
1626
+ return;
1627
+ }
1628
+
1629
+ /*
1630
+ Copyright 2018 Google LLC
1631
+
1632
+ Use of this source code is governed by an MIT-style
1633
+ license that can be found in the LICENSE file or at
1634
+ https://opensource.org/licenses/MIT.
1635
+ */
1636
+ /**
1637
+ * The Deferred class composes Promises in a way that allows for them to be
1638
+ * resolved or rejected from outside the constructor. In most cases promises
1639
+ * should be used directly, but Deferreds can be necessary when the logic to
1640
+ * resolve a promise must be separate.
1641
+ *
1642
+ * @private
1643
+ */
1644
+ class Deferred {
1645
+ /**
1646
+ * Creates a promise and exposes its resolve and reject functions as methods.
1647
+ */
1648
+ constructor() {
1649
+ this.promise = new Promise((resolve, reject) => {
1650
+ this.resolve = resolve;
1651
+ this.reject = reject;
1652
+ });
1653
+ }
1654
+ }
1655
+
1656
+ /*
1657
+ Copyright 2018 Google LLC
1658
+
1659
+ Use of this source code is governed by an MIT-style
1660
+ license that can be found in the LICENSE file or at
1661
+ https://opensource.org/licenses/MIT.
1662
+ */
1663
+ // Callbacks to be executed whenever there's a quota error.
1664
+ // Can't change Function type right now.
1665
+ // eslint-disable-next-line @typescript-eslint/ban-types
1666
+ const quotaErrorCallbacks = new Set();
1667
+
1668
+ /*
1669
+ Copyright 2018 Google LLC
1670
+
1671
+ Use of this source code is governed by an MIT-style
1672
+ license that can be found in the LICENSE file or at
1673
+ https://opensource.org/licenses/MIT.
1674
+ */
1675
+ /**
1676
+ * Runs all of the callback functions, one at a time sequentially, in the order
1677
+ * in which they were registered.
1678
+ *
1679
+ * @memberof workbox-core
1680
+ * @private
1681
+ */
1682
+ async function executeQuotaErrorCallbacks() {
1683
+ {
1684
+ logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`);
1685
+ }
1686
+ for (const callback of quotaErrorCallbacks) {
1687
+ await callback();
1688
+ {
1689
+ logger.log(callback, 'is complete.');
1690
+ }
1691
+ }
1692
+ {
1693
+ logger.log('Finished running callbacks.');
1694
+ }
1695
+ }
1696
+
1697
+ /*
1698
+ Copyright 2019 Google LLC
1699
+ Use of this source code is governed by an MIT-style
1700
+ license that can be found in the LICENSE file or at
1701
+ https://opensource.org/licenses/MIT.
1702
+ */
1703
+ /**
1704
+ * Returns a promise that resolves and the passed number of milliseconds.
1705
+ * This utility is an async/await-friendly version of `setTimeout`.
1706
+ *
1707
+ * @param {number} ms
1708
+ * @return {Promise}
1709
+ * @private
1710
+ */
1711
+ function timeout(ms) {
1712
+ return new Promise(resolve => setTimeout(resolve, ms));
1713
+ }
1714
+
1715
+ // @ts-ignore
1716
+ try {
1717
+ self['workbox:strategies:7.3.0'] && _();
1718
+ } catch (e) {}
1719
+
1720
+ /*
1721
+ Copyright 2020 Google LLC
1722
+
1723
+ Use of this source code is governed by an MIT-style
1724
+ license that can be found in the LICENSE file or at
1725
+ https://opensource.org/licenses/MIT.
1726
+ */
1727
+ function toRequest(input) {
1728
+ return typeof input === 'string' ? new Request(input) : input;
1729
+ }
1730
+ /**
1731
+ * A class created every time a Strategy instance calls
1732
+ * {@link workbox-strategies.Strategy~handle} or
1733
+ * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and
1734
+ * cache actions around plugin callbacks and keeps track of when the strategy
1735
+ * is "done" (i.e. all added `event.waitUntil()` promises have resolved).
1736
+ *
1737
+ * @memberof workbox-strategies
1738
+ */
1739
+ class StrategyHandler {
1740
+ /**
1741
+ * Creates a new instance associated with the passed strategy and event
1742
+ * that's handling the request.
1743
+ *
1744
+ * The constructor also initializes the state that will be passed to each of
1745
+ * the plugins handling this request.
1746
+ *
1747
+ * @param {workbox-strategies.Strategy} strategy
1748
+ * @param {Object} options
1749
+ * @param {Request|string} options.request A request to run this strategy for.
1750
+ * @param {ExtendableEvent} options.event The event associated with the
1751
+ * request.
1752
+ * @param {URL} [options.url]
1753
+ * @param {*} [options.params] The return value from the
1754
+ * {@link workbox-routing~matchCallback} (if applicable).
1755
+ */
1756
+ constructor(strategy, options) {
1757
+ this._cacheKeys = {};
1758
+ /**
1759
+ * The request the strategy is performing (passed to the strategy's
1760
+ * `handle()` or `handleAll()` method).
1761
+ * @name request
1762
+ * @instance
1763
+ * @type {Request}
1764
+ * @memberof workbox-strategies.StrategyHandler
1765
+ */
1766
+ /**
1767
+ * The event associated with this request.
1768
+ * @name event
1769
+ * @instance
1770
+ * @type {ExtendableEvent}
1771
+ * @memberof workbox-strategies.StrategyHandler
1772
+ */
1773
+ /**
1774
+ * A `URL` instance of `request.url` (if passed to the strategy's
1775
+ * `handle()` or `handleAll()` method).
1776
+ * Note: the `url` param will be present if the strategy was invoked
1777
+ * from a workbox `Route` object.
1778
+ * @name url
1779
+ * @instance
1780
+ * @type {URL|undefined}
1781
+ * @memberof workbox-strategies.StrategyHandler
1782
+ */
1783
+ /**
1784
+ * A `param` value (if passed to the strategy's
1785
+ * `handle()` or `handleAll()` method).
1786
+ * Note: the `param` param will be present if the strategy was invoked
1787
+ * from a workbox `Route` object and the
1788
+ * {@link workbox-routing~matchCallback} returned
1789
+ * a truthy value (it will be that value).
1790
+ * @name params
1791
+ * @instance
1792
+ * @type {*|undefined}
1793
+ * @memberof workbox-strategies.StrategyHandler
1794
+ */
1795
+ {
1796
+ finalAssertExports.isInstance(options.event, ExtendableEvent, {
1797
+ moduleName: 'workbox-strategies',
1798
+ className: 'StrategyHandler',
1799
+ funcName: 'constructor',
1800
+ paramName: 'options.event'
1801
+ });
1802
+ }
1803
+ Object.assign(this, options);
1804
+ this.event = options.event;
1805
+ this._strategy = strategy;
1806
+ this._handlerDeferred = new Deferred();
1807
+ this._extendLifetimePromises = [];
1808
+ // Copy the plugins list (since it's mutable on the strategy),
1809
+ // so any mutations don't affect this handler instance.
1810
+ this._plugins = [...strategy.plugins];
1811
+ this._pluginStateMap = new Map();
1812
+ for (const plugin of this._plugins) {
1813
+ this._pluginStateMap.set(plugin, {});
1814
+ }
1815
+ this.event.waitUntil(this._handlerDeferred.promise);
1816
+ }
1817
+ /**
1818
+ * Fetches a given request (and invokes any applicable plugin callback
1819
+ * methods) using the `fetchOptions` (for non-navigation requests) and
1820
+ * `plugins` defined on the `Strategy` object.
1821
+ *
1822
+ * The following plugin lifecycle methods are invoked when using this method:
1823
+ * - `requestWillFetch()`
1824
+ * - `fetchDidSucceed()`
1825
+ * - `fetchDidFail()`
1826
+ *
1827
+ * @param {Request|string} input The URL or request to fetch.
1828
+ * @return {Promise<Response>}
1829
+ */
1830
+ async fetch(input) {
1831
+ const {
1832
+ event
1833
+ } = this;
1834
+ let request = toRequest(input);
1835
+ if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) {
1836
+ const possiblePreloadResponse = await event.preloadResponse;
1837
+ if (possiblePreloadResponse) {
1838
+ {
1839
+ logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`);
1840
+ }
1841
+ return possiblePreloadResponse;
1842
+ }
1843
+ }
1844
+ // If there is a fetchDidFail plugin, we need to save a clone of the
1845
+ // original request before it's either modified by a requestWillFetch
1846
+ // plugin or before the original request's body is consumed via fetch().
1847
+ const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null;
1848
+ try {
1849
+ for (const cb of this.iterateCallbacks('requestWillFetch')) {
1850
+ request = await cb({
1851
+ request: request.clone(),
1852
+ event
1853
+ });
1854
+ }
1855
+ } catch (err) {
1856
+ if (err instanceof Error) {
1857
+ throw new WorkboxError('plugin-error-request-will-fetch', {
1858
+ thrownErrorMessage: err.message
1859
+ });
1860
+ }
1861
+ }
1862
+ // The request can be altered by plugins with `requestWillFetch` making
1863
+ // the original request (most likely from a `fetch` event) different
1864
+ // from the Request we make. Pass both to `fetchDidFail` to aid debugging.
1865
+ const pluginFilteredRequest = request.clone();
1866
+ try {
1867
+ let fetchResponse;
1868
+ // See https://github.com/GoogleChrome/workbox/issues/1796
1869
+ fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions);
1870
+ if ("development" !== 'production') {
1871
+ logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`);
1872
+ }
1873
+ for (const callback of this.iterateCallbacks('fetchDidSucceed')) {
1874
+ fetchResponse = await callback({
1875
+ event,
1876
+ request: pluginFilteredRequest,
1877
+ response: fetchResponse
1878
+ });
1879
+ }
1880
+ return fetchResponse;
1881
+ } catch (error) {
1882
+ {
1883
+ logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error);
1884
+ }
1885
+ // `originalRequest` will only exist if a `fetchDidFail` callback
1886
+ // is being used (see above).
1887
+ if (originalRequest) {
1888
+ await this.runCallbacks('fetchDidFail', {
1889
+ error: error,
1890
+ event,
1891
+ originalRequest: originalRequest.clone(),
1892
+ request: pluginFilteredRequest.clone()
1893
+ });
1894
+ }
1895
+ throw error;
1896
+ }
1897
+ }
1898
+ /**
1899
+ * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on
1900
+ * the response generated by `this.fetch()`.
1901
+ *
1902
+ * The call to `this.cachePut()` automatically invokes `this.waitUntil()`,
1903
+ * so you do not have to manually call `waitUntil()` on the event.
1904
+ *
1905
+ * @param {Request|string} input The request or URL to fetch and cache.
1906
+ * @return {Promise<Response>}
1907
+ */
1908
+ async fetchAndCachePut(input) {
1909
+ const response = await this.fetch(input);
1910
+ const responseClone = response.clone();
1911
+ void this.waitUntil(this.cachePut(input, responseClone));
1912
+ return response;
1913
+ }
1914
+ /**
1915
+ * Matches a request from the cache (and invokes any applicable plugin
1916
+ * callback methods) using the `cacheName`, `matchOptions`, and `plugins`
1917
+ * defined on the strategy object.
1918
+ *
1919
+ * The following plugin lifecycle methods are invoked when using this method:
1920
+ * - cacheKeyWillBeUsed()
1921
+ * - cachedResponseWillBeUsed()
1922
+ *
1923
+ * @param {Request|string} key The Request or URL to use as the cache key.
1924
+ * @return {Promise<Response|undefined>} A matching response, if found.
1925
+ */
1926
+ async cacheMatch(key) {
1927
+ const request = toRequest(key);
1928
+ let cachedResponse;
1929
+ const {
1930
+ cacheName,
1931
+ matchOptions
1932
+ } = this._strategy;
1933
+ const effectiveRequest = await this.getCacheKey(request, 'read');
1934
+ const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), {
1935
+ cacheName
1936
+ });
1937
+ cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);
1938
+ {
1939
+ if (cachedResponse) {
1940
+ logger.debug(`Found a cached response in '${cacheName}'.`);
1941
+ } else {
1942
+ logger.debug(`No cached response found in '${cacheName}'.`);
1943
+ }
1944
+ }
1945
+ for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) {
1946
+ cachedResponse = (await callback({
1947
+ cacheName,
1948
+ matchOptions,
1949
+ cachedResponse,
1950
+ request: effectiveRequest,
1951
+ event: this.event
1952
+ })) || undefined;
1953
+ }
1954
+ return cachedResponse;
1955
+ }
1956
+ /**
1957
+ * Puts a request/response pair in the cache (and invokes any applicable
1958
+ * plugin callback methods) using the `cacheName` and `plugins` defined on
1959
+ * the strategy object.
1960
+ *
1961
+ * The following plugin lifecycle methods are invoked when using this method:
1962
+ * - cacheKeyWillBeUsed()
1963
+ * - cacheWillUpdate()
1964
+ * - cacheDidUpdate()
1965
+ *
1966
+ * @param {Request|string} key The request or URL to use as the cache key.
1967
+ * @param {Response} response The response to cache.
1968
+ * @return {Promise<boolean>} `false` if a cacheWillUpdate caused the response
1969
+ * not be cached, and `true` otherwise.
1970
+ */
1971
+ async cachePut(key, response) {
1972
+ const request = toRequest(key);
1973
+ // Run in the next task to avoid blocking other cache reads.
1974
+ // https://github.com/w3c/ServiceWorker/issues/1397
1975
+ await timeout(0);
1976
+ const effectiveRequest = await this.getCacheKey(request, 'write');
1977
+ {
1978
+ if (effectiveRequest.method && effectiveRequest.method !== 'GET') {
1979
+ throw new WorkboxError('attempt-to-cache-non-get-request', {
1980
+ url: getFriendlyURL(effectiveRequest.url),
1981
+ method: effectiveRequest.method
1982
+ });
1983
+ }
1984
+ // See https://github.com/GoogleChrome/workbox/issues/2818
1985
+ const vary = response.headers.get('Vary');
1986
+ if (vary) {
1987
+ 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.`);
1988
+ }
1989
+ }
1990
+ if (!response) {
1991
+ {
1992
+ logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`);
1993
+ }
1994
+ throw new WorkboxError('cache-put-with-no-response', {
1995
+ url: getFriendlyURL(effectiveRequest.url)
1996
+ });
1997
+ }
1998
+ const responseToCache = await this._ensureResponseSafeToCache(response);
1999
+ if (!responseToCache) {
2000
+ {
2001
+ logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache);
2002
+ }
2003
+ return false;
2004
+ }
2005
+ const {
2006
+ cacheName,
2007
+ matchOptions
2008
+ } = this._strategy;
2009
+ const cache = await self.caches.open(cacheName);
2010
+ const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate');
2011
+ const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams(
2012
+ // TODO(philipwalton): the `__WB_REVISION__` param is a precaching
2013
+ // feature. Consider into ways to only add this behavior if using
2014
+ // precaching.
2015
+ cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null;
2016
+ {
2017
+ logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`);
2018
+ }
2019
+ try {
2020
+ await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache);
2021
+ } catch (error) {
2022
+ if (error instanceof Error) {
2023
+ // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError
2024
+ if (error.name === 'QuotaExceededError') {
2025
+ await executeQuotaErrorCallbacks();
2026
+ }
2027
+ throw error;
2028
+ }
2029
+ }
2030
+ for (const callback of this.iterateCallbacks('cacheDidUpdate')) {
2031
+ await callback({
2032
+ cacheName,
2033
+ oldResponse,
2034
+ newResponse: responseToCache.clone(),
2035
+ request: effectiveRequest,
2036
+ event: this.event
2037
+ });
2038
+ }
2039
+ return true;
2040
+ }
2041
+ /**
2042
+ * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and
2043
+ * executes any of those callbacks found in sequence. The final `Request`
2044
+ * object returned by the last plugin is treated as the cache key for cache
2045
+ * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have
2046
+ * been registered, the passed request is returned unmodified
2047
+ *
2048
+ * @param {Request} request
2049
+ * @param {string} mode
2050
+ * @return {Promise<Request>}
2051
+ */
2052
+ async getCacheKey(request, mode) {
2053
+ const key = `${request.url} | ${mode}`;
2054
+ if (!this._cacheKeys[key]) {
2055
+ let effectiveRequest = request;
2056
+ for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) {
2057
+ effectiveRequest = toRequest(await callback({
2058
+ mode,
2059
+ request: effectiveRequest,
2060
+ event: this.event,
2061
+ // params has a type any can't change right now.
2062
+ params: this.params // eslint-disable-line
2063
+ }));
2064
+ }
2065
+ this._cacheKeys[key] = effectiveRequest;
2066
+ }
2067
+ return this._cacheKeys[key];
2068
+ }
2069
+ /**
2070
+ * Returns true if the strategy has at least one plugin with the given
2071
+ * callback.
2072
+ *
2073
+ * @param {string} name The name of the callback to check for.
2074
+ * @return {boolean}
2075
+ */
2076
+ hasCallback(name) {
2077
+ for (const plugin of this._strategy.plugins) {
2078
+ if (name in plugin) {
2079
+ return true;
2080
+ }
2081
+ }
2082
+ return false;
2083
+ }
2084
+ /**
2085
+ * Runs all plugin callbacks matching the given name, in order, passing the
2086
+ * given param object (merged ith the current plugin state) as the only
2087
+ * argument.
2088
+ *
2089
+ * Note: since this method runs all plugins, it's not suitable for cases
2090
+ * where the return value of a callback needs to be applied prior to calling
2091
+ * the next callback. See
2092
+ * {@link workbox-strategies.StrategyHandler#iterateCallbacks}
2093
+ * below for how to handle that case.
2094
+ *
2095
+ * @param {string} name The name of the callback to run within each plugin.
2096
+ * @param {Object} param The object to pass as the first (and only) param
2097
+ * when executing each callback. This object will be merged with the
2098
+ * current plugin state prior to callback execution.
2099
+ */
2100
+ async runCallbacks(name, param) {
2101
+ for (const callback of this.iterateCallbacks(name)) {
2102
+ // TODO(philipwalton): not sure why `any` is needed. It seems like
2103
+ // this should work with `as WorkboxPluginCallbackParam[C]`.
2104
+ await callback(param);
2105
+ }
2106
+ }
2107
+ /**
2108
+ * Accepts a callback and returns an iterable of matching plugin callbacks,
2109
+ * where each callback is wrapped with the current handler state (i.e. when
2110
+ * you call each callback, whatever object parameter you pass it will
2111
+ * be merged with the plugin's current state).
2112
+ *
2113
+ * @param {string} name The name fo the callback to run
2114
+ * @return {Array<Function>}
2115
+ */
2116
+ *iterateCallbacks(name) {
2117
+ for (const plugin of this._strategy.plugins) {
2118
+ if (typeof plugin[name] === 'function') {
2119
+ const state = this._pluginStateMap.get(plugin);
2120
+ const statefulCallback = param => {
2121
+ const statefulParam = Object.assign(Object.assign({}, param), {
2122
+ state
2123
+ });
2124
+ // TODO(philipwalton): not sure why `any` is needed. It seems like
2125
+ // this should work with `as WorkboxPluginCallbackParam[C]`.
2126
+ return plugin[name](statefulParam);
2127
+ };
2128
+ yield statefulCallback;
2129
+ }
2130
+ }
2131
+ }
2132
+ /**
2133
+ * Adds a promise to the
2134
+ * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises}
2135
+ * of the event associated with the request being handled (usually a
2136
+ * `FetchEvent`).
2137
+ *
2138
+ * Note: you can await
2139
+ * {@link workbox-strategies.StrategyHandler~doneWaiting}
2140
+ * to know when all added promises have settled.
2141
+ *
2142
+ * @param {Promise} promise A promise to add to the extend lifetime promises
2143
+ * of the event that triggered the request.
2144
+ */
2145
+ waitUntil(promise) {
2146
+ this._extendLifetimePromises.push(promise);
2147
+ return promise;
2148
+ }
2149
+ /**
2150
+ * Returns a promise that resolves once all promises passed to
2151
+ * {@link workbox-strategies.StrategyHandler~waitUntil}
2152
+ * have settled.
2153
+ *
2154
+ * Note: any work done after `doneWaiting()` settles should be manually
2155
+ * passed to an event's `waitUntil()` method (not this handler's
2156
+ * `waitUntil()` method), otherwise the service worker thread may be killed
2157
+ * prior to your work completing.
2158
+ */
2159
+ async doneWaiting() {
2160
+ while (this._extendLifetimePromises.length) {
2161
+ const promises = this._extendLifetimePromises.splice(0);
2162
+ const result = await Promise.allSettled(promises);
2163
+ const firstRejection = result.find(i => i.status === 'rejected');
2164
+ if (firstRejection) {
2165
+ throw firstRejection.reason;
2166
+ }
2167
+ }
2168
+ }
2169
+ /**
2170
+ * Stops running the strategy and immediately resolves any pending
2171
+ * `waitUntil()` promises.
2172
+ */
2173
+ destroy() {
2174
+ this._handlerDeferred.resolve(null);
2175
+ }
2176
+ /**
2177
+ * This method will call cacheWillUpdate on the available plugins (or use
2178
+ * status === 200) to determine if the Response is safe and valid to cache.
2179
+ *
2180
+ * @param {Request} options.request
2181
+ * @param {Response} options.response
2182
+ * @return {Promise<Response|undefined>}
2183
+ *
2184
+ * @private
2185
+ */
2186
+ async _ensureResponseSafeToCache(response) {
2187
+ let responseToCache = response;
2188
+ let pluginsUsed = false;
2189
+ for (const callback of this.iterateCallbacks('cacheWillUpdate')) {
2190
+ responseToCache = (await callback({
2191
+ request: this.request,
2192
+ response: responseToCache,
2193
+ event: this.event
2194
+ })) || undefined;
2195
+ pluginsUsed = true;
2196
+ if (!responseToCache) {
2197
+ break;
2198
+ }
2199
+ }
2200
+ if (!pluginsUsed) {
2201
+ if (responseToCache && responseToCache.status !== 200) {
2202
+ responseToCache = undefined;
2203
+ }
2204
+ {
2205
+ if (responseToCache) {
2206
+ if (responseToCache.status !== 200) {
2207
+ if (responseToCache.status === 0) {
2208
+ 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.`);
2209
+ } else {
2210
+ logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`);
2211
+ }
2212
+ }
2213
+ }
2214
+ }
2215
+ }
2216
+ return responseToCache;
2217
+ }
2218
+ }
2219
+
2220
+ /*
2221
+ Copyright 2020 Google LLC
2222
+
2223
+ Use of this source code is governed by an MIT-style
2224
+ license that can be found in the LICENSE file or at
2225
+ https://opensource.org/licenses/MIT.
2226
+ */
2227
+ /**
2228
+ * An abstract base class that all other strategy classes must extend from:
2229
+ *
2230
+ * @memberof workbox-strategies
2231
+ */
2232
+ class Strategy {
2233
+ /**
2234
+ * Creates a new instance of the strategy and sets all documented option
2235
+ * properties as public instance properties.
2236
+ *
2237
+ * Note: if a custom strategy class extends the base Strategy class and does
2238
+ * not need more than these properties, it does not need to define its own
2239
+ * constructor.
2240
+ *
2241
+ * @param {Object} [options]
2242
+ * @param {string} [options.cacheName] Cache name to store and retrieve
2243
+ * requests. Defaults to the cache names provided by
2244
+ * {@link workbox-core.cacheNames}.
2245
+ * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
2246
+ * to use in conjunction with this caching strategy.
2247
+ * @param {Object} [options.fetchOptions] Values passed along to the
2248
+ * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
2249
+ * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
2250
+ * `fetch()` requests made by this strategy.
2251
+ * @param {Object} [options.matchOptions] The
2252
+ * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}
2253
+ * for any `cache.match()` or `cache.put()` calls made by this strategy.
2254
+ */
2255
+ constructor(options = {}) {
2256
+ /**
2257
+ * Cache name to store and retrieve
2258
+ * requests. Defaults to the cache names provided by
2259
+ * {@link workbox-core.cacheNames}.
2260
+ *
2261
+ * @type {string}
2262
+ */
2263
+ this.cacheName = cacheNames.getRuntimeName(options.cacheName);
2264
+ /**
2265
+ * The list
2266
+ * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
2267
+ * used by this strategy.
2268
+ *
2269
+ * @type {Array<Object>}
2270
+ */
2271
+ this.plugins = options.plugins || [];
2272
+ /**
2273
+ * Values passed along to the
2274
+ * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters}
2275
+ * of all fetch() requests made by this strategy.
2276
+ *
2277
+ * @type {Object}
2278
+ */
2279
+ this.fetchOptions = options.fetchOptions;
2280
+ /**
2281
+ * The
2282
+ * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}
2283
+ * for any `cache.match()` or `cache.put()` calls made by this strategy.
2284
+ *
2285
+ * @type {Object}
2286
+ */
2287
+ this.matchOptions = options.matchOptions;
2288
+ }
2289
+ /**
2290
+ * Perform a request strategy and returns a `Promise` that will resolve with
2291
+ * a `Response`, invoking all relevant plugin callbacks.
2292
+ *
2293
+ * When a strategy instance is registered with a Workbox
2294
+ * {@link workbox-routing.Route}, this method is automatically
2295
+ * called when the route matches.
2296
+ *
2297
+ * Alternatively, this method can be used in a standalone `FetchEvent`
2298
+ * listener by passing it to `event.respondWith()`.
2299
+ *
2300
+ * @param {FetchEvent|Object} options A `FetchEvent` or an object with the
2301
+ * properties listed below.
2302
+ * @param {Request|string} options.request A request to run this strategy for.
2303
+ * @param {ExtendableEvent} options.event The event associated with the
2304
+ * request.
2305
+ * @param {URL} [options.url]
2306
+ * @param {*} [options.params]
2307
+ */
2308
+ handle(options) {
2309
+ const [responseDone] = this.handleAll(options);
2310
+ return responseDone;
2311
+ }
2312
+ /**
2313
+ * Similar to {@link workbox-strategies.Strategy~handle}, but
2314
+ * instead of just returning a `Promise` that resolves to a `Response` it
2315
+ * it will return an tuple of `[response, done]` promises, where the former
2316
+ * (`response`) is equivalent to what `handle()` returns, and the latter is a
2317
+ * Promise that will resolve once any promises that were added to
2318
+ * `event.waitUntil()` as part of performing the strategy have completed.
2319
+ *
2320
+ * You can await the `done` promise to ensure any extra work performed by
2321
+ * the strategy (usually caching responses) completes successfully.
2322
+ *
2323
+ * @param {FetchEvent|Object} options A `FetchEvent` or an object with the
2324
+ * properties listed below.
2325
+ * @param {Request|string} options.request A request to run this strategy for.
2326
+ * @param {ExtendableEvent} options.event The event associated with the
2327
+ * request.
2328
+ * @param {URL} [options.url]
2329
+ * @param {*} [options.params]
2330
+ * @return {Array<Promise>} A tuple of [response, done]
2331
+ * promises that can be used to determine when the response resolves as
2332
+ * well as when the handler has completed all its work.
2333
+ */
2334
+ handleAll(options) {
2335
+ // Allow for flexible options to be passed.
2336
+ if (options instanceof FetchEvent) {
2337
+ options = {
2338
+ event: options,
2339
+ request: options.request
2340
+ };
2341
+ }
2342
+ const event = options.event;
2343
+ const request = typeof options.request === 'string' ? new Request(options.request) : options.request;
2344
+ const params = 'params' in options ? options.params : undefined;
2345
+ const handler = new StrategyHandler(this, {
2346
+ event,
2347
+ request,
2348
+ params
2349
+ });
2350
+ const responseDone = this._getResponse(handler, request, event);
2351
+ const handlerDone = this._awaitComplete(responseDone, handler, request, event);
2352
+ // Return an array of promises, suitable for use with Promise.all().
2353
+ return [responseDone, handlerDone];
2354
+ }
2355
+ async _getResponse(handler, request, event) {
2356
+ await handler.runCallbacks('handlerWillStart', {
2357
+ event,
2358
+ request
2359
+ });
2360
+ let response = undefined;
2361
+ try {
2362
+ response = await this._handle(request, handler);
2363
+ // The "official" Strategy subclasses all throw this error automatically,
2364
+ // but in case a third-party Strategy doesn't, ensure that we have a
2365
+ // consistent failure when there's no response or an error response.
2366
+ if (!response || response.type === 'error') {
2367
+ throw new WorkboxError('no-response', {
2368
+ url: request.url
2369
+ });
2370
+ }
2371
+ } catch (error) {
2372
+ if (error instanceof Error) {
2373
+ for (const callback of handler.iterateCallbacks('handlerDidError')) {
2374
+ response = await callback({
2375
+ error,
2376
+ event,
2377
+ request
2378
+ });
2379
+ if (response) {
2380
+ break;
2381
+ }
2382
+ }
2383
+ }
2384
+ if (!response) {
2385
+ throw error;
2386
+ } else {
2387
+ 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.`);
2388
+ }
2389
+ }
2390
+ for (const callback of handler.iterateCallbacks('handlerWillRespond')) {
2391
+ response = await callback({
2392
+ event,
2393
+ request,
2394
+ response
2395
+ });
2396
+ }
2397
+ return response;
2398
+ }
2399
+ async _awaitComplete(responseDone, handler, request, event) {
2400
+ let response;
2401
+ let error;
2402
+ try {
2403
+ response = await responseDone;
2404
+ } catch (error) {
2405
+ // Ignore errors, as response errors should be caught via the `response`
2406
+ // promise above. The `done` promise will only throw for errors in
2407
+ // promises passed to `handler.waitUntil()`.
2408
+ }
2409
+ try {
2410
+ await handler.runCallbacks('handlerDidRespond', {
2411
+ event,
2412
+ request,
2413
+ response
2414
+ });
2415
+ await handler.doneWaiting();
2416
+ } catch (waitUntilError) {
2417
+ if (waitUntilError instanceof Error) {
2418
+ error = waitUntilError;
2419
+ }
2420
+ }
2421
+ await handler.runCallbacks('handlerDidComplete', {
2422
+ event,
2423
+ request,
2424
+ response,
2425
+ error: error
2426
+ });
2427
+ handler.destroy();
2428
+ if (error) {
2429
+ throw error;
2430
+ }
2431
+ }
2432
+ }
2433
+ /**
2434
+ * Classes extending the `Strategy` based class should implement this method,
2435
+ * and leverage the {@link workbox-strategies.StrategyHandler}
2436
+ * arg to perform all fetching and cache logic, which will ensure all relevant
2437
+ * cache, cache options, fetch options and plugins are used (per the current
2438
+ * strategy instance).
2439
+ *
2440
+ * @name _handle
2441
+ * @instance
2442
+ * @abstract
2443
+ * @function
2444
+ * @param {Request} request
2445
+ * @param {workbox-strategies.StrategyHandler} handler
2446
+ * @return {Promise<Response>}
2447
+ *
2448
+ * @memberof workbox-strategies.Strategy
2449
+ */
2450
+
2451
+ /*
2452
+ Copyright 2020 Google LLC
2453
+
2454
+ Use of this source code is governed by an MIT-style
2455
+ license that can be found in the LICENSE file or at
2456
+ https://opensource.org/licenses/MIT.
2457
+ */
2458
+ /**
2459
+ * A {@link workbox-strategies.Strategy} implementation
2460
+ * specifically designed to work with
2461
+ * {@link workbox-precaching.PrecacheController}
2462
+ * to both cache and fetch precached assets.
2463
+ *
2464
+ * Note: an instance of this class is created automatically when creating a
2465
+ * `PrecacheController`; it's generally not necessary to create this yourself.
2466
+ *
2467
+ * @extends workbox-strategies.Strategy
2468
+ * @memberof workbox-precaching
2469
+ */
2470
+ class PrecacheStrategy extends Strategy {
2471
+ /**
2472
+ *
2473
+ * @param {Object} [options]
2474
+ * @param {string} [options.cacheName] Cache name to store and retrieve
2475
+ * requests. Defaults to the cache names provided by
2476
+ * {@link workbox-core.cacheNames}.
2477
+ * @param {Array<Object>} [options.plugins] {@link https://developers.google.com/web/tools/workbox/guides/using-plugins|Plugins}
2478
+ * to use in conjunction with this caching strategy.
2479
+ * @param {Object} [options.fetchOptions] Values passed along to the
2480
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters|init}
2481
+ * of all fetch() requests made by this strategy.
2482
+ * @param {Object} [options.matchOptions] The
2483
+ * {@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions|CacheQueryOptions}
2484
+ * for any `cache.match()` or `cache.put()` calls made by this strategy.
2485
+ * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to
2486
+ * get the response from the network if there's a precache miss.
2487
+ */
2488
+ constructor(options = {}) {
2489
+ options.cacheName = cacheNames.getPrecacheName(options.cacheName);
2490
+ super(options);
2491
+ this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true;
2492
+ // Redirected responses cannot be used to satisfy a navigation request, so
2493
+ // any redirected response must be "copied" rather than cloned, so the new
2494
+ // response doesn't contain the `redirected` flag. See:
2495
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1
2496
+ this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);
2497
+ }
2498
+ /**
2499
+ * @private
2500
+ * @param {Request|string} request A request to run this strategy for.
2501
+ * @param {workbox-strategies.StrategyHandler} handler The event that
2502
+ * triggered the request.
2503
+ * @return {Promise<Response>}
2504
+ */
2505
+ async _handle(request, handler) {
2506
+ const response = await handler.cacheMatch(request);
2507
+ if (response) {
2508
+ return response;
2509
+ }
2510
+ // If this is an `install` event for an entry that isn't already cached,
2511
+ // then populate the cache.
2512
+ if (handler.event && handler.event.type === 'install') {
2513
+ return await this._handleInstall(request, handler);
2514
+ }
2515
+ // Getting here means something went wrong. An entry that should have been
2516
+ // precached wasn't found in the cache.
2517
+ return await this._handleFetch(request, handler);
2518
+ }
2519
+ async _handleFetch(request, handler) {
2520
+ let response;
2521
+ const params = handler.params || {};
2522
+ // Fall back to the network if we're configured to do so.
2523
+ if (this._fallbackToNetwork) {
2524
+ {
2525
+ logger.warn(`The precached response for ` + `${getFriendlyURL(request.url)} in ${this.cacheName} was not ` + `found. Falling back to the network.`);
2526
+ }
2527
+ const integrityInManifest = params.integrity;
2528
+ const integrityInRequest = request.integrity;
2529
+ const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest;
2530
+ // Do not add integrity if the original request is no-cors
2531
+ // See https://github.com/GoogleChrome/workbox/issues/3096
2532
+ response = await handler.fetch(new Request(request, {
2533
+ integrity: request.mode !== 'no-cors' ? integrityInRequest || integrityInManifest : undefined
2534
+ }));
2535
+ // It's only "safe" to repair the cache if we're using SRI to guarantee
2536
+ // that the response matches the precache manifest's expectations,
2537
+ // and there's either a) no integrity property in the incoming request
2538
+ // or b) there is an integrity, and it matches the precache manifest.
2539
+ // See https://github.com/GoogleChrome/workbox/issues/2858
2540
+ // Also if the original request users no-cors we don't use integrity.
2541
+ // See https://github.com/GoogleChrome/workbox/issues/3096
2542
+ if (integrityInManifest && noIntegrityConflict && request.mode !== 'no-cors') {
2543
+ this._useDefaultCacheabilityPluginIfNeeded();
2544
+ const wasCached = await handler.cachePut(request, response.clone());
2545
+ {
2546
+ if (wasCached) {
2547
+ logger.log(`A response for ${getFriendlyURL(request.url)} ` + `was used to "repair" the precache.`);
2548
+ }
2549
+ }
2550
+ }
2551
+ } else {
2552
+ // This shouldn't normally happen, but there are edge cases:
2553
+ // https://github.com/GoogleChrome/workbox/issues/1441
2554
+ throw new WorkboxError('missing-precache-entry', {
2555
+ cacheName: this.cacheName,
2556
+ url: request.url
2557
+ });
2558
+ }
2559
+ {
2560
+ const cacheKey = params.cacheKey || (await handler.getCacheKey(request, 'read'));
2561
+ // Workbox is going to handle the route.
2562
+ // print the routing details to the console.
2563
+ logger.groupCollapsed(`Precaching is responding to: ` + getFriendlyURL(request.url));
2564
+ logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`);
2565
+ logger.groupCollapsed(`View request details here.`);
2566
+ logger.log(request);
2567
+ logger.groupEnd();
2568
+ logger.groupCollapsed(`View response details here.`);
2569
+ logger.log(response);
2570
+ logger.groupEnd();
2571
+ logger.groupEnd();
2572
+ }
2573
+ return response;
2574
+ }
2575
+ async _handleInstall(request, handler) {
2576
+ this._useDefaultCacheabilityPluginIfNeeded();
2577
+ const response = await handler.fetch(request);
2578
+ // Make sure we defer cachePut() until after we know the response
2579
+ // should be cached; see https://github.com/GoogleChrome/workbox/issues/2737
2580
+ const wasCached = await handler.cachePut(request, response.clone());
2581
+ if (!wasCached) {
2582
+ // Throwing here will lead to the `install` handler failing, which
2583
+ // we want to do if *any* of the responses aren't safe to cache.
2584
+ throw new WorkboxError('bad-precaching-response', {
2585
+ url: request.url,
2586
+ status: response.status
2587
+ });
2588
+ }
2589
+ return response;
2590
+ }
2591
+ /**
2592
+ * This method is complex, as there a number of things to account for:
2593
+ *
2594
+ * The `plugins` array can be set at construction, and/or it might be added to
2595
+ * to at any time before the strategy is used.
2596
+ *
2597
+ * At the time the strategy is used (i.e. during an `install` event), there
2598
+ * needs to be at least one plugin that implements `cacheWillUpdate` in the
2599
+ * array, other than `copyRedirectedCacheableResponsesPlugin`.
2600
+ *
2601
+ * - If this method is called and there are no suitable `cacheWillUpdate`
2602
+ * plugins, we need to add `defaultPrecacheCacheabilityPlugin`.
2603
+ *
2604
+ * - If this method is called and there is exactly one `cacheWillUpdate`, then
2605
+ * we don't have to do anything (this might be a previously added
2606
+ * `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin).
2607
+ *
2608
+ * - If this method is called and there is more than one `cacheWillUpdate`,
2609
+ * then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so,
2610
+ * we need to remove it. (This situation is unlikely, but it could happen if
2611
+ * the strategy is used multiple times, the first without a `cacheWillUpdate`,
2612
+ * and then later on after manually adding a custom `cacheWillUpdate`.)
2613
+ *
2614
+ * See https://github.com/GoogleChrome/workbox/issues/2737 for more context.
2615
+ *
2616
+ * @private
2617
+ */
2618
+ _useDefaultCacheabilityPluginIfNeeded() {
2619
+ let defaultPluginIndex = null;
2620
+ let cacheWillUpdatePluginCount = 0;
2621
+ for (const [index, plugin] of this.plugins.entries()) {
2622
+ // Ignore the copy redirected plugin when determining what to do.
2623
+ if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) {
2624
+ continue;
2625
+ }
2626
+ // Save the default plugin's index, in case it needs to be removed.
2627
+ if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
2628
+ defaultPluginIndex = index;
2629
+ }
2630
+ if (plugin.cacheWillUpdate) {
2631
+ cacheWillUpdatePluginCount++;
2632
+ }
2633
+ }
2634
+ if (cacheWillUpdatePluginCount === 0) {
2635
+ this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);
2636
+ } else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {
2637
+ // Only remove the default plugin; multiple custom plugins are allowed.
2638
+ this.plugins.splice(defaultPluginIndex, 1);
2639
+ }
2640
+ // Nothing needs to be done if cacheWillUpdatePluginCount is 1
2641
+ }
2642
+ }
2643
+ PrecacheStrategy.defaultPrecacheCacheabilityPlugin = {
2644
+ async cacheWillUpdate({
2645
+ response
2646
+ }) {
2647
+ if (!response || response.status >= 400) {
2648
+ return null;
2649
+ }
2650
+ return response;
2651
+ }
2652
+ };
2653
+ PrecacheStrategy.copyRedirectedCacheableResponsesPlugin = {
2654
+ async cacheWillUpdate({
2655
+ response
2656
+ }) {
2657
+ return response.redirected ? await copyResponse(response) : response;
2658
+ }
2659
+ };
2660
+
2661
+ /*
2662
+ Copyright 2019 Google LLC
2663
+
2664
+ Use of this source code is governed by an MIT-style
2665
+ license that can be found in the LICENSE file or at
2666
+ https://opensource.org/licenses/MIT.
2667
+ */
2668
+ /**
2669
+ * Performs efficient precaching of assets.
2670
+ *
2671
+ * @memberof workbox-precaching
2672
+ */
2673
+ class PrecacheController {
2674
+ /**
2675
+ * Create a new PrecacheController.
2676
+ *
2677
+ * @param {Object} [options]
2678
+ * @param {string} [options.cacheName] The cache to use for precaching.
2679
+ * @param {string} [options.plugins] Plugins to use when precaching as well
2680
+ * as responding to fetch events for precached assets.
2681
+ * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to
2682
+ * get the response from the network if there's a precache miss.
2683
+ */
2684
+ constructor({
2685
+ cacheName,
2686
+ plugins = [],
2687
+ fallbackToNetwork = true
2688
+ } = {}) {
2689
+ this._urlsToCacheKeys = new Map();
2690
+ this._urlsToCacheModes = new Map();
2691
+ this._cacheKeysToIntegrities = new Map();
2692
+ this._strategy = new PrecacheStrategy({
2693
+ cacheName: cacheNames.getPrecacheName(cacheName),
2694
+ plugins: [...plugins, new PrecacheCacheKeyPlugin({
2695
+ precacheController: this
2696
+ })],
2697
+ fallbackToNetwork
2698
+ });
2699
+ // Bind the install and activate methods to the instance.
2700
+ this.install = this.install.bind(this);
2701
+ this.activate = this.activate.bind(this);
2702
+ }
2703
+ /**
2704
+ * @type {workbox-precaching.PrecacheStrategy} The strategy created by this controller and
2705
+ * used to cache assets and respond to fetch events.
2706
+ */
2707
+ get strategy() {
2708
+ return this._strategy;
2709
+ }
2710
+ /**
2711
+ * Adds items to the precache list, removing any duplicates and
2712
+ * stores the files in the
2713
+ * {@link workbox-core.cacheNames|"precache cache"} when the service
2714
+ * worker installs.
2715
+ *
2716
+ * This method can be called multiple times.
2717
+ *
2718
+ * @param {Array<Object|string>} [entries=[]] Array of entries to precache.
2719
+ */
2720
+ precache(entries) {
2721
+ this.addToCacheList(entries);
2722
+ if (!this._installAndActiveListenersAdded) {
2723
+ self.addEventListener('install', this.install);
2724
+ self.addEventListener('activate', this.activate);
2725
+ this._installAndActiveListenersAdded = true;
2726
+ }
2727
+ }
2728
+ /**
2729
+ * This method will add items to the precache list, removing duplicates
2730
+ * and ensuring the information is valid.
2731
+ *
2732
+ * @param {Array<workbox-precaching.PrecacheController.PrecacheEntry|string>} entries
2733
+ * Array of entries to precache.
2734
+ */
2735
+ addToCacheList(entries) {
2736
+ {
2737
+ finalAssertExports.isArray(entries, {
2738
+ moduleName: 'workbox-precaching',
2739
+ className: 'PrecacheController',
2740
+ funcName: 'addToCacheList',
2741
+ paramName: 'entries'
2742
+ });
2743
+ }
2744
+ const urlsToWarnAbout = [];
2745
+ for (const entry of entries) {
2746
+ // See https://github.com/GoogleChrome/workbox/issues/2259
2747
+ if (typeof entry === 'string') {
2748
+ urlsToWarnAbout.push(entry);
2749
+ } else if (entry && entry.revision === undefined) {
2750
+ urlsToWarnAbout.push(entry.url);
2751
+ }
2752
+ const {
2753
+ cacheKey,
2754
+ url
2755
+ } = createCacheKey(entry);
2756
+ const cacheMode = typeof entry !== 'string' && entry.revision ? 'reload' : 'default';
2757
+ if (this._urlsToCacheKeys.has(url) && this._urlsToCacheKeys.get(url) !== cacheKey) {
2758
+ throw new WorkboxError('add-to-cache-list-conflicting-entries', {
2759
+ firstEntry: this._urlsToCacheKeys.get(url),
2760
+ secondEntry: cacheKey
2761
+ });
2762
+ }
2763
+ if (typeof entry !== 'string' && entry.integrity) {
2764
+ if (this._cacheKeysToIntegrities.has(cacheKey) && this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) {
2765
+ throw new WorkboxError('add-to-cache-list-conflicting-integrities', {
2766
+ url
2767
+ });
2768
+ }
2769
+ this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);
2770
+ }
2771
+ this._urlsToCacheKeys.set(url, cacheKey);
2772
+ this._urlsToCacheModes.set(url, cacheMode);
2773
+ if (urlsToWarnAbout.length > 0) {
2774
+ const warningMessage = `Workbox is precaching URLs without revision ` + `info: ${urlsToWarnAbout.join(', ')}\nThis is generally NOT safe. ` + `Learn more at https://bit.ly/wb-precache`;
2775
+ {
2776
+ logger.warn(warningMessage);
2777
+ }
2778
+ }
2779
+ }
2780
+ }
2781
+ /**
2782
+ * Precaches new and updated assets. Call this method from the service worker
2783
+ * install event.
2784
+ *
2785
+ * Note: this method calls `event.waitUntil()` for you, so you do not need
2786
+ * to call it yourself in your event handlers.
2787
+ *
2788
+ * @param {ExtendableEvent} event
2789
+ * @return {Promise<workbox-precaching.InstallResult>}
2790
+ */
2791
+ install(event) {
2792
+ // waitUntil returns Promise<any>
2793
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
2794
+ return waitUntil(event, async () => {
2795
+ const installReportPlugin = new PrecacheInstallReportPlugin();
2796
+ this.strategy.plugins.push(installReportPlugin);
2797
+ // Cache entries one at a time.
2798
+ // See https://github.com/GoogleChrome/workbox/issues/2528
2799
+ for (const [url, cacheKey] of this._urlsToCacheKeys) {
2800
+ const integrity = this._cacheKeysToIntegrities.get(cacheKey);
2801
+ const cacheMode = this._urlsToCacheModes.get(url);
2802
+ const request = new Request(url, {
2803
+ integrity,
2804
+ cache: cacheMode,
2805
+ credentials: 'same-origin'
2806
+ });
2807
+ await Promise.all(this.strategy.handleAll({
2808
+ params: {
2809
+ cacheKey
2810
+ },
2811
+ request,
2812
+ event
2813
+ }));
2814
+ }
2815
+ const {
2816
+ updatedURLs,
2817
+ notUpdatedURLs
2818
+ } = installReportPlugin;
2819
+ {
2820
+ printInstallDetails(updatedURLs, notUpdatedURLs);
2821
+ }
2822
+ return {
2823
+ updatedURLs,
2824
+ notUpdatedURLs
2825
+ };
2826
+ });
2827
+ }
2828
+ /**
2829
+ * Deletes assets that are no longer present in the current precache manifest.
2830
+ * Call this method from the service worker activate event.
2831
+ *
2832
+ * Note: this method calls `event.waitUntil()` for you, so you do not need
2833
+ * to call it yourself in your event handlers.
2834
+ *
2835
+ * @param {ExtendableEvent} event
2836
+ * @return {Promise<workbox-precaching.CleanupResult>}
2837
+ */
2838
+ activate(event) {
2839
+ // waitUntil returns Promise<any>
2840
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
2841
+ return waitUntil(event, async () => {
2842
+ const cache = await self.caches.open(this.strategy.cacheName);
2843
+ const currentlyCachedRequests = await cache.keys();
2844
+ const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());
2845
+ const deletedURLs = [];
2846
+ for (const request of currentlyCachedRequests) {
2847
+ if (!expectedCacheKeys.has(request.url)) {
2848
+ await cache.delete(request);
2849
+ deletedURLs.push(request.url);
2850
+ }
2851
+ }
2852
+ {
2853
+ printCleanupDetails(deletedURLs);
2854
+ }
2855
+ return {
2856
+ deletedURLs
2857
+ };
2858
+ });
2859
+ }
2860
+ /**
2861
+ * Returns a mapping of a precached URL to the corresponding cache key, taking
2862
+ * into account the revision information for the URL.
2863
+ *
2864
+ * @return {Map<string, string>} A URL to cache key mapping.
2865
+ */
2866
+ getURLsToCacheKeys() {
2867
+ return this._urlsToCacheKeys;
2868
+ }
2869
+ /**
2870
+ * Returns a list of all the URLs that have been precached by the current
2871
+ * service worker.
2872
+ *
2873
+ * @return {Array<string>} The precached URLs.
2874
+ */
2875
+ getCachedURLs() {
2876
+ return [...this._urlsToCacheKeys.keys()];
2877
+ }
2878
+ /**
2879
+ * Returns the cache key used for storing a given URL. If that URL is
2880
+ * unversioned, like `/index.html', then the cache key will be the original
2881
+ * URL with a search parameter appended to it.
2882
+ *
2883
+ * @param {string} url A URL whose cache key you want to look up.
2884
+ * @return {string} The versioned URL that corresponds to a cache key
2885
+ * for the original URL, or undefined if that URL isn't precached.
2886
+ */
2887
+ getCacheKeyForURL(url) {
2888
+ const urlObject = new URL(url, location.href);
2889
+ return this._urlsToCacheKeys.get(urlObject.href);
2890
+ }
2891
+ /**
2892
+ * @param {string} url A cache key whose SRI you want to look up.
2893
+ * @return {string} The subresource integrity associated with the cache key,
2894
+ * or undefined if it's not set.
2895
+ */
2896
+ getIntegrityForCacheKey(cacheKey) {
2897
+ return this._cacheKeysToIntegrities.get(cacheKey);
2898
+ }
2899
+ /**
2900
+ * This acts as a drop-in replacement for
2901
+ * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)
2902
+ * with the following differences:
2903
+ *
2904
+ * - It knows what the name of the precache is, and only checks in that cache.
2905
+ * - It allows you to pass in an "original" URL without versioning parameters,
2906
+ * and it will automatically look up the correct cache key for the currently
2907
+ * active revision of that URL.
2908
+ *
2909
+ * E.g., `matchPrecache('index.html')` will find the correct precached
2910
+ * response for the currently active service worker, even if the actual cache
2911
+ * key is `'/index.html?__WB_REVISION__=1234abcd'`.
2912
+ *
2913
+ * @param {string|Request} request The key (without revisioning parameters)
2914
+ * to look up in the precache.
2915
+ * @return {Promise<Response|undefined>}
2916
+ */
2917
+ async matchPrecache(request) {
2918
+ const url = request instanceof Request ? request.url : request;
2919
+ const cacheKey = this.getCacheKeyForURL(url);
2920
+ if (cacheKey) {
2921
+ const cache = await self.caches.open(this.strategy.cacheName);
2922
+ return cache.match(cacheKey);
2923
+ }
2924
+ return undefined;
2925
+ }
2926
+ /**
2927
+ * Returns a function that looks up `url` in the precache (taking into
2928
+ * account revision information), and returns the corresponding `Response`.
2929
+ *
2930
+ * @param {string} url The precached URL which will be used to lookup the
2931
+ * `Response`.
2932
+ * @return {workbox-routing~handlerCallback}
2933
+ */
2934
+ createHandlerBoundToURL(url) {
2935
+ const cacheKey = this.getCacheKeyForURL(url);
2936
+ if (!cacheKey) {
2937
+ throw new WorkboxError('non-precached-url', {
2938
+ url
2939
+ });
2940
+ }
2941
+ return options => {
2942
+ options.request = new Request(url);
2943
+ options.params = Object.assign({
2944
+ cacheKey
2945
+ }, options.params);
2946
+ return this.strategy.handle(options);
2947
+ };
2948
+ }
2949
+ }
2950
+
2951
+ /*
2952
+ Copyright 2019 Google LLC
2953
+
2954
+ Use of this source code is governed by an MIT-style
2955
+ license that can be found in the LICENSE file or at
2956
+ https://opensource.org/licenses/MIT.
2957
+ */
2958
+ let precacheController;
2959
+ /**
2960
+ * @return {PrecacheController}
2961
+ * @private
2962
+ */
2963
+ const getOrCreatePrecacheController = () => {
2964
+ if (!precacheController) {
2965
+ precacheController = new PrecacheController();
2966
+ }
2967
+ return precacheController;
2968
+ };
2969
+
2970
+ /*
2971
+ Copyright 2018 Google LLC
2972
+
2973
+ Use of this source code is governed by an MIT-style
2974
+ license that can be found in the LICENSE file or at
2975
+ https://opensource.org/licenses/MIT.
2976
+ */
2977
+ /**
2978
+ * Removes any URL search parameters that should be ignored.
2979
+ *
2980
+ * @param {URL} urlObject The original URL.
2981
+ * @param {Array<RegExp>} ignoreURLParametersMatching RegExps to test against
2982
+ * each search parameter name. Matches mean that the search parameter should be
2983
+ * ignored.
2984
+ * @return {URL} The URL with any ignored search parameters removed.
2985
+ *
2986
+ * @private
2987
+ * @memberof workbox-precaching
2988
+ */
2989
+ function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {
2990
+ // Convert the iterable into an array at the start of the loop to make sure
2991
+ // deletion doesn't mess up iteration.
2992
+ for (const paramName of [...urlObject.searchParams.keys()]) {
2993
+ if (ignoreURLParametersMatching.some(regExp => regExp.test(paramName))) {
2994
+ urlObject.searchParams.delete(paramName);
2995
+ }
2996
+ }
2997
+ return urlObject;
2998
+ }
2999
+
3000
+ /*
3001
+ Copyright 2019 Google LLC
3002
+
3003
+ Use of this source code is governed by an MIT-style
3004
+ license that can be found in the LICENSE file or at
3005
+ https://opensource.org/licenses/MIT.
3006
+ */
3007
+ /**
3008
+ * Generator function that yields possible variations on the original URL to
3009
+ * check, one at a time.
3010
+ *
3011
+ * @param {string} url
3012
+ * @param {Object} options
3013
+ *
3014
+ * @private
3015
+ * @memberof workbox-precaching
3016
+ */
3017
+ function* generateURLVariations(url, {
3018
+ ignoreURLParametersMatching = [/^utm_/, /^fbclid$/],
3019
+ directoryIndex = 'index.html',
3020
+ cleanURLs = true,
3021
+ urlManipulation
3022
+ } = {}) {
3023
+ const urlObject = new URL(url, location.href);
3024
+ urlObject.hash = '';
3025
+ yield urlObject.href;
3026
+ const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching);
3027
+ yield urlWithoutIgnoredParams.href;
3028
+ if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) {
3029
+ const directoryURL = new URL(urlWithoutIgnoredParams.href);
3030
+ directoryURL.pathname += directoryIndex;
3031
+ yield directoryURL.href;
3032
+ }
3033
+ if (cleanURLs) {
3034
+ const cleanURL = new URL(urlWithoutIgnoredParams.href);
3035
+ cleanURL.pathname += '.html';
3036
+ yield cleanURL.href;
3037
+ }
3038
+ if (urlManipulation) {
3039
+ const additionalURLs = urlManipulation({
3040
+ url: urlObject
3041
+ });
3042
+ for (const urlToAttempt of additionalURLs) {
3043
+ yield urlToAttempt.href;
3044
+ }
3045
+ }
3046
+ }
3047
+
3048
+ /*
3049
+ Copyright 2020 Google LLC
3050
+
3051
+ Use of this source code is governed by an MIT-style
3052
+ license that can be found in the LICENSE file or at
3053
+ https://opensource.org/licenses/MIT.
3054
+ */
3055
+ /**
3056
+ * A subclass of {@link workbox-routing.Route} that takes a
3057
+ * {@link workbox-precaching.PrecacheController}
3058
+ * instance and uses it to match incoming requests and handle fetching
3059
+ * responses from the precache.
3060
+ *
3061
+ * @memberof workbox-precaching
3062
+ * @extends workbox-routing.Route
3063
+ */
3064
+ class PrecacheRoute extends Route {
3065
+ /**
3066
+ * @param {PrecacheController} precacheController A `PrecacheController`
3067
+ * instance used to both match requests and respond to fetch events.
3068
+ * @param {Object} [options] Options to control how requests are matched
3069
+ * against the list of precached URLs.
3070
+ * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will
3071
+ * check cache entries for a URLs ending with '/' to see if there is a hit when
3072
+ * appending the `directoryIndex` value.
3073
+ * @param {Array<RegExp>} [options.ignoreURLParametersMatching=[/^utm_/, /^fbclid$/]] An
3074
+ * array of regex's to remove search params when looking for a cache match.
3075
+ * @param {boolean} [options.cleanURLs=true] The `cleanURLs` option will
3076
+ * check the cache for the URL with a `.html` added to the end of the end.
3077
+ * @param {workbox-precaching~urlManipulation} [options.urlManipulation]
3078
+ * This is a function that should take a URL and return an array of
3079
+ * alternative URLs that should be checked for precache matches.
3080
+ */
3081
+ constructor(precacheController, options) {
3082
+ const match = ({
3083
+ request
3084
+ }) => {
3085
+ const urlsToCacheKeys = precacheController.getURLsToCacheKeys();
3086
+ for (const possibleURL of generateURLVariations(request.url, options)) {
3087
+ const cacheKey = urlsToCacheKeys.get(possibleURL);
3088
+ if (cacheKey) {
3089
+ const integrity = precacheController.getIntegrityForCacheKey(cacheKey);
3090
+ return {
3091
+ cacheKey,
3092
+ integrity
3093
+ };
3094
+ }
3095
+ }
3096
+ {
3097
+ logger.debug(`Precaching did not find a match for ` + getFriendlyURL(request.url));
3098
+ }
3099
+ return;
3100
+ };
3101
+ super(match, precacheController.strategy);
3102
+ }
3103
+ }
3104
+
3105
+ /*
3106
+ Copyright 2019 Google LLC
3107
+ Use of this source code is governed by an MIT-style
3108
+ license that can be found in the LICENSE file or at
3109
+ https://opensource.org/licenses/MIT.
3110
+ */
3111
+ /**
3112
+ * Add a `fetch` listener to the service worker that will
3113
+ * respond to
3114
+ * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests}
3115
+ * with precached assets.
3116
+ *
3117
+ * Requests for assets that aren't precached, the `FetchEvent` will not be
3118
+ * responded to, allowing the event to fall through to other `fetch` event
3119
+ * listeners.
3120
+ *
3121
+ * @param {Object} [options] See the {@link workbox-precaching.PrecacheRoute}
3122
+ * options.
3123
+ *
3124
+ * @memberof workbox-precaching
3125
+ */
3126
+ function addRoute(options) {
3127
+ const precacheController = getOrCreatePrecacheController();
3128
+ const precacheRoute = new PrecacheRoute(precacheController, options);
3129
+ registerRoute(precacheRoute);
3130
+ }
3131
+
3132
+ /*
3133
+ Copyright 2019 Google LLC
3134
+
3135
+ Use of this source code is governed by an MIT-style
3136
+ license that can be found in the LICENSE file or at
3137
+ https://opensource.org/licenses/MIT.
3138
+ */
3139
+ /**
3140
+ * Adds items to the precache list, removing any duplicates and
3141
+ * stores the files in the
3142
+ * {@link workbox-core.cacheNames|"precache cache"} when the service
3143
+ * worker installs.
3144
+ *
3145
+ * This method can be called multiple times.
3146
+ *
3147
+ * Please note: This method **will not** serve any of the cached files for you.
3148
+ * It only precaches files. To respond to a network request you call
3149
+ * {@link workbox-precaching.addRoute}.
3150
+ *
3151
+ * If you have a single array of files to precache, you can just call
3152
+ * {@link workbox-precaching.precacheAndRoute}.
3153
+ *
3154
+ * @param {Array<Object|string>} [entries=[]] Array of entries to precache.
3155
+ *
3156
+ * @memberof workbox-precaching
3157
+ */
3158
+ function precache(entries) {
3159
+ const precacheController = getOrCreatePrecacheController();
3160
+ precacheController.precache(entries);
3161
+ }
3162
+
3163
+ /*
3164
+ Copyright 2019 Google LLC
3165
+
3166
+ Use of this source code is governed by an MIT-style
3167
+ license that can be found in the LICENSE file or at
3168
+ https://opensource.org/licenses/MIT.
3169
+ */
3170
+ /**
3171
+ * This method will add entries to the precache list and add a route to
3172
+ * respond to fetch events.
3173
+ *
3174
+ * This is a convenience method that will call
3175
+ * {@link workbox-precaching.precache} and
3176
+ * {@link workbox-precaching.addRoute} in a single call.
3177
+ *
3178
+ * @param {Array<Object|string>} entries Array of entries to precache.
3179
+ * @param {Object} [options] See the
3180
+ * {@link workbox-precaching.PrecacheRoute} options.
3181
+ *
3182
+ * @memberof workbox-precaching
3183
+ */
3184
+ function precacheAndRoute(entries, options) {
3185
+ precache(entries);
3186
+ addRoute(options);
3187
+ }
3188
+
3189
+ /*
3190
+ Copyright 2018 Google LLC
3191
+
3192
+ Use of this source code is governed by an MIT-style
3193
+ license that can be found in the LICENSE file or at
3194
+ https://opensource.org/licenses/MIT.
3195
+ */
3196
+ const SUBSTRING_TO_FIND = '-precache-';
3197
+ /**
3198
+ * Cleans up incompatible precaches that were created by older versions of
3199
+ * Workbox, by a service worker registered under the current scope.
3200
+ *
3201
+ * This is meant to be called as part of the `activate` event.
3202
+ *
3203
+ * This should be safe to use as long as you don't include `substringToFind`
3204
+ * (defaulting to `-precache-`) in your non-precache cache names.
3205
+ *
3206
+ * @param {string} currentPrecacheName The cache name currently in use for
3207
+ * precaching. This cache won't be deleted.
3208
+ * @param {string} [substringToFind='-precache-'] Cache names which include this
3209
+ * substring will be deleted (excluding `currentPrecacheName`).
3210
+ * @return {Array<string>} A list of all the cache names that were deleted.
3211
+ *
3212
+ * @private
3213
+ * @memberof workbox-precaching
3214
+ */
3215
+ const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND) => {
3216
+ const cacheNames = await self.caches.keys();
3217
+ const cacheNamesToDelete = cacheNames.filter(cacheName => {
3218
+ return cacheName.includes(substringToFind) && cacheName.includes(self.registration.scope) && cacheName !== currentPrecacheName;
3219
+ });
3220
+ await Promise.all(cacheNamesToDelete.map(cacheName => self.caches.delete(cacheName)));
3221
+ return cacheNamesToDelete;
3222
+ };
3223
+
3224
+ /*
3225
+ Copyright 2019 Google LLC
3226
+
3227
+ Use of this source code is governed by an MIT-style
3228
+ license that can be found in the LICENSE file or at
3229
+ https://opensource.org/licenses/MIT.
3230
+ */
3231
+ /**
3232
+ * Adds an `activate` event listener which will clean up incompatible
3233
+ * precaches that were created by older versions of Workbox.
3234
+ *
3235
+ * @memberof workbox-precaching
3236
+ */
3237
+ function cleanupOutdatedCaches() {
3238
+ // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
3239
+ self.addEventListener('activate', event => {
3240
+ const cacheName = cacheNames.getPrecacheName();
3241
+ event.waitUntil(deleteOutdatedCaches(cacheName).then(cachesDeleted => {
3242
+ {
3243
+ if (cachesDeleted.length > 0) {
3244
+ logger.log(`The following out-of-date precaches were cleaned up ` + `automatically:`, cachesDeleted);
3245
+ }
3246
+ }
3247
+ }));
3248
+ });
3249
+ }
3250
+
3251
+ /*
3252
+ Copyright 2018 Google LLC
3253
+
3254
+ Use of this source code is governed by an MIT-style
3255
+ license that can be found in the LICENSE file or at
3256
+ https://opensource.org/licenses/MIT.
3257
+ */
3258
+ /**
3259
+ * NavigationRoute makes it easy to create a
3260
+ * {@link workbox-routing.Route} that matches for browser
3261
+ * [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests}.
3262
+ *
3263
+ * It will only match incoming Requests whose
3264
+ * {@link https://fetch.spec.whatwg.org/#concept-request-mode|mode}
3265
+ * is set to `navigate`.
3266
+ *
3267
+ * You can optionally only apply this route to a subset of navigation requests
3268
+ * by using one or both of the `denylist` and `allowlist` parameters.
3269
+ *
3270
+ * @memberof workbox-routing
3271
+ * @extends workbox-routing.Route
3272
+ */
3273
+ class NavigationRoute extends Route {
3274
+ /**
3275
+ * If both `denylist` and `allowlist` are provided, the `denylist` will
3276
+ * take precedence and the request will not match this route.
3277
+ *
3278
+ * The regular expressions in `allowlist` and `denylist`
3279
+ * are matched against the concatenated
3280
+ * [`pathname`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname}
3281
+ * and [`search`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search}
3282
+ * portions of the requested URL.
3283
+ *
3284
+ * *Note*: These RegExps may be evaluated against every destination URL during
3285
+ * a navigation. Avoid using
3286
+ * [complex RegExps](https://github.com/GoogleChrome/workbox/issues/3077),
3287
+ * or else your users may see delays when navigating your site.
3288
+ *
3289
+ * @param {workbox-routing~handlerCallback} handler A callback
3290
+ * function that returns a Promise resulting in a Response.
3291
+ * @param {Object} options
3292
+ * @param {Array<RegExp>} [options.denylist] If any of these patterns match,
3293
+ * the route will not handle the request (even if a allowlist RegExp matches).
3294
+ * @param {Array<RegExp>} [options.allowlist=[/./]] If any of these patterns
3295
+ * match the URL's pathname and search parameter, the route will handle the
3296
+ * request (assuming the denylist doesn't match).
3297
+ */
3298
+ constructor(handler, {
3299
+ allowlist = [/./],
3300
+ denylist = []
3301
+ } = {}) {
3302
+ {
3303
+ finalAssertExports.isArrayOfClass(allowlist, RegExp, {
3304
+ moduleName: 'workbox-routing',
3305
+ className: 'NavigationRoute',
3306
+ funcName: 'constructor',
3307
+ paramName: 'options.allowlist'
3308
+ });
3309
+ finalAssertExports.isArrayOfClass(denylist, RegExp, {
3310
+ moduleName: 'workbox-routing',
3311
+ className: 'NavigationRoute',
3312
+ funcName: 'constructor',
3313
+ paramName: 'options.denylist'
3314
+ });
3315
+ }
3316
+ super(options => this._match(options), handler);
3317
+ this._allowlist = allowlist;
3318
+ this._denylist = denylist;
3319
+ }
3320
+ /**
3321
+ * Routes match handler.
3322
+ *
3323
+ * @param {Object} options
3324
+ * @param {URL} options.url
3325
+ * @param {Request} options.request
3326
+ * @return {boolean}
3327
+ *
3328
+ * @private
3329
+ */
3330
+ _match({
3331
+ url,
3332
+ request
3333
+ }) {
3334
+ if (request && request.mode !== 'navigate') {
3335
+ return false;
3336
+ }
3337
+ const pathnameAndSearch = url.pathname + url.search;
3338
+ for (const regExp of this._denylist) {
3339
+ if (regExp.test(pathnameAndSearch)) {
3340
+ {
3341
+ logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL matches this denylist pattern: ` + `${regExp.toString()}`);
3342
+ }
3343
+ return false;
3344
+ }
3345
+ }
3346
+ if (this._allowlist.some(regExp => regExp.test(pathnameAndSearch))) {
3347
+ {
3348
+ logger.debug(`The navigation route ${pathnameAndSearch} ` + `is being used.`);
3349
+ }
3350
+ return true;
3351
+ }
3352
+ {
3353
+ logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL being navigated to doesn't ` + `match the allowlist.`);
3354
+ }
3355
+ return false;
3356
+ }
3357
+ }
3358
+
3359
+ /*
3360
+ Copyright 2019 Google LLC
3361
+
3362
+ Use of this source code is governed by an MIT-style
3363
+ license that can be found in the LICENSE file or at
3364
+ https://opensource.org/licenses/MIT.
3365
+ */
3366
+ /**
3367
+ * Helper function that calls
3368
+ * {@link PrecacheController#createHandlerBoundToURL} on the default
3369
+ * {@link PrecacheController} instance.
3370
+ *
3371
+ * If you are creating your own {@link PrecacheController}, then call the
3372
+ * {@link PrecacheController#createHandlerBoundToURL} on that instance,
3373
+ * instead of using this function.
3374
+ *
3375
+ * @param {string} url The precached URL which will be used to lookup the
3376
+ * `Response`.
3377
+ * @param {boolean} [fallbackToNetwork=true] Whether to attempt to get the
3378
+ * response from the network if there's a precache miss.
3379
+ * @return {workbox-routing~handlerCallback}
3380
+ *
3381
+ * @memberof workbox-precaching
3382
+ */
3383
+ function createHandlerBoundToURL(url) {
3384
+ const precacheController = getOrCreatePrecacheController();
3385
+ return precacheController.createHandlerBoundToURL(url);
3386
+ }
3387
+
3388
+ exports.NavigationRoute = NavigationRoute;
3389
+ exports.cleanupOutdatedCaches = cleanupOutdatedCaches;
3390
+ exports.clientsClaim = clientsClaim;
3391
+ exports.createHandlerBoundToURL = createHandlerBoundToURL;
3392
+ exports.precacheAndRoute = precacheAndRoute;
3393
+ exports.registerRoute = registerRoute;
3394
+
3395
+ }));