├── frontend ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── img │ │ └── icons │ │ │ ├── favicon.ico │ │ │ ├── apple-icon-180.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-150x150.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── manifest-icon-192.png │ │ │ ├── manifest-icon-512.png │ │ │ ├── apple-splash-1136-640.jpg │ │ │ ├── apple-splash-1334-750.jpg │ │ │ ├── apple-splash-1792-828.jpg │ │ │ ├── apple-splash-640-1136.jpg │ │ │ ├── apple-splash-750-1334.jpg │ │ │ ├── apple-splash-828-1792.jpg │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-splash-1125-2436.jpg │ │ │ ├── apple-splash-1170-2532.jpg │ │ │ ├── apple-splash-1242-2208.jpg │ │ │ ├── apple-splash-1242-2688.jpg │ │ │ ├── apple-splash-1284-2778.jpg │ │ │ ├── apple-splash-1536-2048.jpg │ │ │ ├── apple-splash-1620-2160.jpg │ │ │ ├── apple-splash-1668-2224.jpg │ │ │ ├── apple-splash-1668-2388.jpg │ │ │ ├── apple-splash-2048-1536.jpg │ │ │ ├── apple-splash-2048-2732.jpg │ │ │ ├── apple-splash-2160-1620.jpg │ │ │ ├── apple-splash-2208-1242.jpg │ │ │ ├── apple-splash-2224-1668.jpg │ │ │ ├── apple-splash-2388-1668.jpg │ │ │ ├── apple-splash-2436-1125.jpg │ │ │ ├── apple-splash-2532-1170.jpg │ │ │ ├── apple-splash-2688-1242.jpg │ │ │ ├── apple-splash-2732-2048.jpg │ │ │ ├── apple-splash-2778-1284.jpg │ │ │ ├── apple-touch-icon-114x114.png │ │ │ ├── apple-touch-icon-120x120.png │ │ │ ├── apple-touch-icon-144x144.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-180x180.png │ │ │ ├── apple-touch-icon-57x57.png │ │ │ ├── apple-touch-icon-60x60.png │ │ │ ├── apple-touch-icon-72x72.png │ │ │ ├── apple-touch-icon-76x76.png │ │ │ ├── msapplication-icon-144x144.png │ │ │ ├── android-chrome-maskable-192x192.png │ │ │ ├── android-chrome-maskable-512x512.png │ │ │ ├── safari-pinned-tab.svg │ │ │ └── logo-light.svg │ ├── manifest.json │ └── index.html ├── babel.config.js ├── src │ ├── views │ │ ├── About.vue │ │ └── Home.vue │ ├── store │ │ └── index.js │ ├── plugins │ │ └── vuetify.js │ ├── main.js │ ├── App.vue │ ├── components │ │ ├── layout │ │ │ └── TopBar.vue │ │ ├── main │ │ │ └── home.vue │ │ └── builder │ │ │ ├── import_components │ │ │ ├── import_export.vue │ │ │ └── import_portainer.vue │ │ │ ├── app_components │ │ │ ├── app_environment.vue │ │ │ ├── app_storage.vue │ │ │ ├── app_general.vue │ │ │ ├── app_networking.vue │ │ │ └── app_advanced.vue │ │ │ └── builder.vue │ ├── router │ │ └── index.js │ ├── registerServiceWorker.js │ ├── assets │ │ ├── logo.svg │ │ └── js │ │ │ ├── importTemplate.js │ │ │ └── templateGenerator.js │ ├── sw.js │ ├── sw.js.map │ ├── workbox-f163abaa.js │ └── workbox-f163abaa.js.map ├── vue.config.js ├── workbox-config.js ├── .gitignore ├── README.md └── package.json ├── .gitignore ├── root └── etc │ ├── cont-init.d │ └── 30-config │ └── services.d │ └── nginx │ └── run ├── README.md ├── Dockerfile └── nginx.conf /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .github 2 | .vscode 3 | sql_app.db 4 | venv 5 | *.db 6 | node_modules 7 | config 8 | *.pyc -------------------------------------------------------------------------------- /frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"] 3 | }; 4 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /root/etc/cont-init.d/30-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | # permissions 4 | chown -R abc:abc \ 5 | /app -------------------------------------------------------------------------------- /frontend/public/img/icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/favicon.ico -------------------------------------------------------------------------------- /frontend/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-icon-180.png -------------------------------------------------------------------------------- /frontend/public/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /frontend/public/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transpileDependencies: ["vuetify"], 3 | 4 | pwa: { 5 | name: 'Shipwright' 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/public/img/icons/manifest-icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/manifest-icon-192.png -------------------------------------------------------------------------------- /frontend/public/img/icons/manifest-icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/manifest-icon-512.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1136-640.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1136-640.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1334-750.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1334-750.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1792-828.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1792-828.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-640-1136.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-640-1136.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-750-1334.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-750-1334.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-828-1792.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-828-1792.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/public/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1125-2436.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1125-2436.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1170-2532.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1170-2532.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1242-2208.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1242-2208.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1242-2688.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1242-2688.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1284-2778.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1284-2778.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1536-2048.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1536-2048.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1620-2160.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1620-2160.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1668-2224.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1668-2224.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-1668-2388.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-1668-2388.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2048-1536.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2048-1536.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2048-2732.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2048-2732.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2160-1620.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2160-1620.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2208-1242.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2208-1242.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2224-1668.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2224-1668.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2388-1668.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2388-1668.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2436-1125.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2436-1125.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2532-1170.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2532-1170.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2688-1242.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2688-1242.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2732-2048.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2732-2048.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-splash-2778-1284.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-splash-2778-1284.jpg -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /frontend/public/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /frontend/public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /frontend/public/img/icons/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /frontend/public/img/icons/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SelfhostedPro/Shipwright/HEAD/frontend/public/img/icons/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /frontend/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /root/etc/services.d/nginx/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | 3 | #killall nginx 4 | 5 | if pgrep -f "[n]ginx:" > /dev/null; then 6 | pkill -ef [n]ginx: 7 | fi 8 | 9 | exec nginx -c /etc/nginx/nginx.conf -g "daemon off;" -------------------------------------------------------------------------------- /frontend/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: {}, 8 | mutations: {}, 9 | actions: {}, 10 | modules: {} 11 | }); 12 | -------------------------------------------------------------------------------- /frontend/workbox-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globDirectory: 'src/', 3 | globPatterns: [ 4 | '**/*.{vue,js,svg}' 5 | ], 6 | ignoreURLParametersMatching: [ 7 | /^utm_/, 8 | /^fbclid$/ 9 | ], 10 | swDest: 'src/sw.js' 11 | }; -------------------------------------------------------------------------------- /frontend/public/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuetify from "vuetify/lib"; 3 | 4 | Vue.use(Vuetify); 5 | 6 | export default new Vuetify({ 7 | theme: { 8 | themes: { 9 | dark: { 10 | primary: "#41b883" 11 | } 12 | }, 13 | dark: true 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | import vuetify from "./plugins/vuetify"; 6 | import "./registerServiceWorker"; 7 | 8 | Vue.config.productionTip = false; 9 | 10 | new Vue({ 11 | router, 12 | store, 13 | vuetify, 14 | render: h => h(App) 15 | }).$mount("#app"); 16 | -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shipwright 2 | 3 | ### Into 4 | This is a website where you can use a WebUI to create templates for some of the popular docker managment utilities (yacht, portainer, unraid, docker-compose) It's still very much a work in progress but feel free to take a look. Once it's functioning at a basic level I'll be deploying this so anyone can use it 100% free (possibly ad supported). The readme in the frontend folder will tell you how to install and setup Shipwright. -------------------------------------------------------------------------------- /frontend/src/components/layout/TopBar.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 27 | -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Shipwright", 3 | "short_name": "Shipwright", 4 | "start_url": "index.html", 5 | "display": "standalone", 6 | "theme_color": "#41B883", 7 | "background_color": "#000", 8 | "icons": [ 9 | { 10 | "src": "img/icons/manifest-icon-192.png", 11 | "sizes": "192x192", 12 | "type": "image/png", 13 | "purpose": "maskable any" 14 | }, 15 | { 16 | "src": "img/icons/manifest-icon-512.png", 17 | "sizes": "512x512", 18 | "type": "image/png", 19 | "purpose": "maskable any" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build Vue 2 | FROM node:14.5.0-alpine as build-stage 3 | 4 | WORKDIR /app 5 | COPY ./frontend/package*.json ./ 6 | RUN npm install 7 | COPY ./frontend/ . 8 | RUN npm run build 9 | 10 | # Setup Container 11 | FROM lsiobase/alpine:3.12 as deploy-stage 12 | # MAINTANER Your Name "info@selfhosted.pro" 13 | 14 | # Set Variables 15 | ENV PYTHONIOENCODING=UTF-8 16 | ENV THEME=Default 17 | 18 | # Install Dependancies 19 | RUN \ 20 | echo "**** install packages ****" && \ 21 | apk add --no-cache \ 22 | nginx &&\ 23 | echo "**** Cleaning Up ****" &&\ 24 | rm -rf \ 25 | /root/.cache \ 26 | /tmp/* 27 | 28 | # Vue 29 | COPY --from=build-stage /app/dist /app 30 | COPY nginx.conf /etc/nginx/ 31 | 32 | COPY /root / 33 | 34 | # Expose 35 | VOLUME /config 36 | EXPOSE 8000 -------------------------------------------------------------------------------- /frontend/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import Home from "../views/Home.vue"; 4 | import home from "../components/main/home.vue"; 5 | import builder from "../components/builder/builder.vue"; 6 | 7 | Vue.use(VueRouter); 8 | 9 | const routes = [ 10 | { 11 | path: "/", 12 | component: Home, 13 | children: [ 14 | { 15 | path: "", 16 | name: "Home", 17 | component: home 18 | }, 19 | { 20 | path: "/builder", 21 | component: builder, 22 | name: "builder" 23 | } 24 | ] 25 | } 26 | ]; 27 | 28 | const router = new VueRouter({ 29 | mode: "history", 30 | base: process.env.BASE_URL, 31 | routes 32 | }); 33 | 34 | export default router; 35 | -------------------------------------------------------------------------------- /frontend/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import { register } from "register-service-worker"; 4 | 5 | if (process.env.NODE_ENV === "production") { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready() { 8 | console.log( 9 | "App is being served from cache by a service worker.\n" + 10 | "For more details, visit https://goo.gl/AFskqB" 11 | ); 12 | }, 13 | registered() { 14 | console.log("Service worker has been registered."); 15 | }, 16 | cached() { 17 | console.log("Content has been cached for offline use."); 18 | }, 19 | updatefound() { 20 | console.log("New content is downloading."); 21 | }, 22 | updated() { 23 | console.log("New content is available; please refresh."); 24 | }, 25 | offline() { 26 | console.log( 27 | "No internet connection found. App is running in offline mode." 28 | ); 29 | }, 30 | error(error) { 31 | console.error("Error during service worker registration:", error); 32 | } 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | user abc abc; 2 | error_log /var/log/nginx/error.log warn; 3 | pid /var/run/nginx.pid; 4 | 5 | worker_processes 4; 6 | 7 | events { worker_connections 1024; } 8 | 9 | http { 10 | include /etc/nginx/mime.types; 11 | # fallback in case we can't determine a type 12 | default_type application/octet-stream; 13 | access_log /var/log/nginx/access.log combined; 14 | sendfile on; 15 | keepalive_timeout 5; 16 | server { 17 | listen 8000; 18 | root /app; 19 | include /etc/nginx/mime.types; 20 | 21 | location / { 22 | root /app; 23 | index index.html; 24 | try_files $uri $uri/ /index.html; 25 | } 26 | error_page 500 502 503 504 /50x.html; 27 | 28 | location = /50x.html { 29 | root /usr/share/nginx/html; 30 | } 31 | } 32 | } 33 | 34 | 35 | # events { worker_connections 1024; } 36 | 37 | # http { 38 | # ### Set http options 39 | 40 | # # Paths for Vue and FastAPI 41 | # server { 42 | # listen *:8000; 43 | 44 | # # Vue 45 | 46 | 47 | # } 48 | # } -------------------------------------------------------------------------------- /frontend/src/components/main/home.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /frontend/public/img/icons/logo-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/components/builder/import_components/import_export.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 66 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.10.2", 12 | "file-saver": "^2.0.5", 13 | "jszip": "^3.6.0", 14 | "register-service-worker": "^1.7.1", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.5.1", 17 | "vuetify": "^2.4.10", 18 | "vuex": "^3.6.2" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "~4.5.0", 22 | "@vue/cli-plugin-eslint": "~4.5.0", 23 | "@vue/cli-plugin-pwa": "^4.5.12", 24 | "@vue/cli-plugin-router": "~4.5.0", 25 | "@vue/cli-plugin-vuex": "~4.5.0", 26 | "@vue/cli-service": "~4.5.0", 27 | "@vue/eslint-config-prettier": "^6.0.0", 28 | "babel-eslint": "^10.1.0", 29 | "eslint": "^6.7.2", 30 | "eslint-plugin-prettier": "^3.4.0", 31 | "eslint-plugin-vue": "^6.2.2", 32 | "lint-staged": "^9.5.0", 33 | "prettier": "^1.19.1", 34 | "sass": "^1.32.11", 35 | "sass-loader": "^8.0.0", 36 | "vue-cli-plugin-vuetify": "^2.3.1", 37 | "vue-template-compiler": "^2.6.11", 38 | "vuetify-loader": "^1.7.2" 39 | }, 40 | "eslintConfig": { 41 | "root": true, 42 | "env": { 43 | "node": true 44 | }, 45 | "extends": [ 46 | "plugin:vue/essential", 47 | "eslint:recommended", 48 | "@vue/prettier" 49 | ], 50 | "parserOptions": { 51 | "parser": "babel-eslint" 52 | }, 53 | "rules": {} 54 | }, 55 | "browserslist": [ 56 | "> 1%", 57 | "last 2 versions", 58 | "not dead" 59 | ], 60 | "gitHooks": { 61 | "pre-commit": "lint-staged" 62 | }, 63 | "lint-staged": { 64 | "*.{js,jsx,vue}": [ 65 | "vue-cli-service lint", 66 | "git add" 67 | ] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /frontend/src/components/builder/app_components/app_environment.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /frontend/src/components/builder/import_components/import_portainer.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 73 | -------------------------------------------------------------------------------- /frontend/src/components/builder/app_components/app_storage.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 77 | -------------------------------------------------------------------------------- /frontend/src/components/builder/app_components/app_general.vue: -------------------------------------------------------------------------------- 1 | 82 | 83 | 88 | -------------------------------------------------------------------------------- /frontend/src/sw.js: -------------------------------------------------------------------------------- 1 | if(!self.define){const e=e=>{"require"!==e&&(e+=".js");let r=Promise.resolve();return o[e]||(r=new Promise((async r=>{if("document"in self){const o=document.createElement("script");o.src=e,document.head.appendChild(o),o.onload=r}else importScripts(e),r()}))),r.then((()=>{if(!o[e])throw new Error(`Module ${e} didn’t register its module`);return o[e]}))},r=(r,o)=>{Promise.all(r.map(e)).then((e=>o(1===e.length?e[0]:e)))},o={require:Promise.resolve(r)};self.define=(r,s,i)=>{o[r]||(o[r]=Promise.resolve().then((()=>{let o={};const n={uri:location.origin+r.slice(1)};return Promise.all(s.map((r=>{switch(r){case"exports":return o;case"module":return n;default:return e(r)}}))).then((e=>{const r=i(...e);return o.default||(o.default=r),o}))})))}}define("./sw.js",["./workbox-f163abaa"],(function(e){"use strict";self.addEventListener("message",(e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()})),e.precacheAndRoute([{url:"App.vue",revision:"87e4299a98d07d8c112a114ddb372437"},{url:"assets/js/templateGenerator.js",revision:"f407012b384e712a915f776ad5f773fc"},{url:"assets/logo.svg",revision:"60ff54d9dbc103501aba15a7a5e6e0fd"},{url:"components/builder/app_components/app_advanced.vue",revision:"b190faecf9625b4345e5ab08ba5e402f"},{url:"components/builder/app_components/app_environment.vue",revision:"8bb84b785631c38913bea24348b5b684"},{url:"components/builder/app_components/app_general.vue",revision:"f57548b534794fa7c892b6f50c759b7c"},{url:"components/builder/app_components/app_networking.vue",revision:"b0a624d917e92e1e6798dbe9116869a4"},{url:"components/builder/app_components/app_storage.vue",revision:"75d5c483642b650d4d957b3c938a1cbc"},{url:"components/builder/builder.vue",revision:"5eab6e5d29b9da24676b89f1a5f76396"},{url:"components/layout/TopBar.vue",revision:"449712ab0eed792d2ab4ff7f54ffb2ae"},{url:"components/main/home.vue",revision:"b47e25bb21ee49d66abe3995f3616e44"},{url:"main.js",revision:"be4e6eb3ec7a29e28fff2f5bc0acd33d"},{url:"plugins/vuetify.js",revision:"495d097a24b05e2274ca44091f9b7857"},{url:"registerServiceWorker.js",revision:"0ff849d18bb23c5a386f02f93a3183a4"},{url:"router/index.js",revision:"aa6fe70986943a7fe8518b8669851b8b"},{url:"store/index.js",revision:"a7f230e18d45acac693813088fbf10fe"},{url:"views/About.vue",revision:"d88b0aff741f94d016116101462e384e"},{url:"views/Home.vue",revision:"d493128da081caff6a9764f4fe48ea36"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]})})); 2 | //# sourceMappingURL=sw.js.map 3 | -------------------------------------------------------------------------------- /frontend/src/components/builder/app_components/app_networking.vue: -------------------------------------------------------------------------------- 1 | 86 | 87 | 110 | -------------------------------------------------------------------------------- /frontend/src/sw.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sw.js","sources":["../../../../../../private/var/folders/_0/77k3jnrd62jcmgrf2yd5bht00000gq/T/5dbcd6d7e5070f0696c6453995c4d4dc/sw.js"],"sourcesContent":["import {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/precacheAndRoute.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.addEventListener('message', (event) => {\n if (event.data && event.data.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\n\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"App.vue\",\n \"revision\": \"87e4299a98d07d8c112a114ddb372437\"\n },\n {\n \"url\": \"assets/js/templateGenerator.js\",\n \"revision\": \"f407012b384e712a915f776ad5f773fc\"\n },\n {\n \"url\": \"assets/logo.svg\",\n \"revision\": \"60ff54d9dbc103501aba15a7a5e6e0fd\"\n },\n {\n \"url\": \"components/builder/app_components/app_advanced.vue\",\n \"revision\": \"b190faecf9625b4345e5ab08ba5e402f\"\n },\n {\n \"url\": \"components/builder/app_components/app_environment.vue\",\n \"revision\": \"8bb84b785631c38913bea24348b5b684\"\n },\n {\n \"url\": \"components/builder/app_components/app_general.vue\",\n \"revision\": \"f57548b534794fa7c892b6f50c759b7c\"\n },\n {\n \"url\": \"components/builder/app_components/app_networking.vue\",\n \"revision\": \"b0a624d917e92e1e6798dbe9116869a4\"\n },\n {\n \"url\": \"components/builder/app_components/app_storage.vue\",\n \"revision\": \"75d5c483642b650d4d957b3c938a1cbc\"\n },\n {\n \"url\": \"components/builder/builder.vue\",\n \"revision\": \"5eab6e5d29b9da24676b89f1a5f76396\"\n },\n {\n \"url\": \"components/layout/TopBar.vue\",\n \"revision\": \"449712ab0eed792d2ab4ff7f54ffb2ae\"\n },\n {\n \"url\": \"components/main/home.vue\",\n \"revision\": \"b47e25bb21ee49d66abe3995f3616e44\"\n },\n {\n \"url\": \"main.js\",\n \"revision\": \"be4e6eb3ec7a29e28fff2f5bc0acd33d\"\n },\n {\n \"url\": \"plugins/vuetify.js\",\n \"revision\": \"495d097a24b05e2274ca44091f9b7857\"\n },\n {\n \"url\": \"registerServiceWorker.js\",\n \"revision\": \"0ff849d18bb23c5a386f02f93a3183a4\"\n },\n {\n \"url\": \"router/index.js\",\n \"revision\": \"aa6fe70986943a7fe8518b8669851b8b\"\n },\n {\n \"url\": \"store/index.js\",\n \"revision\": \"a7f230e18d45acac693813088fbf10fe\"\n },\n {\n \"url\": \"views/About.vue\",\n \"revision\": \"d88b0aff741f94d016116101462e384e\"\n },\n {\n \"url\": \"views/Home.vue\",\n \"revision\": \"d493128da081caff6a9764f4fe48ea36\"\n }\n], {\n \"ignoreURLParametersMatching\": [/^utm_/, /^fbclid$/]\n});\n\n\n\n\n\n\n\n\n"],"names":["self","addEventListener","event","data","type","skipWaiting"],"mappings":"0yBAmBAA,KAAKC,iBAAiB,WAAYC,IAC5BA,EAAMC,MAA4B,iBAApBD,EAAMC,KAAKC,MAC3BJ,KAAKK,oCAY2B,CAClC,KACS,mBACK,oCAEd,KACS,0CACK,oCAEd,KACS,2BACK,oCAEd,KACS,8DACK,oCAEd,KACS,iEACK,oCAEd,KACS,6DACK,oCAEd,KACS,gEACK,oCAEd,KACS,6DACK,oCAEd,KACS,0CACK,oCAEd,KACS,wCACK,oCAEd,KACS,oCACK,oCAEd,KACS,mBACK,oCAEd,KACS,8BACK,oCAEd,KACS,oCACK,oCAEd,KACS,2BACK,oCAEd,KACS,0BACK,oCAEd,KACS,2BACK,oCAEd,KACS,0BACK,qCAEb,6BAC8B,CAAC,QAAS"} -------------------------------------------------------------------------------- /frontend/src/assets/js/importTemplate.js: -------------------------------------------------------------------------------- 1 | export async function importTemplate(templateFile) { 2 | let templateContent = JSON.parse(await _readTemplate(templateFile)); 3 | if (templateContent.title){ 4 | return templateContent 5 | } else { 6 | console.error("This file isn't from a Shipwright Export") 7 | } 8 | } 9 | 10 | export async function importPortainer(templateFile) { 11 | let templateContent = JSON.parse(await _readTemplate(templateFile)); 12 | var convertedTemplate = [] 13 | 14 | if (templateContent['version']){ 15 | convertedTemplate = portainerV2Conversion(templateContent) 16 | } else { 17 | convertedTemplate = portainerV1Conversion(templateContent) 18 | } 19 | return convertedTemplate 20 | } 21 | 22 | function portainerV1Conversion(templateContent){ 23 | var app_list = [] 24 | for(let app in templateContent){ 25 | var _template_skeleton = { 26 | title: "", 27 | name: "", 28 | image: "", 29 | description: "", 30 | categories: [], 31 | platform: "linux", 32 | note: "", 33 | restart_policy: "", 34 | ports: [], 35 | volumes: [], 36 | env: [], 37 | command: [], 38 | devices: [], 39 | labels: [], 40 | sysctls: [], 41 | cap_add: [], 42 | } 43 | if (templateContent[app].ports){ 44 | templateContent[app].ports = portainerPorts(templateContent[app].ports) 45 | } 46 | if (templateContent[app].sysctls){ 47 | templateContent[app].sysctls = portainerSysctls(templateContent[app.sysctls]) 48 | } 49 | Object.assign(_template_skeleton, templateContent[app]) 50 | app_list.push(_template_skeleton) 51 | } 52 | return app_list 53 | } 54 | function portainerSysctls(sysctls){ 55 | var sysctl_list = [] 56 | for (let sysctl in sysctls){ 57 | let _sysctl = {'name': sysctl, 'values':sysctls[sysctl]} 58 | sysctl_list.push(_sysctl) 59 | } 60 | } 61 | function portainerPorts(ports){ 62 | var port_list = [] 63 | for (let port in ports){ 64 | if (ports[port].includes(':')){ 65 | let _port = ports[port].split(':') 66 | let hport = _port[0] 67 | let cport = _port[1].split('/')[0] 68 | let proto = _port[1].split('/')[1] 69 | port_list.push({"hport": hport, "cport": cport, "proto":proto}) 70 | } else { 71 | let _port = ports[port].split('/') 72 | let cport = _port[0] 73 | let proto = _port[1] 74 | port_list.push({"cport": cport, "proto":proto}) 75 | } 76 | } 77 | return port_list 78 | } 79 | 80 | function portainerV2Conversion(_templateContent){ 81 | let templateContent = _templateContent['templates'] 82 | let converted_template = portainerV1Conversion(templateContent) 83 | return converted_template 84 | } 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | function _readTemplate(templateFile) { 107 | const reader = new FileReader(); 108 | 109 | return new Promise((resolve, reject) => { 110 | reader.onerror = () => { 111 | reader.abort(); 112 | reject(new DOMException("Problem parsing input file.")); 113 | }; 114 | reader.onload = () => { 115 | resolve(reader.result); 116 | }; 117 | reader.readAsText(templateFile); 118 | }); 119 | } 120 | -------------------------------------------------------------------------------- /frontend/src/assets/js/templateGenerator.js: -------------------------------------------------------------------------------- 1 | import JSZip from "jszip"; 2 | import FileSaver from "file-saver"; 3 | export function generateTemplate(templateObject) { 4 | // const title = templateObject.title 5 | // Deep Clone templateObject so changing attributes here doesn't affect the form 6 | var _yachtTemplateObject = JSON.parse(JSON.stringify(templateObject)); 7 | var _portainerTemplateObject = JSON.parse(JSON.stringify(templateObject)); 8 | 9 | let yachtAppList = convYacht(_yachtTemplateObject); 10 | let portainerAppList = convPortainer(_portainerTemplateObject); 11 | let portainerV2AppListApps = JSON.parse(JSON.stringify(portainerAppList)); 12 | let portainerV2Template = { version: "2", templates: portainerV2AppListApps }; 13 | 14 | let zip = new JSZip(); 15 | zip.file( 16 | _yachtTemplateObject.title + "-yacht.json", 17 | JSON.stringify(yachtAppList, null, 2) 18 | ); 19 | zip.file( 20 | _portainerTemplateObject.title + "-portainer-v1.json", 21 | JSON.stringify(portainerAppList, null, 2) 22 | ); 23 | zip.file( 24 | _portainerTemplateObject.title + "-portainer-v2.json", 25 | JSON.stringify(portainerV2Template, null, 4) 26 | ); 27 | zip.file( 28 | templateObject.title + "-export.json", 29 | JSON.stringify(templateObject, null, 2) 30 | ) 31 | zip.generateAsync({ type: "blob" }).then(function(content) { 32 | FileSaver.saveAs(content, templateObject.title + ".zip"); 33 | }); 34 | } 35 | 36 | function convPorts(ports, app) { 37 | var _port_list = []; 38 | // Convert ports for Yacht 39 | if (app === "yacht") { 40 | for (let port in ports) { 41 | // If host port then you need to include that 42 | if (ports[port].hport) { 43 | // If there's a label make sure to convert it to an object 44 | if (ports[port].label && ports[port].label.length > 0) { 45 | let _port_object = {} 46 | _port_object[ 47 | ports[port].label 48 | ] = `${ports[port].hport}:${ports[port].cport}/${ports[port].proto}`; 49 | _port_list.push(_port_object) 50 | } else { 51 | _port_list.push( 52 | `${ports[port].hport}:${ports[port].cport}/${ports[port].proto}` 53 | ); 54 | } 55 | } else { 56 | if (ports[port].label && ports[port].label.length > 0) { 57 | let _port_object = {} 58 | _port_object[ 59 | ports[port].label 60 | ] = `${ports[port].cport}/${ports[port].proto}`; 61 | _port_list.push(_port_object) 62 | } else { 63 | _port_list.push(`${ports[port].cport}/${ports[port].proto}`); 64 | } 65 | } 66 | } 67 | } else if (app === "portainer_v1") { 68 | for (let port in ports) { 69 | if (ports[port].hport) { 70 | _port_list.push( 71 | `${ports[port].hport}:${ports[port].cport}/${ports[port].proto}` 72 | ); 73 | } else { 74 | _port_list.push(`${ports[port].cport}/${ports[port].proto}`); 75 | } 76 | } 77 | } 78 | return _port_list; 79 | } 80 | 81 | function convVolumes(volumes, app) { 82 | var _volume_list = []; 83 | for (let volume in volumes) { 84 | let _volume = volumes[volume]; 85 | if (volumes[volume].variable && app == "yacht") { 86 | _volume.bind = volumes[volume].variable; 87 | delete _volume.variable; 88 | } else { 89 | delete _volume.variable; 90 | } 91 | _volume_list.push(_volume); 92 | } 93 | return _volume_list; 94 | } 95 | 96 | function convPortainer(templateObject) { 97 | var portainerAppList = []; 98 | for (let app in templateObject.containers) { 99 | templateObject.containers[app]["type"] = 1; 100 | if ( 101 | templateObject.containers[app].ports && 102 | templateObject.containers[app].ports.length > 0 103 | ) { 104 | templateObject.containers[app].ports = convPorts( 105 | templateObject.containers[app].ports, 106 | "portainer_v1" 107 | ); 108 | } 109 | if ( 110 | templateObject.containers[app].volumes && 111 | templateObject.containers[app].volumes.length > 0 112 | ) { 113 | templateObject.containers[app].volumes = convVolumes( 114 | templateObject.containers[app].volumes, 115 | "portainer_v1" 116 | ); 117 | } 118 | if ( 119 | templateObject.containers[app].sysctls && 120 | templateObject.containers[app].sysctls.length > 0 121 | ) { 122 | templateObject.containers[app].sysctls = convSysctls( 123 | templateObject.containers[app].sysctls, 124 | "portainer_v1" 125 | ); 126 | } 127 | for (let attribute in templateObject.containers[app]) { 128 | if (templateObject.containers[app][attribute] === null || templateObject.containers[app][attribute] === undefined || templateObject.containers[app][attribute].length === 0) { 129 | delete templateObject.containers[app][attribute] 130 | } 131 | } 132 | portainerAppList.push(templateObject.containers[app]); 133 | } 134 | return portainerAppList; 135 | } 136 | function convYacht(templateObject) { 137 | var yachtAppList = []; 138 | for (let app in templateObject.containers) { 139 | if ( 140 | templateObject.containers[app].ports && 141 | templateObject.containers[app].ports.length > 0 142 | ) { 143 | 144 | templateObject.containers[app].ports = convPorts( 145 | templateObject.containers[app].ports, 146 | "yacht" 147 | ); 148 | } 149 | if ( 150 | templateObject.containers[app].volumes && 151 | templateObject.containers[app].volumes.length > 0 152 | ) { 153 | templateObject.containers[app].volumes = convVolumes( 154 | templateObject.containers[app].volumes, 155 | "yacht" 156 | ); 157 | } 158 | if ( 159 | templateObject.containers[app].sysctls && 160 | templateObject.containers[app].sysctls.length > 0 161 | ) { 162 | templateObject.containers[app].sysctls = convSysctls( 163 | templateObject.containers[app].sysctls, 164 | "yacht" 165 | ); 166 | } 167 | yachtAppList.push(templateObject.containers[app]); 168 | } 169 | return yachtAppList; 170 | } 171 | function convSysctls(sysctls) { 172 | var _sysctl_list = []; 173 | for (let sysctl in sysctls) { 174 | let _sysctl_object = {}; 175 | let _sysctl_name = sysctls[sysctl].name; 176 | let _sysctl_value = sysctls[sysctl].value; 177 | _sysctl_object[_sysctl_name] = _sysctl_value; 178 | _sysctl_list.push(_sysctl_object); 179 | } 180 | return _sysctl_list; 181 | } 182 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Shipwright 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 65 | 66 | 67 | 70 |
71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /frontend/src/components/builder/builder.vue: -------------------------------------------------------------------------------- 1 | 121 | 122 | 275 | 276 | 281 | -------------------------------------------------------------------------------- /frontend/src/components/builder/app_components/app_advanced.vue: -------------------------------------------------------------------------------- 1 | 256 | 257 | 317 | -------------------------------------------------------------------------------- /frontend/src/workbox-f163abaa.js: -------------------------------------------------------------------------------- 1 | define("./workbox-f163abaa.js",["exports"],(function(t){"use strict";try{self["workbox:core:6.1.5"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:6.1.5"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class r extends i{constructor(t,e,s){super((({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)}),e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",(t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})})));t.waitUntil(s),t.ports&&t.ports[0]&&s.then((()=>t.ports[0].postMessage(!0)))}}))}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:i,route:r}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=r&&r.handler;const a=t.method;if(!o&&this.i.has(a)&&(o=this.i.get(a)),!o)return;let c;try{c=o.handle({url:s,request:t,event:e,params:i})}catch(t){c=Promise.reject(t)}const h=r&&r.catchHandler;return c instanceof Promise&&(this.o||h)&&(c=c.catch((async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:i})}catch(t){n=t}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n}))),c}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this.t.get(s.method)||[];for(const r of i){let i;const o=r.match({url:t,sameOrigin:e,request:s,event:n});if(o)return i=o,(Array.isArray(o)&&0===o.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(i=void 0),{route:r,params:i}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let a;function c(){return(c=Object.assign||function(t){for(var e=1;e[h.prefix,t,h.suffix].filter((t=>t&&t.length>0)).join("-"),l=t=>t||u(h.precache),f=t=>t||u(h.runtime);function w(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:6.1.5"]&&_()}catch(t){}function d(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),r=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:r.href}}class p{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class y{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=e&&e.cacheKey||this.h.getCacheKeyForURL(t.url);return s?new Request(s):t},this.h=t}}let g;async function R(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const i=t.clone(),r={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=e?e(r):r,a=function(){if(void 0===g){const t=new Response("");if("body"in t)try{new Response(t.body),g=!0}catch(t){g=!1}g=!1}return g}()?i.body:await i.blob();return new Response(a,o)}function m(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class v{constructor(){this.promise=new Promise(((t,e)=>{this.resolve=t,this.reject=e}))}}const q=new Set;try{self["workbox:strategies:6.1.5"]&&_()}catch(t){}function U(t){return"string"==typeof t?new Request(t):t}class L{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,this.l=t,this.p=new v,this.g=[],this.R=[...t.plugins],this.m=new Map;for(const t of this.R)this.m.set(t,{});this.event.waitUntil(this.p.promise)}async fetch(t){const{event:e}=this;let n=U(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const i=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){throw new s("plugin-error-request-will-fetch",{thrownError:t})}const r=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.l.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:r,response:t});return t}catch(t){throw i&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:i.clone(),request:r.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=U(t);let s;const{cacheName:n,matchOptions:i}=this.l,r=await this.getCacheKey(e,"read"),o=c({},i,{cacheName:n});s=await caches.match(r,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:i,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(t,e){const n=U(t);var i;await(i=0,new Promise((t=>setTimeout(t,i))));const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=r.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const a=await this.v(e);if(!a)return!1;const{cacheName:h,matchOptions:u}=this.l,l=await self.caches.open(h),f=this.hasCallback("cacheDidUpdate"),w=f?await async function(t,e,s,n){const i=m(e.url,s);if(e.url===i)return t.match(e,n);const r=c({},n,{ignoreSearch:!0}),o=await t.keys(e,r);for(const e of o)if(i===m(e.url,s))return t.match(e,n)}(l,r.clone(),["__WB_REVISION__"],u):null;try{await l.put(r,f?a.clone():a)}catch(t){throw"QuotaExceededError"===t.name&&await async function(){for(const t of q)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:h,oldResponse:w,newResponse:a.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){if(!this.u[e]){let s=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))s=U(await t({mode:e,request:s,event:this.event,params:this.params}));this.u[e]=s}return this.u[e]}hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.l.plugins)if("function"==typeof e[t]){const s=this.m.get(e),n=n=>{const i=c({},n,{state:s});return e[t](i)};yield n}}waitUntil(t){return this.g.push(t),t}async doneWaiting(){let t;for(;t=this.g.shift();)await t}destroy(){this.p.resolve()}async v(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class b extends class{constructor(t={}){this.cacheName=f(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,i=new L(this,{event:e,request:s,params:n}),r=this.q(i,s,e);return[r,this.U(r,i,s,e)]}async q(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(i=await this.L(e,t),!i||"error"===i.type)throw new s("no-response",{url:e.url})}catch(s){for(const r of t.iterateCallbacks("handlerDidError"))if(i=await r({error:s,event:n,request:e}),i)break;if(!i)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))i=await s({event:n,request:e,response:i});return i}async U(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:i}),await e.doneWaiting()}catch(t){r=t}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:i,error:r}),e.destroy(),r)throw r}}{constructor(t={}){t.cacheName=l(t.cacheName),super(t),this._=!1!==t.fallbackToNetwork,this.plugins.push(b.copyRedirectedCacheableResponsesPlugin)}async L(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.C(t,e):await this.N(t,e))}async N(t,e){let n;if(!this._)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});return n=await e.fetch(t),n}async C(t,e){this.O();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}O(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==b.copyRedirectedCacheableResponsesPlugin&&(n===b.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(b.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}b.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},b.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await R(t):t};class C{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.k=new Map,this.T=new Map,this.W=new Map,this.l=new b({cacheName:l(t),plugins:[...e,new y({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.l}precache(t){this.addToCacheList(t),this.K||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.K=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=d(n),r="string"!=typeof n&&n.revision?"reload":"default";if(this.k.has(i)&&this.k.get(i)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.k.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.W.has(t)&&this.W.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:i});this.W.set(t,n.integrity)}if(this.k.set(i,t),this.T.set(i,r),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return w(t,(async()=>{const e=new p;this.strategy.plugins.push(e);for(const[e,s]of this.k){const n=this.W.get(s),i=this.T.get(e),r=new Request(e,{integrity:n,cache:i,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}}))}activate(t){return w(t,(async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.k.values()),n=[];for(const i of e)s.has(i.url)||(await t.delete(i),n.push(i.url));return{deletedURLs:n}}))}getURLsToCacheKeys(){return this.k}getCachedURLs(){return[...this.k.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.k.get(e.href)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=c({cacheKey:e},s.params),this.strategy.handle(s))}}let x;const N=()=>(x||(x=new C),x);class E extends i{constructor(t,e){super((({request:s})=>{const n=t.getURLsToCacheKeys();for(const t of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:i}={}){const r=new URL(t,location.href);r.hash="",yield r.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some((t=>t.test(s)))&&t.searchParams.delete(s);return t}(r,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(i){const t=i({url:r});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(t);if(e)return{cacheKey:e}}}),t.strategy)}}function O(t){const e=N();!function(t,e,n){let c;if("string"==typeof t){const s=new URL(t,location.href);c=new i((({url:t})=>t.href===s.href),e,n)}else if(t instanceof RegExp)c=new r(t,e,n);else if("function"==typeof t)c=new i(t,e,n);else{if(!(t instanceof i))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});c=t}(a||(a=new o,a.addFetchListener(),a.addCacheListener()),a).registerRoute(c)}(new E(e,t))}t.precacheAndRoute=function(t,e){!function(t){N().precache(t)}(t),O(e)}})); 2 | //# sourceMappingURL=workbox-f163abaa.js.map 3 | -------------------------------------------------------------------------------- /frontend/src/workbox-f163abaa.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"workbox-f163abaa.js","sources":["../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_version.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/logger.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/models/messages/messageGenerator.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/WorkboxError.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/_version.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/utils/constants.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/utils/normalizeHandler.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/Route.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/RegExpRoute.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/Router.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/utils/getOrCreateDefaultRouter.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/cacheNames.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/waitUntil.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/_version.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/utils/createCacheKey.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/utils/PrecacheInstallReportPlugin.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/utils/PrecacheCacheKeyPlugin.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/canConstructResponseFromBodyStream.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/copyResponse.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/cacheMatchIgnoreParams.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/Deferred.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/models/quotaErrorCallbacks.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-strategies/_version.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-strategies/StrategyHandler.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/timeout.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/getFriendlyURL.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-core/_private/executeQuotaErrorCallbacks.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/PrecacheStrategy.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-strategies/Strategy.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/PrecacheController.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/utils/getOrCreatePrecacheController.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/PrecacheRoute.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/utils/generateURLVariations.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/utils/removeIgnoredSearchParams.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/addRoute.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-routing/registerRoute.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/precacheAndRoute.js","../../../../../../usr/local/lib/node_modules/workbox-cli/node_modules/workbox-precaching/precache.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:6.1.5'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production' ? null : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in self)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null,\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n }\n return api;\n})());\nexport { logger };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { messages } from './messages.js';\nimport '../../_version.js';\nconst fallback = (code, ...args) => {\n let msg = code;\n if (args.length > 0) {\n msg += ` :: ${JSON.stringify(args)}`;\n }\n return msg;\n};\nconst generatorFunction = (code, details = {}) => {\n const message = messages[code];\n if (!message) {\n throw new Error(`Unable to find message for code '${code}'.`);\n }\n return message(details);\n};\nexport const messageGenerator = (process.env.NODE_ENV === 'production') ?\n fallback : generatorFunction;\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { messageGenerator } from '../models/messages/messageGenerator.js';\nimport '../_version.js';\n/**\n * Workbox errors should be thrown with this class.\n * This allows use to ensure the type easily in tests,\n * helps developers identify errors from workbox\n * easily and allows use to optimise error\n * messages correctly.\n *\n * @private\n */\nclass WorkboxError extends Error {\n /**\n *\n * @param {string} errorCode The error code that\n * identifies this particular error.\n * @param {Object=} details Any relevant arguments\n * that will help developers identify issues should\n * be added as a key on the context object.\n */\n constructor(errorCode, details) {\n const message = messageGenerator(errorCode, details);\n super(message);\n this.name = errorCode;\n this.details = details;\n }\n}\nexport { WorkboxError };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:routing:6.1.5'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The default HTTP method, 'GET', used when there's no specific method\n * configured for a route.\n *\n * @type {string}\n *\n * @private\n */\nexport const defaultMethod = 'GET';\n/**\n * The list of valid HTTP methods associated with requests that could be routed.\n *\n * @type {Array}\n *\n * @private\n */\nexport const validMethods = [\n 'DELETE',\n 'GET',\n 'HEAD',\n 'PATCH',\n 'POST',\n 'PUT',\n];\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {function()|Object} handler Either a function, or an object with a\n * 'handle' method.\n * @return {Object} An object with a handle method.\n *\n * @private\n */\nexport const normalizeHandler = (handler) => {\n if (handler && typeof handler === 'object') {\n if (process.env.NODE_ENV !== 'production') {\n assert.hasMethod(handler, 'handle', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return handler;\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(handler, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return { handle: handler };\n }\n};\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { defaultMethod, validMethods } from './utils/constants.js';\nimport { normalizeHandler } from './utils/normalizeHandler.js';\nimport './_version.js';\n/**\n * A `Route` consists of a pair of callback functions, \"match\" and \"handler\".\n * The \"match\" callback determine if a route should be used to \"handle\" a\n * request by returning a non-falsy value if it can. The \"handler\" callback\n * is called when there is a match and should return a Promise that resolves\n * to a `Response`.\n *\n * @memberof module:workbox-routing\n */\nclass Route {\n /**\n * Constructor for Route class.\n *\n * @param {module:workbox-routing~matchCallback} match\n * A callback function that determines whether the route matches a given\n * `fetch` event by returning a non-falsy value.\n * @param {module:workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resolving to a Response.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n */\n constructor(match, handler, method = defaultMethod) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(match, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'match',\n });\n if (method) {\n assert.isOneOf(method, validMethods, { paramName: 'method' });\n }\n }\n // These values are referenced directly by Router so cannot be\n // altered by minificaton.\n this.handler = normalizeHandler(handler);\n this.match = match;\n this.method = method;\n }\n /**\n *\n * @param {module:workbox-routing-handlerCallback} handler A callback\n * function that returns a Promise resolving to a Response\n */\n setCatchHandler(handler) {\n this.catchHandler = normalizeHandler(handler);\n }\n}\nexport { Route };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { Route } from './Route.js';\nimport './_version.js';\n/**\n * RegExpRoute makes it easy to create a regular expression based\n * [Route]{@link module:workbox-routing.Route}.\n *\n * For same-origin requests the RegExp only needs to match part of the URL. For\n * requests against third-party servers, you must define a RegExp that matches\n * the start of the URL.\n *\n * [See the module docs for info.]{@link https://developers.google.com/web/tools/workbox/modules/workbox-routing}\n *\n * @memberof module:workbox-routing\n * @extends module:workbox-routing.Route\n */\nclass RegExpRoute extends Route {\n /**\n * If the regular expression contains\n * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},\n * the captured values will be passed to the\n * [handler's]{@link module:workbox-routing~handlerCallback} `params`\n * argument.\n *\n * @param {RegExp} regExp The regular expression to match against URLs.\n * @param {module:workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resulting in a Response.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n */\n constructor(regExp, handler, method) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(regExp, RegExp, {\n moduleName: 'workbox-routing',\n className: 'RegExpRoute',\n funcName: 'constructor',\n paramName: 'pattern',\n });\n }\n const match = ({ url }) => {\n const result = regExp.exec(url.href);\n // Return immediately if there's no match.\n if (!result) {\n return;\n }\n // Require that the match start at the first character in the URL string\n // if it's a cross-origin request.\n // See https://github.com/GoogleChrome/workbox/issues/281 for the context\n // behind this behavior.\n if ((url.origin !== location.origin) && (result.index !== 0)) {\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`The regular expression '${regExp}' only partially matched ` +\n `against the cross-origin URL '${url}'. RegExpRoute's will only ` +\n `handle cross-origin requests if they match the entire URL.`);\n }\n return;\n }\n // If the route matches, but there aren't any capture groups defined, then\n // this will return [], which is truthy and therefore sufficient to\n // indicate a match.\n // If there are capture groups, then it will return their values.\n return result.slice(1);\n };\n super(match, handler, method);\n }\n}\nexport { RegExpRoute };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { defaultMethod } from './utils/constants.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { normalizeHandler } from './utils/normalizeHandler.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport './_version.js';\n/**\n * The Router can be used to process a FetchEvent through one or more\n * [Routes]{@link module:workbox-routing.Route} responding with a Request if\n * a matching route exists.\n *\n * If no route matches a given a request, the Router will use a \"default\"\n * handler if one is defined.\n *\n * Should the matching Route throw an error, the Router will use a \"catch\"\n * handler if one is defined to gracefully deal with issues and respond with a\n * Request.\n *\n * If a request matches multiple routes, the **earliest** registered route will\n * be used to respond to the request.\n *\n * @memberof module:workbox-routing\n */\nclass Router {\n /**\n * Initializes a new Router.\n */\n constructor() {\n this._routes = new Map();\n this._defaultHandlerMap = new Map();\n }\n /**\n * @return {Map>} routes A `Map` of HTTP\n * method name ('GET', etc.) to an array of all the corresponding `Route`\n * instances that are registered.\n */\n get routes() {\n return this._routes;\n }\n /**\n * Adds a fetch event listener to respond to events when a route matches\n * the event's request.\n */\n addFetchListener() {\n // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705\n self.addEventListener('fetch', ((event) => {\n const { request } = event;\n const responsePromise = this.handleRequest({ request, event });\n if (responsePromise) {\n event.respondWith(responsePromise);\n }\n }));\n }\n /**\n * Adds a message event listener for URLs to cache from the window.\n * This is useful to cache resources loaded on the page prior to when the\n * service worker started controlling it.\n *\n * The format of the message data sent from the window should be as follows.\n * Where the `urlsToCache` array may consist of URL strings or an array of\n * URL string + `requestInit` object (the same as you'd pass to `fetch()`).\n *\n * ```\n * {\n * type: 'CACHE_URLS',\n * payload: {\n * urlsToCache: [\n * './script1.js',\n * './script2.js',\n * ['./script3.js', {mode: 'no-cors'}],\n * ],\n * },\n * }\n * ```\n */\n addCacheListener() {\n // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705\n self.addEventListener('message', ((event) => {\n if (event.data && event.data.type === 'CACHE_URLS') {\n const { payload } = event.data;\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Caching URLs from the window`, payload.urlsToCache);\n }\n const requestPromises = Promise.all(payload.urlsToCache.map((entry) => {\n if (typeof entry === 'string') {\n entry = [entry];\n }\n const request = new Request(...entry);\n return this.handleRequest({ request, event });\n // TODO(philipwalton): TypeScript errors without this typecast for\n // some reason (probably a bug). The real type here should work but\n // doesn't: `Array | undefined>`.\n })); // TypeScript\n event.waitUntil(requestPromises);\n // If a MessageChannel was used, reply to the message on success.\n if (event.ports && event.ports[0]) {\n requestPromises.then(() => event.ports[0].postMessage(true));\n }\n }\n }));\n }\n /**\n * Apply the routing rules to a FetchEvent object to get a Response from an\n * appropriate Route's handler.\n *\n * @param {Object} options\n * @param {Request} options.request The request to handle.\n * @param {ExtendableEvent} options.event The event that triggered the\n * request.\n * @return {Promise|undefined} A promise is returned if a\n * registered route can handle the request. If there is no matching\n * route and there's no `defaultHandler`, `undefined` is returned.\n */\n handleRequest({ request, event }) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(request, Request, {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'handleRequest',\n paramName: 'options.request',\n });\n }\n const url = new URL(request.url, location.href);\n if (!url.protocol.startsWith('http')) {\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Workbox Router only supports URLs that start with 'http'.`);\n }\n return;\n }\n const sameOrigin = url.origin === location.origin;\n const { params, route } = this.findMatchingRoute({\n event,\n request,\n sameOrigin,\n url,\n });\n let handler = route && route.handler;\n const debugMessages = [];\n if (process.env.NODE_ENV !== 'production') {\n if (handler) {\n debugMessages.push([\n `Found a route to handle this request:`, route,\n ]);\n if (params) {\n debugMessages.push([\n `Passing the following params to the route's handler:`, params,\n ]);\n }\n }\n }\n // If we don't have a handler because there was no matching route, then\n // fall back to defaultHandler if that's defined.\n const method = request.method;\n if (!handler && this._defaultHandlerMap.has(method)) {\n if (process.env.NODE_ENV !== 'production') {\n debugMessages.push(`Failed to find a matching route. Falling ` +\n `back to the default handler for ${method}.`);\n }\n handler = this._defaultHandlerMap.get(method);\n }\n if (!handler) {\n if (process.env.NODE_ENV !== 'production') {\n // No handler so Workbox will do nothing. If logs is set of debug\n // i.e. verbose, we should print out this information.\n logger.debug(`No route found for: ${getFriendlyURL(url)}`);\n }\n return;\n }\n if (process.env.NODE_ENV !== 'production') {\n // We have a handler, meaning Workbox is going to handle the route.\n // print the routing details to the console.\n logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);\n debugMessages.forEach((msg) => {\n if (Array.isArray(msg)) {\n logger.log(...msg);\n }\n else {\n logger.log(msg);\n }\n });\n logger.groupEnd();\n }\n // Wrap in try and catch in case the handle method throws a synchronous\n // error. It should still callback to the catch handler.\n let responsePromise;\n try {\n responsePromise = handler.handle({ url, request, event, params });\n }\n catch (err) {\n responsePromise = Promise.reject(err);\n }\n // Get route's catch handler, if it exists\n const catchHandler = route && route.catchHandler;\n if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) {\n responsePromise = responsePromise.catch(async (err) => {\n // If there's a route catch handler, process that first\n if (catchHandler) {\n if (process.env.NODE_ENV !== 'production') {\n // Still include URL here as it will be async from the console group\n // and may not make sense without the URL\n logger.groupCollapsed(`Error thrown when responding to: ` +\n ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);\n logger.error(`Error thrown by:`, route);\n logger.error(err);\n logger.groupEnd();\n }\n try {\n return await catchHandler.handle({ url, request, event, params });\n }\n catch (catchErr) {\n err = catchErr;\n }\n }\n if (this._catchHandler) {\n if (process.env.NODE_ENV !== 'production') {\n // Still include URL here as it will be async from the console group\n // and may not make sense without the URL\n logger.groupCollapsed(`Error thrown when responding to: ` +\n ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);\n logger.error(`Error thrown by:`, route);\n logger.error(err);\n logger.groupEnd();\n }\n return this._catchHandler.handle({ url, request, event });\n }\n throw err;\n });\n }\n return responsePromise;\n }\n /**\n * Checks a request and URL (and optionally an event) against the list of\n * registered routes, and if there's a match, returns the corresponding\n * route along with any params generated by the match.\n *\n * @param {Object} options\n * @param {URL} options.url\n * @param {boolean} options.sameOrigin The result of comparing `url.origin`\n * against the current origin.\n * @param {Request} options.request The request to match.\n * @param {Event} options.event The corresponding event.\n * @return {Object} An object with `route` and `params` properties.\n * They are populated if a matching route was found or `undefined`\n * otherwise.\n */\n findMatchingRoute({ url, sameOrigin, request, event }) {\n const routes = this._routes.get(request.method) || [];\n for (const route of routes) {\n let params;\n const matchResult = route.match({ url, sameOrigin, request, event });\n if (matchResult) {\n if (process.env.NODE_ENV !== 'production') {\n // Warn developers that using an async matchCallback is almost always\n // not the right thing to do. \n if (matchResult instanceof Promise) {\n logger.warn(`While routing ${getFriendlyURL(url)}, an async ` +\n `matchCallback function was used. Please convert the ` +\n `following route to use a synchronous matchCallback function:`, route);\n }\n }\n // See https://github.com/GoogleChrome/workbox/issues/2079\n params = matchResult;\n if (Array.isArray(matchResult) && matchResult.length === 0) {\n // Instead of passing an empty array in as params, use undefined.\n params = undefined;\n }\n else if ((matchResult.constructor === Object &&\n Object.keys(matchResult).length === 0)) {\n // Instead of passing an empty object in as params, use undefined.\n params = undefined;\n }\n else if (typeof matchResult === 'boolean') {\n // For the boolean value true (rather than just something truth-y),\n // don't set params.\n // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353\n params = undefined;\n }\n // Return early if have a match.\n return { route, params };\n }\n }\n // If no match was found above, return and empty object.\n return {};\n }\n /**\n * Define a default `handler` that's called when no routes explicitly\n * match the incoming request.\n *\n * Each HTTP method ('GET', 'POST', etc.) gets its own default handler.\n *\n * Without a default handler, unmatched requests will go against the\n * network as if there were no service worker present.\n *\n * @param {module:workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resulting in a Response.\n * @param {string} [method='GET'] The HTTP method to associate with this\n * default handler. Each method has its own default.\n */\n setDefaultHandler(handler, method = defaultMethod) {\n this._defaultHandlerMap.set(method, normalizeHandler(handler));\n }\n /**\n * If a Route throws an error while handling a request, this `handler`\n * will be called and given a chance to provide a response.\n *\n * @param {module:workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resulting in a Response.\n */\n setCatchHandler(handler) {\n this._catchHandler = normalizeHandler(handler);\n }\n /**\n * Registers a route with the router.\n *\n * @param {module:workbox-routing.Route} route The route to register.\n */\n registerRoute(route) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(route, 'object', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route',\n });\n assert.hasMethod(route, 'match', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route',\n });\n assert.isType(route.handler, 'object', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route',\n });\n assert.hasMethod(route.handler, 'handle', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route.handler',\n });\n assert.isType(route.method, 'string', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route.method',\n });\n }\n if (!this._routes.has(route.method)) {\n this._routes.set(route.method, []);\n }\n // Give precedence to all of the earlier routes by adding this additional\n // route to the end of the array.\n this._routes.get(route.method).push(route);\n }\n /**\n * Unregisters a route with the router.\n *\n * @param {module:workbox-routing.Route} route The route to unregister.\n */\n unregisterRoute(route) {\n if (!this._routes.has(route.method)) {\n throw new WorkboxError('unregister-route-but-not-found-with-method', {\n method: route.method,\n });\n }\n const routeIndex = this._routes.get(route.method).indexOf(route);\n if (routeIndex > -1) {\n this._routes.get(route.method).splice(routeIndex, 1);\n }\n else {\n throw new WorkboxError('unregister-route-route-not-registered');\n }\n }\n}\nexport { Router };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { Router } from '../Router.js';\nimport '../_version.js';\nlet defaultRouter;\n/**\n * Creates a new, singleton Router instance if one does not exist. If one\n * does already exist, that instance is returned.\n *\n * @private\n * @return {Router}\n */\nexport const getOrCreateDefaultRouter = () => {\n if (!defaultRouter) {\n defaultRouter = new Router();\n // The helpers that use the default Router assume these listeners exist.\n defaultRouter.addFetchListener();\n defaultRouter.addCacheListener();\n }\n return defaultRouter;\n};\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst _cacheNameDetails = {\n googleAnalytics: 'googleAnalytics',\n precache: 'precache-v2',\n prefix: 'workbox',\n runtime: 'runtime',\n suffix: typeof registration !== 'undefined' ? registration.scope : '',\n};\nconst _createCacheName = (cacheName) => {\n return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix]\n .filter((value) => value && value.length > 0)\n .join('-');\n};\nconst eachCacheNameDetail = (fn) => {\n for (const key of Object.keys(_cacheNameDetails)) {\n fn(key);\n }\n};\nexport const cacheNames = {\n updateDetails: (details) => {\n eachCacheNameDetail((key) => {\n if (typeof details[key] === 'string') {\n _cacheNameDetails[key] = details[key];\n }\n });\n },\n getGoogleAnalyticsName: (userCacheName) => {\n return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics);\n },\n getPrecacheName: (userCacheName) => {\n return userCacheName || _createCacheName(_cacheNameDetails.precache);\n },\n getPrefix: () => {\n return _cacheNameDetails.prefix;\n },\n getRuntimeName: (userCacheName) => {\n return userCacheName || _createCacheName(_cacheNameDetails.runtime);\n },\n getSuffix: () => {\n return _cacheNameDetails.suffix;\n },\n};\n","/*\n Copyright 2020 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A utility method that makes it easier to use `event.waitUntil` with\n * async functions and return the result.\n *\n * @param {ExtendableEvent} event\n * @param {Function} asyncFn\n * @return {Function}\n * @private\n */\nfunction waitUntil(event, asyncFn) {\n const returnPromise = asyncFn();\n event.waitUntil(returnPromise);\n return returnPromise;\n}\nexport { waitUntil };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:precaching:6.1.5'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport '../_version.js';\n// Name of the search parameter used to store revision info.\nconst REVISION_SEARCH_PARAM = '__WB_REVISION__';\n/**\n * Converts a manifest entry into a versioned URL suitable for precaching.\n *\n * @param {Object|string} entry\n * @return {string} A URL with versioning info.\n *\n * @private\n * @memberof module:workbox-precaching\n */\nexport function createCacheKey(entry) {\n if (!entry) {\n throw new WorkboxError('add-to-cache-list-unexpected-type', { entry });\n }\n // If a precache manifest entry is a string, it's assumed to be a versioned\n // URL, like '/app.abcd1234.js'. Return as-is.\n if (typeof entry === 'string') {\n const urlObject = new URL(entry, location.href);\n return {\n cacheKey: urlObject.href,\n url: urlObject.href,\n };\n }\n const { revision, url } = entry;\n if (!url) {\n throw new WorkboxError('add-to-cache-list-unexpected-type', { entry });\n }\n // If there's just a URL and no revision, then it's also assumed to be a\n // versioned URL.\n if (!revision) {\n const urlObject = new URL(url, location.href);\n return {\n cacheKey: urlObject.href,\n url: urlObject.href,\n };\n }\n // Otherwise, construct a properly versioned URL using the custom Workbox\n // search parameter along with the revision info.\n const cacheKeyURL = new URL(url, location.href);\n const originalURL = new URL(url, location.href);\n cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);\n return {\n cacheKey: cacheKeyURL.href,\n url: originalURL.href,\n };\n}\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A plugin, designed to be used with PrecacheController, to determine the\n * of assets that were updated (or not updated) during the install event.\n *\n * @private\n */\nclass PrecacheInstallReportPlugin {\n constructor() {\n this.updatedURLs = [];\n this.notUpdatedURLs = [];\n this.handlerWillStart = async ({ request, state, }) => {\n // TODO: `state` should never be undefined...\n if (state) {\n state.originalRequest = request;\n }\n };\n this.cachedResponseWillBeUsed = async ({ event, state, cachedResponse, }) => {\n if (event.type === 'install') {\n // TODO: `state` should never be undefined...\n const url = state.originalRequest.url;\n if (cachedResponse) {\n this.notUpdatedURLs.push(url);\n }\n else {\n this.updatedURLs.push(url);\n }\n }\n return cachedResponse;\n };\n }\n}\nexport { PrecacheInstallReportPlugin };\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A plugin, designed to be used with PrecacheController, to translate URLs into\n * the corresponding cache key, based on the current revision info.\n *\n * @private\n */\nclass PrecacheCacheKeyPlugin {\n constructor({ precacheController }) {\n this.cacheKeyWillBeUsed = async ({ request, params, }) => {\n const cacheKey = params && params.cacheKey ||\n this._precacheController.getCacheKeyForURL(request.url);\n return cacheKey ? new Request(cacheKey) : request;\n };\n this._precacheController = precacheController;\n }\n}\nexport { PrecacheCacheKeyPlugin };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nlet supportStatus;\n/**\n * A utility function that determines whether the current browser supports\n * constructing a new `Response` from a `response.body` stream.\n *\n * @return {boolean} `true`, if the current browser can successfully\n * construct a `Response` from a `response.body` stream, `false` otherwise.\n *\n * @private\n */\nfunction canConstructResponseFromBodyStream() {\n if (supportStatus === undefined) {\n const testResponse = new Response('');\n if ('body' in testResponse) {\n try {\n new Response(testResponse.body);\n supportStatus = true;\n }\n catch (error) {\n supportStatus = false;\n }\n }\n supportStatus = false;\n }\n return supportStatus;\n}\nexport { canConstructResponseFromBodyStream };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { canConstructResponseFromBodyStream } from './_private/canConstructResponseFromBodyStream.js';\nimport { WorkboxError } from './_private/WorkboxError.js';\nimport './_version.js';\n/**\n * Allows developers to copy a response and modify its `headers`, `status`,\n * or `statusText` values (the values settable via a\n * [`ResponseInit`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Response/Response#Syntax}\n * object in the constructor).\n * To modify these values, pass a function as the second argument. That\n * function will be invoked with a single object with the response properties\n * `{headers, status, statusText}`. The return value of this function will\n * be used as the `ResponseInit` for the new `Response`. To change the values\n * either modify the passed parameter(s) and return it, or return a totally\n * new object.\n *\n * This method is intentionally limited to same-origin responses, regardless of\n * whether CORS was used or not.\n *\n * @param {Response} response\n * @param {Function} modifier\n * @memberof module:workbox-core\n */\nasync function copyResponse(response, modifier) {\n let origin = null;\n // If response.url isn't set, assume it's cross-origin and keep origin null.\n if (response.url) {\n const responseURL = new URL(response.url);\n origin = responseURL.origin;\n }\n if (origin !== self.location.origin) {\n throw new WorkboxError('cross-origin-copy-response', { origin });\n }\n const clonedResponse = response.clone();\n // Create a fresh `ResponseInit` object by cloning the headers.\n const responseInit = {\n headers: new Headers(clonedResponse.headers),\n status: clonedResponse.status,\n statusText: clonedResponse.statusText,\n };\n // Apply any user modifications.\n const modifiedResponseInit = modifier ? modifier(responseInit) : responseInit;\n // Create the new response from the body stream and `ResponseInit`\n // modifications. Note: not all browsers support the Response.body stream,\n // so fall back to reading the entire body into memory as a blob.\n const body = canConstructResponseFromBodyStream() ?\n clonedResponse.body : await clonedResponse.blob();\n return new Response(body, modifiedResponseInit);\n}\nexport { copyResponse };\n","/*\n Copyright 2020 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nfunction stripParams(fullURL, ignoreParams) {\n const strippedURL = new URL(fullURL);\n for (const param of ignoreParams) {\n strippedURL.searchParams.delete(param);\n }\n return strippedURL.href;\n}\n/**\n * Matches an item in the cache, ignoring specific URL params. This is similar\n * to the `ignoreSearch` option, but it allows you to ignore just specific\n * params (while continuing to match on the others).\n *\n * @private\n * @param {Cache} cache\n * @param {Request} request\n * @param {Object} matchOptions\n * @param {Array} ignoreParams\n * @return {Promise}\n */\nasync function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) {\n const strippedRequestURL = stripParams(request.url, ignoreParams);\n // If the request doesn't include any ignored params, match as normal.\n if (request.url === strippedRequestURL) {\n return cache.match(request, matchOptions);\n }\n // Otherwise, match by comparing keys\n const keysOptions = { ...matchOptions, ignoreSearch: true };\n const cacheKeys = await cache.keys(request, keysOptions);\n for (const cacheKey of cacheKeys) {\n const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams);\n if (strippedRequestURL === strippedCacheKeyURL) {\n return cache.match(cacheKey, matchOptions);\n }\n }\n return;\n}\nexport { cacheMatchIgnoreParams };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n// Callbacks to be executed whenever there's a quota error.\nconst quotaErrorCallbacks = new Set();\nexport { quotaErrorCallbacks };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:strategies:6.1.5'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { cacheMatchIgnoreParams } from 'workbox-core/_private/cacheMatchIgnoreParams.js';\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport { executeQuotaErrorCallbacks } from 'workbox-core/_private/executeQuotaErrorCallbacks.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { timeout } from 'workbox-core/_private/timeout.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport './_version.js';\nfunction toRequest(input) {\n return (typeof input === 'string') ? new Request(input) : input;\n}\n/**\n * A class created every time a Strategy instance instance calls\n * [handle()]{@link module:workbox-strategies.Strategy~handle} or\n * [handleAll()]{@link module:workbox-strategies.Strategy~handleAll} that wraps all fetch and\n * cache actions around plugin callbacks and keeps track of when the strategy\n * is \"done\" (i.e. all added `event.waitUntil()` promises have resolved).\n *\n * @memberof module:workbox-strategies\n */\nclass StrategyHandler {\n /**\n * Creates a new instance associated with the passed strategy and event\n * that's handling the request.\n *\n * The constructor also initializes the state that will be passed to each of\n * the plugins handling this request.\n *\n * @param {module:workbox-strategies.Strategy} strategy\n * @param {Object} options\n * @param {Request|string} options.request A request to run this strategy for.\n * @param {ExtendableEvent} options.event The event associated with the\n * request.\n * @param {URL} [options.url]\n * @param {*} [options.params]\n * [match callback]{@link module:workbox-routing~matchCallback},\n * (if applicable).\n */\n constructor(strategy, options) {\n this._cacheKeys = {};\n /**\n * The request the strategy is performing (passed to the strategy's\n * `handle()` or `handleAll()` method).\n * @name request\n * @instance\n * @type {Request}\n * @memberof module:workbox-strategies.StrategyHandler\n */\n /**\n * The event associated with this request.\n * @name event\n * @instance\n * @type {ExtendableEvent}\n * @memberof module:workbox-strategies.StrategyHandler\n */\n /**\n * A `URL` instance of `request.url` (if passed to the strategy's\n * `handle()` or `handleAll()` method).\n * Note: the `url` param will be present if the strategy was invoked\n * from a workbox `Route` object.\n * @name url\n * @instance\n * @type {URL|undefined}\n * @memberof module:workbox-strategies.StrategyHandler\n */\n /**\n * A `param` value (if passed to the strategy's\n * `handle()` or `handleAll()` method).\n * Note: the `param` param will be present if the strategy was invoked\n * from a workbox `Route` object and the\n * [match callback]{@link module:workbox-routing~matchCallback} returned\n * a truthy value (it will be that value).\n * @name params\n * @instance\n * @type {*|undefined}\n * @memberof module:workbox-strategies.StrategyHandler\n */\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(options.event, ExtendableEvent, {\n moduleName: 'workbox-strategies',\n className: 'StrategyHandler',\n funcName: 'constructor',\n paramName: 'options.event',\n });\n }\n Object.assign(this, options);\n this.event = options.event;\n this._strategy = strategy;\n this._handlerDeferred = new Deferred();\n this._extendLifetimePromises = [];\n // Copy the plugins list (since it's mutable on the strategy),\n // so any mutations don't affect this handler instance.\n this._plugins = [...strategy.plugins];\n this._pluginStateMap = new Map();\n for (const plugin of this._plugins) {\n this._pluginStateMap.set(plugin, {});\n }\n this.event.waitUntil(this._handlerDeferred.promise);\n }\n /**\n * Fetches a given request (and invokes any applicable plugin callback\n * methods) using the `fetchOptions` (for non-navigation requests) and\n * `plugins` defined on the `Strategy` object.\n *\n * The following plugin lifecycle methods are invoked when using this method:\n * - `requestWillFetch()`\n * - `fetchDidSucceed()`\n * - `fetchDidFail()`\n *\n * @param {Request|string} input The URL or request to fetch.\n * @return {Promise}\n */\n async fetch(input) {\n const { event } = this;\n let request = toRequest(input);\n if (request.mode === 'navigate' &&\n event instanceof FetchEvent &&\n event.preloadResponse) {\n const possiblePreloadResponse = await event.preloadResponse;\n if (possiblePreloadResponse) {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Using a preloaded navigation response for ` +\n `'${getFriendlyURL(request.url)}'`);\n }\n return possiblePreloadResponse;\n }\n }\n // If there is a fetchDidFail plugin, we need to save a clone of the\n // original request before it's either modified by a requestWillFetch\n // plugin or before the original request's body is consumed via fetch().\n const originalRequest = this.hasCallback('fetchDidFail') ?\n request.clone() : null;\n try {\n for (const cb of this.iterateCallbacks('requestWillFetch')) {\n request = await cb({ request: request.clone(), event });\n }\n }\n catch (err) {\n throw new WorkboxError('plugin-error-request-will-fetch', {\n thrownError: err,\n });\n }\n // The request can be altered by plugins with `requestWillFetch` making\n // the original request (most likely from a `fetch` event) different\n // from the Request we make. Pass both to `fetchDidFail` to aid debugging.\n const pluginFilteredRequest = request.clone();\n try {\n let fetchResponse;\n // See https://github.com/GoogleChrome/workbox/issues/1796\n fetchResponse = await fetch(request, request.mode === 'navigate' ?\n undefined : this._strategy.fetchOptions);\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Network request for ` +\n `'${getFriendlyURL(request.url)}' returned a response with ` +\n `status '${fetchResponse.status}'.`);\n }\n for (const callback of this.iterateCallbacks('fetchDidSucceed')) {\n fetchResponse = await callback({\n event,\n request: pluginFilteredRequest,\n response: fetchResponse,\n });\n }\n return fetchResponse;\n }\n catch (error) {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Network request for ` +\n `'${getFriendlyURL(request.url)}' threw an error.`, error);\n }\n // `originalRequest` will only exist if a `fetchDidFail` callback\n // is being used (see above).\n if (originalRequest) {\n await this.runCallbacks('fetchDidFail', {\n error,\n event,\n originalRequest: originalRequest.clone(),\n request: pluginFilteredRequest.clone(),\n });\n }\n throw error;\n }\n }\n /**\n * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on\n * the response generated by `this.fetch()`.\n *\n * The call to `this.cachePut()` automatically invokes `this.waitUntil()`,\n * so you do not have to manually call `waitUntil()` on the event.\n *\n * @param {Request|string} input The request or URL to fetch and cache.\n * @return {Promise}\n */\n async fetchAndCachePut(input) {\n const response = await this.fetch(input);\n const responseClone = response.clone();\n this.waitUntil(this.cachePut(input, responseClone));\n return response;\n }\n /**\n * Matches a request from the cache (and invokes any applicable plugin\n * callback methods) using the `cacheName`, `matchOptions`, and `plugins`\n * defined on the strategy object.\n *\n * The following plugin lifecycle methods are invoked when using this method:\n * - cacheKeyWillByUsed()\n * - cachedResponseWillByUsed()\n *\n * @param {Request|string} key The Request or URL to use as the cache key.\n * @return {Promise} A matching response, if found.\n */\n async cacheMatch(key) {\n const request = toRequest(key);\n let cachedResponse;\n const { cacheName, matchOptions } = this._strategy;\n const effectiveRequest = await this.getCacheKey(request, 'read');\n const multiMatchOptions = { ...matchOptions, ...{ cacheName } };\n cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);\n if (process.env.NODE_ENV !== 'production') {\n if (cachedResponse) {\n logger.debug(`Found a cached response in '${cacheName}'.`);\n }\n else {\n logger.debug(`No cached response found in '${cacheName}'.`);\n }\n }\n for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) {\n cachedResponse = (await callback({\n cacheName,\n matchOptions,\n cachedResponse,\n request: effectiveRequest,\n event: this.event,\n })) || undefined;\n }\n return cachedResponse;\n }\n /**\n * Puts a request/response pair in the cache (and invokes any applicable\n * plugin callback methods) using the `cacheName` and `plugins` defined on\n * the strategy object.\n *\n * The following plugin lifecycle methods are invoked when using this method:\n * - cacheKeyWillByUsed()\n * - cacheWillUpdate()\n * - cacheDidUpdate()\n *\n * @param {Request|string} key The request or URL to use as the cache key.\n * @param {Response} response The response to cache.\n * @return {Promise} `false` if a cacheWillUpdate caused the response\n * not be cached, and `true` otherwise.\n */\n async cachePut(key, response) {\n const request = toRequest(key);\n // Run in the next task to avoid blocking other cache reads.\n // https://github.com/w3c/ServiceWorker/issues/1397\n await timeout(0);\n const effectiveRequest = await this.getCacheKey(request, 'write');\n if (process.env.NODE_ENV !== 'production') {\n if (effectiveRequest.method && effectiveRequest.method !== 'GET') {\n throw new WorkboxError('attempt-to-cache-non-get-request', {\n url: getFriendlyURL(effectiveRequest.url),\n method: effectiveRequest.method,\n });\n }\n }\n if (!response) {\n if (process.env.NODE_ENV !== 'production') {\n logger.error(`Cannot cache non-existent response for ` +\n `'${getFriendlyURL(effectiveRequest.url)}'.`);\n }\n throw new WorkboxError('cache-put-with-no-response', {\n url: getFriendlyURL(effectiveRequest.url),\n });\n }\n const responseToCache = await this._ensureResponseSafeToCache(response);\n if (!responseToCache) {\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` +\n `will not be cached.`, responseToCache);\n }\n return false;\n }\n const { cacheName, matchOptions } = this._strategy;\n const cache = await self.caches.open(cacheName);\n const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate');\n const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams(\n // TODO(philipwalton): the `__WB_REVISION__` param is a precaching\n // feature. Consider into ways to only add this behavior if using\n // precaching.\n cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) :\n null;\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Updating the '${cacheName}' cache with a new Response ` +\n `for ${getFriendlyURL(effectiveRequest.url)}.`);\n }\n try {\n await cache.put(effectiveRequest, hasCacheUpdateCallback ?\n responseToCache.clone() : responseToCache);\n }\n catch (error) {\n // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError\n if (error.name === 'QuotaExceededError') {\n await executeQuotaErrorCallbacks();\n }\n throw error;\n }\n for (const callback of this.iterateCallbacks('cacheDidUpdate')) {\n await callback({\n cacheName,\n oldResponse,\n newResponse: responseToCache.clone(),\n request: effectiveRequest,\n event: this.event,\n });\n }\n return true;\n }\n /**\n * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and\n * executes any of those callbacks found in sequence. The final `Request`\n * object returned by the last plugin is treated as the cache key for cache\n * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have\n * been registered, the passed request is returned unmodified\n *\n * @param {Request} request\n * @param {string} mode\n * @return {Promise}\n */\n async getCacheKey(request, mode) {\n if (!this._cacheKeys[mode]) {\n let effectiveRequest = request;\n for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) {\n effectiveRequest = toRequest(await callback({\n mode,\n request: effectiveRequest,\n event: this.event,\n params: this.params,\n }));\n }\n this._cacheKeys[mode] = effectiveRequest;\n }\n return this._cacheKeys[mode];\n }\n /**\n * Returns true if the strategy has at least one plugin with the given\n * callback.\n *\n * @param {string} name The name of the callback to check for.\n * @return {boolean}\n */\n hasCallback(name) {\n for (const plugin of this._strategy.plugins) {\n if (name in plugin) {\n return true;\n }\n }\n return false;\n }\n /**\n * Runs all plugin callbacks matching the given name, in order, passing the\n * given param object (merged ith the current plugin state) as the only\n * argument.\n *\n * Note: since this method runs all plugins, it's not suitable for cases\n * where the return value of a callback needs to be applied prior to calling\n * the next callback. See\n * [`iterateCallbacks()`]{@link module:workbox-strategies.StrategyHandler#iterateCallbacks}\n * below for how to handle that case.\n *\n * @param {string} name The name of the callback to run within each plugin.\n * @param {Object} param The object to pass as the first (and only) param\n * when executing each callback. This object will be merged with the\n * current plugin state prior to callback execution.\n */\n async runCallbacks(name, param) {\n for (const callback of this.iterateCallbacks(name)) {\n // TODO(philipwalton): not sure why `any` is needed. It seems like\n // this should work with `as WorkboxPluginCallbackParam[C]`.\n await callback(param);\n }\n }\n /**\n * Accepts a callback and returns an iterable of matching plugin callbacks,\n * where each callback is wrapped with the current handler state (i.e. when\n * you call each callback, whatever object parameter you pass it will\n * be merged with the plugin's current state).\n *\n * @param {string} name The name fo the callback to run\n * @return {Array}\n */\n *iterateCallbacks(name) {\n for (const plugin of this._strategy.plugins) {\n if (typeof plugin[name] === 'function') {\n const state = this._pluginStateMap.get(plugin);\n const statefulCallback = (param) => {\n const statefulParam = { ...param, state };\n // TODO(philipwalton): not sure why `any` is needed. It seems like\n // this should work with `as WorkboxPluginCallbackParam[C]`.\n return plugin[name](statefulParam);\n };\n yield statefulCallback;\n }\n }\n }\n /**\n * Adds a promise to the\n * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises}\n * of the event event associated with the request being handled (usually a\n * `FetchEvent`).\n *\n * Note: you can await\n * [`doneWaiting()`]{@link module:workbox-strategies.StrategyHandler~doneWaiting}\n * to know when all added promises have settled.\n *\n * @param {Promise} promise A promise to add to the extend lifetime promises\n * of the event that triggered the request.\n */\n waitUntil(promise) {\n this._extendLifetimePromises.push(promise);\n return promise;\n }\n /**\n * Returns a promise that resolves once all promises passed to\n * [`waitUntil()`]{@link module:workbox-strategies.StrategyHandler~waitUntil}\n * have settled.\n *\n * Note: any work done after `doneWaiting()` settles should be manually\n * passed to an event's `waitUntil()` method (not this handler's\n * `waitUntil()` method), otherwise the service worker thread my be killed\n * prior to your work completing.\n */\n async doneWaiting() {\n let promise;\n while (promise = this._extendLifetimePromises.shift()) {\n await promise;\n }\n }\n /**\n * Stops running the strategy and immediately resolves any pending\n * `waitUntil()` promises.\n */\n destroy() {\n this._handlerDeferred.resolve();\n }\n /**\n * This method will call cacheWillUpdate on the available plugins (or use\n * status === 200) to determine if the Response is safe and valid to cache.\n *\n * @param {Request} options.request\n * @param {Response} options.response\n * @return {Promise}\n *\n * @private\n */\n async _ensureResponseSafeToCache(response) {\n let responseToCache = response;\n let pluginsUsed = false;\n for (const callback of this.iterateCallbacks('cacheWillUpdate')) {\n responseToCache = (await callback({\n request: this.request,\n response: responseToCache,\n event: this.event,\n })) || undefined;\n pluginsUsed = true;\n if (!responseToCache) {\n break;\n }\n }\n if (!pluginsUsed) {\n if (responseToCache && responseToCache.status !== 200) {\n responseToCache = undefined;\n }\n if (process.env.NODE_ENV !== 'production') {\n if (responseToCache) {\n if (responseToCache.status !== 200) {\n if (responseToCache.status === 0) {\n logger.warn(`The response for '${this.request.url}' ` +\n `is an opaque response. The caching strategy that you're ` +\n `using will not cache opaque responses by default.`);\n }\n else {\n logger.debug(`The response for '${this.request.url}' ` +\n `returned a status code of '${response.status}' and won't ` +\n `be cached as a result.`);\n }\n }\n }\n }\n }\n return responseToCache;\n }\n}\nexport { StrategyHandler };\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * Returns a promise that resolves and the passed number of milliseconds.\n * This utility is an async/await-friendly version of `setTimeout`.\n *\n * @param {number} ms\n * @return {Promise}\n * @private\n */\nexport function timeout(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst getFriendlyURL = (url) => {\n const urlObj = new URL(String(url), location.href);\n // See https://github.com/GoogleChrome/workbox/issues/2323\n // We want to include everything, except for the origin if it's same-origin.\n return urlObj.href.replace(new RegExp(`^${location.origin}`), '');\n};\nexport { getFriendlyURL };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from '../_private/logger.js';\nimport { quotaErrorCallbacks } from '../models/quotaErrorCallbacks.js';\nimport '../_version.js';\n/**\n * Runs all of the callback functions, one at a time sequentially, in the order\n * in which they were registered.\n *\n * @memberof module:workbox-core\n * @private\n */\nasync function executeQuotaErrorCallbacks() {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`About to run ${quotaErrorCallbacks.size} ` +\n `callbacks to clean up caches.`);\n }\n for (const callback of quotaErrorCallbacks) {\n await callback();\n if (process.env.NODE_ENV !== 'production') {\n logger.log(callback, 'is complete.');\n }\n }\n if (process.env.NODE_ENV !== 'production') {\n logger.log('Finished running callbacks.');\n }\n}\nexport { executeQuotaErrorCallbacks };\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { copyResponse } from 'workbox-core/copyResponse.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { Strategy } from 'workbox-strategies/Strategy.js';\nimport './_version.js';\n/**\n * A [Strategy]{@link module:workbox-strategies.Strategy} implementation\n * specifically designed to work with\n * [PrecacheController]{@link module:workbox-precaching.PrecacheController}\n * to both cache and fetch precached assets.\n *\n * Note: an instance of this class is created automatically when creating a\n * `PrecacheController`; it's generally not necessary to create this yourself.\n *\n * @extends module:workbox-strategies.Strategy\n * @memberof module:workbox-precaching\n */\nclass PrecacheStrategy extends Strategy {\n /**\n *\n * @param {Object} [options]\n * @param {string} [options.cacheName] Cache name to store and retrieve\n * requests. Defaults to the cache names provided by\n * [workbox-core]{@link module:workbox-core.cacheNames}.\n * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}\n * to use in conjunction with this caching strategy.\n * @param {Object} [options.fetchOptions] Values passed along to the\n * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters}\n * of all fetch() requests made by this strategy.\n * @param {Object} [options.matchOptions] The\n * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}\n * for any `cache.match()` or `cache.put()` calls made by this strategy.\n * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to\n * get the response from the network if there's a precache miss.\n */\n constructor(options = {}) {\n options.cacheName = cacheNames.getPrecacheName(options.cacheName);\n super(options);\n this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true;\n // Redirected responses cannot be used to satisfy a navigation request, so\n // any redirected response must be \"copied\" rather than cloned, so the new\n // response doesn't contain the `redirected` flag. See:\n // https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1\n this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);\n }\n /**\n * @private\n * @param {Request|string} request A request to run this strategy for.\n * @param {module:workbox-strategies.StrategyHandler} handler The event that\n * triggered the request.\n * @return {Promise}\n */\n async _handle(request, handler) {\n const response = await handler.cacheMatch(request);\n if (!response) {\n // If this is an `install` event then populate the cache. If this is a\n // `fetch` event (or any other event) then respond with the cached\n // response.\n if (handler.event && handler.event.type === 'install') {\n return await this._handleInstall(request, handler);\n }\n return await this._handleFetch(request, handler);\n }\n return response;\n }\n async _handleFetch(request, handler) {\n let response;\n // Fall back to the network if we don't have a cached response\n // (perhaps due to manual cache cleanup).\n if (this._fallbackToNetwork) {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn(`The precached response for ` +\n `${getFriendlyURL(request.url)} in ${this.cacheName} was not ` +\n `found. Falling back to the network instead.`);\n }\n response = await handler.fetch(request);\n }\n else {\n // This shouldn't normally happen, but there are edge cases:\n // https://github.com/GoogleChrome/workbox/issues/1441\n throw new WorkboxError('missing-precache-entry', {\n cacheName: this.cacheName,\n url: request.url,\n });\n }\n if (process.env.NODE_ENV !== 'production') {\n const cacheKey = handler.params && handler.params.cacheKey ||\n await handler.getCacheKey(request, 'read');\n // Workbox is going to handle the route.\n // print the routing details to the console.\n logger.groupCollapsed(`Precaching is responding to: ` +\n getFriendlyURL(request.url));\n logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey.url)}`);\n logger.groupCollapsed(`View request details here.`);\n logger.log(request);\n logger.groupEnd();\n logger.groupCollapsed(`View response details here.`);\n logger.log(response);\n logger.groupEnd();\n logger.groupEnd();\n }\n return response;\n }\n async _handleInstall(request, handler) {\n this._useDefaultCacheabilityPluginIfNeeded();\n const response = await handler.fetch(request);\n // Make sure we defer cachePut() until after we know the response\n // should be cached; see https://github.com/GoogleChrome/workbox/issues/2737\n const wasCached = await handler.cachePut(request, response.clone());\n if (!wasCached) {\n // Throwing here will lead to the `install` handler failing, which\n // we want to do if *any* of the responses aren't safe to cache.\n throw new WorkboxError('bad-precaching-response', {\n url: request.url,\n status: response.status,\n });\n }\n return response;\n }\n /**\n * This method is complex, as there a number of things to account for:\n *\n * The `plugins` array can be set at construction, and/or it might be added to\n * to at any time before the strategy is used.\n *\n * At the time the strategy is used (i.e. during an `install` event), there\n * needs to be at least one plugin that implements `cacheWillUpdate` in the\n * array, other than `copyRedirectedCacheableResponsesPlugin`.\n *\n * - If this method is called and there are no suitable `cacheWillUpdate`\n * plugins, we need to add `defaultPrecacheCacheabilityPlugin`.\n *\n * - If this method is called and there is exactly one `cacheWillUpdate`, then\n * we don't have to do anything (this might be a previously added\n * `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin).\n *\n * - If this method is called and there is more than one `cacheWillUpdate`,\n * then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so,\n * we need to remove it. (This situation is unlikely, but it could happen if\n * the strategy is used multiple times, the first without a `cacheWillUpdate`,\n * and then later on after manually adding a custom `cacheWillUpdate`.)\n *\n * See https://github.com/GoogleChrome/workbox/issues/2737 for more context.\n *\n * @private\n */\n _useDefaultCacheabilityPluginIfNeeded() {\n let defaultPluginIndex = null;\n let cacheWillUpdatePluginCount = 0;\n for (const [index, plugin] of this.plugins.entries()) {\n // Ignore the copy redirected plugin when determining what to do.\n if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) {\n continue;\n }\n // Save the default plugin's index, in case it needs to be removed.\n if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {\n defaultPluginIndex = index;\n }\n if (plugin.cacheWillUpdate) {\n cacheWillUpdatePluginCount++;\n }\n }\n if (cacheWillUpdatePluginCount === 0) {\n this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);\n }\n else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {\n // Only remove the default plugin; multiple custom plugins are allowed.\n this.plugins.splice(defaultPluginIndex, 1);\n }\n // Nothing needs to be done if cacheWillUpdatePluginCount is 1\n }\n}\nPrecacheStrategy.defaultPrecacheCacheabilityPlugin = {\n async cacheWillUpdate({ response }) {\n if (!response || response.status >= 400) {\n return null;\n }\n return response;\n }\n};\nPrecacheStrategy.copyRedirectedCacheableResponsesPlugin = {\n async cacheWillUpdate({ response }) {\n return response.redirected ? await copyResponse(response) : response;\n }\n};\nexport { PrecacheStrategy };\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { StrategyHandler } from './StrategyHandler.js';\nimport './_version.js';\n/**\n * An abstract base class that all other strategy classes must extend from:\n *\n * @memberof module:workbox-strategies\n */\nclass Strategy {\n /**\n * Creates a new instance of the strategy and sets all documented option\n * properties as public instance properties.\n *\n * Note: if a custom strategy class extends the base Strategy class and does\n * not need more than these properties, it does not need to define its own\n * constructor.\n *\n * @param {Object} [options]\n * @param {string} [options.cacheName] Cache name to store and retrieve\n * requests. Defaults to the cache names provided by\n * [workbox-core]{@link module:workbox-core.cacheNames}.\n * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}\n * to use in conjunction with this caching strategy.\n * @param {Object} [options.fetchOptions] Values passed along to the\n * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)\n * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796)\n * `fetch()` requests made by this strategy.\n * @param {Object} [options.matchOptions] The\n * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}\n * for any `cache.match()` or `cache.put()` calls made by this strategy.\n */\n constructor(options = {}) {\n /**\n * Cache name to store and retrieve\n * requests. Defaults to the cache names provided by\n * [workbox-core]{@link module:workbox-core.cacheNames}.\n *\n * @type {string}\n */\n this.cacheName = cacheNames.getRuntimeName(options.cacheName);\n /**\n * The list\n * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}\n * used by this strategy.\n *\n * @type {Array}\n */\n this.plugins = options.plugins || [];\n /**\n * Values passed along to the\n * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters}\n * of all fetch() requests made by this strategy.\n *\n * @type {Object}\n */\n this.fetchOptions = options.fetchOptions;\n /**\n * The\n * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions}\n * for any `cache.match()` or `cache.put()` calls made by this strategy.\n *\n * @type {Object}\n */\n this.matchOptions = options.matchOptions;\n }\n /**\n * Perform a request strategy and returns a `Promise` that will resolve with\n * a `Response`, invoking all relevant plugin callbacks.\n *\n * When a strategy instance is registered with a Workbox\n * [route]{@link module:workbox-routing.Route}, this method is automatically\n * called when the route matches.\n *\n * Alternatively, this method can be used in a standalone `FetchEvent`\n * listener by passing it to `event.respondWith()`.\n *\n * @param {FetchEvent|Object} options A `FetchEvent` or an object with the\n * properties listed below.\n * @param {Request|string} options.request A request to run this strategy for.\n * @param {ExtendableEvent} options.event The event associated with the\n * request.\n * @param {URL} [options.url]\n * @param {*} [options.params]\n */\n handle(options) {\n const [responseDone] = this.handleAll(options);\n return responseDone;\n }\n /**\n * Similar to [`handle()`]{@link module:workbox-strategies.Strategy~handle}, but\n * instead of just returning a `Promise` that resolves to a `Response` it\n * it will return an tuple of [response, done] promises, where the former\n * (`response`) is equivalent to what `handle()` returns, and the latter is a\n * Promise that will resolve once any promises that were added to\n * `event.waitUntil()` as part of performing the strategy have completed.\n *\n * You can await the `done` promise to ensure any extra work performed by\n * the strategy (usually caching responses) completes successfully.\n *\n * @param {FetchEvent|Object} options A `FetchEvent` or an object with the\n * properties listed below.\n * @param {Request|string} options.request A request to run this strategy for.\n * @param {ExtendableEvent} options.event The event associated with the\n * request.\n * @param {URL} [options.url]\n * @param {*} [options.params]\n * @return {Array} A tuple of [response, done]\n * promises that can be used to determine when the response resolves as\n * well as when the handler has completed all its work.\n */\n handleAll(options) {\n // Allow for flexible options to be passed.\n if (options instanceof FetchEvent) {\n options = {\n event: options,\n request: options.request,\n };\n }\n const event = options.event;\n const request = typeof options.request === 'string' ?\n new Request(options.request) :\n options.request;\n const params = 'params' in options ? options.params : undefined;\n const handler = new StrategyHandler(this, { event, request, params });\n const responseDone = this._getResponse(handler, request, event);\n const handlerDone = this._awaitComplete(responseDone, handler, request, event);\n // Return an array of promises, suitable for use with Promise.all().\n return [responseDone, handlerDone];\n }\n async _getResponse(handler, request, event) {\n await handler.runCallbacks('handlerWillStart', { event, request });\n let response = undefined;\n try {\n response = await this._handle(request, handler);\n // The \"official\" Strategy subclasses all throw this error automatically,\n // but in case a third-party Strategy doesn't, ensure that we have a\n // consistent failure when there's no response or an error response.\n if (!response || response.type === 'error') {\n throw new WorkboxError('no-response', { url: request.url });\n }\n }\n catch (error) {\n for (const callback of handler.iterateCallbacks('handlerDidError')) {\n response = await callback({ error, event, request });\n if (response) {\n break;\n }\n }\n if (!response) {\n throw error;\n }\n else if (process.env.NODE_ENV !== 'production') {\n logger.log(`While responding to '${getFriendlyURL(request.url)}', ` +\n `an ${error} error occurred. Using a fallback response provided by ` +\n `a handlerDidError plugin.`);\n }\n }\n for (const callback of handler.iterateCallbacks('handlerWillRespond')) {\n response = await callback({ event, request, response });\n }\n return response;\n }\n async _awaitComplete(responseDone, handler, request, event) {\n let response;\n let error;\n try {\n response = await responseDone;\n }\n catch (error) {\n // Ignore errors, as response errors should be caught via the `response`\n // promise above. The `done` promise will only throw for errors in\n // promises passed to `handler.waitUntil()`.\n }\n try {\n await handler.runCallbacks('handlerDidRespond', {\n event,\n request,\n response,\n });\n await handler.doneWaiting();\n }\n catch (waitUntilError) {\n error = waitUntilError;\n }\n await handler.runCallbacks('handlerDidComplete', {\n event,\n request,\n response,\n error,\n });\n handler.destroy();\n if (error) {\n throw error;\n }\n }\n}\nexport { Strategy };\n/**\n * Classes extending the `Strategy` based class should implement this method,\n * and leverage the [`handler`]{@link module:workbox-strategies.StrategyHandler}\n * arg to perform all fetching and cache logic, which will ensure all relevant\n * cache, cache options, fetch options and plugins are used (per the current\n * strategy instance).\n *\n * @name _handle\n * @instance\n * @abstract\n * @function\n * @param {Request} request\n * @param {module:workbox-strategies.StrategyHandler} handler\n * @return {Promise}\n *\n * @memberof module:workbox-strategies.Strategy\n */\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { waitUntil } from 'workbox-core/_private/waitUntil.js';\nimport { createCacheKey } from './utils/createCacheKey.js';\nimport { PrecacheInstallReportPlugin } from './utils/PrecacheInstallReportPlugin.js';\nimport { PrecacheCacheKeyPlugin } from './utils/PrecacheCacheKeyPlugin.js';\nimport { printCleanupDetails } from './utils/printCleanupDetails.js';\nimport { printInstallDetails } from './utils/printInstallDetails.js';\nimport { PrecacheStrategy } from './PrecacheStrategy.js';\nimport './_version.js';\n/**\n * Performs efficient precaching of assets.\n *\n * @memberof module:workbox-precaching\n */\nclass PrecacheController {\n /**\n * Create a new PrecacheController.\n *\n * @param {Object} [options]\n * @param {string} [options.cacheName] The cache to use for precaching.\n * @param {string} [options.plugins] Plugins to use when precaching as well\n * as responding to fetch events for precached assets.\n * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to\n * get the response from the network if there's a precache miss.\n */\n constructor({ cacheName, plugins = [], fallbackToNetwork = true } = {}) {\n this._urlsToCacheKeys = new Map();\n this._urlsToCacheModes = new Map();\n this._cacheKeysToIntegrities = new Map();\n this._strategy = new PrecacheStrategy({\n cacheName: cacheNames.getPrecacheName(cacheName),\n plugins: [\n ...plugins,\n new PrecacheCacheKeyPlugin({ precacheController: this }),\n ],\n fallbackToNetwork,\n });\n // Bind the install and activate methods to the instance.\n this.install = this.install.bind(this);\n this.activate = this.activate.bind(this);\n }\n /**\n * @type {module:workbox-precaching.PrecacheStrategy} The strategy created by this controller and\n * used to cache assets and respond to fetch events.\n */\n get strategy() {\n return this._strategy;\n }\n /**\n * Adds items to the precache list, removing any duplicates and\n * stores the files in the\n * [\"precache cache\"]{@link module:workbox-core.cacheNames} when the service\n * worker installs.\n *\n * This method can be called multiple times.\n *\n * @param {Array} [entries=[]] Array of entries to precache.\n */\n precache(entries) {\n this.addToCacheList(entries);\n if (!this._installAndActiveListenersAdded) {\n self.addEventListener('install', this.install);\n self.addEventListener('activate', this.activate);\n this._installAndActiveListenersAdded = true;\n }\n }\n /**\n * This method will add items to the precache list, removing duplicates\n * and ensuring the information is valid.\n *\n * @param {Array} entries\n * Array of entries to precache.\n */\n addToCacheList(entries) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isArray(entries, {\n moduleName: 'workbox-precaching',\n className: 'PrecacheController',\n funcName: 'addToCacheList',\n paramName: 'entries',\n });\n }\n const urlsToWarnAbout = [];\n for (const entry of entries) {\n // See https://github.com/GoogleChrome/workbox/issues/2259\n if (typeof entry === 'string') {\n urlsToWarnAbout.push(entry);\n }\n else if (entry && entry.revision === undefined) {\n urlsToWarnAbout.push(entry.url);\n }\n const { cacheKey, url } = createCacheKey(entry);\n const cacheMode = (typeof entry !== 'string' && entry.revision) ?\n 'reload' : 'default';\n if (this._urlsToCacheKeys.has(url) &&\n this._urlsToCacheKeys.get(url) !== cacheKey) {\n throw new WorkboxError('add-to-cache-list-conflicting-entries', {\n firstEntry: this._urlsToCacheKeys.get(url),\n secondEntry: cacheKey,\n });\n }\n if (typeof entry !== 'string' && entry.integrity) {\n if (this._cacheKeysToIntegrities.has(cacheKey) &&\n this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) {\n throw new WorkboxError('add-to-cache-list-conflicting-integrities', {\n url,\n });\n }\n this._cacheKeysToIntegrities.set(cacheKey, entry.integrity);\n }\n this._urlsToCacheKeys.set(url, cacheKey);\n this._urlsToCacheModes.set(url, cacheMode);\n if (urlsToWarnAbout.length > 0) {\n const warningMessage = `Workbox is precaching URLs without revision ` +\n `info: ${urlsToWarnAbout.join(', ')}\\nThis is generally NOT safe. ` +\n `Learn more at https://bit.ly/wb-precache`;\n if (process.env.NODE_ENV === 'production') {\n // Use console directly to display this warning without bloating\n // bundle sizes by pulling in all of the logger codebase in prod.\n console.warn(warningMessage);\n }\n else {\n logger.warn(warningMessage);\n }\n }\n }\n }\n /**\n * Precaches new and updated assets. Call this method from the service worker\n * install event.\n *\n * Note: this method calls `event.waitUntil()` for you, so you do not need\n * to call it yourself in your event handlers.\n *\n * @param {ExtendableEvent} event\n * @return {Promise}\n */\n install(event) {\n return waitUntil(event, async () => {\n const installReportPlugin = new PrecacheInstallReportPlugin();\n this.strategy.plugins.push(installReportPlugin);\n // Cache entries one at a time.\n // See https://github.com/GoogleChrome/workbox/issues/2528\n for (const [url, cacheKey] of this._urlsToCacheKeys) {\n const integrity = this._cacheKeysToIntegrities.get(cacheKey);\n const cacheMode = this._urlsToCacheModes.get(url);\n const request = new Request(url, {\n integrity,\n cache: cacheMode,\n credentials: 'same-origin',\n });\n await Promise.all(this.strategy.handleAll({\n params: { cacheKey },\n request,\n event,\n }));\n }\n const { updatedURLs, notUpdatedURLs } = installReportPlugin;\n if (process.env.NODE_ENV !== 'production') {\n printInstallDetails(updatedURLs, notUpdatedURLs);\n }\n return { updatedURLs, notUpdatedURLs };\n });\n }\n /**\n * Deletes assets that are no longer present in the current precache manifest.\n * Call this method from the service worker activate event.\n *\n * Note: this method calls `event.waitUntil()` for you, so you do not need\n * to call it yourself in your event handlers.\n *\n * @param {ExtendableEvent} event\n * @return {Promise}\n */\n activate(event) {\n return waitUntil(event, async () => {\n const cache = await self.caches.open(this.strategy.cacheName);\n const currentlyCachedRequests = await cache.keys();\n const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());\n const deletedURLs = [];\n for (const request of currentlyCachedRequests) {\n if (!expectedCacheKeys.has(request.url)) {\n await cache.delete(request);\n deletedURLs.push(request.url);\n }\n }\n if (process.env.NODE_ENV !== 'production') {\n printCleanupDetails(deletedURLs);\n }\n return { deletedURLs };\n });\n }\n /**\n * Returns a mapping of a precached URL to the corresponding cache key, taking\n * into account the revision information for the URL.\n *\n * @return {Map} A URL to cache key mapping.\n */\n getURLsToCacheKeys() {\n return this._urlsToCacheKeys;\n }\n /**\n * Returns a list of all the URLs that have been precached by the current\n * service worker.\n *\n * @return {Array} The precached URLs.\n */\n getCachedURLs() {\n return [...this._urlsToCacheKeys.keys()];\n }\n /**\n * Returns the cache key used for storing a given URL. If that URL is\n * unversioned, like `/index.html', then the cache key will be the original\n * URL with a search parameter appended to it.\n *\n * @param {string} url A URL whose cache key you want to look up.\n * @return {string} The versioned URL that corresponds to a cache key\n * for the original URL, or undefined if that URL isn't precached.\n */\n getCacheKeyForURL(url) {\n const urlObject = new URL(url, location.href);\n return this._urlsToCacheKeys.get(urlObject.href);\n }\n /**\n * This acts as a drop-in replacement for\n * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)\n * with the following differences:\n *\n * - It knows what the name of the precache is, and only checks in that cache.\n * - It allows you to pass in an \"original\" URL without versioning parameters,\n * and it will automatically look up the correct cache key for the currently\n * active revision of that URL.\n *\n * E.g., `matchPrecache('index.html')` will find the correct precached\n * response for the currently active service worker, even if the actual cache\n * key is `'/index.html?__WB_REVISION__=1234abcd'`.\n *\n * @param {string|Request} request The key (without revisioning parameters)\n * to look up in the precache.\n * @return {Promise}\n */\n async matchPrecache(request) {\n const url = request instanceof Request ? request.url : request;\n const cacheKey = this.getCacheKeyForURL(url);\n if (cacheKey) {\n const cache = await self.caches.open(this.strategy.cacheName);\n return cache.match(cacheKey);\n }\n return undefined;\n }\n /**\n * Returns a function that looks up `url` in the precache (taking into\n * account revision information), and returns the corresponding `Response`.\n *\n * @param {string} url The precached URL which will be used to lookup the\n * `Response`.\n * @return {module:workbox-routing~handlerCallback}\n */\n createHandlerBoundToURL(url) {\n const cacheKey = this.getCacheKeyForURL(url);\n if (!cacheKey) {\n throw new WorkboxError('non-precached-url', { url });\n }\n return (options) => {\n options.request = new Request(url);\n options.params = { cacheKey, ...options.params };\n return this.strategy.handle(options);\n };\n }\n}\nexport { PrecacheController };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { PrecacheController } from '../PrecacheController.js';\nimport '../_version.js';\nlet precacheController;\n/**\n * @return {PrecacheController}\n * @private\n */\nexport const getOrCreatePrecacheController = () => {\n if (!precacheController) {\n precacheController = new PrecacheController();\n }\n return precacheController;\n};\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { Route } from 'workbox-routing/Route.js';\nimport { generateURLVariations } from './utils/generateURLVariations.js';\nimport './_version.js';\n/**\n * A subclass of [Route]{@link module:workbox-routing.Route} that takes a\n * [PrecacheController]{@link module:workbox-precaching.PrecacheController}\n * instance and uses it to match incoming requests and handle fetching\n * responses from the precache.\n *\n * @memberof module:workbox-precaching\n * @extends module:workbox-routing.Route\n */\nclass PrecacheRoute extends Route {\n /**\n * @param {PrecacheController} precacheController A `PrecacheController`\n * instance used to both match requests and respond to fetch events.\n * @param {Object} [options] Options to control how requests are matched\n * against the list of precached URLs.\n * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will\n * check cache entries for a URLs ending with '/' to see if there is a hit when\n * appending the `directoryIndex` value.\n * @param {Array} [options.ignoreURLParametersMatching=[/^utm_/, /^fbclid$/]] An\n * array of regex's to remove search params when looking for a cache match.\n * @param {boolean} [options.cleanURLs=true] The `cleanURLs` option will\n * check the cache for the URL with a `.html` added to the end of the end.\n * @param {module:workbox-precaching~urlManipulation} [options.urlManipulation]\n * This is a function that should take a URL and return an array of\n * alternative URLs that should be checked for precache matches.\n */\n constructor(precacheController, options) {\n const match = ({ request }) => {\n const urlsToCacheKeys = precacheController.getURLsToCacheKeys();\n for (const possibleURL of generateURLVariations(request.url, options)) {\n const cacheKey = urlsToCacheKeys.get(possibleURL);\n if (cacheKey) {\n return { cacheKey };\n }\n }\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Precaching did not find a match for ` +\n getFriendlyURL(request.url));\n }\n return;\n };\n super(match, precacheController.strategy);\n }\n}\nexport { PrecacheRoute };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { removeIgnoredSearchParams } from './removeIgnoredSearchParams.js';\nimport '../_version.js';\n/**\n * Generator function that yields possible variations on the original URL to\n * check, one at a time.\n *\n * @param {string} url\n * @param {Object} options\n *\n * @private\n * @memberof module:workbox-precaching\n */\nexport function* generateURLVariations(url, { ignoreURLParametersMatching = [/^utm_/, /^fbclid$/], directoryIndex = 'index.html', cleanURLs = true, urlManipulation, } = {}) {\n const urlObject = new URL(url, location.href);\n urlObject.hash = '';\n yield urlObject.href;\n const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching);\n yield urlWithoutIgnoredParams.href;\n if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) {\n const directoryURL = new URL(urlWithoutIgnoredParams.href);\n directoryURL.pathname += directoryIndex;\n yield directoryURL.href;\n }\n if (cleanURLs) {\n const cleanURL = new URL(urlWithoutIgnoredParams.href);\n cleanURL.pathname += '.html';\n yield cleanURL.href;\n }\n if (urlManipulation) {\n const additionalURLs = urlManipulation({ url: urlObject });\n for (const urlToAttempt of additionalURLs) {\n yield urlToAttempt.href;\n }\n }\n}\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * Removes any URL search parameters that should be ignored.\n *\n * @param {URL} urlObject The original URL.\n * @param {Array} ignoreURLParametersMatching RegExps to test against\n * each search parameter name. Matches mean that the search parameter should be\n * ignored.\n * @return {URL} The URL with any ignored search parameters removed.\n *\n * @private\n * @memberof module:workbox-precaching\n */\nexport function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {\n // Convert the iterable into an array at the start of the loop to make sure\n // deletion doesn't mess up iteration.\n for (const paramName of [...urlObject.searchParams.keys()]) {\n if (ignoreURLParametersMatching.some((regExp) => regExp.test(paramName))) {\n urlObject.searchParams.delete(paramName);\n }\n }\n return urlObject;\n}\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { registerRoute } from 'workbox-routing/registerRoute.js';\nimport { getOrCreatePrecacheController } from './utils/getOrCreatePrecacheController.js';\nimport { PrecacheRoute } from './PrecacheRoute.js';\nimport './_version.js';\n/**\n * Add a `fetch` listener to the service worker that will\n * respond to\n * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests}\n * with precached assets.\n *\n * Requests for assets that aren't precached, the `FetchEvent` will not be\n * responded to, allowing the event to fall through to other `fetch` event\n * listeners.\n *\n * @param {Object} [options] See\n * [PrecacheRoute options]{@link module:workbox-precaching.PrecacheRoute}.\n *\n * @memberof module:workbox-precaching\n */\nfunction addRoute(options) {\n const precacheController = getOrCreatePrecacheController();\n const precacheRoute = new PrecacheRoute(precacheController, options);\n registerRoute(precacheRoute);\n}\nexport { addRoute };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { Route } from './Route.js';\nimport { RegExpRoute } from './RegExpRoute.js';\nimport { getOrCreateDefaultRouter } from './utils/getOrCreateDefaultRouter.js';\nimport './_version.js';\n/**\n * Easily register a RegExp, string, or function with a caching\n * strategy to a singleton Router instance.\n *\n * This method will generate a Route for you if needed and\n * call [registerRoute()]{@link module:workbox-routing.Router#registerRoute}.\n *\n * @param {RegExp|string|module:workbox-routing.Route~matchCallback|module:workbox-routing.Route} capture\n * If the capture param is a `Route`, all other arguments will be ignored.\n * @param {module:workbox-routing~handlerCallback} [handler] A callback\n * function that returns a Promise resulting in a Response. This parameter\n * is required if `capture` is not a `Route` object.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n * @return {module:workbox-routing.Route} The generated `Route`(Useful for\n * unregistering).\n *\n * @memberof module:workbox-routing\n */\nfunction registerRoute(capture, handler, method) {\n let route;\n if (typeof capture === 'string') {\n const captureUrl = new URL(capture, location.href);\n if (process.env.NODE_ENV !== 'production') {\n if (!(capture.startsWith('/') || capture.startsWith('http'))) {\n throw new WorkboxError('invalid-string', {\n moduleName: 'workbox-routing',\n funcName: 'registerRoute',\n paramName: 'capture',\n });\n }\n // We want to check if Express-style wildcards are in the pathname only.\n // TODO: Remove this log message in v4.\n const valueToCheck = capture.startsWith('http') ?\n captureUrl.pathname : capture;\n // See https://github.com/pillarjs/path-to-regexp#parameters\n const wildcards = '[*:?+]';\n if ((new RegExp(`${wildcards}`)).exec(valueToCheck)) {\n logger.debug(`The '$capture' parameter contains an Express-style wildcard ` +\n `character (${wildcards}). Strings are now always interpreted as ` +\n `exact matches; use a RegExp for partial or wildcard matches.`);\n }\n }\n const matchCallback = ({ url }) => {\n if (process.env.NODE_ENV !== 'production') {\n if ((url.pathname === captureUrl.pathname) &&\n (url.origin !== captureUrl.origin)) {\n logger.debug(`${capture} only partially matches the cross-origin URL ` +\n `${url}. This route will only handle cross-origin requests ` +\n `if they match the entire URL.`);\n }\n }\n return url.href === captureUrl.href;\n };\n // If `capture` is a string then `handler` and `method` must be present.\n route = new Route(matchCallback, handler, method);\n }\n else if (capture instanceof RegExp) {\n // If `capture` is a `RegExp` then `handler` and `method` must be present.\n route = new RegExpRoute(capture, handler, method);\n }\n else if (typeof capture === 'function') {\n // If `capture` is a function then `handler` and `method` must be present.\n route = new Route(capture, handler, method);\n }\n else if (capture instanceof Route) {\n route = capture;\n }\n else {\n throw new WorkboxError('unsupported-route-type', {\n moduleName: 'workbox-routing',\n funcName: 'registerRoute',\n paramName: 'capture',\n });\n }\n const defaultRouter = getOrCreateDefaultRouter();\n defaultRouter.registerRoute(route);\n return route;\n}\nexport { registerRoute };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { addRoute } from './addRoute.js';\nimport { precache } from './precache.js';\nimport './_version.js';\n/**\n * This method will add entries to the precache list and add a route to\n * respond to fetch events.\n *\n * This is a convenience method that will call\n * [precache()]{@link module:workbox-precaching.precache} and\n * [addRoute()]{@link module:workbox-precaching.addRoute} in a single call.\n *\n * @param {Array} entries Array of entries to precache.\n * @param {Object} [options] See\n * [PrecacheRoute options]{@link module:workbox-precaching.PrecacheRoute}.\n *\n * @memberof module:workbox-precaching\n */\nfunction precacheAndRoute(entries, options) {\n precache(entries);\n addRoute(options);\n}\nexport { precacheAndRoute };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { getOrCreatePrecacheController } from './utils/getOrCreatePrecacheController.js';\nimport './_version.js';\n/**\n * Adds items to the precache list, removing any duplicates and\n * stores the files in the\n * [\"precache cache\"]{@link module:workbox-core.cacheNames} when the service\n * worker installs.\n *\n * This method can be called multiple times.\n *\n * Please note: This method **will not** serve any of the cached files for you.\n * It only precaches files. To respond to a network request you call\n * [addRoute()]{@link module:workbox-precaching.addRoute}.\n *\n * If you have a single array of files to precache, you can just call\n * [precacheAndRoute()]{@link module:workbox-precaching.precacheAndRoute}.\n *\n * @param {Array} [entries=[]] Array of entries to precache.\n *\n * @memberof module:workbox-precaching\n */\nfunction precache(entries) {\n const precacheController = getOrCreatePrecacheController();\n precacheController.precache(entries);\n}\nexport { precache };\n"],"names":["self","_","e","messageGenerator","code","args","msg","length","JSON","stringify","WorkboxError","Error","constructor","errorCode","details","name","normalizeHandler","handler","handle","Route","match","method","setCatchHandler","catchHandler","RegExpRoute","regExp","url","result","exec","href","origin","location","index","slice","Router","_routes","Map","_defaultHandlerMap","this","addFetchListener","addEventListener","event","request","responsePromise","handleRequest","respondWith","addCacheListener","data","type","payload","requestPromises","Promise","all","urlsToCache","map","entry","Request","waitUntil","ports","then","postMessage","URL","protocol","startsWith","sameOrigin","params","route","findMatchingRoute","has","get","err","reject","_catchHandler","catch","async","catchErr","routes","matchResult","Array","isArray","Object","keys","undefined","setDefaultHandler","set","registerRoute","push","unregisterRoute","routeIndex","indexOf","splice","defaultRouter","_cacheNameDetails","googleAnalytics","precache","prefix","runtime","suffix","registration","scope","_createCacheName","cacheName","filter","value","join","cacheNames","userCacheName","asyncFn","returnPromise","createCacheKey","urlObject","cacheKey","revision","cacheKeyURL","originalURL","searchParams","PrecacheInstallReportPlugin","updatedURLs","notUpdatedURLs","handlerWillStart","state","originalRequest","cachedResponseWillBeUsed","cachedResponse","PrecacheCacheKeyPlugin","precacheController","cacheKeyWillBeUsed","_precacheController","getCacheKeyForURL","supportStatus","copyResponse","response","modifier","clonedResponse","clone","responseInit","headers","Headers","status","statusText","modifiedResponseInit","body","testResponse","Response","error","canConstructResponseFromBodyStream","blob","stripParams","fullURL","ignoreParams","strippedURL","param","delete","Deferred","promise","resolve","quotaErrorCallbacks","Set","toRequest","input","StrategyHandler","strategy","options","_cacheKeys","assign","_strategy","_handlerDeferred","_extendLifetimePromises","_plugins","plugins","_pluginStateMap","plugin","mode","FetchEvent","preloadResponse","possiblePreloadResponse","hasCallback","cb","iterateCallbacks","thrownError","pluginFilteredRequest","fetchResponse","fetch","fetchOptions","callback","runCallbacks","responseClone","cachePut","key","matchOptions","effectiveRequest","getCacheKey","multiMatchOptions","caches","ms","setTimeout","String","replace","RegExp","responseToCache","_ensureResponseSafeToCache","cache","open","hasCacheUpdateCallback","oldResponse","strippedRequestURL","keysOptions","ignoreSearch","cacheKeys","cacheMatchIgnoreParams","put","executeQuotaErrorCallbacks","newResponse","statefulCallback","statefulParam","shift","destroy","pluginsUsed","PrecacheStrategy","responseDone","handleAll","_getResponse","_awaitComplete","_handle","doneWaiting","waitUntilError","_fallbackToNetwork","fallbackToNetwork","copyRedirectedCacheableResponsesPlugin","cacheMatch","_handleInstall","_handleFetch","_useDefaultCacheabilityPluginIfNeeded","defaultPluginIndex","cacheWillUpdatePluginCount","entries","defaultPrecacheCacheabilityPlugin","cacheWillUpdate","redirected","PrecacheController","_urlsToCacheKeys","_urlsToCacheModes","_cacheKeysToIntegrities","install","bind","activate","addToCacheList","_installAndActiveListenersAdded","urlsToWarnAbout","cacheMode","firstEntry","secondEntry","integrity","warningMessage","console","warn","installReportPlugin","credentials","currentlyCachedRequests","expectedCacheKeys","values","deletedURLs","getURLsToCacheKeys","getCachedURLs","createHandlerBoundToURL","getOrCreatePrecacheController","PrecacheRoute","urlsToCacheKeys","possibleURL","ignoreURLParametersMatching","directoryIndex","cleanURLs","urlManipulation","hash","urlWithoutIgnoredParams","paramName","some","test","removeIgnoredSearchParams","pathname","endsWith","directoryURL","cleanURL","additionalURLs","urlToAttempt","generateURLVariations","addRoute","capture","captureUrl","moduleName","funcName"],"mappings":"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"} --------------------------------------------------------------------------------