From 84424025da6359e7133ac0a9ca1b44582f1de9e8 Mon Sep 17 00:00:00 2001 From: Chris Maniewski Date: Thu, 7 Mar 2024 02:47:34 +0100 Subject: [PATCH] cicd: fix production build using import-meta-env --- .env.development | 40 +- .env.example | 38 +- Dockerfile | 115 +--- Readme.md | 10 +- docker/files/frontend/nginx.conf | 9 + docker/files/frontend/start.sh | 8 + index.html | 5 + package-lock.json | 646 +++++++----------- package.json | 10 +- src/Entry.tsx | 4 +- src/apollo/apolloClient.ts | 2 +- src/auth/index.ts | 2 +- .../partials/GroupedTransaction.tsx | 2 +- src/constants/index.ts | 10 +- .../AnalyticsContextProvider.tsx | 2 +- src/context/ipfs/ipfsWithFallbackContext.ts | 7 +- src/context/ipfs/pinata/constants.ts | 6 +- src/redux/sagas/utils/getNetworkClient.ts | 10 +- src/redux/sagas/utils/metatransactions.ts | 2 +- src/redux/sagas/utils/safeHelpers.ts | 4 +- src/redux/sagas/wallet/onboard.ts | 2 +- src/typedefs/globals.d.ts | 38 +- src/utils/checks/canUseMetatransactions.ts | 3 +- src/utils/safes/getContractUsefulMethods.ts | 4 +- vite.config.mts | 16 +- 25 files changed, 380 insertions(+), 615 deletions(-) create mode 100644 docker/files/frontend/nginx.conf create mode 100644 docker/files/frontend/start.sh diff --git a/.env.development b/.env.development index 55e5febc0a4..3201aeb4d35 100644 --- a/.env.development +++ b/.env.development @@ -1,22 +1,20 @@ -# Environment variables for the frontend in development mode +# # Environment variables for the frontend in development mode +# +NETWORK_ID="ganache" +SAFE_ENABLED="false" +REPUTATION_ORACLE_ENDPOINT="http://localhost:3001/reputation/local" +NETWORK_CONTRACT_ADDRESS= +METATX_ENABLED=true +METATX_BROADCASTER_ENDPOINT="http://localhost:3004" +AUTH_PROXY_ENDPOINT="http://localhost:3005" +BSCSCAN_API_KEY= +ETHERSCAN_API_KEY= +GOOGLE_TAG_MANAGER_ID= +PINATA_API_KEY= +PINATA_API_SECRET= +COINGECKO_API_KEY= -# Network the CDapp is deployed to -VITE_NETWORK="ganache" - -# The endpoint of the reputation oracle. -VITE_REPUTATION_ORACLE_ENDPOINT="http://localhost:3001/reputation/local" - -# If the network has / or does not have support for metatranasctions -# Ie: contracts deployed, broadcaster service active -VITE_METATX_ENABLED=true -VITE_METATX_BROADCASTER_ENDPOINT="http://localhost:3004" - -# The endpoint of the service where etherrouter-addres.json, ganache-accounts.json & safe-addresses.json can be found for frontend -VITE_NETWORK_FILES_ENDPOINT="http://localhost:3006" -VITE_GANACHE_RPC_URL="http://localhost:8545" - -# URL where the authentication server is found -VITE_AUTH_PROXY_ENDPOINT="http://localhost:3005" - -# For debugging -VITE_DEBUG=true +# Used in development only +DEBUG=true +NETWORK_FILES_ENDPOINT="http://localhost:3006" +GANACHE_RPC_URL="http://localhost:8545" diff --git a/.env.example b/.env.example index 114575fe56c..1bb3501a2fc 100644 --- a/.env.example +++ b/.env.example @@ -1,46 +1,44 @@ # All possible environment variables for the frontend (set at build time **will end up in source code!!!**) # Network the CDapp is deployed to -VITE_NETWORK="ganache" +NETWORK_ID="ganache" + +# Whether to enable Safe integration +SAFE_ENABLED="false" # EtherRouter contract address for the network the CDapp is deployed to # DOES NOT NEED TO BE SET WHEN DEVELOPING LOCALLY -VITE_NETWORK_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000" +NETWORK_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000" # Required for safe control -VITE_BSCSCAN_API_KEY= -VITE_ETHERSCAN_API_KEY= +BSCSCAN_API_KEY= +ETHERSCAN_API_KEY= # The endpoint of the reputation oracle. -VITE_REPUTATION_ORACLE_ENDPOINT="http://localhost:3001/reputation/local" +REPUTATION_ORACLE_ENDPOINT="http://localhost:3001/reputation/local" # If the network has / or does not have support for metatranasctions # Ie: contracts deployed, broadcaster service active -VITE_METATX_ENABLED=true -VITE_METATX_BROADCASTER_ENDPOINT="http://localhost:3004" +METATX_ENABLED=true +METATX_BROADCASTER_ENDPOINT="http://localhost:3004" # The endpoint of the service where etherrouter-addres.json, ganache-accounts.json & safe-addresses.json can be found for frontend -VITE_NETWORK_FILES_ENDPOINT="http://localhost:3006" -VITE_GANACHE_RPC_URL="http://localhost:8545" +NETWORK_FILES_ENDPOINT="http://localhost:3006" +GANACHE_RPC_URL="http://localhost:8545" # URL where the authentication server is found -VITE_AUTH_PROXY_ENDPOINT="http://localhost:3005" +AUTH_PROXY_ENDPOINT="http://localhost:3005" # ID for Google Tag Manager `GTM-XXXXXXX` -VITE_GOOGLE_TAG_MANAGER_ID= +GOOGLE_TAG_MANAGER_ID= # pinata connection detail from https://app.pinata.cloud/developers/api-keys # Only needed for production -VITE_PINATA_API_KEY= -VITE_PINATA_API_SECRET= +PINATA_API_KEY= +PINATA_API_SECRET= # Needed for currency conversion. For testing, see: https://support.coingecko.com/hc/en-us/articles/21880397454233 -VITE_COINGECKO_API_KEY= +COINGECKO_API_KEY= # For debugging -VITE_DEBUG=true - -# @NOTE Only on production -# It became apparent that we need a "live" way to check what commit we're running on while debugging issues strait into production -VITE_PROD_COMMIT_HASH= - +DEBUG=true diff --git a/Dockerfile b/Dockerfile index 8665fdb4b61..402f65c4d7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,91 +1,24 @@ -FROM node:20.11 - -# @FIX Allow the nginx service to start at build time, so that the installation will work -# See: https://askubuntu.com/questions/365911/why-the-services-do-not-start-at-installation -# RUN sed -i "s|exit 101|exit 0|g" /usr/sbin/policy-rc.d - -# Update the apt cache -RUN apt-get clean -RUN apt-get update - -# Apt-utils needs to be in before installing the rest -RUN apt-get install -y \ - locales \ - apt-utils \ - build-essential \ - curl \ - file \ - zip \ - nginx - -# Reconfigure locales -RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen -RUN locale-gen - -# Create the app directory -WORKDIR /colonyCDapp - -# Copy package.json, package-lock.json and required scripts -COPY package*.json . -COPY scripts/ ./scripts/ - -# Install node_modules -RUN npm ci - -# Copy colonyCDapp -COPY . . - -RUN echo "Building commit hash: $(git rev-parse --short HEAD)" - -RUN echo "\n\ -VITE_PROD_COMMIT_HASH$(git rev-parse --short HEAD)\n\ -VITE_SAFE_ENABLED=false\n\ -" > .env.production - -RUN npm run vite:prod - -# Copy the production bundle -RUN mkdir ../colonyCDappProd -RUN cp -R ./dist/* ../colonyCDappProd - -# Cleanup the source folder -WORKDIR / -RUN rm -Rf colonyCDapp -WORKDIR /colonyCDappProd - -# Setup a basic nginx config -RUN echo "server {\n" \ - " listen 80;\n" \ - " server_name default_server;\n\n" \ - " location / {\n" \ - " root /colonyCDappProd;\n" \ - " try_files \$uri /index.html;\n" \ - " }\n" \ - "}" > /etc/nginx/sites-available/default - -# Expose the HTTP port -EXPOSE 80 - -# @NOTE Hack! -# We replace the environment variables in the built bundle with the ones declared in the kubernetes config -# This is necessary since we aren't in a actual node process, they're just files served by nginx -# Doing it like this allows us to use the same image for different deployments -RUN echo "sed -i \"s|import.meta.env.VITE_NETWORK_CONTRACT_ADDRESS|\\\"\$NETWORK_CONTRACT_ADDRESS\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_URL|\\\"\$URL\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_NETWORK|\\\"\$NETWORK\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_AUTH_PROXY_ENDPOINT|\\\"\$AUTH_PROXY_ENDPOINT\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_METATX_ENABLED|\\\"\$METATX_ENABLED\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_METATX_BROADCASTER_ENDPOINT|\\\"\$BROADCASTER_ENDPOINT\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_REPUTATION_ORACLE_ENDPOINT|\\\"\$REPUTATION_ORACLE_ENDPOINT\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_GOOGLE_TAG_MANAGER_ID|\\\"\$GOOGLE_TAG_MANAGER_ID\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_PINATA_API_KEY|\\\"\$PINATA_API_KEY\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_PINATA_API_SECRET|\\\"\$PINATA_API_SECRET\\\"|g\" ./assets/*.js" \ - "&& sed -i \"s|import.meta.env.VITE_COINGECKO_API_KEY|\\\"\$COINGECKO_API_KEY\\\"|g\" ./assets/*.js" \ - " && nginx -g 'daemon off;'" > ./run.sh - -RUN chmod +x ./run.sh - -# @NOTE Run the actual command, rather then the service -# so that the docker container won't exit -CMD ./run.sh -# READY TO GO ! +# From https://github.com/runtime-env/import-meta-env/blob/main/packages/examples/docker-starter-example/Dockerfile +FROM node:20.11-alpine3.19 as build-stage +RUN apk add git +WORKDIR /app +# To get the git commit hash later +COPY .git ./.git +COPY package.json package-lock.json ./ +RUN SKIP_POSTINSTALL=true npm ci + +# Package the import-meta-env as single binary as we don't have node on the production container +RUN npx @yao-pkg/pkg ./node_modules/@import-meta-env/cli/bin/import-meta-env.js \ + -t node20-alpine-x64 \ + -o import-meta-env-alpine +COPY index.html vite.config.mts .env.example ./ +COPY src/* ./src/ +RUN npm run build + +FROM nginx:1.24.0-alpine as production-stage +RUN mkdir /app +COPY --from=build-stage /app/dist/* /app/dist/ +COPY --from=build-stage /app/import-meta-env-alpine /app/ +COPY .env.example docker/files/frontend/start.sh /app/ +COPY docker/files/frontend/nginx.conf /etc/nginx/ +ENTRYPOINT ["sh","/app/start.sh"] diff --git a/Readme.md b/Readme.md index d14dc8b0f85..f5e7e2d5450 100644 --- a/Readme.md +++ b/Readme.md @@ -28,10 +28,6 @@ npm install _Note: at the end of the install there's a post-install script that will recursively install dependencies for all the currently declared lambda functions_ -### Create `.env` file - -Copy `.env.example` and rename it to `.env`. You should not need to change any of the values to get CDapp running. - ## Running the dev environment ```bash @@ -44,10 +40,10 @@ On the next start, assuming no key cache files changed, it will skip the image b ## Running the dev web server -Once the above dev environment is up and running, you need to start your dev web server, running through vite: +Once the above dev environment is up and running, you need to start your dev web server: ```bash -npm run vite +npm run frontend ``` You can access it at `http://localhost:9091` _(notice the different port, as to not cause a local storage and cache conflict with the Dapp)_ @@ -81,7 +77,7 @@ _NOTE: This only works while the environment is running_ If you want to build the bundle locally for production, you can do it via: ```bash -npm run vite:prod +npm run build ``` _Note: It's a straight-up dev build. Just bundled, no code optimizations whatsoever._ diff --git a/docker/files/frontend/nginx.conf b/docker/files/frontend/nginx.conf new file mode 100644 index 00000000000..b6a072dc177 --- /dev/null +++ b/docker/files/frontend/nginx.conf @@ -0,0 +1,9 @@ +server { + listen 80; + server_name default_server; + location / { + root /app/dist; + index index.html; + try_files $uri $uri/ /index.html; + } +} diff --git a/docker/files/frontend/start.sh b/docker/files/frontend/start.sh new file mode 100644 index 00000000000..92b79d4d9e1 --- /dev/null +++ b/docker/files/frontend/start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cd /app +# Inject environment variables to index.html +./import-meta-env-alpine -x .env.example -p dist/index.html || exit 1 + +cd /app/dist +nginx -g "daemon off;" diff --git a/index.html b/index.html index 018a8100bc6..61de80d4ba2 100644 --- a/index.html +++ b/index.html @@ -13,6 +13,11 @@
+ + + diff --git a/package-lock.json b/package-lock.json index f6950209be1..ff4d75e7104 100644 --- a/package-lock.json +++ b/package-lock.json @@ -117,6 +117,8 @@ "@graphql-codegen/typescript": "^2.8.1", "@graphql-codegen/typescript-operations": "^2.5.6", "@graphql-codegen/typescript-react-apollo": "^3.3.6", + "@import-meta-env/cli": "^0.6.8", + "@import-meta-env/unplugin": "^0.5.1", "@jackfranklin/test-data-bot": "^1.4.0", "@jest/globals": "^29.0.2", "@storybook/addon-essentials": "^7.6.14", @@ -5947,6 +5949,109 @@ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", "dev": true }, + "node_modules/@import-meta-env/cli": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@import-meta-env/cli/-/cli-0.6.8.tgz", + "integrity": "sha512-Lunsmlj02yVtI5drlhNwIUFAQ0wsIUYIrz0Nm5jbvmYvyEUsxC8Qotnf3gXTfvM9Yuutvuc2+dx4uXpa3DajTg==", + "dev": true, + "dependencies": { + "commander": "11.1.0", + "glob": "10.3.10", + "picocolors": "1.0.0", + "serialize-javascript": "6.0.1" + }, + "bin": { + "import-meta-env": "bin/import-meta-env.js" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@import-meta-env/babel": "^0.4.3", + "@import-meta-env/swc": "^0.4.5", + "@import-meta-env/unplugin": "^0.4.8 || ^0.5.0", + "dotenv": "^11.0.0 || ^12.0.4 || ^13.0.1 || ^14.3.2 || ^15.0.1 || ^16.0.0" + }, + "peerDependenciesMeta": { + "@import-meta-env/babel": { + "optional": true + }, + "@import-meta-env/swc": { + "optional": true + }, + "@import-meta-env/unplugin": { + "optional": true + } + } + }, + "node_modules/@import-meta-env/cli/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@import-meta-env/cli/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@import-meta-env/cli/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/@import-meta-env/unplugin": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@import-meta-env/unplugin/-/unplugin-0.5.1.tgz", + "integrity": "sha512-2pn+eYha02TY+iJ8WAlGr9SnOx0o+OvddO6lzU9hBxkogWlU9Q1dI/9thacnjL9alOA3R2qGZPd79kaiYtw81A==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "magic-string": "^0.30.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "unplugin": "^1.5.0" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@import-meta-env/cli": "^0.5.1 || ^0.6.0", + "dotenv": "^11.0.0 || ^12.0.4 || ^13.0.1 || ^14.3.2 || ^15.0.1 || ^16.0.0" + }, + "peerDependenciesMeta": { + "@import-meta-env/cli": { + "optional": true + } + } + }, + "node_modules/@import-meta-env/unplugin/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -8450,22 +8555,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/addon-essentials/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/addon-essentials/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -8529,18 +8618,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@storybook/addon-essentials/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/addon-highlight": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.6.17.tgz", @@ -9156,22 +9233,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/blocks/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/blocks/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -9235,18 +9296,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@storybook/blocks/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/builder-manager": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.17.tgz", @@ -9389,22 +9438,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/builder-manager/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/builder-manager/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -9468,18 +9501,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@storybook/builder-manager/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/builder-vite": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-7.6.17.tgz", @@ -9675,22 +9696,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/builder-vite/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/builder-vite/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -9770,18 +9775,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/@storybook/builder-vite/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/channels": { "version": "7.4.5", "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.4.5.tgz", @@ -10017,34 +10010,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/@storybook/cli/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@storybook/cli/node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/cli/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -10468,22 +10433,6 @@ "integrity": "sha512-oTmGy68gxZZ21FhTJVVvZBYpQHEBZxHKTsGshobMqm9qWpbqdZsA5jvsuPZcHu0KwpmLrOHWPdEfg7XDpNT9UA==", "dev": true }, - "node_modules/@storybook/core-common/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/core-common/node_modules/fs-extra": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", @@ -10541,18 +10490,6 @@ "node": ">=10" } }, - "node_modules/@storybook/core-common/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/core-events": { "version": "7.4.5", "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.4.5.tgz", @@ -10759,22 +10696,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/core-server/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/core-server/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -10865,18 +10786,6 @@ "node": ">=10" } }, - "node_modules/@storybook/core-server/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/core-server/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -11662,22 +11571,6 @@ "source-map": "~0.6.1" } }, - "node_modules/@storybook/react/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/react/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -11741,18 +11634,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@storybook/react/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/react/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -11933,22 +11814,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/telemetry/node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/telemetry/node_modules/fs-extra": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", @@ -12012,18 +11877,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@storybook/telemetry/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/test": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/test/-/test-7.6.17.tgz", @@ -25451,6 +25304,34 @@ "node": ">=0.10.0" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -53467,6 +53348,15 @@ "upper-case-first": "^2.0.2" } }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -56122,16 +56012,6 @@ "node": ">= 10.13.0" } }, - "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -63285,6 +63165,65 @@ "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", "dev": true }, + "@import-meta-env/cli": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@import-meta-env/cli/-/cli-0.6.8.tgz", + "integrity": "sha512-Lunsmlj02yVtI5drlhNwIUFAQ0wsIUYIrz0Nm5jbvmYvyEUsxC8Qotnf3gXTfvM9Yuutvuc2+dx4uXpa3DajTg==", + "dev": true, + "requires": { + "commander": "11.1.0", + "glob": "10.3.10", + "picocolors": "1.0.0", + "serialize-javascript": "6.0.1" + }, + "dependencies": { + "commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + } + } + }, + "@import-meta-env/unplugin": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@import-meta-env/unplugin/-/unplugin-0.5.1.tgz", + "integrity": "sha512-2pn+eYha02TY+iJ8WAlGr9SnOx0o+OvddO6lzU9hBxkogWlU9Q1dI/9thacnjL9alOA3R2qGZPd79kaiYtw81A==", + "dev": true, + "requires": { + "magic-string": "^0.30.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "unplugin": "^1.5.0" + }, + "dependencies": { + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + } + } + }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -65024,16 +64963,6 @@ "undici-types": "~5.26.4" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -65075,12 +65004,6 @@ "requires": { "side-channel": "^1.0.4" } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true } } }, @@ -65518,16 +65441,6 @@ "undici-types": "~5.26.4" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -65569,12 +65482,6 @@ "requires": { "side-channel": "^1.0.4" } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true } } }, @@ -65692,16 +65599,6 @@ "undici-types": "~5.26.4" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -65743,12 +65640,6 @@ "requires": { "side-channel": "^1.0.4" } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true } } }, @@ -65894,16 +65785,6 @@ "undici-types": "~5.26.4" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -65954,12 +65835,6 @@ "requires": { "fsevents": "~2.3.2" } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true } } }, @@ -66149,24 +66024,6 @@ "strip-final-newline": "^2.0.0" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "dependencies": { - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - } - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -66481,16 +66338,6 @@ "integrity": "sha512-oTmGy68gxZZ21FhTJVVvZBYpQHEBZxHKTsGshobMqm9qWpbqdZsA5jvsuPZcHu0KwpmLrOHWPdEfg7XDpNT9UA==", "dev": true }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", @@ -66529,12 +66376,6 @@ "requires": { "find-up": "^5.0.0" } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true } } }, @@ -66708,16 +66549,6 @@ "undici-types": "~5.26.4" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -66778,12 +66609,6 @@ "lru-cache": "^6.0.0" } }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -67292,16 +67117,6 @@ "source-map": "~0.6.1" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -67344,12 +67159,6 @@ "side-channel": "^1.0.4" } }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -67567,16 +67376,6 @@ "undici-types": "~5.26.4" } }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, "fs-extra": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", @@ -67618,12 +67417,6 @@ "requires": { "side-channel": "^1.0.4" } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true } } }, @@ -77607,6 +77400,24 @@ "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -98781,6 +98592,15 @@ "upper-case-first": "^2.0.2" } }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -100864,16 +100684,6 @@ "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "peer": true, - "requires": { - "randombytes": "^2.1.0" - } } } }, diff --git a/package.json b/package.json index 9edd2ea9eeb..7b7ad3abcbd 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,9 @@ "lint:ci": "eslint src --ext ts,tsx --report-unused-disable-directives", "stylelint:ci": "stylelint --allow-empty-input \"src/**/*.css\"", "typecheck": "tsc --noEmit", - "vite": "ulimit -n 2048 && vite", - "vite:safe": "VITE_SAFE_ENABLED=true ulimit -n 2048 && vite", - "vite:prod": "vite build", + "frontend": "ulimit -n 2048 && vite", + "frontend:safe": "SAFE_ENABLED=true ulimit -n 2048 && vite", + "build": "vite build", "truffle": "docker exec -it network bash -c \"cd colonyNetwork && npx truffle console\"", "amplify": "amplify", "voyager": "ts-node temp-voyager/voyager", @@ -31,7 +31,7 @@ "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "chromatic": "npx chromatic --project-token=f08326e25dbf", - "postinstall": "./scripts/lambda-functions-dependencies.sh && scripts/generate-amplify-local-config.sh", + "postinstall": "if [ -z \"$SKIP_POSTINSTALL\" ]; then ./scripts/lambda-functions-dependencies.sh && scripts/generate-amplify-local-config.sh; fi", "upgrade-colony-js": "./scripts/upgrade-colony-js.sh" }, "repository": { @@ -49,6 +49,8 @@ "@graphql-codegen/typescript": "^2.8.1", "@graphql-codegen/typescript-operations": "^2.5.6", "@graphql-codegen/typescript-react-apollo": "^3.3.6", + "@import-meta-env/cli": "^0.6.8", + "@import-meta-env/unplugin": "^0.5.1", "@jackfranklin/test-data-bot": "^1.4.0", "@jest/globals": "^29.0.2", "@storybook/addon-essentials": "^7.6.14", diff --git a/src/Entry.tsx b/src/Entry.tsx index 1d63ab0b787..bf5672065ab 100644 --- a/src/Entry.tsx +++ b/src/Entry.tsx @@ -20,9 +20,9 @@ interface Props { store: any; } -if (import.meta.env.VITE_PROD_COMMIT_HASH) { +if (__COMMIT_HASH__) { // eslint-disable-next-line no-console - console.log(`Running on ${import.meta.env.VITE_PROD_COMMIT_HASH}`); + console.log(`Running on ${__COMMIT_HASH__}`); } const Entry = ({ store }: Props) => { diff --git a/src/apollo/apolloClient.ts b/src/apollo/apolloClient.ts index c7bc9b738ea..c8c509eb32e 100644 --- a/src/apollo/apolloClient.ts +++ b/src/apollo/apolloClient.ts @@ -5,7 +5,7 @@ import removeTypenameLink from './removeTypenameLink.ts'; const httpLink = new HttpLink({ uri: `${ - import.meta.env.VITE_AUTH_PROXY_ENDPOINT || 'http://localhost:3005' + import.meta.env.AUTH_PROXY_ENDPOINT || 'http://localhost:3005' }/graphql`, credentials: 'include', }); diff --git a/src/auth/index.ts b/src/auth/index.ts index 7f2c1ae8abf..7d202414e7c 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -7,7 +7,7 @@ import { isFullWallet } from '~types/wallet.ts'; const authProxyRequest = async (urlPartial: string, options?: RequestInit) => { try { const response = await fetch( - `${import.meta.env.VITE_AUTH_PROXY_ENDPOINT}/${urlPartial}`, + `${import.meta.env.AUTH_PROXY_ENDPOINT}/${urlPartial}`, { method: 'GET', headers: { diff --git a/src/components/common/Extensions/UserHub/partials/TransactionsTab/partials/GroupedTransaction.tsx b/src/components/common/Extensions/UserHub/partials/TransactionsTab/partials/GroupedTransaction.tsx index 2ab4b10a20d..5c67b5305da 100644 --- a/src/components/common/Extensions/UserHub/partials/TransactionsTab/partials/GroupedTransaction.tsx +++ b/src/components/common/Extensions/UserHub/partials/TransactionsTab/partials/GroupedTransaction.tsx @@ -42,7 +42,7 @@ const GroupedTransaction: FC = ({ }; const defaultTransactionGroupMessageDescriptorDescriptionId = { id: - import.meta.env.VITE_DEBUG === 'true' + import.meta.env.DEBUG === 'true' ? `${ transactionGroup[0].metatransaction ? 'meta' : '' }transaction.debug.description` diff --git a/src/constants/index.ts b/src/constants/index.ts index 858015b04de..ad7624eba93 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -50,7 +50,7 @@ export type NetworkInfo = { blockTime?: number; }; -export const DEFAULT_NETWORK = import.meta.env.VITE_NETWORK || Network.Ganache; +export const DEFAULT_NETWORK = import.meta.env.NETWORK_ID || Network.Ganache; export const COLONY_TOTAL_BALANCE_DOMAIN_ID = 0; export const DEFAULT_TOKEN_DECIMALS = 18; @@ -204,9 +204,9 @@ export const NETWORKS_WITH_METATRANSACTIONS = [ export const ADDRESS_ZERO = ethersContants.AddressZero; export const GANACHE_LOCAL_RPC_URL = - import.meta.env.VITE_GANACHE_RPC_URL || 'http://localhost:8545/'; + import.meta.env.GANACHE_RPC_URL || 'http://localhost:8545/'; -export const isDev = import.meta.env.VITE_NETWORK === 'ganache'; +export const isDev = import.meta.env.NETWORK_ID === 'ganache'; export const CDAPP_VERSION = version; @@ -293,6 +293,4 @@ export const FETCH_ABORTED = 'fetchAborted'; export const isFullScreen = 'isFullScreen'; -export const APP_URL = new URL( - import.meta.env.VITE_URL || 'http://localhost:9091/', -); +export const APP_URL = new URL(import.meta.env.URL || 'http://localhost:9091/'); diff --git a/src/context/AnalyticsContext/AnalyticsContextProvider.tsx b/src/context/AnalyticsContext/AnalyticsContextProvider.tsx index 3e4b1e28548..24528d03622 100644 --- a/src/context/AnalyticsContext/AnalyticsContextProvider.tsx +++ b/src/context/AnalyticsContext/AnalyticsContextProvider.tsx @@ -12,7 +12,7 @@ const defaultAnalyticsContext = { // AnalyticsContextProvider const AnalyticsContextProvider: FC = ({ children }) => { - const gtmId = import.meta.env.VITE_GOOGLE_TAG_MANAGER_ID; // GTM ID from environment variable + const gtmId = import.meta.env.GOOGLE_TAG_MANAGER_ID; // GTM ID from environment variable useBeamer(); const contextValue = useMemo(() => { diff --git a/src/context/ipfs/ipfsWithFallbackContext.ts b/src/context/ipfs/ipfsWithFallbackContext.ts index 60344ff4b89..2c63ec3efbf 100644 --- a/src/context/ipfs/ipfsWithFallbackContext.ts +++ b/src/context/ipfs/ipfsWithFallbackContext.ts @@ -4,11 +4,8 @@ import pinataClient from './pinataClient.ts'; const getIPFSContext = () => { if ( - import.meta.env.VITE_NETWORK === 'ganache' || - !( - import.meta.env.VITE_PINATA_API_KEY && - import.meta.env.VITE_PINATA_API_SECRET - ) + import.meta.env.NETWORK_ID === 'ganache' || + !(import.meta.env.PINATA_API_KEY && import.meta.env.PINATA_API_SECRET) ) { const ipfsNode = new IPFSNode(); return getIPFSWithFallback(ipfsNode); diff --git a/src/context/ipfs/pinata/constants.ts b/src/context/ipfs/pinata/constants.ts index 2d21d9579df..7240691ecd8 100644 --- a/src/context/ipfs/pinata/constants.ts +++ b/src/context/ipfs/pinata/constants.ts @@ -1,6 +1,4 @@ export const PINATA_ENDPOINT = 'https://api.pinata.cloud/pinning'; -export const PINATA_API_KEY: string | undefined = import.meta.env - .VITE_PINATA_API_KEY; -export const PINATA_API_SECRET: string | undefined = import.meta.env - .VITE_PINATA_API_SECRET; +export const { PINATA_API_KEY } = import.meta.env; +export const { PINATA_API_SECRET } = import.meta.env; export const JSON_MIME_TYPE = 'application/json'; diff --git a/src/redux/sagas/utils/getNetworkClient.ts b/src/redux/sagas/utils/getNetworkClient.ts index ccdb9bc0cb6..a785dae1b11 100644 --- a/src/redux/sagas/utils/getNetworkClient.ts +++ b/src/redux/sagas/utils/getNetworkClient.ts @@ -23,15 +23,15 @@ const getNetworkClient = async () => { const signer = wallet.ethersProvider.getSigner(); - const reputationOracleUrl = import.meta.env.VITE_REPUTATION_ORACLE_ENDPOINT - ? new URL(import.meta.env.VITE_REPUTATION_ORACLE_ENDPOINT) + const reputationOracleUrl = import.meta.env.REPUTATION_ORACLE_ENDPOINT + ? new URL(import.meta.env.REPUTATION_ORACLE_ENDPOINT) : new URL(`/reputation`, window.location.origin); const ganacheAccountsUrl = new URL( - import.meta.env.VITE_NETWORK_FILES_ENDPOINT || 'http://localhost:3006', + import.meta.env.NETWORK_FILES_ENDPOINT || 'http://localhost:3006', ); - if (import.meta.env.DEV && import.meta.env.VITE_NETWORK === Network.Ganache) { + if (import.meta.env.DEV && import.meta.env.NETWORK_ID === Network.Ganache) { const fetchRes = await fetch( `${ganacheAccountsUrl.href}etherrouter-address.json`, ); @@ -53,7 +53,7 @@ const getNetworkClient = async () => { * and we want to be able to differentiate between them */ networkAddress: - import.meta.env.VITE_NETWORK_CONTRACT_ADDRESS || + import.meta.env.NETWORK_CONTRACT_ADDRESS || ColonyNetworkAddress[network], reputationOracleEndpoint: reputationOracleUrl.href, }, diff --git a/src/redux/sagas/utils/metatransactions.ts b/src/redux/sagas/utils/metatransactions.ts index 240759dc857..fb524192fe8 100644 --- a/src/redux/sagas/utils/metatransactions.ts +++ b/src/redux/sagas/utils/metatransactions.ts @@ -110,7 +110,7 @@ export const broadcastMetatransaction = async ( response: Response; }> => { const response = await fetch( - `${import.meta.env.VITE_METATX_BROADCASTER_ENDPOINT}/broadcast`, + `${import.meta.env.METATX_BROADCASTER_ENDPOINT}/broadcast`, { method: 'POST', headers: { diff --git a/src/redux/sagas/utils/safeHelpers.ts b/src/redux/sagas/utils/safeHelpers.ts index 1f4ed70e8f8..ffe7f2d6ab4 100644 --- a/src/redux/sagas/utils/safeHelpers.ts +++ b/src/redux/sagas/utils/safeHelpers.ts @@ -25,7 +25,7 @@ import RetryProvider from '../wallet/RetryProvider.ts'; import { erc721, ForeignAMB, HomeAMB, ZodiacBridgeModule } from './abis.ts'; // Temporary const safeAddressesUrl = new URL( - import.meta.env.VITE_NETWORK_FILES_ENDPOINT || 'http://localhost:3006', + import.meta.env.NETWORK_FILES_ENDPOINT || 'http://localhost:3006', ); interface SafeAddresses { @@ -62,7 +62,7 @@ const LOCAL_TOKEN_ID = 1; // set in start-bridging-environment.js let SAFE_ADDRESSES: SafeAddresses | null = null; export const getSafeAddresses = async (): Promise => { - if (!isDev || !(import.meta.env.VITE_SAFE_ENABLED === 'true')) + if (!isDev || !(import.meta.env.SAFE_ENABLED === 'true')) return {} as SafeAddresses; if (SAFE_ADDRESSES) return SAFE_ADDRESSES; const addresses = await fetch(`${safeAddressesUrl.href}safe-addresses.json`); diff --git a/src/redux/sagas/wallet/onboard.ts b/src/redux/sagas/wallet/onboard.ts index 09e0a196ab1..a63d0a6f9b1 100644 --- a/src/redux/sagas/wallet/onboard.ts +++ b/src/redux/sagas/wallet/onboard.ts @@ -22,7 +22,7 @@ const { formatMessage } = intl({ }); const ganacheAccountsUrl = new URL( - import.meta.env.VITE_NETWORK_FILES_ENDPOINT || 'http://localhost:3006', + import.meta.env.NETWORK_FILES_ENDPOINT || 'http://localhost:3006', ); const getDevelopmentWallets = async () => { diff --git a/src/typedefs/globals.d.ts b/src/typedefs/globals.d.ts index c92f6ede973..db05a65f03f 100644 --- a/src/typedefs/globals.d.ts +++ b/src/typedefs/globals.d.ts @@ -45,25 +45,27 @@ interface Brand { version: string; } +// eslint-disable-next-line no-underscore-dangle +declare const __COMMIT_HASH__: string | undefined; + interface ImportMetaEnv { - readonly VITE_AUTH_PROXY_ENDPOINT: string; - readonly VITE_BSCSCAN_API_KEY: string | undefined; - readonly VITE_COINGECKO_API_KEY: string; - readonly VITE_DEBUG: string; - readonly VITE_ETHERSCAN_API_KEY: string | undefined; - readonly VITE_NETWORK_FILES_ENDPOINT: string; - readonly VITE_GANACHE_RPC_URL: string | undefined; - readonly VITE_GOOGLE_TAG_MANAGER_ID: string | undefined; - readonly VITE_METATX_ENABLED: string; - readonly VITE_METATX_BROADCASTER_ENDPOINT: string; - readonly VITE_NETWORK: string; - readonly VITE_NETWORK_CONTRACT_ADDRESS: string; - readonly VITE_PINATA_API_KEY: string | undefined; - readonly VITE_PINATA_API_SECRET: string | undefined; - readonly VITE_REPUTATION_ORACLE_ENDPOINT: string; - readonly VITE_PROD_COMMIT_HASH: string | undefined; - readonly VITE_SAFE_ENABLED: string | undefined; - readonly VITE_URL: string | undefined; + readonly AUTH_PROXY_ENDPOINT: string; + readonly BSCSCAN_API_KEY: string | undefined; + readonly COINGECKO_API_KEY: string; + readonly DEBUG: string; + readonly ETHERSCAN_API_KEY: string | undefined; + readonly GANACHE_RPC_URL: string | undefined; + readonly GOOGLE_TAG_MANAGER_ID: string | undefined; + readonly METATX_ENABLED: string; + readonly METATX_BROADCASTER_ENDPOINT: string; + readonly NETWORK_CONTRACT_ADDRESS: string; + readonly NETWORK_FILES_ENDPOINT: string; + readonly NETWORK_ID: string; + readonly PINATA_API_KEY: string | undefined; + readonly PINATA_API_SECRET: string | undefined; + readonly REPUTATION_ORACLE_ENDPOINT: string; + readonly SAFE_ENABLED: string | undefined; + readonly URL: string | undefined; } interface ImportMeta { diff --git a/src/utils/checks/canUseMetatransactions.ts b/src/utils/checks/canUseMetatransactions.ts index cee5ab5508e..e00122fd05d 100644 --- a/src/utils/checks/canUseMetatransactions.ts +++ b/src/utils/checks/canUseMetatransactions.ts @@ -16,7 +16,6 @@ export const canUseMetatransactions = (): boolean => { const networkSupportsMetatransactions = NETWORKS_WITH_METATRANSACTIONS.find( (network) => network === DEFAULT_NETWORK, ); - const areMetaTransactionsEnabled = - import.meta.env.VITE_METATX_ENABLED === 'true'; + const areMetaTransactionsEnabled = import.meta.env.METATX_ENABLED === 'true'; return !!networkSupportsMetatransactions && areMetaTransactionsEnabled; }; diff --git a/src/utils/safes/getContractUsefulMethods.ts b/src/utils/safes/getContractUsefulMethods.ts index a0da407890d..b7ec8f1ad46 100644 --- a/src/utils/safes/getContractUsefulMethods.ts +++ b/src/utils/safes/getContractUsefulMethods.ts @@ -17,9 +17,9 @@ const getCurrentNetworkData = (chainId: number) => { export const getApiKey = (chainId: number) => { if (chainId === BINANCE_NETWORK.chainId) { - return import.meta.env.VITE_BSCSCAN_API_KEY; + return import.meta.env.BSCSCAN_API_KEY; } - return import.meta.env.VITE_ETHERSCAN_API_KEY; + return import.meta.env.ETHERSCAN_API_KEY; }; export const fetchContractName = async ( diff --git a/vite.config.mts b/vite.config.mts index d9ee1d723cb..6f735636cff 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,10 +1,14 @@ +import { execSync } from 'node:child_process'; import react from '@vitejs/plugin-react-swc'; import path from 'path'; import { defineConfig } from 'vite'; import { nodePolyfills } from 'vite-plugin-node-polyfills'; import svgr from 'vite-plugin-svgr'; +import importMetaEnv from '@import-meta-env/unplugin'; -export default defineConfig({ +const __COMMIT_HASH__ = execSync('git rev-parse HEAD').toString().trim(); + +export default defineConfig(({ mode }) => ({ plugins: [ // NOTE: This is only here because of IPFS. When moving to Helia, this can be removed nodePolyfills({ @@ -17,6 +21,10 @@ export default defineConfig({ }), react(), svgr(), + importMetaEnv.vite({ + example: '.env.example', + env: '.env.development', + }) ], resolve: { alias: { @@ -40,7 +48,11 @@ export default defineConfig({ '~v5': path.resolve(__dirname, 'src/components/v5'), }, }, + // NOTE: Do not define environment variables here. Instead, use .env files (__COMMIT_HASH__ is an exception) + define: { + __COMMIT_HASH__: mode === 'production' ? JSON.stringify(__COMMIT_HASH__) : undefined, + }, server: { port: 9091, }, -}); +}));