You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

workbox-6b19f60b.js 89KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701
  1. define("./workbox-6b19f60b.js",['exports'], function (exports) { 'use strict';
  2. try {
  3. self['workbox:core:6.1.5'] && _();
  4. } catch (e) {}
  5. /*
  6. Copyright 2019 Google LLC
  7. Use of this source code is governed by an MIT-style
  8. license that can be found in the LICENSE file or at
  9. https://opensource.org/licenses/MIT.
  10. */
  11. const logger = (() => {
  12. // Don't overwrite this value if it's already set.
  13. // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923
  14. if (!('__WB_DISABLE_DEV_LOGS' in self)) {
  15. self.__WB_DISABLE_DEV_LOGS = false;
  16. }
  17. let inGroup = false;
  18. const methodToColorMap = {
  19. debug: `#7f8c8d`,
  20. log: `#2ecc71`,
  21. warn: `#f39c12`,
  22. error: `#c0392b`,
  23. groupCollapsed: `#3498db`,
  24. groupEnd: null
  25. };
  26. const print = function (method, args) {
  27. if (self.__WB_DISABLE_DEV_LOGS) {
  28. return;
  29. }
  30. if (method === 'groupCollapsed') {
  31. // Safari doesn't print all console.groupCollapsed() arguments:
  32. // https://bugs.webkit.org/show_bug.cgi?id=182754
  33. if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
  34. console[method](...args);
  35. return;
  36. }
  37. }
  38. const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; // When in a group, the workbox prefix is not displayed.
  39. const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];
  40. console[method](...logPrefix, ...args);
  41. if (method === 'groupCollapsed') {
  42. inGroup = true;
  43. }
  44. if (method === 'groupEnd') {
  45. inGroup = false;
  46. }
  47. };
  48. const api = {};
  49. const loggerMethods = Object.keys(methodToColorMap);
  50. for (const key of loggerMethods) {
  51. const method = key;
  52. api[method] = (...args) => {
  53. print(method, args);
  54. };
  55. }
  56. return api;
  57. })();
  58. /*
  59. Copyright 2018 Google LLC
  60. Use of this source code is governed by an MIT-style
  61. license that can be found in the LICENSE file or at
  62. https://opensource.org/licenses/MIT.
  63. */
  64. const messages$1 = {
  65. 'invalid-value': ({
  66. paramName,
  67. validValueDescription,
  68. value
  69. }) => {
  70. if (!paramName || !validValueDescription) {
  71. throw new Error(`Unexpected input to 'invalid-value' error.`);
  72. }
  73. return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`;
  74. },
  75. 'not-an-array': ({
  76. moduleName,
  77. className,
  78. funcName,
  79. paramName
  80. }) => {
  81. if (!moduleName || !className || !funcName || !paramName) {
  82. throw new Error(`Unexpected input to 'not-an-array' error.`);
  83. }
  84. return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`;
  85. },
  86. 'incorrect-type': ({
  87. expectedType,
  88. paramName,
  89. moduleName,
  90. className,
  91. funcName
  92. }) => {
  93. if (!expectedType || !paramName || !moduleName || !funcName) {
  94. throw new Error(`Unexpected input to 'incorrect-type' error.`);
  95. }
  96. return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className ? className + '.' : ''}` + `${funcName}()' must be of type ${expectedType}.`;
  97. },
  98. 'incorrect-class': ({
  99. expectedClass,
  100. paramName,
  101. moduleName,
  102. className,
  103. funcName,
  104. isReturnValueProblem
  105. }) => {
  106. if (!expectedClass || !moduleName || !funcName) {
  107. throw new Error(`Unexpected input to 'incorrect-class' error.`);
  108. }
  109. if (isReturnValueProblem) {
  110. return `The return value from ` + `'${moduleName}.${className ? className + '.' : ''}${funcName}()' ` + `must be an instance of class ${expectedClass.name}.`;
  111. }
  112. return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className ? className + '.' : ''}${funcName}()' ` + `must be an instance of class ${expectedClass.name}.`;
  113. },
  114. 'missing-a-method': ({
  115. expectedMethod,
  116. paramName,
  117. moduleName,
  118. className,
  119. funcName
  120. }) => {
  121. if (!expectedMethod || !paramName || !moduleName || !className || !funcName) {
  122. throw new Error(`Unexpected input to 'missing-a-method' error.`);
  123. }
  124. return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`;
  125. },
  126. 'add-to-cache-list-unexpected-type': ({
  127. entry
  128. }) => {
  129. 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.`;
  130. },
  131. 'add-to-cache-list-conflicting-entries': ({
  132. firstEntry,
  133. secondEntry
  134. }) => {
  135. if (!firstEntry || !secondEntry) {
  136. throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`);
  137. }
  138. return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry._entryId} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`;
  139. },
  140. 'plugin-error-request-will-fetch': ({
  141. thrownError
  142. }) => {
  143. if (!thrownError) {
  144. throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`);
  145. }
  146. return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownError.message}'.`;
  147. },
  148. 'invalid-cache-name': ({
  149. cacheNameId,
  150. value
  151. }) => {
  152. if (!cacheNameId) {
  153. throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`);
  154. }
  155. return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`;
  156. },
  157. 'unregister-route-but-not-found-with-method': ({
  158. method
  159. }) => {
  160. if (!method) {
  161. throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`);
  162. }
  163. return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`;
  164. },
  165. 'unregister-route-route-not-registered': () => {
  166. return `The route you're trying to unregister was not previously ` + `registered.`;
  167. },
  168. 'queue-replay-failed': ({
  169. name
  170. }) => {
  171. return `Replaying the background sync queue '${name}' failed.`;
  172. },
  173. 'duplicate-queue-name': ({
  174. name
  175. }) => {
  176. return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`;
  177. },
  178. 'expired-test-without-max-age': ({
  179. methodName,
  180. paramName
  181. }) => {
  182. return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`;
  183. },
  184. 'unsupported-route-type': ({
  185. moduleName,
  186. className,
  187. funcName,
  188. paramName
  189. }) => {
  190. return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`;
  191. },
  192. 'not-array-of-class': ({
  193. value,
  194. expectedClass,
  195. moduleName,
  196. className,
  197. funcName,
  198. paramName
  199. }) => {
  200. 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.`;
  201. },
  202. 'max-entries-or-age-required': ({
  203. moduleName,
  204. className,
  205. funcName
  206. }) => {
  207. return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`;
  208. },
  209. 'statuses-or-headers-required': ({
  210. moduleName,
  211. className,
  212. funcName
  213. }) => {
  214. return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`;
  215. },
  216. 'invalid-string': ({
  217. moduleName,
  218. funcName,
  219. paramName
  220. }) => {
  221. if (!paramName || !moduleName || !funcName) {
  222. throw new Error(`Unexpected input to 'invalid-string' error.`);
  223. }
  224. 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.`;
  225. },
  226. 'channel-name-required': () => {
  227. return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`;
  228. },
  229. 'invalid-responses-are-same-args': () => {
  230. return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`;
  231. },
  232. 'expire-custom-caches-only': () => {
  233. return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`;
  234. },
  235. 'unit-must-be-bytes': ({
  236. normalizedRangeHeader
  237. }) => {
  238. if (!normalizedRangeHeader) {
  239. throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`);
  240. }
  241. return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`;
  242. },
  243. 'single-range-only': ({
  244. normalizedRangeHeader
  245. }) => {
  246. if (!normalizedRangeHeader) {
  247. throw new Error(`Unexpected input to 'single-range-only' error.`);
  248. }
  249. return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`;
  250. },
  251. 'invalid-range-values': ({
  252. normalizedRangeHeader
  253. }) => {
  254. if (!normalizedRangeHeader) {
  255. throw new Error(`Unexpected input to 'invalid-range-values' error.`);
  256. }
  257. 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}"`;
  258. },
  259. 'no-range-header': () => {
  260. return `No Range header was found in the Request provided.`;
  261. },
  262. 'range-not-satisfiable': ({
  263. size,
  264. start,
  265. end
  266. }) => {
  267. return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`;
  268. },
  269. 'attempt-to-cache-non-get-request': ({
  270. url,
  271. method
  272. }) => {
  273. return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`;
  274. },
  275. 'cache-put-with-no-response': ({
  276. url
  277. }) => {
  278. return `There was an attempt to cache '${url}' but the response was not ` + `defined.`;
  279. },
  280. 'no-response': ({
  281. url,
  282. error
  283. }) => {
  284. let message = `The strategy could not generate a response for '${url}'.`;
  285. if (error) {
  286. message += ` The underlying error is ${error}.`;
  287. }
  288. return message;
  289. },
  290. 'bad-precaching-response': ({
  291. url,
  292. status
  293. }) => {
  294. return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`);
  295. },
  296. 'non-precached-url': ({
  297. url
  298. }) => {
  299. return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`;
  300. },
  301. 'add-to-cache-list-conflicting-integrities': ({
  302. url
  303. }) => {
  304. return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`;
  305. },
  306. 'missing-precache-entry': ({
  307. cacheName,
  308. url
  309. }) => {
  310. return `Unable to find a precached response in ${cacheName} for ${url}.`;
  311. },
  312. 'cross-origin-copy-response': ({
  313. origin
  314. }) => {
  315. return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`;
  316. }
  317. };
  318. /*
  319. Copyright 2018 Google LLC
  320. Use of this source code is governed by an MIT-style
  321. license that can be found in the LICENSE file or at
  322. https://opensource.org/licenses/MIT.
  323. */
  324. const generatorFunction = (code, details = {}) => {
  325. const message = messages$1[code];
  326. if (!message) {
  327. throw new Error(`Unable to find message for code '${code}'.`);
  328. }
  329. return message(details);
  330. };
  331. const messageGenerator = generatorFunction;
  332. /*
  333. Copyright 2018 Google LLC
  334. Use of this source code is governed by an MIT-style
  335. license that can be found in the LICENSE file or at
  336. https://opensource.org/licenses/MIT.
  337. */
  338. /**
  339. * Workbox errors should be thrown with this class.
  340. * This allows use to ensure the type easily in tests,
  341. * helps developers identify errors from workbox
  342. * easily and allows use to optimise error
  343. * messages correctly.
  344. *
  345. * @private
  346. */
  347. class WorkboxError extends Error {
  348. /**
  349. *
  350. * @param {string} errorCode The error code that
  351. * identifies this particular error.
  352. * @param {Object=} details Any relevant arguments
  353. * that will help developers identify issues should
  354. * be added as a key on the context object.
  355. */
  356. constructor(errorCode, details) {
  357. const message = messageGenerator(errorCode, details);
  358. super(message);
  359. this.name = errorCode;
  360. this.details = details;
  361. }
  362. }
  363. /*
  364. Copyright 2018 Google LLC
  365. Use of this source code is governed by an MIT-style
  366. license that can be found in the LICENSE file or at
  367. https://opensource.org/licenses/MIT.
  368. */
  369. /*
  370. * This method throws if the supplied value is not an array.
  371. * The destructed values are required to produce a meaningful error for users.
  372. * The destructed and restructured object is so it's clear what is
  373. * needed.
  374. */
  375. const isArray = (value, details) => {
  376. if (!Array.isArray(value)) {
  377. throw new WorkboxError('not-an-array', details);
  378. }
  379. };
  380. const hasMethod = (object, expectedMethod, details) => {
  381. const type = typeof object[expectedMethod];
  382. if (type !== 'function') {
  383. details['expectedMethod'] = expectedMethod;
  384. throw new WorkboxError('missing-a-method', details);
  385. }
  386. };
  387. const isType = (object, expectedType, details) => {
  388. if (typeof object !== expectedType) {
  389. details['expectedType'] = expectedType;
  390. throw new WorkboxError('incorrect-type', details);
  391. }
  392. };
  393. const isInstance = (object, expectedClass, details) => {
  394. if (!(object instanceof expectedClass)) {
  395. details['expectedClass'] = expectedClass;
  396. throw new WorkboxError('incorrect-class', details);
  397. }
  398. };
  399. const isOneOf = (value, validValues, details) => {
  400. if (!validValues.includes(value)) {
  401. details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`;
  402. throw new WorkboxError('invalid-value', details);
  403. }
  404. };
  405. const isArrayOfClass = (value, expectedClass, details) => {
  406. const error = new WorkboxError('not-array-of-class', details);
  407. if (!Array.isArray(value)) {
  408. throw error;
  409. }
  410. for (const item of value) {
  411. if (!(item instanceof expectedClass)) {
  412. throw error;
  413. }
  414. }
  415. };
  416. const finalAssertExports = {
  417. hasMethod,
  418. isArray,
  419. isInstance,
  420. isOneOf,
  421. isType,
  422. isArrayOfClass
  423. };
  424. try {
  425. self['workbox:routing:6.1.5'] && _();
  426. } catch (e) {}
  427. /*
  428. Copyright 2018 Google LLC
  429. Use of this source code is governed by an MIT-style
  430. license that can be found in the LICENSE file or at
  431. https://opensource.org/licenses/MIT.
  432. */
  433. /**
  434. * The default HTTP method, 'GET', used when there's no specific method
  435. * configured for a route.
  436. *
  437. * @type {string}
  438. *
  439. * @private
  440. */
  441. const defaultMethod = 'GET';
  442. /**
  443. * The list of valid HTTP methods associated with requests that could be routed.
  444. *
  445. * @type {Array<string>}
  446. *
  447. * @private
  448. */
  449. const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'];
  450. /*
  451. Copyright 2018 Google LLC
  452. Use of this source code is governed by an MIT-style
  453. license that can be found in the LICENSE file or at
  454. https://opensource.org/licenses/MIT.
  455. */
  456. /**
  457. * @param {function()|Object} handler Either a function, or an object with a
  458. * 'handle' method.
  459. * @return {Object} An object with a handle method.
  460. *
  461. * @private
  462. */
  463. const normalizeHandler = handler => {
  464. if (handler && typeof handler === 'object') {
  465. {
  466. finalAssertExports.hasMethod(handler, 'handle', {
  467. moduleName: 'workbox-routing',
  468. className: 'Route',
  469. funcName: 'constructor',
  470. paramName: 'handler'
  471. });
  472. }
  473. return handler;
  474. } else {
  475. {
  476. finalAssertExports.isType(handler, 'function', {
  477. moduleName: 'workbox-routing',
  478. className: 'Route',
  479. funcName: 'constructor',
  480. paramName: 'handler'
  481. });
  482. }
  483. return {
  484. handle: handler
  485. };
  486. }
  487. };
  488. /*
  489. Copyright 2018 Google LLC
  490. Use of this source code is governed by an MIT-style
  491. license that can be found in the LICENSE file or at
  492. https://opensource.org/licenses/MIT.
  493. */
  494. /**
  495. * A `Route` consists of a pair of callback functions, "match" and "handler".
  496. * The "match" callback determine if a route should be used to "handle" a
  497. * request by returning a non-falsy value if it can. The "handler" callback
  498. * is called when there is a match and should return a Promise that resolves
  499. * to a `Response`.
  500. *
  501. * @memberof module:workbox-routing
  502. */
  503. class Route {
  504. /**
  505. * Constructor for Route class.
  506. *
  507. * @param {module:workbox-routing~matchCallback} match
  508. * A callback function that determines whether the route matches a given
  509. * `fetch` event by returning a non-falsy value.
  510. * @param {module:workbox-routing~handlerCallback} handler A callback
  511. * function that returns a Promise resolving to a Response.
  512. * @param {string} [method='GET'] The HTTP method to match the Route
  513. * against.
  514. */
  515. constructor(match, handler, method = defaultMethod) {
  516. {
  517. finalAssertExports.isType(match, 'function', {
  518. moduleName: 'workbox-routing',
  519. className: 'Route',
  520. funcName: 'constructor',
  521. paramName: 'match'
  522. });
  523. if (method) {
  524. finalAssertExports.isOneOf(method, validMethods, {
  525. paramName: 'method'
  526. });
  527. }
  528. } // These values are referenced directly by Router so cannot be
  529. // altered by minificaton.
  530. this.handler = normalizeHandler(handler);
  531. this.match = match;
  532. this.method = method;
  533. }
  534. /**
  535. *
  536. * @param {module:workbox-routing-handlerCallback} handler A callback
  537. * function that returns a Promise resolving to a Response
  538. */
  539. setCatchHandler(handler) {
  540. this.catchHandler = normalizeHandler(handler);
  541. }
  542. }
  543. /*
  544. Copyright 2018 Google LLC
  545. Use of this source code is governed by an MIT-style
  546. license that can be found in the LICENSE file or at
  547. https://opensource.org/licenses/MIT.
  548. */
  549. /**
  550. * RegExpRoute makes it easy to create a regular expression based
  551. * [Route]{@link module:workbox-routing.Route}.
  552. *
  553. * For same-origin requests the RegExp only needs to match part of the URL. For
  554. * requests against third-party servers, you must define a RegExp that matches
  555. * the start of the URL.
  556. *
  557. * [See the module docs for info.]{@link https://developers.google.com/web/tools/workbox/modules/workbox-routing}
  558. *
  559. * @memberof module:workbox-routing
  560. * @extends module:workbox-routing.Route
  561. */
  562. class RegExpRoute extends Route {
  563. /**
  564. * If the regular expression contains
  565. * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},
  566. * the captured values will be passed to the
  567. * [handler's]{@link module:workbox-routing~handlerCallback} `params`
  568. * argument.
  569. *
  570. * @param {RegExp} regExp The regular expression to match against URLs.
  571. * @param {module:workbox-routing~handlerCallback} handler A callback
  572. * function that returns a Promise resulting in a Response.
  573. * @param {string} [method='GET'] The HTTP method to match the Route
  574. * against.
  575. */
  576. constructor(regExp, handler, method) {
  577. {
  578. finalAssertExports.isInstance(regExp, RegExp, {
  579. moduleName: 'workbox-routing',
  580. className: 'RegExpRoute',
  581. funcName: 'constructor',
  582. paramName: 'pattern'
  583. });
  584. }
  585. const match = ({
  586. url
  587. }) => {
  588. const result = regExp.exec(url.href); // Return immediately if there's no match.
  589. if (!result) {
  590. return;
  591. } // Require that the match start at the first character in the URL string
  592. // if it's a cross-origin request.
  593. // See https://github.com/GoogleChrome/workbox/issues/281 for the context
  594. // behind this behavior.
  595. if (url.origin !== location.origin && result.index !== 0) {
  596. {
  597. logger.debug(`The regular expression '${regExp}' only partially matched ` + `against the cross-origin URL '${url}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`);
  598. }
  599. return;
  600. } // If the route matches, but there aren't any capture groups defined, then
  601. // this will return [], which is truthy and therefore sufficient to
  602. // indicate a match.
  603. // If there are capture groups, then it will return their values.
  604. return result.slice(1);
  605. };
  606. super(match, handler, method);
  607. }
  608. }
  609. /*
  610. Copyright 2018 Google LLC
  611. Use of this source code is governed by an MIT-style
  612. license that can be found in the LICENSE file or at
  613. https://opensource.org/licenses/MIT.
  614. */
  615. const getFriendlyURL = url => {
  616. const urlObj = new URL(String(url), location.href); // See https://github.com/GoogleChrome/workbox/issues/2323
  617. // We want to include everything, except for the origin if it's same-origin.
  618. return urlObj.href.replace(new RegExp(`^${location.origin}`), '');
  619. };
  620. /*
  621. Copyright 2018 Google LLC
  622. Use of this source code is governed by an MIT-style
  623. license that can be found in the LICENSE file or at
  624. https://opensource.org/licenses/MIT.
  625. */
  626. /**
  627. * The Router can be used to process a FetchEvent through one or more
  628. * [Routes]{@link module:workbox-routing.Route} responding with a Request if
  629. * a matching route exists.
  630. *
  631. * If no route matches a given a request, the Router will use a "default"
  632. * handler if one is defined.
  633. *
  634. * Should the matching Route throw an error, the Router will use a "catch"
  635. * handler if one is defined to gracefully deal with issues and respond with a
  636. * Request.
  637. *
  638. * If a request matches multiple routes, the **earliest** registered route will
  639. * be used to respond to the request.
  640. *
  641. * @memberof module:workbox-routing
  642. */
  643. class Router {
  644. /**
  645. * Initializes a new Router.
  646. */
  647. constructor() {
  648. this._routes = new Map();
  649. this._defaultHandlerMap = new Map();
  650. }
  651. /**
  652. * @return {Map<string, Array<module:workbox-routing.Route>>} routes A `Map` of HTTP
  653. * method name ('GET', etc.) to an array of all the corresponding `Route`
  654. * instances that are registered.
  655. */
  656. get routes() {
  657. return this._routes;
  658. }
  659. /**
  660. * Adds a fetch event listener to respond to events when a route matches
  661. * the event's request.
  662. */
  663. addFetchListener() {
  664. // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
  665. self.addEventListener('fetch', event => {
  666. const {
  667. request
  668. } = event;
  669. const responsePromise = this.handleRequest({
  670. request,
  671. event
  672. });
  673. if (responsePromise) {
  674. event.respondWith(responsePromise);
  675. }
  676. });
  677. }
  678. /**
  679. * Adds a message event listener for URLs to cache from the window.
  680. * This is useful to cache resources loaded on the page prior to when the
  681. * service worker started controlling it.
  682. *
  683. * The format of the message data sent from the window should be as follows.
  684. * Where the `urlsToCache` array may consist of URL strings or an array of
  685. * URL string + `requestInit` object (the same as you'd pass to `fetch()`).
  686. *
  687. * ```
  688. * {
  689. * type: 'CACHE_URLS',
  690. * payload: {
  691. * urlsToCache: [
  692. * './script1.js',
  693. * './script2.js',
  694. * ['./script3.js', {mode: 'no-cors'}],
  695. * ],
  696. * },
  697. * }
  698. * ```
  699. */
  700. addCacheListener() {
  701. // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
  702. self.addEventListener('message', event => {
  703. if (event.data && event.data.type === 'CACHE_URLS') {
  704. const {
  705. payload
  706. } = event.data;
  707. {
  708. logger.debug(`Caching URLs from the window`, payload.urlsToCache);
  709. }
  710. const requestPromises = Promise.all(payload.urlsToCache.map(entry => {
  711. if (typeof entry === 'string') {
  712. entry = [entry];
  713. }
  714. const request = new Request(...entry);
  715. return this.handleRequest({
  716. request,
  717. event
  718. }); // TODO(philipwalton): TypeScript errors without this typecast for
  719. // some reason (probably a bug). The real type here should work but
  720. // doesn't: `Array<Promise<Response> | undefined>`.
  721. })); // TypeScript
  722. event.waitUntil(requestPromises); // If a MessageChannel was used, reply to the message on success.
  723. if (event.ports && event.ports[0]) {
  724. requestPromises.then(() => event.ports[0].postMessage(true));
  725. }
  726. }
  727. });
  728. }
  729. /**
  730. * Apply the routing rules to a FetchEvent object to get a Response from an
  731. * appropriate Route's handler.
  732. *
  733. * @param {Object} options
  734. * @param {Request} options.request The request to handle.
  735. * @param {ExtendableEvent} options.event The event that triggered the
  736. * request.
  737. * @return {Promise<Response>|undefined} A promise is returned if a
  738. * registered route can handle the request. If there is no matching
  739. * route and there's no `defaultHandler`, `undefined` is returned.
  740. */
  741. handleRequest({
  742. request,
  743. event
  744. }) {
  745. {
  746. finalAssertExports.isInstance(request, Request, {
  747. moduleName: 'workbox-routing',
  748. className: 'Router',
  749. funcName: 'handleRequest',
  750. paramName: 'options.request'
  751. });
  752. }
  753. const url = new URL(request.url, location.href);
  754. if (!url.protocol.startsWith('http')) {
  755. {
  756. logger.debug(`Workbox Router only supports URLs that start with 'http'.`);
  757. }
  758. return;
  759. }
  760. const sameOrigin = url.origin === location.origin;
  761. const {
  762. params,
  763. route
  764. } = this.findMatchingRoute({
  765. event,
  766. request,
  767. sameOrigin,
  768. url
  769. });
  770. let handler = route && route.handler;
  771. const debugMessages = [];
  772. {
  773. if (handler) {
  774. debugMessages.push([`Found a route to handle this request:`, route]);
  775. if (params) {
  776. debugMessages.push([`Passing the following params to the route's handler:`, params]);
  777. }
  778. }
  779. } // If we don't have a handler because there was no matching route, then
  780. // fall back to defaultHandler if that's defined.
  781. const method = request.method;
  782. if (!handler && this._defaultHandlerMap.has(method)) {
  783. {
  784. debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`);
  785. }
  786. handler = this._defaultHandlerMap.get(method);
  787. }
  788. if (!handler) {
  789. {
  790. // No handler so Workbox will do nothing. If logs is set of debug
  791. // i.e. verbose, we should print out this information.
  792. logger.debug(`No route found for: ${getFriendlyURL(url)}`);
  793. }
  794. return;
  795. }
  796. {
  797. // We have a handler, meaning Workbox is going to handle the route.
  798. // print the routing details to the console.
  799. logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);
  800. debugMessages.forEach(msg => {
  801. if (Array.isArray(msg)) {
  802. logger.log(...msg);
  803. } else {
  804. logger.log(msg);
  805. }
  806. });
  807. logger.groupEnd();
  808. } // Wrap in try and catch in case the handle method throws a synchronous
  809. // error. It should still callback to the catch handler.
  810. let responsePromise;
  811. try {
  812. responsePromise = handler.handle({
  813. url,
  814. request,
  815. event,
  816. params
  817. });
  818. } catch (err) {
  819. responsePromise = Promise.reject(err);
  820. } // Get route's catch handler, if it exists
  821. const catchHandler = route && route.catchHandler;
  822. if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {
  823. responsePromise = responsePromise.catch(async err => {
  824. // If there's a route catch handler, process that first
  825. if (catchHandler) {
  826. {
  827. // Still include URL here as it will be async from the console group
  828. // and may not make sense without the URL
  829. logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);
  830. logger.error(`Error thrown by:`, route);
  831. logger.error(err);
  832. logger.groupEnd();
  833. }
  834. try {
  835. return await catchHandler.handle({
  836. url,
  837. request,
  838. event,
  839. params
  840. });
  841. } catch (catchErr) {
  842. err = catchErr;
  843. }
  844. }
  845. if (this._catchHandler) {
  846. {
  847. // Still include URL here as it will be async from the console group
  848. // and may not make sense without the URL
  849. logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);
  850. logger.error(`Error thrown by:`, route);
  851. logger.error(err);
  852. logger.groupEnd();
  853. }
  854. return this._catchHandler.handle({
  855. url,
  856. request,
  857. event
  858. });
  859. }
  860. throw err;
  861. });
  862. }
  863. return responsePromise;
  864. }
  865. /**
  866. * Checks a request and URL (and optionally an event) against the list of
  867. * registered routes, and if there's a match, returns the corresponding
  868. * route along with any params generated by the match.
  869. *
  870. * @param {Object} options
  871. * @param {URL} options.url
  872. * @param {boolean} options.sameOrigin The result of comparing `url.origin`
  873. * against the current origin.
  874. * @param {Request} options.request The request to match.
  875. * @param {Event} options.event The corresponding event.
  876. * @return {Object} An object with `route` and `params` properties.
  877. * They are populated if a matching route was found or `undefined`
  878. * otherwise.
  879. */
  880. findMatchingRoute({
  881. url,
  882. sameOrigin,
  883. request,
  884. event
  885. }) {
  886. const routes = this._routes.get(request.method) || [];
  887. for (const route of routes) {
  888. let params;
  889. const matchResult = route.match({
  890. url,
  891. sameOrigin,
  892. request,
  893. event
  894. });
  895. if (matchResult) {
  896. {
  897. // Warn developers that using an async matchCallback is almost always
  898. // not the right thing to do.
  899. if (matchResult instanceof Promise) {
  900. logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route);
  901. }
  902. } // See https://github.com/GoogleChrome/workbox/issues/2079
  903. params = matchResult;
  904. if (Array.isArray(matchResult) && matchResult.length === 0) {
  905. // Instead of passing an empty array in as params, use undefined.
  906. params = undefined;
  907. } else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {
  908. // Instead of passing an empty object in as params, use undefined.
  909. params = undefined;
  910. } else if (typeof matchResult === 'boolean') {
  911. // For the boolean value true (rather than just something truth-y),
  912. // don't set params.
  913. // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353
  914. params = undefined;
  915. } // Return early if have a match.
  916. return {
  917. route,
  918. params
  919. };
  920. }
  921. } // If no match was found above, return and empty object.
  922. return {};
  923. }
  924. /**
  925. * Define a default `handler` that's called when no routes explicitly
  926. * match the incoming request.
  927. *
  928. * Each HTTP method ('GET', 'POST', etc.) gets its own default handler.
  929. *
  930. * Without a default handler, unmatched requests will go against the
  931. * network as if there were no service worker present.
  932. *
  933. * @param {module:workbox-routing~handlerCallback} handler A callback
  934. * function that returns a Promise resulting in a Response.
  935. * @param {string} [method='GET'] The HTTP method to associate with this
  936. * default handler. Each method has its own default.
  937. */
  938. setDefaultHandler(handler, method = defaultMethod) {
  939. this._defaultHandlerMap.set(method, normalizeHandler(handler));
  940. }
  941. /**
  942. * If a Route throws an error while handling a request, this `handler`
  943. * will be called and given a chance to provide a response.
  944. *
  945. * @param {module:workbox-routing~handlerCallback} handler A callback
  946. * function that returns a Promise resulting in a Response.
  947. */
  948. setCatchHandler(handler) {
  949. this._catchHandler = normalizeHandler(handler);
  950. }
  951. /**
  952. * Registers a route with the router.
  953. *
  954. * @param {module:workbox-routing.Route} route The route to register.
  955. */
  956. registerRoute(route) {
  957. {
  958. finalAssertExports.isType(route, 'object', {
  959. moduleName: 'workbox-routing',
  960. className: 'Router',
  961. funcName: 'registerRoute',
  962. paramName: 'route'
  963. });
  964. finalAssertExports.hasMethod(route, 'match', {
  965. moduleName: 'workbox-routing',
  966. className: 'Router',
  967. funcName: 'registerRoute',
  968. paramName: 'route'
  969. });
  970. finalAssertExports.isType(route.handler, 'object', {
  971. moduleName: 'workbox-routing',
  972. className: 'Router',
  973. funcName: 'registerRoute',
  974. paramName: 'route'
  975. });
  976. finalAssertExports.hasMethod(route.handler, 'handle', {
  977. moduleName: 'workbox-routing',
  978. className: 'Router',
  979. funcName: 'registerRoute',
  980. paramName: 'route.handler'
  981. });
  982. finalAssertExports.isType(route.method, 'string', {
  983. moduleName: 'workbox-routing',
  984. className: 'Router',
  985. funcName: 'registerRoute',
  986. paramName: 'route.method'
  987. });
  988. }
  989. if (!this._routes.has(route.method)) {
  990. this._routes.set(route.method, []);
  991. } // Give precedence to all of the earlier routes by adding this additional
  992. // route to the end of the array.
  993. this._routes.get(route.method).push(route);
  994. }
  995. /**
  996. * Unregisters a route with the router.
  997. *
  998. * @param {module:workbox-routing.Route} route The route to unregister.
  999. */
  1000. unregisterRoute(route) {
  1001. if (!this._routes.has(route.method)) {
  1002. throw new WorkboxError('unregister-route-but-not-found-with-method', {
  1003. method: route.method
  1004. });
  1005. }
  1006. const routeIndex = this._routes.get(route.method).indexOf(route);
  1007. if (routeIndex > -1) {
  1008. this._routes.get(route.method).splice(routeIndex, 1);
  1009. } else {
  1010. throw new WorkboxError('unregister-route-route-not-registered');
  1011. }
  1012. }
  1013. }
  1014. /*
  1015. Copyright 2019 Google LLC
  1016. Use of this source code is governed by an MIT-style
  1017. license that can be found in the LICENSE file or at
  1018. https://opensource.org/licenses/MIT.
  1019. */
  1020. let defaultRouter;
  1021. /**
  1022. * Creates a new, singleton Router instance if one does not exist. If one
  1023. * does already exist, that instance is returned.
  1024. *
  1025. * @private
  1026. * @return {Router}
  1027. */
  1028. const getOrCreateDefaultRouter = () => {
  1029. if (!defaultRouter) {
  1030. defaultRouter = new Router(); // The helpers that use the default Router assume these listeners exist.
  1031. defaultRouter.addFetchListener();
  1032. defaultRouter.addCacheListener();
  1033. }
  1034. return defaultRouter;
  1035. };
  1036. /*
  1037. Copyright 2019 Google LLC
  1038. Use of this source code is governed by an MIT-style
  1039. license that can be found in the LICENSE file or at
  1040. https://opensource.org/licenses/MIT.
  1041. */
  1042. /**
  1043. * Easily register a RegExp, string, or function with a caching
  1044. * strategy to a singleton Router instance.
  1045. *
  1046. * This method will generate a Route for you if needed and
  1047. * call [registerRoute()]{@link module:workbox-routing.Router#registerRoute}.
  1048. *
  1049. * @param {RegExp|string|module:workbox-routing.Route~matchCallback|module:workbox-routing.Route} capture
  1050. * If the capture param is a `Route`, all other arguments will be ignored.
  1051. * @param {module:workbox-routing~handlerCallback} [handler] A callback
  1052. * function that returns a Promise resulting in a Response. This parameter
  1053. * is required if `capture` is not a `Route` object.
  1054. * @param {string} [method='GET'] The HTTP method to match the Route
  1055. * against.
  1056. * @return {module:workbox-routing.Route} The generated `Route`(Useful for
  1057. * unregistering).
  1058. *
  1059. * @memberof module:workbox-routing
  1060. */
  1061. function registerRoute(capture, handler, method) {
  1062. let route;
  1063. if (typeof capture === 'string') {
  1064. const captureUrl = new URL(capture, location.href);
  1065. {
  1066. if (!(capture.startsWith('/') || capture.startsWith('http'))) {
  1067. throw new WorkboxError('invalid-string', {
  1068. moduleName: 'workbox-routing',
  1069. funcName: 'registerRoute',
  1070. paramName: 'capture'
  1071. });
  1072. } // We want to check if Express-style wildcards are in the pathname only.
  1073. // TODO: Remove this log message in v4.
  1074. const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; // See https://github.com/pillarjs/path-to-regexp#parameters
  1075. const wildcards = '[*:?+]';
  1076. if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
  1077. 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.`);
  1078. }
  1079. }
  1080. const matchCallback = ({
  1081. url
  1082. }) => {
  1083. {
  1084. if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
  1085. logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url}. This route will only handle cross-origin requests ` + `if they match the entire URL.`);
  1086. }
  1087. }
  1088. return url.href === captureUrl.href;
  1089. }; // If `capture` is a string then `handler` and `method` must be present.
  1090. route = new Route(matchCallback, handler, method);
  1091. } else if (capture instanceof RegExp) {
  1092. // If `capture` is a `RegExp` then `handler` and `method` must be present.
  1093. route = new RegExpRoute(capture, handler, method);
  1094. } else if (typeof capture === 'function') {
  1095. // If `capture` is a function then `handler` and `method` must be present.
  1096. route = new Route(capture, handler, method);
  1097. } else if (capture instanceof Route) {
  1098. route = capture;
  1099. } else {
  1100. throw new WorkboxError('unsupported-route-type', {
  1101. moduleName: 'workbox-routing',
  1102. funcName: 'registerRoute',
  1103. paramName: 'capture'
  1104. });
  1105. }
  1106. const defaultRouter = getOrCreateDefaultRouter();
  1107. defaultRouter.registerRoute(route);
  1108. return route;
  1109. }
  1110. try {
  1111. self['workbox:strategies:6.1.5'] && _();
  1112. } catch (e) {}
  1113. /*
  1114. Copyright 2018 Google LLC
  1115. Use of this source code is governed by an MIT-style
  1116. license that can be found in the LICENSE file or at
  1117. https://opensource.org/licenses/MIT.
  1118. */
  1119. const cacheOkAndOpaquePlugin = {
  1120. /**
  1121. * Returns a valid response (to allow caching) if the status is 200 (OK) or
  1122. * 0 (opaque).
  1123. *
  1124. * @param {Object} options
  1125. * @param {Response} options.response
  1126. * @return {Response|null}
  1127. *
  1128. * @private
  1129. */
  1130. cacheWillUpdate: async ({
  1131. response
  1132. }) => {
  1133. if (response.status === 200 || response.status === 0) {
  1134. return response;
  1135. }
  1136. return null;
  1137. }
  1138. };
  1139. /*
  1140. Copyright 2018 Google LLC
  1141. Use of this source code is governed by an MIT-style
  1142. license that can be found in the LICENSE file or at
  1143. https://opensource.org/licenses/MIT.
  1144. */
  1145. const _cacheNameDetails = {
  1146. googleAnalytics: 'googleAnalytics',
  1147. precache: 'precache-v2',
  1148. prefix: 'workbox',
  1149. runtime: 'runtime',
  1150. suffix: typeof registration !== 'undefined' ? registration.scope : ''
  1151. };
  1152. const _createCacheName = cacheName => {
  1153. return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-');
  1154. };
  1155. const eachCacheNameDetail = fn => {
  1156. for (const key of Object.keys(_cacheNameDetails)) {
  1157. fn(key);
  1158. }
  1159. };
  1160. const cacheNames = {
  1161. updateDetails: details => {
  1162. eachCacheNameDetail(key => {
  1163. if (typeof details[key] === 'string') {
  1164. _cacheNameDetails[key] = details[key];
  1165. }
  1166. });
  1167. },
  1168. getGoogleAnalyticsName: userCacheName => {
  1169. return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics);
  1170. },
  1171. getPrecacheName: userCacheName => {
  1172. return userCacheName || _createCacheName(_cacheNameDetails.precache);
  1173. },
  1174. getPrefix: () => {
  1175. return _cacheNameDetails.prefix;
  1176. },
  1177. getRuntimeName: userCacheName => {
  1178. return userCacheName || _createCacheName(_cacheNameDetails.runtime);
  1179. },
  1180. getSuffix: () => {
  1181. return _cacheNameDetails.suffix;
  1182. }
  1183. };
  1184. function _extends() {
  1185. _extends = Object.assign || function (target) {
  1186. for (var i = 1; i < arguments.length; i++) {
  1187. var source = arguments[i];
  1188. for (var key in source) {
  1189. if (Object.prototype.hasOwnProperty.call(source, key)) {
  1190. target[key] = source[key];
  1191. }
  1192. }
  1193. }
  1194. return target;
  1195. };
  1196. return _extends.apply(this, arguments);
  1197. }
  1198. function stripParams(fullURL, ignoreParams) {
  1199. const strippedURL = new URL(fullURL);
  1200. for (const param of ignoreParams) {
  1201. strippedURL.searchParams.delete(param);
  1202. }
  1203. return strippedURL.href;
  1204. }
  1205. /**
  1206. * Matches an item in the cache, ignoring specific URL params. This is similar
  1207. * to the `ignoreSearch` option, but it allows you to ignore just specific
  1208. * params (while continuing to match on the others).
  1209. *
  1210. * @private
  1211. * @param {Cache} cache
  1212. * @param {Request} request
  1213. * @param {Object} matchOptions
  1214. * @param {Array<string>} ignoreParams
  1215. * @return {Promise<Response|undefined>}
  1216. */
  1217. async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) {
  1218. const strippedRequestURL = stripParams(request.url, ignoreParams); // If the request doesn't include any ignored params, match as normal.
  1219. if (request.url === strippedRequestURL) {
  1220. return cache.match(request, matchOptions);
  1221. } // Otherwise, match by comparing keys
  1222. const keysOptions = _extends({}, matchOptions, {
  1223. ignoreSearch: true
  1224. });
  1225. const cacheKeys = await cache.keys(request, keysOptions);
  1226. for (const cacheKey of cacheKeys) {
  1227. const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams);
  1228. if (strippedRequestURL === strippedCacheKeyURL) {
  1229. return cache.match(cacheKey, matchOptions);
  1230. }
  1231. }
  1232. return;
  1233. }
  1234. /*
  1235. Copyright 2018 Google LLC
  1236. Use of this source code is governed by an MIT-style
  1237. license that can be found in the LICENSE file or at
  1238. https://opensource.org/licenses/MIT.
  1239. */
  1240. /**
  1241. * The Deferred class composes Promises in a way that allows for them to be
  1242. * resolved or rejected from outside the constructor. In most cases promises
  1243. * should be used directly, but Deferreds can be necessary when the logic to
  1244. * resolve a promise must be separate.
  1245. *
  1246. * @private
  1247. */
  1248. class Deferred {
  1249. /**
  1250. * Creates a promise and exposes its resolve and reject functions as methods.
  1251. */
  1252. constructor() {
  1253. this.promise = new Promise((resolve, reject) => {
  1254. this.resolve = resolve;
  1255. this.reject = reject;
  1256. });
  1257. }
  1258. }
  1259. /*
  1260. Copyright 2018 Google LLC
  1261. Use of this source code is governed by an MIT-style
  1262. license that can be found in the LICENSE file or at
  1263. https://opensource.org/licenses/MIT.
  1264. */
  1265. const quotaErrorCallbacks = new Set();
  1266. /*
  1267. Copyright 2018 Google LLC
  1268. Use of this source code is governed by an MIT-style
  1269. license that can be found in the LICENSE file or at
  1270. https://opensource.org/licenses/MIT.
  1271. */
  1272. /**
  1273. * Runs all of the callback functions, one at a time sequentially, in the order
  1274. * in which they were registered.
  1275. *
  1276. * @memberof module:workbox-core
  1277. * @private
  1278. */
  1279. async function executeQuotaErrorCallbacks() {
  1280. {
  1281. logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`);
  1282. }
  1283. for (const callback of quotaErrorCallbacks) {
  1284. await callback();
  1285. {
  1286. logger.log(callback, 'is complete.');
  1287. }
  1288. }
  1289. {
  1290. logger.log('Finished running callbacks.');
  1291. }
  1292. }
  1293. /*
  1294. Copyright 2019 Google LLC
  1295. Use of this source code is governed by an MIT-style
  1296. license that can be found in the LICENSE file or at
  1297. https://opensource.org/licenses/MIT.
  1298. */
  1299. /**
  1300. * Returns a promise that resolves and the passed number of milliseconds.
  1301. * This utility is an async/await-friendly version of `setTimeout`.
  1302. *
  1303. * @param {number} ms
  1304. * @return {Promise}
  1305. * @private
  1306. */
  1307. function timeout(ms) {
  1308. return new Promise(resolve => setTimeout(resolve, ms));
  1309. }
  1310. function toRequest(input) {
  1311. return typeof input === 'string' ? new Request(input) : input;
  1312. }
  1313. /**
  1314. * A class created every time a Strategy instance instance calls
  1315. * [handle()]{@link module:workbox-strategies.Strategy~handle} or
  1316. * [handleAll()]{@link module:workbox-strategies.Strategy~handleAll} that wraps all fetch and
  1317. * cache actions around plugin callbacks and keeps track of when the strategy
  1318. * is "done" (i.e. all added `event.waitUntil()` promises have resolved).
  1319. *
  1320. * @memberof module:workbox-strategies
  1321. */
  1322. class StrategyHandler {
  1323. /**
  1324. * Creates a new instance associated with the passed strategy and event
  1325. * that's handling the request.
  1326. *
  1327. * The constructor also initializes the state that will be passed to each of
  1328. * the plugins handling this request.
  1329. *
  1330. * @param {module:workbox-strategies.Strategy} strategy
  1331. * @param {Object} options
  1332. * @param {Request|string} options.request A request to run this strategy for.
  1333. * @param {ExtendableEvent} options.event The event associated with the
  1334. * request.
  1335. * @param {URL} [options.url]
  1336. * @param {*} [options.params]
  1337. * [match callback]{@link module:workbox-routing~matchCallback},
  1338. * (if applicable).
  1339. */
  1340. constructor(strategy, options) {
  1341. this._cacheKeys = {};
  1342. /**
  1343. * The request the strategy is performing (passed to the strategy's
  1344. * `handle()` or `handleAll()` method).
  1345. * @name request
  1346. * @instance
  1347. * @type {Request}
  1348. * @memberof module:workbox-strategies.StrategyHandler
  1349. */
  1350. /**
  1351. * The event associated with this request.
  1352. * @name event
  1353. * @instance
  1354. * @type {ExtendableEvent}
  1355. * @memberof module:workbox-strategies.StrategyHandler
  1356. */
  1357. /**
  1358. * A `URL` instance of `request.url` (if passed to the strategy's
  1359. * `handle()` or `handleAll()` method).
  1360. * Note: the `url` param will be present if the strategy was invoked
  1361. * from a workbox `Route` object.
  1362. * @name url
  1363. * @instance
  1364. * @type {URL|undefined}
  1365. * @memberof module:workbox-strategies.StrategyHandler
  1366. */
  1367. /**
  1368. * A `param` value (if passed to the strategy's
  1369. * `handle()` or `handleAll()` method).
  1370. * Note: the `param` param will be present if the strategy was invoked
  1371. * from a workbox `Route` object and the
  1372. * [match callback]{@link module:workbox-routing~matchCallback} returned
  1373. * a truthy value (it will be that value).
  1374. * @name params
  1375. * @instance
  1376. * @type {*|undefined}
  1377. * @memberof module:workbox-strategies.StrategyHandler
  1378. */
  1379. {
  1380. finalAssertExports.isInstance(options.event, ExtendableEvent, {
  1381. moduleName: 'workbox-strategies',
  1382. className: 'StrategyHandler',
  1383. funcName: 'constructor',
  1384. paramName: 'options.event'
  1385. });
  1386. }
  1387. Object.assign(this, options);
  1388. this.event = options.event;
  1389. this._strategy = strategy;
  1390. this._handlerDeferred = new Deferred();
  1391. this._extendLifetimePromises = []; // Copy the plugins list (since it's mutable on the strategy),
  1392. // so any mutations don't affect this handler instance.
  1393. this._plugins = [...strategy.plugins];
  1394. this._pluginStateMap = new Map();
  1395. for (const plugin of this._plugins) {
  1396. this._pluginStateMap.set(plugin, {});
  1397. }
  1398. this.event.waitUntil(this._handlerDeferred.promise);
  1399. }
  1400. /**
  1401. * Fetches a given request (and invokes any applicable plugin callback
  1402. * methods) using the `fetchOptions` (for non-navigation requests) and
  1403. * `plugins` defined on the `Strategy` object.
  1404. *
  1405. * The following plugin lifecycle methods are invoked when using this method:
  1406. * - `requestWillFetch()`
  1407. * - `fetchDidSucceed()`
  1408. * - `fetchDidFail()`
  1409. *
  1410. * @param {Request|string} input The URL or request to fetch.
  1411. * @return {Promise<Response>}
  1412. */
  1413. async fetch(input) {
  1414. const {
  1415. event
  1416. } = this;
  1417. let request = toRequest(input);
  1418. if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) {
  1419. const possiblePreloadResponse = await event.preloadResponse;
  1420. if (possiblePreloadResponse) {
  1421. {
  1422. logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`);
  1423. }
  1424. return possiblePreloadResponse;
  1425. }
  1426. } // If there is a fetchDidFail plugin, we need to save a clone of the
  1427. // original request before it's either modified by a requestWillFetch
  1428. // plugin or before the original request's body is consumed via fetch().
  1429. const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null;
  1430. try {
  1431. for (const cb of this.iterateCallbacks('requestWillFetch')) {
  1432. request = await cb({
  1433. request: request.clone(),
  1434. event
  1435. });
  1436. }
  1437. } catch (err) {
  1438. throw new WorkboxError('plugin-error-request-will-fetch', {
  1439. thrownError: err
  1440. });
  1441. } // The request can be altered by plugins with `requestWillFetch` making
  1442. // the original request (most likely from a `fetch` event) different
  1443. // from the Request we make. Pass both to `fetchDidFail` to aid debugging.
  1444. const pluginFilteredRequest = request.clone();
  1445. try {
  1446. let fetchResponse; // See https://github.com/GoogleChrome/workbox/issues/1796
  1447. fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions);
  1448. if ("development" !== 'production') {
  1449. logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`);
  1450. }
  1451. for (const callback of this.iterateCallbacks('fetchDidSucceed')) {
  1452. fetchResponse = await callback({
  1453. event,
  1454. request: pluginFilteredRequest,
  1455. response: fetchResponse
  1456. });
  1457. }
  1458. return fetchResponse;
  1459. } catch (error) {
  1460. {
  1461. logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error);
  1462. } // `originalRequest` will only exist if a `fetchDidFail` callback
  1463. // is being used (see above).
  1464. if (originalRequest) {
  1465. await this.runCallbacks('fetchDidFail', {
  1466. error,
  1467. event,
  1468. originalRequest: originalRequest.clone(),
  1469. request: pluginFilteredRequest.clone()
  1470. });
  1471. }
  1472. throw error;
  1473. }
  1474. }
  1475. /**
  1476. * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on
  1477. * the response generated by `this.fetch()`.
  1478. *
  1479. * The call to `this.cachePut()` automatically invokes `this.waitUntil()`,
  1480. * so you do not have to manually call `waitUntil()` on the event.
  1481. *
  1482. * @param {Request|string} input The request or URL to fetch and cache.
  1483. * @return {Promise<Response>}
  1484. */
  1485. async fetchAndCachePut(input) {
  1486. const response = await this.fetch(input);
  1487. const responseClone = response.clone();
  1488. this.waitUntil(this.cachePut(input, responseClone));
  1489. return response;
  1490. }
  1491. /**
  1492. * Matches a request from the cache (and invokes any applicable plugin
  1493. * callback methods) using the `cacheName`, `matchOptions`, and `plugins`
  1494. * defined on the strategy object.
  1495. *
  1496. * The following plugin lifecycle methods are invoked when using this method:
  1497. * - cacheKeyWillByUsed()
  1498. * - cachedResponseWillByUsed()
  1499. *
  1500. * @param {Request|string} key The Request or URL to use as the cache key.
  1501. * @return {Promise<Response|undefined>} A matching response, if found.
  1502. */
  1503. async cacheMatch(key) {
  1504. const request = toRequest(key);
  1505. let cachedResponse;
  1506. const {
  1507. cacheName,
  1508. matchOptions
  1509. } = this._strategy;
  1510. const effectiveRequest = await this.getCacheKey(request, 'read');
  1511. const multiMatchOptions = _extends({}, matchOptions, {
  1512. cacheName
  1513. });
  1514. cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);
  1515. {
  1516. if (cachedResponse) {
  1517. logger.debug(`Found a cached response in '${cacheName}'.`);
  1518. } else {
  1519. logger.debug(`No cached response found in '${cacheName}'.`);
  1520. }
  1521. }
  1522. for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) {
  1523. cachedResponse = (await callback({
  1524. cacheName,
  1525. matchOptions,
  1526. cachedResponse,
  1527. request: effectiveRequest,
  1528. event: this.event
  1529. })) || undefined;
  1530. }
  1531. return cachedResponse;
  1532. }
  1533. /**
  1534. * Puts a request/response pair in the cache (and invokes any applicable
  1535. * plugin callback methods) using the `cacheName` and `plugins` defined on
  1536. * the strategy object.
  1537. *
  1538. * The following plugin lifecycle methods are invoked when using this method:
  1539. * - cacheKeyWillByUsed()
  1540. * - cacheWillUpdate()
  1541. * - cacheDidUpdate()
  1542. *
  1543. * @param {Request|string} key The request or URL to use as the cache key.
  1544. * @param {Response} response The response to cache.
  1545. * @return {Promise<boolean>} `false` if a cacheWillUpdate caused the response
  1546. * not be cached, and `true` otherwise.
  1547. */
  1548. async cachePut(key, response) {
  1549. const request = toRequest(key); // Run in the next task to avoid blocking other cache reads.
  1550. // https://github.com/w3c/ServiceWorker/issues/1397
  1551. await timeout(0);
  1552. const effectiveRequest = await this.getCacheKey(request, 'write');
  1553. {
  1554. if (effectiveRequest.method && effectiveRequest.method !== 'GET') {
  1555. throw new WorkboxError('attempt-to-cache-non-get-request', {
  1556. url: getFriendlyURL(effectiveRequest.url),
  1557. method: effectiveRequest.method
  1558. });
  1559. }
  1560. }
  1561. if (!response) {
  1562. {
  1563. logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`);
  1564. }
  1565. throw new WorkboxError('cache-put-with-no-response', {
  1566. url: getFriendlyURL(effectiveRequest.url)
  1567. });
  1568. }
  1569. const responseToCache = await this._ensureResponseSafeToCache(response);
  1570. if (!responseToCache) {
  1571. {
  1572. logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache);
  1573. }
  1574. return false;
  1575. }
  1576. const {
  1577. cacheName,
  1578. matchOptions
  1579. } = this._strategy;
  1580. const cache = await self.caches.open(cacheName);
  1581. const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate');
  1582. const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams( // TODO(philipwalton): the `__WB_REVISION__` param is a precaching
  1583. // feature. Consider into ways to only add this behavior if using
  1584. // precaching.
  1585. cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null;
  1586. {
  1587. logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`);
  1588. }
  1589. try {
  1590. await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache);
  1591. } catch (error) {
  1592. // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError
  1593. if (error.name === 'QuotaExceededError') {
  1594. await executeQuotaErrorCallbacks();
  1595. }
  1596. throw error;
  1597. }
  1598. for (const callback of this.iterateCallbacks('cacheDidUpdate')) {
  1599. await callback({
  1600. cacheName,
  1601. oldResponse,
  1602. newResponse: responseToCache.clone(),
  1603. request: effectiveRequest,
  1604. event: this.event
  1605. });
  1606. }
  1607. return true;
  1608. }
  1609. /**
  1610. * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and
  1611. * executes any of those callbacks found in sequence. The final `Request`
  1612. * object returned by the last plugin is treated as the cache key for cache
  1613. * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have
  1614. * been registered, the passed request is returned unmodified
  1615. *
  1616. * @param {Request} request
  1617. * @param {string} mode
  1618. * @return {Promise<Request>}
  1619. */
  1620. async getCacheKey(request, mode) {
  1621. if (!this._cacheKeys[mode]) {
  1622. let effectiveRequest = request;
  1623. for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) {
  1624. effectiveRequest = toRequest(await callback({
  1625. mode,
  1626. request: effectiveRequest,
  1627. event: this.event,
  1628. params: this.params
  1629. }));
  1630. }
  1631. this._cacheKeys[mode] = effectiveRequest;
  1632. }
  1633. return this._cacheKeys[mode];
  1634. }
  1635. /**
  1636. * Returns true if the strategy has at least one plugin with the given
  1637. * callback.
  1638. *
  1639. * @param {string} name The name of the callback to check for.
  1640. * @return {boolean}
  1641. */
  1642. hasCallback(name) {
  1643. for (const plugin of this._strategy.plugins) {
  1644. if (name in plugin) {
  1645. return true;
  1646. }
  1647. }
  1648. return false;
  1649. }
  1650. /**
  1651. * Runs all plugin callbacks matching the given name, in order, passing the
  1652. * given param object (merged ith the current plugin state) as the only
  1653. * argument.
  1654. *
  1655. * Note: since this method runs all plugins, it's not suitable for cases
  1656. * where the return value of a callback needs to be applied prior to calling
  1657. * the next callback. See
  1658. * [`iterateCallbacks()`]{@link module:workbox-strategies.StrategyHandler#iterateCallbacks}
  1659. * below for how to handle that case.
  1660. *
  1661. * @param {string} name The name of the callback to run within each plugin.
  1662. * @param {Object} param The object to pass as the first (and only) param
  1663. * when executing each callback. This object will be merged with the
  1664. * current plugin state prior to callback execution.
  1665. */
  1666. async runCallbacks(name, param) {
  1667. for (const callback of this.iterateCallbacks(name)) {
  1668. // TODO(philipwalton): not sure why `any` is needed. It seems like
  1669. // this should work with `as WorkboxPluginCallbackParam[C]`.
  1670. await callback(param);
  1671. }
  1672. }
  1673. /**
  1674. * Accepts a callback and returns an iterable of matching plugin callbacks,
  1675. * where each callback is wrapped with the current handler state (i.e. when
  1676. * you call each callback, whatever object parameter you pass it will
  1677. * be merged with the plugin's current state).
  1678. *
  1679. * @param {string} name The name fo the callback to run
  1680. * @return {Array<Function>}
  1681. */
  1682. *iterateCallbacks(name) {
  1683. for (const plugin of this._strategy.plugins) {
  1684. if (typeof plugin[name] === 'function') {
  1685. const state = this._pluginStateMap.get(plugin);
  1686. const statefulCallback = param => {
  1687. const statefulParam = _extends({}, param, {
  1688. state
  1689. }); // TODO(philipwalton): not sure why `any` is needed. It seems like
  1690. // this should work with `as WorkboxPluginCallbackParam[C]`.
  1691. return plugin[name](statefulParam);
  1692. };
  1693. yield statefulCallback;
  1694. }
  1695. }
  1696. }
  1697. /**
  1698. * Adds a promise to the
  1699. * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises}
  1700. * of the event event associated with the request being handled (usually a
  1701. * `FetchEvent`).
  1702. *
  1703. * Note: you can await
  1704. * [`doneWaiting()`]{@link module:workbox-strategies.StrategyHandler~doneWaiting}
  1705. * to know when all added promises have settled.
  1706. *
  1707. * @param {Promise} promise A promise to add to the extend lifetime promises
  1708. * of the event that triggered the request.
  1709. */
  1710. waitUntil(promise) {
  1711. this._extendLifetimePromises.push(promise);
  1712. return promise;
  1713. }
  1714. /**
  1715. * Returns a promise that resolves once all promises passed to
  1716. * [`waitUntil()`]{@link module:workbox-strategies.StrategyHandler~waitUntil}
  1717. * have settled.
  1718. *
  1719. * Note: any work done after `doneWaiting()` settles should be manually
  1720. * passed to an event's `waitUntil()` method (not this handler's
  1721. * `waitUntil()` method), otherwise the service worker thread my be killed
  1722. * prior to your work completing.
  1723. */
  1724. async doneWaiting() {
  1725. let promise;
  1726. while (promise = this._extendLifetimePromises.shift()) {
  1727. await promise;
  1728. }
  1729. }
  1730. /**
  1731. * Stops running the strategy and immediately resolves any pending
  1732. * `waitUntil()` promises.
  1733. */
  1734. destroy() {
  1735. this._handlerDeferred.resolve();
  1736. }
  1737. /**
  1738. * This method will call cacheWillUpdate on the available plugins (or use
  1739. * status === 200) to determine if the Response is safe and valid to cache.
  1740. *
  1741. * @param {Request} options.request
  1742. * @param {Response} options.response
  1743. * @return {Promise<Response|undefined>}
  1744. *
  1745. * @private
  1746. */
  1747. async _ensureResponseSafeToCache(response) {
  1748. let responseToCache = response;
  1749. let pluginsUsed = false;
  1750. for (const callback of this.iterateCallbacks('cacheWillUpdate')) {
  1751. responseToCache = (await callback({
  1752. request: this.request,
  1753. response: responseToCache,
  1754. event: this.event
  1755. })) || undefined;
  1756. pluginsUsed = true;
  1757. if (!responseToCache) {
  1758. break;
  1759. }
  1760. }
  1761. if (!pluginsUsed) {
  1762. if (responseToCache && responseToCache.status !== 200) {
  1763. responseToCache = undefined;
  1764. }
  1765. {
  1766. if (responseToCache) {
  1767. if (responseToCache.status !== 200) {
  1768. if (responseToCache.status === 0) {
  1769. 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.`);
  1770. } else {
  1771. logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`);
  1772. }
  1773. }
  1774. }
  1775. }
  1776. }
  1777. return responseToCache;
  1778. }
  1779. }
  1780. /*
  1781. Copyright 2020 Google LLC
  1782. Use of this source code is governed by an MIT-style
  1783. license that can be found in the LICENSE file or at
  1784. https://opensource.org/licenses/MIT.
  1785. */
  1786. /**
  1787. * An abstract base class that all other strategy classes must extend from:
  1788. *
  1789. * @memberof module:workbox-strategies
  1790. */
  1791. class Strategy {
  1792. /**
  1793. * Creates a new instance of the strategy and sets all documented option
  1794. * properties as public instance properties.
  1795. *
  1796. * Note: if a custom strategy class extends the base Strategy class and does
  1797. * not need more than these properties, it does not need to define its own
  1798. * constructor.
  1799. *
  1800. * @param {Object} [options]
  1801. * @param {string} [options.cacheName] Cache name to store and retrieve
  1802. * requests. Defaults to the cache names provided by
  1803. * [workbox-core]{@link module:workbox-core.cacheNames}.
  1804. * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
  1805. * to use in conjunction with this caching strategy.
  1806. * @param {Object} [options.fetchOptions] Values passed along to the
  1807. * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
  1808. * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
  1809. * `fetch()` requests made by this strategy.
  1810. * @param {Object} [options.matchOptions] The
  1811. * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}
  1812. * for any `cache.match()` or `cache.put()` calls made by this strategy.
  1813. */
  1814. constructor(options = {}) {
  1815. /**
  1816. * Cache name to store and retrieve
  1817. * requests. Defaults to the cache names provided by
  1818. * [workbox-core]{@link module:workbox-core.cacheNames}.
  1819. *
  1820. * @type {string}
  1821. */
  1822. this.cacheName = cacheNames.getRuntimeName(options.cacheName);
  1823. /**
  1824. * The list
  1825. * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
  1826. * used by this strategy.
  1827. *
  1828. * @type {Array<Object>}
  1829. */
  1830. this.plugins = options.plugins || [];
  1831. /**
  1832. * Values passed along to the
  1833. * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters}
  1834. * of all fetch() requests made by this strategy.
  1835. *
  1836. * @type {Object}
  1837. */
  1838. this.fetchOptions = options.fetchOptions;
  1839. /**
  1840. * The
  1841. * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}
  1842. * for any `cache.match()` or `cache.put()` calls made by this strategy.
  1843. *
  1844. * @type {Object}
  1845. */
  1846. this.matchOptions = options.matchOptions;
  1847. }
  1848. /**
  1849. * Perform a request strategy and returns a `Promise` that will resolve with
  1850. * a `Response`, invoking all relevant plugin callbacks.
  1851. *
  1852. * When a strategy instance is registered with a Workbox
  1853. * [route]{@link module:workbox-routing.Route}, this method is automatically
  1854. * called when the route matches.
  1855. *
  1856. * Alternatively, this method can be used in a standalone `FetchEvent`
  1857. * listener by passing it to `event.respondWith()`.
  1858. *
  1859. * @param {FetchEvent|Object} options A `FetchEvent` or an object with the
  1860. * properties listed below.
  1861. * @param {Request|string} options.request A request to run this strategy for.
  1862. * @param {ExtendableEvent} options.event The event associated with the
  1863. * request.
  1864. * @param {URL} [options.url]
  1865. * @param {*} [options.params]
  1866. */
  1867. handle(options) {
  1868. const [responseDone] = this.handleAll(options);
  1869. return responseDone;
  1870. }
  1871. /**
  1872. * Similar to [`handle()`]{@link module:workbox-strategies.Strategy~handle}, but
  1873. * instead of just returning a `Promise` that resolves to a `Response` it
  1874. * it will return an tuple of [response, done] promises, where the former
  1875. * (`response`) is equivalent to what `handle()` returns, and the latter is a
  1876. * Promise that will resolve once any promises that were added to
  1877. * `event.waitUntil()` as part of performing the strategy have completed.
  1878. *
  1879. * You can await the `done` promise to ensure any extra work performed by
  1880. * the strategy (usually caching responses) completes successfully.
  1881. *
  1882. * @param {FetchEvent|Object} options A `FetchEvent` or an object with the
  1883. * properties listed below.
  1884. * @param {Request|string} options.request A request to run this strategy for.
  1885. * @param {ExtendableEvent} options.event The event associated with the
  1886. * request.
  1887. * @param {URL} [options.url]
  1888. * @param {*} [options.params]
  1889. * @return {Array<Promise>} A tuple of [response, done]
  1890. * promises that can be used to determine when the response resolves as
  1891. * well as when the handler has completed all its work.
  1892. */
  1893. handleAll(options) {
  1894. // Allow for flexible options to be passed.
  1895. if (options instanceof FetchEvent) {
  1896. options = {
  1897. event: options,
  1898. request: options.request
  1899. };
  1900. }
  1901. const event = options.event;
  1902. const request = typeof options.request === 'string' ? new Request(options.request) : options.request;
  1903. const params = 'params' in options ? options.params : undefined;
  1904. const handler = new StrategyHandler(this, {
  1905. event,
  1906. request,
  1907. params
  1908. });
  1909. const responseDone = this._getResponse(handler, request, event);
  1910. const handlerDone = this._awaitComplete(responseDone, handler, request, event); // Return an array of promises, suitable for use with Promise.all().
  1911. return [responseDone, handlerDone];
  1912. }
  1913. async _getResponse(handler, request, event) {
  1914. await handler.runCallbacks('handlerWillStart', {
  1915. event,
  1916. request
  1917. });
  1918. let response = undefined;
  1919. try {
  1920. response = await this._handle(request, handler); // The "official" Strategy subclasses all throw this error automatically,
  1921. // but in case a third-party Strategy doesn't, ensure that we have a
  1922. // consistent failure when there's no response or an error response.
  1923. if (!response || response.type === 'error') {
  1924. throw new WorkboxError('no-response', {
  1925. url: request.url
  1926. });
  1927. }
  1928. } catch (error) {
  1929. for (const callback of handler.iterateCallbacks('handlerDidError')) {
  1930. response = await callback({
  1931. error,
  1932. event,
  1933. request
  1934. });
  1935. if (response) {
  1936. break;
  1937. }
  1938. }
  1939. if (!response) {
  1940. throw error;
  1941. } else {
  1942. logger.log(`While responding to '${getFriendlyURL(request.url)}', ` + `an ${error} error occurred. Using a fallback response provided by ` + `a handlerDidError plugin.`);
  1943. }
  1944. }
  1945. for (const callback of handler.iterateCallbacks('handlerWillRespond')) {
  1946. response = await callback({
  1947. event,
  1948. request,
  1949. response
  1950. });
  1951. }
  1952. return response;
  1953. }
  1954. async _awaitComplete(responseDone, handler, request, event) {
  1955. let response;
  1956. let error;
  1957. try {
  1958. response = await responseDone;
  1959. } catch (error) {// Ignore errors, as response errors should be caught via the `response`
  1960. // promise above. The `done` promise will only throw for errors in
  1961. // promises passed to `handler.waitUntil()`.
  1962. }
  1963. try {
  1964. await handler.runCallbacks('handlerDidRespond', {
  1965. event,
  1966. request,
  1967. response
  1968. });
  1969. await handler.doneWaiting();
  1970. } catch (waitUntilError) {
  1971. error = waitUntilError;
  1972. }
  1973. await handler.runCallbacks('handlerDidComplete', {
  1974. event,
  1975. request,
  1976. response,
  1977. error
  1978. });
  1979. handler.destroy();
  1980. if (error) {
  1981. throw error;
  1982. }
  1983. }
  1984. }
  1985. /**
  1986. * Classes extending the `Strategy` based class should implement this method,
  1987. * and leverage the [`handler`]{@link module:workbox-strategies.StrategyHandler}
  1988. * arg to perform all fetching and cache logic, which will ensure all relevant
  1989. * cache, cache options, fetch options and plugins are used (per the current
  1990. * strategy instance).
  1991. *
  1992. * @name _handle
  1993. * @instance
  1994. * @abstract
  1995. * @function
  1996. * @param {Request} request
  1997. * @param {module:workbox-strategies.StrategyHandler} handler
  1998. * @return {Promise<Response>}
  1999. *
  2000. * @memberof module:workbox-strategies.Strategy
  2001. */
  2002. /*
  2003. Copyright 2018 Google LLC
  2004. Use of this source code is governed by an MIT-style
  2005. license that can be found in the LICENSE file or at
  2006. https://opensource.org/licenses/MIT.
  2007. */
  2008. const messages = {
  2009. strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`,
  2010. printFinalResponse: response => {
  2011. if (response) {
  2012. logger.groupCollapsed(`View the final response here.`);
  2013. logger.log(response || '[No response returned]');
  2014. logger.groupEnd();
  2015. }
  2016. }
  2017. };
  2018. /*
  2019. Copyright 2018 Google LLC
  2020. Use of this source code is governed by an MIT-style
  2021. license that can be found in the LICENSE file or at
  2022. https://opensource.org/licenses/MIT.
  2023. */
  2024. /**
  2025. * An implementation of a
  2026. * [network first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#network-falling-back-to-cache}
  2027. * request strategy.
  2028. *
  2029. * By default, this strategy will cache responses with a 200 status code as
  2030. * well as [opaque responses]{@link https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests}.
  2031. * Opaque responses are are cross-origin requests where the response doesn't
  2032. * support [CORS]{@link https://enable-cors.org/}.
  2033. *
  2034. * If the network request fails, and there is no cache match, this will throw
  2035. * a `WorkboxError` exception.
  2036. *
  2037. * @extends module:workbox-strategies.Strategy
  2038. * @memberof module:workbox-strategies
  2039. */
  2040. class NetworkFirst extends Strategy {
  2041. /**
  2042. * @param {Object} [options]
  2043. * @param {string} [options.cacheName] Cache name to store and retrieve
  2044. * requests. Defaults to cache names provided by
  2045. * [workbox-core]{@link module:workbox-core.cacheNames}.
  2046. * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
  2047. * to use in conjunction with this caching strategy.
  2048. * @param {Object} [options.fetchOptions] Values passed along to the
  2049. * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
  2050. * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
  2051. * `fetch()` requests made by this strategy.
  2052. * @param {Object} [options.matchOptions] [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
  2053. * @param {number} [options.networkTimeoutSeconds] If set, any network requests
  2054. * that fail to respond within the timeout will fallback to the cache.
  2055. *
  2056. * This option can be used to combat
  2057. * "[lie-fi]{@link https://developers.google.com/web/fundamentals/performance/poor-connectivity/#lie-fi}"
  2058. * scenarios.
  2059. */
  2060. constructor(options = {}) {
  2061. super(options); // If this instance contains no plugins with a 'cacheWillUpdate' callback,
  2062. // prepend the `cacheOkAndOpaquePlugin` plugin to the plugins list.
  2063. if (!this.plugins.some(p => 'cacheWillUpdate' in p)) {
  2064. this.plugins.unshift(cacheOkAndOpaquePlugin);
  2065. }
  2066. this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
  2067. {
  2068. if (this._networkTimeoutSeconds) {
  2069. finalAssertExports.isType(this._networkTimeoutSeconds, 'number', {
  2070. moduleName: 'workbox-strategies',
  2071. className: this.constructor.name,
  2072. funcName: 'constructor',
  2073. paramName: 'networkTimeoutSeconds'
  2074. });
  2075. }
  2076. }
  2077. }
  2078. /**
  2079. * @private
  2080. * @param {Request|string} request A request to run this strategy for.
  2081. * @param {module:workbox-strategies.StrategyHandler} handler The event that
  2082. * triggered the request.
  2083. * @return {Promise<Response>}
  2084. */
  2085. async _handle(request, handler) {
  2086. const logs = [];
  2087. {
  2088. finalAssertExports.isInstance(request, Request, {
  2089. moduleName: 'workbox-strategies',
  2090. className: this.constructor.name,
  2091. funcName: 'handle',
  2092. paramName: 'makeRequest'
  2093. });
  2094. }
  2095. const promises = [];
  2096. let timeoutId;
  2097. if (this._networkTimeoutSeconds) {
  2098. const {
  2099. id,
  2100. promise
  2101. } = this._getTimeoutPromise({
  2102. request,
  2103. logs,
  2104. handler
  2105. });
  2106. timeoutId = id;
  2107. promises.push(promise);
  2108. }
  2109. const networkPromise = this._getNetworkPromise({
  2110. timeoutId,
  2111. request,
  2112. logs,
  2113. handler
  2114. });
  2115. promises.push(networkPromise);
  2116. const response = await handler.waitUntil((async () => {
  2117. // Promise.race() will resolve as soon as the first promise resolves.
  2118. return (await handler.waitUntil(Promise.race(promises))) || ( // If Promise.race() resolved with null, it might be due to a network
  2119. // timeout + a cache miss. If that were to happen, we'd rather wait until
  2120. // the networkPromise resolves instead of returning null.
  2121. // Note that it's fine to await an already-resolved promise, so we don't
  2122. // have to check to see if it's still "in flight".
  2123. await networkPromise);
  2124. })());
  2125. {
  2126. logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
  2127. for (const log of logs) {
  2128. logger.log(log);
  2129. }
  2130. messages.printFinalResponse(response);
  2131. logger.groupEnd();
  2132. }
  2133. if (!response) {
  2134. throw new WorkboxError('no-response', {
  2135. url: request.url
  2136. });
  2137. }
  2138. return response;
  2139. }
  2140. /**
  2141. * @param {Object} options
  2142. * @param {Request} options.request
  2143. * @param {Array} options.logs A reference to the logs array
  2144. * @param {Event} options.event
  2145. * @return {Promise<Response>}
  2146. *
  2147. * @private
  2148. */
  2149. _getTimeoutPromise({
  2150. request,
  2151. logs,
  2152. handler
  2153. }) {
  2154. let timeoutId;
  2155. const timeoutPromise = new Promise(resolve => {
  2156. const onNetworkTimeout = async () => {
  2157. {
  2158. logs.push(`Timing out the network response at ` + `${this._networkTimeoutSeconds} seconds.`);
  2159. }
  2160. resolve(await handler.cacheMatch(request));
  2161. };
  2162. timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000);
  2163. });
  2164. return {
  2165. promise: timeoutPromise,
  2166. id: timeoutId
  2167. };
  2168. }
  2169. /**
  2170. * @param {Object} options
  2171. * @param {number|undefined} options.timeoutId
  2172. * @param {Request} options.request
  2173. * @param {Array} options.logs A reference to the logs Array.
  2174. * @param {Event} options.event
  2175. * @return {Promise<Response>}
  2176. *
  2177. * @private
  2178. */
  2179. async _getNetworkPromise({
  2180. timeoutId,
  2181. request,
  2182. logs,
  2183. handler
  2184. }) {
  2185. let error;
  2186. let response;
  2187. try {
  2188. response = await handler.fetchAndCachePut(request);
  2189. } catch (fetchError) {
  2190. error = fetchError;
  2191. }
  2192. if (timeoutId) {
  2193. clearTimeout(timeoutId);
  2194. }
  2195. {
  2196. if (response) {
  2197. logs.push(`Got response from network.`);
  2198. } else {
  2199. logs.push(`Unable to get a response from the network. Will respond ` + `with a cached response.`);
  2200. }
  2201. }
  2202. if (error || !response) {
  2203. response = await handler.cacheMatch(request);
  2204. {
  2205. if (response) {
  2206. logs.push(`Found a cached response in the '${this.cacheName}'` + ` cache.`);
  2207. } else {
  2208. logs.push(`No response found in the '${this.cacheName}' cache.`);
  2209. }
  2210. }
  2211. }
  2212. return response;
  2213. }
  2214. }
  2215. /*
  2216. Copyright 2018 Google LLC
  2217. Use of this source code is governed by an MIT-style
  2218. license that can be found in the LICENSE file or at
  2219. https://opensource.org/licenses/MIT.
  2220. */
  2221. /**
  2222. * An implementation of a
  2223. * [network-only]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#network-only}
  2224. * request strategy.
  2225. *
  2226. * This class is useful if you want to take advantage of any
  2227. * [Workbox plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}.
  2228. *
  2229. * If the network request fails, this will throw a `WorkboxError` exception.
  2230. *
  2231. * @extends module:workbox-strategies.Strategy
  2232. * @memberof module:workbox-strategies
  2233. */
  2234. class NetworkOnly extends Strategy {
  2235. /**
  2236. * @param {Object} [options]
  2237. * @param {Array<Object>} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
  2238. * to use in conjunction with this caching strategy.
  2239. * @param {Object} [options.fetchOptions] Values passed along to the
  2240. * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
  2241. * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)
  2242. * `fetch()` requests made by this strategy.
  2243. * @param {number} [options.networkTimeoutSeconds] If set, any network requests
  2244. * that fail to respond within the timeout will result in a network error.
  2245. */
  2246. constructor(options = {}) {
  2247. super(options);
  2248. this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
  2249. }
  2250. /**
  2251. * @private
  2252. * @param {Request|string} request A request to run this strategy for.
  2253. * @param {module:workbox-strategies.StrategyHandler} handler The event that
  2254. * triggered the request.
  2255. * @return {Promise<Response>}
  2256. */
  2257. async _handle(request, handler) {
  2258. {
  2259. finalAssertExports.isInstance(request, Request, {
  2260. moduleName: 'workbox-strategies',
  2261. className: this.constructor.name,
  2262. funcName: '_handle',
  2263. paramName: 'request'
  2264. });
  2265. }
  2266. let error = undefined;
  2267. let response;
  2268. try {
  2269. const promises = [handler.fetch(request)];
  2270. if (this._networkTimeoutSeconds) {
  2271. const timeoutPromise = timeout(this._networkTimeoutSeconds * 1000);
  2272. promises.push(timeoutPromise);
  2273. }
  2274. response = await Promise.race(promises);
  2275. if (!response) {
  2276. throw new Error(`Timed out the network response after ` + `${this._networkTimeoutSeconds} seconds.`);
  2277. }
  2278. } catch (err) {
  2279. error = err;
  2280. }
  2281. {
  2282. logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));
  2283. if (response) {
  2284. logger.log(`Got response from network.`);
  2285. } else {
  2286. logger.log(`Unable to get a response from the network.`);
  2287. }
  2288. messages.printFinalResponse(response);
  2289. logger.groupEnd();
  2290. }
  2291. if (!response) {
  2292. throw new WorkboxError('no-response', {
  2293. url: request.url,
  2294. error
  2295. });
  2296. }
  2297. return response;
  2298. }
  2299. }
  2300. /*
  2301. Copyright 2019 Google LLC
  2302. Use of this source code is governed by an MIT-style
  2303. license that can be found in the LICENSE file or at
  2304. https://opensource.org/licenses/MIT.
  2305. */
  2306. /**
  2307. * Claim any currently available clients once the service worker
  2308. * becomes active. This is normally used in conjunction with `skipWaiting()`.
  2309. *
  2310. * @memberof module:workbox-core
  2311. */
  2312. function clientsClaim() {
  2313. self.addEventListener('activate', () => self.clients.claim());
  2314. }
  2315. exports.NetworkFirst = NetworkFirst;
  2316. exports.NetworkOnly = NetworkOnly;
  2317. exports.clientsClaim = clientsClaim;
  2318. exports.registerRoute = registerRoute;
  2319. });
  2320. //# sourceMappingURL=workbox-6b19f60b.js.map