From 9a33b84b1c1b761130fb4e7bbfbd57cce78ab346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 27 Sep 2025 17:05:06 -0500 Subject: [PATCH] feat: install button --- .vscode/settings.json | 1 + bun.lockb | Bin 555062 -> 601273 bytes packages/i18n/strings/en.json | 9 + packages/website/astro.config.ts | 4 +- packages/website/dev-dist/sw.js | 94 + packages/website/dev-dist/workbox-bf09d6d8.js | 3373 +++++++++++++++++ packages/website/package.json | 3 + .../public/assets/images/pwa-promo.png | Bin 0 -> 83294 bytes packages/website/src/components/PWA.astro | 33 + .../website/src/components/PWAPrompter.astro | 102 + .../website/src/pages/[...locale]/index.astro | 3 + packages/website/tsconfig.json | 6 +- 12 files changed, 3626 insertions(+), 2 deletions(-) create mode 100644 packages/website/dev-dist/sw.js create mode 100644 packages/website/dev-dist/workbox-bf09d6d8.js create mode 100644 packages/website/public/assets/images/pwa-promo.png create mode 100644 packages/website/src/components/PWAPrompter.astro diff --git a/.vscode/settings.json b/.vscode/settings.json index 2a4147cf3..b272192fe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,6 +21,7 @@ "AYUV", "battleresults", "bbox", + "beforeinstallprompt", "bepaint", "betakrieg", "BINORMAL", diff --git a/bun.lockb b/bun.lockb index 00fca5d1352ff0f6ddc53c6864f9d837d2425dfc..225e45e8fa8be2dfa6985d40ed93fa7893e6981b 100755 GIT binary patch delta 82852 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 niWP`bU|8q<fHFg_}^Y1GaHU{~-H2ePmKrtL! delta 49145 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

(eA4?M zJwFARx%ASk+bOo1!a1C>4R2VCzEVJDzHs`$0%@g%fHzkbW!`D!lm@3bI4hh$VLh|K zlb*i%{cP_Ia09&M=;WptQ$S(hGvZ`)biS0wdPPdzpt>U{Meu1SWI7Ap>hLO+O({+ycqV9001lAR?* z-^|DxRM^FUWQ|BgX)y(k!Q|yYu*qAxw5tc+uCD?@gWCpV)fAHs2<_lr5~62C+Dmnb zg*Z8#5g`zvXa=ttcypIooLjjeS%c0SD2QRjqhgveR_NiTH9aVKBj(Vpn(Ma*%rYoo zXgyoWl!}mVn?tI?o-wiLTZ4JnK@!J8HE$qTyZ5sj3-2y@oNNtVb`gSnNqitDt0=cC zIeAtSZOI|J2ML__LE`M+Ll_ZtBo5I18x>lSd zzPmMEy+XP~hD}8~gN2#9ijyx(|GKS7ikF@>5#NUVrmMOyz zO>+7myV=o5i8)I4!c4bs*TK)9&6Pi*6aJT61Z?3_Z0aR<+C*4X2ywi H)!6?4t30vj diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 81ceebaba..90cb99401 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -837,6 +837,15 @@ }, "home": { + "pwa": { + "title": "Install the BlitzKit App", + "new": "NEW", + "checking": "Checking compatibility...", + "incompatible": "Incompatible device.", + "incompatible_help": "Try manually.", + "install": "Install" + }, + "discord": { "join_short": "Join cool people!", "join_long": "Join super duper cool people!", diff --git a/packages/website/astro.config.ts b/packages/website/astro.config.ts index da8334338..ede0d7029 100644 --- a/packages/website/astro.config.ts +++ b/packages/website/astro.config.ts @@ -12,6 +12,8 @@ import { tools } from "./src/constants/tools"; export default defineConfig({ devToolbar: { enabled: false }, + vite: { server: { allowedHosts: [] } }, + integrations: [ favicons({ name: strings.common.name, @@ -75,7 +77,7 @@ export default defineConfig({ }, }), - AstroPWA({ manifest: false }), + AstroPWA({ manifest: false, devOptions: { enabled: true } }), react(), ], diff --git a/packages/website/dev-dist/sw.js b/packages/website/dev-dist/sw.js new file mode 100644 index 000000000..74095df85 --- /dev/null +++ b/packages/website/dev-dist/sw.js @@ -0,0 +1,94 @@ +/** + * Copyright 2018 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// If the loader is already loaded, just stop. +if (!self.define) { + let registry = {}; + + // Used for `eval` and `importScripts` where we can't get script URL by other means. + // In both cases, it's safe to use a global var because those functions are synchronous. + let nextDefineUri; + + const singleRequire = (uri, parentUri) => { + uri = new URL(uri + ".js", parentUri).href; + return registry[uri] || ( + + new Promise(resolve => { + if ("document" in self) { + const script = document.createElement("script"); + script.src = uri; + script.onload = resolve; + document.head.appendChild(script); + } else { + nextDefineUri = uri; + importScripts(uri); + resolve(); + } + }) + + .then(() => { + let promise = registry[uri]; + if (!promise) { + throw new Error(`Module ${uri} didn’t register its module`); + } + return promise; + }) + ); + }; + + self.define = (depsNames, factory) => { + const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href; + if (registry[uri]) { + // Module is already loading or loaded. + return; + } + let exports = {}; + const require = depUri => singleRequire(depUri, uri); + const specialDeps = { + module: { uri }, + exports, + require + }; + registry[uri] = Promise.all(depsNames.map( + depName => specialDeps[depName] || require(depName) + )).then(deps => { + factory(...deps); + return exports; + }); + }; +} +define(['./workbox-bf09d6d8'], (function (workbox) { 'use strict'; + + self.addEventListener('message', event => { + if (event.data && event.data.type === 'SKIP_WAITING') { + self.skipWaiting(); + } + }); + + /** + * The precacheAndRoute() method efficiently caches and responds to + * requests for URLs in the manifest. + * See https://goo.gl/S9QRab + */ + workbox.precacheAndRoute([{ + "url": "/", + "revision": "0.at3jsejees" + }], { + "directoryIndex": "index.html" + }); + workbox.cleanupOutdatedCaches(); + workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("/"), { + allowlist: [/^\/$/] + })); + +})); diff --git a/packages/website/dev-dist/workbox-bf09d6d8.js b/packages/website/dev-dist/workbox-bf09d6d8.js new file mode 100644 index 000000000..d89e4342a --- /dev/null +++ b/packages/website/dev-dist/workbox-bf09d6d8.js @@ -0,0 +1,3373 @@ +define(['exports'], (function (exports) { 'use strict'; + + // @ts-ignore + try { + self['workbox:core:7.2.0'] && _(); + } catch (e) {} + + /* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const logger = (() => { + // Don't overwrite this value if it's already set. + // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923 + if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) { + self.__WB_DISABLE_DEV_LOGS = false; + } + let inGroup = false; + const methodToColorMap = { + debug: `#7f8c8d`, + log: `#2ecc71`, + warn: `#f39c12`, + error: `#c0392b`, + groupCollapsed: `#3498db`, + groupEnd: null // No colored prefix on groupEnd + }; + const print = function (method, args) { + if (self.__WB_DISABLE_DEV_LOGS) { + return; + } + if (method === 'groupCollapsed') { + // Safari doesn't print all console.groupCollapsed() arguments: + // https://bugs.webkit.org/show_bug.cgi?id=182754 + if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + console[method](...args); + return; + } + } + const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; + // When in a group, the workbox prefix is not displayed. + const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')]; + console[method](...logPrefix, ...args); + if (method === 'groupCollapsed') { + inGroup = true; + } + if (method === 'groupEnd') { + inGroup = false; + } + }; + // eslint-disable-next-line @typescript-eslint/ban-types + const api = {}; + const loggerMethods = Object.keys(methodToColorMap); + for (const key of loggerMethods) { + const method = key; + api[method] = (...args) => { + print(method, args); + }; + } + return api; + })(); + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const messages = { + 'invalid-value': ({ + paramName, + validValueDescription, + value + }) => { + if (!paramName || !validValueDescription) { + throw new Error(`Unexpected input to 'invalid-value' error.`); + } + return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`; + }, + 'not-an-array': ({ + moduleName, + className, + funcName, + paramName + }) => { + if (!moduleName || !className || !funcName || !paramName) { + throw new Error(`Unexpected input to 'not-an-array' error.`); + } + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`; + }, + 'incorrect-type': ({ + expectedType, + paramName, + moduleName, + className, + funcName + }) => { + if (!expectedType || !paramName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'incorrect-type' error.`); + } + const classNameStr = className ? `${className}.` : ''; + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}` + `${funcName}()' must be of type ${expectedType}.`; + }, + 'incorrect-class': ({ + expectedClassName, + paramName, + moduleName, + className, + funcName, + isReturnValueProblem + }) => { + if (!expectedClassName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'incorrect-class' error.`); + } + const classNameStr = className ? `${className}.` : ''; + if (isReturnValueProblem) { + return `The return value from ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; + } + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; + }, + 'missing-a-method': ({ + expectedMethod, + paramName, + moduleName, + className, + funcName + }) => { + if (!expectedMethod || !paramName || !moduleName || !className || !funcName) { + throw new Error(`Unexpected input to 'missing-a-method' error.`); + } + return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`; + }, + 'add-to-cache-list-unexpected-type': ({ + entry + }) => { + return `An unexpected entry was passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' The entry ` + `'${JSON.stringify(entry)}' isn't supported. You must supply an array of ` + `strings with one or more characters, objects with a url property or ` + `Request objects.`; + }, + 'add-to-cache-list-conflicting-entries': ({ + firstEntry, + secondEntry + }) => { + if (!firstEntry || !secondEntry) { + throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`); + } + return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`; + }, + 'plugin-error-request-will-fetch': ({ + thrownErrorMessage + }) => { + if (!thrownErrorMessage) { + throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`); + } + return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownErrorMessage}'.`; + }, + 'invalid-cache-name': ({ + cacheNameId, + value + }) => { + if (!cacheNameId) { + throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`); + } + return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`; + }, + 'unregister-route-but-not-found-with-method': ({ + method + }) => { + if (!method) { + throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`); + } + return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`; + }, + 'unregister-route-route-not-registered': () => { + return `The route you're trying to unregister was not previously ` + `registered.`; + }, + 'queue-replay-failed': ({ + name + }) => { + return `Replaying the background sync queue '${name}' failed.`; + }, + 'duplicate-queue-name': ({ + name + }) => { + return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`; + }, + 'expired-test-without-max-age': ({ + methodName, + paramName + }) => { + return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`; + }, + 'unsupported-route-type': ({ + moduleName, + className, + funcName, + paramName + }) => { + return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`; + }, + 'not-array-of-class': ({ + value, + expectedClass, + moduleName, + className, + funcName, + paramName + }) => { + return `The supplied '${paramName}' parameter must be an array of ` + `'${expectedClass}' objects. Received '${JSON.stringify(value)},'. ` + `Please check the call to ${moduleName}.${className}.${funcName}() ` + `to fix the issue.`; + }, + 'max-entries-or-age-required': ({ + moduleName, + className, + funcName + }) => { + return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`; + }, + 'statuses-or-headers-required': ({ + moduleName, + className, + funcName + }) => { + return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`; + }, + 'invalid-string': ({ + moduleName, + funcName, + paramName + }) => { + if (!paramName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'invalid-string' error.`); + } + return `When using strings, the '${paramName}' parameter must start with ` + `'http' (for cross-origin matches) or '/' (for same-origin matches). ` + `Please see the docs for ${moduleName}.${funcName}() for ` + `more info.`; + }, + 'channel-name-required': () => { + return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`; + }, + 'invalid-responses-are-same-args': () => { + return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`; + }, + 'expire-custom-caches-only': () => { + return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`; + }, + 'unit-must-be-bytes': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`); + } + return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`; + }, + 'single-range-only': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'single-range-only' error.`); + } + return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`; + }, + 'invalid-range-values': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'invalid-range-values' error.`); + } + return `The Range header is missing both start and end values. At least ` + `one of those values is needed. The Range header provided was ` + `"${normalizedRangeHeader}"`; + }, + 'no-range-header': () => { + return `No Range header was found in the Request provided.`; + }, + 'range-not-satisfiable': ({ + size, + start, + end + }) => { + return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`; + }, + 'attempt-to-cache-non-get-request': ({ + url, + method + }) => { + return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`; + }, + 'cache-put-with-no-response': ({ + url + }) => { + return `There was an attempt to cache '${url}' but the response was not ` + `defined.`; + }, + 'no-response': ({ + url, + error + }) => { + let message = `The strategy could not generate a response for '${url}'.`; + if (error) { + message += ` The underlying error is ${error}.`; + } + return message; + }, + 'bad-precaching-response': ({ + url, + status + }) => { + return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`); + }, + 'non-precached-url': ({ + url + }) => { + return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`; + }, + 'add-to-cache-list-conflicting-integrities': ({ + url + }) => { + return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`; + }, + 'missing-precache-entry': ({ + cacheName, + url + }) => { + return `Unable to find a precached response in ${cacheName} for ${url}.`; + }, + 'cross-origin-copy-response': ({ + origin + }) => { + return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`; + }, + 'opaque-streams-source': ({ + type + }) => { + const message = `One of the workbox-streams sources resulted in an ` + `'${type}' response.`; + if (type === 'opaqueredirect') { + return `${message} Please do not use a navigation request that results ` + `in a redirect as a source.`; + } + return `${message} Please ensure your sources are CORS-enabled.`; + } + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const generatorFunction = (code, details = {}) => { + const message = messages[code]; + if (!message) { + throw new Error(`Unable to find message for code '${code}'.`); + } + return message(details); + }; + const messageGenerator = generatorFunction; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Workbox errors should be thrown with this class. + * This allows use to ensure the type easily in tests, + * helps developers identify errors from workbox + * easily and allows use to optimise error + * messages correctly. + * + * @private + */ + class WorkboxError extends Error { + /** + * + * @param {string} errorCode The error code that + * identifies this particular error. + * @param {Object=} details Any relevant arguments + * that will help developers identify issues should + * be added as a key on the context object. + */ + constructor(errorCode, details) { + const message = messageGenerator(errorCode, details); + super(message); + this.name = errorCode; + this.details = details; + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /* + * This method throws if the supplied value is not an array. + * The destructed values are required to produce a meaningful error for users. + * The destructed and restructured object is so it's clear what is + * needed. + */ + const isArray = (value, details) => { + if (!Array.isArray(value)) { + throw new WorkboxError('not-an-array', details); + } + }; + const hasMethod = (object, expectedMethod, details) => { + const type = typeof object[expectedMethod]; + if (type !== 'function') { + details['expectedMethod'] = expectedMethod; + throw new WorkboxError('missing-a-method', details); + } + }; + const isType = (object, expectedType, details) => { + if (typeof object !== expectedType) { + details['expectedType'] = expectedType; + throw new WorkboxError('incorrect-type', details); + } + }; + const isInstance = (object, + // Need the general type to do the check later. + // eslint-disable-next-line @typescript-eslint/ban-types + expectedClass, details) => { + if (!(object instanceof expectedClass)) { + details['expectedClassName'] = expectedClass.name; + throw new WorkboxError('incorrect-class', details); + } + }; + const isOneOf = (value, validValues, details) => { + if (!validValues.includes(value)) { + details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`; + throw new WorkboxError('invalid-value', details); + } + }; + const isArrayOfClass = (value, + // Need general type to do check later. + expectedClass, + // eslint-disable-line + details) => { + const error = new WorkboxError('not-array-of-class', details); + if (!Array.isArray(value)) { + throw error; + } + for (const item of value) { + if (!(item instanceof expectedClass)) { + throw error; + } + } + }; + const finalAssertExports = { + hasMethod, + isArray, + isInstance, + isOneOf, + isType, + isArrayOfClass + }; + + // @ts-ignore + try { + self['workbox:routing:7.2.0'] && _(); + } catch (e) {} + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * The default HTTP method, 'GET', used when there's no specific method + * configured for a route. + * + * @type {string} + * + * @private + */ + const defaultMethod = 'GET'; + /** + * The list of valid HTTP methods associated with requests that could be routed. + * + * @type {Array} + * + * @private + */ + const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT']; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * @param {function()|Object} handler Either a function, or an object with a + * 'handle' method. + * @return {Object} An object with a handle method. + * + * @private + */ + const normalizeHandler = handler => { + if (handler && typeof handler === 'object') { + { + finalAssertExports.hasMethod(handler, 'handle', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'handler' + }); + } + return handler; + } else { + { + finalAssertExports.isType(handler, 'function', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'handler' + }); + } + return { + handle: handler + }; + } + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A `Route` consists of a pair of callback functions, "match" and "handler". + * The "match" callback determine if a route should be used to "handle" a + * request by returning a non-falsy value if it can. The "handler" callback + * is called when there is a match and should return a Promise that resolves + * to a `Response`. + * + * @memberof workbox-routing + */ + class Route { + /** + * Constructor for Route class. + * + * @param {workbox-routing~matchCallback} match + * A callback function that determines whether the route matches a given + * `fetch` event by returning a non-falsy value. + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resolving to a Response. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + */ + constructor(match, handler, method = defaultMethod) { + { + finalAssertExports.isType(match, 'function', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'match' + }); + if (method) { + finalAssertExports.isOneOf(method, validMethods, { + paramName: 'method' + }); + } + } + // These values are referenced directly by Router so cannot be + // altered by minificaton. + this.handler = normalizeHandler(handler); + this.match = match; + this.method = method; + } + /** + * + * @param {workbox-routing-handlerCallback} handler A callback + * function that returns a Promise resolving to a Response + */ + setCatchHandler(handler) { + this.catchHandler = normalizeHandler(handler); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * RegExpRoute makes it easy to create a regular expression based + * {@link workbox-routing.Route}. + * + * For same-origin requests the RegExp only needs to match part of the URL. For + * requests against third-party servers, you must define a RegExp that matches + * the start of the URL. + * + * @memberof workbox-routing + * @extends workbox-routing.Route + */ + class RegExpRoute extends Route { + /** + * If the regular expression contains + * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references}, + * the captured values will be passed to the + * {@link workbox-routing~handlerCallback} `params` + * argument. + * + * @param {RegExp} regExp The regular expression to match against URLs. + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + */ + constructor(regExp, handler, method) { + { + finalAssertExports.isInstance(regExp, RegExp, { + moduleName: 'workbox-routing', + className: 'RegExpRoute', + funcName: 'constructor', + paramName: 'pattern' + }); + } + const match = ({ + url + }) => { + const result = regExp.exec(url.href); + // Return immediately if there's no match. + if (!result) { + return; + } + // Require that the match start at the first character in the URL string + // if it's a cross-origin request. + // See https://github.com/GoogleChrome/workbox/issues/281 for the context + // behind this behavior. + if (url.origin !== location.origin && result.index !== 0) { + { + logger.debug(`The regular expression '${regExp.toString()}' only partially matched ` + `against the cross-origin URL '${url.toString()}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`); + } + return; + } + // If the route matches, but there aren't any capture groups defined, then + // this will return [], which is truthy and therefore sufficient to + // indicate a match. + // If there are capture groups, then it will return their values. + return result.slice(1); + }; + super(match, handler, method); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const getFriendlyURL = url => { + const urlObj = new URL(String(url), location.href); + // See https://github.com/GoogleChrome/workbox/issues/2323 + // We want to include everything, except for the origin if it's same-origin. + return urlObj.href.replace(new RegExp(`^${location.origin}`), ''); + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * The Router can be used to process a `FetchEvent` using one or more + * {@link workbox-routing.Route}, responding with a `Response` if + * a matching route exists. + * + * If no route matches a given a request, the Router will use a "default" + * handler if one is defined. + * + * Should the matching Route throw an error, the Router will use a "catch" + * handler if one is defined to gracefully deal with issues and respond with a + * Request. + * + * If a request matches multiple routes, the **earliest** registered route will + * be used to respond to the request. + * + * @memberof workbox-routing + */ + class Router { + /** + * Initializes a new Router. + */ + constructor() { + this._routes = new Map(); + this._defaultHandlerMap = new Map(); + } + /** + * @return {Map>} routes A `Map` of HTTP + * method name ('GET', etc.) to an array of all the corresponding `Route` + * instances that are registered. + */ + get routes() { + return this._routes; + } + /** + * Adds a fetch event listener to respond to events when a route matches + * the event's request. + */ + addFetchListener() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('fetch', event => { + const { + request + } = event; + const responsePromise = this.handleRequest({ + request, + event + }); + if (responsePromise) { + event.respondWith(responsePromise); + } + }); + } + /** + * Adds a message event listener for URLs to cache from the window. + * This is useful to cache resources loaded on the page prior to when the + * service worker started controlling it. + * + * The format of the message data sent from the window should be as follows. + * Where the `urlsToCache` array may consist of URL strings or an array of + * URL string + `requestInit` object (the same as you'd pass to `fetch()`). + * + * ``` + * { + * type: 'CACHE_URLS', + * payload: { + * urlsToCache: [ + * './script1.js', + * './script2.js', + * ['./script3.js', {mode: 'no-cors'}], + * ], + * }, + * } + * ``` + */ + addCacheListener() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('message', event => { + // event.data is type 'any' + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (event.data && event.data.type === 'CACHE_URLS') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { + payload + } = event.data; + { + logger.debug(`Caching URLs from the window`, payload.urlsToCache); + } + const requestPromises = Promise.all(payload.urlsToCache.map(entry => { + if (typeof entry === 'string') { + entry = [entry]; + } + const request = new Request(...entry); + return this.handleRequest({ + request, + event + }); + // TODO(philipwalton): TypeScript errors without this typecast for + // some reason (probably a bug). The real type here should work but + // doesn't: `Array | undefined>`. + })); // TypeScript + event.waitUntil(requestPromises); + // If a MessageChannel was used, reply to the message on success. + if (event.ports && event.ports[0]) { + void requestPromises.then(() => event.ports[0].postMessage(true)); + } + } + }); + } + /** + * Apply the routing rules to a FetchEvent object to get a Response from an + * appropriate Route's handler. + * + * @param {Object} options + * @param {Request} options.request The request to handle. + * @param {ExtendableEvent} options.event The event that triggered the + * request. + * @return {Promise|undefined} A promise is returned if a + * registered route can handle the request. If there is no matching + * route and there's no `defaultHandler`, `undefined` is returned. + */ + handleRequest({ + request, + event + }) { + { + finalAssertExports.isInstance(request, Request, { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'handleRequest', + paramName: 'options.request' + }); + } + const url = new URL(request.url, location.href); + if (!url.protocol.startsWith('http')) { + { + logger.debug(`Workbox Router only supports URLs that start with 'http'.`); + } + return; + } + const sameOrigin = url.origin === location.origin; + const { + params, + route + } = this.findMatchingRoute({ + event, + request, + sameOrigin, + url + }); + let handler = route && route.handler; + const debugMessages = []; + { + if (handler) { + debugMessages.push([`Found a route to handle this request:`, route]); + if (params) { + debugMessages.push([`Passing the following params to the route's handler:`, params]); + } + } + } + // If we don't have a handler because there was no matching route, then + // fall back to defaultHandler if that's defined. + const method = request.method; + if (!handler && this._defaultHandlerMap.has(method)) { + { + debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`); + } + handler = this._defaultHandlerMap.get(method); + } + if (!handler) { + { + // No handler so Workbox will do nothing. If logs is set of debug + // i.e. verbose, we should print out this information. + logger.debug(`No route found for: ${getFriendlyURL(url)}`); + } + return; + } + { + // We have a handler, meaning Workbox is going to handle the route. + // print the routing details to the console. + logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`); + debugMessages.forEach(msg => { + if (Array.isArray(msg)) { + logger.log(...msg); + } else { + logger.log(msg); + } + }); + logger.groupEnd(); + } + // Wrap in try and catch in case the handle method throws a synchronous + // error. It should still callback to the catch handler. + let responsePromise; + try { + responsePromise = handler.handle({ + url, + request, + event, + params + }); + } catch (err) { + responsePromise = Promise.reject(err); + } + // Get route's catch handler, if it exists + const catchHandler = route && route.catchHandler; + if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) { + responsePromise = responsePromise.catch(async err => { + // If there's a route catch handler, process that first + if (catchHandler) { + { + // Still include URL here as it will be async from the console group + // and may not make sense without the URL + logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`); + logger.error(`Error thrown by:`, route); + logger.error(err); + logger.groupEnd(); + } + try { + return await catchHandler.handle({ + url, + request, + event, + params + }); + } catch (catchErr) { + if (catchErr instanceof Error) { + err = catchErr; + } + } + } + if (this._catchHandler) { + { + // Still include URL here as it will be async from the console group + // and may not make sense without the URL + logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`); + logger.error(`Error thrown by:`, route); + logger.error(err); + logger.groupEnd(); + } + return this._catchHandler.handle({ + url, + request, + event + }); + } + throw err; + }); + } + return responsePromise; + } + /** + * Checks a request and URL (and optionally an event) against the list of + * registered routes, and if there's a match, returns the corresponding + * route along with any params generated by the match. + * + * @param {Object} options + * @param {URL} options.url + * @param {boolean} options.sameOrigin The result of comparing `url.origin` + * against the current origin. + * @param {Request} options.request The request to match. + * @param {Event} options.event The corresponding event. + * @return {Object} An object with `route` and `params` properties. + * They are populated if a matching route was found or `undefined` + * otherwise. + */ + findMatchingRoute({ + url, + sameOrigin, + request, + event + }) { + const routes = this._routes.get(request.method) || []; + for (const route of routes) { + let params; + // route.match returns type any, not possible to change right now. + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const matchResult = route.match({ + url, + sameOrigin, + request, + event + }); + if (matchResult) { + { + // Warn developers that using an async matchCallback is almost always + // not the right thing to do. + if (matchResult instanceof Promise) { + logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route); + } + } + // See https://github.com/GoogleChrome/workbox/issues/2079 + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + params = matchResult; + if (Array.isArray(params) && params.length === 0) { + // Instead of passing an empty array in as params, use undefined. + params = undefined; + } else if (matchResult.constructor === Object && + // eslint-disable-line + Object.keys(matchResult).length === 0) { + // Instead of passing an empty object in as params, use undefined. + params = undefined; + } else if (typeof matchResult === 'boolean') { + // For the boolean value true (rather than just something truth-y), + // don't set params. + // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353 + params = undefined; + } + // Return early if have a match. + return { + route, + params + }; + } + } + // If no match was found above, return and empty object. + return {}; + } + /** + * Define a default `handler` that's called when no routes explicitly + * match the incoming request. + * + * Each HTTP method ('GET', 'POST', etc.) gets its own default handler. + * + * Without a default handler, unmatched requests will go against the + * network as if there were no service worker present. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {string} [method='GET'] The HTTP method to associate with this + * default handler. Each method has its own default. + */ + setDefaultHandler(handler, method = defaultMethod) { + this._defaultHandlerMap.set(method, normalizeHandler(handler)); + } + /** + * If a Route throws an error while handling a request, this `handler` + * will be called and given a chance to provide a response. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + */ + setCatchHandler(handler) { + this._catchHandler = normalizeHandler(handler); + } + /** + * Registers a route with the router. + * + * @param {workbox-routing.Route} route The route to register. + */ + registerRoute(route) { + { + finalAssertExports.isType(route, 'object', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.hasMethod(route, 'match', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.isType(route.handler, 'object', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.hasMethod(route.handler, 'handle', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route.handler' + }); + finalAssertExports.isType(route.method, 'string', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route.method' + }); + } + if (!this._routes.has(route.method)) { + this._routes.set(route.method, []); + } + // Give precedence to all of the earlier routes by adding this additional + // route to the end of the array. + this._routes.get(route.method).push(route); + } + /** + * Unregisters a route with the router. + * + * @param {workbox-routing.Route} route The route to unregister. + */ + unregisterRoute(route) { + if (!this._routes.has(route.method)) { + throw new WorkboxError('unregister-route-but-not-found-with-method', { + method: route.method + }); + } + const routeIndex = this._routes.get(route.method).indexOf(route); + if (routeIndex > -1) { + this._routes.get(route.method).splice(routeIndex, 1); + } else { + throw new WorkboxError('unregister-route-route-not-registered'); + } + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + let defaultRouter; + /** + * Creates a new, singleton Router instance if one does not exist. If one + * does already exist, that instance is returned. + * + * @private + * @return {Router} + */ + const getOrCreateDefaultRouter = () => { + if (!defaultRouter) { + defaultRouter = new Router(); + // The helpers that use the default Router assume these listeners exist. + defaultRouter.addFetchListener(); + defaultRouter.addCacheListener(); + } + return defaultRouter; + }; + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Easily register a RegExp, string, or function with a caching + * strategy to a singleton Router instance. + * + * This method will generate a Route for you if needed and + * call {@link workbox-routing.Router#registerRoute}. + * + * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture + * If the capture param is a `Route`, all other arguments will be ignored. + * @param {workbox-routing~handlerCallback} [handler] A callback + * function that returns a Promise resulting in a Response. This parameter + * is required if `capture` is not a `Route` object. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + * @return {workbox-routing.Route} The generated `Route`. + * + * @memberof workbox-routing + */ + function registerRoute(capture, handler, method) { + let route; + if (typeof capture === 'string') { + const captureUrl = new URL(capture, location.href); + { + if (!(capture.startsWith('/') || capture.startsWith('http'))) { + throw new WorkboxError('invalid-string', { + moduleName: 'workbox-routing', + funcName: 'registerRoute', + paramName: 'capture' + }); + } + // We want to check if Express-style wildcards are in the pathname only. + // TODO: Remove this log message in v4. + const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; + // See https://github.com/pillarjs/path-to-regexp#parameters + const wildcards = '[*:?+]'; + if (new RegExp(`${wildcards}`).exec(valueToCheck)) { + logger.debug(`The '$capture' parameter contains an Express-style wildcard ` + `character (${wildcards}). Strings are now always interpreted as ` + `exact matches; use a RegExp for partial or wildcard matches.`); + } + } + const matchCallback = ({ + url + }) => { + { + if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) { + logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url.toString()}. This route will only handle cross-origin requests ` + `if they match the entire URL.`); + } + } + return url.href === captureUrl.href; + }; + // If `capture` is a string then `handler` and `method` must be present. + route = new Route(matchCallback, handler, method); + } else if (capture instanceof RegExp) { + // If `capture` is a `RegExp` then `handler` and `method` must be present. + route = new RegExpRoute(capture, handler, method); + } else if (typeof capture === 'function') { + // If `capture` is a function then `handler` and `method` must be present. + route = new Route(capture, handler, method); + } else if (capture instanceof Route) { + route = capture; + } else { + throw new WorkboxError('unsupported-route-type', { + moduleName: 'workbox-routing', + funcName: 'registerRoute', + paramName: 'capture' + }); + } + const defaultRouter = getOrCreateDefaultRouter(); + defaultRouter.registerRoute(route); + return route; + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const _cacheNameDetails = { + googleAnalytics: 'googleAnalytics', + precache: 'precache-v2', + prefix: 'workbox', + runtime: 'runtime', + suffix: typeof registration !== 'undefined' ? registration.scope : '' + }; + const _createCacheName = cacheName => { + return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-'); + }; + const eachCacheNameDetail = fn => { + for (const key of Object.keys(_cacheNameDetails)) { + fn(key); + } + }; + const cacheNames = { + updateDetails: details => { + eachCacheNameDetail(key => { + if (typeof details[key] === 'string') { + _cacheNameDetails[key] = details[key]; + } + }); + }, + getGoogleAnalyticsName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics); + }, + getPrecacheName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.precache); + }, + getPrefix: () => { + return _cacheNameDetails.prefix; + }, + getRuntimeName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.runtime); + }, + getSuffix: () => { + return _cacheNameDetails.suffix; + } + }; + + /* + Copyright 2020 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A utility method that makes it easier to use `event.waitUntil` with + * async functions and return the result. + * + * @param {ExtendableEvent} event + * @param {Function} asyncFn + * @return {Function} + * @private + */ + function waitUntil(event, asyncFn) { + const returnPromise = asyncFn(); + event.waitUntil(returnPromise); + return returnPromise; + } + + // @ts-ignore + try { + self['workbox:precaching:7.2.0'] && _(); + } catch (e) {} + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + // Name of the search parameter used to store revision info. + const REVISION_SEARCH_PARAM = '__WB_REVISION__'; + /** + * Converts a manifest entry into a versioned URL suitable for precaching. + * + * @param {Object|string} entry + * @return {string} A URL with versioning info. + * + * @private + * @memberof workbox-precaching + */ + function createCacheKey(entry) { + if (!entry) { + throw new WorkboxError('add-to-cache-list-unexpected-type', { + entry + }); + } + // If a precache manifest entry is a string, it's assumed to be a versioned + // URL, like '/app.abcd1234.js'. Return as-is. + if (typeof entry === 'string') { + const urlObject = new URL(entry, location.href); + return { + cacheKey: urlObject.href, + url: urlObject.href + }; + } + const { + revision, + url + } = entry; + if (!url) { + throw new WorkboxError('add-to-cache-list-unexpected-type', { + entry + }); + } + // If there's just a URL and no revision, then it's also assumed to be a + // versioned URL. + if (!revision) { + const urlObject = new URL(url, location.href); + return { + cacheKey: urlObject.href, + url: urlObject.href + }; + } + // Otherwise, construct a properly versioned URL using the custom Workbox + // search parameter along with the revision info. + const cacheKeyURL = new URL(url, location.href); + const originalURL = new URL(url, location.href); + cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision); + return { + cacheKey: cacheKeyURL.href, + url: originalURL.href + }; + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A plugin, designed to be used with PrecacheController, to determine the + * of assets that were updated (or not updated) during the install event. + * + * @private + */ + class PrecacheInstallReportPlugin { + constructor() { + this.updatedURLs = []; + this.notUpdatedURLs = []; + this.handlerWillStart = async ({ + request, + state + }) => { + // TODO: `state` should never be undefined... + if (state) { + state.originalRequest = request; + } + }; + this.cachedResponseWillBeUsed = async ({ + event, + state, + cachedResponse + }) => { + if (event.type === 'install') { + if (state && state.originalRequest && state.originalRequest instanceof Request) { + // TODO: `state` should never be undefined... + const url = state.originalRequest.url; + if (cachedResponse) { + this.notUpdatedURLs.push(url); + } else { + this.updatedURLs.push(url); + } + } + } + return cachedResponse; + }; + } + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A plugin, designed to be used with PrecacheController, to translate URLs into + * the corresponding cache key, based on the current revision info. + * + * @private + */ + class PrecacheCacheKeyPlugin { + constructor({ + precacheController + }) { + this.cacheKeyWillBeUsed = async ({ + request, + params + }) => { + // Params is type any, can't change right now. + /* eslint-disable */ + const cacheKey = (params === null || params === void 0 ? void 0 : params.cacheKey) || this._precacheController.getCacheKeyForURL(request.url); + /* eslint-enable */ + return cacheKey ? new Request(cacheKey, { + headers: request.headers + }) : request; + }; + this._precacheController = precacheController; + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * @param {string} groupTitle + * @param {Array} deletedURLs + * + * @private + */ + const logGroup = (groupTitle, deletedURLs) => { + logger.groupCollapsed(groupTitle); + for (const url of deletedURLs) { + logger.log(url); + } + logger.groupEnd(); + }; + /** + * @param {Array} deletedURLs + * + * @private + * @memberof workbox-precaching + */ + function printCleanupDetails(deletedURLs) { + const deletionCount = deletedURLs.length; + if (deletionCount > 0) { + logger.groupCollapsed(`During precaching cleanup, ` + `${deletionCount} cached ` + `request${deletionCount === 1 ? ' was' : 's were'} deleted.`); + logGroup('Deleted Cache Requests', deletedURLs); + logger.groupEnd(); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * @param {string} groupTitle + * @param {Array} urls + * + * @private + */ + function _nestedGroup(groupTitle, urls) { + if (urls.length === 0) { + return; + } + logger.groupCollapsed(groupTitle); + for (const url of urls) { + logger.log(url); + } + logger.groupEnd(); + } + /** + * @param {Array} urlsToPrecache + * @param {Array} urlsAlreadyPrecached + * + * @private + * @memberof workbox-precaching + */ + function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) { + const precachedCount = urlsToPrecache.length; + const alreadyPrecachedCount = urlsAlreadyPrecached.length; + if (precachedCount || alreadyPrecachedCount) { + let message = `Precaching ${precachedCount} file${precachedCount === 1 ? '' : 's'}.`; + if (alreadyPrecachedCount > 0) { + message += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? ' is' : 's are'} already cached.`; + } + logger.groupCollapsed(message); + _nestedGroup(`View newly precached URLs.`, urlsToPrecache); + _nestedGroup(`View previously precached URLs.`, urlsAlreadyPrecached); + logger.groupEnd(); + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + let supportStatus; + /** + * A utility function that determines whether the current browser supports + * constructing a new `Response` from a `response.body` stream. + * + * @return {boolean} `true`, if the current browser can successfully + * construct a `Response` from a `response.body` stream, `false` otherwise. + * + * @private + */ + function canConstructResponseFromBodyStream() { + if (supportStatus === undefined) { + const testResponse = new Response(''); + if ('body' in testResponse) { + try { + new Response(testResponse.body); + supportStatus = true; + } catch (error) { + supportStatus = false; + } + } + supportStatus = false; + } + return supportStatus; + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Allows developers to copy a response and modify its `headers`, `status`, + * or `statusText` values (the values settable via a + * [`ResponseInit`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Response/Response#Syntax} + * object in the constructor). + * To modify these values, pass a function as the second argument. That + * function will be invoked with a single object with the response properties + * `{headers, status, statusText}`. The return value of this function will + * be used as the `ResponseInit` for the new `Response`. To change the values + * either modify the passed parameter(s) and return it, or return a totally + * new object. + * + * This method is intentionally limited to same-origin responses, regardless of + * whether CORS was used or not. + * + * @param {Response} response + * @param {Function} modifier + * @memberof workbox-core + */ + async function copyResponse(response, modifier) { + let origin = null; + // If response.url isn't set, assume it's cross-origin and keep origin null. + if (response.url) { + const responseURL = new URL(response.url); + origin = responseURL.origin; + } + if (origin !== self.location.origin) { + throw new WorkboxError('cross-origin-copy-response', { + origin + }); + } + const clonedResponse = response.clone(); + // Create a fresh `ResponseInit` object by cloning the headers. + const responseInit = { + headers: new Headers(clonedResponse.headers), + status: clonedResponse.status, + statusText: clonedResponse.statusText + }; + // Apply any user modifications. + const modifiedResponseInit = modifier ? modifier(responseInit) : responseInit; + // Create the new response from the body stream and `ResponseInit` + // modifications. Note: not all browsers support the Response.body stream, + // so fall back to reading the entire body into memory as a blob. + const body = canConstructResponseFromBodyStream() ? clonedResponse.body : await clonedResponse.blob(); + return new Response(body, modifiedResponseInit); + } + + /* + Copyright 2020 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + function stripParams(fullURL, ignoreParams) { + const strippedURL = new URL(fullURL); + for (const param of ignoreParams) { + strippedURL.searchParams.delete(param); + } + return strippedURL.href; + } + /** + * Matches an item in the cache, ignoring specific URL params. This is similar + * to the `ignoreSearch` option, but it allows you to ignore just specific + * params (while continuing to match on the others). + * + * @private + * @param {Cache} cache + * @param {Request} request + * @param {Object} matchOptions + * @param {Array} ignoreParams + * @return {Promise} + */ + async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) { + const strippedRequestURL = stripParams(request.url, ignoreParams); + // If the request doesn't include any ignored params, match as normal. + if (request.url === strippedRequestURL) { + return cache.match(request, matchOptions); + } + // Otherwise, match by comparing keys + const keysOptions = Object.assign(Object.assign({}, matchOptions), { + ignoreSearch: true + }); + const cacheKeys = await cache.keys(request, keysOptions); + for (const cacheKey of cacheKeys) { + const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams); + if (strippedRequestURL === strippedCacheKeyURL) { + return cache.match(cacheKey, matchOptions); + } + } + return; + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * The Deferred class composes Promises in a way that allows for them to be + * resolved or rejected from outside the constructor. In most cases promises + * should be used directly, but Deferreds can be necessary when the logic to + * resolve a promise must be separate. + * + * @private + */ + class Deferred { + /** + * Creates a promise and exposes its resolve and reject functions as methods. + */ + constructor() { + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + }); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + // Callbacks to be executed whenever there's a quota error. + // Can't change Function type right now. + // eslint-disable-next-line @typescript-eslint/ban-types + const quotaErrorCallbacks = new Set(); + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Runs all of the callback functions, one at a time sequentially, in the order + * in which they were registered. + * + * @memberof workbox-core + * @private + */ + async function executeQuotaErrorCallbacks() { + { + logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`); + } + for (const callback of quotaErrorCallbacks) { + await callback(); + { + logger.log(callback, 'is complete.'); + } + } + { + logger.log('Finished running callbacks.'); + } + } + + /* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Returns a promise that resolves and the passed number of milliseconds. + * This utility is an async/await-friendly version of `setTimeout`. + * + * @param {number} ms + * @return {Promise} + * @private + */ + function timeout(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + // @ts-ignore + try { + self['workbox:strategies:7.2.0'] && _(); + } catch (e) {} + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + function toRequest(input) { + return typeof input === 'string' ? new Request(input) : input; + } + /** + * A class created every time a Strategy instance instance calls + * {@link workbox-strategies.Strategy~handle} or + * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and + * cache actions around plugin callbacks and keeps track of when the strategy + * is "done" (i.e. all added `event.waitUntil()` promises have resolved). + * + * @memberof workbox-strategies + */ + class StrategyHandler { + /** + * Creates a new instance associated with the passed strategy and event + * that's handling the request. + * + * The constructor also initializes the state that will be passed to each of + * the plugins handling this request. + * + * @param {workbox-strategies.Strategy} strategy + * @param {Object} options + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] The return value from the + * {@link workbox-routing~matchCallback} (if applicable). + */ + constructor(strategy, options) { + this._cacheKeys = {}; + /** + * The request the strategy is performing (passed to the strategy's + * `handle()` or `handleAll()` method). + * @name request + * @instance + * @type {Request} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * The event associated with this request. + * @name event + * @instance + * @type {ExtendableEvent} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * A `URL` instance of `request.url` (if passed to the strategy's + * `handle()` or `handleAll()` method). + * Note: the `url` param will be present if the strategy was invoked + * from a workbox `Route` object. + * @name url + * @instance + * @type {URL|undefined} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * A `param` value (if passed to the strategy's + * `handle()` or `handleAll()` method). + * Note: the `param` param will be present if the strategy was invoked + * from a workbox `Route` object and the + * {@link workbox-routing~matchCallback} returned + * a truthy value (it will be that value). + * @name params + * @instance + * @type {*|undefined} + * @memberof workbox-strategies.StrategyHandler + */ + { + finalAssertExports.isInstance(options.event, ExtendableEvent, { + moduleName: 'workbox-strategies', + className: 'StrategyHandler', + funcName: 'constructor', + paramName: 'options.event' + }); + } + Object.assign(this, options); + this.event = options.event; + this._strategy = strategy; + this._handlerDeferred = new Deferred(); + this._extendLifetimePromises = []; + // Copy the plugins list (since it's mutable on the strategy), + // so any mutations don't affect this handler instance. + this._plugins = [...strategy.plugins]; + this._pluginStateMap = new Map(); + for (const plugin of this._plugins) { + this._pluginStateMap.set(plugin, {}); + } + this.event.waitUntil(this._handlerDeferred.promise); + } + /** + * Fetches a given request (and invokes any applicable plugin callback + * methods) using the `fetchOptions` (for non-navigation requests) and + * `plugins` defined on the `Strategy` object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - `requestWillFetch()` + * - `fetchDidSucceed()` + * - `fetchDidFail()` + * + * @param {Request|string} input The URL or request to fetch. + * @return {Promise} + */ + async fetch(input) { + const { + event + } = this; + let request = toRequest(input); + if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) { + const possiblePreloadResponse = await event.preloadResponse; + if (possiblePreloadResponse) { + { + logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`); + } + return possiblePreloadResponse; + } + } + // If there is a fetchDidFail plugin, we need to save a clone of the + // original request before it's either modified by a requestWillFetch + // plugin or before the original request's body is consumed via fetch(). + const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null; + try { + for (const cb of this.iterateCallbacks('requestWillFetch')) { + request = await cb({ + request: request.clone(), + event + }); + } + } catch (err) { + if (err instanceof Error) { + throw new WorkboxError('plugin-error-request-will-fetch', { + thrownErrorMessage: err.message + }); + } + } + // The request can be altered by plugins with `requestWillFetch` making + // the original request (most likely from a `fetch` event) different + // from the Request we make. Pass both to `fetchDidFail` to aid debugging. + const pluginFilteredRequest = request.clone(); + try { + let fetchResponse; + // See https://github.com/GoogleChrome/workbox/issues/1796 + fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions); + if ("development" !== 'production') { + logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`); + } + for (const callback of this.iterateCallbacks('fetchDidSucceed')) { + fetchResponse = await callback({ + event, + request: pluginFilteredRequest, + response: fetchResponse + }); + } + return fetchResponse; + } catch (error) { + { + logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error); + } + // `originalRequest` will only exist if a `fetchDidFail` callback + // is being used (see above). + if (originalRequest) { + await this.runCallbacks('fetchDidFail', { + error: error, + event, + originalRequest: originalRequest.clone(), + request: pluginFilteredRequest.clone() + }); + } + throw error; + } + } + /** + * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on + * the response generated by `this.fetch()`. + * + * The call to `this.cachePut()` automatically invokes `this.waitUntil()`, + * so you do not have to manually call `waitUntil()` on the event. + * + * @param {Request|string} input The request or URL to fetch and cache. + * @return {Promise} + */ + async fetchAndCachePut(input) { + const response = await this.fetch(input); + const responseClone = response.clone(); + void this.waitUntil(this.cachePut(input, responseClone)); + return response; + } + /** + * Matches a request from the cache (and invokes any applicable plugin + * callback methods) using the `cacheName`, `matchOptions`, and `plugins` + * defined on the strategy object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - cacheKeyWillBeUsed() + * - cachedResponseWillBeUsed() + * + * @param {Request|string} key The Request or URL to use as the cache key. + * @return {Promise} A matching response, if found. + */ + async cacheMatch(key) { + const request = toRequest(key); + let cachedResponse; + const { + cacheName, + matchOptions + } = this._strategy; + const effectiveRequest = await this.getCacheKey(request, 'read'); + const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), { + cacheName + }); + cachedResponse = await caches.match(effectiveRequest, multiMatchOptions); + { + if (cachedResponse) { + logger.debug(`Found a cached response in '${cacheName}'.`); + } else { + logger.debug(`No cached response found in '${cacheName}'.`); + } + } + for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) { + cachedResponse = (await callback({ + cacheName, + matchOptions, + cachedResponse, + request: effectiveRequest, + event: this.event + })) || undefined; + } + return cachedResponse; + } + /** + * Puts a request/response pair in the cache (and invokes any applicable + * plugin callback methods) using the `cacheName` and `plugins` defined on + * the strategy object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - cacheKeyWillBeUsed() + * - cacheWillUpdate() + * - cacheDidUpdate() + * + * @param {Request|string} key The request or URL to use as the cache key. + * @param {Response} response The response to cache. + * @return {Promise} `false` if a cacheWillUpdate caused the response + * not be cached, and `true` otherwise. + */ + async cachePut(key, response) { + const request = toRequest(key); + // Run in the next task to avoid blocking other cache reads. + // https://github.com/w3c/ServiceWorker/issues/1397 + await timeout(0); + const effectiveRequest = await this.getCacheKey(request, 'write'); + { + if (effectiveRequest.method && effectiveRequest.method !== 'GET') { + throw new WorkboxError('attempt-to-cache-non-get-request', { + url: getFriendlyURL(effectiveRequest.url), + method: effectiveRequest.method + }); + } + // See https://github.com/GoogleChrome/workbox/issues/2818 + const vary = response.headers.get('Vary'); + if (vary) { + logger.debug(`The response for ${getFriendlyURL(effectiveRequest.url)} ` + `has a 'Vary: ${vary}' header. ` + `Consider setting the {ignoreVary: true} option on your strategy ` + `to ensure cache matching and deletion works as expected.`); + } + } + if (!response) { + { + logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`); + } + throw new WorkboxError('cache-put-with-no-response', { + url: getFriendlyURL(effectiveRequest.url) + }); + } + const responseToCache = await this._ensureResponseSafeToCache(response); + if (!responseToCache) { + { + logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache); + } + return false; + } + const { + cacheName, + matchOptions + } = this._strategy; + const cache = await self.caches.open(cacheName); + const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate'); + const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams( + // TODO(philipwalton): the `__WB_REVISION__` param is a precaching + // feature. Consider into ways to only add this behavior if using + // precaching. + cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null; + { + logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`); + } + try { + await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache); + } catch (error) { + if (error instanceof Error) { + // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError + if (error.name === 'QuotaExceededError') { + await executeQuotaErrorCallbacks(); + } + throw error; + } + } + for (const callback of this.iterateCallbacks('cacheDidUpdate')) { + await callback({ + cacheName, + oldResponse, + newResponse: responseToCache.clone(), + request: effectiveRequest, + event: this.event + }); + } + return true; + } + /** + * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and + * executes any of those callbacks found in sequence. The final `Request` + * object returned by the last plugin is treated as the cache key for cache + * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have + * been registered, the passed request is returned unmodified + * + * @param {Request} request + * @param {string} mode + * @return {Promise} + */ + async getCacheKey(request, mode) { + const key = `${request.url} | ${mode}`; + if (!this._cacheKeys[key]) { + let effectiveRequest = request; + for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) { + effectiveRequest = toRequest(await callback({ + mode, + request: effectiveRequest, + event: this.event, + // params has a type any can't change right now. + params: this.params // eslint-disable-line + })); + } + this._cacheKeys[key] = effectiveRequest; + } + return this._cacheKeys[key]; + } + /** + * Returns true if the strategy has at least one plugin with the given + * callback. + * + * @param {string} name The name of the callback to check for. + * @return {boolean} + */ + hasCallback(name) { + for (const plugin of this._strategy.plugins) { + if (name in plugin) { + return true; + } + } + return false; + } + /** + * Runs all plugin callbacks matching the given name, in order, passing the + * given param object (merged ith the current plugin state) as the only + * argument. + * + * Note: since this method runs all plugins, it's not suitable for cases + * where the return value of a callback needs to be applied prior to calling + * the next callback. See + * {@link workbox-strategies.StrategyHandler#iterateCallbacks} + * below for how to handle that case. + * + * @param {string} name The name of the callback to run within each plugin. + * @param {Object} param The object to pass as the first (and only) param + * when executing each callback. This object will be merged with the + * current plugin state prior to callback execution. + */ + async runCallbacks(name, param) { + for (const callback of this.iterateCallbacks(name)) { + // TODO(philipwalton): not sure why `any` is needed. It seems like + // this should work with `as WorkboxPluginCallbackParam[C]`. + await callback(param); + } + } + /** + * Accepts a callback and returns an iterable of matching plugin callbacks, + * where each callback is wrapped with the current handler state (i.e. when + * you call each callback, whatever object parameter you pass it will + * be merged with the plugin's current state). + * + * @param {string} name The name fo the callback to run + * @return {Array} + */ + *iterateCallbacks(name) { + for (const plugin of this._strategy.plugins) { + if (typeof plugin[name] === 'function') { + const state = this._pluginStateMap.get(plugin); + const statefulCallback = param => { + const statefulParam = Object.assign(Object.assign({}, param), { + state + }); + // TODO(philipwalton): not sure why `any` is needed. It seems like + // this should work with `as WorkboxPluginCallbackParam[C]`. + return plugin[name](statefulParam); + }; + yield statefulCallback; + } + } + } + /** + * Adds a promise to the + * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises} + * of the event event associated with the request being handled (usually a + * `FetchEvent`). + * + * Note: you can await + * {@link workbox-strategies.StrategyHandler~doneWaiting} + * to know when all added promises have settled. + * + * @param {Promise} promise A promise to add to the extend lifetime promises + * of the event that triggered the request. + */ + waitUntil(promise) { + this._extendLifetimePromises.push(promise); + return promise; + } + /** + * Returns a promise that resolves once all promises passed to + * {@link workbox-strategies.StrategyHandler~waitUntil} + * have settled. + * + * Note: any work done after `doneWaiting()` settles should be manually + * passed to an event's `waitUntil()` method (not this handler's + * `waitUntil()` method), otherwise the service worker thread my be killed + * prior to your work completing. + */ + async doneWaiting() { + let promise; + while (promise = this._extendLifetimePromises.shift()) { + await promise; + } + } + /** + * Stops running the strategy and immediately resolves any pending + * `waitUntil()` promises. + */ + destroy() { + this._handlerDeferred.resolve(null); + } + /** + * This method will call cacheWillUpdate on the available plugins (or use + * status === 200) to determine if the Response is safe and valid to cache. + * + * @param {Request} options.request + * @param {Response} options.response + * @return {Promise} + * + * @private + */ + async _ensureResponseSafeToCache(response) { + let responseToCache = response; + let pluginsUsed = false; + for (const callback of this.iterateCallbacks('cacheWillUpdate')) { + responseToCache = (await callback({ + request: this.request, + response: responseToCache, + event: this.event + })) || undefined; + pluginsUsed = true; + if (!responseToCache) { + break; + } + } + if (!pluginsUsed) { + if (responseToCache && responseToCache.status !== 200) { + responseToCache = undefined; + } + { + if (responseToCache) { + if (responseToCache.status !== 200) { + if (responseToCache.status === 0) { + logger.warn(`The response for '${this.request.url}' ` + `is an opaque response. The caching strategy that you're ` + `using will not cache opaque responses by default.`); + } else { + logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`); + } + } + } + } + } + return responseToCache; + } + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * An abstract base class that all other strategy classes must extend from: + * + * @memberof workbox-strategies + */ + class Strategy { + /** + * Creates a new instance of the strategy and sets all documented option + * properties as public instance properties. + * + * Note: if a custom strategy class extends the base Strategy class and does + * not need more than these properties, it does not need to define its own + * constructor. + * + * @param {Object} [options] + * @param {string} [options.cacheName] Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * to use in conjunction with this caching strategy. + * @param {Object} [options.fetchOptions] Values passed along to the + * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) + * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) + * `fetch()` requests made by this strategy. + * @param {Object} [options.matchOptions] The + * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + */ + constructor(options = {}) { + /** + * Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * + * @type {string} + */ + this.cacheName = cacheNames.getRuntimeName(options.cacheName); + /** + * The list + * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * used by this strategy. + * + * @type {Array} + */ + this.plugins = options.plugins || []; + /** + * Values passed along to the + * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters} + * of all fetch() requests made by this strategy. + * + * @type {Object} + */ + this.fetchOptions = options.fetchOptions; + /** + * The + * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + * + * @type {Object} + */ + this.matchOptions = options.matchOptions; + } + /** + * Perform a request strategy and returns a `Promise` that will resolve with + * a `Response`, invoking all relevant plugin callbacks. + * + * When a strategy instance is registered with a Workbox + * {@link workbox-routing.Route}, this method is automatically + * called when the route matches. + * + * Alternatively, this method can be used in a standalone `FetchEvent` + * listener by passing it to `event.respondWith()`. + * + * @param {FetchEvent|Object} options A `FetchEvent` or an object with the + * properties listed below. + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] + */ + handle(options) { + const [responseDone] = this.handleAll(options); + return responseDone; + } + /** + * Similar to {@link workbox-strategies.Strategy~handle}, but + * instead of just returning a `Promise` that resolves to a `Response` it + * it will return an tuple of `[response, done]` promises, where the former + * (`response`) is equivalent to what `handle()` returns, and the latter is a + * Promise that will resolve once any promises that were added to + * `event.waitUntil()` as part of performing the strategy have completed. + * + * You can await the `done` promise to ensure any extra work performed by + * the strategy (usually caching responses) completes successfully. + * + * @param {FetchEvent|Object} options A `FetchEvent` or an object with the + * properties listed below. + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] + * @return {Array} A tuple of [response, done] + * promises that can be used to determine when the response resolves as + * well as when the handler has completed all its work. + */ + handleAll(options) { + // Allow for flexible options to be passed. + if (options instanceof FetchEvent) { + options = { + event: options, + request: options.request + }; + } + const event = options.event; + const request = typeof options.request === 'string' ? new Request(options.request) : options.request; + const params = 'params' in options ? options.params : undefined; + const handler = new StrategyHandler(this, { + event, + request, + params + }); + const responseDone = this._getResponse(handler, request, event); + const handlerDone = this._awaitComplete(responseDone, handler, request, event); + // Return an array of promises, suitable for use with Promise.all(). + return [responseDone, handlerDone]; + } + async _getResponse(handler, request, event) { + await handler.runCallbacks('handlerWillStart', { + event, + request + }); + let response = undefined; + try { + response = await this._handle(request, handler); + // The "official" Strategy subclasses all throw this error automatically, + // but in case a third-party Strategy doesn't, ensure that we have a + // consistent failure when there's no response or an error response. + if (!response || response.type === 'error') { + throw new WorkboxError('no-response', { + url: request.url + }); + } + } catch (error) { + if (error instanceof Error) { + for (const callback of handler.iterateCallbacks('handlerDidError')) { + response = await callback({ + error, + event, + request + }); + if (response) { + break; + } + } + } + if (!response) { + throw error; + } else { + logger.log(`While responding to '${getFriendlyURL(request.url)}', ` + `an ${error instanceof Error ? error.toString() : ''} error occurred. Using a fallback response provided by ` + `a handlerDidError plugin.`); + } + } + for (const callback of handler.iterateCallbacks('handlerWillRespond')) { + response = await callback({ + event, + request, + response + }); + } + return response; + } + async _awaitComplete(responseDone, handler, request, event) { + let response; + let error; + try { + response = await responseDone; + } catch (error) { + // Ignore errors, as response errors should be caught via the `response` + // promise above. The `done` promise will only throw for errors in + // promises passed to `handler.waitUntil()`. + } + try { + await handler.runCallbacks('handlerDidRespond', { + event, + request, + response + }); + await handler.doneWaiting(); + } catch (waitUntilError) { + if (waitUntilError instanceof Error) { + error = waitUntilError; + } + } + await handler.runCallbacks('handlerDidComplete', { + event, + request, + response, + error: error + }); + handler.destroy(); + if (error) { + throw error; + } + } + } + /** + * Classes extending the `Strategy` based class should implement this method, + * and leverage the {@link workbox-strategies.StrategyHandler} + * arg to perform all fetching and cache logic, which will ensure all relevant + * cache, cache options, fetch options and plugins are used (per the current + * strategy instance). + * + * @name _handle + * @instance + * @abstract + * @function + * @param {Request} request + * @param {workbox-strategies.StrategyHandler} handler + * @return {Promise} + * + * @memberof workbox-strategies.Strategy + */ + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A {@link workbox-strategies.Strategy} implementation + * specifically designed to work with + * {@link workbox-precaching.PrecacheController} + * to both cache and fetch precached assets. + * + * Note: an instance of this class is created automatically when creating a + * `PrecacheController`; it's generally not necessary to create this yourself. + * + * @extends workbox-strategies.Strategy + * @memberof workbox-precaching + */ + class PrecacheStrategy extends Strategy { + /** + * + * @param {Object} [options] + * @param {string} [options.cacheName] Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * @param {Array} [options.plugins] {@link https://developers.google.com/web/tools/workbox/guides/using-plugins|Plugins} + * to use in conjunction with this caching strategy. + * @param {Object} [options.fetchOptions] Values passed along to the + * {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters|init} + * of all fetch() requests made by this strategy. + * @param {Object} [options.matchOptions] The + * {@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions|CacheQueryOptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to + * get the response from the network if there's a precache miss. + */ + constructor(options = {}) { + options.cacheName = cacheNames.getPrecacheName(options.cacheName); + super(options); + this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true; + // Redirected responses cannot be used to satisfy a navigation request, so + // any redirected response must be "copied" rather than cloned, so the new + // response doesn't contain the `redirected` flag. See: + // https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1 + this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin); + } + /** + * @private + * @param {Request|string} request A request to run this strategy for. + * @param {workbox-strategies.StrategyHandler} handler The event that + * triggered the request. + * @return {Promise} + */ + async _handle(request, handler) { + const response = await handler.cacheMatch(request); + if (response) { + return response; + } + // If this is an `install` event for an entry that isn't already cached, + // then populate the cache. + if (handler.event && handler.event.type === 'install') { + return await this._handleInstall(request, handler); + } + // Getting here means something went wrong. An entry that should have been + // precached wasn't found in the cache. + return await this._handleFetch(request, handler); + } + async _handleFetch(request, handler) { + let response; + const params = handler.params || {}; + // Fall back to the network if we're configured to do so. + if (this._fallbackToNetwork) { + { + logger.warn(`The precached response for ` + `${getFriendlyURL(request.url)} in ${this.cacheName} was not ` + `found. Falling back to the network.`); + } + const integrityInManifest = params.integrity; + const integrityInRequest = request.integrity; + const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest; + // Do not add integrity if the original request is no-cors + // See https://github.com/GoogleChrome/workbox/issues/3096 + response = await handler.fetch(new Request(request, { + integrity: request.mode !== 'no-cors' ? integrityInRequest || integrityInManifest : undefined + })); + // It's only "safe" to repair the cache if we're using SRI to guarantee + // that the response matches the precache manifest's expectations, + // and there's either a) no integrity property in the incoming request + // or b) there is an integrity, and it matches the precache manifest. + // See https://github.com/GoogleChrome/workbox/issues/2858 + // Also if the original request users no-cors we don't use integrity. + // See https://github.com/GoogleChrome/workbox/issues/3096 + if (integrityInManifest && noIntegrityConflict && request.mode !== 'no-cors') { + this._useDefaultCacheabilityPluginIfNeeded(); + const wasCached = await handler.cachePut(request, response.clone()); + { + if (wasCached) { + logger.log(`A response for ${getFriendlyURL(request.url)} ` + `was used to "repair" the precache.`); + } + } + } + } else { + // This shouldn't normally happen, but there are edge cases: + // https://github.com/GoogleChrome/workbox/issues/1441 + throw new WorkboxError('missing-precache-entry', { + cacheName: this.cacheName, + url: request.url + }); + } + { + const cacheKey = params.cacheKey || (await handler.getCacheKey(request, 'read')); + // Workbox is going to handle the route. + // print the routing details to the console. + logger.groupCollapsed(`Precaching is responding to: ` + getFriendlyURL(request.url)); + logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`); + logger.groupCollapsed(`View request details here.`); + logger.log(request); + logger.groupEnd(); + logger.groupCollapsed(`View response details here.`); + logger.log(response); + logger.groupEnd(); + logger.groupEnd(); + } + return response; + } + async _handleInstall(request, handler) { + this._useDefaultCacheabilityPluginIfNeeded(); + const response = await handler.fetch(request); + // Make sure we defer cachePut() until after we know the response + // should be cached; see https://github.com/GoogleChrome/workbox/issues/2737 + const wasCached = await handler.cachePut(request, response.clone()); + if (!wasCached) { + // Throwing here will lead to the `install` handler failing, which + // we want to do if *any* of the responses aren't safe to cache. + throw new WorkboxError('bad-precaching-response', { + url: request.url, + status: response.status + }); + } + return response; + } + /** + * This method is complex, as there a number of things to account for: + * + * The `plugins` array can be set at construction, and/or it might be added to + * to at any time before the strategy is used. + * + * At the time the strategy is used (i.e. during an `install` event), there + * needs to be at least one plugin that implements `cacheWillUpdate` in the + * array, other than `copyRedirectedCacheableResponsesPlugin`. + * + * - If this method is called and there are no suitable `cacheWillUpdate` + * plugins, we need to add `defaultPrecacheCacheabilityPlugin`. + * + * - If this method is called and there is exactly one `cacheWillUpdate`, then + * we don't have to do anything (this might be a previously added + * `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin). + * + * - If this method is called and there is more than one `cacheWillUpdate`, + * then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so, + * we need to remove it. (This situation is unlikely, but it could happen if + * the strategy is used multiple times, the first without a `cacheWillUpdate`, + * and then later on after manually adding a custom `cacheWillUpdate`.) + * + * See https://github.com/GoogleChrome/workbox/issues/2737 for more context. + * + * @private + */ + _useDefaultCacheabilityPluginIfNeeded() { + let defaultPluginIndex = null; + let cacheWillUpdatePluginCount = 0; + for (const [index, plugin] of this.plugins.entries()) { + // Ignore the copy redirected plugin when determining what to do. + if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) { + continue; + } + // Save the default plugin's index, in case it needs to be removed. + if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) { + defaultPluginIndex = index; + } + if (plugin.cacheWillUpdate) { + cacheWillUpdatePluginCount++; + } + } + if (cacheWillUpdatePluginCount === 0) { + this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin); + } else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) { + // Only remove the default plugin; multiple custom plugins are allowed. + this.plugins.splice(defaultPluginIndex, 1); + } + // Nothing needs to be done if cacheWillUpdatePluginCount is 1 + } + } + PrecacheStrategy.defaultPrecacheCacheabilityPlugin = { + async cacheWillUpdate({ + response + }) { + if (!response || response.status >= 400) { + return null; + } + return response; + } + }; + PrecacheStrategy.copyRedirectedCacheableResponsesPlugin = { + async cacheWillUpdate({ + response + }) { + return response.redirected ? await copyResponse(response) : response; + } + }; + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Performs efficient precaching of assets. + * + * @memberof workbox-precaching + */ + class PrecacheController { + /** + * Create a new PrecacheController. + * + * @param {Object} [options] + * @param {string} [options.cacheName] The cache to use for precaching. + * @param {string} [options.plugins] Plugins to use when precaching as well + * as responding to fetch events for precached assets. + * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to + * get the response from the network if there's a precache miss. + */ + constructor({ + cacheName, + plugins = [], + fallbackToNetwork = true + } = {}) { + this._urlsToCacheKeys = new Map(); + this._urlsToCacheModes = new Map(); + this._cacheKeysToIntegrities = new Map(); + this._strategy = new PrecacheStrategy({ + cacheName: cacheNames.getPrecacheName(cacheName), + plugins: [...plugins, new PrecacheCacheKeyPlugin({ + precacheController: this + })], + fallbackToNetwork + }); + // Bind the install and activate methods to the instance. + this.install = this.install.bind(this); + this.activate = this.activate.bind(this); + } + /** + * @type {workbox-precaching.PrecacheStrategy} The strategy created by this controller and + * used to cache assets and respond to fetch events. + */ + get strategy() { + return this._strategy; + } + /** + * Adds items to the precache list, removing any duplicates and + * stores the files in the + * {@link workbox-core.cacheNames|"precache cache"} when the service + * worker installs. + * + * This method can be called multiple times. + * + * @param {Array} [entries=[]] Array of entries to precache. + */ + precache(entries) { + this.addToCacheList(entries); + if (!this._installAndActiveListenersAdded) { + self.addEventListener('install', this.install); + self.addEventListener('activate', this.activate); + this._installAndActiveListenersAdded = true; + } + } + /** + * This method will add items to the precache list, removing duplicates + * and ensuring the information is valid. + * + * @param {Array} entries + * Array of entries to precache. + */ + addToCacheList(entries) { + { + finalAssertExports.isArray(entries, { + moduleName: 'workbox-precaching', + className: 'PrecacheController', + funcName: 'addToCacheList', + paramName: 'entries' + }); + } + const urlsToWarnAbout = []; + for (const entry of entries) { + // See https://github.com/GoogleChrome/workbox/issues/2259 + if (typeof entry === 'string') { + urlsToWarnAbout.push(entry); + } else if (entry && entry.revision === undefined) { + urlsToWarnAbout.push(entry.url); + } + const { + cacheKey, + url + } = createCacheKey(entry); + const cacheMode = typeof entry !== 'string' && entry.revision ? 'reload' : 'default'; + if (this._urlsToCacheKeys.has(url) && this._urlsToCacheKeys.get(url) !== cacheKey) { + throw new WorkboxError('add-to-cache-list-conflicting-entries', { + firstEntry: this._urlsToCacheKeys.get(url), + secondEntry: cacheKey + }); + } + if (typeof entry !== 'string' && entry.integrity) { + if (this._cacheKeysToIntegrities.has(cacheKey) && this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) { + throw new WorkboxError('add-to-cache-list-conflicting-integrities', { + url + }); + } + this._cacheKeysToIntegrities.set(cacheKey, entry.integrity); + } + this._urlsToCacheKeys.set(url, cacheKey); + this._urlsToCacheModes.set(url, cacheMode); + if (urlsToWarnAbout.length > 0) { + const warningMessage = `Workbox is precaching URLs without revision ` + `info: ${urlsToWarnAbout.join(', ')}\nThis is generally NOT safe. ` + `Learn more at https://bit.ly/wb-precache`; + { + logger.warn(warningMessage); + } + } + } + } + /** + * Precaches new and updated assets. Call this method from the service worker + * install event. + * + * Note: this method calls `event.waitUntil()` for you, so you do not need + * to call it yourself in your event handlers. + * + * @param {ExtendableEvent} event + * @return {Promise} + */ + install(event) { + // waitUntil returns Promise + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return waitUntil(event, async () => { + const installReportPlugin = new PrecacheInstallReportPlugin(); + this.strategy.plugins.push(installReportPlugin); + // Cache entries one at a time. + // See https://github.com/GoogleChrome/workbox/issues/2528 + for (const [url, cacheKey] of this._urlsToCacheKeys) { + const integrity = this._cacheKeysToIntegrities.get(cacheKey); + const cacheMode = this._urlsToCacheModes.get(url); + const request = new Request(url, { + integrity, + cache: cacheMode, + credentials: 'same-origin' + }); + await Promise.all(this.strategy.handleAll({ + params: { + cacheKey + }, + request, + event + })); + } + const { + updatedURLs, + notUpdatedURLs + } = installReportPlugin; + { + printInstallDetails(updatedURLs, notUpdatedURLs); + } + return { + updatedURLs, + notUpdatedURLs + }; + }); + } + /** + * Deletes assets that are no longer present in the current precache manifest. + * Call this method from the service worker activate event. + * + * Note: this method calls `event.waitUntil()` for you, so you do not need + * to call it yourself in your event handlers. + * + * @param {ExtendableEvent} event + * @return {Promise} + */ + activate(event) { + // waitUntil returns Promise + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return waitUntil(event, async () => { + const cache = await self.caches.open(this.strategy.cacheName); + const currentlyCachedRequests = await cache.keys(); + const expectedCacheKeys = new Set(this._urlsToCacheKeys.values()); + const deletedURLs = []; + for (const request of currentlyCachedRequests) { + if (!expectedCacheKeys.has(request.url)) { + await cache.delete(request); + deletedURLs.push(request.url); + } + } + { + printCleanupDetails(deletedURLs); + } + return { + deletedURLs + }; + }); + } + /** + * Returns a mapping of a precached URL to the corresponding cache key, taking + * into account the revision information for the URL. + * + * @return {Map} A URL to cache key mapping. + */ + getURLsToCacheKeys() { + return this._urlsToCacheKeys; + } + /** + * Returns a list of all the URLs that have been precached by the current + * service worker. + * + * @return {Array} The precached URLs. + */ + getCachedURLs() { + return [...this._urlsToCacheKeys.keys()]; + } + /** + * Returns the cache key used for storing a given URL. If that URL is + * unversioned, like `/index.html', then the cache key will be the original + * URL with a search parameter appended to it. + * + * @param {string} url A URL whose cache key you want to look up. + * @return {string} The versioned URL that corresponds to a cache key + * for the original URL, or undefined if that URL isn't precached. + */ + getCacheKeyForURL(url) { + const urlObject = new URL(url, location.href); + return this._urlsToCacheKeys.get(urlObject.href); + } + /** + * @param {string} url A cache key whose SRI you want to look up. + * @return {string} The subresource integrity associated with the cache key, + * or undefined if it's not set. + */ + getIntegrityForCacheKey(cacheKey) { + return this._cacheKeysToIntegrities.get(cacheKey); + } + /** + * This acts as a drop-in replacement for + * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match) + * with the following differences: + * + * - It knows what the name of the precache is, and only checks in that cache. + * - It allows you to pass in an "original" URL without versioning parameters, + * and it will automatically look up the correct cache key for the currently + * active revision of that URL. + * + * E.g., `matchPrecache('index.html')` will find the correct precached + * response for the currently active service worker, even if the actual cache + * key is `'/index.html?__WB_REVISION__=1234abcd'`. + * + * @param {string|Request} request The key (without revisioning parameters) + * to look up in the precache. + * @return {Promise} + */ + async matchPrecache(request) { + const url = request instanceof Request ? request.url : request; + const cacheKey = this.getCacheKeyForURL(url); + if (cacheKey) { + const cache = await self.caches.open(this.strategy.cacheName); + return cache.match(cacheKey); + } + return undefined; + } + /** + * Returns a function that looks up `url` in the precache (taking into + * account revision information), and returns the corresponding `Response`. + * + * @param {string} url The precached URL which will be used to lookup the + * `Response`. + * @return {workbox-routing~handlerCallback} + */ + createHandlerBoundToURL(url) { + const cacheKey = this.getCacheKeyForURL(url); + if (!cacheKey) { + throw new WorkboxError('non-precached-url', { + url + }); + } + return options => { + options.request = new Request(url); + options.params = Object.assign({ + cacheKey + }, options.params); + return this.strategy.handle(options); + }; + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + let precacheController; + /** + * @return {PrecacheController} + * @private + */ + const getOrCreatePrecacheController = () => { + if (!precacheController) { + precacheController = new PrecacheController(); + } + return precacheController; + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Removes any URL search parameters that should be ignored. + * + * @param {URL} urlObject The original URL. + * @param {Array} ignoreURLParametersMatching RegExps to test against + * each search parameter name. Matches mean that the search parameter should be + * ignored. + * @return {URL} The URL with any ignored search parameters removed. + * + * @private + * @memberof workbox-precaching + */ + function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) { + // Convert the iterable into an array at the start of the loop to make sure + // deletion doesn't mess up iteration. + for (const paramName of [...urlObject.searchParams.keys()]) { + if (ignoreURLParametersMatching.some(regExp => regExp.test(paramName))) { + urlObject.searchParams.delete(paramName); + } + } + return urlObject; + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Generator function that yields possible variations on the original URL to + * check, one at a time. + * + * @param {string} url + * @param {Object} options + * + * @private + * @memberof workbox-precaching + */ + function* generateURLVariations(url, { + ignoreURLParametersMatching = [/^utm_/, /^fbclid$/], + directoryIndex = 'index.html', + cleanURLs = true, + urlManipulation + } = {}) { + const urlObject = new URL(url, location.href); + urlObject.hash = ''; + yield urlObject.href; + const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching); + yield urlWithoutIgnoredParams.href; + if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) { + const directoryURL = new URL(urlWithoutIgnoredParams.href); + directoryURL.pathname += directoryIndex; + yield directoryURL.href; + } + if (cleanURLs) { + const cleanURL = new URL(urlWithoutIgnoredParams.href); + cleanURL.pathname += '.html'; + yield cleanURL.href; + } + if (urlManipulation) { + const additionalURLs = urlManipulation({ + url: urlObject + }); + for (const urlToAttempt of additionalURLs) { + yield urlToAttempt.href; + } + } + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A subclass of {@link workbox-routing.Route} that takes a + * {@link workbox-precaching.PrecacheController} + * instance and uses it to match incoming requests and handle fetching + * responses from the precache. + * + * @memberof workbox-precaching + * @extends workbox-routing.Route + */ + class PrecacheRoute extends Route { + /** + * @param {PrecacheController} precacheController A `PrecacheController` + * instance used to both match requests and respond to fetch events. + * @param {Object} [options] Options to control how requests are matched + * against the list of precached URLs. + * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will + * check cache entries for a URLs ending with '/' to see if there is a hit when + * appending the `directoryIndex` value. + * @param {Array} [options.ignoreURLParametersMatching=[/^utm_/, /^fbclid$/]] An + * array of regex's to remove search params when looking for a cache match. + * @param {boolean} [options.cleanURLs=true] The `cleanURLs` option will + * check the cache for the URL with a `.html` added to the end of the end. + * @param {workbox-precaching~urlManipulation} [options.urlManipulation] + * This is a function that should take a URL and return an array of + * alternative URLs that should be checked for precache matches. + */ + constructor(precacheController, options) { + const match = ({ + request + }) => { + const urlsToCacheKeys = precacheController.getURLsToCacheKeys(); + for (const possibleURL of generateURLVariations(request.url, options)) { + const cacheKey = urlsToCacheKeys.get(possibleURL); + if (cacheKey) { + const integrity = precacheController.getIntegrityForCacheKey(cacheKey); + return { + cacheKey, + integrity + }; + } + } + { + logger.debug(`Precaching did not find a match for ` + getFriendlyURL(request.url)); + } + return; + }; + super(match, precacheController.strategy); + } + } + + /* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Add a `fetch` listener to the service worker that will + * respond to + * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests} + * with precached assets. + * + * Requests for assets that aren't precached, the `FetchEvent` will not be + * responded to, allowing the event to fall through to other `fetch` event + * listeners. + * + * @param {Object} [options] See the {@link workbox-precaching.PrecacheRoute} + * options. + * + * @memberof workbox-precaching + */ + function addRoute(options) { + const precacheController = getOrCreatePrecacheController(); + const precacheRoute = new PrecacheRoute(precacheController, options); + registerRoute(precacheRoute); + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Adds items to the precache list, removing any duplicates and + * stores the files in the + * {@link workbox-core.cacheNames|"precache cache"} when the service + * worker installs. + * + * This method can be called multiple times. + * + * Please note: This method **will not** serve any of the cached files for you. + * It only precaches files. To respond to a network request you call + * {@link workbox-precaching.addRoute}. + * + * If you have a single array of files to precache, you can just call + * {@link workbox-precaching.precacheAndRoute}. + * + * @param {Array} [entries=[]] Array of entries to precache. + * + * @memberof workbox-precaching + */ + function precache(entries) { + const precacheController = getOrCreatePrecacheController(); + precacheController.precache(entries); + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * This method will add entries to the precache list and add a route to + * respond to fetch events. + * + * This is a convenience method that will call + * {@link workbox-precaching.precache} and + * {@link workbox-precaching.addRoute} in a single call. + * + * @param {Array} entries Array of entries to precache. + * @param {Object} [options] See the + * {@link workbox-precaching.PrecacheRoute} options. + * + * @memberof workbox-precaching + */ + function precacheAndRoute(entries, options) { + precache(entries); + addRoute(options); + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const SUBSTRING_TO_FIND = '-precache-'; + /** + * Cleans up incompatible precaches that were created by older versions of + * Workbox, by a service worker registered under the current scope. + * + * This is meant to be called as part of the `activate` event. + * + * This should be safe to use as long as you don't include `substringToFind` + * (defaulting to `-precache-`) in your non-precache cache names. + * + * @param {string} currentPrecacheName The cache name currently in use for + * precaching. This cache won't be deleted. + * @param {string} [substringToFind='-precache-'] Cache names which include this + * substring will be deleted (excluding `currentPrecacheName`). + * @return {Array} A list of all the cache names that were deleted. + * + * @private + * @memberof workbox-precaching + */ + const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND) => { + const cacheNames = await self.caches.keys(); + const cacheNamesToDelete = cacheNames.filter(cacheName => { + return cacheName.includes(substringToFind) && cacheName.includes(self.registration.scope) && cacheName !== currentPrecacheName; + }); + await Promise.all(cacheNamesToDelete.map(cacheName => self.caches.delete(cacheName))); + return cacheNamesToDelete; + }; + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Adds an `activate` event listener which will clean up incompatible + * precaches that were created by older versions of Workbox. + * + * @memberof workbox-precaching + */ + function cleanupOutdatedCaches() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('activate', event => { + const cacheName = cacheNames.getPrecacheName(); + event.waitUntil(deleteOutdatedCaches(cacheName).then(cachesDeleted => { + { + if (cachesDeleted.length > 0) { + logger.log(`The following out-of-date precaches were cleaned up ` + `automatically:`, cachesDeleted); + } + } + })); + }); + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * NavigationRoute makes it easy to create a + * {@link workbox-routing.Route} that matches for browser + * [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests}. + * + * It will only match incoming Requests whose + * {@link https://fetch.spec.whatwg.org/#concept-request-mode|mode} + * is set to `navigate`. + * + * You can optionally only apply this route to a subset of navigation requests + * by using one or both of the `denylist` and `allowlist` parameters. + * + * @memberof workbox-routing + * @extends workbox-routing.Route + */ + class NavigationRoute extends Route { + /** + * If both `denylist` and `allowlist` are provided, the `denylist` will + * take precedence and the request will not match this route. + * + * The regular expressions in `allowlist` and `denylist` + * are matched against the concatenated + * [`pathname`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname} + * and [`search`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search} + * portions of the requested URL. + * + * *Note*: These RegExps may be evaluated against every destination URL during + * a navigation. Avoid using + * [complex RegExps](https://github.com/GoogleChrome/workbox/issues/3077), + * or else your users may see delays when navigating your site. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {Object} options + * @param {Array} [options.denylist] If any of these patterns match, + * the route will not handle the request (even if a allowlist RegExp matches). + * @param {Array} [options.allowlist=[/./]] If any of these patterns + * match the URL's pathname and search parameter, the route will handle the + * request (assuming the denylist doesn't match). + */ + constructor(handler, { + allowlist = [/./], + denylist = [] + } = {}) { + { + finalAssertExports.isArrayOfClass(allowlist, RegExp, { + moduleName: 'workbox-routing', + className: 'NavigationRoute', + funcName: 'constructor', + paramName: 'options.allowlist' + }); + finalAssertExports.isArrayOfClass(denylist, RegExp, { + moduleName: 'workbox-routing', + className: 'NavigationRoute', + funcName: 'constructor', + paramName: 'options.denylist' + }); + } + super(options => this._match(options), handler); + this._allowlist = allowlist; + this._denylist = denylist; + } + /** + * Routes match handler. + * + * @param {Object} options + * @param {URL} options.url + * @param {Request} options.request + * @return {boolean} + * + * @private + */ + _match({ + url, + request + }) { + if (request && request.mode !== 'navigate') { + return false; + } + const pathnameAndSearch = url.pathname + url.search; + for (const regExp of this._denylist) { + if (regExp.test(pathnameAndSearch)) { + { + logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL matches this denylist pattern: ` + `${regExp.toString()}`); + } + return false; + } + } + if (this._allowlist.some(regExp => regExp.test(pathnameAndSearch))) { + { + logger.debug(`The navigation route ${pathnameAndSearch} ` + `is being used.`); + } + return true; + } + { + logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL being navigated to doesn't ` + `match the allowlist.`); + } + return false; + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Helper function that calls + * {@link PrecacheController#createHandlerBoundToURL} on the default + * {@link PrecacheController} instance. + * + * If you are creating your own {@link PrecacheController}, then call the + * {@link PrecacheController#createHandlerBoundToURL} on that instance, + * instead of using this function. + * + * @param {string} url The precached URL which will be used to lookup the + * `Response`. + * @param {boolean} [fallbackToNetwork=true] Whether to attempt to get the + * response from the network if there's a precache miss. + * @return {workbox-routing~handlerCallback} + * + * @memberof workbox-precaching + */ + function createHandlerBoundToURL(url) { + const precacheController = getOrCreatePrecacheController(); + return precacheController.createHandlerBoundToURL(url); + } + + exports.NavigationRoute = NavigationRoute; + exports.cleanupOutdatedCaches = cleanupOutdatedCaches; + exports.createHandlerBoundToURL = createHandlerBoundToURL; + exports.precacheAndRoute = precacheAndRoute; + exports.registerRoute = registerRoute; + +})); diff --git a/packages/website/package.json b/packages/website/package.json index 8e33fa9f2..751f5cd70 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -11,6 +11,8 @@ "dependencies": { "@astrojs/react": "^4.4.0", "@radix-ui/colors": "^3.0.0", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/themes": "^3.2.1", "@react-three/fiber": "^9.3.0", "@types/react": "^19.1.14", "@types/react-dom": "^19.1.9", @@ -18,6 +20,7 @@ "astro": "^5.14.1", "astro-favicons": "^3.1.5", "fuzzysort": "^3.1.0", + "pwa-install-handler": "^2.6.3", "react": "^19.1.1", "react-dom": "^19.1.1" } diff --git a/packages/website/public/assets/images/pwa-promo.png b/packages/website/public/assets/images/pwa-promo.png new file mode 100644 index 0000000000000000000000000000000000000000..29d8f1b7e5813bbb5bbe0a718e2ea42c4576eb0e GIT binary patch literal 83294 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 z z{|JC37~6H>E@0`27u`g6F;Zg;98)Wc&d>pj2B~ynjq^Mc^hi*XxwSi9lE55P*9OZ= z1^{g$E3eb_88LUlu)dj@%?9{vyuhAkeY7i@c@b?;{M%rs1H*C#gEK}*{n5Zp9JhcL8L)Fx8;SBD=uVzt@$8QwI3{0}ed)Z5O=M zowWcrG2`@oE>MPZY@YDI7t15(VEU>k_N~A|FvnpQY(JjycxSeHI$`SRj zgWjk#oO_Fn-f{uQE#2E1Iwp+4X~KxTN_!vFv92eBW+yo6+E;e>JUgLj>08*=^n30B z+D-;Zc`p$Fq^8TA@7-QsCbm{F129ZtrnvSz9lr+PZq!v;r0&f;c z`~6&PyI7r(wGdlNag6<@v3d73c;knE1-ov%Gb!JT^0K-MkQ@bykmbevk|n;cY>gduGIN`=PdGovw&=E%F!tiKa{g(ga!HHan6D<*NcnRH(N;_i zQ4blOTd69bl1MJDAECEwPrYJT-vPI*?P8?H^p7cH zGf*2?pA~rr!!uZ2IfbDS@$4}j0tLiQWCqOC&YRJnzv3dq8uV#mdaIGtcDv^hNg*oe zYk=VgkSdSmj8BxgHX|XBaw|xjUeE)f^BJTSBpNQD!cE3N^162!1IgSb2~+~`0BPW$ z%I1KWUB~mVCtNyx3QyhtB|QAa-!boz3>~JQSmVajX19L~0U!DH@v6kerC)0q7CPF# zJH^?ixJGrAF-pIO)J{C8f$qqw4dB_$$lH@I;bJ7q^!irhwXCm}p$aM;&dgfH^WgwH z#{er%hLlBTx9R}0AP#rs?X)z9I$b~jw27=XA>O}I;5&oSk~e4QFop#0;xg~TQ}x`o znLP)37W{@o&-nZ-WL-U$usS#$z;7Y2J|8pBFXdv%8Y~Q`PVcxGjbWB+vz2pC7W^h> z4I8wJ@dNM*1}Bml`BQhE>jF`BF2|$bF5}p<(+e)TrF1^%s!wy)Qu6F-^KZ{&C1F0DkXug#t5SeS?FUL=m72Z!UCX}^obG1 zRUJOmbz>vGOm4#D#70a`Z!pYn*0Vkbe#*tev)eOzfU|>l#W6s~{+!P5jQg&`9vZck zBqTFhQFvneK1>+h;KfQ4GusUi?h5P$S)IzCIy4cV;Lz|)I{WM{GjvZO3aEgDt}QJK zv}~F{(6PZ#Z}Tp0eDiy8=LbHKc4f=zFFPYL2AJ20&G6=*)#W8T^WDF|qkr~$SU7Ri z=djn>$-*sVGyTBcm-g*NzQ#6v3lHX=tqlPfipr5bZWQ3ZQ-9AvS-QXgNO~Tk$e#7ls*awqfeO0YK3p8n-9$#E$C>v6#WdNH(g>)ZA4DfQfxd{S*K2 zZA62W4YDzlBxz~TSHag!D68H;;(P`d3<#caD@*)9Z?NNDc$*8> zqcJ+bf$xYXUU?A@ec?aiz@y({RWk3~MsTsJ59{8-4IQi`so5ul_{@$S?Y)%-G3cjQiAgtzV0aX2TGpp`Wn9YtN#=J@_+g7;q9}pOCKcc4{~pLM7lnV z+Kk6&Ih!B&a8uIz;yOL(q^1WdX37=J%1Vwsm-_Xey<^5iTyFqrd&TFa7apHO*7Hqo zzPc0l7OWP*?>_qXwXA9Bq6z?$J6waC)c}=PT7Fkj0yJdLmtB|3&ts~tnd|xLr`^;2 zIc?1Q0>Ft@co^D8@-<_}=0|Yv{>O0d-bWO86fL~O048oMxww#pcOxS2nv5I>dh7KY z`iL3M5~*`s*>hR zq)2|DpVyeU%aBBuf)fr!mRYlNEk>A;_TUPVKl*q75&Zdo_TRw$M<34_<;(z5r>pa~ z#QJ{q|NQS62(O^TQAD>E)XU~iT*piLQd!4ag_dgWsb7r&kH41hdZGXJ^s)BSOt*LA zvk41pk9%3=8Rq_;Ui}8r5Bu$xXT1IkYo_V zs5Tngu(-4ETi0FzWhR71w9p)OXfe%zPmh^~idi5rLX0zbN&8383K9X8@BN*>4}bcP z{!94bpZr+{tedRri6*rtzxWsA+xPm(Zw#D*y0?g-gRH!xY*y5>^7fMT3)~=HR_wP= zP^+H>{OVfj5`($1RL4^4_Os1SV8DlC|Li#=3}S#rsXIs*13qh50X6NRVOpiV3jktj zm7Y6FS_YmnP?O8<@)oU34Wj!k%%07qPF+?sYc5`6^2o&9cCA*1M=NBCF0}(&*v)L>3=pH#w#|Iw* z+)TaRIboZ|Y#>=>APmvk*Cu;EJ1UyU5zNZJBqA$AR8v*MXviR^5h#&vp&Q_4%V*aB?KP5IePYbNZ-l5J5?_OyC zvK5f19j8m~R_qqtAZ?mWB5`Jd+p}sQ{qT?f6#n6V@!!HHKl(!nUZE`waPss^_{)Ft zKfRZN$hNq-!I06lx0>*~`C)NR>oLA=S)FTofC~HC z?#sA%1-mTrQor6o!V&*4kMTB)Fn4DUU=|pcGte368H@BF)Gf=c5GjP%p9TkNp}D?2 zRzT8OjFZ1co?_BG04*bYZvZ&p_Lk!Z8T=k(eP0GYjNCyR4dIfun3)|f)@NXwm~~7H zhN$Z!M`sdy&*-<01BQTAv1dQFbccBGUDU%h zl6xxP)N6MuW-gRn0M8jJ^!Rf9jxEDYDb#IK7Kz&!oIQi-^_SJU?Dv(3_2qgWW>w2- zNy?aRAG*Fi*NeQe9{|ghjzN~Z4IA`~O+UQ|onTMomsE?qt(YtT=o@utV7<1}qKT6z z-i;68{(~RD{fAlCw?bVXg3XE;AA%iQbu-(8E$aZMogBYr0Hn_gadp{%s`bz}aA`d! z{aem?onHXI>ZE3a0Kxet@@C|bUe18wq8@#6Cm@Jz8uKJUA~Ct=NPpsZsL55yU-6fj z*alsYtaK?M?9E%i6!o(dUMs(_=%1EBFl;YDN70xkia+?%{{a52|L8x5um1X5p7tGvP8X)ZX7g{x`nbQ)qK$yTE z>)c~;m1*2+Kw`$!zGtxl8LLpw&C#93-D7caL6MjBedsn3$f+5Zo+dMRlt2cXqT9pY zB=&AEX^k(t!R)GrTT=10{fzE>4Q}AXV%vO4^psJLJ0L``yr024>je|)t?q~o9)0i= z7_yZ-LyMQsB!_>qnzziod-Kzw`smaQ3OKD&pUaX-NskwRC6<3|*|rEE$bBlsvdbCPB*C_Z&x(a_xV(*1?nc{#wL5L7d{)NgPN3~jqn z!a?_z*I!F)#`m9Ax$i$f$pZJ^y(x2=ui}6kj39cf1v>iQ=|}DSRPuO6SLvqPI_cdH zP2M^7RL7=%yK4+{bL1QV0W>f{vB0>CQDLu?xsBR93>ddBi@WzfBoG{M#@FR+yGg(= zf%*6GUlDnc^`XIoeEc>7e(lJv*=h}BwJ||ih8>RvaMeB|gD}4q0D-Nv=$H235$uld zW+NuDOy>z?_2KW&cEF=4$ce5V8%^@9^?WT*)&UeaPqlmqTscnff*)jrqUbUlVk@mr zX-|k2uqIr-c7)5>9&o@?oCqmk>CF;Ga_#iLXQ|a&!W@69yY%JFfT}a8gn1d=HfVWr zQ7YtF*z=2D(AJa|eB%A4ds)5kL0FZoCT>n?@wdL~1ps4&+MtlSVkc(?#}wsUn4DN@ z$&0`IyhwvTLjikTRDXsr^zd z8WUnA#x<%4f@McKWPP}d?f3)Q%w8k7XkWL0)znfxTKH}n16>x@oNvKzFOX?%9ZkYw z9VJtT_2GYKFJOB0Tke}XNCUFItYUbO`C*_>x;9M({eet zv~0~YJpfn`XOoLeGe0kJ01CME>aW=@0bqF0@_l^k!?_x71w3LqbKZEh%4@ob{>}*lan@NP4Jno3l0cIGH zqqA~DQ-Z5oqE72ZOw0x^a1n8S{14gCF^)75rfQ#On2Ed4FxYt;64Yo8dqFg{ZH48$ z)ubSY+}&DE4+t&A^w$tzs0bnXOHy4$pjb$zGz0CGL zCSBjr(IXOhlWeww*JJFy62Fg@R_zMtk&&b5{VqxSR80~kMKcNqr{R z(Y@u9Y$NzoV)yY{URuJ2z&B0e*sRQNTYztph%WS9BD<(Nj9=kl4X*)kKln8c&OzHO z$BV9SFjg2D{GzZxEr&r+qSh#=>NR+;`TX_q0NcZrE$^JhM?cJeKc>Bk=b|Bh^jKDT z?Va@4ncBb$p9L^o*>!dmHJSBjMvdMA(9{tQ3kpz`zc)FtshY(1ZEz;=h7QjHYsSat22e(8I>PA0+rd6Xysd#R z)C|zEM0KuamcXAFv3NTMxE|n!Km^}airGT^2?1fm=qU$)1hbTatC;Re5ztvI_L3{q8TRC1Den zSF!b88EFoZdOy8;EdGZc0P#?a3Ot-u4IRpwj*ig11;H-^UqIj!V~2v@ZsYWQEYeQ0 zS1mEW418N;e8T=XpBgsOY#bZ&i_IrD-$1Yje#Q!01{kC2{zUYZZ8+mF6fsu~A}0Du zmnl#Ru;TAc{`JM2$-Ni z+k8lJdcbA4@yM78`-ITu?#8|4h*)2izDVTV!$@xc z;y&;t*z1pn{iFEM1+u9Tm-%xN5Dkuf`|D?H9AGBWg45gi-`#8cGC6*gwg5v^m;H+&O1%>IWvm*rFOYH;5vig zI_}{8^8mirh_Mti8$@es9c|lzbVEp>TqH6`Co$+r=fLAPpy4gUH!)WBQ(A@SY3d_$qD$k1^I zA}?BY5%@kheh58ho<7@4i-9zbhXi1a|PQh61TcHW+w+UIqRA#?z^ zX|FueSPD}Y5#FTem;xEx&pM~$`~b4Co!lEJU}>7f!C4I*+bVK1eHH+e%O1gw@>eX3}XqK zb{GKiA@=W;BU&nBqmqwy0)Wo4vueW9vRa0Q|4hAkgvn3=G;UYwH@JLHDfNL%>b7HT z9uIJH@SYlGoZs<~%-Wn}%fVyv?ZdczXz9gG$wN4%7oWvgb#2iA2IkaE#t&WQMmoPu z32>lct~{NcvkqNTY>dwgAHe~f11a(C?4GqHts|zf4 zAA@Er0E_hv<4Au~?%1=<8C*=4uuFHb3Lucv^zh+NItG$ZefYGbhK&wT?JF1Nm}XgYE zdc{CH+2K8}(>0t<7qGqQW&Vy5IZva{;DhhU%k03)=K}?f+c*zH$>%YuE_c4v4mxTU zO%(uYS+4M^d@sIt*xnq-0V)}PPby`2wu~?0=~J@uqTcT=(oxpue)ixKcyQF&v!(-p zsf))oJJK{weekXf6m5ZpF(zIS)zx|S7}tE=Z<^^C1JtZeS8w=LV9sbF&%bAR*8C|M zz}i^k-)OA$EIQ!E==>tD$iHuu^+>dw?cO5^T8jEUUDBrU`qaWJ!80A`DFCwJ;~I3` zuQETZ+;`z-E08S6OFtdHEKmhq*r=d{eyDY1D^K1 zKjTnwZ`nN&xdy)dfYSrw>YAzz`h(Bw_~`+uZ)3O8uyjAwOF^HsTi%Obi+js$9gAF;d07yCJ0opz9h(0+_ffH6o~a7_%5^X$O;2i2WoBCj#O7W}*j>cmzRRaLwdqesO6qkSh!u>fIRSMBOj zS&$*rb*Y$~2k3xXHV*hH!Bhi3IAqD&O$NWsDO{YrhRgf{VO&F8<`Xgi;?|t##`6AC zpwL>YPyUD_vH(>2HCSSOo@IdyR42lAukqKq)ViKE&ym)5KntnVR@t- ztLvV2C9OFX@T)Qj00;15YMK=^3wz~7V6CUoC)%}Bxi`HwWD9S?z@^6-`0iu4`tbpY zyvT62+Z|hY!5o{lgNokIt?6X|Tni{F1DrrZVb`67sTFzkn0IWp-z1nu4QcQ4q3Eeb z4;5RZriskeIKVjbC3~!u90|Tx8(e z$ud8Rf0$T=iboGJ2>ubo2Ok04B$s^`Dc=)1P7fdblno>egIaneJS$8I`s~mv(HD#x zR-%YAa$UHwZY?Wx%BlsZahA-VlY{ zi+1&iZf<}oY+d`srQjyGiCJdL1`A_?U;tHBEWoCq>yYl4A```Fjxk<`u;;yuLVv^V8Q^^gX2|egNLl+a78>!l={Vhw#B? z5W*dJPhbe+)eYE7t3mK8r(JA zd!miv^K*RhbAa<#a2E+BhmSJp_yn!I!_8`uN>psmbqpJxv6*P;Ka))IQ`PVE?58?^ z^<2tFYU=mB&U!p=$l!cE9cCwDi(_|IKHis!zJ*gxHRH3s@a6J-p&GB6GC%$NA0)K& z@^ZF7TT~+Lr9#Enf!5qK=?V|A0Pj@qw-x}c1UbZMKiM(^Sx?lN3Cs1vj;nPYH8mWcr%xGbDyIF@0W zkoCQVi~QoOFHfDXh|1c zBqMl+*gp@8Y;b=gtquEGDlFDtfv{&IUFMm`>&X*H7^eP?c4oVmpTp-Levd@nba2N& z#mqQqUrp8T`8Jn&O(>VE<+L&)5FjR~z_Z^FD0<`~R(iJ^34l_vPffq4x*hGYRtyHl zq&P%Z7nq8!3b?A^nHm6|8fKf@^poHJPqGMnk67QXY*Mt7MwpMEF+dTAi|BjpB0H-) zjMCV76z5vJ)nf*Ll^@^C03lXa&*l`I;!v@_;0+$&bcZFlfi8{1I;1WdAGPH-l8%q9 zyUYMbv4U-B$GXk>49?Fo@MQp8wLwILU>(Wyn*w#FJQes1r6a3;KjBP{ETRrAa%jWXOV5cc?s$A z0>Vd`nXTTlfdmaTXU}MFkND_E`S1J2y4t*6$HxbH<>&GiUy@XBmt|a+P&Ymtg_205e!)bn?^XtdK0oiK1tvvrF<%smFmPVW_tr&w+3j zB^v*tW3`~7^CZXlx|sVXzoEynK9}8FCclz{^nW`ZEGZTC=U00`nu?_tQtRRZ03Dz+ zeV^v?;HP;2yd$y#QWeUo1T=6uzG#6CO1ZMsjm1wbClqm*>P(z(P^LGCVMW|+NF%UA zBhMwdwp^aQfvd~cS!aIkg1G8R8U=6D>l8*z_l~pBAnq{1M$h#nz^mr~A7tam{fBT9 z%X!x{t+RpV)h}V#oD&-a3}U*J!UF1n$F|@GasxP_`LXnVSJ!pGvZ=ELzv}x^|6%l& z*I%)r<7Te;&I!lEM-M*9tnUY~qUhMo`BQY8dWiMa zSejqbra-BnW~@)9GX@=X_!hC0QxvN)mo=K7D@`9J|tDw#-j2el4u;{emC%1*%Ve_|cEy;k^&Z=%H+^ z7@5FWFrQG?Hh^y*cil8Yz%(iNbzL z%=9>NvlD|SV}e*HS$t*5n~&hk2oB9txQW4dORzCLFVq@B$x-%d}z4aSh$NM-V{`=pL7t^CWnf&16AHzL#ME4|# z;$9jc)zmANmzJ?0xqK03;%q4YH1D4T`0dODED70lymyEXgyQt{!Hw}*-2u$nJg+D; zVyb7N>{~3?g&LrFt+0@ZN~#PM7V0q*xpBK`9Xl&XWxckoNEzIBOd}gJb_Mj5Iu~W~vBgM2RA1Mh8IP zbb}oGFb<(&mAuqPm8ILP=R1M(tRTO-d`03e_fdc)9gX*A^uSm8q5{4E8h5a?IcWZT zuep1p{rt|t)T5aDX%=@sfAj;3A|y$5(B8eIS{ol6QI=Sf z_}hxHiI!Di_I@d5C=Q08q(sJHw0DmIQdd9O^03M{30jS@RgC;j*eqTmUhkNkL4*S% zuWif-kojeFS{2$KWHzg$Nab=qC~NS09BcausQRO7=yYI7eNszhR^BhN(f%6Vcf#j-Z*?Dj`0?+<8n^Z%B=?m5MWl&8Al+ai*2uR!=N4IWQ9lx*1x_f#48m_X15OsZQ-QAS|%Cog! z7hH?Krq7Fx-PHylzp_O0XdJ`h%uVc6+MF2$-v99w;3^-#4tEf6HS0KcuYZ$ugQqZj z@(1LqvoDoro?0g1Qt;MUI?&D2O+lqaKA)D@ryj?!YZ$Qf>^VSs@4ZFO>C;Ew%OdYj zVeA+>jPb?Uk4ok)55X6+sW9TgxE}8 zr*D!WiIfDY3{V^p#oXQy2zMGAbh{;gSS*u*g5b8eq*h|x9D!z%c%m94#XTp|;Sp%^ zFaC=~WhEWJUE;R0P;ZSm9MN*#A}z{sT*MHB2w~n)1C!RWrM-+$saO0DxmjAd-=ZUW)ys`;<*h1iAzWW0|a}EH$pt zc#$Pss`_ze)xzrN-$(>O0~Qms?Ra$-lbIy%^Tf}YJQH@N`T~vow3DbtJGvIvwWEZD zK!-Z=?dF=xoiz5RV1*b-&H1?f^zJM339~kqB$sb)G4CZ$s&qvcKqv-N`owqaqmTcc z#M@OmeV+gz>cFPL{w%zG-9W$EBUU%!!L0>9e_X*XzyLnBo`Kp}0Ku>BXqUoyV4)%4 z3@5{IBnFNZn1dxhwCk%k^mlcB0_*ijez+H6?M_n8*y(t$(**Di+&WmJ19qs`BG_i^ z{y{~a!HDq*Q;nm9*h10W=`gl=hJ3R-fBzt;3FAa&b~9kWRTaThYLn0MbDwT7w8Cqs zep$9qA8X4j^_s{_yy4B)0I$EwLe2XZc`-f6deWbM{wHuBgH8DM7-bb5n6^{S${sZI zJvotf_8Fx}8B^qwYW457TQHwGp3vE)4Q)M%b=hG@;KqQ&;Djz++Z}IJfl|+gf_Gfg zI`-`vJwrAU`*U0Te9a5QqCwemHxF(Awd9vT;{p0Lxi=|u`crAq3`(BR{Y|2`5)bG1 zSW9bw0Qe75iRLUbgNC-!SbtNY#5<^+4%Mv%s)yz)>M_4Mh93@w6@!K7_!u0VyGwMI zU>F5l%;-^tuh-q*1SBzF!H{R@IIKX~84eJ1X2yq)VXDsFKF$yRRbhO!soy;$VQl4I zJ>v^jZ_)1+@iv0`L(ZMI-2@PL{j%yOafaf63x36b8CCERUu3cU6nzoX-7MS>_dm^S z@TUOBAI@iOu%T6Y?O;2D$anZ%$o$=cn^^UVA*0B$yKXdtvkn3k%m zXkiT27@vZiDY=KzE^W8zHx;beFAPCXb)MATA)5HFzzU^kk6 zE5E;l;^h_{r$7BefQR3k1Cjp`>Ne~7(0tDF?@ONXA!wpYO9njxzwP@ESW1SDqlfU5 zPyZMm<;g&$A9*U!IwR}*Aiu<%%g1%EnIYCIh743Dnyh!5D+8MpN{|u@HMb$4Ly$uT zw^?723g_zbW&X|}NPn^wZRNhklpVNBCkIqY26h5|d@7N&(7%4iY!{Bc1|tw>akFSKcr41~4f1 z8;dh=C_tqT$}GM^1MJ}RFtN<^OW?;Mx&pO0dCT4+1!$!lD58)I#!_y82k|}}Wf31i z@NDzGWe#9`Gj9DY7$2qFj`ZSJ+0gN9&K%xD!oL12 zs{nrZ@gKlZw)TQ!eLT;#BCL(^GJT3~s)o5QYs19@V-g)4F*^kJ#Kr^e(}_G2K+dhN z&okhi<%#?)c`a6+Wo#qt}AsAwXtfejf7RA(jz4w_K~6xqPRdJbfMr*FQ=tnU>CC?yMT z9t3f?M|sW1FVVVY6|b>AjY3m4a}qsR0cQndun_xd*;O`2$Cc@+eorjYaTtsK)1FkY zK2nQy9=s|7YrU8-oYE)pBREDNT%W>bde58o;0tv66w=ix#Lxc@z`c*yBHw^t%lNFX zU|GKhn%S|vrtWn1f_G-SqkyHys|WDo&;A%be)t10Rv)0al{jXuW1pU@S}5tHypSmr zN8qXKrnoJ@XI4@EzFy;`eNKRPcJi1+S=8B0JKbZ)t;tVpq%0FBKxr?9nNtnXA z$&(?23>XmUWLw*<5DV5&@BLv(uW?7@(fViGGBr#)NC)b&m*%Azj z{U0S;+2Qy2sF$~?Je?|qVu0ERpud%^%yoXu$_5useqfgmF<9_&wXyj7v0=o4ruqP? zj&NY6H;yYdaF}l4eBiBg~tKooXLWNz-@KFKBE)3u=&Kc^1iI^g@gdYhra*m$LHc;%y1B zrhDsnre%J6bwB`Z`#kjtOpjpC!A4wRnlk1L&dSy6>SJ~Oc6r@=xtzBaN9eQ^4o~%s zhI{wEpGwdJ(B0k`AiOV-HQfQA#?*t_*r5%rb!rNLV_|sFDfl&fJ^S_vKx#k%H553o zCCl!34^~+e;WDXlVus&{zT=uBwq&-jS-+O8IX8t|FuNS8j;XEG2JCiE4dZjVzfhu1 z2iIl+z+otQ$uKYoGUGF#V7>uE#*CA`b!H;tu<=&&ii^=0Biv?Rg$KUmh+th;PLTi$%CJnxch#7#_j;j z^6B^3FxL(MZ=6uD8(oMg4P?49HmM?U9H8FzQgvuRE-koO`Sfjn)DyI z9|!9B(8$4Ca_&m3K7h~wvvp1Zzu+u*%3|f7jr}R>3-Us&9P1m4?;fo<85tahmELzO zKv}>ohN45{ht2(I-<4&!7EAkMY{U&=g`52HJ_Ps0 z3?}}y;x4l$p^A1G#avvyk;OjrMNH=}WexB9zX$X%_~8EM@O$6?2eghCC5%DGBaXju zEE5k|K7;I?BO&E>yRA6YUqYZ2853=lfUzSlvi|wv?1c7;xytO0nBVTIFgpW?32Ogb z-NsQSd+3Rkb?QIvZx0sQE-pKD&Nb1X!V*Z&w7?Ary5nNiwlcqC06aSSBuyI53KH}p zyHpqGgZB&wY6FOYpNXz&-9?ua-hs}6BJhrMyoe%!1~erR1DBrBUc~|&W1yKC*r7tDJt@VG4M>mBTB3?>uPm_>C3bL1>jH@K*#u|}!5L$Q zq4@TZ-bJFj6vpesTm!jA{H>JjH6ZHua%}^I%vvTmy*|xA`0S2AP#c!pdUT&RWIFmF z>j@uaT6K?Cm9z{G^_yta$gBwW;Dzfm0zdkMyK6I!(;t8S_uz+_^`V0^-U6)|k9ojhbKEA664F(*zIW^i?}fs#*KVU`^4a8S6{n%Es+w^@rX z6I#ShC`KQy-6f+(x;7REUKeS`1p{m-pbj1JR+*Zut!UuvdQP$WeU(|r)6>Ury}27F;pG%K?@h_pdgSFB~Dt1J1-V=x+tau(IOjQEetcmq3DBfON zWX1m3Q&>}|stcg#uhM1!0o`~E=HwYG=4aN(iQ88Iupr9~nHThYAW!p|&JKBmq^)+)=*oxF;VST>yt2~iBd;0{=vTo}CZ)_0z<@1kz z5B}hXe+G~4f1je1Y&KV9M1z2YU`vy1}5xi@HA26QVyEZPvt&o~-A)%73SM z_I)NX`q<*j+fV9Dr27MlVPz&7ipxqd=0q^3Wv>I2bA{3JH3-n=)}kTwkNDiUat0A8 zKGdG{o~ae*<^;AfAoQ6+Z3Wh60`7SkJCux2d-$6O?-M#!Kg&$;<=dxswx0NRoyPnO ze~=m9?|tv@)1rp$H9HW;h!IfE$ZhKU>{&sshlSF!trop-X(VDR>whV_vhWKOPquMvN-IoJv4>(m--;cferxL ztkdkv8+6si3W`W8n+fr%j3cP5z+tfb(R|?sVSXs;B0~gnE11NGihZIsS>JM*2O{pt zk({@@2LONoKG*=WK^dGORKQn@$3gygfauEchKo3^gzd3oGl8Cn-5SNEfRO_z&&(imrmN!`pd6BKW zuW9)jo~zw%49INVuDjU+egVv|VSwy=L(7V?CYi$U55{hh?U_zfBUA(R7v-C+;DGYI zjsRU7I_4s33x0e)RuOR>6D+_PoAUr&CKM9EyD^k&!TAAE9rcIy~#dT1P_x@J{vpSa+=y zpa9sja?Zy_yJF(zba>unSC(&ArUpr!r{0PcU%vufkM*S+3@Dlc9Lj1%a_qctPV_bK zW4#*ZbD&nl-4$7E%L)${9!hs%W8gbxC+6`;7!^nl+^YOq5&Alsot-&v)8YnrBzGMkb&R@dU&wr6E#=mQKneQgu z&xVd4eewse%Aoe@*%z7Rz04Ndmtr_uiyxkfTYQbFR4kRrVwP$)ZpW5H)kB%xU8LIs z-60^fB!VyN@VvNN10Xc|)2>yxU>5xV(YnG-sQ_U0VpbsI9GZ&}BZ4=0kdGdTg(4oR zp`ch%M|Nq6Y}rL4$Lg2^5Rfn5PGg#J#M*0G1Bs!kP~m(kgLEspzM%oU)*@|7)%auR zfO#+rud-MTtzUu_j3p#J`}2)O1XhbRu`%EA6|)O7-#yzp6Dn3$^2FEx6F(3B-U6X8 z!l7L`0`?qdPSbVXnX8R+&$!59;L}%M!t1ODOaF%I2C{wGWyh{oPUVb~9*6qd0CCja^pTVWCBW&~9_4V@G_SuvL z8w>3Vu73{#K+IPwY(oPurYmFJ-BO<1J{oey?P<**4CAu)lscKrv=$q?XFR56Tj@5G^=CiOO88 zz23+ZDzH=LSL$o(^~YmpyGdnyUAE_5zPcV|;q4390&G)Ov?XcQe>xl@_)TYadBS=2 z`b&8H{MY}+fgs++aDEQk(^s%tpR&#v_o6_ymsGr!{-l?+-ha8(!R^!I`OiAv&BltG z%l~%iefR(gfzGy6BLv>B%HWM2ELSIjCI?L3unve}6XYk9f|3x;GyoG-g zQo6o`?W?a~ckv2(EX4xd^6HLQ1;x2Q7ByOeoYD61AY zmqcVeH^EZ$=-Nu$>IG}5=B7k$FbW=gpa*^uu^4~rqJ9bKL_04LIEwyHR(+7ZFN=$) z>s#T1auJ<(vRf1xGcxO2XFUvVLUes)dvQ#(am$9gC*Ld?Na7L9BeUR3tGh(SVgRXJ zTnf`O9idunHO!W7ltlNX;;veFW2|0|!R`2EhK^d#M&FYMX9XFMc6qi3%{|pG)I2Io z4P4Rb5y7c1lHOGH! z)i^G9rSEIm+7c-B^?FNr4+XUd2WLGn-3HWn8Q!6JXGg#TSub?eO*+H50mPSETZJuV z!PFeD5B8RUGQ;$I*+A1SD2`oFZi$gRR?Tt1gPg7&Vvolts%f?^&?j zUXvaMg<2~izw!hpg>Zz=jJUD;u5uH=W>VY@7~BmJFiti=0;2GCbu-pxM3k+`woANi)PWXuerYOx&vHT4gEmyz(X_kD_RDy!^^!*@Ppp<+>W&8n7S81#Rxf%57j?a=Vs*|0)UyZC0ofs zniD8)AS&7ptK#Ou>vKnAdFZ=G%hg5+T5v?cNr|zgfkS-fKLozr_L6s?LUH#@-C8yh zu4>ybv>F(AmNI8*8j7I~Y@opy_~ng-;n~)c&R0<)&M;UXK`7z$9YYM>iXEgwQw?|x zdn!6U2sMxe2Z{iVW!4y?iuDzsI$$-U4peVVd07KMG5X9xYXu0Eh@fqcrK^=q`%JAt z09|B$^W-n!#hb^!bKM|CQ9jFRlb64huu1w-SO5yYxeq1_vdf+d3DiNk27zU^*Bn_C zVOy5HFMY=p@D_T#+ZjwIxY=c5rS_+Txkz+!aOxv$i03YXHQxz_u0^zziHK zVSLAh*)bR%ReNqA(^DsAautcI0$x*QeYko9qq3klg03v=g78}Od=`D0>o&HjVhbnR z-APw>6p##2#9n2F5@bMDoIugh>8cY8L9a{M*tbtswiI^g$}9jhfI6(UdN>116Ll3> zYL?Z})m0*Kuxo*L1=CE(q@%1#k<4-?ROMP*Td~eDlGp&UT%3{vUHqD?e#t=PA_%^E z`vksv_SbNojaR>mgyFMxC(p9j`vSm6GoN&U!rz#d@uxZi&b|4AOQMEn_riR*u+WR^A%$g5+_X9KuXz z7erhyV8t?+1KD<4QMo4086aqcY}W=8heKt-H74nSwo_(`Hh_!n(v^`yb$>h#BdFEx z^7<6M_~u{2oAYn(jt%Da?y~x1`|1lwYXx8bvV`(dm^#M{9aV@c$}?8WCIQ-hhpO!I zZFYXo3-{g0!0(p2_22%v)vhZhvexIjS2mw*xoI(9sZ%zJGS!A#nR82kr+9#DWEdGZ z$}%<h}{T#O^E}a<2@3lcT@rt5MTt<@1a%q9)VyG_Yl(Y zZ8jVrQX=ARHfY^_Li_Kc(Ze=$@xdQQu#JSUIZliO)#*iZQy`$@e9Fwq(zEDTY_K)D zMa&gF-|C2i8E}4Z%+~|2)Byq*73evDBg*K-P_TBXC>x^#B?GkLHWR&}!CmLdvikU5 zX||26$lSC~qR;5S_Qs562tXYfoAod{xp1K3fj6Q@NA5fZltJMm!3}`Okd*uLB!kkE zY#@33;%77oewPXB+?_s$?VGP*$`I?F0Zd+D`0DE()|VA>Op`yto5f61SGJr$H8X*QaoGev%pAOSry%<*d8bcpZ4&N^1rfWpzW* z?HTyBB5;J-YAyMrxU+~$&M>;oh;$`KFyn+8J-E*XXhq#hmnQ}@yFSkHR$$~r-PVOA z_!rhQOi+mSw5;=7I>rF# zfz7Kl00MkV5Ob{i(EQ(Nx{VvmZN$co%gG@D3T`%>)WBrd%>htXnb<0x1b*`<1VwO? zVlCYij!OTIQGNVmJui#3M-rCm0kJ^ztRu;^;pr7Le82+J1q$*&t?M%f=vYE)vG|MYb`hw@(U!H@J{++EF#|(w z2e^FYKyAGZtv_9?jw{1dc0!MAVEvit<&@R>@rSkGludzX3(_g(LA1)xdka@r7rYTr9*E!n=*RFuo-kidt86U! z60Xqbr9PC6rM%48lg#AVaEAL0?=Vi``f3&~zh+@Q;OKyS=bD>zc-@lkkk!45XiW3n zdr?K;{oh_^=p_s}!oR8}ws~}dsvVu{i9Zx(&zre-#B0}$Rv#Z6SSG&UdYF+8rSXfwF~E;7I(0tIh`hz;;HB5s&7ur{xL=eBqN^I$1Dy%Y?D zHIRY>BknhJ%?PesCkn?7tC88x8$mz^iPPm#zSIIQ6c-TQmQ><3MhoxH8+`M?8&G!_a$ z?+0)_fq2ZSjYD-GYTvaz)%!Fy?ejH&`7IdQ?@|N~2ez4_qNo1xe!(oMS;pFl+Ut&& zbb#JqqF`3*oNG3y{aD7St59|7{F%!4q6=J{1Ox!bqX*)?uw-jFr!BZv(7Ar4}A>L08;P4?q?_uZ@y8KmJMQb(1#dm z2I?NTGDh$^KqvkdFon)b9UO2MR+Yef+oVknd@TxbAW@d<7hN!n#hqywqe$n>=C_-a z)f^o59l>vNeT7dN&fY$S=TCnQZ(sig&d{QP=5TX{VV-|W~hKoPm*CAL)^st1e?JO;Ne z*?w!Vf=c8?qX!I7bavj#i{KfoPGqueA z>Tvnu>6>rh)w3_*;{0g_y>CbYKp#&WBOq&S2MLZ*Pl)P!YWFZtb3j`bZI{Ye%CFCi zk1vC5TSU022Dp6+-E!Xn{xHG`Gpz&idKHN);ec!8d?*Hjetf z&H99NK8d2{PL9!dk;K4*UozeB-240ab(+qo5j`L>Ae4>NW3b=_Bl@BITQn|wba}ik1Nqz`5kdt^QEewPXjUbVUnEU9Lvaen<%`!>ndxtNr49wDU0-IF_Y7XY z{4%q?Cls#{LzdyTq`171!c8Ig5ktRE<6)?z;h@xqCEkn{W(qu+)=*MU%4 zr`Bf{p?lFvWZTjdtGdWiTUkh>FkTjEiIvIL1>;Iwg6J7S7HKoHyS!kq!~KK9j#L|$ z=Wl6)?-x&gk)Qu_iqyT`os*c0yY%T61^D8rQ!&rZFl%>tiIN1oP${6vXI-zE$<>ov<+7^#w~!V2a3J=ZtJ{zP~9PR>z~Efqw#f%`okRPd_4(zI>2_B z;Z!Dfm@z&tqR#g}?y*DlATjH&5`rXS%lrk~aW>w6_$jQi2#k6dJWYF4XYmGS{cYCs z;ik{%+JbwYBJf>bzi``6MnT_DJyFgVpI@C?@w2)T&hh zngXF~Gq;kB2xWXF2h8I5&0?(j@qq-gh@>VUVn$K8C)iw_W$-HJVo$wE9i?Tue zPLIyrM{iH%aW#HG4W#{0rz8fB4ZQ%nJh-neUuONzbJ~}K!&PnQLJcDxM5pA%npn1Q zG^2n&4~}USu%gu-lFwUrs{jU(tkP)JExWSm-XjXKA~x%Tt|KseF!INZF{$CB&gVs4 zdr-tSoiU?Y1wxnEN{!ao!(}_e1(zsB6NL|(B@1vu3*e~4PGI^)v4n%T{s;&TgTynG zI@zc-k^2g747APp6X|$QUOmmA_YIt8@WXv?5#*$+Xk`x?z&N7Mnt*jzi5Oymll$R& zmUB2UHhZ3cS2@g5%L40{$>;MH;kJLOoHsGJN-Y8K-2+pnN{H_P|NL_}qz&!m{RZ`n zBPqXcpkgql6mb;!~OBTjnQp%)rm-1EWT6DPrwP057w? zmF&wAtsHu}!yI(yGel^BPr$9X;LO>c=`-c!5r$=k31OTCa5Zd}UBi=*J(zOe?!ng% z%nsbhs1dA>%ibLT#ke6LT;exUd84e*;I>7v^b+W;H@sYtwi!V1TxWK7l8qTp;mwP$ zNY%k0$1(MI7e3jRfTH(Yk+mONIptZt2*re+AQnBp$h%E|k zBS57Wv~$HpB=TBaWKd+>SZNHxfvnW*QlX5^1D=X}a^tNPH8d?DM%7sZuZ4qyt6Fo4>4k zvFm*R+ig+@;9F2!-dn@x>HW~>p-%LnDK9klpR6y-p#)_+&;qPJK#ESNR-Y#}%>Hf` zk5vuFA<`oFHN@j)eMRmqIMbt!2N|DQ_WasiP7WkWgS@`30k+_SmktI<;Ef^%jOs{S zBGHItm;L%=r#UGT8j+~hvq8yIfnQa3eO)QbfnTNLs~!N56Eh!+<(anPa@1>MELPh} z1a>dBx$L->j^baJI9l~chAa?kFSC0DI((MHh$q%ryhWz>B!k}zvgqTa zN2(3%pDEJ7B+Gx=IN-aMElD@9KkCaqhE%h?`u*&oMctomJ}>U{is<4`3Y{GGvIfV} z`7_qPZ|>@$Qg#+sncj=9zR|{LJPXvkLj!>3*T>9e6xJ1sFCXQhz^X%u)QlEh z1V9USU$eNvxWGio8q`9`$LC|2-CKQNb$>Aw#s`Hdg00^0%rQU%kP4pm04$)Y)&&Kq z5v)2|=py2p@gS5w!#~<`Kmrl)Bof5=oul%g1s{PcgiU_FZ{YOJ3pjc4O*UxY-YZ$B zJMnTw4>B0VN1c>$l@9~pWtj|pzuqRbtgz4Upvki=(zc9{FJEGUp-51Dak|u4fymS z*ID|kyjWfo@T^f^+*EXbv54GR1+Y2>wTh3U?302bYyR7Aw%JIbtUa^0?F9kf%coz# z+m}zss=M1=nRu%!F=Q16>47n759UGFr|p&G_mV(6L~D@R4~#9)#ThW_=N#a?$hr>* z8_*2PjM1*`ST=n=_ivZ&EZy_BVvXNTqMAGS*JpA84rYuU9Ux8OQhHr#nAfZCLh83g zJxfYn3Bb!>mS#lNyEdg%OBi)NRTt5c^YUoI2Os?1gsv^9@aBRhQk3gOtXMw+^WW2m z$O<4e`?DoY7KGIA-(jNeSd1MSaT?hbh1N%%pDuHw6(3_^KU9wB1X#JR)?|P>vW)7= zOoY)rKEN|Zw;s2)GzQR+@&=C4Nkj@*X3Z{rCXA6BuwDJEEN)&vT2dxaRs_fcXkVE@ zNIzFc$07ztvD)uwCCg@w+lt~E>>Yig+tTajU&7m0PsEpVOZq(SH!((#abp7-H;>$( zi1D3Mgdg0(K({7UcPH!YFdJa=G-q&?3Lv!L=|K*vXHj6N13CpABo6I81 z=m)?%_l=?hUW=~pk|Y6~5YYkNhcNR?@A@h1Jr+Xf1JK^z@>fp9y;qo{dYx+yoF2^G z3sWYln$vW}*~3WF`%jBerf)vTcYpYew39-D*00a^CH@mD@bZ1jc|!d?)jIIh(dkvf zQ}T7z&(b_8YClyAr$tuab71BqA?PZ?hAUNS&!=&);5%#_DgLfx{Egp{duNRsFB#RjpToef5636uzT!e7Y45hxviP;y_bo>R*@USJy6k zsmjhjtWRkoc4u$xKI7F$^z&w)K@*dG=qxU3)B8!>O%Cl6lL5)H>A>i>ia8QDgbe}7Zsyy-F-EPo9 z`I1)UuugsL0@#83kwv_MEAK+T9$ye{npQx|Bk(I^pEI2NDuGsRj=v^)(( z+;uiy#E4ONuHe=4Z{X#V-@+O0iGjL3Vs*CRH@APqp{IZYQ%n@4M+G@G%&Ok{5E|uENAB@t-unY5Z-#Yae z;CBzChlHeeEtvfb2bXzZa$>539asOiFT2met(JyB^3f82)%4ifhEXkmK9*noro~Pwk1xs%7Z~vH&0iC2ZP^8L05esQ#OQn_Y{6vOE6NY6AGw-1LIHurw32g8yfTA zc7kJlQdV?(i~vBZ<0~&jl+O1qE*72zYH^pKEAqW|ykMj9(5Pc^xz=1XuV$c&S zEb8|Vl=2_Ct-N~i6}6E+X>I zW^t(RzZOMcp0~V3eG%8|4%>77x>|>K1K7dM09%7!Ye13vONCw-_=bLYb}TjL+usX7 z_pSh#dPVk`-h11ow7J!;PHze4Tz{KAkPRiX_=2fH(Z$rjEY*$AdUxZ5L;C_3Hq-d? zsq2gB)&kTas=S!1c_m1}s5{IJWglMtlugKoD59DNyHJU(<>d}elnr&B8aUhQ?Zwk_ zqGN#mdcUNusvklDKTx0vX8kQMp}MhvstVNU8wmJE@oQYIjz|i?<%jx-Vk^3?;HFY& z)Oh*q3wV|P&fh-Iy1uvMn9MqhV{>zIATZnYBDCsIRlKnrGVe9}FFk0;pM;x7NFtFNEeilrd3Ra%YTE7394%%#L(l zr_cw zaRE%Z*z|?&o(5xloJTD{EGqleDtyhHi3DfK<+2BBU$S;^$a&5?j1hDn;<8#J;+7ZO z@f2a1+*mdw;%+x*@aEMs5_2!lo)btRI}3%ROcjuXnJ!F0SqCQG)5xMS0^r21E)0Gb zWpxJ!xG+Epd-QyDvghMp_QF8B`jiQA@D z74trmj`udD=}=bJPDX9{PEVIoQ&nidrkOOrTYg<08mRNhbfE!UPV&)UcKUjKnk&1<>KVgIcj-x#xs_ znmTwBUq4Yu`)gYIrp%9nTyR}jl4iiE0HG5? zJ$`0j*R5~){;GNoN#8Xvrqn}%TL5rcELKV?`RX#4EwbgZBp?XA_QhE-#d+F+o)s6W z!ns7YT0Nn8*`rK2!s<#~zFP06H>-7&yi%@qZUKJh2MBI`WGM?! z0+!f&5S{A|N3Fq0U?lxsD6#ld+2AnC zEnAA&Eryr!_?0g%4q#!iO7&&qp=o2*-VA=`;JlUD7fQb_4=fp4p@s+RpYq1qSzmc3JbTgoz@er z&&Aam6opgp1RsB>J)#x+`r)eIVcaSahV+7-H=TILcOaX4Qcc$$zW3 zvUpb)0Y7$fX1~DlyrE{w(DVrRA9V6~fC|v_@oO1$xu2r5gQkoYph7jTw>rYuGEJ|# z2y-Cr-Q%3CTHTmfWwHeB?mIUld+5Z#~n z@sY@TB>Qs+qf$rTvUDv(H<%2B64(F>u?4J#0Y+Pq5QGI5#u`G!^vq?)fX$emc3>#) zW2h%H>F5BuK{&I=fmzE)Se1 z2fiPgAX1otlh@IvW?-^P1NV2G*r<`uqyBJ1Ta~JV^A-4|ZLBXFW&l;)y#u}dY^**v z)7ANxu{;lO*VN!S*K0!k(#Y=$LPKb-^~q17R;SembHGW^TmyT`Ur4vfdr<0u%~ICd zf|}-01ng@Uz!*3(0;=s zZ6<^+ESPYwTn4>tWY}EugP+df?Bol0_V^2U^WwL(uSz06yKT7-Wz*a@`bgBlyrb~< zDFu1h!a7R~zpWTM&LooewMBC-5q@M+3ZqO)y(ljL%P(8#o}Ynf@cBb?wFk2L8My-I zEpX@k#3@%h)x}&E3(fCtO3U^A?vuZ-o3a+tD3VMU+ql(yz;_iw;ls6`Kh70^}h;9ZC zm49E)x@!Qb`T2JV1R8AlSSh1eqiu$%bbvuyqo5MXX6ZD8O_PBxs6G+@*sw#(^~85? zJQ~YHM8JoegRe1|Y}T#q*0ihC>lfLY`}{YwNjL%@#EI7MZm%!Q|B)t@6@ehTv?OV7 z&tEPThUpc`WlTV9f{YC{M9buLYm zt@tS)H4ayG1bLBI7by8tU8`-YApo8xH}=zFCC0CU8{5t>BF}s@@QY^faMoW7wmFL4 zPne#HzVcUs3pf`M4Pa0QF0h7a-5TR0l%4lUs*!s#h(aX-xUfl zie9p;Umi+?8v^*qD>jH=OgvzA#Q2z9;gYmzcTSO5o__gDxVm^L&czuJ!^GQ5=CoSf zXMG>2Yfhr`7@#Z_kt4bLH2Pn<3+!2|OA=Y8i?#QHm>=)fwyjM5HNaqfJE%5LmwxeS z88iTDu&ezq`6Y^N&V}o1gP4a(=!m}6?^0J=cCU@FH_!ZV=p0&_01mtU-P3K{V88*# zKIEQ@uX6_N7+7_wgtP~pNP7&iD1J0WN&P6v#*784~_v^cq_jWqqyiqZzVS1!=&Q5 zUz@8wc|83waQW!Y!85|3tcxA9<6u#i$$4AETm~6teHfeofLCOko;-!qH{Za^r@w}? zw_oRcYYH%ctTILxmydFP(Wa2N^BVd};zOct;IQ*FS4+fNp8AHOyWq(#05q01)oJQX zh|G|joHyqJej3mqx(6?FYVr%^cVO$ld*HV}_1s+ykQ}sBz}2v<*?GHWFXN*FL#NHw zUkB;zLN8xvYJDGI_I?wqVp4T~=}_02nE_&Hl88_RH=yS+6|nPLT$Q+V6Eu!GjgW~SO;;pc+5IUhyXc zKu^4igR^#e%WVh-utD^Uj^*(^s!N54c!f#vJ)^q{0m{UCA<)`c`6Tem;{0kg6foM- zhEYHP3J}0H*C!b$*Kk5^EWd)cufEQVOZQLNszstq9+)O^_EbMf{{VP`(EGRD@l-*a zBrjujWc{%7wZa*9N2@!|b35KR_O}CX884LqbdJsQfb^l}x2+M}Gn7G{D&GeKzp6|h z4r~T&asGPE*rfYj&Nr}Bu|R#{q1?lqk-BfG&v0f|&;xNWRBisQ5>8wZZbK{!Ae7(u zZxi||E$Pz^h<-y3`fhqo7EBp#pmRKS-1)j7JElKV<3d9<4D<5Syw16B%ty!K%v{`H zqJ*s)%bHboY#wMGFKtN~G@O%jo~~ACK*jD%R1IZ7g~I}uys9!C5=SafOxd$i_`D|2HZ9UrdG-A%kt2CdV*$a=jm;K`T2$e&+x z2&yFE<;5~f+fjxi*X<(O1_ur)7z-7vt}^I)WrgbQ^r2Z`SQMo>mfu=jTu#NwnOAt| zq)`DtH2}1Zmi2)<@A@@(h92DYp>s`>9N@KvlDUWtbASvE>J<1oAiK!+LIbcN!Xb>V zEAHMBd=5$Tl^Ba9!p*XwufGq%t&})djW_|gVPG>R*)aVYzjT7!HTPgSZ369;<6%pJ zj(C6-#dwQ%h3$EuPaQx-08~G~ST-XcO5jr6n}aN%Wo1Vl5qi$z{7fI~h%R6T3HrCh z!-F!&gMfl={!_063D)8IaDCli%#y;Z5o~= z=;$S^FJHrpZ@$Q4?iX-=_KX0L9gR2kKm`1hwQ?u#N_%?A`!xEIs?XLeUdncq#_K-L zS7np(t;7SY#oj(pSXvT!NYa@!lwwgoP5F0o0@fGXCG)z67gR<}*3c~{@&d!{W19yN~X@%kVsLwdf zIHnkjv#jbSYv2p|Qk0oIx);S67$y^?y$|E4>vM-dAc^H|x7k>MK713d+E|nI7XRM7 z{0g3Z_4BOXd(8W1M1GLWzGUVWa5r75g0qh_6G}dauC1YHLCRBBtC&p~1{!JF6>BfM zx||XKYCJ#gBkyb;>mgMpAkXl;h~xpH1;ROavF--k3mo?VR4jw91~u68+rZrF)vR%$ zo?Z%dem5~yny&WxnRWayR;P6yobO-^K2V3(t;HK3ROf8Qfl8Gj^=Q=cRutA@lEOv;J6y6h3{Ko# z$>v1ILPpm92cME;@mH<5f<10G(J8f#OYOg2*e0DxGKf|oV8LLVzZ zz}4k5Vp`ZPUY-UNx*rV==nPGOi+{3Yt$xcKh=K2?x(^C47QotdWjG@c{XB$Ls6y{E6!f3_*q?boBBE+>?G^Y;YH`5h4UzyTDXL(5uy8|JL920tl# zru%edrS|$IQP6>30m7TWW)HB|r(JU+94>}`+vM3D%$J$@eoB5nU3a>s%2j?FGcfb{ zqpe~mSHCML&8)T2xqca-)@-gS9#rSAt4gXiCNq~5#+YpB-^doIRf3n8Q7p`7CIJfwIoz z`Wc}$9vBGNZx!cl)8_I7WsvN61EjPOE3dVYS9r85IbvzYoPD)mv;LoQ0OS5`fC-BfjCaUjc9wV^M;J+RsE=$mh z0}UqR8PIj{=rtuu4dx4Kj>jrpq*-e~)f!axq?dsb8y}Yvych}q?LHi>ah-usmGg$K z^klsBQ-QNny`%)*xIsRI0jm6!?y&i-)Wg+VYy|d~D0#MdQ>xz*|uLN%PVna@70fz=x zu*rZ@C-7#_&{sS8v*m5NwpVv;^Trhag4Td%eF$Av2c@6ubM^03#=F&N=OfJBNDTP+ zx0fbhmfyE~83ap4Fg+Fb4~*jU^9#&fuKpr&?bq`Fp=jtX0AU48j^mGo&W(l8z8cd(mgsbbuhlPv5Vp z2KB=DbliJNiy|!K}6*MJiZ@rdjSD!u;y; ztpbS92guMomrj}OWO1t$ZUbzGp;_hg7VPSULaXvab+2h(V@kFnb|wQTJ!$X8RF&Jl zGkV>!p0a6=0G7YDEssG^uks+Mw*gn0n5=A}ui3sb0iB=-4f>}8Z zpf5y>4gjM?ajEoyLB#E#AR}xtnXex?T?bp5N2^lCRavp2;J4edsJq<+xVpH==XV)6 z-olFvd|&_iXK?!FD~iC3d5uM_^wCORp(%fmIt^Gt5u+?#A1A$+m3vOHnp+LnJp&3e zofH9?OmH~Bknye2Dox_=nbgnun33vW^`e93(TCo?j4hDW=gWjv+Bv^2v|!?18V@L; z1;!pr3?6J_0m2a4zL}wvVS*2B*17Kb^mkGrk6MbL}sG$o? zy)tX2)E+Ap^i$|uqsLNO{2dM>fbWo;&Mj~sSAKcE-88IuZ2N$uCIUml=o)>V<6iA` zd@bgmpqL>ReG%K=y}ETw?&_Su-){uiV`U$Cd&;peJK9%6I;k|ch@1jm3BZfIwTK%^ zer8a14jkLFvLXQxmo=5?h{0(^MhA9cW@{^2Vuw{Et1cHADB|)o@je?Ek_vSt+x07W z@#J5^lP`Zsd+F|`OJ1=di?^c!M`?=$A&9HGI#;xbVpDv2=pz>jp*D0sEpH|*ydZNePt=t&vh}$eY8x(E7_p~lNDQr zd2?>8SJO1ldXNQK4Iz5*4wmXvqe%?9B$JPZZk-9#SCWl6AUD7B@Ck)m%H&?=0hneJ z48I~RXgR{MFIiRPx%e@|(PU!T_u}B_(BC(94IxtJyB1lA*iGq*?G5&ZqL+Zc65k)wZMo z>RzV3-~v$VDmQc7E(UO(JRwQjX0hk9}f;npu590+!Y0^P0Z z>6FPldfHn~k!+H}P@ztstj%<9T9w!H={Y}b1>Q%b(Z#_`1K=6DMU}QT`N^pU+qPa~ z-PZm+cU|c~$Kv854Ydf%GN{xVEDSMvQ5hsZF*5t)=v!Vc17- z$fEBNiM#B;jQzoe4P2v(U^bBj_x${M2EKm?w(F7qV4ke(UvX5_@%t8|#flr4ZV6mV*Ma4P(a4_8B}#xvHL-Ceoqd_dTndLvcBb}%(l)pErIO2 z0o%dX_p&YO(Ri#?eseP6nn>zcGeCKF>dNZSRxNv^_ga4^3&iR-LxLaxm29G$TZ*|n zesFaiD_$We;HgVwZJ~uD{$vFJ*#Rx;;1$^Fw6EuvWN_ zM`nHqew$+SU~9D2YXiW8a|=){n0P=7vpgP*pt*;Nu`V)7RVz4M3mDi`{Z$z`_JeXy z?A`}@JtNDktimLeia;6Phosv8U5{~hnI$#nfO1os132svG_{|dpJ^(a5-||^YAs-? zy4xhJmdgq4xJq-|j-JOaxRc?uD~&OBD5Jx@16HOm%mT_uK#3A_>|9>MB3 z1K?4l;t>-jY4g=ZW_w%glqnkpp20Vn@jd_gZ%EYLN-Vwr3flN($6%G5C>5fF!8h;= zZLk7;2r90EeP@SI2Nde(7XXS=v z=vL`a5S-_$782YtrPj$;Yqv({%90jO1K=@uVDO&r4j_Hi!@1FxaP`i=& z!H)b8QRjz#iEG-&<1Iy_Au%NRRUQD~EWLiP)J$j&aF(Y%=JSQ--WAl!ky-hL;q}0$ zOg7MIQ<%TBAvE|2#%>nT9-cu%MN(z zM^e_==I75*qpAe`Z?=@pbXMxKXCde#RJy#N>8`)(oM%-8TB|QG^Uu3K9Uu9AEF~__^MymT0Q)OeJzJ7UJF|n6+>B~3RJum33 zTGy7s3O!hQaZy3F3^HY-wvt63Df>ZfWe<-lvi7d8UrA(_OY!v!pdq|^Fa8{`0csF~ zCQl1|?RB9kBh;WjD;uhNmmGS+^%c19t%|^bURW~F^zH>_-%FmV&iY!dYbI*@{tbNq zUas?QlR6mRF4YXJb=k3Ovd%WlkC#a<_%Z>yZY;5OmM&HnN)ezF?4W)>Eb(H3+L4(o#bbMMC31@2 zAx`hdUgXBLM*&b?Mg}jN9QeFEKsi^jK>4mg8&ai6_Ai}^y&KxY1H)Ra$=B}-^;qbB>)Kpq}&l$vdG#{^XdZa3n$!!PJ63K2FmyXXjy5j z-^KEbz?Bm!T|f=O4O^*RU|&Bp`Szq+F~IK{EIm-Tqg^9Na-dL;KYdnac?G^N!l^+E zh19X)La;r8x!ZXU5NnHM6QiQ7{7~9Af$e!iIqY325>Kk`OOKU(M#$h1$}_I-u@fu; z$&di1?*%+FS_J?m@(P&6&|!q`cllEm7{Ko?P=f zkh;6z{vzA$l|*(yf4|Fob}K`Up8*0px3`Y?(q|^d)O;JN`>S5`xX@OAX_%E;)g5Z^ ztLh7NnRD<)LisX={Tnb3%rOPe93 z`hZ6;P|>+mjUP!TxXA%*ZKSYc)4YDUg#a}Zov+yiS61D;0JT^<&$r;lMX*@vq?P zU;T49JNb$%qKQJhg8+dxUj3E^30PnjD|}cnT05YyFX!+a>{xjsOh~}s|;jVP6o0qpoV!qUw+ZoYVvwdC@*7Mo3`DDX9@)jwfpB{aw~>cFt7+FdO9`- z!@}?S`#ylZk#)jyljuHEdjw=C^{vLf1k=?8sKRDR89|n2wmx>1im7Qs5wkmn3m(_H zjYKFR_g#hp-lZ&ezU+|LF4rrMVP5BwkqdKwlSn?}bELW`|%kK4>T^ z{3n-c9Yun(JR~x%_?ONx+2DK<6&QnwYn(^BL|%|0;zl8rdTyv5Rw!+Wi`S;yUb$m>uk|hhKqOM_D7M2%$u6K=TXjqYj=eHOJ{x2V`8=VT!V)}cyN6cVE%Fh z1FxWc-YXBlSekb+DtA%0L;E%a_d*0%dY5B}P_sFCX0BfS+H>hJxCEGs*sxG<`yA>_ za{{u^_@*s~vcanM*|?auDeNs@0f|LZ?_jJtLDxcYQ!x%IgF)FjdRJaY9`Y1 z3mna4g6~K*r?ld%)FTJmfzFxq zT96xyGQWG7_1$M3-@t%JQCc$dL&L_|>6TOgxSC_TK7-dUehy#$>Yq|{7Sw;WvcGmR zzk?B4reN!GJzI^?D)jAzo4?ROUflA6R@UQ|E!1G+MQVQj>KY?G4L&q zp}!yLFyjdGkmv^D^J7rmTXm!{c32xjb>8|XHuu8E+Wza+AACQS$sx@08Sn+D3>|@A zxLH1L^;QP1`IYVYGOISJac<63P0#B^C2vsZwR;X)i+a7#w#69CzI<(C8Sgt_T+-p; z^R0O2@5gQk^?40DCVlH!mj^Lv6lmZO)m7Vj3+CoTrvvz)ycV@QL2K>R2}^N>4vCm+ z#u7ZPOF{uSUS{p&ed7dz?RR4Q$o_F4021B4yUGg1?PZWpDTQMPj>Ul)efd@y{6<;1 zfo(^NF6#EqPj|G9<1k`uz7u%%_+P`5-~J1D`}#|AV7A7~axg#0b#^aIqY+<1ZxbH_ zuTX)W*8@860~4`o)}x?n^;LP24G04QZgUX{5|;tw>vsj$S1+^J`%1)K8B7q0OOI6( zx-VPL%4^4)mvArmIbZ>wFZcpF_2_k8rx*InuK`HkCJVL^s=AD&HFe7QIBTChJ0Q`^ z?yF=2pL`$7efXGm_OM}D-Ox#g0Nuj%Z9vjK@CgVl0q|m)TWO&Mp7JcEHEmR9n2XXX zY1;GB?+SWaps+*%M`MWodABpb9K;H^8MTuW{`q;ZJfKX7>IdjWUGtT*z@AP-7NY|> zFAvAW_;9VR>iA;dxeptQ`n~JRi2{-CGUIucb$s7^`4{lw>A%Y7-b&k8r1qP52M>5) z025reeGd@90ipNZ3!!Cp9t0f7Nq2xgH230`Hh2eCu|SnR0&OpV83r(^NU@QyR&QvT z8!vHN13Q9`Q1qJa<%8Kv5N4mP$N>lg_xw70xhwF4I)4S`asFbK{(|OO?%R2LpsK5s zU4bAtpf(`2mj&Eo(0*5tD-|?tYFKa&`I3ExIM)f9TSTbtvs?ZW0N#}LTo(?_7X)=~ zS8?;R1E9%UPW9PLQ0rG!=#*SVzn#D$&6o%(4F+93RYc_&1&kaJib$rChd~*VT6EQUR~?ucC{fJC-x!?*jT^YPE|yIOj$Gz; zH=G1ATzxdStv(Mn)x;$IQ;Rn4zQSC%^^=ig zwEQqT45(kf=yyoRv0;Q^-n+Cd67)$Wa9AL4~gOawX@sMcLEoFZY zWl1V>mit%WGsA_SQFtx!ASK~d6V+LfI{JsL!ez-CxR`_v*o%=Q36#pStK$y}!wl?0 zY>JJ2lY>0(#;VN#SVeb^VqF~z`->7Hp26}S1tMJ?M_I;ZYK8UHM63_nv03Au8;{}Z z-~O`tolr-su7DymfE3(I2X5_dF<1c9 zqHk~==3Yqp%@4COZfG0ST9zzo%apFkrx6VvxW<<~;T2F48+!sj*kzqwnB6yMn}huV z2+$LeXXQEuH!}|P>h~{lmA?jvS{Dn#xTFuor?0vv>Ea3`k_SPnvkOFiqO{9pytG+E zd44m4g|?vuSxPN?hJ|)~`{V?bN}Md?jSf^F2PG9f?e|=i4F$O92T#c0o=IvNpv@BB z)N<}5v=v;Xqh!$2wYplig1zm#!;>_N?plV{!OvlEI?1UpLA@Jmq&_#ta2t{N Z{{`GP`4DG;+YSH#002ovPDHLkV1i56lCJ;& literal 0 HcmV?d00001 diff --git a/packages/website/src/components/PWA.astro b/packages/website/src/components/PWA.astro index e69de29bb..1b1fcbea1 100644 --- a/packages/website/src/components/PWA.astro +++ b/packages/website/src/components/PWA.astro @@ -0,0 +1,33 @@ +--- +import { pwaInfo } from "virtual:pwa-info"; +--- + + + +{pwaInfo && } diff --git a/packages/website/src/components/PWAPrompter.astro b/packages/website/src/components/PWAPrompter.astro new file mode 100644 index 000000000..713f8123b --- /dev/null +++ b/packages/website/src/components/PWAPrompter.astro @@ -0,0 +1,102 @@ +--- +import { DownloadIcon } from "@radix-ui/react-icons"; +import { + Badge, + Box, + Button, + Card, + Flex, + Inset, + Link, + Spinner, + Text, +} from "@radix-ui/themes"; +import { getStrings } from "../core/i18n/getStrings"; +import type { LocaleAcceptorProps } from "../hooks/useLocale"; + +type Props = LocaleAcceptorProps; + +const { locale } = Astro.props; +const strings = getStrings(locale); +--- + + + + + + + + + + + + + + + {strings.website.home.pwa.title} + + + {strings.website.home.pwa.new} + + + + + + + {strings.website.home.pwa.checking} + + + + + {strings.website.home.pwa.incompatible}{" "} + + {strings.website.home.pwa.incompatible_help} + + + + + + + + + diff --git a/packages/website/src/pages/[...locale]/index.astro b/packages/website/src/pages/[...locale]/index.astro index af513a94d..c8ebc3df8 100644 --- a/packages/website/src/pages/[...locale]/index.astro +++ b/packages/website/src/pages/[...locale]/index.astro @@ -8,6 +8,7 @@ import type { GetStaticPaths } from "astro"; import { AesonPlug } from "../../components/AesonPlug"; import HomeHero from "../../components/HomeHero.astro"; import { Plugs } from "../../components/Plugs"; +import PWAPrompter from "../../components/PWAPrompter.astro"; import ToolCard from "../../components/ToolCard.astro"; import { tools, type Tool } from "../../constants/tools"; import { getStrings } from "../../core/i18n/getStrings"; @@ -64,6 +65,8 @@ export const getStaticPaths = (() => { + +