From f37b6abea4e365893ab835380129888df2318f19 Mon Sep 17 00:00:00 2001 From: Deepthi Sigireddi Date: Mon, 27 Jun 2022 01:14:07 -0700 Subject: [PATCH] add vtadmin docker image (#10543) (#10580) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add-vtadmin-docker-image Signed-off-by: Léopold Jacquot * env as function, update tests and code Signed-off-by: Andrew Mason Signed-off-by: Léopold Jacquot * feat: fix remaining env usages to be function calls Signed-off-by: Manan Gupta Signed-off-by: Léopold Jacquot * add vtadmin build result in the bootstrap image Signed-off-by: Léopold Jacquot * fix vtadmin web cleaning Signed-off-by: Léopold Jacquot * add vtadmin docker image entrypoint Signed-off-by: Léopold Jacquot * add the possibility to custom vtadmin web port in Docker image Signed-off-by: Léopold Jacquot * fix vtadmin docker port Signed-off-by: Léopold Jacquot * fix vtadmin entrypoint Signed-off-by: Léopold Jacquot * set default vtadmin docker user as vitess Signed-off-by: Léopold Jacquot * do not build vtadmin frontend in the bootstrap image Signed-off-by: Léopold Jacquot * build vtadmin frontend only in vtadmin docker image Signed-off-by: Léopold Jacquot * vtadmin replace sed and custom entrypoint with config.js file Signed-off-by: Léopold Jacquot * remove vitess web files in lite docker image Signed-off-by: Léopold Jacquot * move vtadmin config into a specific directory Signed-off-by: Léopold Jacquot * restore vtadmin web file in mysql57 lite docker image Signed-off-by: Léopold Jacquot Co-authored-by: Andrew Mason Co-authored-by: Manan Gupta Co-authored-by: Léopold Jacquot Co-authored-by: Andrew Mason Co-authored-by: Manan Gupta --- .dockerignore | 2 + docker/k8s/vtadmin/Dockerfile | 55 ++++++ docker/release.sh | 5 + go/vt/vtadmin/README.md | 2 +- web/vtadmin/package-lock.json | 168 ++++-------------- web/vtadmin/package.json | 2 +- web/vtadmin/public/config/config.js | 8 + web/vtadmin/public/index.html | 3 +- web/vtadmin/src/api/http.ts | 9 +- .../src/components/routes/Settings.tsx | 3 +- .../src/components/routes/tablet/Tablet.tsx | 3 +- .../routes/workflow/WorkflowStreams.tsx | 3 +- web/vtadmin/src/errors/bugsnag.ts | 5 +- web/vtadmin/src/errors/errorHandler.ts | 3 +- web/vtadmin/src/hooks/useDocumentTitle.ts | 3 +- web/vtadmin/src/react-app-env.d.ts | 4 +- web/vtadmin/src/util/env.ts | 6 +- 17 files changed, 133 insertions(+), 151 deletions(-) create mode 100644 docker/k8s/vtadmin/Dockerfile create mode 100644 web/vtadmin/public/config/config.js diff --git a/.dockerignore b/.dockerignore index 98cca97e5d..b71f6e4df5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,3 +9,5 @@ releases /vthook/ /bin/ /vtdataroot/ +/web/vtadmin/node_modules +/web/vtadmin/build diff --git a/docker/k8s/vtadmin/Dockerfile b/docker/k8s/vtadmin/Dockerfile new file mode 100644 index 0000000000..eb61557ec7 --- /dev/null +++ b/docker/k8s/vtadmin/Dockerfile @@ -0,0 +1,55 @@ +# Copyright 2022 The Vitess Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG VT_BASE_VER=latest +ARG DEBIAN_VER=bullseye-slim + +FROM vitess/k8s:${VT_BASE_VER} AS k8s + +FROM node:16-${DEBIAN_VER} as node + +# Set up Vitess environment (just enough to run pre-built Go binaries) +ENV VTROOT /vt +ENV VTADMIN_WEB_PORT=14201 + +# Prepare directory structure. +RUN mkdir -p /vt/bin && \ + mkdir -p /vt/web && mkdir -p /vtdataroot + +# Copy binaries +COPY --from=k8s /vt/bin/vtadmin /vt/bin/ + +# Copy certs to allow https calls +COPY --from=k8s /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +# copy web admin files +COPY --from=k8s /vt/web/vtadmin /vt/web/vtadmin + +# install/build/clean web dependencies +RUN npm --prefix /vt/web/vtadmin ci && \ + npm run --prefix /vt/web/vtadmin build + +# add vitess user/group and add permissions +RUN deluser node && \ + groupadd -r --gid 2000 vitess && \ + useradd -r -g vitess --uid 1000 vitess && \ + chown -R vitess:vitess /vt && \ + chown -R vitess:vitess /vtdataroot + +USER vitess + +VOLUME /vt/web/vtadmin/build/config + +CMD ["/bin/bash", "-c", "/vt/web/vtadmin/node_modules/.bin/serve --no-clipboard -l $VTADMIN_WEB_PORT -s /vt/web/vtadmin/build"] + diff --git a/docker/release.sh b/docker/release.sh index 5b3b9fda94..37e9de2d10 100755 --- a/docker/release.sh +++ b/docker/release.sh @@ -16,6 +16,11 @@ do docker push vitess/k8s:$vt_base_version-$debian_version if [[ $debian_version == $default_debian_version ]]; then docker push vitess/k8s:$vt_base_version; fi + docker build --platform linux/amd64 --build-arg VT_BASE_VER=$vt_base_version --build-arg DEBIAN_VER=$debian_version-slim -t vitess/vtadmin:$vt_base_version-$debian_version k8s/vtadmin + docker tag vitess/vtadmin:$vt_base_version-$debian_version vitess/vtadmin:$vt_base_version + docker push vitess/vtadmin:$vt_base_version-$debian_version + if [[ $debian_version == $default_debian_version ]]; then docker push vitess/vtadmin:$vt_base_version; fi + docker build --platform linux/amd64 --build-arg VT_BASE_VER=$vt_base_version --build-arg DEBIAN_VER=$debian_version-slim -t vitess/vtgate:$vt_base_version-$debian_version k8s/vtgate docker tag vitess/vtgate:$vt_base_version-$debian_version vitess/vtgate:$vt_base_version docker push vitess/vtgate:$vt_base_version-$debian_version diff --git a/go/vt/vtadmin/README.md b/go/vt/vtadmin/README.md index d794df9069..75ef9cdc20 100644 --- a/go/vt/vtadmin/README.md +++ b/go/vt/vtadmin/README.md @@ -49,7 +49,7 @@ Then, you can run `make build`, and run `./bin/vtadmin` with any flags you need ### Building and running `vtadmin-web` -Make sure you are using node version 12.x. +Make sure you are using node version 16.x. Then, you may run: diff --git a/web/vtadmin/package-lock.json b/web/vtadmin/package-lock.json index 07ac0cf853..41e6a7f45b 100644 --- a/web/vtadmin/package-lock.json +++ b/web/vtadmin/package-lock.json @@ -34,6 +34,7 @@ "react-tiny-popover": "^6.0.5", "react-toastify": "^8.1.0", "sass": "^1.43.4", + "serve": "^13.0.2", "svgo": "^2.8.0", "typescript": "^4.5.4", "web-vitals": "^0.2.4" @@ -49,7 +50,6 @@ "postcss": "^8.4.6", "prettier": "^2.2.1", "protobufjs": "^6.10.2", - "serve": "^13.0.2", "stylelint": "^14.4.0", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard-scss": "^3.0.0", @@ -4962,8 +4962,7 @@ "node_modules/@zeit/schemas": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", - "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==", - "dev": true + "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==" }, "node_modules/abab": { "version": "2.0.5", @@ -5127,7 +5126,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, "dependencies": { "string-width": "^4.1.0" } @@ -5200,7 +5198,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, "funding": [ { "type": "github", @@ -5880,7 +5877,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, "dependencies": { "ansi-align": "^3.0.0", "camelcase": "^6.2.0", @@ -5902,7 +5898,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -5917,7 +5912,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5933,7 +5927,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -5944,14 +5937,12 @@ "node_modules/boxen/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/boxen/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -5960,7 +5951,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -5972,7 +5962,6 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, "engines": { "node": ">=10" }, @@ -6315,7 +6304,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, "engines": { "node": ">=6" }, @@ -6360,7 +6348,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", - "dev": true, "dependencies": { "arch": "^2.1.1", "execa": "^1.0.0", @@ -6374,7 +6361,6 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -6390,7 +6376,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, "dependencies": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -6408,7 +6393,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, "dependencies": { "pump": "^3.0.0" }, @@ -6420,7 +6404,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6429,7 +6412,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, "dependencies": { "path-key": "^2.0.0" }, @@ -6441,7 +6423,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, "engines": { "node": ">=4" } @@ -6450,7 +6431,6 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, "bin": { "semver": "bin/semver" } @@ -6459,7 +6439,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "dependencies": { "shebang-regex": "^1.0.0" }, @@ -6471,7 +6450,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7820,7 +7798,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, "engines": { "node": ">=4.0.0" } @@ -9436,7 +9413,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", - "dev": true, "dependencies": { "punycode": "^1.3.2" } @@ -9444,8 +9420,7 @@ "node_modules/fast-url-parser/node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "node_modules/fastest-levenshtein": { "version": "1.0.12", @@ -15283,8 +15258,7 @@ "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "node_modules/no-case": { "version": "3.0.4", @@ -15706,7 +15680,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, "engines": { "node": ">=4" } @@ -15834,8 +15807,7 @@ "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "node_modules/path-key": { "version": "3.1.1", @@ -16809,7 +16781,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -16824,7 +16795,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -17442,7 +17412,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", - "dev": true, "dependencies": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -17452,7 +17421,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, "dependencies": { "rc": "^1.0.1" }, @@ -18110,7 +18078,6 @@ "version": "13.0.2", "resolved": "https://registry.npmjs.org/serve/-/serve-13.0.2.tgz", "integrity": "sha512-71R6fKvNgKrqARAag6lYJNnxDzpH7DCNrMuvPY5PLVaC2PDhJsGTj/34o4o4tPWhTuLgEXqvgnAWbATQ9zGZTQ==", - "dev": true, "dependencies": { "@zeit/schemas": "2.6.0", "ajv": "6.12.6", @@ -18130,7 +18097,6 @@ "version": "6.1.3", "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", - "dev": true, "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", @@ -18146,7 +18112,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, "engines": { "node": ">= 0.8" } @@ -18155,7 +18120,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true, "engines": { "node": ">= 0.6" } @@ -18164,7 +18128,6 @@ "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -18173,7 +18136,6 @@ "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, "dependencies": { "mime-db": "~1.33.0" }, @@ -18185,7 +18147,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -18196,14 +18157,12 @@ "node_modules/serve-handler/node_modules/path-to-regexp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", - "dev": true + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" }, "node_modules/serve-handler/node_modules/range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true, "engines": { "node": ">= 0.6" } @@ -18279,14 +18238,12 @@ "node_modules/serve/node_modules/arg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz", - "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==", - "dev": true + "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==" }, "node_modules/serve/node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, "engines": { "node": ">= 0.8" } @@ -18295,7 +18252,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -18309,7 +18265,6 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", - "dev": true, "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -18327,7 +18282,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "dependencies": { "ms": "2.0.0" } @@ -18335,8 +18289,7 @@ "node_modules/serve/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/set-cookie-parser": { "version": "2.4.8", @@ -18819,7 +18772,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -19928,7 +19880,6 @@ "version": "1.5.2", "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz", "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==", - "dev": true, "dependencies": { "registry-auth-token": "3.3.2", "registry-url": "3.1.0" @@ -20526,7 +20477,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, "dependencies": { "string-width": "^4.0.0" }, @@ -24618,8 +24568,7 @@ "@zeit/schemas": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz", - "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==", - "dev": true + "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==" }, "abab": { "version": "2.0.5", @@ -24744,7 +24693,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, "requires": { "string-width": "^4.1.0" } @@ -24792,8 +24740,7 @@ "arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==" }, "arg": { "version": "5.0.1", @@ -25301,7 +25248,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, "requires": { "ansi-align": "^3.0.0", "camelcase": "^6.2.0", @@ -25317,7 +25263,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -25326,7 +25271,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -25336,7 +25280,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -25344,20 +25287,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -25365,8 +25305,7 @@ "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" } } }, @@ -25611,8 +25550,7 @@ "cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" }, "cli-cursor": { "version": "3.1.0", @@ -25639,7 +25577,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz", "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==", - "dev": true, "requires": { "arch": "^2.1.1", "execa": "^1.0.0", @@ -25650,7 +25587,6 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -25663,7 +25599,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", @@ -25678,7 +25613,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, "requires": { "pump": "^3.0.0" } @@ -25686,14 +25620,12 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, "requires": { "path-key": "^2.0.0" } @@ -25701,20 +25633,17 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -25722,8 +25651,7 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" } } }, @@ -26637,8 +26565,7 @@ "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "deep-is": { "version": "0.1.4", @@ -27848,7 +27775,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", - "dev": true, "requires": { "punycode": "^1.3.2" }, @@ -27856,8 +27782,7 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" } } }, @@ -32139,8 +32064,7 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "no-case": { "version": "3.0.4", @@ -32446,8 +32370,7 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, "p-limit": { "version": "2.3.0", @@ -32539,8 +32462,7 @@ "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "path-key": { "version": "3.1.1", @@ -33209,7 +33131,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -33220,8 +33141,7 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" } } }, @@ -33675,7 +33595,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", - "dev": true, "requires": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -33685,7 +33604,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, "requires": { "rc": "^1.0.1" } @@ -34139,7 +34057,6 @@ "version": "13.0.2", "resolved": "https://registry.npmjs.org/serve/-/serve-13.0.2.tgz", "integrity": "sha512-71R6fKvNgKrqARAag6lYJNnxDzpH7DCNrMuvPY5PLVaC2PDhJsGTj/34o4o4tPWhTuLgEXqvgnAWbATQ9zGZTQ==", - "dev": true, "requires": { "@zeit/schemas": "2.6.0", "ajv": "6.12.6", @@ -34155,20 +34072,17 @@ "arg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz", - "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==", - "dev": true + "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==" }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -34179,7 +34093,6 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz", "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", - "dev": true, "requires": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -34194,7 +34107,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -34202,8 +34114,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -34211,7 +34122,6 @@ "version": "6.1.3", "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", - "dev": true, "requires": { "bytes": "3.0.0", "content-disposition": "0.5.2", @@ -34226,26 +34136,22 @@ "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, "requires": { "mime-db": "~1.33.0" } @@ -34254,7 +34160,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -34262,14 +34167,12 @@ "path-to-regexp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", - "dev": true + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" } } }, @@ -34714,8 +34617,7 @@ "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-final-newline": { "version": "2.0.0", @@ -35502,7 +35404,6 @@ "version": "1.5.2", "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz", "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==", - "dev": true, "requires": { "registry-auth-token": "3.3.2", "registry-url": "3.1.0" @@ -35951,7 +35852,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, "requires": { "string-width": "^4.0.0" } diff --git a/web/vtadmin/package.json b/web/vtadmin/package.json index a2c2601934..a31e5485c5 100644 --- a/web/vtadmin/package.json +++ b/web/vtadmin/package.json @@ -33,6 +33,7 @@ "react-tiny-popover": "^6.0.5", "react-toastify": "^8.1.0", "sass": "^1.43.4", + "serve": "^13.0.2", "svgo": "^2.8.0", "typescript": "^4.5.4", "web-vitals": "^0.2.4" @@ -86,7 +87,6 @@ "postcss": "^8.4.6", "prettier": "^2.2.1", "protobufjs": "^6.10.2", - "serve": "^13.0.2", "stylelint": "^14.4.0", "stylelint-config-prettier": "^9.0.3", "stylelint-config-standard-scss": "^3.0.0", diff --git a/web/vtadmin/public/config/config.js b/web/vtadmin/public/config/config.js new file mode 100644 index 0000000000..ee97d86937 --- /dev/null +++ b/web/vtadmin/public/config/config.js @@ -0,0 +1,8 @@ +window.env = { + 'REACT_APP_VTADMIN_API_ADDRESS': "", + 'REACT_APP_FETCH_CREDENTIALS': "omit", + 'REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS': true, + 'REACT_APP_BUGSNAG_API_KEY': "", + 'REACT_APP_DOCUMENT_TITLE': "", + 'REACT_APP_READONLY_MODE': false, +}; diff --git a/web/vtadmin/public/index.html b/web/vtadmin/public/index.html index 597cf34065..033821017b 100644 --- a/web/vtadmin/public/index.html +++ b/web/vtadmin/public/index.html @@ -7,7 +7,8 @@ - + + VTAdmin diff --git a/web/vtadmin/src/api/http.ts b/web/vtadmin/src/api/http.ts index 25f41640d6..4bec4cf74c 100644 --- a/web/vtadmin/src/api/http.ts +++ b/web/vtadmin/src/api/http.ts @@ -19,7 +19,7 @@ import * as errorHandler from '../errors/errorHandler'; import { HttpFetchError, HttpResponseNotOkError, MalformedHttpResponseError } from '../errors/errorTypes'; import { HttpOkResponse } from './responseTypes'; import { TabletDebugVars } from '../util/tabletDebugVars'; -import { isReadOnlyMode } from '../util/env'; +import { env, isReadOnlyMode } from '../util/env'; /** * vtfetch makes HTTP requests against the given vtadmin-api endpoint @@ -41,8 +41,7 @@ export const vtfetch = async (endpoint: string, options: RequestInit = {}): Prom throw new Error(`Cannot execute write request in read-only mode: ${options.method} ${endpoint}`); } - const { REACT_APP_VTADMIN_API_ADDRESS } = process.env; - const url = `${REACT_APP_VTADMIN_API_ADDRESS}${endpoint}`; + const url = `${env().REACT_APP_VTADMIN_API_ADDRESS}${endpoint}`; const opts = { ...vtfetchOpts(), ...options }; let response = null; @@ -87,7 +86,7 @@ export const vtfetch = async (endpoint: string, options: RequestInit = {}): Prom }; export const vtfetchOpts = (): RequestInit => { - const credentials = process.env.REACT_APP_FETCH_CREDENTIALS; + const credentials = env().REACT_APP_FETCH_CREDENTIALS; if (credentials && credentials !== 'omit' && credentials !== 'same-origin' && credentials !== 'include') { throw Error( `Invalid fetch credentials property: ${credentials}. Must be undefined or one of omit, same-origin, include` @@ -384,7 +383,7 @@ export interface TabletDebugVarsResponse { } export const fetchExperimentalTabletDebugVars = async (params: FetchTabletParams): Promise => { - if (!process.env.REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS) { + if (!env().REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS) { return Promise.resolve({ params }); } diff --git a/web/vtadmin/src/components/routes/Settings.tsx b/web/vtadmin/src/components/routes/Settings.tsx index b9cdcf4c55..b0253d0fbe 100644 --- a/web/vtadmin/src/components/routes/Settings.tsx +++ b/web/vtadmin/src/components/routes/Settings.tsx @@ -11,6 +11,7 @@ import { TabContainer } from '../tabs/TabContainer'; import { TextInput } from '../TextInput'; import Toggle from '../toggle/Toggle'; import { Tooltip } from '../tooltip/Tooltip'; +import { env } from '../../util/env'; import style from './Settings.module.scss'; /* eslint-disable jsx-a11y/anchor-is-valid */ @@ -26,7 +27,7 @@ export const Settings = () => {

Settings

Environment variables

-
{JSON.stringify(process.env, null, 2)}
+
{JSON.stringify(env(), null, 2)}
{process.env.NODE_ENV !== 'production' && ( <> diff --git a/web/vtadmin/src/components/routes/tablet/Tablet.tsx b/web/vtadmin/src/components/routes/tablet/Tablet.tsx index f8421a0025..6e8695cc64 100644 --- a/web/vtadmin/src/components/routes/tablet/Tablet.tsx +++ b/web/vtadmin/src/components/routes/tablet/Tablet.tsx @@ -33,6 +33,7 @@ import Advanced from './Advanced'; import style from './Tablet.module.scss'; import { TabletCharts } from './TabletCharts'; import { TabletReplication } from './TabletReplication'; +import { env } from '../../../util/env'; interface RouteParams { alias: string; @@ -125,7 +126,7 @@ export const Tablet = () => {
- {process.env.REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS && ( + {env().REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS && ( )}
diff --git a/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx index 218b38b276..91173a4215 100644 --- a/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx +++ b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx @@ -28,6 +28,7 @@ import { TabletLink } from '../../links/TabletLink'; import { StreamStatePip } from '../../pips/StreamStatePip'; import { WorkflowStreamsLagChart } from '../../charts/WorkflowStreamsLagChart'; import { ShardLink } from '../../links/ShardLink'; +import { env } from '../../../util/env'; interface Props { clusterID: string; @@ -106,7 +107,7 @@ export const WorkflowStreams = ({ clusterID, keyspace, name }: Props) => { return (
- {process.env.REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS && ( + {env().REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS && ( <>

Stream VReplication Lag

diff --git a/web/vtadmin/src/errors/bugsnag.ts b/web/vtadmin/src/errors/bugsnag.ts index 4a985dee3f..098c2537eb 100644 --- a/web/vtadmin/src/errors/bugsnag.ts +++ b/web/vtadmin/src/errors/bugsnag.ts @@ -15,8 +15,9 @@ */ import BugsnagJS from '@bugsnag/js'; import { ErrorHandler } from './errorTypes'; +import { env } from '../util/env'; -const { REACT_APP_BUGSNAG_API_KEY } = process.env; +const { REACT_APP_BUGSNAG_API_KEY } = env(); /** * If using Bugsnag, Bugsnag.start() will automatically capture and report @@ -24,7 +25,7 @@ const { REACT_APP_BUGSNAG_API_KEY } = process.env; * initialize it for capturing handled errors. */ export const initialize = () => { - if (typeof REACT_APP_BUGSNAG_API_KEY === 'string') { + if (typeof REACT_APP_BUGSNAG_API_KEY === 'string' && REACT_APP_BUGSNAG_API_KEY.length) { BugsnagJS.start(REACT_APP_BUGSNAG_API_KEY); } }; diff --git a/web/vtadmin/src/errors/errorHandler.ts b/web/vtadmin/src/errors/errorHandler.ts index abc4faa71d..e031da9812 100644 --- a/web/vtadmin/src/errors/errorHandler.ts +++ b/web/vtadmin/src/errors/errorHandler.ts @@ -16,6 +16,7 @@ import { pick } from 'lodash'; import { getHandlers } from './errorHandlers'; +import { env } from '../util/env'; /** * Initializes error handling for both unhandled and handled exceptions. @@ -63,7 +64,7 @@ export const notify = (error: Error, metadata?: object) => { * leaking sensitive environment variables, like API keys. */ const sanitizeEnv = () => - pick(process.env, [ + pick(env(), [ 'REACT_APP_BUILD_BRANCH', 'REACT_APP_BUILD_SHA', 'REACT_APP_ENABLE_EXPERIMENTAL_TABLET_DEBUG_VARS', diff --git a/web/vtadmin/src/hooks/useDocumentTitle.ts b/web/vtadmin/src/hooks/useDocumentTitle.ts index a4a18f9cac..93584a39e6 100644 --- a/web/vtadmin/src/hooks/useDocumentTitle.ts +++ b/web/vtadmin/src/hooks/useDocumentTitle.ts @@ -1,6 +1,7 @@ import { useEffect } from 'react'; +import { env } from '../util/env'; -const BASE_TITLE = process.env.REACT_APP_DOCUMENT_TITLE || 'VTAdmin'; +const BASE_TITLE = env().REACT_APP_DOCUMENT_TITLE || 'VTAdmin'; // useDocumentTitle is a simple hook to set the document.title of the page. // diff --git a/web/vtadmin/src/react-app-env.d.ts b/web/vtadmin/src/react-app-env.d.ts index cecce7ca60..3d019534b7 100644 --- a/web/vtadmin/src/react-app-env.d.ts +++ b/web/vtadmin/src/react-app-env.d.ts @@ -43,4 +43,6 @@ declare namespace NodeJS { } } -interface Window {} +interface Window { + env: NodeJS.ProcessEnv; +} diff --git a/web/vtadmin/src/util/env.ts b/web/vtadmin/src/util/env.ts index adf74d6da7..082e3a8fc8 100644 --- a/web/vtadmin/src/util/env.ts +++ b/web/vtadmin/src/util/env.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +export const env: () => NodeJS.ProcessEnv = () => { + return { ...window.env, ...process.env }; +}; + // process.env variables are always strings, hence this tiny helper function // to transmute it into a boolean. It is a function, rather than a constant, // to support dynamic updates to process.env in tests. -export const isReadOnlyMode = (): boolean => process.env.REACT_APP_READONLY_MODE === 'true'; +export const isReadOnlyMode = (): boolean => env().REACT_APP_READONLY_MODE === 'true';