{"version":3,"file":"index.mjs","names":["privateCacheNames","privateCacheNames","privateCacheNames","privateCacheNames","clientsClaim","disableDevLogs"],"sources":["../src/cacheNames.ts","../src/lib/broadcastUpdate/constants.ts","../src/lib/broadcastUpdate/responsesAreSame.ts","../src/lib/broadcastUpdate/BroadcastCacheUpdate.ts","../src/lib/broadcastUpdate/BroadcastUpdatePlugin.ts","../src/lib/cacheableResponse/CacheableResponse.ts","../src/lib/cacheableResponse/CacheableResponsePlugin.ts","../src/lib/expiration/models/CacheTimestampsModel.ts","../src/lib/expiration/CacheExpiration.ts","../src/registerQuotaErrorCallback.ts","../src/lib/expiration/ExpirationPlugin.ts","../src/lib/googleAnalytics/constants.ts","../src/lib/googleAnalytics/initializeGoogleAnalytics.ts","../src/lib/precaching/PrecacheFallbackPlugin.ts","../src/lib/rangeRequests/utils/calculateEffectiveBoundaries.ts","../src/lib/rangeRequests/utils/parseRangeHeader.ts","../src/lib/rangeRequests/createPartialResponse.ts","../src/lib/rangeRequests/RangeRequestsPlugin.ts","../src/lib/strategies/CacheFirst.ts","../src/lib/strategies/CacheOnly.ts","../src/lib/strategies/StaleWhileRevalidate.ts","../src/PrecacheRoute.ts","../src/utils/PrecacheCacheKeyPlugin.ts","../src/utils/parsePrecacheOptions.ts","../src/Serwist.ts"],"sourcesContent":["/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { cacheNames as privateCacheNames } from \"./utils/cacheNames.js\";\n\n/**\n * Get the current cache names and prefix/suffix used by Serwist.\n *\n * `cacheNames.precache` is used for precached assets,\n * `cacheNames.googleAnalytics` is used by `@serwist/google-analytics` to\n * store `analytics.js`, and `cacheNames.runtime` is used for everything else.\n *\n * `cacheNames.prefix` can be used to retrieve just the current prefix value.\n * `cacheNames.suffix` can be used to retrieve just the current suffix value.\n *\n * @returns An object with `precache`, `runtime`, `prefix`, and `googleAnalytics` properties.\n */\nexport const cacheNames = {\n  get googleAnalytics(): string {\n    return privateCacheNames.getGoogleAnalyticsName();\n  },\n  get precache(): string {\n    return privateCacheNames.getPrecacheName();\n  },\n  get prefix(): string {\n    return privateCacheNames.getPrefix();\n  },\n  get runtime(): string {\n    return privateCacheNames.getRuntimeName();\n  },\n  get suffix(): string {\n    return privateCacheNames.getSuffix();\n  },\n};\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nexport const BROADCAST_UPDATE_MESSAGE_TYPE = \"CACHE_UPDATED\";\nexport const BROADCAST_UPDATE_MESSAGE_META = \"serwist-broadcast-update\";\nexport const BROADCAST_UPDATE_DEFAULT_NOTIFY = true;\nexport const BROADCAST_UPDATE_DEFAULT_HEADERS = [\"content-length\", \"etag\", \"last-modified\"];\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\n\n/**\n * Given two responses, compares several header values to see if they are\n * the same or not.\n *\n * @param firstResponse The first response.\n * @param secondResponse The second response.\n * @param headersToCheck A list of headers to check.\n * @returns\n */\nexport const responsesAreSame = (firstResponse: Response, secondResponse: Response, headersToCheck: string[]): boolean => {\n  if (process.env.NODE_ENV !== \"production\") {\n    if (!(firstResponse instanceof Response && secondResponse instanceof Response)) {\n      throw new SerwistError(\"invalid-responses-are-same-args\");\n    }\n  }\n\n  const atLeastOneHeaderAvailable = headersToCheck.some((header) => {\n    return firstResponse.headers.has(header) && secondResponse.headers.has(header);\n  });\n\n  if (!atLeastOneHeaderAvailable) {\n    if (process.env.NODE_ENV !== \"production\") {\n      logger.warn(\"Unable to determine where the response has been updated because none of the headers that would be checked are present.\");\n      logger.debug(\"Attempting to compare the following: \", firstResponse, secondResponse, headersToCheck);\n    }\n\n    // Just return true, indicating the that responses are the same, since we\n    // can't determine otherwise.\n    return true;\n  }\n\n  return headersToCheck.every((header) => {\n    const headerStateComparison = firstResponse.headers.has(header) === secondResponse.headers.has(header);\n    const headerValueComparison = firstResponse.headers.get(header) === secondResponse.headers.get(header);\n\n    return headerStateComparison && headerValueComparison;\n  });\n};\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { CacheDidUpdateCallbackParam } from \"../../types.js\";\nimport { assert } from \"../../utils/assert.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { resultingClientExists } from \"../../utils/resultingClientExists.js\";\nimport { timeout } from \"../../utils/timeout.js\";\nimport {\n  BROADCAST_UPDATE_DEFAULT_HEADERS,\n  BROADCAST_UPDATE_DEFAULT_NOTIFY,\n  BROADCAST_UPDATE_MESSAGE_META,\n  BROADCAST_UPDATE_MESSAGE_TYPE,\n} from \"./constants.js\";\nimport { responsesAreSame } from \"./responsesAreSame.js\";\nimport type { BroadcastCacheUpdateOptions, BroadcastMessage, BroadcastPayload, BroadcastPayloadGenerator } from \"./types.js\";\n\n// UA-sniff Safari: https://stackoverflow.com/questions/7944460/detect-safari-browser\n// TODO(philipwalton): remove once this Safari bug fix has been released.\n// https://bugs.webkit.org/show_bug.cgi?id=201169\nconst isSafari = typeof navigator !== \"undefined\" && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n\n// Give TypeScript the correct global.\ndeclare const self: ServiceWorkerGlobalScope;\n/**\n * Generates the default payload used in update messages. By default the\n * payload includes the `cacheName` and `updatedURL` fields.\n *\n * @returns\n * @private\n */\nconst defaultPayloadGenerator = (data: CacheDidUpdateCallbackParam): BroadcastPayload => {\n  return {\n    cacheName: data.cacheName,\n    updatedURL: data.request.url,\n  };\n};\n\n/**\n * A class that uses the `postMessage()` API to inform any open windows/tabs when\n * a cached response has been updated.\n *\n * For efficiency's sake, the underlying response bodies are not compared;\n * only specific response headers are checked.\n */\nexport class BroadcastCacheUpdate {\n  private readonly _headersToCheck: string[];\n  private readonly _generatePayload: BroadcastPayloadGenerator;\n  private readonly _notifyAllClients: boolean;\n\n  /**\n   * Construct an instance of `BroadcastCacheUpdate`.\n   *\n   * @param options\n   */\n  constructor({ generatePayload, headersToCheck, notifyAllClients }: BroadcastCacheUpdateOptions = {}) {\n    this._headersToCheck = headersToCheck || BROADCAST_UPDATE_DEFAULT_HEADERS;\n    this._generatePayload = generatePayload || defaultPayloadGenerator;\n    this._notifyAllClients = notifyAllClients ?? BROADCAST_UPDATE_DEFAULT_NOTIFY;\n  }\n\n  /**\n   * Compares two responses and sends a message (via `postMessage()`) to all window clients if the\n   * responses differ. Neither of the Responses can be opaque.\n   *\n   * The message that's posted has the following format (where `payload` can\n   * be customized via the `generatePayload` option the instance is created\n   * with):\n   *\n   * ```\n   * {\n   *   type: 'CACHE_UPDATED',\n   *   meta: 'workbox-broadcast-update',\n   *   payload: {\n   *     cacheName: 'the-cache-name',\n   *     updatedURL: 'https://example.com/'\n   *   }\n   * }\n   * ```\n   *\n   * @param options\n   * @returns Resolves once the update is sent.\n   */\n  async notifyIfUpdated(options: CacheDidUpdateCallbackParam): Promise<void> {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isType(options.cacheName, \"string\", {\n        moduleName: \"serwist\",\n        className: \"BroadcastCacheUpdate\",\n        funcName: \"notifyIfUpdated\",\n        paramName: \"cacheName\",\n      });\n      assert!.isInstance(options.newResponse, Response, {\n        moduleName: \"serwist\",\n        className: \"BroadcastCacheUpdate\",\n        funcName: \"notifyIfUpdated\",\n        paramName: \"newResponse\",\n      });\n      assert!.isInstance(options.request, Request, {\n        moduleName: \"serwist\",\n        className: \"BroadcastCacheUpdate\",\n        funcName: \"notifyIfUpdated\",\n        paramName: \"request\",\n      });\n    }\n\n    // Without two responses there is nothing to compare.\n    if (!options.oldResponse) {\n      return;\n    }\n\n    if (!responsesAreSame(options.oldResponse, options.newResponse, this._headersToCheck)) {\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.log(\"Newer response found (and cached) for:\", options.request.url);\n      }\n\n      const messageData = {\n        type: BROADCAST_UPDATE_MESSAGE_TYPE,\n        meta: BROADCAST_UPDATE_MESSAGE_META,\n        payload: this._generatePayload(options),\n      } satisfies BroadcastMessage;\n\n      // For navigation requests, wait until the new window client exists\n      // before sending the message\n      if (options.request.mode === \"navigate\") {\n        let resultingClientId: string | undefined;\n        if (options.event instanceof FetchEvent) {\n          resultingClientId = options.event.resultingClientId;\n        }\n\n        const resultingWin = await resultingClientExists(resultingClientId);\n\n        // Safari does not currently implement postMessage buffering and\n        // there's no good way to feature detect that, so to increase the\n        // chances of the message being delivered in Safari, we add a timeout.\n        // We also do this if `resultingClientExists()` didn't return a client,\n        // which means it timed out, so it's worth waiting a bit longer.\n        if (!resultingWin || isSafari) {\n          // 3500 is chosen because (according to CrUX data) 80% of mobile\n          // websites hit the DOMContentLoaded event in less than 3.5 seconds.\n          // And presumably sites implementing service worker are on the\n          // higher end of the performance spectrum.\n          await timeout(3500);\n        }\n      }\n\n      if (this._notifyAllClients) {\n        const windows = await self.clients.matchAll({ type: \"window\" });\n        for (const win of windows) {\n          win.postMessage(messageData);\n        }\n      } else {\n        // See https://github.com/GoogleChrome/workbox/issues/2895\n        if (options.event instanceof FetchEvent) {\n          const client = await self.clients.get(options.event.clientId);\n          client?.postMessage(messageData);\n        }\n      }\n    }\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { CacheDidUpdateCallbackParam, SerwistPlugin } from \"../../types.js\";\nimport { BroadcastCacheUpdate } from \"./BroadcastCacheUpdate.js\";\nimport type { BroadcastCacheUpdateOptions } from \"./types.js\";\n\n/**\n * A class implementing the `cacheDidUpdate` lifecycle callback. It will automatically\n * broadcast a message whenever a cached response is updated.\n */\nexport class BroadcastUpdatePlugin implements SerwistPlugin {\n  private readonly _broadcastUpdate: BroadcastCacheUpdate;\n\n  /**\n   * Construct a {@linkcode BroadcastCacheUpdate} instance with\n   * the passed options and calls its {@linkcode BroadcastCacheUpdate.notifyIfUpdated}\n   * method whenever the plugin's {@linkcode BroadcastUpdatePlugin.cacheDidUpdate} callback\n   * is invoked.\n   *\n   * @param options\n   */\n  constructor(options?: BroadcastCacheUpdateOptions) {\n    this._broadcastUpdate = new BroadcastCacheUpdate(options);\n  }\n\n  /**\n   * @private\n   * @param options The input object to this function.\n   */\n  cacheDidUpdate(options: CacheDidUpdateCallbackParam) {\n    void this._broadcastUpdate.notifyIfUpdated(options);\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../utils/assert.js\";\nimport { getFriendlyURL } from \"../../utils/getFriendlyURL.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\n\nexport interface CacheableResponseOptions {\n  /**\n   * One or more HTTP status codes that a response can have to be considered cacheable.\n   */\n  statuses?: number[];\n  /**\n   * A mapping of header names and expected values that a response can have and be\n   * considered cacheable. If multiple headers are provided, only one needs to be present.\n   */\n  headers?: HeadersInit;\n}\n\n/**\n * Allows you to set up rules determining what status codes and/or headers need\n * to be present in order for a [response](https://developer.mozilla.org/en-US/docs/Web/API/Response)\n * to be considered cacheable.\n */\nexport class CacheableResponse {\n  private readonly _statuses?: CacheableResponseOptions[\"statuses\"];\n  private readonly _headers?: Headers;\n\n  /**\n   * To construct a new `CacheableResponse` instance you must provide at least\n   * one of the `config` properties.\n   *\n   * If both `statuses` and `headers` are specified, then both conditions must\n   * be met for the response to be considered cacheable.\n   *\n   * @param config\n   */\n  constructor(config: CacheableResponseOptions = {}) {\n    if (process.env.NODE_ENV !== \"production\") {\n      if (!(config.statuses || config.headers)) {\n        throw new SerwistError(\"statuses-or-headers-required\", {\n          moduleName: \"serwist\",\n          className: \"CacheableResponse\",\n          funcName: \"constructor\",\n        });\n      }\n\n      if (config.statuses) {\n        assert!.isArray(config.statuses, {\n          moduleName: \"serwist\",\n          className: \"CacheableResponse\",\n          funcName: \"constructor\",\n          paramName: \"config.statuses\",\n        });\n      }\n\n      if (config.headers) {\n        assert!.isType(config.headers, \"object\", {\n          moduleName: \"serwist\",\n          className: \"CacheableResponse\",\n          funcName: \"constructor\",\n          paramName: \"config.headers\",\n        });\n      }\n    }\n\n    this._statuses = config.statuses;\n    if (config.headers) {\n      this._headers = new Headers(config.headers);\n    }\n  }\n\n  /**\n   * Checks a response to see whether it's cacheable or not.\n   *\n   * @param response The response whose cacheability is being\n   * checked.\n   * @returns `true` if the response is cacheable, and `false`\n   * otherwise.\n   */\n  isResponseCacheable(response: Response): boolean {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isInstance(response, Response, {\n        moduleName: \"serwist\",\n        className: \"CacheableResponse\",\n        funcName: \"isResponseCacheable\",\n        paramName: \"response\",\n      });\n    }\n\n    let cacheable = true;\n\n    if (this._statuses) {\n      cacheable = this._statuses.includes(response.status);\n    }\n\n    if (this._headers && cacheable) {\n      for (const [headerName, headerValue] of this._headers.entries()) {\n        if (response.headers.get(headerName) !== headerValue) {\n          cacheable = false;\n          break;\n        }\n      }\n    }\n\n    if (process.env.NODE_ENV !== \"production\") {\n      if (!cacheable) {\n        logger.groupCollapsed(\n          `The request for '${getFriendlyURL(response.url)}' returned a response that does not meet the criteria for being cached.`,\n        );\n\n        logger.groupCollapsed(\"View cacheability criteria here.\");\n        logger.log(`Cacheable statuses: ${JSON.stringify(this._statuses)}`);\n        logger.log(`Cacheable headers: ${JSON.stringify(this._headers, null, 2)}`);\n        logger.groupEnd();\n\n        const logFriendlyHeaders: { [key: string]: string } = {};\n        response.headers.forEach((value, key) => {\n          logFriendlyHeaders[key] = value;\n        });\n\n        logger.groupCollapsed(\"View response status and headers here.\");\n        logger.log(`Response status: ${response.status}`);\n        logger.log(`Response headers: ${JSON.stringify(logFriendlyHeaders, null, 2)}`);\n        logger.groupEnd();\n\n        logger.groupCollapsed(\"View full response details here.\");\n        logger.log(response.headers);\n        logger.log(response);\n        logger.groupEnd();\n\n        logger.groupEnd();\n      }\n    }\n\n    return cacheable;\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { SerwistPlugin } from \"../../types.js\";\nimport type { CacheableResponseOptions } from \"./CacheableResponse.js\";\nimport { CacheableResponse } from \"./CacheableResponse.js\";\n\n/**\n * A class implementing the `cacheWillUpdate` lifecycle callback. This makes it\n * easier to add in cacheability checks to requests made via Serwist's built-in\n * strategies.\n */\nexport class CacheableResponsePlugin implements SerwistPlugin {\n  private readonly _cacheableResponse: CacheableResponse;\n\n  /**\n   * To construct a new `CacheableResponsePlugin` instance you must provide at\n   * least one of the `config` properties.\n   *\n   * If both `statuses` and `headers` are specified, then both conditions must\n   * be met for the response to be considered cacheable.\n   *\n   * @param config\n   */\n  constructor(config: CacheableResponseOptions) {\n    this._cacheableResponse = new CacheableResponse(config);\n  }\n\n  /**\n   * @param options\n   * @returns\n   * @private\n   */\n  cacheWillUpdate: SerwistPlugin[\"cacheWillUpdate\"] = async ({ response }) => {\n    if (this._cacheableResponse.isResponseCacheable(response)) {\n      return response;\n    }\n    return null;\n  };\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { DBSchema, IDBPDatabase } from \"idb\";\nimport { deleteDB, openDB } from \"idb\";\n\nconst DB_NAME = \"serwist-expiration\";\nconst CACHE_OBJECT_STORE = \"cache-entries\";\n\nconst normalizeURL = (unNormalizedUrl: string) => {\n  const url = new URL(unNormalizedUrl, location.href);\n  url.hash = \"\";\n\n  return url.href;\n};\n\ninterface CacheTimestampsModelEntry {\n  id: string;\n  cacheName: string;\n  url: string;\n  timestamp: number;\n}\n\ninterface CacheDbSchema extends DBSchema {\n  \"cache-entries\": {\n    key: string;\n    value: CacheTimestampsModelEntry;\n    indexes: { cacheName: string; timestamp: number };\n  };\n}\n\n/**\n * Returns the timestamp model.\n *\n * @private\n */\nexport class CacheTimestampsModel {\n  private readonly _cacheName: string;\n  private _db: IDBPDatabase<CacheDbSchema> | null = null;\n\n  /**\n   *\n   * @param cacheName\n   *\n   * @private\n   */\n  constructor(cacheName: string) {\n    this._cacheName = cacheName;\n  }\n\n  /**\n   * Takes a URL and returns an ID that will be unique in the object store.\n   *\n   * @param url\n   * @returns\n   * @private\n   */\n  private _getId(url: string): string {\n    return `${this._cacheName}|${normalizeURL(url)}`;\n  }\n\n  /**\n   * Performs an upgrade of indexedDB.\n   *\n   * @param db\n   *\n   * @private\n   */\n  private _upgradeDb(db: IDBPDatabase<CacheDbSchema>) {\n    const objStore = db.createObjectStore(CACHE_OBJECT_STORE, {\n      keyPath: \"id\",\n    });\n\n    // TODO(philipwalton): once we don't have to support EdgeHTML, we can\n    // create a single index with the keyPath `['cacheName', 'timestamp']`\n    // instead of doing both these indexes.\n    objStore.createIndex(\"cacheName\", \"cacheName\", { unique: false });\n    objStore.createIndex(\"timestamp\", \"timestamp\", { unique: false });\n  }\n\n  /**\n   * Performs an upgrade of indexedDB and deletes deprecated DBs.\n   *\n   * @param db\n   *\n   * @private\n   */\n  private _upgradeDbAndDeleteOldDbs(db: IDBPDatabase<CacheDbSchema>) {\n    this._upgradeDb(db);\n    if (this._cacheName) {\n      void deleteDB(this._cacheName);\n    }\n  }\n\n  /**\n   * @param url\n   * @param timestamp\n   *\n   * @private\n   */\n  async setTimestamp(url: string, timestamp: number): Promise<void> {\n    url = normalizeURL(url);\n\n    const entry = {\n      id: this._getId(url),\n      cacheName: this._cacheName,\n      url,\n      timestamp,\n    } satisfies CacheTimestampsModelEntry;\n    const db = await this.getDb();\n    const tx = db.transaction(CACHE_OBJECT_STORE, \"readwrite\", {\n      durability: \"relaxed\",\n    });\n    await tx.store.put(entry);\n    await tx.done;\n  }\n\n  /**\n   * Returns the timestamp stored for a given URL.\n   *\n   * @param url\n   * @returns\n   * @private\n   */\n  async getTimestamp(url: string): Promise<number | undefined> {\n    const db = await this.getDb();\n    const entry = await db.get(CACHE_OBJECT_STORE, this._getId(url));\n    return entry?.timestamp;\n  }\n\n  /**\n   * Iterates through all the entries in the object store (from newest to\n   * oldest) and removes entries once either `maxCount` is reached or the\n   * entry's timestamp is less than `minTimestamp`.\n   *\n   * @param minTimestamp\n   * @param maxCount\n   * @returns\n   * @private\n   */\n  async expireEntries(minTimestamp: number, maxCount?: number): Promise<string[]> {\n    const db = await this.getDb();\n    let cursor = await db.transaction(CACHE_OBJECT_STORE, \"readwrite\").store.index(\"timestamp\").openCursor(null, \"prev\");\n    const urlsDeleted: string[] = [];\n    let entriesNotDeletedCount = 0;\n    while (cursor) {\n      const result = cursor.value;\n      // TODO(philipwalton): once we can use a multi-key index, we\n      // won't have to check `cacheName` here.\n      if (result.cacheName === this._cacheName) {\n        // Delete an entry if it's older than the max age or\n        // if we already have the max number allowed.\n        if ((minTimestamp && result.timestamp < minTimestamp) || (maxCount && entriesNotDeletedCount >= maxCount)) {\n          cursor.delete();\n          urlsDeleted.push(result.url);\n        } else {\n          entriesNotDeletedCount++;\n        }\n      }\n      cursor = await cursor.continue();\n    }\n\n    return urlsDeleted;\n  }\n\n  /**\n   * Returns an open connection to the database.\n   *\n   * @private\n   */\n  private async getDb() {\n    if (!this._db) {\n      this._db = await openDB(DB_NAME, 1, {\n        upgrade: this._upgradeDbAndDeleteOldDbs.bind(this),\n      });\n    }\n    return this._db;\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../utils/assert.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\nimport { CacheTimestampsModel } from \"./models/CacheTimestampsModel.js\";\n\ninterface CacheExpirationConfig {\n  /**\n   * The maximum number of entries to cache. Entries used least recently will\n   * be removed as the maximum is reached.\n   */\n  maxEntries?: number;\n  /**\n   * The maximum age of an entry before it's treated as stale and removed.\n   */\n  maxAgeSeconds?: number;\n  /**\n   * The [`CacheQueryOptions`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete#Parameters)\n   * that will be used when calling `delete()` on the cache.\n   */\n  matchOptions?: CacheQueryOptions;\n}\n\n/**\n * Allows you to expires cached responses based on age or maximum number of entries.\n * @see https://serwist.pages.dev/docs/serwist/core/cache-expiration\n */\nexport class CacheExpiration {\n  private _isRunning = false;\n  private _rerunRequested = false;\n  private readonly _maxEntries?: number;\n  private readonly _maxAgeSeconds?: number;\n  private readonly _matchOptions?: CacheQueryOptions;\n  private readonly _cacheName: string;\n  private readonly _timestampModel: CacheTimestampsModel;\n\n  /**\n   * To construct a new `CacheExpiration` instance you must provide at least\n   * one of the `config` properties.\n   *\n   * @param cacheName Name of the cache to apply restrictions to.\n   * @param config\n   */\n  constructor(cacheName: string, config: CacheExpirationConfig = {}) {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isType(cacheName, \"string\", {\n        moduleName: \"serwist\",\n        className: \"CacheExpiration\",\n        funcName: \"constructor\",\n        paramName: \"cacheName\",\n      });\n\n      if (!(config.maxEntries || config.maxAgeSeconds)) {\n        throw new SerwistError(\"max-entries-or-age-required\", {\n          moduleName: \"serwist\",\n          className: \"CacheExpiration\",\n          funcName: \"constructor\",\n        });\n      }\n\n      if (config.maxEntries) {\n        assert!.isType(config.maxEntries, \"number\", {\n          moduleName: \"serwist\",\n          className: \"CacheExpiration\",\n          funcName: \"constructor\",\n          paramName: \"config.maxEntries\",\n        });\n      }\n\n      if (config.maxAgeSeconds) {\n        assert!.isType(config.maxAgeSeconds, \"number\", {\n          moduleName: \"serwist\",\n          className: \"CacheExpiration\",\n          funcName: \"constructor\",\n          paramName: \"config.maxAgeSeconds\",\n        });\n      }\n    }\n\n    this._maxEntries = config.maxEntries;\n    this._maxAgeSeconds = config.maxAgeSeconds;\n    this._matchOptions = config.matchOptions;\n    this._cacheName = cacheName;\n    this._timestampModel = new CacheTimestampsModel(cacheName);\n  }\n\n  /**\n   * Expires entries for the given cache and given criteria.\n   */\n  async expireEntries(): Promise<void> {\n    if (this._isRunning) {\n      this._rerunRequested = true;\n      return;\n    }\n    this._isRunning = true;\n\n    const minTimestamp = this._maxAgeSeconds ? Date.now() - this._maxAgeSeconds * 1000 : 0;\n\n    const urlsExpired = await this._timestampModel.expireEntries(minTimestamp, this._maxEntries);\n\n    // Delete URLs from the cache\n    const cache = await self.caches.open(this._cacheName);\n    for (const url of urlsExpired) {\n      await cache.delete(url, this._matchOptions);\n    }\n\n    if (process.env.NODE_ENV !== \"production\") {\n      if (urlsExpired.length > 0) {\n        logger.groupCollapsed(\n          `Expired ${urlsExpired.length} ` +\n            `${urlsExpired.length === 1 ? \"entry\" : \"entries\"} and removed ` +\n            `${urlsExpired.length === 1 ? \"it\" : \"them\"} from the ` +\n            `'${this._cacheName}' cache.`,\n        );\n        logger.log(`Expired the following ${urlsExpired.length === 1 ? \"URL\" : \"URLs\"}:`);\n        for (const url of urlsExpired) {\n          logger.log(`    ${url}`);\n        }\n        logger.groupEnd();\n      } else {\n        logger.debug(\"Cache expiration ran and found no entries to remove.\");\n      }\n    }\n\n    this._isRunning = false;\n    if (this._rerunRequested) {\n      this._rerunRequested = false;\n      void this.expireEntries();\n    }\n  }\n\n  /**\n   * Updates the timestamp for the given URL, allowing it to be correctly\n   * tracked by the class.\n   *\n   * @param url\n   */\n  async updateTimestamp(url: string): Promise<void> {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isType(url, \"string\", {\n        moduleName: \"serwist\",\n        className: \"CacheExpiration\",\n        funcName: \"updateTimestamp\",\n        paramName: \"url\",\n      });\n    }\n\n    await this._timestampModel.setTimestamp(url, Date.now());\n  }\n\n  /**\n   * Checks if a URL has expired or not before it's used.\n   *\n   * This looks the timestamp up in IndexedDB and can be slow.\n   *\n   * Note: This method does not remove an expired entry, call\n   * `expireEntries()` to remove such entries instead.\n   *\n   * @param url\n   * @returns\n   */\n  async isURLExpired(url: string): Promise<boolean> {\n    if (!this._maxAgeSeconds) {\n      if (process.env.NODE_ENV !== \"production\") {\n        throw new SerwistError(\"expired-test-without-max-age\", {\n          methodName: \"isURLExpired\",\n          paramName: \"maxAgeSeconds\",\n        });\n      }\n      return false;\n    }\n    const timestamp = await this._timestampModel.getTimestamp(url);\n    const expireOlderThan = Date.now() - this._maxAgeSeconds * 1000;\n    return timestamp !== undefined ? timestamp < expireOlderThan : true;\n  }\n\n  /**\n   * Removes the IndexedDB used to keep track of cache expiration metadata.\n   */\n  async delete(): Promise<void> {\n    // Make sure we don't attempt another rerun if we're called in the middle of\n    // a cache expiration.\n    this._rerunRequested = false;\n    await this._timestampModel.expireEntries(Number.POSITIVE_INFINITY); // Expires all.\n  }\n}\n","/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { quotaErrorCallbacks } from \"./models/quotaErrorCallbacks.js\";\nimport { assert } from \"./utils/assert.js\";\nimport { logger } from \"./utils/logger.js\";\n\n/**\n * Adds a function to the set of quotaErrorCallbacks that will be executed if\n * there's a quota error.\n *\n * @param callback\n */\n// biome-ignore lint/complexity/noBannedTypes: Can't change Function type\nexport const registerQuotaErrorCallback = (callback: Function): void => {\n  if (process.env.NODE_ENV !== \"production\") {\n    assert!.isType(callback, \"function\", {\n      moduleName: \"@serwist/core\",\n      funcName: \"register\",\n      paramName: \"callback\",\n    });\n  }\n\n  quotaErrorCallbacks.add(callback);\n\n  if (process.env.NODE_ENV !== \"production\") {\n    logger.log(\"Registered a callback to respond to quota errors.\", callback);\n  }\n};\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { registerQuotaErrorCallback } from \"../../registerQuotaErrorCallback.js\";\nimport type { CacheDidUpdateCallbackParam, CachedResponseWillBeUsedCallbackParam, SerwistPlugin } from \"../../types.js\";\nimport { assert } from \"../../utils/assert.js\";\nimport { cacheNames as privateCacheNames } from \"../../utils/cacheNames.js\";\nimport { getFriendlyURL } from \"../../utils/getFriendlyURL.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\nimport type { Strategy } from \"../strategies/Strategy.js\";\nimport { CacheExpiration } from \"./CacheExpiration.js\";\n\nexport interface ExpirationPluginOptions {\n  /**\n   * The maximum number of entries to cache. Entries used (if `maxAgeFrom` is\n   * `\"last-used\"`) or fetched from the network (if `maxAgeFrom` is `\"last-fetched\"`)\n   * least recently will be removed as the maximum is reached.\n   */\n  maxEntries?: number;\n  /**\n   * The maximum number of seconds before an entry is treated as stale and removed.\n   */\n  maxAgeSeconds?: number;\n  /**\n   * Determines whether `maxAgeSeconds` should be calculated from when an\n   * entry was last fetched or when it was last used.\n   *\n   * @default \"last-fetched\"\n   */\n  maxAgeFrom?: \"last-fetched\" | \"last-used\";\n  /**\n   * The [`CacheQueryOptions`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete#Parameters)\n   * that will be used when calling `delete()` on the cache.\n   */\n  matchOptions?: CacheQueryOptions;\n  /**\n   * Whether to opt this cache into automatic deletion if the available storage quota has been exceeded.\n   */\n  purgeOnQuotaError?: boolean;\n}\n\n/**\n * This plugin can be used in a {@linkcode Strategy} to regularly enforce a\n * limit on the age and/or the number of cached requests.\n *\n * It can only be used with {@linkcode Strategy} instances that have a custom `cacheName` property set.\n * In other words, it can't be used to expire entries in strategies that use the default runtime\n * cache name.\n *\n * Whenever a cached response is used or updated, this plugin will look\n * at the associated cache and remove any old or extra responses.\n *\n * When using `maxAgeSeconds`, responses may be used *once* after expiring\n * because the expiration clean up will not have occurred until *after* the\n * cached response has been used. If the response has a \"Date\" header, then a lightweight expiration\n * check is performed, and the response will not be used immediately.\n *\n * When using `maxEntries`, the least recently requested entry will be removed\n * from the cache.\n *\n * @see https://serwist.pages.dev/docs/serwist/runtime-caching/plugins/expiration-plugin\n */\nexport class ExpirationPlugin implements SerwistPlugin {\n  private readonly _config: ExpirationPluginOptions;\n  private _cacheExpirations: Map<string, CacheExpiration>;\n\n  /**\n   * @param config\n   */\n  constructor(config: ExpirationPluginOptions = {}) {\n    if (process.env.NODE_ENV !== \"production\") {\n      if (!(config.maxEntries || config.maxAgeSeconds)) {\n        throw new SerwistError(\"max-entries-or-age-required\", {\n          moduleName: \"serwist\",\n          className: \"ExpirationPlugin\",\n          funcName: \"constructor\",\n        });\n      }\n\n      if (config.maxEntries) {\n        assert!.isType(config.maxEntries, \"number\", {\n          moduleName: \"serwist\",\n          className: \"ExpirationPlugin\",\n          funcName: \"constructor\",\n          paramName: \"config.maxEntries\",\n        });\n      }\n\n      if (config.maxAgeSeconds) {\n        assert!.isType(config.maxAgeSeconds, \"number\", {\n          moduleName: \"serwist\",\n          className: \"ExpirationPlugin\",\n          funcName: \"constructor\",\n          paramName: \"config.maxAgeSeconds\",\n        });\n      }\n\n      if (config.maxAgeFrom) {\n        assert!.isType(config.maxAgeFrom, \"string\", {\n          moduleName: \"serwist\",\n          className: \"ExpirationPlugin\",\n          funcName: \"constructor\",\n          paramName: \"config.maxAgeFrom\",\n        });\n      }\n    }\n\n    this._config = config;\n    this._cacheExpirations = new Map();\n\n    if (!this._config.maxAgeFrom) {\n      this._config.maxAgeFrom = \"last-fetched\";\n    }\n\n    if (this._config.purgeOnQuotaError) {\n      registerQuotaErrorCallback(() => this.deleteCacheAndMetadata());\n    }\n  }\n\n  /**\n   * A simple helper method to return a CacheExpiration instance for a given\n   * cache name.\n   *\n   * @param cacheName\n   * @returns\n   * @private\n   */\n  private _getCacheExpiration(cacheName: string): CacheExpiration {\n    if (cacheName === privateCacheNames.getRuntimeName()) {\n      throw new SerwistError(\"expire-custom-caches-only\");\n    }\n\n    let cacheExpiration = this._cacheExpirations.get(cacheName);\n    if (!cacheExpiration) {\n      cacheExpiration = new CacheExpiration(cacheName, this._config);\n      this._cacheExpirations.set(cacheName, cacheExpiration);\n    }\n    return cacheExpiration;\n  }\n\n  /**\n   * A lifecycle callback that will be triggered automatically when a\n   * response is about to be returned from a [`Cache`](https://developer.mozilla.org/en-US/docs/Web/API/Cache).\n   * It allows the response to be inspected for freshness and\n   * prevents it from being used if the response's `Date` header value is\n   * older than the configured `maxAgeSeconds`.\n   *\n   * @param options\n   * @returns `cachedResponse` if it is fresh and `null` if it is stale or\n   * not available.\n   * @private\n   */\n  cachedResponseWillBeUsed({ event, cacheName, request, cachedResponse }: CachedResponseWillBeUsedCallbackParam) {\n    if (!cachedResponse) {\n      return null;\n    }\n\n    const isFresh = this._isResponseDateFresh(cachedResponse);\n\n    // Expire entries to ensure that even if the expiration date has\n    // expired, it'll only be used once.\n    const cacheExpiration = this._getCacheExpiration(cacheName);\n\n    const isMaxAgeFromLastUsed = this._config.maxAgeFrom === \"last-used\";\n\n    const done = (async () => {\n      // Update the metadata for the request URL to the current timestamp.\n      // Only applies if `maxAgeFrom` is `\"last-used\"`, since the current\n      // lifecycle callback is `cachedResponseWillBeUsed`.\n      // This needs to be called before `expireEntries()` so as to avoid\n      // this URL being marked as expired.\n      if (isMaxAgeFromLastUsed) {\n        await cacheExpiration.updateTimestamp(request.url);\n      }\n      await cacheExpiration.expireEntries();\n    })();\n    try {\n      event.waitUntil(done);\n    } catch {\n      if (process.env.NODE_ENV !== \"production\") {\n        if (event instanceof FetchEvent) {\n          logger.warn(`Unable to ensure service worker stays alive when updating cache entry for '${getFriendlyURL(event.request.url)}'.`);\n        }\n      }\n    }\n\n    return isFresh ? cachedResponse : null;\n  }\n\n  /**\n   * @param cachedResponse\n   * @returns\n   * @private\n   */\n  private _isResponseDateFresh(cachedResponse: Response): boolean {\n    const isMaxAgeFromLastUsed = this._config.maxAgeFrom === \"last-used\";\n    // If `maxAgeFrom` is `\"last-used\"`, the `Date` header doesn't really\n    // matter since it is about when the response was created.\n    if (isMaxAgeFromLastUsed) {\n      return true;\n    }\n    const now = Date.now();\n    if (!this._config.maxAgeSeconds) {\n      return true;\n    }\n    // Check if the `Date` header will suffice a quick expiration check.\n    // See https://github.com/GoogleChromeLabs/sw-toolbox/issues/164 for\n    // discussion.\n    const dateHeaderTimestamp = this._getDateHeaderTimestamp(cachedResponse);\n    if (dateHeaderTimestamp === null) {\n      // Unable to parse date, so assume it's fresh.\n      return true;\n    }\n    // If we have a valid headerTime, then our response is fresh if the\n    // headerTime plus maxAgeSeconds is greater than the current time.\n    return dateHeaderTimestamp >= now - this._config.maxAgeSeconds * 1000;\n  }\n\n  /**\n   * Extracts the `Date` header and parse it into an useful value.\n   *\n   * @param cachedResponse\n   * @returns\n   * @private\n   */\n  private _getDateHeaderTimestamp(cachedResponse: Response): number | null {\n    if (!cachedResponse.headers.has(\"date\")) {\n      return null;\n    }\n\n    const dateHeader = cachedResponse.headers.get(\"date\")!;\n    const parsedDate = new Date(dateHeader);\n    const headerTime = parsedDate.getTime();\n\n    // If the `Date` header is invalid for some reason, `parsedDate.getTime()`\n    // will return NaN.\n    if (Number.isNaN(headerTime)) {\n      return null;\n    }\n\n    return headerTime;\n  }\n\n  /**\n   * A lifecycle callback that will be triggered automatically when an entry is added\n   * to a cache.\n   *\n   * @param options\n   * @private\n   */\n  async cacheDidUpdate({ cacheName, request }: CacheDidUpdateCallbackParam) {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isType(cacheName, \"string\", {\n        moduleName: \"serwist\",\n        className: \"Plugin\",\n        funcName: \"cacheDidUpdate\",\n        paramName: \"cacheName\",\n      });\n      assert!.isInstance(request, Request, {\n        moduleName: \"serwist\",\n        className: \"Plugin\",\n        funcName: \"cacheDidUpdate\",\n        paramName: \"request\",\n      });\n    }\n\n    const cacheExpiration = this._getCacheExpiration(cacheName);\n    await cacheExpiration.updateTimestamp(request.url);\n    await cacheExpiration.expireEntries();\n  }\n\n  /**\n   * Deletes the underlying `Cache` instance associated with this instance and the metadata\n   * from IndexedDB used to keep track of expiration details for each `Cache` instance.\n   *\n   * When using cache expiration, calling this method is preferable to calling\n   * `caches.delete()` directly, since this will ensure that the IndexedDB\n   * metadata is also cleanly removed and that open IndexedDB instances are deleted.\n   *\n   * Note that if you're *not* using cache expiration for a given cache, calling\n   * `caches.delete()` and passing in the cache's name should be sufficient.\n   * There is no Serwist-specific method needed for cleanup in that case.\n   */\n  async deleteCacheAndMetadata(): Promise<void> {\n    // Do this one at a time instead of all at once via `Promise.all()` to\n    // reduce the chance of inconsistency if a promise rejects.\n    for (const [cacheName, cacheExpiration] of this._cacheExpirations) {\n      await self.caches.delete(cacheName);\n      await cacheExpiration.delete();\n    }\n\n    // Reset this._cacheExpirations to its initial state.\n    this._cacheExpirations = new Map();\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nexport const QUEUE_NAME = \"serwist-google-analytics\";\nexport const MAX_RETENTION_TIME = 60 * 48; // Two days in minutes\nexport const GOOGLE_ANALYTICS_HOST = \"www.google-analytics.com\";\nexport const GTM_HOST = \"www.googletagmanager.com\";\nexport const ANALYTICS_JS_PATH = \"/analytics.js\";\nexport const GTAG_JS_PATH = \"/gtag/js\";\nexport const GTM_JS_PATH = \"/gtm.js\";\nexport const COLLECT_DEFAULT_PATH = \"/collect\";\n\n// This RegExp matches all known Measurement Protocol single-hit collect\n// endpoints. Most of the time the default path (/collect) is used, but\n// occasionally an experimental endpoint is used when testing new features,\n// (e.g. /r/collect or /j/collect)\nexport const COLLECT_PATHS_REGEX = /^\\/(\\w+\\/)?collect/;\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { NetworkFirst } from \"../../lib/strategies/NetworkFirst.js\";\nimport { NetworkOnly } from \"../../lib/strategies/NetworkOnly.js\";\nimport { Route } from \"../../Route.js\";\nimport type { Serwist } from \"../../Serwist.js\";\nimport type { RouteMatchCallbackOptions } from \"../../types.js\";\nimport { cacheNames as privateCacheNames } from \"../../utils/cacheNames.js\";\nimport { getFriendlyURL } from \"../../utils/getFriendlyURL.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { BackgroundSyncPlugin } from \"../backgroundSync/BackgroundSyncPlugin.js\";\nimport type { BackgroundSyncQueue, BackgroundSyncQueueEntry } from \"../backgroundSync/BackgroundSyncQueue.js\";\nimport {\n  ANALYTICS_JS_PATH,\n  COLLECT_PATHS_REGEX,\n  GOOGLE_ANALYTICS_HOST,\n  GTAG_JS_PATH,\n  GTM_HOST,\n  GTM_JS_PATH,\n  MAX_RETENTION_TIME,\n  QUEUE_NAME,\n} from \"./constants.js\";\n\nexport interface GoogleAnalyticsInitializeOptions {\n  serwist: Serwist;\n  /**\n   * The cache name to store and retrieve analytics.js. Defaults to Serwist's default cache names.\n   */\n  cacheName?: string;\n  /**\n   * [Measurement Protocol parameters](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters),\n   * expressed as key/value pairs, to be added to replayed Google Analytics\n   * requests. This can be used to, e.g., set a custom dimension indicating\n   * that the request was replayed.\n   */\n  parameterOverrides?: { [paramName: string]: string };\n  /**\n   * A function that allows you to modify the hit parameters prior to replaying\n   * the hit. The function is invoked with the original hit's URLSearchParams\n   * object as its only argument.\n   */\n  hitFilter?: (params: URLSearchParams) => void;\n}\n\n/**\n * Creates the requestWillDequeue callback to be used with the background\n * sync plugin. The callback takes the failed request and adds the\n * `qt` param based on the current time, as well as applies any other\n * user-defined hit modifications.\n *\n * @param config\n * @returns The requestWillDequeue callback function.\n * @private\n */\nconst createOnSyncCallback = (config: Pick<GoogleAnalyticsInitializeOptions, \"parameterOverrides\" | \"hitFilter\">) => {\n  return async ({ queue }: { queue: BackgroundSyncQueue }) => {\n    let entry: BackgroundSyncQueueEntry | undefined;\n    while ((entry = await queue.shiftRequest())) {\n      const { request, timestamp } = entry;\n      const url = new URL(request.url);\n\n      try {\n        // Measurement protocol requests can set their payload parameters in\n        // either the URL query string (for GET requests) or the POST body.\n        const params = request.method === \"POST\" ? new URLSearchParams(await request.clone().text()) : url.searchParams;\n\n        // Calculate the qt param, accounting for the fact that an existing\n        // qt param may be present and should be updated rather than replaced.\n        const originalHitTime = timestamp! - (Number(params.get(\"qt\")) || 0);\n        const queueTime = Date.now() - originalHitTime;\n\n        // Set the qt param prior to applying hitFilter or parameterOverrides.\n        params.set(\"qt\", String(queueTime));\n\n        // Apply `parameterOverrides`, if set.\n        if (config.parameterOverrides) {\n          for (const param of Object.keys(config.parameterOverrides)) {\n            const value = config.parameterOverrides[param];\n            params.set(param, value);\n          }\n        }\n\n        // Apply `hitFilter`, if set.\n        if (typeof config.hitFilter === \"function\") {\n          config.hitFilter.call(null, params);\n        }\n\n        // Retry the fetch. Ignore URL search params from the URL as they're\n        // now in the post body.\n        await fetch(\n          new Request(url.origin + url.pathname, {\n            body: params.toString(),\n            method: \"POST\",\n            mode: \"cors\",\n            credentials: \"omit\",\n            headers: { \"Content-Type\": \"text/plain\" },\n          }),\n        );\n\n        if (process.env.NODE_ENV !== \"production\") {\n          logger.log(`Request for '${getFriendlyURL(url.href)}' has been replayed`);\n        }\n      } catch (err) {\n        await queue.unshiftRequest(entry);\n\n        if (process.env.NODE_ENV !== \"production\") {\n          logger.log(`Request for '${getFriendlyURL(url.href)}' failed to replay, putting it back in the queue.`);\n        }\n        throw err;\n      }\n    }\n    if (process.env.NODE_ENV !== \"production\") {\n      logger.log(\"All Google Analytics request successfully replayed; \" + \"the queue is now empty!\");\n    }\n  };\n};\n\n/**\n * Creates GET and POST routes to catch failed Measurement Protocol hits.\n *\n * @param bgSyncPlugin\n * @returns The created routes.\n * @private\n */\nconst createCollectRoutes = (bgSyncPlugin: BackgroundSyncPlugin) => {\n  const match = ({ url }: RouteMatchCallbackOptions) => url.hostname === GOOGLE_ANALYTICS_HOST && COLLECT_PATHS_REGEX.test(url.pathname);\n\n  const handler = new NetworkOnly({\n    plugins: [bgSyncPlugin],\n  });\n\n  return [new Route(match, handler, \"GET\"), new Route(match, handler, \"POST\")];\n};\n\n/**\n * Creates a route with a network first strategy for the analytics.js script.\n *\n * @param cacheName\n * @returns The created route.\n * @private\n */\nconst createAnalyticsJsRoute = (cacheName: string) => {\n  const match = ({ url }: RouteMatchCallbackOptions) => url.hostname === GOOGLE_ANALYTICS_HOST && url.pathname === ANALYTICS_JS_PATH;\n\n  const handler = new NetworkFirst({ cacheName });\n\n  return new Route(match, handler, \"GET\");\n};\n\n/**\n * Creates a route with a network first strategy for the gtag.js script.\n *\n * @param cacheName\n * @returns The created route.\n * @private\n */\nconst createGtagJsRoute = (cacheName: string) => {\n  const match = ({ url }: RouteMatchCallbackOptions) => url.hostname === GTM_HOST && url.pathname === GTAG_JS_PATH;\n\n  const handler = new NetworkFirst({ cacheName });\n\n  return new Route(match, handler, \"GET\");\n};\n\n/**\n * Creates a route with a network first strategy for the gtm.js script.\n *\n * @param cacheName\n * @returns The created route.\n * @private\n */\nconst createGtmJsRoute = (cacheName: string) => {\n  const match = ({ url }: RouteMatchCallbackOptions) => url.hostname === GTM_HOST && url.pathname === GTM_JS_PATH;\n\n  const handler = new NetworkFirst({ cacheName });\n\n  return new Route(match, handler, \"GET\");\n};\n\n/**\n * Initialize Serwist's offline Google Analytics v3 support.\n *\n * @param options\n */\nexport const initializeGoogleAnalytics = ({ serwist, cacheName, ...options }: GoogleAnalyticsInitializeOptions): void => {\n  const resolvedCacheName = privateCacheNames.getGoogleAnalyticsName(cacheName);\n\n  const bgSyncPlugin = new BackgroundSyncPlugin(QUEUE_NAME, {\n    maxRetentionTime: MAX_RETENTION_TIME,\n    onSync: createOnSyncCallback(options),\n  });\n\n  const routes = [\n    createGtmJsRoute(resolvedCacheName),\n    createAnalyticsJsRoute(resolvedCacheName),\n    createGtagJsRoute(resolvedCacheName),\n    ...createCollectRoutes(bgSyncPlugin),\n  ];\n\n  for (const route of routes) {\n    serwist.registerRoute(route);\n  }\n};\n","/*\n  Copyright 2020 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { Serwist } from \"../../Serwist.js\";\nimport type { HandlerDidErrorCallbackParam, SerwistPlugin } from \"../../types.js\";\n\nexport interface PrecacheFallbackEntry {\n  /**\n   * A precached URL to be used as a fallback.\n   */\n  url: string;\n  /**\n   * A function that checks whether the fallback entry can be used\n   * for a request.\n   */\n  matcher: (param: HandlerDidErrorCallbackParam) => boolean;\n}\n\nexport interface PrecacheFallbackPluginOptions {\n  /**\n   * Precached URLs to be used as the fallback\n   * if the associated strategy can't generate a response.\n   */\n  fallbackUrls: (string | PrecacheFallbackEntry)[];\n  /**\n   * A {@linkcode Serwist} instance.\n   */\n  serwist: Serwist;\n}\n\n/**\n * Allows you to specify offline fallbacks to be used when a given strategy\n * is unable to generate a response.\n *\n * It does this by intercepting the `handlerDidError` plugin callback\n * and returning a precached response, taking the expected revision parameter\n * into account automatically.\n */\nexport class PrecacheFallbackPlugin implements SerwistPlugin {\n  private readonly _fallbackUrls: (string | PrecacheFallbackEntry)[];\n  private readonly _serwist: Serwist;\n\n  /**\n   * Constructs a new instance with the associated `fallbackUrls`.\n   *\n   * @param config\n   */\n  constructor({ fallbackUrls, serwist }: PrecacheFallbackPluginOptions) {\n    this._fallbackUrls = fallbackUrls;\n    this._serwist = serwist;\n  }\n\n  /**\n   * @returns The precache response for one of the fallback URLs, or `undefined` if\n   * nothing satisfies the conditions.\n   * @private\n   */\n  async handlerDidError(param: HandlerDidErrorCallbackParam) {\n    for (const fallback of this._fallbackUrls) {\n      if (typeof fallback === \"string\") {\n        const fallbackResponse = await this._serwist.matchPrecache(fallback);\n        if (fallbackResponse !== undefined) {\n          return fallbackResponse;\n        }\n      } else if (fallback.matcher(param)) {\n        const fallbackResponse = await this._serwist.matchPrecache(fallback.url);\n        if (fallbackResponse !== undefined) {\n          return fallbackResponse;\n        }\n      }\n    }\n    return undefined;\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../../utils/assert.js\";\nimport { SerwistError } from \"../../../utils/SerwistError.js\";\n\n/**\n * @param blob A source blob.\n * @param start The offset to use as the start of the\n * slice.\n * @param end The offset to use as the end of the slice.\n * @returns An object with `start` and `end` properties, reflecting\n * the effective boundaries to use given the size of the blob.\n * @private\n */\nexport const calculateEffectiveBoundaries = (blob: Blob, start?: number, end?: number): { start: number; end: number } => {\n  if (process.env.NODE_ENV !== \"production\") {\n    assert!.isInstance(blob, Blob, {\n      moduleName: \"@serwist/range-requests\",\n      funcName: \"calculateEffectiveBoundaries\",\n      paramName: \"blob\",\n    });\n  }\n\n  const blobSize = blob.size;\n\n  if ((end && end > blobSize) || (start && start < 0)) {\n    throw new SerwistError(\"range-not-satisfiable\", {\n      size: blobSize,\n      end,\n      start,\n    });\n  }\n\n  let effectiveStart: number;\n  let effectiveEnd: number;\n\n  if (start !== undefined && end !== undefined) {\n    effectiveStart = start;\n    // Range values are inclusive, so add 1 to the value.\n    effectiveEnd = end + 1;\n  } else if (start !== undefined && end === undefined) {\n    effectiveStart = start;\n    effectiveEnd = blobSize;\n  } else if (end !== undefined && start === undefined) {\n    effectiveStart = blobSize - end;\n    effectiveEnd = blobSize;\n  }\n\n  return {\n    start: effectiveStart!,\n    end: effectiveEnd!,\n  };\n};\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../../utils/assert.js\";\nimport { SerwistError } from \"../../../utils/SerwistError.js\";\n\n/**\n * @param rangeHeader A `Range` header value.\n * @returns An object with `start` and `end` properties, reflecting\n * the parsed value of the `Range` header. If either the `start` or `end` are\n * omitted, then `null` will be returned.\n * @private\n */\nexport const parseRangeHeader = (\n  rangeHeader: string,\n): {\n  start?: number;\n  end?: number;\n} => {\n  if (process.env.NODE_ENV !== \"production\") {\n    assert!.isType(rangeHeader, \"string\", {\n      moduleName: \"@serwist/range-requests\",\n      funcName: \"parseRangeHeader\",\n      paramName: \"rangeHeader\",\n    });\n  }\n\n  const normalizedRangeHeader = rangeHeader.trim().toLowerCase();\n  if (!normalizedRangeHeader.startsWith(\"bytes=\")) {\n    throw new SerwistError(\"unit-must-be-bytes\", { normalizedRangeHeader });\n  }\n\n  // Specifying multiple ranges separate by commas is valid syntax, but this\n  // library only attempts to handle a single, contiguous sequence of bytes.\n  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#Syntax\n  if (normalizedRangeHeader.includes(\",\")) {\n    throw new SerwistError(\"single-range-only\", { normalizedRangeHeader });\n  }\n\n  const rangeParts = /(\\d*)-(\\d*)/.exec(normalizedRangeHeader);\n  // We need either at least one of the start or end values.\n  if (!rangeParts || !(rangeParts[1] || rangeParts[2])) {\n    throw new SerwistError(\"invalid-range-values\", { normalizedRangeHeader });\n  }\n\n  return {\n    start: rangeParts[1] === \"\" ? undefined : Number(rangeParts[1]),\n    end: rangeParts[2] === \"\" ? undefined : Number(rangeParts[2]),\n  };\n};\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../utils/assert.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\nimport { calculateEffectiveBoundaries } from \"./utils/calculateEffectiveBoundaries.js\";\nimport { parseRangeHeader } from \"./utils/parseRangeHeader.js\";\n\n/**\n * Given a request and a response, this will return a\n * promise that resolves to a partial response.\n *\n * If the original response already contains partial content (i.e. it has\n * a status of 206), then this assumes it already fulfills the `Range`\n * requirements, and will return it as-is.\n *\n * @param request A request, which should contain a `Range`\n * header.\n * @param originalResponse A response.\n * @returns Either a `206 Partial Content` response, with\n * the response body set to the slice of content specified by the request's\n * `Range` header, or a `416 Range Not Satisfiable` response if the\n * conditions of the `Range` header can't be met.\n */\nexport const createPartialResponse = async (request: Request, originalResponse: Response): Promise<Response> => {\n  try {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isInstance(request, Request, {\n        moduleName: \"@serwist/range-requests\",\n        funcName: \"createPartialResponse\",\n        paramName: \"request\",\n      });\n\n      assert!.isInstance(originalResponse, Response, {\n        moduleName: \"@serwist/range-requests\",\n        funcName: \"createPartialResponse\",\n        paramName: \"originalResponse\",\n      });\n    }\n\n    if (originalResponse.status === 206) {\n      // If we already have a 206, then just pass it through as-is;\n      // see https://github.com/GoogleChrome/workbox/issues/1720\n      return originalResponse;\n    }\n\n    const rangeHeader = request.headers.get(\"range\");\n    if (!rangeHeader) {\n      throw new SerwistError(\"no-range-header\");\n    }\n\n    const boundaries = parseRangeHeader(rangeHeader);\n    const originalBlob = await originalResponse.blob();\n\n    const effectiveBoundaries = calculateEffectiveBoundaries(originalBlob, boundaries.start, boundaries.end);\n\n    const slicedBlob = originalBlob.slice(effectiveBoundaries.start, effectiveBoundaries.end);\n    const slicedBlobSize = slicedBlob.size;\n\n    const slicedResponse = new Response(slicedBlob, {\n      // Status code 206 is for a Partial Content response.\n      // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206\n      status: 206,\n      statusText: \"Partial Content\",\n      headers: originalResponse.headers,\n    });\n\n    slicedResponse.headers.set(\"Content-Length\", String(slicedBlobSize));\n    slicedResponse.headers.set(\"Content-Range\", `bytes ${effectiveBoundaries.start}-${effectiveBoundaries.end - 1}/` + `${originalBlob.size}`);\n\n    return slicedResponse;\n  } catch (error) {\n    if (process.env.NODE_ENV !== \"production\") {\n      logger.warn(\"Unable to construct a partial response; returning a \" + \"416 Range Not Satisfiable response instead.\");\n      logger.groupCollapsed(\"View details here.\");\n      logger.log(error);\n      logger.log(request);\n      logger.log(originalResponse);\n      logger.groupEnd();\n    }\n\n    return new Response(\"\", {\n      status: 416,\n      statusText: \"Range Not Satisfiable\",\n    });\n  }\n};\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { SerwistPlugin } from \"../../types.js\";\nimport { createPartialResponse } from \"./createPartialResponse.js\";\n\n/**\n * Makes it easy for a request with a `Range` header to be fulfilled by a cached response.\n *\n * It does this by intercepting the `cachedResponseWillBeUsed` plugin callback\n * and returning the appropriate subset of the cached response body.\n */\nexport class RangeRequestsPlugin implements SerwistPlugin {\n  /**\n   * @param options\n   * @returns If request contains a `Range` header, then a\n   * partial response whose body is a subset of `cachedResponse` is\n   * returned. Otherwise, `cachedResponse` is returned as-is.\n   * @private\n   */\n  cachedResponseWillBeUsed: SerwistPlugin[\"cachedResponseWillBeUsed\"] = async ({ request, cachedResponse }) => {\n    // Only return a sliced response if there's something valid in the cache,\n    // and there's a Range: header in the request.\n    if (cachedResponse && request.headers.has(\"range\")) {\n      return await createPartialResponse(request, cachedResponse);\n    }\n\n    // If there was no Range: header, or if cachedResponse wasn't valid, just\n    // pass it through as-is.\n    return cachedResponse;\n  };\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../utils/assert.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\nimport { Strategy } from \"./Strategy.js\";\nimport type { StrategyHandler } from \"./StrategyHandler.js\";\nimport { messages } from \"./utils/messages.js\";\n\n/**\n * An implementation of the [cache first](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#cache_first_falling_back_to_network)\n * request strategy.\n *\n * A cache first strategy is useful for assets that have been revisioned,\n * such as URLs like \"/styles/example.a8f5f1.css\", since they\n * can be cached for long periods of time.\n *\n * If the network request fails, and there is no cache match, this will throw\n * a {@linkcode SerwistError} exception.\n */\nexport class CacheFirst extends Strategy {\n  /**\n   * @private\n   * @param request A request to run this strategy for.\n   * @param handler The event that triggered the request.\n   * @returns\n   */\n  async _handle(request: Request, handler: StrategyHandler): Promise<Response> {\n    const logs = [];\n\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isInstance(request, Request, {\n        moduleName: \"serwist\",\n        className: this.constructor.name,\n        funcName: \"makeRequest\",\n        paramName: \"request\",\n      });\n    }\n\n    let response = await handler.cacheMatch(request);\n\n    let error: Error | undefined;\n    if (!response) {\n      if (process.env.NODE_ENV !== \"production\") {\n        logs.push(`No response found in the '${this.cacheName}' cache. Will respond with a network request.`);\n      }\n      try {\n        response = await handler.fetchAndCachePut(request);\n      } catch (err) {\n        if (err instanceof Error) {\n          error = err;\n        }\n      }\n\n      if (process.env.NODE_ENV !== \"production\") {\n        if (response) {\n          logs.push(\"Got response from network.\");\n        } else {\n          logs.push(\"Unable to get a response from the network.\");\n        }\n      }\n    } else {\n      if (process.env.NODE_ENV !== \"production\") {\n        logs.push(`Found a cached response in the '${this.cacheName}' cache.`);\n      }\n    }\n\n    if (process.env.NODE_ENV !== \"production\") {\n      logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));\n      for (const log of logs) {\n        logger.log(log);\n      }\n      messages.printFinalResponse(response);\n      logger.groupEnd();\n    }\n\n    if (!response) {\n      throw new SerwistError(\"no-response\", { url: request.url, error });\n    }\n    return response;\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../utils/assert.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\nimport { Strategy } from \"./Strategy.js\";\nimport type { StrategyHandler } from \"./StrategyHandler.js\";\nimport { messages } from \"./utils/messages.js\";\n\n/**\n * An implementation of the [cache only](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#cache_only)\n * request strategy.\n *\n * This class is useful if you already have your own precaching step.\n *\n * If there is no cache match, this will throw a {@linkcode SerwistError} exception.\n */\nexport class CacheOnly extends Strategy {\n  /**\n   * @private\n   * @param request A request to run this strategy for.\n   * @param handler The event that triggered the request.\n   * @returns\n   */\n  async _handle(request: Request, handler: StrategyHandler): Promise<Response> {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isInstance(request, Request, {\n        moduleName: \"serwist\",\n        className: this.constructor.name,\n        funcName: \"makeRequest\",\n        paramName: \"request\",\n      });\n    }\n\n    const response = await handler.cacheMatch(request);\n\n    if (process.env.NODE_ENV !== \"production\") {\n      logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));\n      if (response) {\n        logger.log(`Found a cached response in the '${this.cacheName}' cache.`);\n        messages.printFinalResponse(response);\n      } else {\n        logger.log(`No response found in the '${this.cacheName}' cache.`);\n      }\n      logger.groupEnd();\n    }\n\n    if (!response) {\n      throw new SerwistError(\"no-response\", { url: request.url });\n    }\n    return response;\n  }\n}\n","/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { assert } from \"../../utils/assert.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport { SerwistError } from \"../../utils/SerwistError.js\";\nimport { cacheOkAndOpaquePlugin } from \"./plugins/cacheOkAndOpaquePlugin.js\";\nimport type { StrategyOptions } from \"./Strategy.js\";\nimport { Strategy } from \"./Strategy.js\";\nimport type { StrategyHandler } from \"./StrategyHandler.js\";\nimport { messages } from \"./utils/messages.js\";\n\n/**\n * An implementation of the\n * [stale-while-revalidate](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#stale_while_revalidate)\n * request strategy.\n *\n * Resources are requested from both the cache and the network in parallel.\n * The strategy will respond with the cached version if available, otherwise\n * wait for the network response. The cache is updated with the network response\n * with each successful request.\n *\n * By default, this strategy will cache responses with a 200 status code as\n * well as [opaque responses](https://developer.chrome.com/docs/workbox/caching-resources-during-runtime/#opaque-responses).\n * Opaque responses are cross-origin requests where the response doesn't\n * support [CORS](https://enable-cors.org/).\n *\n * If the network request fails, and there is no cache match, this will throw\n * a {@linkcode SerwistError} exception.\n */\nexport class StaleWhileRevalidate extends Strategy {\n  /**\n   * @param options\n   */\n  constructor(options: StrategyOptions = {}) {\n    super(options);\n\n    // If this instance contains no plugins with a 'cacheWillUpdate' callback,\n    // prepend the `cacheOkAndOpaquePlugin` plugin to the plugins list.\n    if (!this.plugins.some((p) => \"cacheWillUpdate\" in p)) {\n      this.plugins.unshift(cacheOkAndOpaquePlugin);\n    }\n  }\n\n  /**\n   * @private\n   * @param request A request to run this strategy for.\n   * @param handler The event that triggered the request.\n   * @returns\n   */\n  async _handle(request: Request, handler: StrategyHandler): Promise<Response> {\n    const logs = [];\n\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isInstance(request, Request, {\n        moduleName: \"serwist\",\n        className: this.constructor.name,\n        funcName: \"handle\",\n        paramName: \"request\",\n      });\n    }\n\n    const fetchAndCachePromise = handler.fetchAndCachePut(request).catch(() => {\n      // Swallow this error because a 'no-response' error will be thrown in\n      // main handler return flow. This will be in the `waitUntil()` flow.\n    });\n    void handler.waitUntil(fetchAndCachePromise);\n\n    let response = await handler.cacheMatch(request);\n\n    let error: Error | undefined;\n    if (response) {\n      if (process.env.NODE_ENV !== \"production\") {\n        logs.push(`Found a cached response in the '${this.cacheName}' cache. Will update with the network response in the background.`);\n      }\n    } else {\n      if (process.env.NODE_ENV !== \"production\") {\n        logs.push(`No response found in the '${this.cacheName}' cache. Will wait for the network response.`);\n      }\n      try {\n        // NOTE(philipwalton): Really annoying that we have to type cast here.\n        // https://github.com/microsoft/TypeScript/issues/20006\n        response = (await fetchAndCachePromise) as Response | undefined;\n      } catch (err) {\n        if (err instanceof Error) {\n          error = err;\n        }\n      }\n    }\n\n    if (process.env.NODE_ENV !== \"production\") {\n      logger.groupCollapsed(messages.strategyStart(this.constructor.name, request));\n      for (const log of logs) {\n        logger.log(log);\n      }\n      messages.printFinalResponse(response);\n      logger.groupEnd();\n    }\n\n    if (!response) {\n      throw new SerwistError(\"no-response\", { url: request.url, error });\n    }\n    return response;\n  }\n}\n","/*\n  Copyright 2020 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport { Route } from \"./Route.js\";\nimport type { Serwist } from \"./Serwist.js\";\nimport type { PrecacheRouteOptions, RouteMatchCallback, RouteMatchCallbackOptions } from \"./types.js\";\nimport { generateURLVariations } from \"./utils/generateURLVariations.js\";\nimport { getFriendlyURL } from \"./utils/getFriendlyURL.js\";\nimport { logger } from \"./utils/logger.js\";\n\n/**\n * A subclass of {@linkcode Route} that takes a {@linkcode Serwist} instance and uses it to match\n * incoming requests and handle fetching responses from the precache.\n */\nexport class PrecacheRoute extends Route {\n  /**\n   * @param serwist A {@linkcode Serwist} instance.\n   * @param options Options to control how requests are matched\n   * against the list of precached URLs.\n   */\n  constructor(serwist: Serwist, options?: PrecacheRouteOptions) {\n    const match: RouteMatchCallback = ({ request }: RouteMatchCallbackOptions) => {\n      const urlsToCacheKeys = serwist.getUrlsToPrecacheKeys();\n      for (const possibleURL of generateURLVariations(request.url, options)) {\n        const cacheKey = urlsToCacheKeys.get(possibleURL);\n        if (cacheKey) {\n          const integrity = serwist.getIntegrityForPrecacheKey(cacheKey);\n          return { cacheKey, integrity };\n        }\n      }\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.debug(`Precaching did not find a match for ${getFriendlyURL(request.url)}.`);\n      }\n      return;\n    };\n\n    super(match, serwist.precacheStrategy);\n  }\n}\n","/*\n  Copyright 2020 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the LICENSE file or at\n  https://opensource.org/licenses/MIT.\n*/\n\nimport type { Serwist } from \"../Serwist.js\";\nimport type { SerwistPlugin, SerwistPluginCallbackParam } from \"../types.js\";\n\n/**\n * A plugin, designed to be used with PrecacheController, to translate URLs into\n * the corresponding cache key, based on the current revision info.\n *\n * @private\n */\nexport class PrecacheCacheKeyPlugin implements SerwistPlugin {\n  private readonly _precacheController: Serwist;\n\n  constructor({ precacheController }: { precacheController: Serwist }) {\n    this._precacheController = precacheController;\n  }\n\n  cacheKeyWillBeUsed: SerwistPlugin[\"cacheKeyWillBeUsed\"] = async ({ request, params }: SerwistPluginCallbackParam[\"cacheKeyWillBeUsed\"]) => {\n    // Params is type any, can't change right now.\n    const cacheKey = params?.cacheKey || this._precacheController.getPrecacheKeyForUrl(request.url);\n\n    return cacheKey ? new Request(cacheKey, { headers: request.headers }) : request;\n  };\n}\n","import { privateCacheNames } from \"../index.internal.js\";\nimport type { PrecacheStrategyOptions } from \"../lib/strategies/PrecacheStrategy.js\";\nimport type { Serwist } from \"../Serwist.js\";\nimport type { PrecacheOptions, PrecacheRouteOptions } from \"../types.js\";\nimport { PrecacheCacheKeyPlugin } from \"./PrecacheCacheKeyPlugin.js\";\n\nexport const parsePrecacheOptions = (serwist: Serwist, precacheOptions: PrecacheOptions = {}) => {\n  const {\n    cacheName: precacheCacheName,\n    plugins: precachePlugins = [],\n    fetchOptions: precacheFetchOptions,\n    matchOptions: precacheMatchOptions,\n    fallbackToNetwork: precacheFallbackToNetwork,\n    directoryIndex: precacheDirectoryIndex,\n    ignoreURLParametersMatching: precacheIgnoreUrls,\n    cleanURLs: precacheCleanUrls,\n    urlManipulation: precacheUrlManipulation,\n    cleanupOutdatedCaches,\n    concurrency = 10,\n    navigateFallback,\n    navigateFallbackAllowlist,\n    navigateFallbackDenylist,\n  } = precacheOptions ?? {};\n\n  return {\n    precacheStrategyOptions: {\n      cacheName: privateCacheNames.getPrecacheName(precacheCacheName),\n      plugins: [...precachePlugins, new PrecacheCacheKeyPlugin({ precacheController: serwist })],\n      fetchOptions: precacheFetchOptions,\n      matchOptions: precacheMatchOptions,\n      fallbackToNetwork: precacheFallbackToNetwork,\n    } satisfies PrecacheStrategyOptions,\n    precacheRouteOptions: {\n      directoryIndex: precacheDirectoryIndex,\n      ignoreURLParametersMatching: precacheIgnoreUrls,\n      cleanURLs: precacheCleanUrls,\n      urlManipulation: precacheUrlManipulation,\n    } satisfies PrecacheRouteOptions,\n    precacheMiscOptions: {\n      cleanupOutdatedCaches,\n      concurrency,\n      navigateFallback,\n      navigateFallbackAllowlist,\n      navigateFallbackDenylist,\n    },\n  };\n};\n","import { parallel } from \"@serwist/utils\";\nimport { defaultMethod, type HTTPMethod } from \"./constants.js\";\nimport { disableDevLogs as disableDevLogsImpl } from \"./disableDevLogs.js\";\nimport { type GoogleAnalyticsInitializeOptions, initializeGoogleAnalytics } from \"./lib/googleAnalytics/initializeGoogleAnalytics.js\";\nimport { type PrecacheFallbackEntry, PrecacheFallbackPlugin } from \"./lib/precaching/PrecacheFallbackPlugin.js\";\nimport { PrecacheStrategy } from \"./lib/strategies/PrecacheStrategy.js\";\nimport { Strategy } from \"./lib/strategies/Strategy.js\";\nimport { NavigationRoute } from \"./NavigationRoute.js\";\nimport { enableNavigationPreload } from \"./navigationPreload.js\";\nimport { PrecacheRoute } from \"./PrecacheRoute.js\";\nimport type { Route } from \"./Route.js\";\nimport { setCacheNameDetails } from \"./setCacheNameDetails.js\";\nimport type {\n  CleanupResult,\n  InstallEvent,\n  InstallResult,\n  PrecacheEntry,\n  PrecacheOptions,\n  RequestRule,\n  RouteHandler,\n  RouteHandlerCallback,\n  RouteHandlerCallbackOptions,\n  RouteHandlerObject,\n  RouteMatchCallback,\n  RouteMatchCallbackOptions,\n  RuntimeCaching,\n} from \"./types.js\";\nimport { assert } from \"./utils/assert.js\";\nimport { cleanupOutdatedCaches as cleanupOutdatedCachesImpl } from \"./utils/cleanupOutdatedCaches.js\";\nimport { clientsClaim as clientsClaimImpl } from \"./utils/clientsClaim.js\";\nimport { createCacheKey } from \"./utils/createCacheKey.js\";\nimport { getFriendlyURL } from \"./utils/getFriendlyURL.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { normalizeHandler } from \"./utils/normalizeHandler.js\";\nimport { PrecacheInstallReportPlugin } from \"./utils/PrecacheInstallReportPlugin.js\";\nimport { parsePrecacheOptions } from \"./utils/parsePrecacheOptions.js\";\nimport { parseRoute } from \"./utils/parseRoute.js\";\nimport { printCleanupDetails } from \"./utils/printCleanupDetails.js\";\nimport { printInstallDetails } from \"./utils/printInstallDetails.js\";\nimport { SerwistError } from \"./utils/SerwistError.js\";\nimport { waitUntil } from \"./utils/waitUntil.js\";\n\ndeclare const self: ServiceWorkerGlobalScope;\n\nexport interface FallbackEntry extends PrecacheFallbackEntry {}\n\nexport interface FallbacksOptions {\n  /**\n   * A list of fallback entries.\n   */\n  entries: FallbackEntry[];\n}\n\nexport interface SerwistOptions {\n  /**\n   * A list of URLs that should be cached.\n   */\n  precacheEntries?: (PrecacheEntry | string)[];\n  /**\n   * Options to customize how Serwist precaches the URLs in the precache list.\n   */\n  precacheOptions?: PrecacheOptions;\n  /**\n   * Forces the waiting service worker to become the active one.\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting\n   */\n  skipWaiting?: boolean;\n  /**\n   * Imports external scripts. They are executed in the order they\n   * are passed.\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts\n   */\n  importScripts?: string[];\n  /**\n   * Enables navigation preloading if it is supported.\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/navigationPreload\n   */\n  navigationPreload?: boolean;\n  /**\n   * Modifies the prefix of the default cache names used by Serwist packages.\n   */\n  cacheId?: string | undefined;\n  /**\n   * Claims any currently available clients once the service worker\n   * becomes active. This is normally used in conjunction with `skipWaiting()`.\n   *\n   * @default false\n   */\n  clientsClaim?: boolean;\n  /**\n   * A list of caching strategies.\n   */\n  runtimeCaching?: RuntimeCaching[];\n  /**\n   * Request rules that define how certain resources should be fetched\n   * before the service worker starts up.\n   *\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent/addRoutes\n   * @experimental\n   */\n  requestRules?: RequestRule | RequestRule[];\n  /**\n   * Your configuration for {@linkcode initializeGoogleAnalytics}. This plugin is\n   * only initialized when this option is not `undefined` or `false`.\n   */\n  offlineAnalyticsConfig?: Omit<GoogleAnalyticsInitializeOptions, \"serwist\"> | boolean;\n  /**\n   * Disables Serwist's logging in development mode.\n   *\n   * @default false\n   */\n  disableDevLogs?: boolean;\n  /**\n   * Precaches routes so that they can be used as a fallback when\n   * a {@linkcode Strategy} fails to generate a response.\n   *\n   * Note: This option mutates `runtimeCaching`. It also expects the URLs\n   * defined in `entries` to have been precached beforehand.\n   */\n  fallbacks?: FallbacksOptions;\n}\n\ntype RequestArgs = string | [string, RequestInit?];\n\ninterface CacheURLsMessageData {\n  type: string;\n  payload: {\n    urlsToCache: RequestArgs[];\n  };\n}\n\n/**\n * A class that helps bootstrap the service worker.\n *\n * @see https://serwist.pages.dev/docs/serwist/core/serwist\n */\nexport class Serwist {\n  private readonly _urlsToCacheKeys: Map<string, string> = new Map();\n  private readonly _urlsToCacheModes: Map<string, \"reload\" | \"default\" | \"no-store\" | \"no-cache\" | \"force-cache\" | \"only-if-cached\"> = new Map();\n  private readonly _cacheKeysToIntegrities: Map<string, string> = new Map();\n  private _concurrentPrecaching: number;\n  private readonly _precacheStrategy: Strategy;\n  private readonly _routes: Map<HTTPMethod, Route[]>;\n  private readonly _defaultHandlerMap: Map<HTTPMethod, RouteHandlerObject>;\n  private _catchHandler?: RouteHandlerObject;\n  private _requestRules?: RequestRule | RequestRule[];\n\n  constructor({\n    precacheEntries,\n    precacheOptions,\n    skipWaiting = false,\n    importScripts,\n    navigationPreload = false,\n    cacheId,\n    clientsClaim = false,\n    runtimeCaching,\n    offlineAnalyticsConfig,\n    disableDevLogs = false,\n    fallbacks,\n    requestRules,\n  }: SerwistOptions = {}) {\n    const { precacheStrategyOptions, precacheRouteOptions, precacheMiscOptions } = parsePrecacheOptions(this, precacheOptions);\n\n    this._concurrentPrecaching = precacheMiscOptions.concurrency;\n    this._precacheStrategy = new PrecacheStrategy(precacheStrategyOptions);\n    this._routes = new Map();\n    this._defaultHandlerMap = new Map();\n    this._requestRules = requestRules;\n\n    this.handleInstall = this.handleInstall.bind(this);\n    this.handleActivate = this.handleActivate.bind(this);\n    this.handleFetch = this.handleFetch.bind(this);\n    this.handleCache = this.handleCache.bind(this);\n\n    if (!!importScripts && importScripts.length > 0) self.importScripts(...importScripts);\n\n    if (navigationPreload) enableNavigationPreload();\n\n    if (cacheId !== undefined) {\n      setCacheNameDetails({\n        prefix: cacheId,\n      });\n    }\n\n    if (skipWaiting) {\n      self.skipWaiting();\n    } else {\n      self.addEventListener(\"message\", (event) => {\n        if (event.data && event.data.type === \"SKIP_WAITING\") {\n          self.skipWaiting();\n        }\n      });\n    }\n\n    if (clientsClaim) clientsClaimImpl();\n\n    if (!!precacheEntries && precacheEntries.length > 0) {\n      this.addToPrecacheList(precacheEntries);\n    }\n\n    if (precacheMiscOptions.cleanupOutdatedCaches) {\n      cleanupOutdatedCachesImpl(precacheStrategyOptions.cacheName);\n    }\n\n    this.registerRoute(new PrecacheRoute(this, precacheRouteOptions));\n\n    if (precacheMiscOptions.navigateFallback) {\n      this.registerRoute(\n        new NavigationRoute(this.createHandlerBoundToUrl(precacheMiscOptions.navigateFallback), {\n          allowlist: precacheMiscOptions.navigateFallbackAllowlist,\n          denylist: precacheMiscOptions.navigateFallbackDenylist,\n        }),\n      );\n    }\n\n    if (offlineAnalyticsConfig !== undefined) {\n      if (typeof offlineAnalyticsConfig === \"boolean\") {\n        offlineAnalyticsConfig && initializeGoogleAnalytics({ serwist: this });\n      } else {\n        initializeGoogleAnalytics({\n          ...offlineAnalyticsConfig,\n          serwist: this,\n        });\n      }\n    }\n\n    if (runtimeCaching !== undefined) {\n      if (fallbacks !== undefined) {\n        const fallbackPlugin = new PrecacheFallbackPlugin({\n          fallbackUrls: fallbacks.entries,\n          serwist: this,\n        });\n\n        runtimeCaching.forEach((cacheEntry) => {\n          if (\n            cacheEntry.handler instanceof Strategy &&\n            // This also filters entries with `PrecacheFallbackPlugin` as it also has `handlerDidError`.\n            !cacheEntry.handler.plugins.some((plugin) => \"handlerDidError\" in plugin)\n          ) {\n            cacheEntry.handler.plugins.push(fallbackPlugin);\n          }\n        });\n      }\n      for (const entry of runtimeCaching) {\n        this.registerCapture(entry.matcher, entry.handler, entry.method);\n      }\n    }\n\n    if (disableDevLogs) disableDevLogsImpl();\n  }\n\n  /**\n   * The strategy used to precache assets and respond to `fetch` events.\n   */\n  get precacheStrategy(): Strategy {\n    return this._precacheStrategy;\n  }\n  /**\n   * A `Map` of HTTP method name (`'GET'`, etc.) to an array of all corresponding registered {@linkcode Route}\n   * instances.\n   */\n  get routes(): Map<HTTPMethod, Route[]> {\n    return this._routes;\n  }\n\n  /**\n   * Adds Serwist's event listeners for you. Before calling it, add your own listeners should you need to.\n   */\n  addEventListeners() {\n    self.addEventListener(\"install\", this.handleInstall);\n    self.addEventListener(\"activate\", this.handleActivate);\n    self.addEventListener(\"fetch\", this.handleFetch);\n    self.addEventListener(\"message\", this.handleCache);\n  }\n\n  /**\n   * Adds items to the precache list, removing duplicates and ensuring the information is valid.\n   *\n   * @param entries Array of entries to precache.\n   */\n  addToPrecacheList(entries: (PrecacheEntry | string)[]): void {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isArray(entries, {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"addToCacheList\",\n        paramName: \"entries\",\n      });\n    }\n\n    const urlsToWarnAbout: string[] = [];\n    for (const entry of entries) {\n      // See https://github.com/GoogleChrome/workbox/issues/2259\n      if (typeof entry === \"string\") {\n        urlsToWarnAbout.push(entry);\n      } else if (entry && !entry.integrity && entry.revision === undefined) {\n        urlsToWarnAbout.push(entry.url);\n      }\n\n      const { cacheKey, url } = createCacheKey(entry);\n      const cacheMode = typeof entry !== \"string\" && entry.revision ? \"reload\" : \"default\";\n\n      if (this._urlsToCacheKeys.has(url) && this._urlsToCacheKeys.get(url) !== cacheKey) {\n        throw new SerwistError(\"add-to-cache-list-conflicting-entries\", {\n          firstEntry: this._urlsToCacheKeys.get(url),\n          secondEntry: cacheKey,\n        });\n      }\n\n      if (typeof entry !== \"string\" && entry.integrity) {\n        if (this._cacheKeysToIntegrities.has(cacheKey) && this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) {\n          throw new SerwistError(\"add-to-cache-list-conflicting-integrities\", {\n            url,\n          });\n        }\n        this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);\n      }\n\n      this._urlsToCacheKeys.set(url, cacheKey);\n      this._urlsToCacheModes.set(url, cacheMode);\n    }\n    if (urlsToWarnAbout.length > 0) {\n      const warningMessage = `Serwist is precaching URLs without revision info: ${urlsToWarnAbout.join(\n        \", \",\n      )}\\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;\n      if (process.env.NODE_ENV === \"production\") {\n        // Use console directly to display this warning without bloating\n        // bundle sizes by pulling in all of the logger codebase in prod.\n        console.warn(warningMessage);\n      } else {\n        logger.warn(warningMessage);\n      }\n    }\n  }\n\n  /**\n   * Precaches new and updated assets. Call this method from the service worker's\n   * `install` event.\n   *\n   * Note: this method calls `event.waitUntil()` for you, so you do not need\n   * to call it yourself in your event handlers.\n   *\n   * @param event\n   * @returns\n   */\n  handleInstall(event: InstallEvent): Promise<InstallResult> {\n    void this.registerRequestRules(event);\n\n    return waitUntil<InstallResult>(event, async () => {\n      const installReportPlugin = new PrecacheInstallReportPlugin();\n      this.precacheStrategy.plugins.push(installReportPlugin);\n\n      await parallel(this._concurrentPrecaching, Array.from(this._urlsToCacheKeys.entries()), async ([url, cacheKey]): Promise<void> => {\n        const integrity = this._cacheKeysToIntegrities.get(cacheKey);\n        const cacheMode = this._urlsToCacheModes.get(url);\n\n        const request = new Request(url, {\n          integrity,\n          cache: cacheMode,\n          credentials: \"same-origin\",\n        });\n\n        await Promise.all(\n          this.precacheStrategy.handleAll({\n            event,\n            request,\n            url: new URL(request.url),\n            params: { cacheKey },\n          }),\n        );\n      });\n\n      const { updatedURLs, notUpdatedURLs } = installReportPlugin;\n\n      if (process.env.NODE_ENV !== \"production\") {\n        printInstallDetails(updatedURLs, notUpdatedURLs);\n      }\n\n      return { updatedURLs, notUpdatedURLs };\n    });\n  }\n\n  /**\n   * Registers request rules using the experimental `InstallEvent.addRoutes()` API.\n   * These rules allow bypassing the service worker for specific requests to improve performance.\n   *\n   * @param event The event object of an `install` event handler.\n   * @throws {Error} When the route rules are invalid\n   */\n  async registerRequestRules(event: InstallEvent): Promise<void> {\n    if (!this._requestRules) {\n      return;\n    }\n\n    // Check if both the API and route rules are available\n    if (!event?.addRoutes) {\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.warn(\n          \"Request rules ignored as the Static Routing API is not supported in this browser. \" +\n            \"See https://caniuse.com/mdn-api_installevent_addroutes for more information.\",\n        );\n      }\n      return;\n    }\n\n    try {\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.warn(\n          \"Request rules may not be supported in all browsers as the Static Routing API is experimental. \" +\n            \"This feature allows bypassing the service worker for specific requests to improve performance. \" +\n            \"See https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent/addRoutes for more information.\",\n        );\n      }\n\n      await event.addRoutes(this._requestRules);\n\n      // Free up the rules object.\n      this._requestRules = undefined;\n    } catch (error) {\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.error(\n          `Failed to register request rules: ${error instanceof Error ? error.message : String(error)}. ` +\n            \"This may occur if the browser doesn't support the Static Routing API or if the request rules are invalid.\",\n        );\n      }\n\n      throw error;\n    }\n  }\n\n  /**\n   * Deletes assets that are no longer present in the current precache manifest.\n   * Call this method from the service worker's `activate` event.\n   *\n   * Note: this method calls `event.waitUntil()` for you, so you do not need\n   * to call it yourself in your event handlers.\n   *\n   * @param event\n   * @returns\n   */\n  handleActivate(event: ExtendableEvent): Promise<CleanupResult> {\n    return waitUntil<CleanupResult>(event, async () => {\n      const cache = await self.caches.open(this.precacheStrategy.cacheName);\n      const currentlyCachedRequests = await cache.keys();\n      const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());\n\n      const deletedCacheRequests: string[] = [];\n\n      for (const request of currentlyCachedRequests) {\n        if (!expectedCacheKeys.has(request.url)) {\n          await cache.delete(request);\n          deletedCacheRequests.push(request.url);\n        }\n      }\n\n      if (process.env.NODE_ENV !== \"production\") {\n        printCleanupDetails(deletedCacheRequests);\n      }\n\n      return { deletedCacheRequests };\n    });\n  }\n\n  /**\n   * Gets a `Response` from an appropriate `Route`'s handler. Call this method\n   * from the service worker's `fetch` event.\n   * @param event\n   */\n  handleFetch(event: FetchEvent) {\n    const { request } = event;\n    const responsePromise = this.handleRequest({ request, event });\n    if (responsePromise) {\n      event.respondWith(responsePromise);\n    }\n  }\n\n  /**\n   * Caches new URLs on demand. Call this method from the service worker's\n   * `message` event. To trigger the handler, send a message of type `\"CACHE_URLS\"`\n   * alongside a list of URLs that should be cached as `urlsToCache`.\n   * @param event\n   */\n  handleCache(event: ExtendableMessageEvent) {\n    if (event.data && event.data.type === \"CACHE_URLS\") {\n      const { payload }: CacheURLsMessageData = event.data;\n\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.debug(\"Caching URLs from the window\", payload.urlsToCache);\n      }\n\n      const requestPromises = Promise.all(\n        payload.urlsToCache.map((entry: string | [string, RequestInit?]) => {\n          let request: Request;\n          if (typeof entry === \"string\") {\n            request = new Request(entry);\n          } else {\n            request = new Request(...entry);\n          }\n          return this.handleRequest({ request, event });\n        }),\n      );\n\n      event.waitUntil(requestPromises);\n\n      // If a MessageChannel was used, reply to the message on success.\n      if (event.ports?.[0]) {\n        void requestPromises.then(() => event.ports[0].postMessage(true));\n      }\n    }\n  }\n\n  /**\n   * Define a default handler that's called when no routes explicitly\n   * match the incoming request.\n   *\n   * Each HTTP method (`'GET'`, `'POST'`, etc.) gets its own default handler.\n   *\n   * Without a default handler, unmatched requests will go against the\n   * network as if there were no service worker present.\n   *\n   * @param handler A callback function that returns a `Promise` resulting in a `Response`.\n   * @param method The HTTP method to associate with this default handler. Each method\n   * has its own default. Defaults to `'GET'`.\n   */\n  setDefaultHandler(handler: RouteHandler, method: HTTPMethod = defaultMethod): void {\n    this._defaultHandlerMap.set(method, normalizeHandler(handler));\n  }\n\n  /**\n   * If a {@linkcode Route} throws an error while handling a request, this handler\n   * will be called and given a chance to provide a response.\n   *\n   * @param handler A callback function that returns a `Promise` resulting\n   * in a `Response`.\n   */\n  setCatchHandler(handler: RouteHandler): void {\n    this._catchHandler = normalizeHandler(handler);\n  }\n\n  /**\n   * Registers a `RegExp`, string, or function with a caching\n   * strategy to the router.\n   *\n   * @param capture If the capture param is a {@linkcode Route} object, all other arguments will be ignored.\n   * @param handler A callback function that returns a `Promise` resulting in a `Response`.\n   * This parameter is required if `capture` is not a {@linkcode Route} object.\n   * @param method The HTTP method to match the route against. Defaults to `'GET'`.\n   * @returns The generated {@linkcode Route} object.\n   */\n  registerCapture<T extends RegExp | string | RouteMatchCallback | Route>(\n    capture: T,\n    handler?: T extends Route ? never : RouteHandler,\n    method?: T extends Route ? never : HTTPMethod,\n  ): Route {\n    const route = parseRoute(capture, handler, method);\n    this.registerRoute(route);\n    return route;\n  }\n\n  /**\n   * Registers a {@linkcode Route} with the router.\n   *\n   * @param route The {@linkcode Route} to register.\n   */\n  registerRoute(route: Route): void {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isType(route, \"object\", {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"registerRoute\",\n        paramName: \"route\",\n      });\n\n      assert!.hasMethod(route, \"match\", {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"registerRoute\",\n        paramName: \"route\",\n      });\n\n      assert!.isType(route.handler, \"object\", {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"registerRoute\",\n        paramName: \"route\",\n      });\n\n      assert!.hasMethod(route.handler, \"handle\", {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"registerRoute\",\n        paramName: \"route.handler\",\n      });\n\n      assert!.isType(route.method, \"string\", {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"registerRoute\",\n        paramName: \"route.method\",\n      });\n    }\n\n    if (!this._routes.has(route.method)) {\n      this._routes.set(route.method, []);\n    }\n\n    // Give precedence to all of the earlier routes by adding this additional\n    // route to the end of the array.\n    this._routes.get(route.method)!.push(route);\n  }\n\n  /**\n   * Unregisters a route from the router.\n   *\n   * @param route The {@linkcode Route} object to unregister.\n   */\n  unregisterRoute(route: Route): void {\n    if (!this._routes.has(route.method)) {\n      throw new SerwistError(\"unregister-route-but-not-found-with-method\", {\n        method: route.method,\n      });\n    }\n\n    const routeIndex = this._routes.get(route.method)!.indexOf(route);\n    if (routeIndex > -1) {\n      this._routes.get(route.method)!.splice(routeIndex, 1);\n    } else {\n      throw new SerwistError(\"unregister-route-route-not-registered\");\n    }\n  }\n\n  /**\n   * Returns a mapping of a precached URL to the corresponding cache key, taking\n   * into account the revision information for the URL.\n   *\n   * @returns A URL to cache key mapping.\n   */\n  getUrlsToPrecacheKeys(): Map<string, string> {\n    return this._urlsToCacheKeys;\n  }\n\n  /**\n   * Returns a list of all the URLs that have been precached by the current\n   * service worker.\n   *\n   * @returns The precached URLs.\n   */\n  getPrecachedUrls(): string[] {\n    return [...this._urlsToCacheKeys.keys()];\n  }\n\n  /**\n   * Returns the cache key used for storing a given URL. If that URL is\n   * unversioned, like \"/index.html\", then the cache key will be the original\n   * URL with a search parameter appended to it.\n   *\n   * @param url A URL whose cache key you want to look up.\n   * @returns The versioned URL that corresponds to a cache key\n   * for the original URL, or undefined if that URL isn't precached.\n   */\n  getPrecacheKeyForUrl(url: string): string | undefined {\n    const urlObject = new URL(url, location.href);\n    return this._urlsToCacheKeys.get(urlObject.href);\n  }\n\n  /**\n   * @param url A cache key whose SRI you want to look up.\n   * @returns The subresource integrity associated with the cache key,\n   * or undefined if it's not set.\n   */\n  getIntegrityForPrecacheKey(cacheKey: string): string | undefined {\n    return this._cacheKeysToIntegrities.get(cacheKey);\n  }\n\n  /**\n   * This acts as a drop-in replacement for\n   * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)\n   * with the following differences:\n   *\n   * - It knows what the name of the precache is, and only checks in that cache.\n   * - It allows you to pass in an \"original\" URL without versioning parameters,\n   * and it will automatically look up the correct cache key for the currently\n   * active revision of that URL.\n   *\n   * E.g., `matchPrecache('index.html')` will find the correct precached\n   * response for the currently active service worker, even if the actual cache\n   * key is `'/index.html?__WB_REVISION__=1234abcd'`.\n   *\n   * @param request The key (without revisioning parameters)\n   * to look up in the precache.\n   * @returns\n   */\n  async matchPrecache(request: string | Request): Promise<Response | undefined> {\n    const url = request instanceof Request ? request.url : request;\n    const cacheKey = this.getPrecacheKeyForUrl(url);\n    if (cacheKey) {\n      const cache = await self.caches.open(this.precacheStrategy.cacheName);\n      return cache.match(cacheKey);\n    }\n    return undefined;\n  }\n\n  /**\n   * Returns a function that looks up `url` in the precache (taking into\n   * account revision information), and returns the corresponding `Response`.\n   *\n   * @param url The precached URL which will be used to lookup the response.\n   * @return\n   */\n  createHandlerBoundToUrl(url: string): RouteHandlerCallback {\n    const cacheKey = this.getPrecacheKeyForUrl(url);\n    if (!cacheKey) {\n      throw new SerwistError(\"non-precached-url\", { url });\n    }\n    return (options) => {\n      options.request = new Request(url);\n      options.params = { cacheKey, ...options.params };\n\n      return this.precacheStrategy.handle(options);\n    };\n  }\n\n  /**\n   * Applies the routing rules to a `FetchEvent` object to get a response from an\n   * appropriate route.\n   *\n   * @param options\n   * @returns A promise is returned if a registered route can handle the request.\n   * If there is no matching route and there's no default handler, `undefined`\n   * is returned.\n   */\n  handleRequest({\n    request,\n    event,\n  }: {\n    /**\n     * The request to handle.\n     */\n    request: Request;\n    /**\n     * The event that triggered the request.\n     */\n    event: ExtendableEvent;\n  }): Promise<Response> | undefined {\n    if (process.env.NODE_ENV !== \"production\") {\n      assert!.isInstance(request, Request, {\n        moduleName: \"serwist\",\n        className: \"Serwist\",\n        funcName: \"handleRequest\",\n        paramName: \"options.request\",\n      });\n    }\n\n    const url = new URL(request.url, location.href);\n    if (!url.protocol.startsWith(\"http\")) {\n      if (process.env.NODE_ENV !== \"production\") {\n        logger.debug(\"Router only supports URLs that start with 'http'.\");\n      }\n      return;\n    }\n\n    const sameOrigin = url.origin === location.origin;\n    const { params, route } = this.findMatchingRoute({\n      event,\n      request,\n      sameOrigin,\n      url,\n    });\n    let handler = route?.handler;\n\n    const debugMessages = [];\n    if (process.env.NODE_ENV !== \"production\") {\n      if (handler) {\n        debugMessages.push([\"Found a route to handle this request:\", route]);\n\n        if (params) {\n          debugMessages.push([`Passing the following params to the route's handler:`, params]);\n        }\n      }\n    }\n\n    // If we don't have a handler because there was no matching route, then\n    // fall back to defaultHandler if that's defined.\n    const method = request.method as HTTPMethod;\n    if (!handler && this._defaultHandlerMap.has(method)) {\n      if (process.env.NODE_ENV !== \"production\") {\n        debugMessages.push(`Failed to find a matching route. Falling back to the default handler for ${method}.`);\n      }\n      handler = this._defaultHandlerMap.get(method);\n    }\n\n    if (!handler) {\n      if (process.env.NODE_ENV !== \"production\") {\n        // No handler so Serwist will do nothing. If logs is set of debug\n        // i.e. verbose, we should print out this information.\n        logger.debug(`No route found for: ${getFriendlyURL(url)}`);\n      }\n      return;\n    }\n\n    if (process.env.NODE_ENV !== \"production\") {\n      // We have a handler, meaning Serwist is going to handle the route.\n      // print the routing details to the console.\n      logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);\n\n      for (const msg of debugMessages) {\n        if (Array.isArray(msg)) {\n          logger.log(...msg);\n        } else {\n          logger.log(msg);\n        }\n      }\n\n      logger.groupEnd();\n    }\n\n    // Wrap in try and catch in case the handle method throws a synchronous\n    // error. It should still callback to the catch handler.\n    let responsePromise: Promise<Response>;\n    try {\n      responsePromise = handler.handle({ url, request, event, params });\n    } catch (err) {\n      responsePromise = Promise.reject(err);\n    }\n\n    // Get route's catch handler, if it exists\n    const catchHandler = route?.catchHandler;\n\n    if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {\n      responsePromise = responsePromise.catch(async (err) => {\n        // If there's a route catch handler, process that first\n        if (catchHandler) {\n          if (process.env.NODE_ENV !== \"production\") {\n            // Still include URL here as it will be async from the console group\n            // and may not make sense without the URL\n            logger.groupCollapsed(`Error thrown when responding to:  ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);\n            logger.error(\"Error thrown by:\", route);\n            logger.error(err);\n            logger.groupEnd();\n          }\n\n          try {\n            return await catchHandler.handle({ url, request, event, params });\n          } catch (catchErr) {\n            if (catchErr instanceof Error) {\n              err = catchErr;\n            }\n          }\n        }\n\n        if (this._catchHandler) {\n          if (process.env.NODE_ENV !== \"production\") {\n            // Still include URL here as it will be async from the console group\n            // and may not make sense without the URL\n            logger.groupCollapsed(`Error thrown when responding to:  ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);\n            logger.error(\"Error thrown by:\", route);\n            logger.error(err);\n            logger.groupEnd();\n          }\n          return this._catchHandler.handle({ url, request, event });\n        }\n\n        throw err;\n      });\n    }\n\n    return responsePromise;\n  }\n\n  /**\n   * Checks a request and URL (and optionally an event) against the list of\n   * registered routes, and if there's a match, returns the corresponding\n   * route along with any params generated by the match.\n   *\n   * @param options\n   * @returns An object with `route` and `params` properties. They are populated\n   * if a matching route was found or `undefined` otherwise.\n   */\n  findMatchingRoute({ url, sameOrigin, request, event }: RouteMatchCallbackOptions): {\n    route?: Route;\n    params?: RouteHandlerCallbackOptions[\"params\"];\n  } {\n    const routes = this._routes.get(request.method as HTTPMethod) || [];\n    for (const route of routes) {\n      let params: Promise<any> | undefined;\n      // route.match returns type any, not possible to change right now.\n      const matchResult = route.match({ url, sameOrigin, request, event });\n      if (matchResult) {\n        if (process.env.NODE_ENV !== \"production\") {\n          // Warn developers that using an async matchCallback is almost always\n          // not the right thing to do.\n          if (matchResult instanceof Promise) {\n            logger.warn(\n              `While routing ${getFriendlyURL(\n                url,\n              )}, an async matchCallback function was used. Please convert the following route to use a synchronous matchCallback function:`,\n              route,\n            );\n          }\n        }\n\n        // See https://github.com/GoogleChrome/workbox/issues/2079\n        params = matchResult;\n        if (Array.isArray(params) && params.length === 0) {\n          // Instead of passing an empty array in as params, use undefined.\n          params = undefined;\n        } else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {\n          // Instead of passing an empty object in as params, use undefined.\n          params = undefined;\n        } else if (typeof matchResult === \"boolean\") {\n          // For the boolean value true (rather than just something truth-y),\n          // don't set params.\n          // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353\n          params = undefined;\n        }\n\n        // Return early if have a match.\n        return { route, params };\n      }\n    }\n    // If no match was found above, return and empty object.\n    return {};\n  }\n}\n"],"mappings":"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"}