diff --git a/.credo.exs b/.credo.exs index 09db2f0079d9..444b59323dc9 100644 --- a/.credo.exs +++ b/.credo.exs @@ -33,7 +33,7 @@ # If you create your own checks, you must specify the source files for # them here, so they can be loaded by Credo before running the analysis. # - requires: [], + requires: ["apps/utils/lib/credo/**/*.ex"], # # If you want to enforce a style guide and need a more traditional linting # experience, you can change `strict` to `true` below: @@ -140,9 +140,10 @@ {Credo.Check.Refactor.AppendSingleItem}, {Credo.Check.Refactor.VariableRebinding}, {Credo.Check.Warning.MapGetUnsafePass}, - {Credo.Check.Consistency.MultiAliasImportRequireUse} + {Credo.Check.Consistency.MultiAliasImportRequireUse}, # Custom checks can be created using `mix credo.gen.check`. + {Utils.Credo.Checks.CompileEnvUsage} # ] } diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index 85c1efdcb249..af751b9c0976 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -21,10 +21,10 @@ on: - production-zksync - staging-l2 paths-ignore: - - 'CHANGELOG.md' - - '**/README.md' - - 'docker/*' - - 'docker-compose/*' + - "CHANGELOG.md" + - "**/README.md" + - "docker/*" + - "docker-compose/*" pull_request: types: [opened, synchronize, reopened, labeled] branches: @@ -459,6 +459,34 @@ jobs: - run: ./node_modules/.bin/jest working-directory: apps/block_scout_web/assets + test_utils: + name: Utils Tests + runs-on: ubuntu-latest + needs: build-and-cache + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: ${{ env.OTP_VERSION }} + elixir-version: ${{ env.ELIXIR_VERSION }} + hexpm-mirrors: | + https://builds.hex.pm + https://cdn.jsdelivr.net/hex + + - name: Restore Mix Deps Cache + uses: actions/cache/restore@v4 + id: deps-cache + with: + path: | + deps + _build + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }} + restore-keys: | + ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash- + + - working-directory: apps/utils + run: mix test + test_nethermind_mox_ethereum_jsonrpc: strategy: fail-fast: false diff --git a/.github/workflows/pre-release-arbitrum.yml b/.github/workflows/pre-release-arbitrum.yml index a58456762081..23d40950aeb7 100644 --- a/.github/workflows/pre-release-arbitrum.yml +++ b/.github/workflows/pre-release-arbitrum.yml @@ -41,13 +41,6 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - DISABLE_WEBAPP=false - API_V1_READ_METHODS_DISABLED=false - API_V1_WRITE_METHODS_DISABLED=false - CACHE_EXCHANGE_RATES_PERIOD= - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= - ADMIN_PANEL_ENABLED=false BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -65,11 +58,6 @@ jobs: linux/arm64/v8 build-args: | DISABLE_API=true - DISABLE_WEBAPP=true - CACHE_EXCHANGE_RATES_PERIOD= - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= - ADMIN_PANEL_ENABLED=false BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -87,11 +75,6 @@ jobs: linux/arm64/v8 build-args: | DISABLE_INDEXER=true - DISABLE_WEBAPP=true - CACHE_EXCHANGE_RATES_PERIOD= - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= - ADMIN_PANEL_ENABLED=false BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -108,13 +91,6 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - DISABLE_WEBAPP=false - API_V1_READ_METHODS_DISABLED=false - API_V1_WRITE_METHODS_DISABLED=false - CACHE_EXCHANGE_RATES_PERIOD= - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -133,11 +109,6 @@ jobs: linux/arm64/v8 build-args: | DISABLE_API=true - DISABLE_WEBAPP=true - CACHE_EXCHANGE_RATES_PERIOD= - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= - ADMIN_PANEL_ENABLED=false BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -156,11 +127,6 @@ jobs: linux/arm64/v8 build-args: | DISABLE_INDEXER=true - DISABLE_WEBAPP=true - CACHE_EXCHANGE_RATES_PERIOD= - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-alpha.${{ inputs.number }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum diff --git a/.github/workflows/publish-docker-image-for-arbitrum.yml b/.github/workflows/publish-docker-image-for-arbitrum.yml index 3266fbee762e..06dd671ad3a1 100644 --- a/.github/workflows/publish-docker-image-for-arbitrum.yml +++ b/.github/workflows/publish-docker-image-for-arbitrum.yml @@ -36,13 +36,6 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - API_V1_READ_METHODS_DISABLED=false - DISABLE_WEBAPP=false - API_V1_WRITE_METHODS_DISABLED=false - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -59,12 +52,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_API=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -81,12 +69,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_INDEXER=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -103,13 +86,6 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - API_V1_READ_METHODS_DISABLED=false - DISABLE_WEBAPP=false - API_V1_WRITE_METHODS_DISABLED=false - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -127,12 +103,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_API=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum @@ -150,12 +121,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_INDEXER=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=arbitrum diff --git a/.github/workflows/publish-docker-image-for-eth-sepolia.yml b/.github/workflows/publish-docker-image-for-eth-sepolia.yml index bd320c9ef175..eba3c88a9b3b 100644 --- a/.github/workflows/publish-docker-image-for-eth-sepolia.yml +++ b/.github/workflows/publish-docker-image-for-eth-sepolia.yml @@ -36,13 +36,6 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - API_V1_READ_METHODS_DISABLED=false - DISABLE_WEBAPP=false - API_V1_WRITE_METHODS_DISABLED=false - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=ethereum @@ -59,12 +52,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_API=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=ethereum @@ -81,12 +69,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_INDEXER=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }} RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=ethereum @@ -103,13 +86,6 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - API_V1_READ_METHODS_DISABLED=false - DISABLE_WEBAPP=false - API_V1_WRITE_METHODS_DISABLED=false - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }}-shrink-internal-txs RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=ethereum @@ -127,12 +103,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_API=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }}-shrink-internal-txs RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=ethereum @@ -150,12 +121,7 @@ jobs: linux/amd64 linux/arm64/v8 build-args: | - CACHE_EXCHANGE_RATES_PERIOD= - DISABLE_WEBAPP=true DISABLE_INDEXER=true - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED= - ADMIN_PANEL_ENABLED=false - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL= BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }}-shrink-internal-txs RELEASE_VERSION=${{ env.RELEASE_VERSION }} CHAIN_TYPE=ethereum diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 321123881c5d..c5db206a67e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,6 @@ When contributing to the codebase, please adhere to the following naming convent By following these conventions, we can maintain a clean and understandable codebase. - ### API V2 Naming Convention When contributing to the API v2, please adhere to the following naming conventions for response fields to ensure clarity and consistency: @@ -83,3 +82,23 @@ When contributing to the API v2, please adhere to the following naming conventio - The transaction hash should be returned as a hex string in the `transaction_hash` property. - All fields that contain the "index" suffix should be returned as numbers. +## Compile time Environment Variables + +When working with compile time environment variables in the codebase, follow these guidelines: + +- Always use the `Utils.CompileTimeEnvHelper` module instead of direct `Application.compile_env/2` calls: + +```elixir +# DO use this approach +use Utils.CompileTimeEnvHelper, + attribute_name: [:app, :test] + +# Access the value using the module attribute +@attribute_name + +# DON'T use this approach +Application.compile_env(:app, :test) # avoid direct compile_env calls +``` + +This approach provides faster compilation time and simplifies development and maintenance. + diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index ef743c30f6d6..442777d478c7 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -12,7 +12,7 @@ ### Bug Fixes -*Things you changed that fix bugs. If a fixes a bug, but in so doing adds a new requirement, removes code, or requires a database reset and reindex, the breaking part of the change should be added to Incompatible Changes below also.* +*Things you changed that fix bugs. If it fixes a bug, but in so doing adds a new requirement, removes code, or requires a database reset and reindex, the breaking part of the change should be added to Incompatible Changes below also.* ### Incompatible Changes @@ -27,6 +27,6 @@ - [ ] If I added new functionality, I added tests covering it. - [ ] If I fixed a bug, I added a regression test to prevent the bug from silently reappearing again. - [ ] I checked whether I should update the docs and did so by submitting a PR to [docs repository](https://github.com/blockscout/docs). -- [ ] If I added/changed/removed ENV var, I submitted a PR to [docs repository](https://github.com/blockscout/docs) to update the list of [env vars](https://github.com/blockscout/docs/blob/master/for-developers/information-and-settings/env-variables.md) and I updated the version to `master` in the Version column. If I removed variable, I added it to [Deprecated ENV Variables](https://github.com/blockscout/docs/blob/master/for-developers/information-and-settings/env-variables/deprecated-env-variables/README.md) page. After merging docs PR, changes will be reflected in these [pages](https://docs.blockscout.com/for-developers/information-and-settings/env-variables). +- [ ] If I added/changed/removed ENV var, I submitted a PR to [docs repository](https://github.com/blockscout/docs) to update the list of [env vars](https://github.com/blockscout/docs/blob/master/setup/env-variables/README.md) and I updated the version to `master` in the Version column. If I removed variable, I added it to [Deprecated ENV Variables](https://github.com/blockscout/docs/blob/master/setup/env-variables/deprecated-env-variables/README.md) page. After merging docs PR, changes will be reflected in these [pages](https://docs.blockscout.com/setup/env-variables). - [ ] If I added new DB indices, I checked, that they are not redundant, with PGHero or other tools. - [ ] If I added/removed chain type, I modified the Github CI matrix and PR labels accordingly. diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index f32b03fb552c..8ebf3c7dd3ed 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -7,18 +7,18 @@ "name": "blockscout", "license": "GPL-3.0", "dependencies": { - "@amplitude/analytics-browser": "^2.11.8", - "@fortawesome/fontawesome-free": "^6.6.0", + "@amplitude/analytics-browser": "^2.11.9", + "@fortawesome/fontawesome-free": "^6.7.1", "@tarekraafat/autocomplete.js": "^10.2.9", "@walletconnect/web3-provider": "^1.8.0", "assert": "^2.1.0", "bignumber.js": "^9.1.2", "bootstrap": "^4.6.0", - "chart.js": "^4.4.6", + "chart.js": "^4.4.7", "chartjs-adapter-luxon": "^1.3.1", "clipboard": "^2.0.11", "core-js": "^3.39.0", - "crypto-browserify": "^3.12.0", + "crypto-browserify": "^3.12.1", "dropzone": "^5.9.3", "eth-net-props": "^1.0.41", "highlight.js": "^11.10.0", @@ -46,7 +46,7 @@ "lodash.reduce": "^4.6.0", "luxon": "^3.5.0", "malihu-custom-scrollbar-plugin": "3.1.5", - "mixpanel-browser": "^2.55.1", + "mixpanel-browser": "^2.56.0", "moment": "^2.30.1", "nanomorph": "^5.4.0", "numeral": "^2.0.6", @@ -71,8 +71,8 @@ "xss": "^1.0.15" }, "devDependencies": { - "@babel/core": "^7.25.2", - "@babel/preset-env": "^7.25.4", + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", "autoprefixer": "^10.4.20", "babel-loader": "^9.2.1", "copy-webpack-plugin": "^12.0.2", @@ -87,9 +87,9 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "mini-css-extract-plugin": "^2.9.2", - "postcss": "^8.4.47", + "postcss": "^8.4.49", "postcss-loader": "^8.1.1", - "sass": "^1.79.4", + "sass": "^1.81.0", "sass-loader": "^14.2.1", "style-loader": "^4.0.0", "webpack": "^5.96.1", @@ -101,11 +101,10 @@ } }, "../../../deps/phoenix": { - "version": "1.5.14", - "license": "MIT" + "version": "0.0.1" }, "../../../deps/phoenix_html": { - "version": "3.0.4" + "version": "0.0.1" }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", @@ -122,16 +121,16 @@ "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" }, "node_modules/@amplitude/analytics-browser": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.11.8.tgz", - "integrity": "sha512-lFv8deROLwBfSlg92+r1NitWJ6BN45IKwpPLoixA0fZytScXEJqc0Gl5O+BY4qScbFECYt9PFKblhB+jC+IvPg==", + "version": "2.11.9", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.11.9.tgz", + "integrity": "sha512-FHejpsW3OypNKaIBvMwLm74UUSBcR+VwrBsj7V2VlPDNRdeaFi21kJgVYUW5AcjxTsadMzBQGBb4BarZ4k2+9Q==", "dependencies": { - "@amplitude/analytics-client-common": "^2.3.4", - "@amplitude/analytics-core": "^2.5.3", + "@amplitude/analytics-client-common": "^2.3.5", + "@amplitude/analytics-core": "^2.5.4", "@amplitude/analytics-remote-config": "^0.4.0", - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-types": "^2.8.4", "@amplitude/plugin-autocapture-browser": "^1.0.2", - "@amplitude/plugin-page-view-tracking-browser": "^2.3.4", + "@amplitude/plugin-page-view-tracking-browser": "^2.3.5", "tslib": "^2.4.1" } }, @@ -141,13 +140,13 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/@amplitude/analytics-client-common": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.3.4.tgz", - "integrity": "sha512-3oqdvca5W4BPblTaxf60YRtlh2uC+N3rA99wowDAhTBJoMJJaauOBoXu5BbiQO1u8Zw/c8ymyr8E20+glyptUg==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.3.5.tgz", + "integrity": "sha512-BCP+jorfLMAKK/g87fAk4IPP/NzQLMCep+Qe23tqOCWguwTEINYnyzD/GmhaIKXSM2o9pmMLlHbhkA1vXUtF8g==", "dependencies": { "@amplitude/analytics-connector": "^1.4.8", - "@amplitude/analytics-core": "^2.5.3", - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-core": "^2.5.4", + "@amplitude/analytics-types": "^2.8.4", "tslib": "^2.4.1" } }, @@ -165,11 +164,11 @@ } }, "node_modules/@amplitude/analytics-core": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.5.3.tgz", - "integrity": "sha512-dvx3PS0adnHRS22VbuP9YtWg//bQGF2c61Pj5IYXVsemtRRHqiS7XJ860brk3WeQgOkqf3Gyc023DoYcsWGoNQ==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.5.4.tgz", + "integrity": "sha512-J5ZF8hQmxmxM+7bu25a2TfTnk/LQ/oH5FYdg79f1lJ85Aa6oUlCDxgvXwy1RVpwaFjWlZQgV4XVaAUrxtSPRFw==", "dependencies": { - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-types": "^2.8.4", "tslib": "^2.4.1" } }, @@ -195,9 +194,9 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/@amplitude/analytics-types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.8.3.tgz", - "integrity": "sha512-HNmKVd0ACoi3xTi86xi+is7WgqKT78JA4fYLcM25/ckFkZ1zVCqD1AubaADEh26m34nJ3qDLK5Pob4QptQNPAg==" + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.8.4.tgz", + "integrity": "sha512-jQ8WY1aPbpBshl0L/0YEeQn/wZlBr8Jlqc20qf8nbuDuimFy8RqAkE+BVaMI86FCkr3AJ7PjMXkGwCSbUx88CA==" }, "node_modules/@amplitude/experiment-core": { "version": "0.10.0", @@ -224,12 +223,12 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/@amplitude/plugin-page-view-tracking-browser": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.3.4.tgz", - "integrity": "sha512-l7RS5gssG0BPYlgirV0NQ94EPzTOdDkp0z2jqU45D3DQAJXkoloUyw5lw/cbUXYwNulHZTG/BExcERfdvVWkLA==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.3.5.tgz", + "integrity": "sha512-qcV4DLxRAZRriYBNvjc2PGW1EDad6PSsIXmxVs6j8i9fxY2SfdvsFd/Qd23CHj1e6Dt5QpAVJZpUMCEdqqDZbA==", "dependencies": { - "@amplitude/analytics-client-common": "^2.3.4", - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-client-common": "^2.3.5", + "@amplitude/analytics-types": "^2.8.4", "tslib": "^2.4.1" } }, @@ -263,11 +262,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -275,28 +275,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -317,51 +317,52 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/generator": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", - "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "dependencies": { - "@babel/types": "^7.25.6", + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -383,17 +384,17 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", - "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.25.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/traverse": "^7.25.4", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { @@ -404,13 +405,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", - "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -437,39 +438,38 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -479,34 +479,34 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", - "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-wrap-function": "^7.25.0", - "@babel/traverse": "^7.25.0" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -516,14 +516,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", - "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -533,100 +533,87 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", - "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "dev": true, "dependencies": { - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", - "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", - "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", - "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "dependencies": { - "@babel/types": "^7.25.6" + "@babel/types": "^7.26.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -636,13 +623,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", - "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -652,12 +639,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", - "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -667,12 +654,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", - "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -682,14 +669,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -699,13 +686,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", - "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -762,52 +749,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -817,12 +765,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -942,21 +890,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", @@ -1004,12 +937,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1019,15 +952,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", - "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-remap-async-to-generator": "^7.25.0", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/traverse": "^7.25.4" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1037,14 +969,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1054,12 +986,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1069,12 +1001,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", - "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1084,13 +1016,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", - "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1100,14 +1032,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1117,16 +1048,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", - "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.25.0", - "@babel/traverse": "^7.25.4", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -1137,13 +1068,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1153,12 +1084,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1168,13 +1099,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1184,12 +1115,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1199,13 +1130,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", - "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1215,13 +1146,12 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1231,13 +1161,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1247,13 +1177,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1263,13 +1192,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1279,14 +1208,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", - "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.1" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1296,13 +1225,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1312,12 +1240,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", - "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1327,13 +1255,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1343,12 +1270,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1358,13 +1285,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1374,14 +1301,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1391,15 +1318,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", - "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1409,13 +1336,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1425,13 +1352,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1441,12 +1368,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1456,13 +1383,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1472,13 +1398,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1488,15 +1413,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1506,13 +1430,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1522,13 +1446,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1538,14 +1461,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1555,12 +1477,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1570,13 +1492,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", - "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1586,15 +1508,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1604,12 +1525,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1619,12 +1540,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1634,13 +1555,29 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1681,12 +1618,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1696,13 +1633,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1712,12 +1649,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1727,12 +1664,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1742,12 +1679,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1757,12 +1694,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1772,13 +1709,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1788,13 +1725,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1804,13 +1741,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", - "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1820,93 +1757,79 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", - "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.25.4", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.4", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.25.1", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.25.2", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.25.0", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.25.4", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.8", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.37.1", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -1972,12 +1895,6 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, "node_modules/@babel/runtime": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz", @@ -1990,28 +1907,28 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", - "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2020,13 +1937,12 @@ } }, "node_modules/@babel/types": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", - "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2183,9 +2099,9 @@ } }, "node_modules/@fortawesome/fontawesome-free": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.6.0.tgz", - "integrity": "sha512-60G28ke/sXdtS9KZCpZSHHkCbdsOGEhIUGlwq6yhY74UpTiToIh8np7A8yphhM4BWsvNFtIvLpi4co+h9Mr9Ow==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.1.tgz", + "integrity": "sha512-ALIk/MOh5gYe1TG/ieS5mVUsk7VUIJTJKPMK9rFFqOgfp0Q3d5QiBXbcOMwUvs37fyZVCz46YjOE6IFeOAXCHA==", "engines": { "node": ">=6" } @@ -3043,6 +2959,309 @@ "node": ">= 8" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, "node_modules/@rrweb/types": { "version": "2.0.0-alpha.14", "resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.14.tgz", @@ -4144,20 +4363,19 @@ } }, "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "minimalistic-assert": "^1.0.0" } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" }, "node_modules/assert": { "version": "2.1.0", @@ -4739,24 +4957,56 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", - "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", "dependencies": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.4", + "elliptic": "^6.5.5", + "hash-base": "~3.0", "inherits": "^2.0.4", - "parse-asn1": "^5.1.6", - "readable-stream": "^3.6.2", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 4" + "node": ">= 0.12" } }, + "node_modules/browserify-sign/node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/browserify-sign/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4776,6 +5026,19 @@ } ] }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/browserslist": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", @@ -5034,19 +5297,6 @@ "node": ">=4" } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -5057,9 +5307,9 @@ } }, "node_modules/chart.js": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", - "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.7.tgz", + "integrity": "sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -5538,26 +5788,61 @@ } }, "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" }, "engines": { - "node": "*" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/crypto-browserify/node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, + "node_modules/crypto-browserify/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -6133,6 +6418,19 @@ "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.2.1.tgz", "integrity": "sha512-eAcRiEPTs7utXWPaAgu/OX1HRJpxW7xSHpw4LTDrGFaeWnJ37HRlqpUkKsDm0AoTbtrvHQhH+5U2Cd87EGhJTg==" }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -6554,14 +6852,6 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/escodegen": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", @@ -8616,9 +8906,9 @@ "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" }, "node_modules/immutable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", - "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", "dev": true }, "node_modules/import-fresh": { @@ -11032,14 +11322,14 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { @@ -11664,13 +11954,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -11783,9 +12073,9 @@ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" }, "node_modules/mixpanel-browser": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/mixpanel-browser/-/mixpanel-browser-2.55.1.tgz", - "integrity": "sha512-NSEPdFSJxoR1OCKWKHbtqd3BeH1c9NjXbEt0tN5TgBEO1nSDji6niU9n4MopAXOP0POET9spjpQKxZtLZKTJwA==", + "version": "2.56.0", + "resolved": "https://registry.npmjs.org/mixpanel-browser/-/mixpanel-browser-2.56.0.tgz", + "integrity": "sha512-GYeEz58pV2M9MZtK8vSPL4oJmCwGS08FDDRZvZwr5VJpWdT4Lgyg6zXhmNfCmSTEIw2coaarm7HZ4FL9dAVvnA==", "dependencies": { "rrweb": "2.0.0-alpha.13" } @@ -12188,17 +12478,52 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, + "node_modules/parse-asn1/node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-asn1/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/parse-headers": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.4.tgz", @@ -12319,14 +12644,14 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -12481,9 +12806,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -12501,7 +12826,7 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -13501,9 +13826,9 @@ "dev": true }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "dependencies": { "regenerate": "^1.4.2" @@ -13557,15 +13882,15 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -13573,27 +13898,24 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -13895,13 +14217,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.4.tgz", - "integrity": "sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.81.0.tgz", + "integrity": "sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==", "dev": true, "dependencies": { "chokidar": "^4.0.0", - "immutable": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -13909,6 +14231,9 @@ }, "engines": { "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, "node_modules/sass-loader": { @@ -14724,14 +15049,6 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14981,9 +15298,9 @@ } }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "engines": { "node": ">=4" @@ -15003,9 +15320,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "engines": { "node": ">=4" @@ -16197,16 +16514,16 @@ "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" }, "@amplitude/analytics-browser": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.11.8.tgz", - "integrity": "sha512-lFv8deROLwBfSlg92+r1NitWJ6BN45IKwpPLoixA0fZytScXEJqc0Gl5O+BY4qScbFECYt9PFKblhB+jC+IvPg==", + "version": "2.11.9", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.11.9.tgz", + "integrity": "sha512-FHejpsW3OypNKaIBvMwLm74UUSBcR+VwrBsj7V2VlPDNRdeaFi21kJgVYUW5AcjxTsadMzBQGBb4BarZ4k2+9Q==", "requires": { - "@amplitude/analytics-client-common": "^2.3.4", - "@amplitude/analytics-core": "^2.5.3", + "@amplitude/analytics-client-common": "^2.3.5", + "@amplitude/analytics-core": "^2.5.4", "@amplitude/analytics-remote-config": "^0.4.0", - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-types": "^2.8.4", "@amplitude/plugin-autocapture-browser": "^1.0.2", - "@amplitude/plugin-page-view-tracking-browser": "^2.3.4", + "@amplitude/plugin-page-view-tracking-browser": "^2.3.5", "tslib": "^2.4.1" }, "dependencies": { @@ -16218,13 +16535,13 @@ } }, "@amplitude/analytics-client-common": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.3.4.tgz", - "integrity": "sha512-3oqdvca5W4BPblTaxf60YRtlh2uC+N3rA99wowDAhTBJoMJJaauOBoXu5BbiQO1u8Zw/c8ymyr8E20+glyptUg==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.3.5.tgz", + "integrity": "sha512-BCP+jorfLMAKK/g87fAk4IPP/NzQLMCep+Qe23tqOCWguwTEINYnyzD/GmhaIKXSM2o9pmMLlHbhkA1vXUtF8g==", "requires": { "@amplitude/analytics-connector": "^1.4.8", - "@amplitude/analytics-core": "^2.5.3", - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-core": "^2.5.4", + "@amplitude/analytics-types": "^2.8.4", "tslib": "^2.4.1" }, "dependencies": { @@ -16244,11 +16561,11 @@ } }, "@amplitude/analytics-core": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.5.3.tgz", - "integrity": "sha512-dvx3PS0adnHRS22VbuP9YtWg//bQGF2c61Pj5IYXVsemtRRHqiS7XJ860brk3WeQgOkqf3Gyc023DoYcsWGoNQ==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.5.4.tgz", + "integrity": "sha512-J5ZF8hQmxmxM+7bu25a2TfTnk/LQ/oH5FYdg79f1lJ85Aa6oUlCDxgvXwy1RVpwaFjWlZQgV4XVaAUrxtSPRFw==", "requires": { - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-types": "^2.8.4", "tslib": "^2.4.1" }, "dependencies": { @@ -16278,9 +16595,9 @@ } }, "@amplitude/analytics-types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.8.3.tgz", - "integrity": "sha512-HNmKVd0ACoi3xTi86xi+is7WgqKT78JA4fYLcM25/ckFkZ1zVCqD1AubaADEh26m34nJ3qDLK5Pob4QptQNPAg==" + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.8.4.tgz", + "integrity": "sha512-jQ8WY1aPbpBshl0L/0YEeQn/wZlBr8Jlqc20qf8nbuDuimFy8RqAkE+BVaMI86FCkr3AJ7PjMXkGwCSbUx88CA==" }, "@amplitude/experiment-core": { "version": "0.10.0", @@ -16309,12 +16626,12 @@ } }, "@amplitude/plugin-page-view-tracking-browser": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.3.4.tgz", - "integrity": "sha512-l7RS5gssG0BPYlgirV0NQ94EPzTOdDkp0z2jqU45D3DQAJXkoloUyw5lw/cbUXYwNulHZTG/BExcERfdvVWkLA==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.3.5.tgz", + "integrity": "sha512-qcV4DLxRAZRriYBNvjc2PGW1EDad6PSsIXmxVs6j8i9fxY2SfdvsFd/Qd23CHj1e6Dt5QpAVJZpUMCEdqqDZbA==", "requires": { - "@amplitude/analytics-client-common": "^2.3.4", - "@amplitude/analytics-types": "^2.8.3", + "@amplitude/analytics-client-common": "^2.3.5", + "@amplitude/analytics-types": "^2.8.4", "tslib": "^2.4.1" }, "dependencies": { @@ -16346,34 +16663,35 @@ } }, "@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "requires": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==" + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==" }, "@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -16389,42 +16707,43 @@ } }, "@babel/generator": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", - "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "requires": { - "@babel/types": "^7.25.6", + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" } }, "@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "requires": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "dev": true, "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "requires": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -16445,28 +16764,28 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", - "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.25.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/traverse": "^7.25.4", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", - "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" } }, @@ -16484,191 +16803,180 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "requires": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "requires": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "requires": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" } }, "@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==" + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", - "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-wrap-function": "^7.25.0", - "@babel/traverse": "^7.25.0" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/helper-replace-supers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", - "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", + "dev": true, "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==" + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" }, "@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==" + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==" }, "@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==" + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==" }, "@babel/helper-wrap-function": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", - "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "dev": true, "requires": { - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/helpers": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", - "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", - "requires": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6" - } - }, - "@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "requires": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" } }, "@babel/parser": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", - "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "requires": { - "@babel/types": "^7.25.6" + "@babel/types": "^7.26.0" } }, "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", - "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", - "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", - "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" } }, "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", - "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/plugin-proposal-private-property-in-object": { @@ -16705,49 +17013,22 @@ "@babel/helper-plugin-utils": "^7.12.13" } }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, "@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-syntax-import-meta": { @@ -16831,15 +17112,6 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, "@babel/plugin-syntax-top-level-await": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", @@ -16869,409 +17141,407 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-async-generator-functions": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", - "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-remap-async-to-generator": "^7.25.0", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/traverse": "^7.25.4" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", - "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-class-properties": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", - "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-classes": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", - "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.25.0", - "@babel/traverse": "^7.25.4", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" } }, "@babel/plugin-transform-destructuring": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", - "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", - "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" } }, "@babel/plugin-transform-function-name": { - "version": "7.25.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", - "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/traverse": "^7.25.1" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-literals": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", - "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", - "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", - "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.25.0", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" } }, "@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" } }, "@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-optional-chaining": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", - "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" } }, "@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-private-methods": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", - "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.25.4", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" } }, + "@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + } + }, "@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-runtime": { @@ -17299,178 +17569,164 @@ } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", - "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", - "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" } }, "@babel/preset-env": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", - "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.25.4", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.4", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.25.1", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.25.2", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.25.0", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.25.4", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.8", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.4", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.37.1", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "dependencies": { @@ -17520,12 +17776,6 @@ "esutils": "^2.0.2" } }, - "@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, "@babel/runtime": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz", @@ -17535,37 +17785,36 @@ } }, "@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "requires": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" } }, "@babel/traverse": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", - "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", - "requires": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "requires": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", - "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "requires": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" } }, "@bcoe/v8-coverage": { @@ -17679,9 +17928,9 @@ "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==" }, "@fortawesome/fontawesome-free": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.6.0.tgz", - "integrity": "sha512-60G28ke/sXdtS9KZCpZSHHkCbdsOGEhIUGlwq6yhY74UpTiToIh8np7A8yphhM4BWsvNFtIvLpi4co+h9Mr9Ow==" + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.1.tgz", + "integrity": "sha512-ALIk/MOh5gYe1TG/ieS5mVUsk7VUIJTJKPMK9rFFqOgfp0Q3d5QiBXbcOMwUvs37fyZVCz46YjOE6IFeOAXCHA==" }, "@humanwhocodes/config-array": { "version": "0.13.0", @@ -18330,6 +18579,132 @@ "fastq": "^1.6.0" } }, + "@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, + "optional": true, + "requires": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0", + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "dependencies": { + "node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + } + } + }, + "@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "dev": true, + "optional": true + }, "@rrweb/types": { "version": "2.0.0-alpha.14", "resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.14.tgz", @@ -19267,20 +19642,19 @@ } }, "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "minimalistic-assert": "^1.0.0" }, "dependencies": { "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" } } }, @@ -19731,25 +20105,71 @@ } }, "browserify-sign": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", - "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", "requires": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.4", + "elliptic": "^6.5.5", + "hash-base": "~3.0", "inherits": "^2.0.4", - "parse-asn1": "^5.1.6", - "readable-stream": "^3.6.2", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "dependencies": { + "hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "requires": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } } } }, @@ -19934,16 +20354,6 @@ "type-detect": "^4.0.5" } }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, "char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -19951,9 +20361,9 @@ "dev": true }, "chart.js": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", - "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.7.tgz", + "integrity": "sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==", "requires": { "@kurkle/color": "^0.3.0" } @@ -20329,21 +20739,38 @@ } }, "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "dependencies": { + "hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "requires": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } } }, "css-color-keywords": { @@ -20738,6 +21165,13 @@ "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.2.1.tgz", "integrity": "sha512-eAcRiEPTs7utXWPaAgu/OX1HRJpxW7xSHpw4LTDrGFaeWnJ37HRlqpUkKsDm0AoTbtrvHQhH+5U2Cd87EGhJTg==" }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -21075,11 +21509,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, "escodegen": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", @@ -22659,9 +23088,9 @@ "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" }, "immutable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", - "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", "dev": true }, "import-fresh": { @@ -24428,9 +24857,9 @@ } }, "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==" }, "json-parse-even-better-errors": { "version": "2.3.1", @@ -24992,13 +25421,13 @@ } }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.3", + "picomatch": "^2.3.1" } }, "miller-rabin": { @@ -25085,9 +25514,9 @@ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" }, "mixpanel-browser": { - "version": "2.55.1", - "resolved": "https://registry.npmjs.org/mixpanel-browser/-/mixpanel-browser-2.55.1.tgz", - "integrity": "sha512-NSEPdFSJxoR1OCKWKHbtqd3BeH1c9NjXbEt0tN5TgBEO1nSDji6niU9n4MopAXOP0POET9spjpQKxZtLZKTJwA==", + "version": "2.56.0", + "resolved": "https://registry.npmjs.org/mixpanel-browser/-/mixpanel-browser-2.56.0.tgz", + "integrity": "sha512-GYeEz58pV2M9MZtK8vSPL4oJmCwGS08FDDRZvZwr5VJpWdT4Lgyg6zXhmNfCmSTEIw2coaarm7HZ4FL9dAVvnA==", "requires": { "rrweb": "2.0.0-alpha.13" } @@ -25379,15 +25808,32 @@ } }, "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "requires": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "requires": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } } }, "parse-headers": { @@ -25481,14 +25927,14 @@ "integrity": "sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==" }, "picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pify": { @@ -25583,13 +26029,13 @@ "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==" }, "postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "requires": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, @@ -26272,9 +26718,9 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "requires": { "regenerate": "^1.4.2" @@ -26313,34 +26759,32 @@ "dev": true }, "regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, "requires": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, + "regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, "regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true - } + "jsesc": "~3.0.2" } }, "request": { @@ -26581,13 +27025,14 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { - "version": "1.79.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.4.tgz", - "integrity": "sha512-K0QDSNPXgyqO4GZq2HO5Q70TLxTH6cIT59RdoCHMivrC8rqzaTw5ab9prjz9KUN1El4FLXrBXJhik61JR4HcGg==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.81.0.tgz", + "integrity": "sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==", "dev": true, "requires": { + "@parcel/watcher": "^2.4.1", "chokidar": "^4.0.0", - "immutable": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" } }, @@ -27161,11 +27606,6 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -27355,9 +27795,9 @@ } }, "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true }, "unicode-match-property-ecmascript": { @@ -27371,9 +27811,9 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true }, "unicode-property-aliases-ecmascript": { diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index b30e2dc2b7ac..1302f2873e31 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -19,18 +19,18 @@ "eslint": "eslint js/**" }, "dependencies": { - "@fortawesome/fontawesome-free": "^6.6.0", - "@amplitude/analytics-browser": "^2.11.8", + "@fortawesome/fontawesome-free": "^6.7.1", + "@amplitude/analytics-browser": "^2.11.9", "@tarekraafat/autocomplete.js": "^10.2.9", "@walletconnect/web3-provider": "^1.8.0", "assert": "^2.1.0", "bignumber.js": "^9.1.2", "bootstrap": "^4.6.0", - "chart.js": "^4.4.6", + "chart.js": "^4.4.7", "chartjs-adapter-luxon": "^1.3.1", "clipboard": "^2.0.11", "core-js": "^3.39.0", - "crypto-browserify": "^3.12.0", + "crypto-browserify": "^3.12.1", "dropzone": "^5.9.3", "eth-net-props": "^1.0.41", "highlight.js": "^11.10.0", @@ -58,7 +58,7 @@ "lodash.reduce": "^4.6.0", "luxon": "^3.5.0", "malihu-custom-scrollbar-plugin": "3.1.5", - "mixpanel-browser": "^2.55.1", + "mixpanel-browser": "^2.56.0", "moment": "^2.30.1", "nanomorph": "^5.4.0", "numeral": "^2.0.6", @@ -83,8 +83,8 @@ "xss": "^1.0.15" }, "devDependencies": { - "@babel/core": "^7.25.2", - "@babel/preset-env": "^7.25.4", + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", "autoprefixer": "^10.4.20", "babel-loader": "^9.2.1", "copy-webpack-plugin": "^12.0.2", @@ -99,9 +99,9 @@ "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "mini-css-extract-plugin": "^2.9.2", - "postcss": "^8.4.47", + "postcss": "^8.4.49", "postcss-loader": "^8.1.1", - "sass": "^1.79.4", + "sass": "^1.81.0", "sass-loader": "^14.2.1", "style-loader": "^4.0.0", "webpack": "^5.96.1", diff --git a/apps/block_scout_web/lib/block_scout_web/application.ex b/apps/block_scout_web/lib/block_scout_web/application.ex index b96ea10c6fc3..e50cc806c161 100644 --- a/apps/block_scout_web/lib/block_scout_web/application.ex +++ b/apps/block_scout_web/lib/block_scout_web/application.ex @@ -4,18 +4,15 @@ defmodule BlockScoutWeb.Application do """ use Application + use Utils.CompileTimeEnvHelper, disable_api?: [:block_scout_web, :disable_api?] alias BlockScoutWeb.Endpoint - alias BlockScoutWeb.Prometheus.Exporter, as: PrometheusExporter - alias BlockScoutWeb.Prometheus.PublicExporter, as: PrometheusPublicExporter def start(_type, _args) do base_children = [Supervisor.child_spec(Endpoint, [])] api_children = setup_and_define_children() all_children = base_children ++ api_children opts = [strategy: :one_for_one, name: BlockScoutWeb.Supervisor, max_restarts: 1_000] - PrometheusExporter.setup() - PrometheusPublicExporter.setup() Supervisor.start_link(all_children, opts) end @@ -26,19 +23,20 @@ defmodule BlockScoutWeb.Application do :ok end - if Application.compile_env(:block_scout_web, :disable_api?) do + if @disable_api? do defp setup_and_define_children, do: [] else defp setup_and_define_children do alias BlockScoutWeb.API.APILogger alias BlockScoutWeb.Counters.{BlocksIndexedCounter, InternalTransactionsIndexedCounter} - alias BlockScoutWeb.Prometheus.{Exporter, PhoenixInstrumenter} + alias BlockScoutWeb.Prometheus.{Exporter, PhoenixInstrumenter, PublicExporter} alias BlockScoutWeb.{MainPageRealtimeEventHandler, RealtimeEventHandler, SmartContractRealtimeEventHandler} alias BlockScoutWeb.Utility.EventHandlersMetrics alias Explorer.Chain.Metrics, as: ChainMetrics PhoenixInstrumenter.setup() Exporter.setup() + PublicExporter.setup() APILogger.message( "Current global API rate limit #{inspect(Application.get_env(:block_scout_web, :api_rate_limit)[:global_limit])} reqs/sec" diff --git a/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex b/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex index 86dec8a3f9fb..424a3f068f27 100644 --- a/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex +++ b/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex @@ -3,6 +3,7 @@ defmodule BlockScoutWeb.AddressChannel do Establishes pub/sub channel for address page live updates. """ use BlockScoutWeb, :channel + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0] @@ -38,7 +39,7 @@ defmodule BlockScoutWeb.AddressChannel do @burn_address_hash burn_address_hash @current_token_balances_limit 50 - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :celo -> @chain_type_transaction_associations [ :gas_token diff --git a/apps/block_scout_web/lib/block_scout_web/channels/user_socket_v2.ex b/apps/block_scout_web/lib/block_scout_web/channels/user_socket_v2.ex index 696b3b0de4a2..7047543bba42 100644 --- a/apps/block_scout_web/lib/block_scout_web/channels/user_socket_v2.ex +++ b/apps/block_scout_web/lib/block_scout_web/channels/user_socket_v2.ex @@ -3,6 +3,7 @@ defmodule BlockScoutWeb.UserSocketV2 do Module to distinct new and old UI websocket connections """ use Phoenix.Socket + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] channel("addresses:*", BlockScoutWeb.AddressChannel) channel("blocks:*", BlockScoutWeb.BlockChannel) @@ -13,7 +14,7 @@ defmodule BlockScoutWeb.UserSocketV2 do channel("token_instances:*", BlockScoutWeb.TokenInstanceChannel) channel("zkevm_batches:*", BlockScoutWeb.PolygonZkevmConfirmedBatchChannel) - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> channel("arbitrum:*", BlockScoutWeb.ArbitrumChannel) # todo: change `optimism*"` to `optimism:*` after the deprecated `optimism_deposits:new_deposits` topic is removed :optimism -> channel("optimism*", BlockScoutWeb.OptimismChannel) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v2/email_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v2/email_controller.ex index 829b914220f3..4bec5561cece 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v2/email_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/account/api/v2/email_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.Account.API.V2.EmailController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, invalid_session_key: [:block_scout_web, :invalid_session_key] import BlockScoutWeb.Account.AuthController, only: [current_user: 1] @@ -11,8 +12,6 @@ defmodule BlockScoutWeb.Account.API.V2.EmailController do require Logger - @invalid_session_key Application.compile_env(:block_scout_web, :invalid_session_key) - action_fallback(BlockScoutWeb.Account.API.V2.FallbackController) plug(:fetch_cookies, signed: [@invalid_session_key]) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex index 7317039553e7..9f112f1ec32b 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex @@ -22,6 +22,9 @@ defmodule BlockScoutWeb.AddressTransactionController do AddressTransactionCsvExporter } + alias Explorer.Chain.CSVExport.Celo.AddressElectionRewardsCsvExporter, + as: CeloAddressElectionRewardsCsvExporter + alias Explorer.Chain.{DenormalizationHelper, Transaction, Wei} alias Indexer.Fetcher.OnDemand.CoinBalance, as: CoinBalanceOnDemand @@ -223,4 +226,9 @@ defmodule BlockScoutWeb.AddressTransactionController do def logs_csv(conn, params) do items_csv(conn, params, AddressLogCsvExporter) end + + @spec celo_election_rewards_csv(Conn.t(), map()) :: Conn.t() + def celo_election_rewards_csv(conn, params) do + items_csv(conn, params, CeloAddressElectionRewardsCsvExporter) + end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex index a2629b1344d6..ae1aa0a65165 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.RPC.ContractController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Logger @@ -17,7 +18,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do alias Explorer.ThirdPartyIntegrations.Sourcify import BlockScoutWeb.API.V2.AddressController, only: [validate_address: 2, validate_address: 3] - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do @optimization_runs "0" else @optimization_runs 200 diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/token_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/token_controller.ex index 51e1aff18221..e6423b577b9c 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/token_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/token_controller.ex @@ -1,9 +1,9 @@ defmodule BlockScoutWeb.API.RPC.TokenController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, bridged_token_enabled: [:explorer, [Explorer.Chain.BridgedToken, :enabled]] alias BlockScoutWeb.API.RPC.Helper alias Explorer.{Chain, PagingOptions} - alias Explorer.Chain.BridgedToken def gettoken(conn, params) do with {:contractaddress_param, {:ok, contractaddress_param}} <- fetch_contractaddress(params), @@ -51,7 +51,7 @@ defmodule BlockScoutWeb.API.RPC.TokenController do end end - if Application.compile_env(:explorer, BridgedToken)[:enabled] do + if @bridged_token_enabled do @api_true [api?: true] def bridgedtokenlist(conn, params) do import BlockScoutWeb.PagingHelper, diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex index bc09024c9810..db7353cf8b02 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.AddressController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import BlockScoutWeb.Chain, only: [ @@ -39,7 +40,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do alias Indexer.Fetcher.OnDemand.ContractCode, as: ContractCodeOnDemand alias Indexer.Fetcher.OnDemand.TokenBalance, as: TokenBalanceOnDemand - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :celo -> @chain_type_transaction_necessity_by_association %{ :gas_token => :optional @@ -83,7 +84,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do api?: true ] - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> @contract_address_preloads [ :smart_contract, diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/api_key_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/api_key_controller.ex index 2ca19379af2d..995d063863a8 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/api_key_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/api_key_controller.ex @@ -1,10 +1,9 @@ defmodule BlockScoutWeb.API.V2.APIKeyController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, api_v2_temp_token_key: [:block_scout_web, :api_v2_temp_token_key] alias BlockScoutWeb.{AccessHelper, CaptchaHelper} - @api_v2_temp_token_key Application.compile_env(:block_scout_web, :api_v2_temp_token_key) - action_fallback(BlockScoutWeb.API.V2.FallbackController) plug(:fetch_cookies, signed: [@api_v2_temp_token_key]) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex index d7a3164b476e..2fb34766ab51 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.BlockController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import BlockScoutWeb.Chain, only: [ @@ -38,7 +39,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do alias Explorer.Chain.Optimism.TransactionBatch, as: OptimismTransactionBatch alias Explorer.Chain.Scroll.Reader, as: ScrollReader - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> @chain_type_transaction_necessity_by_association %{ :beacon_blob_transaction => :optional @@ -479,7 +480,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do defp celo_reward_type_to_atom(reward_type_string) do reward_type_string - |> CeloElectionReward.type_from_string() + |> CeloElectionReward.type_from_url_string() |> case do {:ok, type} -> {:ok, type} :error -> {:error, {:invalid, :celo_election_reward_type}} diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex index f82b4f476e64..74cf80675e82 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.MainPageController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.{Chain, PagingOptions} alias BlockScoutWeb.API.V2.{BlockView, OptimismView, TransactionView} @@ -10,7 +11,7 @@ defmodule BlockScoutWeb.API.V2.MainPageController do import Explorer.MicroserviceInterfaces.BENS, only: [maybe_preload_ens: 1] import Explorer.MicroserviceInterfaces.Metadata, only: [maybe_preload_metadata: 1] - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :celo -> @chain_type_transaction_necessity_by_association %{ :gas_token => :optional diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex index 84d42690f934..9a00ea3b7065 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.StatsController do use Phoenix.Controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.API.V2.Helper alias BlockScoutWeb.Chain.MarketHistoryChartController @@ -177,7 +178,7 @@ defmodule BlockScoutWeb.API.V2.StatsController do end end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :rsk -> defp add_chain_type_fields(response) do alias Explorer.Chain.Cache.RootstockLockedBTC diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex index 2e72170b1454..42b17d3e76a0 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex @@ -1,10 +1,10 @@ defmodule BlockScoutWeb.API.V2.TokenController do - alias Explorer.PagingOptions use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, bridged_token_enabled: [:explorer, [Explorer.Chain.BridgedToken, :enabled]] alias BlockScoutWeb.{AccessHelper, CaptchaHelper} alias BlockScoutWeb.API.V2.{AddressView, TransactionView} - alias Explorer.{Chain, Helper} + alias Explorer.{Chain, Helper, PagingOptions} alias Explorer.Chain.{Address, BridgedToken, Token, Token.Instance} alias Indexer.Fetcher.OnDemand.TokenInstanceMetadataRefetch, as: TokenInstanceMetadataRefetchOnDemand alias Indexer.Fetcher.OnDemand.TokenTotalSupply, as: TokenTotalSupplyOnDemand @@ -46,7 +46,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do end end - if Application.compile_env(:explorer, Explorer.Chain.BridgedToken)[:enabled] do + if @bridged_token_enabled do defp token_response(conn, token, address_hash) do if token.bridged do bridged_token = @@ -195,8 +195,12 @@ defmodule BlockScoutWeb.API.V2.TokenController do {:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params), {:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)}, {:not_found, false} <- {:not_found, Chain.erc_20_token?(token)}, - {:format, {token_id, ""}} <- {:format, Integer.parse(token_id_string)} do - token_instance = token_instance_from_token_id_and_token_address(token_id, address_hash, token) + {:format, {token_id, ""}} <- {:format, Integer.parse(token_id_string)}, + {:ok, token_instance} <- Chain.nft_instance_from_token_id_and_token_address(token_id, address_hash, @api_true) do + token_instance = + token_instance + |> Chain.select_repo(@api_true).preload(owner: [:names, :smart_contract, proxy_implementations_association()]) + |> Chain.put_owner_to_token_instance(token, @api_true) conn |> put_status(200) @@ -361,26 +365,6 @@ defmodule BlockScoutWeb.API.V2.TokenController do defp put_owner(token_instances, holder_address), do: Enum.map(token_instances, fn token_instance -> %Instance{token_instance | owner: holder_address} end) - defp token_instance_from_token_id_and_token_address(token_id, address_hash, token) do - case Chain.nft_instance_from_token_id_and_token_address(token_id, address_hash, @api_true) do - {:ok, token_instance} -> - token_instance - |> Chain.select_repo(@api_true).preload(owner: [:names, :smart_contract, proxy_implementations_association()]) - |> Chain.put_owner_to_token_instance(token, @api_true) - - {:error, :not_found} -> - %Instance{ - token_id: Decimal.new(token_id), - metadata: nil, - owner: nil, - token: nil, - token_contract_address_hash: address_hash - } - |> Instance.put_is_unique(token, @api_true) - |> Chain.put_owner_to_token_instance(token, @api_true) - end - end - @spec put_token_to_instance(Instance.t(), Token.t()) :: Instance.t() defp put_token_to_instance( token_instance, diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex index 4c648221fffd..668cf6fa1945 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.TransactionController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import BlockScoutWeb.Account.AuthController, only: [current_user: 1] alias BlockScoutWeb.API.V2.BlobView @@ -51,7 +52,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do action_fallback(BlockScoutWeb.API.V2.FallbackController) - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> @chain_type_transaction_necessity_by_association %{ :beacon_blob_transaction => :optional diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex index 5450b97173e4..89e0c722a5c1 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.VerificationController do use BlockScoutWeb, :controller + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import Explorer.SmartContract.Solidity.Verifier, only: [parse_boolean: 1] @@ -21,7 +22,7 @@ defmodule BlockScoutWeb.API.V2.VerificationController do @sc_verification_started "Smart-contract verification started" @zk_optimization_modes ["0", "1", "2", "3", "s", "z"] - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do @optimization_runs "0" else @optimization_runs 200 diff --git a/apps/block_scout_web/lib/block_scout_web/counters/blocks_indexed_counter.ex b/apps/block_scout_web/lib/block_scout_web/counters/blocks_indexed_counter.ex index d5e7b64ab487..3ca57e6b87aa 100644 --- a/apps/block_scout_web/lib/block_scout_web/counters/blocks_indexed_counter.ex +++ b/apps/block_scout_web/lib/block_scout_web/counters/blocks_indexed_counter.ex @@ -6,15 +6,13 @@ defmodule BlockScoutWeb.Counters.BlocksIndexedCounter do """ use GenServer - - alias BlockScoutWeb.Notifier - alias Explorer.Chain - # It is undesirable to automatically start the counter in all environments. # Consider the test environment: if it initiates but does not finish before a # test ends, that test will fail. - config = Application.compile_env(:block_scout_web, __MODULE__) - @enabled Keyword.get(config, :enabled) + use Utils.CompileTimeEnvHelper, enabled: [:block_scout_web, [__MODULE__, :enabled]] + + alias BlockScoutWeb.Notifier + alias Explorer.Chain @doc """ Starts a process to periodically update the % of blocks indexed. diff --git a/apps/block_scout_web/lib/block_scout_web/counters/internal_transactions_indexed_counter.ex b/apps/block_scout_web/lib/block_scout_web/counters/internal_transactions_indexed_counter.ex index cb9d5937875f..f0c7df3ebd25 100644 --- a/apps/block_scout_web/lib/block_scout_web/counters/internal_transactions_indexed_counter.ex +++ b/apps/block_scout_web/lib/block_scout_web/counters/internal_transactions_indexed_counter.ex @@ -6,15 +6,13 @@ defmodule BlockScoutWeb.Counters.InternalTransactionsIndexedCounter do """ use GenServer - - alias BlockScoutWeb.Notifier - alias Explorer.Chain - # It is undesirable to automatically start the counter in all environments. # Consider the test environment: if it initiates but does not finish before a # test ends, that test will fail. - config = Application.compile_env(:block_scout_web, __MODULE__) - @enabled Keyword.get(config, :enabled) + use Utils.CompileTimeEnvHelper, enabled: [:block_scout_web, [__MODULE__, :enabled]] + + alias BlockScoutWeb.Notifier + alias Explorer.Chain @doc """ Starts a process to periodically update the % of internal transactions indexed. diff --git a/apps/block_scout_web/lib/block_scout_web/endpoint.ex b/apps/block_scout_web/lib/block_scout_web/endpoint.ex index dfb2f2b84434..7d642b6f6a20 100644 --- a/apps/block_scout_web/lib/block_scout_web/endpoint.ex +++ b/apps/block_scout_web/lib/block_scout_web/endpoint.ex @@ -2,11 +2,17 @@ defmodule BlockScoutWeb.Endpoint do use Phoenix.Endpoint, otp_app: :block_scout_web use Absinthe.Phoenix.Endpoint - if Application.compile_env(:block_scout_web, :sql_sandbox) do + use Utils.CompileTimeEnvHelper, + disable_api?: [:block_scout_web, :disable_api?], + sql_sandbox: [:block_scout_web, :sql_sandbox], + cookie_domain: [:block_scout_web, :cookie_domain], + session_cookie_ttl: [:block_scout_web, :session_cookie_ttl] + + if @sql_sandbox do plug(Phoenix.Ecto.SQL.Sandbox, repo: Explorer.Repo) end - if Application.compile_env(:block_scout_web, :disable_api?) do + if @disable_api? do plug(BlockScoutWeb.HealthRouter) else socket("/socket", BlockScoutWeb.UserSocket, websocket: [timeout: 45_000]) @@ -60,8 +66,8 @@ defmodule BlockScoutWeb.Endpoint do signing_salt: "iC2ksJHS", same_site: "Lax", http_only: false, - domain: Application.compile_env(:block_scout_web, :cookie_domain), - max_age: Application.compile_env(:block_scout_web, :session_cookie_ttl) + domain: @cookie_domain, + max_age: @session_cookie_ttl ) use SpandexPhoenix diff --git a/apps/block_scout_web/lib/block_scout_web/etherscan.ex b/apps/block_scout_web/lib/block_scout_web/etherscan.ex index 472bf82780d7..06367f6e8666 100644 --- a/apps/block_scout_web/lib/block_scout_web/etherscan.ex +++ b/apps/block_scout_web/lib/block_scout_web/etherscan.ex @@ -2,7 +2,7 @@ defmodule BlockScoutWeb.Etherscan do @moduledoc """ Documentation data for Etherscan-compatible API. """ - alias Explorer.Chain.BridgedToken + use Utils.CompileTimeEnvHelper, bridged_token_enabled: [:block_scout_web, [Explorer.Chain.BridgedToken, :enabled]] @account_balance_example_value %{ "status" => "1", @@ -2010,7 +2010,7 @@ defmodule BlockScoutWeb.Etherscan do ] } - if Application.compile_env(:explorer, BridgedToken)[:enabled] do + if @bridged_token_enabled do @success_status_type %{ type: "status", enum: ~s(["1"]), @@ -3064,7 +3064,7 @@ defmodule BlockScoutWeb.Etherscan do @token_gettokenholders_action ] - @token_actions if Application.compile_env(:explorer, BridgedToken)[:enabled], + @token_actions if @bridged_token_enabled, do: [@token_bridgedtokenlist_action, @base_token_actions], else: @base_token_actions diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex b/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex index 2a01ac5b8f29..b579a9dbc58f 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex @@ -3,6 +3,7 @@ defmodule BlockScoutWeb.GraphQL.Schema do use Absinthe.Schema use Absinthe.Relay.Schema, :modern + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Absinthe.Middleware.Dataloader, as: AbsintheDataloaderMiddleware alias Absinthe.Plugin, as: AbsinthePlugin @@ -24,7 +25,7 @@ defmodule BlockScoutWeb.GraphQL.Schema do import_types(BlockScoutWeb.GraphQL.Schema.Types) - if Application.compile_env(:explorer, :chain_type) == :celo do + if @chain_type == :celo do import_types(BlockScoutWeb.GraphQL.Celo.Schema.Types) end @@ -107,7 +108,7 @@ defmodule BlockScoutWeb.GraphQL.Schema do resolve(&Transaction.get_by/3) end - if Application.compile_env(:explorer, :chain_type) == :celo do + if @chain_type == :celo do require BlockScoutWeb.GraphQL.Celo.QueryFields alias BlockScoutWeb.GraphQL.Celo.QueryFields diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/schema/types.ex b/apps/block_scout_web/lib/block_scout_web/graphql/schema/types.ex index f9fdee7ba7e1..4dd86565e538 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/schema/types.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/schema/types.ex @@ -1,9 +1,10 @@ defmodule BlockScoutWeb.GraphQL.Schema.Transaction do @moduledoc false + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.GraphQL.Resolvers.{Block, InternalTransaction} - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :celo -> @chain_type_fields quote( do: [ @@ -62,8 +63,10 @@ defmodule BlockScoutWeb.GraphQL.Schema.Transaction do end defmodule BlockScoutWeb.GraphQL.Schema.SmartContracts do + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + @moduledoc false - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :zksync -> @chain_type_fields quote( do: [ diff --git a/apps/block_scout_web/lib/block_scout_web/microservice_interfaces/transaction_interpretation.ex b/apps/block_scout_web/lib/block_scout_web/microservice_interfaces/transaction_interpretation.ex index d2af052ea967..a2cc867cfa5e 100644 --- a/apps/block_scout_web/lib/block_scout_web/microservice_interfaces/transaction_interpretation.ex +++ b/apps/block_scout_web/lib/block_scout_web/microservice_interfaces/transaction_interpretation.ex @@ -35,14 +35,17 @@ defmodule BlockScoutWeb.MicroserviceInterfaces.TransactionInterpretation do | {:error, Jason.DecodeError.t()} | {:ok, any()} def interpret(transaction_or_map, request_builder \\ &prepare_request_body/1) do - if enabled?() do + with {:enabled, true} <- {:enabled, enabled?()}, + {:cache, :no_cached_data} <- + {:cache, try_get_cached_value(get_hash(transaction_or_map))} do url = interpret_url() body = request_builder.(transaction_or_map) http_post_request(url, body) else - {{:error, :disabled}, 403} + {:cache, {:ok, _response} = result} -> result + {:enabled, false} -> {{:error, :disabled}, 403} end end @@ -96,6 +99,16 @@ defmodule BlockScoutWeb.MicroserviceInterfaces.TransactionInterpretation do end end + defp try_get_cached_value(hash) do + with {:ok, %Response{body: body, status_code: 200}} <- HTTPoison.get(cache_url(hash)), + {:ok, json} <- body |> Jason.decode() do + {:ok, json |> Map.get("response") |> Map.put("success", true)} |> preload_template_variables() + else + _ -> + :no_cached_data + end + end + defp http_response_code({:ok, %Response{status_code: status_code}}), do: status_code defp http_response_code(_), do: 500 @@ -105,6 +118,10 @@ defmodule BlockScoutWeb.MicroserviceInterfaces.TransactionInterpretation do base_url(:block_scout_web, __MODULE__) <> "/transactions/summary" end + defp cache_url(hash) do + base_url(:block_scout_web, __MODULE__) <> "/cache/#{hash}" + end + defp prepare_request_body(transaction) do transaction = Chain.select_repo(@api_true).preload(transaction, [ @@ -391,4 +408,7 @@ defmodule BlockScoutWeb.MicroserviceInterfaces.TransactionInterpretation do {mock_transaction, decoded_input, decoded_input |> Transaction.format_decoded_input() |> TransactionView.decoded_input()} end + + defp get_hash(%{hash: hash}), do: hash + defp get_hash(%{"hash" => hash}), do: hash end diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index 9ed9e000273d..4cb73aa5f015 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -2,6 +2,7 @@ defmodule BlockScoutWeb.Notifier do @moduledoc """ Responds to events by sending appropriate channel updates to front-end. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Logger @@ -31,7 +32,7 @@ defmodule BlockScoutWeb.Notifier do @check_broadcast_sequence_period 500 - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> @chain_type_specific_events ~w(new_arbitrum_batches new_messages_to_arbitrum_amount)a @@ -296,7 +297,7 @@ defmodule BlockScoutWeb.Notifier do }) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> def handle_event({:chain_event, topic, _, _} = event) when topic in @chain_type_specific_events, # credo:disable-for-next-line Credo.Check.Design.AliasUsage diff --git a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex index 8360aadc5ed3..77c7b5409d62 100644 --- a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex +++ b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex @@ -2,6 +2,8 @@ defmodule BlockScoutWeb.PagingHelper do @moduledoc """ Helper for fetching filters and other url query parameters """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + import Explorer.Chain, only: [string_to_transaction_hash: 1] import Explorer.Chain.SmartContract.Proxy.Models.Implementation, only: [proxy_implementations_association: 0] @@ -13,7 +15,7 @@ defmodule BlockScoutWeb.PagingHelper do @default_paging_options %PagingOptions{page_size: @page_size + 1} @allowed_filter_labels ["validated", "pending"] - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> @allowed_type_labels [ "coin_transfer", diff --git a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex index c0fb18915f34..f075509c6867 100644 --- a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex +++ b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex @@ -2,8 +2,8 @@ defmodule BlockScoutWeb.RealtimeEventHandler do @moduledoc """ Subscribing process for broadcast events from realtime. """ - use GenServer + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.Notifier alias Explorer.Chain.Events.Subscriber @@ -12,7 +12,7 @@ defmodule BlockScoutWeb.RealtimeEventHandler do GenServer.start_link(__MODULE__, [], name: __MODULE__) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> def chain_type_specific_subscriptions do Subscriber.to(:new_arbitrum_batches, :realtime) diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex index 07300fd79bbd..43426fbe25df 100644 --- a/apps/block_scout_web/lib/block_scout_web/router.ex +++ b/apps/block_scout_web/lib/block_scout_web/router.ex @@ -1,12 +1,18 @@ defmodule BlockScoutWeb.Router do use BlockScoutWeb, :router + use Utils.CompileTimeEnvHelper, + admin_panel_enabled: [:block_scout_web, :admin_panel_enabled], + graphql_enabled: [:block_scout_web, [Api.GraphQL, :enabled]], + api_router_reading_enabled: [:block_scout_web, [BlockScoutWeb.Routers.ApiRouter, :reading_enabled]], + web_router_enabled: [:block_scout_web, [BlockScoutWeb.Routers.WebRouter, :enabled]] + alias BlockScoutWeb.Plug.{GraphQL, RateLimit} - alias BlockScoutWeb.Routers.{AccountRouter, ApiRouter, WebRouter} + alias BlockScoutWeb.Routers.{AccountRouter, ApiRouter} @max_query_string_length 5_000 - if Application.compile_env(:block_scout_web, :admin_panel_enabled) do + if @admin_panel_enabled do forward("/admin", BlockScoutWeb.Routers.AdminRouter) end @@ -62,8 +68,7 @@ defmodule BlockScoutWeb.Router do scope "/graphiql" do pipe_through(:api_v1_graphql) - if Application.compile_env(:block_scout_web, Api.GraphQL)[:enabled] && - Application.compile_env(:block_scout_web, ApiRouter)[:reading_enabled] do + if @graphql_enabled && @api_router_reading_enabled do forward("/", Absinthe.Plug.GraphiQL, schema: BlockScoutWeb.GraphQL.Schema, interface: :advanced, @@ -79,7 +84,7 @@ defmodule BlockScoutWeb.Router do get("/robots.txt", RobotsController, :robots) get("/sitemap.xml", RobotsController, :sitemap) - if Application.compile_env(:block_scout_web, ApiRouter)[:reading_enabled] do + if @api_router_reading_enabled do get("/api-docs", APIDocsController, :index) get("/eth-rpc-api-docs", APIDocsController, :eth_rpc) else @@ -94,7 +99,7 @@ defmodule BlockScoutWeb.Router do post("/contract_verifications", BlockScoutWeb.AddressContractVerificationController, :create) end - if Application.compile_env(:block_scout_web, WebRouter)[:enabled] do + if @web_router_enabled do forward("/", BlockScoutWeb.Routers.WebRouter) end end diff --git a/apps/block_scout_web/lib/block_scout_web/routers/api_router.ex b/apps/block_scout_web/lib/block_scout_web/routers/api_router.ex index 80038e0b103a..ece2cf66fb39 100644 --- a/apps/block_scout_web/lib/block_scout_web/routers/api_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/routers/api_router.ex @@ -13,6 +13,16 @@ defmodule BlockScoutWeb.Routers.ApiRouter do Router for API """ use BlockScoutWeb, :router + + use Utils.CompileTimeEnvHelper, + chain_type: [:explorer, :chain_type], + mud_enabled: [:explorer, [Explorer.Chain.Mud, :enabled]], + graphql_enabled: [:block_scout_web, [Api.GraphQL, :enabled]], + graphql_max_complexity: [:block_scout_web, [Api.GraphQL, :max_complexity]], + graphql_token_limit: [:block_scout_web, [Api.GraphQL, :token_limit]], + reading_enabled: [:block_scout_web, [__MODULE__, :reading_enabled]], + writing_enabled: [:block_scout_web, [__MODULE__, :writing_enabled]] + alias BlockScoutWeb.AddressTransactionController alias BlockScoutWeb.Routers.{ @@ -127,27 +137,27 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/watchlist", V2.TransactionController, :watchlist_transactions) get("/stats", V2.TransactionController, :stats) - if Application.compile_env(:explorer, :chain_type) == :polygon_zkevm do + if @chain_type == :polygon_zkevm do get("/zkevm-batch/:batch_number", V2.TransactionController, :polygon_zkevm_batch) end - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do get("/zksync-batch/:batch_number", V2.TransactionController, :zksync_batch) end - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do get("/arbitrum-batch/:batch_number", V2.TransactionController, :arbitrum_batch) end - if Application.compile_env(:explorer, :chain_type) == :optimism do + if @chain_type == :optimism do get("/optimism-batch/:batch_number", V2.TransactionController, :optimism_batch) end - if Application.compile_env(:explorer, :chain_type) == :scroll do + if @chain_type == :scroll do get("/scroll-batch/:batch_number", V2.TransactionController, :scroll_batch) end - if Application.compile_env(:explorer, :chain_type) == :suave do + if @chain_type == :suave do get("/execution-node/:execution_node_hash_param", V2.TransactionController, :execution_node) end @@ -159,7 +169,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/:transaction_hash_param/state-changes", V2.TransactionController, :state_changes) get("/:transaction_hash_param/summary", V2.TransactionController, :summary) - if Application.compile_env(:explorer, :chain_type) == :ethereum do + if @chain_type == :ethereum do get("/:transaction_hash_param/blobs", V2.TransactionController, :blobs) end end @@ -180,20 +190,20 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/:block_hash_or_number/internal-transactions", V2.BlockController, :internal_transactions) get("/:block_hash_or_number/withdrawals", V2.BlockController, :withdrawals) - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do get("/arbitrum-batch/:batch_number", V2.BlockController, :arbitrum_batch) end - if Application.compile_env(:explorer, :chain_type) == :celo do + if @chain_type == :celo do get("/:block_hash_or_number/epoch", V2.BlockController, :celo_epoch) get("/:block_hash_or_number/election-rewards/:reward_type", V2.BlockController, :celo_election_rewards) end - if Application.compile_env(:explorer, :chain_type) == :optimism do + if @chain_type == :optimism do get("/optimism-batch/:batch_number", V2.BlockController, :optimism_batch) end - if Application.compile_env(:explorer, :chain_type) == :scroll do + if @chain_type == :scroll do get("/scroll-batch/:batch_number", V2.BlockController, :scroll_batch) end end @@ -216,7 +226,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/:address_hash_param/nft", V2.AddressController, :nft_list) get("/:address_hash_param/nft/collections", V2.AddressController, :nft_collections) - if Application.compile_env(:explorer, :chain_type) == :celo do + if @chain_type == :celo do get("/:address_hash_param/election-rewards", V2.AddressController, :celo_election_rewards) end end @@ -227,21 +237,21 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/transactions/watchlist", V2.MainPageController, :watchlist_transactions) get("/indexing-status", V2.MainPageController, :indexing_status) - if Application.compile_env(:explorer, :chain_type) == :optimism do + if @chain_type == :optimism do get("/optimism-deposits", V2.MainPageController, :optimism_deposits) end - if Application.compile_env(:explorer, :chain_type) == :polygon_zkevm do + if @chain_type == :polygon_zkevm do get("/zkevm/batches/confirmed", V2.PolygonZkevmController, :batches_confirmed) get("/zkevm/batches/latest-number", V2.PolygonZkevmController, :batch_latest_number) end - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do get("/zksync/batches/confirmed", V2.ZkSyncController, :batches_confirmed) get("/zksync/batches/latest-number", V2.ZkSyncController, :batch_latest_number) end - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do get("/arbitrum/messages/to-rollup", V2.ArbitrumController, :recent_messages_to_l2) get("/arbitrum/batches/committed", V2.ArbitrumController, :batches_committed) get("/arbitrum/batches/latest-number", V2.ArbitrumController, :batch_latest_number) @@ -259,7 +269,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/optimism" do - if Application.compile_env(:explorer, :chain_type) == :optimism do + if @chain_type == :optimism do get("/txn-batches", V2.OptimismController, :transaction_batches) get("/txn-batches/count", V2.OptimismController, :transaction_batches_count) get("/txn-batches/:l2_block_range_start/:l2_block_range_end", V2.OptimismController, :transaction_batches) @@ -279,7 +289,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/polygon-edge" do - if Application.compile_env(:explorer, :chain_type) == :polygon_edge do + if @chain_type == :polygon_edge do get("/deposits", V2.PolygonEdgeController, :deposits) get("/deposits/count", V2.PolygonEdgeController, :deposits_count) get("/withdrawals", V2.PolygonEdgeController, :withdrawals) @@ -288,7 +298,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/scroll" do - if Application.compile_env(:explorer, :chain_type) == :scroll do + if @chain_type == :scroll do get("/batches", V2.ScrollController, :batches) get("/batches/count", V2.ScrollController, :batches_count) get("/batches/:number", V2.ScrollController, :batch) @@ -300,7 +310,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/shibarium" do - if Application.compile_env(:explorer, :chain_type) == :shibarium do + if @chain_type == :shibarium do get("/deposits", V2.ShibariumController, :deposits) get("/deposits/count", V2.ShibariumController, :deposits_count) get("/withdrawals", V2.ShibariumController, :withdrawals) @@ -314,7 +324,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/zkevm" do - if Application.compile_env(:explorer, :chain_type) == :polygon_zkevm do + if @chain_type == :polygon_zkevm do get("/batches", V2.PolygonZkevmController, :batches) get("/batches/count", V2.PolygonZkevmController, :batches_count) get("/batches/:batch_number", V2.PolygonZkevmController, :batch) @@ -363,13 +373,13 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/blobs" do - if Application.compile_env(:explorer, :chain_type) == :ethereum do + if @chain_type == :ethereum do get("/:blob_hash_param", V2.BlobController, :blob) end end scope "/validators" do - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :stability -> scope "/stability" do get("/", V2.ValidatorController, :stability_validators_list) @@ -388,7 +398,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/zksync" do - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do get("/batches", V2.ZkSyncController, :batches) get("/batches/count", V2.ZkSyncController, :batches_count) get("/batches/:batch_number", V2.ZkSyncController, :batch) @@ -396,7 +406,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/mud" do - if Application.compile_env(:explorer, Explorer.Chain.Mud)[:enabled] do + if @mud_enabled do get("/worlds", V2.MudController, :worlds) get("/worlds/count", V2.MudController, :worlds_count) get("/worlds/:world/tables", V2.MudController, :world_tables) @@ -410,7 +420,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do end scope "/arbitrum" do - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do get("/messages/:direction", V2.ArbitrumController, :messages) get("/messages/:direction/count", V2.ArbitrumController, :messages_count) get("/batches", V2.ArbitrumController, :batches) @@ -436,12 +446,12 @@ defmodule BlockScoutWeb.Routers.ApiRouter do scope "/v1/graphql" do pipe_through(:api_v1_graphql) - if Application.compile_env(:block_scout_web, Api.GraphQL)[:enabled] do + if @graphql_enabled do forward("/", Absinthe.Plug, schema: BlockScoutWeb.GraphQL.Schema, analyze_complexity: true, - max_complexity: Application.compile_env(:block_scout_web, Api.GraphQL)[:max_complexity], - token_limit: Application.compile_env(:block_scout_web, Api.GraphQL)[:token_limit] + max_complexity: @graphql_max_complexity, + token_limit: @graphql_token_limit ) end end @@ -463,6 +473,10 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/logs-csv", AddressTransactionController, :logs_csv) + if @chain_type == :celo do + get("/celo-election-rewards-csv", AddressTransactionController, :celo_election_rewards_csv) + end + scope "/health" do get("/", HealthController, :health) get("/liveness", HealthController, :liveness) @@ -471,17 +485,17 @@ defmodule BlockScoutWeb.Routers.ApiRouter do get("/gas-price-oracle", GasPriceOracleController, :gas_price_oracle) - if Application.compile_env(:block_scout_web, __MODULE__)[:reading_enabled] do + if @reading_enabled do get("/supply", V1.SupplyController, :supply) post("/eth-rpc", EthRPC.EthController, :eth_request) end - if Application.compile_env(:block_scout_web, __MODULE__)[:writing_enabled] do + if @writing_enabled do post("/decompiled_smart_contract", V1.DecompiledSmartContractController, :create) post("/verified_smart_contracts", V1.VerifiedSmartContractController, :create) end - if Application.compile_env(:block_scout_web, __MODULE__)[:reading_enabled] do + if @reading_enabled do forward("/", RPC.RPCTranslator, %{ "block" => {RPC.BlockController, []}, "account" => {RPC.AddressController, []}, @@ -499,7 +513,7 @@ defmodule BlockScoutWeb.Routers.ApiRouter do pipe_through(:api) alias BlockScoutWeb.API.{EthRPC, RPC} - if Application.compile_env(:block_scout_web, __MODULE__)[:reading_enabled] do + if @reading_enabled do post("/eth-rpc", EthRPC.EthController, :eth_request) forward("/", RPCTranslatorForwarder, %{ diff --git a/apps/block_scout_web/lib/block_scout_web/routers/smart_contracts_api_v2_router.ex b/apps/block_scout_web/lib/block_scout_web/routers/smart_contracts_api_v2_router.ex index aee2f7363b69..22bc36dc9e31 100644 --- a/apps/block_scout_web/lib/block_scout_web/routers/smart_contracts_api_v2_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/routers/smart_contracts_api_v2_router.ex @@ -4,6 +4,8 @@ defmodule BlockScoutWeb.Routers.SmartContractsApiV2Router do Router for /api/v2/smart-contracts. This route has separate router in order to ignore sobelow's warning about missing CSRF protection """ use BlockScoutWeb, :router + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + alias BlockScoutWeb.API.V2 alias BlockScoutWeb.Plug.{CheckApiV2, RateLimit} @@ -71,7 +73,7 @@ defmodule BlockScoutWeb.Routers.SmartContractsApiV2Router do post("/standard-input", V2.VerificationController, :verification_via_standard_input) - if Application.compile_env(:explorer, :chain_type) !== :zksync do + if @chain_type !== :zksync do post("/flattened-code", V2.VerificationController, :verification_via_flattened_code) post("/sourcify", V2.VerificationController, :verification_via_sourcify) post("/multi-part", V2.VerificationController, :verification_via_multi_part) @@ -80,7 +82,7 @@ defmodule BlockScoutWeb.Routers.SmartContractsApiV2Router do post("/vyper-standard-input", V2.VerificationController, :verification_via_vyper_standard_input) end - if Application.compile_env(:explorer, :chain_type) === :arbitrum do + if @chain_type === :arbitrum do post("/stylus-github-repository", V2.VerificationController, :verification_via_stylus_github_repository) end end diff --git a/apps/block_scout_web/lib/block_scout_web/routers/tokens_api_v2_router.ex b/apps/block_scout_web/lib/block_scout_web/routers/tokens_api_v2_router.ex index c9506cfc84e2..3954c04cdaba 100644 --- a/apps/block_scout_web/lib/block_scout_web/routers/tokens_api_v2_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/routers/tokens_api_v2_router.ex @@ -4,6 +4,8 @@ defmodule BlockScoutWeb.Routers.TokensApiV2Router do Router for /api/v2/tokens. This route has separate router in order to ignore sobelow's warning about missing CSRF protection """ use BlockScoutWeb, :router + use Utils.CompileTimeEnvHelper, bridged_token_enabled: [:explorer, [Explorer.Chain.BridgedToken, :enabled]] + alias BlockScoutWeb.API.V2 alias BlockScoutWeb.Plug.{CheckApiV2, RateLimit} @@ -52,7 +54,7 @@ defmodule BlockScoutWeb.Routers.TokensApiV2Router do scope "/", as: :api_v2 do pipe_through(:api_v2) - if Application.compile_env(:explorer, Explorer.Chain.BridgedToken)[:enabled] do + if @bridged_token_enabled do get("/bridged", V2.TokenController, :bridged_tokens_list) end diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex index 11ae92643390..bbc0d6741e12 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.AddressView do use BlockScoutWeb, :view + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import BlockScoutWeb.Account.AuthController, only: [current_user: 1] @@ -242,7 +243,7 @@ defmodule BlockScoutWeb.API.V2.AddressView do }) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> defp chain_type_fields(result, params) do # credo:disable-for-next-line Credo.Check.Design.AliasUsage diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex index 79f3abdd6731..35152fd16588 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.BlockView do use BlockScoutWeb, :view + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.BlockView alias BlockScoutWeb.API.V2.{ApiView, Helper} @@ -103,7 +104,7 @@ defmodule BlockScoutWeb.API.V2.BlockView do def count_withdrawals(%Block{withdrawals: withdrawals}) when is_list(withdrawals), do: Enum.count(withdrawals) def count_withdrawals(_), do: nil - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :rsk -> defp chain_type_fields(result, block, single_block?) do if single_block? do diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/filecoin_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/filecoin_view.ex index 82a2270b65c4..6e26f264c8ee 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/filecoin_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/filecoin_view.ex @@ -1,11 +1,13 @@ -if Application.compile_env(:explorer, :chain_type) == :filecoin do - defmodule BlockScoutWeb.API.V2.FilecoinView do - @moduledoc """ - View functions for rendering Filecoin-related data in JSON format. - """ +defmodule BlockScoutWeb.API.V2.FilecoinView do + @moduledoc """ + View functions for rendering Filecoin-related data in JSON format. + """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] - alias Explorer.Chain - alias Explorer.Chain.Address + if @chain_type == :filecoin do + # TODO: remove when https://github.com/elixir-lang/elixir/issues/13975 comes to elixir release + alias Explorer.Chain, warn: false + alias Explorer.Chain.Address, warn: false @api_true [api?: true] @@ -108,3 +110,5 @@ if Application.compile_env(:explorer, :chain_type) == :filecoin do end end end + +# end diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex index 88b3e41f5330..b2752554f09d 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex @@ -2,6 +2,7 @@ defmodule BlockScoutWeb.API.V2.Helper do @moduledoc """ API V2 helper """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Ecto.Association.NotLoaded alias Explorer.Chain.Address @@ -118,7 +119,7 @@ defmodule BlockScoutWeb.API.V2.Helper do } end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> defp address_chain_type_fields(result, address) do # credo:disable-for-next-line Credo.Check.Design.AliasUsage diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex index 1134914e6248..dbda49f01570 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.SearchView do use BlockScoutWeb, :view + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.{BlockView, Endpoint} alias Explorer.Chain @@ -165,7 +166,7 @@ defmodule BlockScoutWeb.API.V2.SearchView do %{"type" => "blob", "parameter" => to_string(item.hash)} end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> defp chain_type_fields(result) do # credo:disable-for-next-line Credo.Check.Design.AliasUsage diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex index 70da14e7fb09..7bf5670579e5 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do use BlockScoutWeb, :view + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import Explorer.Helper, only: [decode_data: 2] import Explorer.SmartContract.Reader, only: [zip_tuple_values_with_types: 2] @@ -443,7 +444,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do to_string(value) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> defp chain_type_fields(result, params) do # credo:disable-for-next-line Credo.Check.Design.AliasUsage diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex index 935a06ff8df3..72b1ad715199 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.TokenView do use BlockScoutWeb, :view + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.API.V2.Helper alias BlockScoutWeb.NFTHelper @@ -141,7 +142,7 @@ defmodule BlockScoutWeb.API.V2.TokenView do end end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> defp chain_type_fields(result, params) do # credo:disable-for-next-line Credo.Check.Design.AliasUsage diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex index 53d7aa6ac1a1..739271dbbc2b 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.V2.TransactionView do use BlockScoutWeb, :view + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias BlockScoutWeb.API.V2.{ApiView, Helper, InternalTransactionView, TokenTransferView, TokenView} @@ -780,7 +781,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do Map.merge(map, %{"change" => change}) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :polygon_edge -> defp chain_type_transformations(transactions) do transactions diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/zilliqa_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/zilliqa_view.ex index d3f7c4768776..238d2c72ab3c 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/zilliqa_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/zilliqa_view.ex @@ -1,11 +1,13 @@ -if Application.compile_env(:explorer, :chain_type) == :zilliqa do - defmodule BlockScoutWeb.API.V2.ZilliqaView do - @moduledoc """ - View functions for rendering Zilliqa-related data in JSON format. - """ +defmodule BlockScoutWeb.API.V2.ZilliqaView do + @moduledoc """ + View functions for rendering Zilliqa-related data in JSON format. + """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] - alias Explorer.Chain.Block - alias Explorer.Chain.Zilliqa.{AggregateQuorumCertificate, QuorumCertificate} + if @chain_type == :zilliqa do + # TODO: remove when https://github.com/elixir-lang/elixir/issues/13975 comes to elixir release + alias Explorer.Chain.Block, warn: false + alias Explorer.Chain.Zilliqa.{AggregateQuorumCertificate, QuorumCertificate}, warn: false @doc """ Extends the JSON output with a sub-map containing information related to Zilliqa, diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index 7ffaf8b09e0c..412358ec2388 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -87,7 +87,6 @@ defmodule BlockScoutWeb.Mixfile do {:bypass, "~> 2.1", only: :test}, # To add (CORS)(https://www.w3.org/TR/cors/) {:cors_plug, "~> 3.0"}, - {:credo, "~> 1.5", only: :test, runtime: false}, # For Absinthe to load data in batches {:dataloader, "~> 2.0.0"}, {:dialyxir, "~> 1.1", only: [:dev, :test], runtime: false}, @@ -156,6 +155,7 @@ defmodule BlockScoutWeb.Mixfile do {:ex_json_schema, "~> 0.10.1"}, {:ueberauth, "~> 0.7"}, {:ueberauth_auth0, "~> 2.0"}, + {:utils, in_umbrella: true}, {:bureaucrat, "~> 0.2.9", only: :test}, {:logger_json, "~> 5.1"} ] diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs index 1e391497e9cb..b66848970826 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs @@ -1050,24 +1050,12 @@ defmodule BlockScoutWeb.API.V2.TokenControllerTest do assert Address.checksum(instance.owner_address_hash) == data["owner"]["hash"] end - test "get token instance by token id which is not presented in DB", %{conn: conn} do + test "get 404 on token instance which is not presented in DB", %{conn: conn} do token = insert(:token, type: "ERC-721") request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/instances/0") - token_address = Address.checksum(token.contract_address.hash) - token_name = token.name - token_type = token.type - assert %{ - "animation_url" => nil, - "external_app_url" => nil, - "id" => "0", - "image_url" => nil, - "is_unique" => true, - "metadata" => nil, - "owner" => nil, - "token" => %{"address" => ^token_address, "name" => ^token_name, "type" => ^token_type} - } = json_response(request, 200) + assert %{"message" => "Not found"} = json_response(request, 404) end # https://github.com/blockscout/blockscout/issues/9906 diff --git a/apps/block_scout_web/test/block_scout_web/views/api/v2/transaction_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/api/v2/transaction_view_test.exs index 6b42d89a5f83..a5ff0b18f6b9 100644 --- a/apps/block_scout_web/test/block_scout_web/views/api/v2/transaction_view_test.exs +++ b/apps/block_scout_web/test/block_scout_web/views/api/v2/transaction_view_test.exs @@ -79,6 +79,81 @@ defmodule BlockScoutWeb.API.V2.TransactionViewTest do ]} ] = TransactionView.decode_logs(logs, false) end + + test "properly decode logs if they have same topics" do + insert(:contract_method, + identifier: Base.decode16!("d20a68b2", case: :lower), + abi: %{ + "name" => "OptionSettled", + "type" => "event", + "inputs" => [ + %{"name" => "accountId", "type" => "uint256", "indexed" => true, "internalType" => "uint256"}, + %{"name" => "option", "type" => "address", "indexed" => false, "internalType" => "address"}, + %{"name" => "subId", "type" => "uint256", "indexed" => false, "internalType" => "uint256"}, + %{"name" => "amount", "type" => "int256", "indexed" => false, "internalType" => "int256"}, + %{"name" => "value", "type" => "int256", "indexed" => false, "internalType" => "int256"} + ], + "anonymous" => false + } + ) + + topic1_bytes = ExKeccak.hash_256("OptionSettled(uint256,address,uint256,int256,int256)") + topic1 = "0x" <> Base.encode16(topic1_bytes, case: :lower) + topic2 = "0x0000000000000000000000000000000000000000000000000000000000005d19" + + log1_data = + "0x000000000000000000000000aeb81cbe6b19ceeb0dbe0d230cffe35bb40a13a700000000000000000000000000000000000000000000045d964b80006597b700fffffffffffffffffffffffffffffffffffffffffffffffffe55aca2c2f40000ffffffffffffffffffffffffffffffffffffffffffffffe3a8289da3d7a13ef2" + + log2_data = + "0x000000000000000000000000aeb81cbe6b19ceeb0dbe0d230cffe35bb40a13a700000000000000000000000000000000000000000000045d964b80006597b700000000000000000000000000000000000000000000000000011227ebced227ae00000000000000000000000000000000000000000000001239fdf180a3d6bd85" + + transaction = insert(:transaction) + + log1 = + insert(:log, + transaction: transaction, + first_topic: topic(topic1), + second_topic: topic(topic2), + third_topic: nil, + fourth_topic: nil, + data: log1_data + ) + + log2 = + insert(:log, + transaction: transaction, + first_topic: topic(topic1), + second_topic: topic(topic2), + third_topic: nil, + fourth_topic: nil, + data: log2_data + ) + + logs = [log1, log2] + + assert [ + {:ok, "d20a68b2", + "OptionSettled(uint256 indexed accountId, address option, uint256 subId, int256 amount, int256 value)", + [ + {"accountId", "uint256", true, 23833}, + {"option", "address", false, + <<174, 184, 28, 190, 107, 25, 206, 235, 13, 190, 13, 35, 12, 255, 227, 91, 180, 10, 19, 167>>}, + {"subId", "uint256", false, 20_615_843_020_801_704_441_600}, + {"amount", "int256", false, -120_000_000_000_000_000}, + {"value", "int256", false, -522_838_470_013_113_778_446} + ]}, + {:ok, "d20a68b2", + "OptionSettled(uint256 indexed accountId, address option, uint256 subId, int256 amount, int256 value)", + [ + {"accountId", "uint256", true, 23833}, + {"option", "address", false, + <<174, 184, 28, 190, 107, 25, 206, 235, 13, 190, 13, 35, 12, 255, 227, 91, 180, 10, 19, 167>>}, + {"subId", "uint256", false, 20_615_843_020_801_704_441_600}, + {"amount", "int256", false, 77_168_037_359_396_782}, + {"value", "int256", false, 336_220_154_890_848_484_741} + ]} + ] = TransactionView.decode_logs(logs, false) + end end defp topic(topic_hex_string) do diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex index 1024cb806238..36c5294f5cc0 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex @@ -3,6 +3,7 @@ defmodule EthereumJSONRPC.Block do Block format as returned by [`eth_getBlockByHash`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_getblockbyhash) and [`eth_getBlockByNumber`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_getblockbynumber). """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import EthereumJSONRPC, only: [quantity_to_integer: 1, timestamp_to_datetime: 1] @@ -16,7 +17,7 @@ defmodule EthereumJSONRPC.Block do # (sha3Uncles) is the RLP-encoded hash of an empty list. @sha3_uncles_empty_list "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :rsk -> @chain_type_fields quote( do: [ @@ -124,7 +125,7 @@ defmodule EthereumJSONRPC.Block do [uncles](https://bitcoin.stackexchange.com/questions/39329/in-ethereum-what-is-an-uncle-block) `t:EthereumJSONRPC.hash/0`. * `"baseFeePerGas"` - `t:EthereumJSONRPC.quantity/0` of wei to denote amount of fee burnt per unit gas used. Introduced in [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :rsk -> """ * `"minimumGasPrice"` - `t:EthereumJSONRPC.quantity/0` of the minimum gas price for this block. * `"bitcoinMergedMiningHeader"` - `t:EthereumJSONRPC.data/0` of the Bitcoin merged mining header. @@ -190,7 +191,7 @@ defmodule EthereumJSONRPC.Block do ...> "totalDifficulty" => 340282366920938463463374607431465668165, ...> "transactions" => [], ...> "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :rsk -> """ "minimumGasPrice" => 345786,\ "bitcoinMergedMiningHeader" => "0x00006d20ffd048280094a6ea0851d854036aacaa25ee0f23f0040200000000000000000078d2638fe0b4477c54601e6449051afba8228e0a88ff06b0c91f091fd34d5da57487c76402610517372c2fe9",\ @@ -241,7 +242,7 @@ defmodule EthereumJSONRPC.Block do timestamp: Timex.parse!("2017-12-15T21:03:30Z", "{ISO:Extended:Z}"), total_difficulty: 340282366920938463463374607431465668165, transactions_root: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :rsk -> """ bitcoin_merged_mining_coinbase_transaction: "0x00000000000000805bf0dc9203da49a3b4e3ec913806e43102cc07db991272dc8b7018da57eb5abe59a32d070000ffffffff03449a4d26000000001976a914536ffa992491508dca0354e52f32a3a7a679a53a88ac00000000000000002b6a2952534b424c4f434b3ad2508d21d28c8f89d495923c0758ec3f64bd6755b4ec416f5601312600542a400000000000000000266a24aa21a9ed4ae42ea6dca2687aaed665714bf58b055c4e11f2fb038605930d630b49ad7b9d00000000",\ bitcoin_merged_mining_header: "0x00006d20ffd048280094a6ea0851d854036aacaa25ee0f23f0040200000000000000000078d2638fe0b4477c54601e6449051afba8228e0a88ff06b0c91f091fd34d5da57487c76402610517372c2fe9",\ @@ -312,7 +313,7 @@ defmodule EthereumJSONRPC.Block do timestamp: Timex.parse!("2015-07-30T15:32:07Z", "{ISO:Extended:Z}"), total_difficulty: 1039309006117, transactions_root: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :rsk -> """ bitcoin_merged_mining_coinbase_transaction: nil,\ bitcoin_merged_mining_header: nil,\ @@ -523,7 +524,7 @@ defmodule EthereumJSONRPC.Block do end @spec chain_type_fields(params, elixir) :: params - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :rsk -> defp chain_type_fields(params, elixir) do params @@ -937,7 +938,7 @@ defmodule EthereumJSONRPC.Block do {key, Withdrawals.to_elixir(withdrawals, block_hash, quantity_to_integer(block_number))} end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :zilliqa -> defp entry_to_elixir({"view" = key, quantity}, _block) when not is_nil(quantity) do {key, quantity_to_integer(quantity)} diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/blocks.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/blocks.ex index 9439089f6057..e02ef953a478 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/blocks.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/blocks.ex @@ -3,6 +3,7 @@ defmodule EthereumJSONRPC.Blocks do Blocks format as returned by [`eth_getBlockByHash`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_getblockbyhash) and [`eth_getBlockByNumber`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_getblockbynumber) from batch requests. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias EthereumJSONRPC.{Block, Transactions, Transport, Uncles, Withdrawals} @@ -17,7 +18,7 @@ defmodule EthereumJSONRPC.Blocks do errors: [] ] - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :zilliqa -> @chain_type_fields quote( do: [ @@ -99,7 +100,7 @@ defmodule EthereumJSONRPC.Blocks do end @spec extend_with_chain_type_fields(t(), elixir()) :: t() - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :zilliqa -> defp extend_with_chain_type_fields(%__MODULE__{} = blocks, elixir_blocks) do # credo:disable-for-next-line Credo.Check.Design.AliasUsage @@ -164,7 +165,7 @@ defmodule EthereumJSONRPC.Blocks do timestamp: Timex.parse!("1970-01-01T00:00:00Z", "{ISO:Extended:Z}"), total_difficulty: 131072, transactions_root: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :rsk -> """ bitcoin_merged_mining_coinbase_transaction: nil,\ bitcoin_merged_mining_header: nil,\ diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http/httpoison.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http/httpoison.ex index d7f561075192..3cc475d3ded4 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http/httpoison.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http/httpoison.ex @@ -9,9 +9,18 @@ defmodule EthereumJSONRPC.HTTP.HTTPoison do @impl HTTP def json_rpc(url, json, headers, options) when is_binary(url) and is_list(options) do + gzip_enabled? = Application.get_env(:ethereum_jsonrpc, EthereumJSONRPC.HTTP)[:gzip_enabled?] + + headers = + if gzip_enabled? do + [{"Accept-Encoding", "gzip"} | headers] + else + headers + end + case HTTPoison.post(url, json, headers, options) do - {:ok, %HTTPoison.Response{body: body, status_code: status_code}} -> - {:ok, %{body: body, status_code: status_code}} + {:ok, %HTTPoison.Response{body: body, status_code: status_code, headers: headers}} -> + {:ok, %{body: try_unzip(gzip_enabled?, body, headers), status_code: status_code}} {:error, %HTTPoison.Error{reason: reason}} -> {:error, reason} @@ -19,4 +28,31 @@ defmodule EthereumJSONRPC.HTTP.HTTPoison do end def json_rpc(url, _json, _headers, _options) when is_nil(url), do: {:error, "URL is nil"} + + defp try_unzip(true, body, headers) do + gzipped = + Enum.any?( + headers + |> Enum.map(fn {k, v} -> + {String.downcase(k), String.downcase(v)} + end), + fn kv -> + case kv do + {"content-encoding", "gzip"} -> true + {"content-encoding", "x-gzip"} -> true + _ -> false + end + end + ) + + if gzipped do + :zlib.gunzip(body) + else + body + end + end + + defp try_unzip(_gzip_enabled?, body, _headers) do + body + end end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipt.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipt.ex index a09d04a66170..2b7410ebe9a4 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipt.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipt.ex @@ -3,12 +3,13 @@ defmodule EthereumJSONRPC.Receipt do Receipts format as returned by [`eth_getTransactionReceipt`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_gettransactionreceipt). """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import EthereumJSONRPC, only: [quantity_to_integer: 1] alias EthereumJSONRPC.Logs - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> @chain_type_fields quote( do: [ @@ -117,7 +118,7 @@ defmodule EthereumJSONRPC.Receipt do status: :ok, transaction_hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", transaction_index: 0,\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :ethereum -> """ blob_gas_price: 0,\ blob_gas_used: 0\ @@ -169,7 +170,7 @@ defmodule EthereumJSONRPC.Receipt do status: nil, transaction_hash: "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060", transaction_index: 0,\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :ethereum -> """ blob_gas_price: 0,\ blob_gas_used: 0\ @@ -234,7 +235,7 @@ defmodule EthereumJSONRPC.Receipt do defp maybe_append_gas_price(params, _), do: params - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> defp chain_type_fields(params, elixir) do params diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex index 0ef62c61867d..9b5c432a52c8 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex @@ -4,6 +4,7 @@ defmodule EthereumJSONRPC.Receipts do [`eth_getTransactionReceipt`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_gettransactionreceipt) from batch requests. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import EthereumJSONRPC, only: [json_rpc: 2, request: 1] @@ -100,7 +101,7 @@ defmodule EthereumJSONRPC.Receipts do status: :ok, transaction_hash: "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", transaction_index: 0,\ - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :ethereum -> """ blob_gas_price: 0,\ blob_gas_used: 0\ diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex index a584ae1d5043..4fd2c31b5da8 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex @@ -7,6 +7,8 @@ defmodule EthereumJSONRPC.Transaction do [`eth_getTransactionByBlockHashAndIndex`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_gettransactionbyblockhashandindex), and [`eth_getTransactionByBlockNumberAndIndex`](https://github.com/ethereum/wiki/wiki/JSON-RPC/e8e0771b9f3677693649d945956bc60e886ceb2b#eth_gettransactionbyblocknumberandindex) """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + import EthereumJSONRPC, only: [ quantity_to_integer: 1, @@ -18,7 +20,7 @@ defmodule EthereumJSONRPC.Transaction do alias EthereumJSONRPC alias EthereumJSONRPC.SignedAuthorization - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> @chain_type_fields quote( do: [ @@ -122,7 +124,7 @@ defmodule EthereumJSONRPC.Transaction do * `"maxFeePerGas"` - `t:EthereumJSONRPC.quantity/0` of wei to denote max fee per unit of gas used. Introduced in [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) * `"type"` - `t:EthereumJSONRPC.quantity/0` denotes transaction type. Introduced in [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) * `"authorizationList"` - `t:list/0` of `t:EthereumJSONRPC.SignedAuthorization.t/0` authorization tuples. Introduced in [EIP-7702](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md) - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :ethereum -> """ * `"maxFeePerBlobGas"` - `t:EthereumJSONRPC.quantity/0` of wei to denote max fee per unit of blob gas used. Introduced in [EIP-4844](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md) * `"blobVersionedHashes"` - `t:list/0` of `t:EthereumJSONRPC.hash/0` of included data blobs hashes. Introduced in [EIP-4844](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md) @@ -740,7 +742,7 @@ defmodule EthereumJSONRPC.Transaction do do: {key, value |> Enum.map(&SignedAuthorization.to_params/1)} # Celo-specific fields - if Application.compile_env(:explorer, :chain_type) == :celo do + if @chain_type == :celo do defp entry_to_elixir({key, value}) when key in ~w(feeCurrency gatewayFeeRecipient), do: {key, value} diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs index dd83d7330b85..cbc0b829abe9 100644 --- a/apps/ethereum_jsonrpc/mix.exs +++ b/apps/ethereum_jsonrpc/mix.exs @@ -58,8 +58,6 @@ defmodule EthereumJSONRPC.MixProject do {:certifi, "~> 2.3"}, # WebSocket-server for testing `EthereumJSONRPC.WebSocket.WebSocketClient`. {:cowboy, "~> 2.0", only: [:dev, :test]}, - # Style Checking - {:credo, "~> 1.5", only: :test, runtime: false}, # Static Type Checking {:dialyxir, "~> 1.1", only: [:dev, :test], runtime: false}, {:ex_keccak, "~> 0.7.5"}, @@ -88,6 +86,7 @@ defmodule EthereumJSONRPC.MixProject do {:poolboy, "~> 1.5.2"}, {:b58, "~> 1.0.2"}, {:logger_json, "~> 5.1"}, + {:utils, in_umbrella: true}, {:websockex, "~> 0.4.3"} ] end diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index cfa4f10dfc5b..99350f00877a 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -82,7 +82,8 @@ defmodule Explorer.Application do con_cache_child_spec(MarketHistoryCache.cache_name()), con_cache_child_spec(RSK.cache_name(), ttl_check_interval: :timer.minutes(1), global_ttl: :timer.minutes(30)), {Redix, redix_opts()}, - {Explorer.Utility.MissingRangesManipulator, []} + {Explorer.Utility.MissingRangesManipulator, []}, + {Explorer.Utility.ReplicaAccessibilityManager, []} ] children = base_children ++ configurable_children() diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 24c19b1d39e1..b75ca90b9fa0 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -3740,11 +3740,12 @@ defmodule Explorer.Chain do when accumulator: term() def stream_token_instances_with_error(initial, reducer, limited? \\ false) when is_function(reducer, 2) do # likely to get valid metadata - high_priority = ["request error: 429", ":checkout_timeout", ":econnrefused", ":timeout"] + high_priority = ["request error: 429", ":checkout_timeout"] # almost impossible to get valid metadata negative_priority = ["VM execution error", "no uri", "invalid json"] Instance + |> where([instance], is_nil(instance.is_banned) or not instance.is_banned) |> where([instance], not is_nil(instance.error)) |> where([instance], is_nil(instance.refetch_after) or instance.refetch_after < ^DateTime.utc_now()) |> select([instance], %{ @@ -3947,14 +3948,15 @@ defmodule Explorer.Chain do @spec upsert_token_instance(map()) :: {:ok, Instance.t()} | {:error, Ecto.Changeset.t()} def upsert_token_instance(params) do changeset = Instance.changeset(%Instance{}, params) + max_retries_count_before_ban = Instance.error_to_max_retries_count_before_ban(params[:error]) Repo.insert(changeset, - on_conflict: token_instance_metadata_on_conflict(), + on_conflict: token_instance_metadata_on_conflict(max_retries_count_before_ban), conflict_target: [:token_id, :token_contract_address_hash] ) end - defp token_instance_metadata_on_conflict do + defp token_instance_metadata_on_conflict(max_retries_count_before_ban) do config = Application.get_env(:indexer, Indexer.Fetcher.TokenInstance.Retry) coef = config[:exp_timeout_coeff] @@ -3978,16 +3980,29 @@ defmodule Explorer.Chain do refetch_after: fragment( """ - CASE WHEN EXCLUDED.metadata IS NULL THEN - NOW() AT TIME ZONE 'UTC' + interval '1 seconds' * (? * ? ^ LEAST(? + 1.0, ?)) + CASE + WHEN ? > ? THEN + NULL + WHEN EXCLUDED.metadata IS NULL THEN + NOW() AT TIME ZONE 'UTC' + interval '1 seconds' * (? * ? ^ LEAST(? + 1.0, ?)) ELSE NULL END """, + token_instance.retries_count + 1, + ^max_retries_count_before_ban, ^coef, ^base, token_instance.retries_count, ^max_retry_count + ), + is_banned: + fragment( + """ + CASE WHEN ? > ? THEN TRUE ELSE FALSE END + """, + token_instance.retries_count + 1, + ^max_retries_count_before_ban ) ] ], diff --git a/apps/explorer/lib/explorer/chain/address.ex b/apps/explorer/lib/explorer/chain/address.ex index 0729633b3825..690987a3eadd 100644 --- a/apps/explorer/lib/explorer/chain/address.ex +++ b/apps/explorer/lib/explorer/chain/address.ex @@ -5,6 +5,7 @@ defmodule Explorer.Chain.Address.Schema do Changes in the schema should be reflected in the bulk import module: - Explorer.Chain.Import.Runner.Addresses """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.Chain.{ Address, @@ -24,7 +25,7 @@ defmodule Explorer.Chain.Address.Schema do alias Explorer.Chain.Cache.{Accounts, NetVersion} alias Explorer.Chain.SmartContract.Proxy.Models.Implementation - @chain_type_fields (case Application.compile_env(:explorer, :chain_type) do + @chain_type_fields (case @chain_type do :filecoin -> alias Explorer.Chain.Filecoin.{IDAddress, NativeAddress} @@ -133,6 +134,7 @@ defmodule Explorer.Chain.Address do require Explorer.Chain.Address.Schema use Explorer.Schema + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Ecto.Association.NotLoaded alias Ecto.Changeset @@ -145,7 +147,7 @@ defmodule Explorer.Chain.Address do import Explorer.Chain.SmartContract.Proxy.Models.Implementation, only: [proxy_implementations_association: 0] @optional_attrs ~w(contract_code fetched_coin_balance fetched_coin_balance_block_number nonce decompiled verified gas_used transactions_count token_transfers_count)a - @chain_type_optional_attrs (case Application.compile_env(:explorer, :chain_type) do + @chain_type_optional_attrs (case @chain_type do :filecoin -> ~w(filecoin_id filecoin_robust filecoin_actor_type)a @@ -200,7 +202,7 @@ defmodule Explorer.Chain.Address do * `inserted_at` - when this address was inserted * `updated_at` - when this address was last updated * `ens_domain_name` - virtual field for ENS domain name passing - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :filecoin -> """ * `filecoin_native_address` - robust f0/f1/f2/f3/f4 Filecoin address * `filecoin_id_address` - short f0 Filecoin address that may change during chain reorgs diff --git a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex index 7d2efd461704..65d356d5441b 100644 --- a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex +++ b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex @@ -348,7 +348,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do |> Stream.map(fn ctb -> [ Address.checksum(ctb.address_hash), - CurrencyHelper.divide_decimals(ctb.value, token.decimals) + ctb.value |> CurrencyHelper.divide_decimals(token.decimals) |> Decimal.to_string(:xsd) ] end) diff --git a/apps/explorer/lib/explorer/chain/advanced_filter.ex b/apps/explorer/lib/explorer/chain/advanced_filter.ex index 5924084c64e0..2f38bc27ab71 100644 --- a/apps/explorer/lib/explorer/chain/advanced_filter.ex +++ b/apps/explorer/lib/explorer/chain/advanced_filter.ex @@ -283,7 +283,11 @@ defmodule Explorer.Chain.AdvancedFilter do query |> page_transactions(paging_options) |> limit_query(paging_options) - |> apply_transactions_filters(options) + |> apply_transactions_filters( + options, + fn query -> query |> order_by([transaction], desc: transaction.block_number, desc: transaction.index) end + ) + |> limit_query(paging_options) end defp page_transactions(query, %PagingOptions{ @@ -315,8 +319,8 @@ defmodule Explorer.Chain.AdvancedFilter do (internal_transaction.type == :call and internal_transaction.index > 0) or internal_transaction.type != :call, order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, + desc: transaction.block_number, + desc: transaction.index, desc: internal_transaction.index ] ) @@ -332,8 +336,8 @@ defmodule Explorer.Chain.AdvancedFilter do (internal_transaction.type == :call and internal_transaction.index > 0) or internal_transaction.type != :call, order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, + desc: transaction.block_number, + desc: transaction.index, desc: internal_transaction.index ] ) @@ -342,7 +346,14 @@ defmodule Explorer.Chain.AdvancedFilter do query |> page_internal_transactions(paging_options) |> limit_query(paging_options) - |> apply_internal_transactions_filters(options) + |> apply_transactions_filters(options, fn query -> + query + |> order_by([internal_transaction], + desc: internal_transaction.block_number, + desc: internal_transaction.transaction_index, + desc: internal_transaction.index + ) + end) |> limit_query(paging_options) |> preload([:transaction]) end @@ -698,25 +709,17 @@ defmodule Explorer.Chain.AdvancedFilter do |> filter_token_transfers_by_amount(options[:amount][:from], options[:amount][:to]) end - defp apply_transactions_filters(query, options) do - query - |> filter_transactions_by_amount(options[:amount][:from], options[:amount][:to]) - |> filter_transactions_by_methods(options[:methods]) - |> only_collated_transactions() - |> filter_by_addresses(options[:from_address_hashes], options[:to_address_hashes], options[:address_relation]) - |> filter_by_age(:transaction, options) - end - - defp apply_internal_transactions_filters(query, options) do + defp apply_transactions_filters(query, options, order_by) do query |> filter_transactions_by_amount(options[:amount][:from], options[:amount][:to]) |> filter_transactions_by_methods(options[:methods]) |> only_collated_transactions() |> filter_by_age(:transaction, options) - |> filter_internal_transactions_by_addresses( + |> filter_transactions_by_addresses( options[:from_address_hashes], options[:to_address_hashes], - options[:address_relation] + options[:address_relation], + order_by ) end @@ -815,59 +818,6 @@ defmodule Explorer.Chain.AdvancedFilter do defp filter_by_timestamp(query, _, _), do: query - defp filter_by_addresses(query, from_addresses, to_addresses, relation) do - to_address_dynamic = do_filter_by_addresses(:to_address_hash, to_addresses) - - from_address_dynamic = do_filter_by_addresses(:from_address_hash, from_addresses) - - final_condition = - case {to_address_dynamic, from_address_dynamic} do - {not_nil_to_address, not_nil_from_address} when nil not in [not_nil_to_address, not_nil_from_address] -> - combine_filter_by_addresses(not_nil_to_address, not_nil_from_address, relation) - - _ -> - to_address_dynamic || from_address_dynamic - end - - case final_condition do - not_nil when not is_nil(not_nil) -> query |> where(^not_nil) - _ -> query - end - end - - defp do_filter_by_addresses(field, addresses) do - to_include_dynamic = do_filter_by_addresses_inclusion(field, addresses && Keyword.get(addresses, :include)) - to_exclude_dynamic = do_filter_by_addresses_exclusion(field, addresses && Keyword.get(addresses, :exclude)) - - case {to_include_dynamic, to_exclude_dynamic} do - {not_nil_include, not_nil_exclude} when nil not in [not_nil_include, not_nil_exclude] -> - dynamic([t], ^not_nil_include and ^not_nil_exclude) - - _ -> - to_include_dynamic || to_exclude_dynamic - end - end - - defp do_filter_by_addresses_inclusion(field, [_ | _] = addresses) do - dynamic([t], field(t, ^field) in ^addresses) - end - - defp do_filter_by_addresses_inclusion(_, _), do: nil - - defp do_filter_by_addresses_exclusion(field, [_ | _] = addresses) do - dynamic([t], field(t, ^field) not in ^addresses) - end - - defp do_filter_by_addresses_exclusion(_, _), do: nil - - defp combine_filter_by_addresses(from_addresses_dynamic, to_addresses_dynamic, :or) do - dynamic([t], ^from_addresses_dynamic or ^to_addresses_dynamic) - end - - defp combine_filter_by_addresses(from_addresses_dynamic, to_addresses_dynamic, _) do - dynamic([t], ^from_addresses_dynamic and ^to_addresses_dynamic) - end - defp filter_token_transfers_by_addresses(query_function, from_addresses_params, to_addresses_params, relation) do case {process_address_inclusion(from_addresses_params), process_address_inclusion(to_addresses_params)} do {nil, nil} -> query_function @@ -1050,152 +1000,149 @@ defmodule Explorer.Chain.AdvancedFilter do end end - defp filter_internal_transactions_by_addresses(query, from_addresses, to_addresses, relation) do + defp filter_transactions_by_addresses(query, from_addresses, to_addresses, relation, order_by) do + order_by = fn query -> query |> exclude(:order_by) |> order_by.() end + case {process_address_inclusion(from_addresses), process_address_inclusion(to_addresses)} do {nil, nil} -> query - {from, nil} -> do_filter_internal_transactions_by_address(query, from, :from_address_hash) - {nil, to} -> do_filter_internal_transactions_by_address(query, to, :to_address_hash) - {from, to} -> do_filter_internal_transactions_by_both_addresses(query, from, to, relation) + {from, nil} -> do_filter_transactions_by_address(query, from, :from_address_hash, order_by) + {nil, to} -> do_filter_transactions_by_address(query, to, :to_address_hash, order_by) + {from, to} -> do_filter_transactions_by_both_addresses(query, from, to, relation, order_by) end end - defp do_filter_internal_transactions_by_address(query, {:include, addresses}, field) do + defp do_filter_transactions_by_address(query, {:include, addresses}, field, order_by) do queries = addresses |> Enum.map(fn address -> - query |> where([token_transfer], field(token_transfer, ^field) == ^address) + query + |> where([transaction], field(transaction, ^field) == ^address) + |> order_by.() end) |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union_all(acc, ^query) end) - from(internal_transaction in subquery(queries), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(queries)) + filtered_query |> order_by.() end - defp do_filter_internal_transactions_by_address(query, {:exclude, addresses}, field) do - query |> where([t], field(t, ^field) not in ^addresses) + defp do_filter_transactions_by_address(query, {:exclude, addresses}, field, order_by) do + query + |> where([transaction], field(transaction, ^field) not in ^addresses) + |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses(query, {:include, from}, {:include, to}, relation) do + defp do_filter_transactions_by_both_addresses(query, {:include, from}, {:include, to}, relation, order_by) do from_queries = from |> Enum.map(fn from_address -> - query |> where([internal_transaction], internal_transaction.from_address_hash == ^from_address) + query + |> where([transaction], transaction.from_address_hash == ^from_address) + |> order_by.() end) to_queries = to |> Enum.map(fn to_address -> - query |> where([internal_transaction], internal_transaction.to_address_hash == ^to_address) + query + |> where([transaction], transaction.to_address_hash == ^to_address) + |> order_by.() end) - do_filter_internal_transactions_by_both_addresses_to_include(from_queries, to_queries, relation) + do_filter_transactions_by_both_addresses_to_include(from_queries, to_queries, relation, order_by) end - defp do_filter_internal_transactions_by_both_addresses(query, {:include, from}, {:exclude, to}, :and) do + defp do_filter_transactions_by_both_addresses(query, {:include, from}, {:exclude, to}, :and, order_by) do from_queries = from |> Enum.map(fn from_address -> query |> where( - [internal_transaction], - internal_transaction.from_address_hash == ^from_address and internal_transaction.to_address_hash not in ^to + [transaction], + transaction.from_address_hash == ^from_address and transaction.to_address_hash not in ^to ) + |> order_by.() end) |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union_all(acc, ^query) end) - from(internal_transaction in subquery(from_queries), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(from_queries)) + filtered_query |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses(query, {:include, from}, {:exclude, to}, _relation) do + defp do_filter_transactions_by_both_addresses(query, {:include, from}, {:exclude, to}, _relation, order_by) do from_queries = from |> Enum.map(fn from_address -> query |> where( - [internal_transaction], - internal_transaction.from_address_hash == ^from_address or internal_transaction.to_address_hash not in ^to + [transaction], + transaction.from_address_hash == ^from_address or transaction.to_address_hash not in ^to ) + |> order_by.() end) |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union_all(acc, ^query) end) - from(internal_transaction in subquery(from_queries), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(from_queries)) + filtered_query |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses(query, {:exclude, from}, {:include, to}, :and) do + defp do_filter_transactions_by_both_addresses(query, {:exclude, from}, {:include, to}, :and, order_by) do to_queries = to |> Enum.map(fn to_address -> query |> where( - [internal_transaction], - internal_transaction.to_address_hash == ^to_address and internal_transaction.from_address_hash not in ^from + [transaction], + transaction.to_address_hash == ^to_address and transaction.from_address_hash not in ^from ) + |> order_by.() end) |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union_all(acc, ^query) end) - from(internal_transaction in subquery(to_queries), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(to_queries)) + filtered_query |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses(query, {:exclude, from}, {:include, to}, _relation) do + defp do_filter_transactions_by_both_addresses(query, {:exclude, from}, {:include, to}, _relation, order_by) do to_queries = to |> Enum.map(fn to_address -> query |> where( - [internal_transaction], - internal_transaction.to_address_hash == ^to_address or internal_transaction.from_address_hash not in ^from + [transaction], + transaction.to_address_hash == ^to_address or transaction.from_address_hash not in ^from ) + |> order_by.() end) |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union_all(acc, ^query) end) - from(internal_transaction in subquery(to_queries), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(to_queries)) + filtered_query |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses(query, {:exclude, from}, {:exclude, to}, :and) do + defp do_filter_transactions_by_both_addresses(query, {:exclude, from}, {:exclude, to}, :and, order_by) do query - |> where([t], t.from_address_hash not in ^from and t.to_address_hash not in ^to) + |> where( + [transaction], + transaction.from_address_hash not in ^from and transaction.to_address_hash not in ^to + ) + |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses(query, {:exclude, from}, {:exclude, to}, _relation) do + defp do_filter_transactions_by_both_addresses(query, {:exclude, from}, {:exclude, to}, _relation, order_by) do query - |> where([t], t.from_address_hash not in ^from or t.to_address_hash not in ^to) + |> where( + [transaction], + transaction.from_address_hash not in ^from or transaction.to_address_hash not in ^to + ) + |> order_by.() end - defp do_filter_internal_transactions_by_both_addresses_to_include(from_queries, to_queries, relation) do + defp do_filter_transactions_by_both_addresses_to_include(from_queries, to_queries, relation, order_by) do case relation do :and -> united_from_queries = @@ -1204,13 +1151,10 @@ defmodule Explorer.Chain.AdvancedFilter do united_to_queries = to_queries |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union_all(acc, ^query) end) - from(internal_transaction in subquery(intersect_all(united_from_queries, ^united_to_queries)), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(intersect_all(united_from_queries, ^united_to_queries))) + + filtered_query + |> order_by.() _ -> union_query = @@ -1219,13 +1163,8 @@ defmodule Explorer.Chain.AdvancedFilter do |> map_first(&subquery/1) |> Enum.reduce(fn query, acc -> union(acc, ^query) end) - from(internal_transaction in subquery(union_query), - order_by: [ - desc: internal_transaction.block_number, - desc: internal_transaction.transaction_index, - desc: internal_transaction.index - ] - ) + filtered_query = from(transaction in subquery(union_query)) + filtered_query |> order_by.() end end diff --git a/apps/explorer/lib/explorer/chain/block.ex b/apps/explorer/lib/explorer/chain/block.ex index 311242d57cdd..97b64444ad65 100644 --- a/apps/explorer/lib/explorer/chain/block.ex +++ b/apps/explorer/lib/explorer/chain/block.ex @@ -5,6 +5,8 @@ defmodule Explorer.Chain.Block.Schema do Changes in the schema should be reflected in the bulk import module: - Explorer.Chain.Import.Runner.Blocks """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + alias Explorer.Chain.{ Address, Block, @@ -23,7 +25,7 @@ defmodule Explorer.Chain.Block.Schema do alias Explorer.Chain.Zilliqa.QuorumCertificate, as: ZilliqaQuorumCertificate alias Explorer.Chain.ZkSync.BatchBlock, as: ZkSyncBatchBlock - @chain_type_fields (case Application.compile_env(:explorer, :chain_type) do + @chain_type_fields (case @chain_type do :ethereum -> elem( quote do @@ -185,6 +187,7 @@ defmodule Explorer.Chain.Block do require Explorer.Chain.Block.Schema use Explorer.Schema + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.Chain.{Block, Hash, Transaction, Wei} alias Explorer.Chain.Block.{EmissionReward, Reward} @@ -193,7 +196,7 @@ defmodule Explorer.Chain.Block do @optional_attrs ~w(size refetch_needed total_difficulty difficulty base_fee_per_gas)a - @chain_type_optional_attrs (case Application.compile_env(:explorer, :chain_type) do + @chain_type_optional_attrs (case @chain_type do :rsk -> ~w(minimum_gas_price bitcoin_merged_mining_header bitcoin_merged_mining_coinbase_transaction bitcoin_merged_mining_merkle_proof hash_for_merged_mining)a @@ -246,7 +249,7 @@ defmodule Explorer.Chain.Block do * `refetch_needed` - `true` if block has missing data and has to be refetched. * `transactions` - the `t:Explorer.Chain.Transaction.t/0` in this block. * `base_fee_per_gas` - Minimum fee required per unit of gas. Fee adjusts based on network congestion. - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :rsk -> """ * `bitcoin_merged_mining_header` - Bitcoin merged mining header on Rootstock chains. * `bitcoin_merged_mining_coinbase_transaction` - Bitcoin merged mining coinbase transaction on Rootstock chains. diff --git a/apps/explorer/lib/explorer/chain/block_number_helper.ex b/apps/explorer/lib/explorer/chain/block_number_helper.ex index 48fb1a7fba63..f06a70494389 100644 --- a/apps/explorer/lib/explorer/chain/block_number_helper.ex +++ b/apps/explorer/lib/explorer/chain/block_number_helper.ex @@ -3,12 +3,13 @@ defmodule Explorer.Chain.BlockNumberHelper do @moduledoc """ Functions to operate with block numbers based on null round heights (applicable for CHAIN_TYPE=filecoin) """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] def previous_block_number(number), do: neighbor_block_number(number, :previous) def next_block_number(number), do: neighbor_block_number(number, :next) - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :filecoin -> def null_rounds_count, do: Explorer.Chain.NullRoundHeight.total() diff --git a/apps/explorer/lib/explorer/chain/cache/blackfort_validators_counters.ex b/apps/explorer/lib/explorer/chain/cache/blackfort_validators_counters.ex index cf2a77411183..0cd9e8b5e221 100644 --- a/apps/explorer/lib/explorer/chain/cache/blackfort_validators_counters.ex +++ b/apps/explorer/lib/explorer/chain/cache/blackfort_validators_counters.ex @@ -6,22 +6,20 @@ defmodule Explorer.Chain.Cache.BlackfortValidatorsCounters do """ use GenServer - - alias Explorer.Chain - alias Explorer.Chain.Blackfort.Validator, as: ValidatorBlackfort - - @validators_counter_key "blackfort_validators_counter" - @new_validators_counter_key "new_blackfort_validators_counter" - # It is undesirable to automatically start the consolidation in all environments. # Consider the test environment: if the consolidation initiates but does not # finish before a test ends, that test will fail. This way, hundreds of # tests were failing before disabling the consolidation and the scheduler in # the test env. - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] + + alias Explorer.Chain + alias Explorer.Chain.Blackfort.Validator, as: ValidatorBlackfort - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) + @validators_counter_key "blackfort_validators_counter" + @new_validators_counter_key "new_blackfort_validators_counter" @doc """ Starts a process to periodically update validators blackfort counters diff --git a/apps/explorer/lib/explorer/chain/cache/contracts_counter.ex b/apps/explorer/lib/explorer/chain/cache/contracts_counter.ex index 27700e13508b..a6ce0162ae2d 100644 --- a/apps/explorer/lib/explorer/chain/cache/contracts_counter.ex +++ b/apps/explorer/lib/explorer/chain/cache/contracts_counter.ex @@ -6,20 +6,18 @@ defmodule Explorer.Chain.Cache.ContractsCounter do """ use GenServer - - alias Explorer.Chain - - @counter_type "contracts_counter" - # It is undesirable to automatically start the consolidation in all environments. # Consider the test environment: if the consolidation initiates but does not # finish before a test ends, that test will fail. This way, hundreds of # tests were failing before disabling the consolidation and the scheduler in # the test env. - config = Application.compile_env(:explorer, Explorer.Chain.Cache.ContractsCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] + + alias Explorer.Chain - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) + @counter_type "contracts_counter" @doc """ Starts a process to periodically update the counter of all the contracts. diff --git a/apps/explorer/lib/explorer/chain/cache/gas_usage.ex b/apps/explorer/lib/explorer/chain/cache/gas_usage.ex index ddff60dd41ab..075411521271 100644 --- a/apps/explorer/lib/explorer/chain/cache/gas_usage.ex +++ b/apps/explorer/lib/explorer/chain/cache/gas_usage.ex @@ -2,6 +2,7 @@ defmodule Explorer.Chain.Cache.GasUsage do @moduledoc """ Cache for total gas usage. """ + use Utils.CompileTimeEnvHelper, enabled: [:explorer, [__MODULE__, :enabled]] require Logger @@ -10,9 +11,6 @@ defmodule Explorer.Chain.Cache.GasUsage do from: 2 ] - config = Application.compile_env(:explorer, __MODULE__) - @enabled Keyword.get(config, :enabled) - use Explorer.Chain.MapCache, name: :gas_usage, key: :sum, diff --git a/apps/explorer/lib/explorer/chain/cache/new_contracts_counter.ex b/apps/explorer/lib/explorer/chain/cache/new_contracts_counter.ex index 8a8d27dd7b52..4c3b611808b3 100644 --- a/apps/explorer/lib/explorer/chain/cache/new_contracts_counter.ex +++ b/apps/explorer/lib/explorer/chain/cache/new_contracts_counter.ex @@ -6,20 +6,18 @@ defmodule Explorer.Chain.Cache.NewContractsCounter do """ use GenServer - - alias Explorer.Chain - - @counter_type "new_contracts_counter" - # It is undesirable to automatically start the consolidation in all environments. # Consider the test environment: if the consolidation initiates but does not # finish before a test ends, that test will fail. This way, hundreds of # tests were failing before disabling the consolidation and the scheduler in # the test env. - config = Application.compile_env(:explorer, Explorer.Chain.Cache.NewContractsCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] + + alias Explorer.Chain - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) + @counter_type "new_contracts_counter" @doc """ Starts a process to periodically update the counter of new diff --git a/apps/explorer/lib/explorer/chain/cache/new_verified_contracts_counter.ex b/apps/explorer/lib/explorer/chain/cache/new_verified_contracts_counter.ex index 019e76ec24e5..c8aec530e580 100644 --- a/apps/explorer/lib/explorer/chain/cache/new_verified_contracts_counter.ex +++ b/apps/explorer/lib/explorer/chain/cache/new_verified_contracts_counter.ex @@ -6,20 +6,18 @@ defmodule Explorer.Chain.Cache.NewVerifiedContractsCounter do """ use GenServer - - alias Explorer.Chain - - @counter_type "new_verified_contracts_counter" - # It is undesirable to automatically start the consolidation in all environments. # Consider the test environment: if the consolidation initiates but does not # finish before a test ends, that test will fail. This way, hundreds of # tests were failing before disabling the consolidation and the scheduler in # the test env. - config = Application.compile_env(:explorer, Explorer.Chain.Cache.NewVerifiedContractsCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] + + alias Explorer.Chain - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) + @counter_type "new_verified_contracts_counter" @doc """ Starts a process to periodically update the counter of new verified diff --git a/apps/explorer/lib/explorer/chain/cache/stability_validators_counters.ex b/apps/explorer/lib/explorer/chain/cache/stability_validators_counters.ex index 1034465848c6..816be2526acf 100644 --- a/apps/explorer/lib/explorer/chain/cache/stability_validators_counters.ex +++ b/apps/explorer/lib/explorer/chain/cache/stability_validators_counters.ex @@ -6,6 +6,14 @@ defmodule Explorer.Chain.Cache.StabilityValidatorsCounters do """ use GenServer + # It is undesirable to automatically start the consolidation in all environments. + # Consider the test environment: if the consolidation initiates but does not + # finish before a test ends, that test will fail. This way, hundreds of + # tests were failing before disabling the consolidation and the scheduler in + # the test env. + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] alias Explorer.Chain alias Explorer.Chain.Stability.Validator, as: ValidatorStability @@ -14,16 +22,6 @@ defmodule Explorer.Chain.Cache.StabilityValidatorsCounters do @new_validators_counter_key "new_stability_validators_counter" @active_validators_counter_key "active_stability_validators_counter" - # It is undesirable to automatically start the consolidation in all environments. - # Consider the test environment: if the consolidation initiates but does not - # finish before a test ends, that test will fail. This way, hundreds of - # tests were failing before disabling the consolidation and the scheduler in - # the test env. - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) - - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) - @doc """ Starts a process to periodically update validators stability counters """ diff --git a/apps/explorer/lib/explorer/chain/cache/verified_contracts_counter.ex b/apps/explorer/lib/explorer/chain/cache/verified_contracts_counter.ex index 10c850ef10b7..6e942b6217b3 100644 --- a/apps/explorer/lib/explorer/chain/cache/verified_contracts_counter.ex +++ b/apps/explorer/lib/explorer/chain/cache/verified_contracts_counter.ex @@ -6,20 +6,18 @@ defmodule Explorer.Chain.Cache.VerifiedContractsCounter do """ use GenServer - - alias Explorer.Chain - - @counter_type "verified_contracts_counter" - # It is undesirable to automatically start the consolidation in all environments. # Consider the test environment: if the consolidation initiates but does not # finish before a test ends, that test will fail. This way, hundreds of # tests were failing before disabling the consolidation and the scheduler in # the test env. - config = Application.compile_env(:explorer, Explorer.Chain.Cache.VerifiedContractsCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] + + alias Explorer.Chain - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) + @counter_type "verified_contracts_counter" @doc """ Starts a process to periodically update the counter of verified contracts. diff --git a/apps/explorer/lib/explorer/chain/cache/withdrawals_sum.ex b/apps/explorer/lib/explorer/chain/cache/withdrawals_sum.ex index cac2cf3a0384..e83da187aa13 100644 --- a/apps/explorer/lib/explorer/chain/cache/withdrawals_sum.ex +++ b/apps/explorer/lib/explorer/chain/cache/withdrawals_sum.ex @@ -1,16 +1,16 @@ defmodule Explorer.Chain.Cache.WithdrawalsSum do - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) - @moduledoc """ Caches the sum of all withdrawals. - It loads the sum asynchronously and in a time interval of #{@update_interval_in_milliseconds} milliseconds. + It loads the sum asynchronously and in a time interval of 30 minutes. """ use GenServer + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] + alias Explorer.Chain alias Explorer.Chain.Wei diff --git a/apps/explorer/lib/explorer/chain/celo/election_reward.ex b/apps/explorer/lib/explorer/chain/celo/election_reward.ex index e45d563f2b35..6b69d02e2b37 100644 --- a/apps/explorer/lib/explorer/chain/celo/election_reward.ex +++ b/apps/explorer/lib/explorer/chain/celo/election_reward.ex @@ -39,13 +39,20 @@ defmodule Explorer.Chain.Celo.ElectionReward do @type type :: :voter | :validator | :group | :delegated_payment @types_enum ~w(voter validator group delegated_payment)a - @reward_type_string_to_atom %{ + @reward_type_url_string_to_atom %{ "voter" => :voter, "validator" => :validator, "group" => :group, "delegated-payment" => :delegated_payment } + @reward_type_string_to_atom %{ + "voter" => :voter, + "validator" => :validator, + "group" => :group, + "delegated_payment" => :delegated_payment + } + @reward_type_atom_to_token_atom %{ :voter => :celo_token, :validator => :usd_token, @@ -113,12 +120,6 @@ defmodule Explorer.Chain.Celo.ElectionReward do |> foreign_key_constraint(:block_hash) |> foreign_key_constraint(:account_address_hash) |> foreign_key_constraint(:associated_account_address_hash) - - # todo: do I need to set this unique constraint here? or it is redundant? - # |> unique_constraint( - # [:block_hash, :type, :account_address_hash, :associated_account_address_hash], - # name: :celo_election_rewards_pkey - # ) end @doc """ @@ -128,7 +129,7 @@ defmodule Explorer.Chain.Celo.ElectionReward do def types, do: @types_enum @doc """ - Converts a reward type string to its corresponding atom. + Converts a reward type url string to its corresponding atom. ## Parameters - `type_string` (`String.t()`): The string representation of the reward type. @@ -138,15 +139,15 @@ defmodule Explorer.Chain.Celo.ElectionReward do ## Examples - iex> ElectionReward.type_from_string("voter") + iex> ElectionReward.type_from_url_string("voter") {:ok, :voter} - iex> ElectionReward.type_from_string("invalid") + iex> ElectionReward.type_from_url_string("invalid") :error """ - @spec type_from_string(String.t()) :: {:ok, type} | :error - def type_from_string(type_string) do - Map.fetch(@reward_type_string_to_atom, type_string) + @spec type_from_url_string(String.t()) :: {:ok, type} | :error + def type_from_url_string(type_string) do + Map.fetch(@reward_type_url_string_to_atom, type_string) end @doc """ @@ -360,7 +361,7 @@ defmodule Explorer.Chain.Celo.ElectionReward do {amount, ""} <- Decimal.parse(amount_string), {:ok, associated_account_address_hash} <- Hash.Address.cast(associated_account_address_hash_string), - {:ok, type} <- type_from_string(type_string) do + {:ok, type} <- Map.fetch(@reward_type_string_to_atom, type_string) do [ paging_options: %{ default_paging_options() @@ -521,4 +522,37 @@ defmodule Explorer.Chain.Celo.ElectionReward do "type" => type } end + + @doc """ + Custom filter for `ElectionReward`, inspired by + `Chain.where_block_number_in_period/3`. + + TODO: Consider reusing `Chain.where_block_number_in_period/3`. This would + require storing or making `merge_select` of `block_number`. + """ + @spec where_block_number_in_period( + Ecto.Query.t(), + String.t() | integer() | nil, + String.t() | integer() | nil + ) :: Ecto.Query.t() + def where_block_number_in_period(base_query, from_block, to_block) + when is_nil(from_block) and not is_nil(to_block), + do: where(base_query, [_, block], block.number <= ^to_block) + + def where_block_number_in_period(base_query, from_block, to_block) + when not is_nil(from_block) and is_nil(to_block), + do: where(base_query, [_, block], block.number > ^from_block) + + def where_block_number_in_period(base_query, from_block, to_block) + when is_nil(from_block) and is_nil(to_block), + do: base_query + + def where_block_number_in_period(base_query, from_block, to_block), + do: + where( + base_query, + [_, block], + block.number > ^from_block and + block.number <= ^to_block + ) end diff --git a/apps/explorer/lib/explorer/chain/celo/reader.ex b/apps/explorer/lib/explorer/chain/celo/reader.ex index ac49b8787b4a..8a76aed80e23 100644 --- a/apps/explorer/lib/explorer/chain/celo/reader.ex +++ b/apps/explorer/lib/explorer/chain/celo/reader.ex @@ -5,21 +5,14 @@ defmodule Explorer.Chain.Celo.Reader do import Ecto.Query, only: [limit: 2] - import Explorer.Chain, - only: [ - select_repo: 1, - join_associations: 2, - default_paging_options: 0, - max_consensus_block_number: 1 - ] - + alias Explorer.Chain alias Explorer.Chain.Block alias Explorer.Chain.Cache.{Blocks, CeloCoreContracts} alias Explorer.Chain.Celo.{ElectionReward, Helper} alias Explorer.Chain.{Hash, Token, Wei} @election_reward_types ElectionReward.types() - @default_paging_options default_paging_options() + @default_paging_options Chain.default_paging_options() @doc """ Retrieves election rewards associated with a given address hash. @@ -50,13 +43,17 @@ defmodule Explorer.Chain.Celo.Reader do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = Keyword.get(options, :paging_options, @default_paging_options) + from_block = Chain.from_block(options) + to_block = Chain.to_block(options) + address_hash |> ElectionReward.address_hash_to_ordered_rewards_query() + |> ElectionReward.where_block_number_in_period(from_block, to_block) |> ElectionReward.join_token() |> ElectionReward.paginate(paging_options) |> limit(^paging_options.page_size) - |> join_associations(necessity_by_association) - |> select_repo(options).all() + |> Chain.join_associations(necessity_by_association) + |> Chain.select_repo(options).all() end @doc """ @@ -94,8 +91,8 @@ defmodule Explorer.Chain.Celo.Reader do |> ElectionReward.block_hash_to_rewards_by_type_query(reward_type) |> ElectionReward.paginate(paging_options) |> limit(^paging_options.page_size) - |> join_associations(necessity_by_association) - |> select_repo(options).all() + |> Chain.join_associations(necessity_by_association) + |> Chain.select_repo(options).all() end @doc """ @@ -132,7 +129,7 @@ defmodule Explorer.Chain.Celo.Reader do reward_type_to_aggregated_rewards = block_hash |> ElectionReward.block_hash_to_aggregated_rewards_by_type_query() - |> select_repo(options).all() + |> Chain.select_repo(options).all() |> Map.new(fn {type, total, count} -> {type, %{total: total, count: count}} end) @@ -204,7 +201,7 @@ defmodule Explorer.Chain.Celo.Reader do |> Blocks.atomic_take_enough() |> case do [%Block{number: number}] -> {:ok, number} - nil -> max_consensus_block_number(options) + nil -> Chain.max_consensus_block_number(options) end |> case do {:ok, number} -> number diff --git a/apps/explorer/lib/explorer/chain/csv_export/celo/address_election_rewards_csv_exporter.ex b/apps/explorer/lib/explorer/chain/csv_export/celo/address_election_rewards_csv_exporter.ex new file mode 100644 index 000000000000..cd596132ae89 --- /dev/null +++ b/apps/explorer/lib/explorer/chain/csv_export/celo/address_election_rewards_csv_exporter.ex @@ -0,0 +1,87 @@ +defmodule Explorer.Chain.CSVExport.Celo.AddressElectionRewardsCsvExporter do + @moduledoc """ + Exports Celo election rewards to a csv file. + """ + import Explorer.Chain.Celo.Helper, + only: [ + block_number_to_epoch_number: 1 + ] + + alias Explorer.Chain.Celo.Reader + alias Explorer.Chain.CSVExport.Helper + alias Explorer.Chain.{Hash, Wei} + + @spec export(Hash.Address.t(), String.t() | nil, String.t() | nil, any(), any()) :: Enumerable.t() + def export(address_hash, from_period, to_period, _filter_type, _filter_value) do + {from_block, to_block} = Helper.block_from_period(from_period, to_period) + + options = [ + paging_options: Helper.paging_options(), + from_block: from_block, + to_block: to_block + ] + + address_hash + |> Reader.address_hash_to_election_rewards(options) + |> to_csv_format() + |> Helper.dump_to_stream() + end + + @spec to_csv_format(Enumerable.t()) :: Enumerable.t() + defp to_csv_format(election_rewards) do + column_names = [ + "EpochNumber", + "BlockNumber", + "TimestampUTC", + "EpochTxType", + "ValidatorAddress", + "ValidatorGroupAddress", + "ToAddress", + "Type", + "Value", + "ValueInWei", + "TokenSymbol", + "TokenContractAddress" + ] + + reward_type_to_human_readable = %{ + voter: "Voter Rewards", + validator: "Validator Rewards", + group: "Validator Group Rewards", + delegated_payment: "Delegated Validator Rewards" + } + + rows = + election_rewards + |> Stream.map(fn reward -> + [ + # EpochNumber + reward.block.number |> block_number_to_epoch_number(), + # BlockNumber + reward.block.number, + # TimestampUTC + reward.block.timestamp, + # EpochTxType + Map.get(reward_type_to_human_readable, reward.type, "N/A"), + # ValidatorAddress + (reward.type in ~w(group delegated_payment)a && reward.associated_account_address_hash) || "N/A", + # ValidatorGroupAddress + (reward.type in ~w(validator voter)a && reward.associated_account_address_hash) || "N/A", + # ToAddress + reward.account_address_hash, + # Type + "IN", + # Value + reward.amount |> Wei.to(:ether) |> Decimal.to_string(:normal), + # ValueInWei + reward.amount |> Wei.to(:wei) |> Decimal.to_string(:normal), + # TokenSymbol + reward.token.symbol, + # TokenContractAddress + reward.token.contract_address_hash + ] + end) + + Stream.concat([column_names], rows) + end +end diff --git a/apps/explorer/lib/explorer/chain/events/publisher.ex b/apps/explorer/lib/explorer/chain/events/publisher.ex index a0048248cf73..97e052e0da6e 100644 --- a/apps/explorer/lib/explorer/chain/events/publisher.ex +++ b/apps/explorer/lib/explorer/chain/events/publisher.ex @@ -2,6 +2,7 @@ defmodule Explorer.Chain.Events.Publisher do @moduledoc """ Publishes events related to the Chain context. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] @common_allowed_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions @@ -10,7 +11,7 @@ defmodule Explorer.Chain.Events.Publisher do smart_contract_was_verified zkevm_confirmed_batches eth_bytecode_db_lookup_started smart_contract_was_not_verified)a - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> @chain_type_specific_allowed_events ~w(new_arbitrum_batches new_messages_to_arbitrum_amount)a diff --git a/apps/explorer/lib/explorer/chain/events/subscriber.ex b/apps/explorer/lib/explorer/chain/events/subscriber.ex index 741422fac3f4..7f4133cd5428 100644 --- a/apps/explorer/lib/explorer/chain/events/subscriber.ex +++ b/apps/explorer/lib/explorer/chain/events/subscriber.ex @@ -2,6 +2,7 @@ defmodule Explorer.Chain.Events.Subscriber do @moduledoc """ Subscribes to events related to the Chain context. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] @common_allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions @@ -10,7 +11,7 @@ defmodule Explorer.Chain.Events.Subscriber do smart_contract_was_verified zkevm_confirmed_batches eth_bytecode_db_lookup_started smart_contract_was_not_verified)a - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> @chain_type_specific_allowed_broadcast_events ~w(new_arbitrum_batches new_messages_to_arbitrum_amount)a diff --git a/apps/explorer/lib/explorer/chain/import.ex b/apps/explorer/lib/explorer/chain/import.ex index 4886ab9dd3fa..2a2ad02d26df 100644 --- a/apps/explorer/lib/explorer/chain/import.ex +++ b/apps/explorer/lib/explorer/chain/import.ex @@ -12,16 +12,24 @@ defmodule Explorer.Chain.Import do require Logger @stages [ - Import.Stage.BlockRelated, - Import.Stage.BlockReferencing, - Import.Stage.BlockFollowing, - Import.Stage.BlockPending, - Import.Stage.ChainTypeSpecific + [ + Import.Stage.Main + ], + [ + Import.Stage.BlockTransactionReferencing, + Import.Stage.TokenReferencing, + Import.Stage.InternalTransactions, + Import.Stage.ChainTypeSpecific + ] ] # in order so that foreign keys are inserted before being referenced - @configured_runners Enum.flat_map(@stages, fn stage -> stage.runners() end) - @all_runners Enum.flat_map(@stages, fn stage -> stage.all_runners() end) + @configured_runners Enum.flat_map(@stages, fn stage_batch -> + Enum.flat_map(stage_batch, fn stage -> stage.runners() end) + end) + @all_runners Enum.flat_map(@stages, fn stage_batch -> + Enum.flat_map(stage_batch, fn stage -> stage.all_runners() end) + end) quoted_runner_option_value = quote do @@ -283,9 +291,11 @@ defmodule Explorer.Chain.Import do timestamps = timestamps() full_options = Map.put(options, :timestamps, timestamps) - {multis, final_runner_to_changes_list} = - Enum.flat_map_reduce(@stages, runner_to_changes_list, fn stage, remaining_runner_to_changes_list -> - stage.multis(remaining_runner_to_changes_list, full_options) + {multis_batches, final_runner_to_changes_list} = + Enum.map_reduce(@stages, runner_to_changes_list, fn stage_batch, remaining_runner_to_changes_list -> + Enum.flat_map_reduce(stage_batch, remaining_runner_to_changes_list, fn stage, inner_remaining_list -> + stage.multis(inner_remaining_list, full_options) + end) end) unless Enum.empty?(final_runner_to_changes_list) do @@ -293,7 +303,7 @@ defmodule Explorer.Chain.Import do "No stages consumed the following runners: #{final_runner_to_changes_list |> Map.keys() |> inspect()}" end - multis + multis_batches end def insert_changes_list(repo, changes_list, options) when is_atom(repo) and is_list(changes_list) do @@ -337,17 +347,21 @@ defmodule Explorer.Chain.Import do reraise exception, __STACKTRACE__ end - defp logged_import(multis, options) when is_list(multis) and is_map(options) do + defp logged_import(multis_batches, options) when is_list(multis_batches) and is_map(options) do import_id = :erlang.unique_integer([:positive]) - Explorer.Logger.metadata(fn -> import_transactions(multis, options) end, import_id: import_id) + Explorer.Logger.metadata(fn -> import_batch_transactions(multis_batches, options) end, import_id: import_id) end - defp import_transactions(multis, options) when is_list(multis) and is_map(options) do - Enum.reduce_while(multis, {:ok, %{}}, fn multi, {:ok, acc_changes} -> - case import_transaction(multi, options) do - {:ok, changes} -> {:cont, {:ok, Map.merge(acc_changes, changes)}} - {:error, _, _, _} = error -> {:halt, error} + defp import_batch_transactions(multis_batches, options) when is_list(multis_batches) and is_map(options) do + Enum.reduce_while(multis_batches, {:ok, %{}}, fn multis, {:ok, acc_changes} -> + multis + |> run_parallel_multis(options) + |> Task.yield_many(:infinity) + |> handle_task_results(acc_changes) + |> case do + {:ok, changes} -> {:cont, {:ok, changes}} + error -> {:halt, error} end end) rescue @@ -358,8 +372,26 @@ defmodule Explorer.Chain.Import do end end + defp run_parallel_multis(multis, options) do + Enum.map(multis, fn multi -> Task.async(fn -> import_transaction(multi, options) end) end) + end + defp import_transaction(multi, options) when is_map(options) do Repo.logged_transaction(multi, timeout: Map.get(options, :timeout, @transaction_timeout)) + rescue + exception -> {:exception, exception, __STACKTRACE__} + end + + defp handle_task_results(task_results, acc_changes) do + Enum.reduce_while(task_results, {:ok, acc_changes}, fn {_task, task_result}, {:ok, acc_changes_inner} -> + case task_result do + {:ok, {:ok, changes}} -> {:cont, {:ok, Map.merge(acc_changes_inner, changes)}} + {:ok, {:exception, exception, stacktrace}} -> reraise exception, stacktrace + {:ok, error} -> {:halt, error} + {:exit, reason} -> {:halt, reason} + nil -> {:halt, :timeout} + end + end) end defp set_refetch_needed_for_partially_imported_blocks(%{blocks: %{params: blocks_params}}) do diff --git a/apps/explorer/lib/explorer/chain/import/runner/tokens.ex b/apps/explorer/lib/explorer/chain/import/runner/tokens.ex index 31a1686c41aa..618f814cc964 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/tokens.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/tokens.ex @@ -2,6 +2,7 @@ defmodule Explorer.Chain.Import.Runner.Tokens do @moduledoc """ Bulk imports `t:Explorer.Chain.Token.t/0`. """ + use Utils.CompileTimeEnvHelper, bridged_tokens_enabled: [:explorer, [Explorer.Chain.BridgedToken, :enabled]] require Ecto.Query @@ -139,7 +140,7 @@ defmodule Explorer.Chain.Import.Runner.Tokens do ) end - if Application.compile_env(:explorer, Explorer.Chain.BridgedToken)[:enabled] do + if @bridged_tokens_enabled do def default_on_conflict do from( token in Token, diff --git a/apps/explorer/lib/explorer/chain/import/runner/transactions.ex b/apps/explorer/lib/explorer/chain/import/runner/transactions.ex index d16e442f176a..74ae42d19d60 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/transactions.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/transactions.ex @@ -2,6 +2,7 @@ defmodule Explorer.Chain.Import.Runner.Transactions do @moduledoc """ Bulk imports `t:Explorer.Chain.Transaction.t/0`. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Ecto.Query @@ -108,7 +109,7 @@ defmodule Explorer.Chain.Import.Runner.Transactions do end # todo: avoid code duplication - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :suave -> defp default_on_conflict do from( diff --git a/apps/explorer/lib/explorer/chain/import/stage/block_following.ex b/apps/explorer/lib/explorer/chain/import/stage/block_following.ex deleted file mode 100644 index 984892673ed9..000000000000 --- a/apps/explorer/lib/explorer/chain/import/stage/block_following.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule Explorer.Chain.Import.Stage.BlockFollowing do - @moduledoc """ - Imports any tables that follows and cannot be imported at the same time as - those imported by `Explorer.Chain.Import.Stage.BlockRelated` and `Explorer.Chain.Import.Stage.BlockReferencing` - """ - - alias Explorer.Chain.Import.{Runner, Stage} - - @behaviour Stage - - @impl Stage - def runners, - do: [ - Runner.Block.SecondDegreeRelations, - Runner.Block.Rewards, - Runner.Address.TokenBalances, - Runner.Address.CurrentTokenBalances - ] - - @impl Stage - def all_runners, - do: runners() - - @impl Stage - def multis(runner_to_changes_list, options) do - {final_multi, final_remaining_runner_to_changes_list} = - Stage.single_multi(runners(), runner_to_changes_list, options) - - {[final_multi], final_remaining_runner_to_changes_list} - end -end diff --git a/apps/explorer/lib/explorer/chain/import/stage/block_pending.ex b/apps/explorer/lib/explorer/chain/import/stage/block_pending.ex deleted file mode 100644 index abcd95e141cd..000000000000 --- a/apps/explorer/lib/explorer/chain/import/stage/block_pending.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule Explorer.Chain.Import.Stage.BlockPending do - @moduledoc """ - Imports any tables that uses `Explorer.Chain.PendingBlockOperation` to track - progress and cannot be imported at the same time as those imported by - `Explorer.Chain.Import.Stage.BlockRelated` and `Explorer.Chain.Import.Stage.BlockReferencing` - """ - - alias Explorer.Chain.Import.{Runner, Stage} - - @behaviour Stage - - @impl Stage - def runners, - do: [ - Runner.InternalTransactions - ] - - @impl Stage - def all_runners, - do: runners() - - @impl Stage - def multis(runner_to_changes_list, options) do - {final_multi, final_remaining_runner_to_changes_list} = - Stage.single_multi(runners(), runner_to_changes_list, options) - - {[final_multi], final_remaining_runner_to_changes_list} - end -end diff --git a/apps/explorer/lib/explorer/chain/import/stage/block_referencing.ex b/apps/explorer/lib/explorer/chain/import/stage/block_referencing.ex deleted file mode 100644 index af647c274c6c..000000000000 --- a/apps/explorer/lib/explorer/chain/import/stage/block_referencing.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Explorer.Chain.Import.Stage.BlockReferencing do - @moduledoc """ - Imports any tables that reference `t:Explorer.Chain.Block.t/0` and that were - imported by `Explorer.Chain.Import.Stage.BlockRelated`. - """ - - alias Explorer.Chain.Import.{Runner, Stage} - - @behaviour Stage - - @impl Stage - def runners do - [ - Runner.Transaction.Forks, - Runner.Logs, - Runner.Tokens, - Runner.TokenInstances, - Runner.TransactionActions, - Runner.Withdrawals, - Runner.SignedAuthorizations - ] - end - - @impl Stage - def all_runners, - do: runners() - - @impl Stage - def multis(runner_to_changes_list, options) do - {final_multi, final_remaining_runner_to_changes_list} = - Stage.single_multi(runners(), runner_to_changes_list, options) - - {[final_multi], final_remaining_runner_to_changes_list} - end -end diff --git a/apps/explorer/lib/explorer/chain/import/stage/block_transaction_referencing.ex b/apps/explorer/lib/explorer/chain/import/stage/block_transaction_referencing.ex new file mode 100644 index 000000000000..91c5a201206e --- /dev/null +++ b/apps/explorer/lib/explorer/chain/import/stage/block_transaction_referencing.ex @@ -0,0 +1,34 @@ +defmodule Explorer.Chain.Import.Stage.BlockTransactionReferencing do + @moduledoc """ + Imports any data that is related to blocks and transactions. + """ + + alias Explorer.Chain.Import.{Runner, Stage} + + @behaviour Stage + + @runners [ + Runner.TokenTransfers, + Runner.Transaction.Forks, + Runner.Logs, + Runner.Block.Rewards, + Runner.Block.SecondDegreeRelations, + Runner.TransactionActions, + Runner.Withdrawals, + Runner.SignedAuthorizations + ] + + @impl Stage + def runners, do: @runners + + @impl Stage + def all_runners, do: runners() + + @impl Stage + def multis(runner_to_changes_list, options) do + {final_multi, final_remaining_runner_to_changes_list} = + Stage.single_multi(runners(), runner_to_changes_list, options) + + {[final_multi], final_remaining_runner_to_changes_list} + end +end diff --git a/apps/explorer/lib/explorer/chain/import/stage/internal_transactions.ex b/apps/explorer/lib/explorer/chain/import/stage/internal_transactions.ex new file mode 100644 index 000000000000..178c6a1b95a3 --- /dev/null +++ b/apps/explorer/lib/explorer/chain/import/stage/internal_transactions.ex @@ -0,0 +1,27 @@ +defmodule Explorer.Chain.Import.Stage.InternalTransactions do + @moduledoc """ + Imports the rest of the data. + """ + + alias Explorer.Chain.Import.{Runner, Stage} + + @behaviour Stage + + @runners [ + Runner.InternalTransactions + ] + + @impl Stage + def runners, do: @runners + + @impl Stage + def all_runners, do: runners() + + @impl Stage + def multis(runner_to_changes_list, options) do + {final_multi, final_remaining_runner_to_changes_list} = + Stage.single_multi(runners(), runner_to_changes_list, options) + + {[final_multi], final_remaining_runner_to_changes_list} + end +end diff --git a/apps/explorer/lib/explorer/chain/import/stage/block_related.ex b/apps/explorer/lib/explorer/chain/import/stage/main.ex similarity index 80% rename from apps/explorer/lib/explorer/chain/import/stage/block_related.ex rename to apps/explorer/lib/explorer/chain/import/stage/main.ex index b18808fb7367..3f3a581691d2 100644 --- a/apps/explorer/lib/explorer/chain/import/stage/block_related.ex +++ b/apps/explorer/lib/explorer/chain/import/stage/main.ex @@ -1,6 +1,6 @@ -defmodule Explorer.Chain.Import.Stage.BlockRelated do +defmodule Explorer.Chain.Import.Stage.Main do @moduledoc """ - Import blocks along with block related entities. + Imports main data (addresses, address_coin_balances, address_coin_balances_daily, tokens, blocks, transactions). """ alias Explorer.Chain.Import.{Runner, Stage} @@ -10,11 +10,11 @@ defmodule Explorer.Chain.Import.Stage.BlockRelated do @addresses_runner Runner.Addresses @rest_runners [ + Runner.Tokens, Runner.Blocks, Runner.Address.CoinBalances, Runner.Address.CoinBalancesDaily, - Runner.Transactions, - Runner.TokenTransfers + Runner.Transactions ] @impl Stage diff --git a/apps/explorer/lib/explorer/chain/import/stage/token_referencing.ex b/apps/explorer/lib/explorer/chain/import/stage/token_referencing.ex new file mode 100644 index 000000000000..22cb8466e827 --- /dev/null +++ b/apps/explorer/lib/explorer/chain/import/stage/token_referencing.ex @@ -0,0 +1,29 @@ +defmodule Explorer.Chain.Import.Stage.TokenReferencing do + @moduledoc """ + Imports any data that is related to tokens. + """ + + alias Explorer.Chain.Import.{Runner, Stage} + + @behaviour Stage + + @runners [ + Runner.TokenInstances, + Runner.Address.TokenBalances, + Runner.Address.CurrentTokenBalances + ] + + @impl Stage + def runners, do: @runners + + @impl Stage + def all_runners, do: runners() + + @impl Stage + def multis(runner_to_changes_list, options) do + {final_multi, final_remaining_runner_to_changes_list} = + Stage.single_multi(runners(), runner_to_changes_list, options) + + {[final_multi], final_remaining_runner_to_changes_list} + end +end diff --git a/apps/explorer/lib/explorer/chain/internal_transaction/call_type.ex b/apps/explorer/lib/explorer/chain/internal_transaction/call_type.ex index 2925fb408b9c..f10acac94448 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction/call_type.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction/call_type.ex @@ -4,9 +4,10 @@ defmodule Explorer.Chain.InternalTransaction.CallType do """ use Ecto.Type + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] @base_call_types ~w(call callcode delegatecall staticcall)a - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do @call_types @base_call_types ++ ~w(invalid)a else @call_types @base_call_types @@ -19,7 +20,7 @@ defmodule Explorer.Chain.InternalTransaction.CallType do the current contract's context with the delegated contract's code. There's some good chances for finding bugs when fuzzing these if the memory layout differs between the current contract and the delegated contract. * `:staticcall` - #{if Application.compile_env(:explorer, :chain_type) == :arbitrum do + #{if @chain_type == :arbitrum do """ * `:invalid` """ @@ -27,7 +28,7 @@ defmodule Explorer.Chain.InternalTransaction.CallType do "" end} """ - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do @type t :: :call | :callcode | :delegatecall | :staticcall | :invalid else @type t :: :call | :callcode | :delegatecall | :staticcall @@ -71,7 +72,7 @@ defmodule Explorer.Chain.InternalTransaction.CallType do def cast(call_type) when call_type in ["call", "callcode", "delegatecall", "staticcall"], do: {:ok, String.to_existing_atom(call_type)} - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do def cast("invalid"), do: {:ok, :invalid} end @@ -123,7 +124,7 @@ defmodule Explorer.Chain.InternalTransaction.CallType do def load(call_type) when call_type in ["call", "callcode", "delegatecall", "staticcall"], do: {:ok, String.to_existing_atom(call_type)} - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do def load("invalid"), do: {:ok, :invalid} end diff --git a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex index a187d174dec3..1b07b5ff7b6b 100644 --- a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex +++ b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex @@ -4,6 +4,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do """ use Ecto.Type + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] @typedoc """ * `:call` @@ -12,7 +13,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do * `:reward` * `:selfdestruct` * `:stop` - #{if Application.compile_env(:explorer, :chain_type) == :arbitrum do + #{if @chain_type == :arbitrum do """ * `:invalid` """ @@ -20,7 +21,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do "" end} """ - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do @type t :: :call | :create | :create2 | :reward | :selfdestruct | :stop | :invalid else @type t :: :call | :create | :create2 | :reward | :selfdestruct | :stop @@ -75,7 +76,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do def cast(type) when type in ["call", "create", "create2", "reward", "selfdestruct", "stop"], do: {:ok, String.to_existing_atom(type)} - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do def cast("invalid"), do: {:ok, :invalid} end @@ -110,7 +111,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do @spec dump(term()) :: {:ok, String.t()} | :error def dump(type) when type in [:call, :create, :create2, :reward, :selfdestruct, :stop], do: {:ok, Atom.to_string(type)} - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do def dump(:invalid), do: {:ok, "invalid"} end @@ -146,7 +147,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do def load(type) when type in ["call", "create", "create2", "reward", "selfdestruct", "stop"], do: {:ok, String.to_existing_atom(type)} - if Application.compile_env(:explorer, :chain_type) == :arbitrum do + if @chain_type == :arbitrum do def load("invalid"), do: {:ok, :invalid} end diff --git a/apps/explorer/lib/explorer/chain/log.ex b/apps/explorer/lib/explorer/chain/log.ex index 92018eb1bf74..3feeea8ae673 100644 --- a/apps/explorer/lib/explorer/chain/log.ex +++ b/apps/explorer/lib/explorer/chain/log.ex @@ -1,5 +1,6 @@ defmodule Explorer.Chain.Log.Schema do @moduledoc false + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.Chain.{ Address, @@ -19,7 +20,7 @@ defmodule Explorer.Chain.Log.Schema do # violates the primary key constraint. To resolve this issue, we've excluded # `transaction_hash` from the composite primary key when dealing with `:celo` # chain type. - @transaction_field (case Application.compile_env(:explorer, :chain_type) do + @transaction_field (case @chain_type do :celo -> quote do [ @@ -79,6 +80,7 @@ defmodule Explorer.Chain.Log do @moduledoc "Captures a Web3 log entry generated by a transaction" use Explorer.Schema + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Explorer.Chain.Log.Schema require Logger @@ -90,7 +92,7 @@ defmodule Explorer.Chain.Log do alias Explorer.SmartContract.SigProviderInterface @required_attrs ~w(address_hash data block_hash index)a - |> (&(case Application.compile_env(:explorer, :chain_type) do + |> (&(case @chain_type do :celo -> &1 @@ -99,7 +101,7 @@ defmodule Explorer.Chain.Log do end)).() @optional_attrs ~w(first_topic second_topic third_topic fourth_topic block_number)a - |> (&(case Application.compile_env(:explorer, :chain_type) do + |> (&(case @chain_type do :celo -> [:transaction_hash | &1] @@ -197,7 +199,7 @@ defmodule Explorer.Chain.Log do defp handle_method_decode_error(error, log, transaction, options, skip_sig_provider?, contracts_acc, events_acc) do case error do {:error, _reason} -> - case find_method_candidates(log, transaction, options, events_acc, skip_sig_provider?) do + case find_method_candidates(log, transaction, options, events_acc) do {{:error, :contract_not_verified, []}, events_acc} -> {decode_event_via_sig_provider(log, transaction, false, skip_sig_provider?), contracts_acc, events_acc} @@ -233,28 +235,33 @@ defmodule Explorer.Chain.Log do end end - defp find_method_candidates(log, transaction, options, events_acc, skip_sig_provider?) do + defp find_method_candidates(log, transaction, options, events_acc) do if is_nil(log.first_topic) do {{:error, :could_not_decode}, events_acc} else <> = log.first_topic.bytes - key = {method_id, log.second_topic, log.third_topic, log.fourth_topic} - if Map.has_key?(events_acc, key) do - {events_acc[key], events_acc} + if Map.has_key?(events_acc, method_id) do + {find_and_decode_in_candidates(events_acc[method_id], log, transaction), events_acc} else - result = find_method_candidates_from_db(method_id, log, transaction, options, skip_sig_provider?) - {result, Map.put(events_acc, key, result)} + {result, event_candidates} = find_method_candidates_from_db(method_id, log, transaction, options) + {result, Map.put(events_acc, method_id, event_candidates)} end end end - defp find_method_candidates_from_db(method_id, log, transaction, options, skip_sig_provider?) do - candidates_query = ContractMethod.find_contract_method_query(method_id, 3) - - candidates = - candidates_query + defp find_method_candidates_from_db(method_id, log, transaction, options) do + event_candidates = + method_id + |> ContractMethod.find_contract_method_query(3) |> Chain.select_repo(options).all() + + {find_and_decode_in_candidates(event_candidates, log, transaction), event_candidates} + end + + defp find_and_decode_in_candidates(event_candidates, log, transaction) do + result = + event_candidates |> Enum.flat_map(fn contract_method -> case find_and_decode([contract_method.abi], log, transaction.hash) do {:ok, selector, mapping} -> @@ -269,15 +276,7 @@ defmodule Explorer.Chain.Log do end) |> Enum.take(1) - {:error, :contract_not_verified, - if(candidates == [], - do: - if(skip_sig_provider?, - do: [], - else: decode_event_via_sig_provider(log, transaction, true) - ), - else: candidates - )} + {:error, :contract_not_verified, result} end @spec find_and_decode([map()], __MODULE__.t(), Hash.t()) :: @@ -351,7 +350,7 @@ defmodule Explorer.Chain.Log do log, transaction, only_candidates?, - skip_sig_provider? \\ false + skip_sig_provider? ) do with true <- SigProviderInterface.enabled?(), false <- skip_sig_provider?, diff --git a/apps/explorer/lib/explorer/chain/metrics/queries.ex b/apps/explorer/lib/explorer/chain/metrics/queries.ex index 496b6ea4d4a0..927f762ce428 100644 --- a/apps/explorer/lib/explorer/chain/metrics/queries.ex +++ b/apps/explorer/lib/explorer/chain/metrics/queries.ex @@ -1,6 +1,6 @@ defmodule Explorer.Chain.Metrics.Queries do @moduledoc """ - Module for DB queries to get chain metrics exposed at /metrics endpoint + Module for DB queries to get chain metrics exposed at /public-metrics endpoint """ import Ecto.Query, diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index 1fc439ee344b..e0c587e8ec31 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -2,6 +2,8 @@ defmodule Explorer.Chain.SmartContract.Schema do @moduledoc """ Models smart-contract. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + alias Explorer.Chain.SmartContract.ExternalLibrary alias Explorer.Chain.{ @@ -11,7 +13,7 @@ defmodule Explorer.Chain.SmartContract.Schema do SmartContractAdditionalSource } - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :zksync -> @chain_type_fields quote( do: [ @@ -104,6 +106,7 @@ defmodule Explorer.Chain.SmartContract do require Explorer.Chain.SmartContract.Schema use Explorer.Schema + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias ABI.FunctionSelector alias Ecto.{Changeset, Multi} @@ -140,7 +143,7 @@ defmodule Explorer.Chain.SmartContract do @optional_changeset_attrs ~w(abi compiler_settings)a @optional_invalid_contract_changeset_attrs ~w(autodetect_constructor_args)a - @chain_type_optional_attrs (case Application.compile_env(:explorer, :chain_type) do + @chain_type_optional_attrs (case @chain_type do :zksync -> ~w(zk_compiler_version)a @@ -397,7 +400,7 @@ defmodule Explorer.Chain.SmartContract do * `name` - the human-readable name of the smart contract. * `compiler_version` - the version of the Solidity compiler used to compile `contract_source_code` with `optimization` into `address` `t:Explorer.Chain.Address.t/0` `contract_code`. - #{case Application.compile_env(:explorer, :chain_type) do + #{case @chain_type do :zksync -> """ * `zk_compiler_version` - the version of ZkSolc or ZkVyper compilers. """ diff --git a/apps/explorer/lib/explorer/chain/smart_contract/proxy.ex b/apps/explorer/lib/explorer/chain/smart_contract/proxy.ex index 8f67e8d8f1cd..0a66653284c9 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract/proxy.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract/proxy.ex @@ -2,6 +2,7 @@ defmodule Explorer.Chain.SmartContract.Proxy do @moduledoc """ Module for proxy smart-contract implementation detection """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias EthereumJSONRPC.Contract alias Explorer.Chain.{Address, Hash, SmartContract} @@ -584,7 +585,7 @@ defmodule Explorer.Chain.SmartContract.Proxy do end) end - if Application.compile_env(:explorer, :chain_type) == :filecoin do + if @chain_type == :filecoin do def chain_type_fields(%{"address" => address_hash} = address, implementations_info) do Map.put(address, "filecoin_robust_address", implementations_info[address_hash]) end diff --git a/apps/explorer/lib/explorer/chain/smart_contract/proxy/models/implementation.ex b/apps/explorer/lib/explorer/chain/smart_contract/proxy/models/implementation.ex index 41e82383b0c6..f84b04ea1b6e 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract/proxy/models/implementation.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract/proxy/models/implementation.ex @@ -6,6 +6,7 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do require Logger use Explorer.Schema + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] import Ecto.Query, only: [ @@ -427,7 +428,7 @@ defmodule Explorer.Chain.SmartContract.Proxy.Models.Implementation do def names(_, _), do: [] - if Application.compile_env(:explorer, :chain_type) == :filecoin do + if @chain_type == :filecoin do @doc """ Fetches associated addresses for Filecoin based on the provided nested IDs. diff --git a/apps/explorer/lib/explorer/chain/token.ex b/apps/explorer/lib/explorer/chain/token.ex index 83f1bd9d306c..c521288187d8 100644 --- a/apps/explorer/lib/explorer/chain/token.ex +++ b/apps/explorer/lib/explorer/chain/token.ex @@ -1,9 +1,10 @@ defmodule Explorer.Chain.Token.Schema do @moduledoc false + use Utils.CompileTimeEnvHelper, bridged_token_enabled: [:explorer, [Explorer.Chain.BridgedToken, :enabled]] alias Explorer.Chain.{Address, Hash} - if Application.compile_env(:explorer, Explorer.Chain.BridgedToken)[:enabled] do + if @bridged_token_enabled do @bridged_field [ quote do field(:bridged, :boolean) diff --git a/apps/explorer/lib/explorer/chain/token/instance.ex b/apps/explorer/lib/explorer/chain/token/instance.ex index ee3422dfff80..4dc9d44aae9c 100644 --- a/apps/explorer/lib/explorer/chain/token/instance.ex +++ b/apps/explorer/lib/explorer/chain/token/instance.ex @@ -20,6 +20,7 @@ defmodule Explorer.Chain.Token.Instance do * `error` - error fetching token instance * `refetch_after` - when to refetch the token instance * `retries_count` - number of times the token instance has been retried + * `is_banned` - if the token instance is banned """ @primary_key false typed_schema "token_instances" do @@ -32,6 +33,7 @@ defmodule Explorer.Chain.Token.Instance do field(:is_unique, :boolean, virtual: true) field(:refetch_after, :utc_datetime_usec) field(:retries_count, :integer) + field(:is_banned, :boolean, default: false) belongs_to(:owner, Address, foreign_key: :owner_address_hash, references: :hash, type: Hash.Address) @@ -59,7 +61,8 @@ defmodule Explorer.Chain.Token.Instance do :owner_updated_at_block, :owner_updated_at_log_index, :refetch_after, - :retries_count + :retries_count, + :is_banned ]) |> validate_required([:token_id, :token_contract_address_hash]) |> foreign_key_constraint(:token_contract_address_hash) @@ -636,4 +639,46 @@ defmodule Explorer.Chain.Token.Instance do timeout: @timeout ) end + + @max_retries_count_value 32767 + @error_to_ban_interval %{ + 9 => [ + "VM execution error", + "request error: 404", + "no uri", + "ignored host", + "(-32000)", + "invalid ", + "{:max_redirect_overflow, ", + "{:invalid_redirection, ", + "nxdomain", + ":nxdomain", + "econnrefused", + ":econnrefused" + ], + # 32767 is the maximum value for retries_count (smallint) + @max_retries_count_value => ["request error: 429"] + } + + @doc """ + Determines the maximum number of retries allowed before banning based on the given error. + + ## Parameters + - error: The error encountered that may trigger retries. + + ## Returns + - An integer representing the maximum number of retries allowed before a ban is enforced. + """ + @spec error_to_max_retries_count_before_ban(String.t() | nil) :: non_neg_integer() + def error_to_max_retries_count_before_ban(nil) do + @max_retries_count_value + end + + def error_to_max_retries_count_before_ban(error) do + Enum.find_value(@error_to_ban_interval, fn {interval, errors} -> + Enum.any?(errors, fn error_pattern -> + String.starts_with?(error, error_pattern) + end) && interval + end) || 13 + end end diff --git a/apps/explorer/lib/explorer/chain/token_transfer.ex b/apps/explorer/lib/explorer/chain/token_transfer.ex index 4d4aae5b98ac..bed36a7ede6a 100644 --- a/apps/explorer/lib/explorer/chain/token_transfer.ex +++ b/apps/explorer/lib/explorer/chain/token_transfer.ex @@ -5,6 +5,7 @@ defmodule Explorer.Chain.TokenTransfer.Schema do Changes in the schema should be reflected in the bulk import module: - Explorer.Chain.Import.Runner.TokenTransfers """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.Chain.{ Address, @@ -17,7 +18,7 @@ defmodule Explorer.Chain.TokenTransfer.Schema do # Remove `transaction_hash` from primary key for `:celo` chain type. See # `Explorer.Chain.Log.Schema` for more details. - @transaction_field (case Application.compile_env(:explorer, :chain_type) do + @transaction_field (case @chain_type do :celo -> quote do [ @@ -132,6 +133,7 @@ defmodule Explorer.Chain.TokenTransfer do """ use Explorer.Schema + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Explorer.Chain.TokenTransfer.Schema @@ -180,7 +182,7 @@ defmodule Explorer.Chain.TokenTransfer do Explorer.Chain.TokenTransfer.Schema.generate() @required_attrs ~w(block_number log_index from_address_hash to_address_hash token_contract_address_hash block_hash token_type)a - |> (&(case Application.compile_env(:explorer, :chain_type) do + |> (&(case @chain_type do :celo -> &1 @@ -188,7 +190,7 @@ defmodule Explorer.Chain.TokenTransfer do [:transaction_hash | &1] end)).() @optional_attrs ~w(amount amounts token_ids block_consensus)a - |> (&(case Application.compile_env(:explorer, :chain_type) do + |> (&(case @chain_type do :celo -> [:transaction_hash | &1] diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex index f9f93952bea6..23f116b5487c 100644 --- a/apps/explorer/lib/explorer/chain/transaction.ex +++ b/apps/explorer/lib/explorer/chain/transaction.ex @@ -5,6 +5,7 @@ defmodule Explorer.Chain.Transaction.Schema do Changes in the schema should be reflected in the bulk import module: - Explorer.Chain.Import.Runner.Transactions """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.Chain @@ -29,7 +30,7 @@ defmodule Explorer.Chain.Transaction.Schema do alias Explorer.Chain.Transaction.{Fork, Status} alias Explorer.Chain.ZkSync.BatchTransaction, as: ZkSyncBatchTransaction - @chain_type_fields (case Application.compile_env(:explorer, :chain_type) do + @chain_type_fields (case @chain_type do :ethereum -> # elem(quote do ... end, 2) doesn't work with a single has_one instruction quote do @@ -298,6 +299,10 @@ defmodule Explorer.Chain.Transaction do use Explorer.Schema + use Utils.CompileTimeEnvHelper, + chain_type: [:explorer, :chain_type], + decode_not_a_contract_calls: [:explorer, :decode_not_a_contract_calls] + require Logger require Explorer.Chain.Transaction.Schema @@ -330,7 +335,7 @@ defmodule Explorer.Chain.Transaction do gas_used index created_contract_code_indexed_at status to_address_hash revert_reason type has_error_in_internal_transactions r s v near_receipt_hash near_transaction_hash)a - @chain_type_optional_attrs (case Application.compile_env(:explorer, :chain_type) do + @chain_type_optional_attrs (case @chain_type do :optimism -> ~w(l1_fee l1_fee_scalar l1_gas_price l1_gas_used l1_transaction_origin l1_block_number)a @@ -812,7 +817,7 @@ defmodule Explorer.Chain.Transaction do end # skip decoding if to_address is not a contract unless DECODE_NOT_A_CONTRACT_CALLS is set - if not Application.compile_env(:explorer, :decode_not_a_contract_calls) do + if not @decode_not_a_contract_calls do def decoded_input_data( %__MODULE__{to_address: %{contract_code: nil}}, _, @@ -1856,7 +1861,7 @@ defmodule Explorer.Chain.Transaction do {:maximum, fee_calc(transaction, gas_price, gas, unit)} end - if Application.compile_env(:explorer, :chain_type) == :optimism do + if @chain_type == :optimism do def fee(%Transaction{gas_price: nil, gas_used: _gas_used}, _unit) do {:actual, nil} end diff --git a/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex b/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex index c8f6599c4c9b..32c956e1cbe4 100644 --- a/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex +++ b/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex @@ -3,6 +3,7 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do Caches Address transactions gas usage counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Ecto.Changeset alias Explorer.Chain.Address.Counters @@ -12,9 +13,6 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do @cache_name :address_transactions_gas_usage_counter @last_update_key "last_update" - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex b/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex index a5a7ea300c9d..cb5a2d2b2317 100644 --- a/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex +++ b/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex @@ -3,6 +3,7 @@ defmodule Explorer.Counters.AddressTokenTransfersCounter do Caches Address token transfers counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Ecto.Changeset alias Explorer.Chain.Address.Counters @@ -12,9 +13,6 @@ defmodule Explorer.Counters.AddressTokenTransfersCounter do @cache_name :address_token_transfers_counter @last_update_key "last_update" - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex b/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex index 0712be9307ec..d34d01277a4c 100644 --- a/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex +++ b/apps/explorer/lib/explorer/counters/address_tokens_usd_sum.ex @@ -3,6 +3,7 @@ defmodule Explorer.Counters.AddressTokenUsdSum do Caches Address tokens USD value. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Explorer.Chain alias Explorer.Counters.Helper @@ -10,9 +11,6 @@ defmodule Explorer.Counters.AddressTokenUsdSum do @cache_name :address_tokens_fiat_value @last_update_key "last_update" - config = Application.compile_env(:explorer, Explorer.Counters.AddressTokenUsdSum) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/address_transactions_counter.ex b/apps/explorer/lib/explorer/counters/address_transactions_counter.ex index 75a7aaea2ea1..f2ffb505bfe8 100644 --- a/apps/explorer/lib/explorer/counters/address_transactions_counter.ex +++ b/apps/explorer/lib/explorer/counters/address_transactions_counter.ex @@ -3,6 +3,7 @@ defmodule Explorer.Counters.AddressTransactionsCounter do Caches Address transactions counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Ecto.Changeset alias Explorer.Chain.Address.Counters @@ -12,9 +13,6 @@ defmodule Explorer.Counters.AddressTransactionsCounter do @cache_name :address_transactions_counter @last_update_key "last_update" - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/addresses_counter.ex b/apps/explorer/lib/explorer/counters/addresses_counter.ex index 51fb845bb945..53633844d75a 100644 --- a/apps/explorer/lib/explorer/counters/addresses_counter.ex +++ b/apps/explorer/lib/explorer/counters/addresses_counter.ex @@ -6,6 +6,14 @@ defmodule Explorer.Counters.AddressesCounter do """ use GenServer + # It is undesirable to automatically start the consolidation in all environments. + # Consider the test environment: if the consolidation initiates but does not + # finish before a test ends, that test will fail. This way, hundreds of + # tests were failing before disabling the consolidation and the scheduler in + # the test env. + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] alias Explorer.Chain.Address.Counters @@ -21,16 +29,6 @@ defmodule Explorer.Counters.AddressesCounter do @cache_key end - # It is undesirable to automatically start the consolidation in all environments. - # Consider the test environment: if the consolidation initiates but does not - # finish before a test ends, that test will fail. This way, hundreds of - # tests were failing before disabling the consolidation and the scheduler in - # the test env. - config = Application.compile_env(:explorer, Explorer.Counters.AddressesCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) - - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) - @doc """ Starts a process to periodically update the counter of the token holders. """ diff --git a/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex b/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex index 53621029afd7..5cb090f70e4d 100644 --- a/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex +++ b/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex @@ -6,6 +6,14 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do """ use GenServer + # It is undesirable to automatically start the consolidation in all environments. + # Consider the test environment: if the consolidation initiates but does not + # finish before a test ends, that test will fail. This way, hundreds of + # tests were failing before disabling the consolidation and the scheduler in + # the test env. + use Utils.CompileTimeEnvHelper, + enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]], + update_interval_in_milliseconds: [:explorer, [__MODULE__, :update_interval_in_milliseconds]] alias Explorer.Chain.Address.Counters @@ -21,16 +29,6 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do @cache_key end - # It is undesirable to automatically start the consolidation in all environments. - # Consider the test environment: if the consolidation initiates but does not - # finish before a test ends, that test will fail. This way, hundreds of - # tests were failing before disabling the consolidation and the scheduler in - # the test env. - config = Application.compile_env(:explorer, Explorer.Counters.AddressesWithBalanceCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) - - @update_interval_in_milliseconds Keyword.get(config, :update_interval_in_milliseconds) - @doc """ Starts a process to periodically update the counter of the token holders. """ diff --git a/apps/explorer/lib/explorer/counters/block_burnt_fee_counter.ex b/apps/explorer/lib/explorer/counters/block_burnt_fee_counter.ex index 64c02d50fc09..ce1ea8cdf344 100644 --- a/apps/explorer/lib/explorer/counters/block_burnt_fee_counter.ex +++ b/apps/explorer/lib/explorer/counters/block_burnt_fee_counter.ex @@ -3,15 +3,13 @@ defmodule Explorer.Counters.BlockBurntFeeCounter do Caches Block Burnt Fee counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Explorer.Chain alias Explorer.Counters.Helper @cache_name :block_burnt_fee_counter - config = Application.compile_env(:explorer, __MODULE__) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex b/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex index 79cd92fb8d3a..0a1c9cdc01a6 100644 --- a/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex +++ b/apps/explorer/lib/explorer/counters/block_priority_fee_counter.ex @@ -3,15 +3,13 @@ defmodule Explorer.Counters.BlockPriorityFeeCounter do Caches Block Priority Fee counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Explorer.Chain alias Explorer.Counters.Helper @cache_name :block_priority_fee_counter - config = Application.compile_env(:explorer, Explorer.Counters.BlockPriorityFeeCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/token_holders_counter.ex b/apps/explorer/lib/explorer/counters/token_holders_counter.ex index e8e12a3aa66c..391c4ad44e35 100644 --- a/apps/explorer/lib/explorer/counters/token_holders_counter.ex +++ b/apps/explorer/lib/explorer/counters/token_holders_counter.ex @@ -3,6 +3,7 @@ defmodule Explorer.Counters.TokenHoldersCounter do Caches Token holders counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Explorer.Chain.Address.CurrentTokenBalance alias Explorer.Chain.Token @@ -12,9 +13,6 @@ defmodule Explorer.Counters.TokenHoldersCounter do @cache_name :token_holders_count @ets_last_update_key "last_update" - config = Application.compile_env(:explorer, Explorer.Counters.TokenHoldersCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/counters/token_transfers_counter.ex b/apps/explorer/lib/explorer/counters/token_transfers_counter.ex index 75fb27e5e72d..d4cf9f91b0b7 100644 --- a/apps/explorer/lib/explorer/counters/token_transfers_counter.ex +++ b/apps/explorer/lib/explorer/counters/token_transfers_counter.ex @@ -3,6 +3,7 @@ defmodule Explorer.Counters.TokenTransfersCounter do Caches Token transfers counter. """ use GenServer + use Utils.CompileTimeEnvHelper, enable_consolidation: [:explorer, [__MODULE__, :enable_consolidation]] alias Explorer.Chain alias Explorer.Counters.Helper @@ -10,9 +11,6 @@ defmodule Explorer.Counters.TokenTransfersCounter do @cache_name :token_transfers_counter @last_update_key "last_update" - config = Application.compile_env(:explorer, Explorer.Counters.TokenTransfersCounter) - @enable_consolidation Keyword.get(config, :enable_consolidation) - @spec start_link(term()) :: GenServer.on_start() def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) diff --git a/apps/explorer/lib/explorer/repo.ex b/apps/explorer/lib/explorer/repo.ex index 7b159e263556..436008ed8ed6 100644 --- a/apps/explorer/lib/explorer/repo.ex +++ b/apps/explorer/lib/explorer/repo.ex @@ -111,9 +111,11 @@ defmodule Explorer.Repo do if Mix.env() == :test do def replica, do: __MODULE__ else - def replica, do: Explorer.Repo.Replica1 + def replica, do: (Application.get_env(:explorer, :replica_inaccessible?) && Explorer.Repo) || replica_repo() end + def replica_repo, do: Explorer.Repo.Replica1 + def account_repo, do: Explorer.Repo.Account defmodule Replica1 do diff --git a/apps/explorer/lib/explorer/utility/replica_accessibility_manager.ex b/apps/explorer/lib/explorer/utility/replica_accessibility_manager.ex new file mode 100644 index 000000000000..a3388db20c04 --- /dev/null +++ b/apps/explorer/lib/explorer/utility/replica_accessibility_manager.ex @@ -0,0 +1,65 @@ +defmodule Explorer.Utility.ReplicaAccessibilityManager do + @moduledoc """ + Module responsible for periodically checking replica accessibility. + """ + + use GenServer + + alias Explorer.Repo + + @interval :timer.seconds(10) + + @spec start_link(term()) :: GenServer.on_start() + def start_link(_) do + GenServer.start_link(__MODULE__, :ok, name: __MODULE__) + end + + def init(_) do + if System.get_env("DATABASE_READ_ONLY_API_URL") do + schedule_next_check(0) + + {:ok, %{}} + else + :ignore + end + end + + def handle_info(:check, state) do + check() + schedule_next_check(@interval) + + {:noreply, state} + end + + defp check do + case Repo.replica_repo().query(query()) do + {:ok, %{rows: [[is_slave, lag]]}} -> + replica_inaccessible? = is_slave and :timer.seconds(lag || 0) > max_lag() + set_replica_inaccessibility(replica_inaccessible?) + + _ -> + set_replica_inaccessibility(true) + end + end + + defp query do + """ + SELECT pg_is_in_recovery(), ( + EXTRACT(EPOCH FROM now()) - + EXTRACT(EPOCH FROM pg_last_xact_replay_timestamp()) + )::int; + """ + end + + defp max_lag do + Application.get_env(:explorer, :replica_max_lag) + end + + defp set_replica_inaccessibility(inaccessible?) do + Application.put_env(:explorer, :replica_inaccessible?, inaccessible?) + end + + defp schedule_next_check(interval) do + Process.send_after(self(), :check, interval) + end +end diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs index f69c2a17bc7f..9a76c73d8e0c 100644 --- a/apps/explorer/mix.exs +++ b/apps/explorer/mix.exs @@ -67,7 +67,6 @@ defmodule Explorer.Mixfile do {:bypass, "~> 2.1", only: :test}, {:briefly, "~> 0.4", github: "CargoSense/briefly"}, {:comeonin, "~> 5.3"}, - {:credo, "~> 1.5", only: :test, runtime: false}, # For Absinthe to load data in batches {:dataloader, "~> 2.0.0"}, {:decimal, "~> 2.0"}, @@ -128,7 +127,8 @@ defmodule Explorer.Mixfile do {:ueberauth_auth0, "~> 2.0"}, {:oauth2, "~> 2.0"}, {:siwe, github: "royal-markets/siwe-ex", ref: "51c9c08240eb7eea3c35693011f8d260cd9bb3be"}, - {:joken, "~> 2.6"} + {:joken, "~> 2.6"}, + {:utils, in_umbrella: true} ] end diff --git a/apps/explorer/priv/repo/migrations/20241002125432_add_is_banned_to_token_instances.exs b/apps/explorer/priv/repo/migrations/20241002125432_add_is_banned_to_token_instances.exs new file mode 100644 index 000000000000..2e67556f2089 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20241002125432_add_is_banned_to_token_instances.exs @@ -0,0 +1,9 @@ +defmodule Explorer.Repo.Migrations.AddIsBannedToTokenInstances do + use Ecto.Migration + + def change do + alter table(:token_instances) do + add(:is_banned, :boolean, default: false, null: true) + end + end +end diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index 3a78abcc6d91..ddbc1d2d8524 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -1,5 +1,6 @@ defmodule Explorer.Factory do use ExMachina.Ecto, repo: Explorer.Repo + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Ecto.Query @@ -63,7 +64,7 @@ defmodule Explorer.Factory do alias Ueberauth.Auth.{Extra, Info} alias Ueberauth.Auth - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do @optimization_runs "1" else @optimization_runs 1 @@ -268,7 +269,7 @@ defmodule Explorer.Factory do |> Map.merge(address_factory_chain_type_fields()) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :zksync -> defp address_factory_chain_type_fields() do %{ @@ -581,7 +582,7 @@ defmodule Explorer.Factory do |> Map.merge(block_factory_chain_type_fields()) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> defp block_factory_chain_type_fields() do %{ @@ -946,7 +947,7 @@ defmodule Explorer.Factory do |> Map.merge(transaction_factory_chain_type_fields()) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :arbitrum -> defp transaction_factory_chain_type_fields() do %{ diff --git a/apps/indexer/lib/indexer/block/catchup/missing_ranges_collector.ex b/apps/indexer/lib/indexer/block/catchup/missing_ranges_collector.ex index ebd10dc41d6b..fc97210c4215 100644 --- a/apps/indexer/lib/indexer/block/catchup/missing_ranges_collector.ex +++ b/apps/indexer/lib/indexer/block/catchup/missing_ranges_collector.ex @@ -4,6 +4,7 @@ defmodule Indexer.Block.Catchup.MissingRangesCollector do """ use GenServer + use Utils.CompileTimeEnvHelper, future_check_interval: [:indexer, [__MODULE__, :future_check_interval]] alias EthereumJSONRPC.Utility.RangesHelper alias Explorer.{Chain, Helper, Repo} @@ -11,7 +12,6 @@ defmodule Indexer.Block.Catchup.MissingRangesCollector do alias Explorer.Utility.{MissingBlockRange, MissingRangesManipulator} @default_missing_ranges_batch_size 100_000 - @future_check_interval Application.compile_env(:indexer, __MODULE__)[:future_check_interval] @past_check_interval 10 @increased_past_check_interval :timer.minutes(1) diff --git a/apps/indexer/lib/indexer/block/fetcher.ex b/apps/indexer/lib/indexer/block/fetcher.ex index 4105e4382520..afc5f4f676fa 100644 --- a/apps/indexer/lib/indexer/block/fetcher.ex +++ b/apps/indexer/lib/indexer/block/fetcher.ex @@ -4,6 +4,7 @@ defmodule Indexer.Block.Fetcher do """ use Spandex.Decorators + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Logger @@ -289,7 +290,7 @@ defmodule Indexer.Block.Fetcher do end end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :ethereum -> defp import_options(basic_import_options, %{transactions_with_receipts: transactions_with_receipts}) do basic_import_options diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex index c0d4650efc39..59fef6de6256 100644 --- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex +++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex @@ -5,6 +5,7 @@ defmodule Indexer.Block.Realtime.Fetcher do use GenServer use Spandex.Decorators + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Indexer.Tracer require Logger @@ -165,7 +166,7 @@ defmodule Indexer.Block.Realtime.Fetcher do Process.cancel_timer(timer) end - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :stability -> defp fetch_validators_async do GenServer.cast(Indexer.Fetcher.Stability.Validator, :update_validators_list) @@ -307,7 +308,7 @@ defmodule Indexer.Block.Realtime.Fetcher do @spec remove_assets_by_number(non_neg_integer()) :: any() - case Application.compile_env(:explorer, :chain_type) do + case @chain_type do :optimism -> # Removes all rows from `op_transaction_batches` and `op_withdrawals` tables # previously written starting from the reorg block number diff --git a/apps/indexer/lib/indexer/fetcher/on_demand/token_instance_metadata_refetch.ex b/apps/indexer/lib/indexer/fetcher/on_demand/token_instance_metadata_refetch.ex index 02792dd625c6..6d1dd42bc8d7 100644 --- a/apps/indexer/lib/indexer/fetcher/on_demand/token_instance_metadata_refetch.ex +++ b/apps/indexer/lib/indexer/fetcher/on_demand/token_instance_metadata_refetch.ex @@ -46,7 +46,7 @@ defmodule Indexer.Fetcher.OnDemand.TokenInstanceMetadataRefetch do end defp fetch_and_broadcast_metadata(token_instance, _state) do - from_base_uri? = Application.get_env(:indexer, __MODULE__)[:base_uri_retry?] + from_base_uri? = Application.get_env(:indexer, TokenInstanceHelper)[:base_uri_retry?] token_id = TokenInstanceHelper.prepare_token_id(token_instance.token_id) contract_address_hash_string = to_string(token_instance.token_contract_address_hash) diff --git a/apps/indexer/lib/indexer/fetcher/optimism.ex b/apps/indexer/lib/indexer/fetcher/optimism.ex index 68834687cdf3..9deaa81fd95e 100644 --- a/apps/indexer/lib/indexer/fetcher/optimism.ex +++ b/apps/indexer/lib/indexer/fetcher/optimism.ex @@ -20,6 +20,7 @@ defmodule Indexer.Fetcher.Optimism do alias EthereumJSONRPC.Block.ByNumber alias EthereumJSONRPC.Contract alias Explorer.Repo + alias Indexer.Fetcher.RollupL1ReorgMonitor alias Indexer.Helper @fetcher_name :optimism @@ -238,8 +239,7 @@ defmodule Indexer.Fetcher.Optimism do optimism_l1_rpc = l1_rpc_url() with {:system_config_valid, true} <- {:system_config_valid, Helper.address_correct?(system_config)}, - {:reorg_monitor_started, true} <- - {:reorg_monitor_started, !is_nil(Process.whereis(Indexer.Fetcher.RollupL1ReorgMonitor))}, + _ <- RollupL1ReorgMonitor.wait_for_start(caller), {:rpc_l1_undefined, false} <- {:rpc_l1_undefined, is_nil(optimism_l1_rpc)}, json_rpc_named_arguments = json_rpc_named_arguments(optimism_l1_rpc), {optimism_portal, start_block_l1} <- read_system_config(system_config, json_rpc_named_arguments), @@ -275,13 +275,6 @@ defmodule Indexer.Fetcher.Optimism do stop: false }} else - {:reorg_monitor_started, false} -> - Logger.error( - "Cannot start this process as reorg monitor in Indexer.Fetcher.RollupL1ReorgMonitor is not started." - ) - - {:stop, :normal, %{}} - {:rpc_l1_undefined, true} -> Logger.error("L1 RPC URL is not defined.") {:stop, :normal, %{}} @@ -353,23 +346,46 @@ defmodule Indexer.Fetcher.Optimism do error_message = &"Cannot call public getters of SystemConfig. Error: #{inspect(&1)}" - case Helper.repeated_call( - &json_rpc/2, - [requests, json_rpc_named_arguments], - error_message, - Helper.finite_retries_number() - ) do - {:ok, responses} -> - "0x000000000000000000000000" <> optimism_portal = Enum.at(responses, 0).result - start_block = quantity_to_integer(Enum.at(responses, 1).result) - {"0x" <> optimism_portal, start_block} + env = Application.get_all_env(:indexer)[__MODULE__] + fallback_start_block = env[:start_block_l1] + + {optimism_portal, start_block} = + case Helper.repeated_call( + &json_rpc/2, + [requests, json_rpc_named_arguments], + error_message, + Helper.finite_retries_number() + ) do + {:ok, responses} -> + optimism_portal_result = Map.get(Enum.at(responses, 0), :result) + + optimism_portal = + with {:nil_result, true, _} <- {:nil_result, is_nil(optimism_portal_result), optimism_portal_result}, + {:fallback_defined, true} <- {:fallback_defined, Helper.address_correct?(env[:portal])} do + env[:portal] + else + {:nil_result, false, portal} -> + "0x000000000000000000000000" <> optimism_portal = portal + "0x" <> optimism_portal + + {:fallback_defined, false} -> + nil + end + + start_block = + responses + |> Enum.at(1) + |> Map.get(:result, fallback_start_block) + |> quantity_to_integer() + + {optimism_portal, start_block} - _ -> - env = Application.get_all_env(:indexer)[__MODULE__] + _ -> + {env[:portal], fallback_start_block} + end - if Helper.address_correct?(env[:portal]) and not is_nil(env[:start_block_l1]) do - {env[:portal], env[:start_block_l1]} - end + if Helper.address_correct?(optimism_portal) and !is_nil(start_block) do + {String.downcase(optimism_portal), start_block} end end diff --git a/apps/indexer/lib/indexer/fetcher/optimism/transaction_batch.ex b/apps/indexer/lib/indexer/fetcher/optimism/transaction_batch.ex index aa0623e05997..a8daf641a109 100644 --- a/apps/indexer/lib/indexer/fetcher/optimism/transaction_batch.ex +++ b/apps/indexer/lib/indexer/fetcher/optimism/transaction_batch.ex @@ -102,8 +102,7 @@ defmodule Indexer.Fetcher.Optimism.TransactionBatch do {:system_config_valid, Helper.address_correct?(system_config)}, {:genesis_block_l2_invalid, false} <- {:genesis_block_l2_invalid, is_nil(env[:genesis_block_l2]) or env[:genesis_block_l2] < 0}, - {:reorg_monitor_started, true} <- - {:reorg_monitor_started, !is_nil(Process.whereis(RollupL1ReorgMonitor))}, + _ <- RollupL1ReorgMonitor.wait_for_start(__MODULE__), {:rpc_l1_undefined, false} <- {:rpc_l1_undefined, is_nil(optimism_l1_rpc)}, json_rpc_named_arguments = Optimism.json_rpc_named_arguments(optimism_l1_rpc), {:system_config_read, {start_block_l1, batch_inbox, batch_submitter}} <- @@ -160,13 +159,6 @@ defmodule Indexer.Fetcher.Optimism.TransactionBatch do Logger.error("L2 genesis block number is undefined or invalid.") {:stop, :normal, state} - {:reorg_monitor_started, false} -> - Logger.error( - "Cannot start this process as reorg monitor in Indexer.Fetcher.RollupL1ReorgMonitor is not started." - ) - - {:stop, :normal, state} - {:rpc_l1_undefined, true} -> Logger.error("L1 RPC URL is not defined.") {:stop, :normal, state} @@ -1447,25 +1439,51 @@ defmodule Indexer.Fetcher.Optimism.TransactionBatch do error_message = &"Cannot call public getters of SystemConfig. Error: #{inspect(&1)}" - case Helper.repeated_call( - &json_rpc/2, - [requests, json_rpc_named_arguments], - error_message, - Helper.finite_retries_number() - ) do - {:ok, responses} -> - start_block = quantity_to_integer(Enum.at(responses, 0).result) - "0x000000000000000000000000" <> batch_inbox = Enum.at(responses, 1).result - "0x000000000000000000000000" <> batch_submitter = Enum.at(responses, 2).result - {start_block, String.downcase("0x" <> batch_inbox), String.downcase("0x" <> batch_submitter)} + env = Application.get_all_env(:indexer)[__MODULE__] + fallback_start_block = Application.get_all_env(:indexer)[Indexer.Fetcher.Optimism][:start_block_l1] + + {start_block, batch_inbox, batch_submitter} = + case Helper.repeated_call( + &json_rpc/2, + [requests, json_rpc_named_arguments], + error_message, + Helper.finite_retries_number() + ) do + {:ok, responses} -> + start_block = + responses + |> Enum.at(0) + |> Map.get(:result, fallback_start_block) + |> quantity_to_integer() + + inbox_result = Map.get(Enum.at(responses, 1), :result) + submitter_result = Map.get(Enum.at(responses, 2), :result) + + {batch_inbox, batch_submitter} = + with {:nil_result, true, _, _} <- + {:nil_result, is_nil(inbox_result) or is_nil(submitter_result), inbox_result, submitter_result}, + {:fallback_defined, true} <- + {:fallback_defined, + Helper.address_correct?(env[:inbox]) and Helper.address_correct?(env[:submitter])} do + {env[:inbox], env[:submitter]} + else + {:nil_result, false, inbox, submitter} -> + "0x000000000000000000000000" <> batch_inbox = inbox + "0x000000000000000000000000" <> batch_submitter = submitter + {"0x" <> batch_inbox, "0x" <> batch_submitter} + + {:fallback_defined, false} -> + {nil, nil} + end - _ -> - start_block = Application.get_all_env(:indexer)[Indexer.Fetcher.Optimism][:start_block_l1] - env = Application.get_all_env(:indexer)[__MODULE__] + {start_block, batch_inbox, batch_submitter} - if not is_nil(start_block) and Helper.address_correct?(env[:inbox]) and Helper.address_correct?(env[:submitter]) do - {start_block, String.downcase(env[:inbox]), String.downcase(env[:submitter])} - end + _ -> + {fallback_start_block, env[:inbox], env[:submitter]} + end + + if !is_nil(start_block) and Helper.address_correct?(batch_inbox) and Helper.address_correct?(batch_submitter) do + {start_block, String.downcase(batch_inbox), String.downcase(batch_submitter)} end end diff --git a/apps/indexer/lib/indexer/fetcher/polygon_zkevm/bridge_l1.ex b/apps/indexer/lib/indexer/fetcher/polygon_zkevm/bridge_l1.ex index 6d086d5d4446..1e45795d35ff 100644 --- a/apps/indexer/lib/indexer/fetcher/polygon_zkevm/bridge_l1.ex +++ b/apps/indexer/lib/indexer/fetcher/polygon_zkevm/bridge_l1.ex @@ -57,7 +57,7 @@ defmodule Indexer.Fetcher.PolygonZkevm.BridgeL1 do env_l2 = Application.get_all_env(:indexer)[Indexer.Fetcher.PolygonZkevm.BridgeL2] with {:start_block_undefined, false} <- {:start_block_undefined, is_nil(env[:start_block])}, - {:reorg_monitor_started, true} <- {:reorg_monitor_started, !is_nil(Process.whereis(RollupL1ReorgMonitor))}, + _ <- RollupL1ReorgMonitor.wait_for_start(__MODULE__), rpc = env[:rpc], {:rpc_undefined, false} <- {:rpc_undefined, is_nil(rpc)}, {:rollup_network_id_l1_is_valid, true} <- @@ -101,10 +101,6 @@ defmodule Indexer.Fetcher.PolygonZkevm.BridgeL1 do # the process shouldn't start if the start block is not defined {:stop, :normal, %{}} - {:reorg_monitor_started, false} -> - Logger.error("Cannot start this process as Indexer.Fetcher.RollupL1ReorgMonitor is not started.") - {:stop, :normal, %{}} - {:rpc_undefined, true} -> Logger.error("L1 RPC URL is not defined.") {:stop, :normal, %{}} diff --git a/apps/indexer/lib/indexer/fetcher/rollup_l1_reorg_monitor.ex b/apps/indexer/lib/indexer/fetcher/rollup_l1_reorg_monitor.ex index b2f9541b2b5d..772440833db9 100644 --- a/apps/indexer/lib/indexer/fetcher/rollup_l1_reorg_monitor.ex +++ b/apps/indexer/lib/indexer/fetcher/rollup_l1_reorg_monitor.ex @@ -9,6 +9,7 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do use GenServer use Indexer.Fetcher + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Logger @@ -16,8 +17,9 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do alias Indexer.Helper @fetcher_name :rollup_l1_reorg_monitor + @start_recheck_period_seconds 3 - @modules_can_use_reorg_monitor (case Application.compile_env(:explorer, :chain_type) do + @modules_can_use_reorg_monitor (case @chain_type do :optimism -> [ Indexer.Fetcher.Optimism.Deposit, @@ -67,6 +69,11 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do GenServer.start_link(__MODULE__, args, Keyword.put_new(gen_server_options, :name, __MODULE__)) end + @impl GenServer + def init(_args) do + {:ok, %{}, {:continue, :ok}} + end + @doc """ This function initializes L1 blocks reorg monitor for the current rollup defined by CHAIN_TYPE. If the current chain is not a rollup, the module just doesn't start. @@ -84,10 +91,10 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do ## Returns - `{:ok, state}` with the determined parameters for the monitor loop if at least one rollup module is launched. - - `:ignore` if the monitor is not needed. + - `{:stop, :normal, %{}}` if the monitor is not needed. """ @impl GenServer - def init(_args) do + def handle_continue(:ok, _state) do Logger.metadata(fetcher: @fetcher_name) modules_using_reorg_monitor = @@ -96,7 +103,7 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do if Enum.empty?(modules_using_reorg_monitor) do # don't start reorg monitor as there is no module which would use it - :ignore + {:stop, :normal, %{}} else l1_rpc = Enum.at(modules_using_reorg_monitor, 0).l1_rpc_url() @@ -106,7 +113,7 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do Process.send(self(), :reorg_monitor, []) - {:ok, + {:noreply, %{ block_check_interval: block_check_interval, json_rpc_named_arguments: json_rpc_named_arguments, @@ -155,4 +162,34 @@ defmodule Indexer.Fetcher.RollupL1ReorgMonitor do {:noreply, %{state | prev_latest: latest}} end + + @doc """ + Infinitely waits for the module to be initialized and started. + + ## Parameters + - `waiting_module`: The module which called this function. + + ## Returns + - nothing + """ + @spec wait_for_start(module()) :: any() + def wait_for_start(waiting_module) do + state = + try do + __MODULE__ + |> Process.whereis() + |> :sys.get_state() + catch + :exit, _ -> %{} + end + + if map_size(state) == 0 do + Logger.warning( + "#{waiting_module} waits for #{__MODULE__} to start. Rechecking in #{@start_recheck_period_seconds} second(s)..." + ) + + :timer.sleep(@start_recheck_period_seconds * 1_000) + wait_for_start(waiting_module) + end + end end diff --git a/apps/indexer/lib/indexer/fetcher/scroll/batch.ex b/apps/indexer/lib/indexer/fetcher/scroll/batch.ex index 10e0c3a32d97..cf356b1c2309 100644 --- a/apps/indexer/lib/indexer/fetcher/scroll/batch.ex +++ b/apps/indexer/lib/indexer/fetcher/scroll/batch.ex @@ -78,7 +78,7 @@ defmodule Indexer.Fetcher.Scroll.Batch do env = Application.get_all_env(:indexer)[__MODULE__] with {:start_block_undefined, false} <- {:start_block_undefined, is_nil(env[:start_block])}, - {:reorg_monitor_started, true} <- {:reorg_monitor_started, !is_nil(Process.whereis(RollupL1ReorgMonitor))}, + _ <- RollupL1ReorgMonitor.wait_for_start(__MODULE__), rpc = l1_rpc_url(), {:rpc_undefined, false} <- {:rpc_undefined, is_nil(rpc)}, {:scroll_chain_contract_address_is_valid, true} <- @@ -114,10 +114,6 @@ defmodule Indexer.Fetcher.Scroll.Batch do # the process shouldn't start if the start block is not defined {:stop, :normal, %{}} - {:reorg_monitor_started, false} -> - Logger.error("Cannot start this process as Indexer.Fetcher.RollupL1ReorgMonitor is not started.") - {:stop, :normal, %{}} - {:rpc_undefined, true} -> Logger.error("L1 RPC URL is not defined.") {:stop, :normal, %{}} diff --git a/apps/indexer/lib/indexer/fetcher/scroll/bridge_l1.ex b/apps/indexer/lib/indexer/fetcher/scroll/bridge_l1.ex index be75a223b973..408cc72b8464 100644 --- a/apps/indexer/lib/indexer/fetcher/scroll/bridge_l1.ex +++ b/apps/indexer/lib/indexer/fetcher/scroll/bridge_l1.ex @@ -69,7 +69,7 @@ defmodule Indexer.Fetcher.Scroll.BridgeL1 do env = Application.get_all_env(:indexer)[__MODULE__] with {:start_block_undefined, false} <- {:start_block_undefined, is_nil(env[:start_block])}, - {:reorg_monitor_started, true} <- {:reorg_monitor_started, !is_nil(Process.whereis(RollupL1ReorgMonitor))}, + _ <- RollupL1ReorgMonitor.wait_for_start(__MODULE__), rpc = l1_rpc_url(), {:rpc_undefined, false} <- {:rpc_undefined, is_nil(rpc)}, {:messenger_contract_address_is_valid, true} <- @@ -104,10 +104,6 @@ defmodule Indexer.Fetcher.Scroll.BridgeL1 do # the process shouldn't start if the start block is not defined {:stop, :normal, %{}} - {:reorg_monitor_started, false} -> - Logger.error("Cannot start this process as Indexer.Fetcher.RollupL1ReorgMonitor is not started.") - {:stop, :normal, %{}} - {:rpc_undefined, true} -> Logger.error("L1 RPC URL is not defined.") {:stop, :normal, %{}} diff --git a/apps/indexer/lib/indexer/fetcher/shibarium/l1.ex b/apps/indexer/lib/indexer/fetcher/shibarium/l1.ex index 95151b9e2d03..99b7d7343d0e 100644 --- a/apps/indexer/lib/indexer/fetcher/shibarium/l1.ex +++ b/apps/indexer/lib/indexer/fetcher/shibarium/l1.ex @@ -112,7 +112,7 @@ defmodule Indexer.Fetcher.Shibarium.L1 do env = Application.get_all_env(:indexer)[__MODULE__] with {:start_block_undefined, false} <- {:start_block_undefined, is_nil(env[:start_block])}, - {:reorg_monitor_started, true} <- {:reorg_monitor_started, !is_nil(Process.whereis(RollupL1ReorgMonitor))}, + _ <- RollupL1ReorgMonitor.wait_for_start(__MODULE__), rpc = env[:rpc], {:rpc_undefined, false} <- {:rpc_undefined, is_nil(rpc)}, {:deposit_manager_address_is_valid, true} <- @@ -164,10 +164,6 @@ defmodule Indexer.Fetcher.Shibarium.L1 do # the process shouldn't start if the start block is not defined {:stop, :normal, %{}} - {:reorg_monitor_started, false} -> - Logger.error("Cannot start this process as Indexer.Fetcher.RollupL1ReorgMonitor is not started.") - {:stop, :normal, %{}} - {:rpc_undefined, true} -> Logger.error("L1 RPC URL is not defined.") {:stop, :normal, %{}} diff --git a/apps/indexer/lib/indexer/fetcher/token_balance.ex b/apps/indexer/lib/indexer/fetcher/token_balance.ex index 5bfd3deaffaa..8b2692707892 100644 --- a/apps/indexer/lib/indexer/fetcher/token_balance.ex +++ b/apps/indexer/lib/indexer/fetcher/token_balance.ex @@ -259,14 +259,15 @@ defmodule Indexer.Fetcher.TokenBalance do end end - defp entry(%{ - token_contract_address_hash: token_contract_address_hash, - address_hash: address_hash, - block_number: block_number, - token_type: token_type, - token_id: token_id, - retries_count: retries_count - }) do + defp entry( + %{ + token_contract_address_hash: token_contract_address_hash, + address_hash: address_hash, + block_number: block_number, + token_type: token_type, + token_id: token_id + } = params + ) do token_id_int = case token_id do %Decimal{} -> Decimal.to_integer(token_id) @@ -274,7 +275,14 @@ defmodule Indexer.Fetcher.TokenBalance do _ -> token_id end - {address_hash.bytes, token_contract_address_hash.bytes, block_number, token_type, token_id_int, retries_count || 0} + { + address_hash.bytes, + token_contract_address_hash.bytes, + block_number, + token_type, + token_id_int, + Map.get(params, :retries_count) || 0 + } end defp format_params( diff --git a/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex b/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex index 0987055f3328..cb6a9b4bc3dc 100644 --- a/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex +++ b/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex @@ -252,11 +252,12 @@ defmodule Indexer.Fetcher.TokenInstance.Helper do end end - def normalize_token_id("ERC-721", _token_id), do: nil - - def normalize_token_id(_token_type, token_id), + @spec normalize_token_id(binary(), integer()) :: nil | binary() + defp normalize_token_id("ERC-1155", token_id), do: token_id |> Integer.to_string(16) |> String.downcase() |> String.pad_leading(64, "0") + defp normalize_token_id(_token_type, _token_id), do: nil + defp result_to_insert_params({:ok, %{metadata: metadata}}, token_contract_address_hash, token_id) do %{ token_id: token_id, diff --git a/apps/indexer/lib/indexer/prometheus/collector/filecoin_pending_address_operations_collector.ex b/apps/indexer/lib/indexer/prometheus/collector/filecoin_pending_address_operations_collector.ex index 207990ca456b..b21677173168 100644 --- a/apps/indexer/lib/indexer/prometheus/collector/filecoin_pending_address_operations_collector.ex +++ b/apps/indexer/lib/indexer/prometheus/collector/filecoin_pending_address_operations_collector.ex @@ -1,14 +1,16 @@ -if Application.compile_env(:explorer, :chain_type) == :filecoin do - defmodule Indexer.Prometheus.Collector.FilecoinPendingAddressOperations do - @moduledoc """ - Custom collector to count number of records in filecoin_pending_address_operations table. - """ +defmodule Indexer.Prometheus.Collector.FilecoinPendingAddressOperations do + @moduledoc """ + Custom collector to count number of records in filecoin_pending_address_operations table. + """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] + if @chain_type == :filecoin do use Prometheus.Collector - alias Explorer.Chain.Filecoin.PendingAddressOperation - alias Explorer.Repo - alias Prometheus.Model + # TODO: remove when https://github.com/elixir-lang/elixir/issues/13975 comes to elixir release + alias Explorer.Chain.Filecoin.PendingAddressOperation, warn: false + alias Explorer.Repo, warn: false + alias Prometheus.Model, warn: false def collect_mf(_registry, callback) do callback.( diff --git a/apps/indexer/lib/indexer/transform/address_coin_balances.ex b/apps/indexer/lib/indexer/transform/address_coin_balances.ex index 84d692c5caeb..14882d5682d0 100644 --- a/apps/indexer/lib/indexer/transform/address_coin_balances.ex +++ b/apps/indexer/lib/indexer/transform/address_coin_balances.ex @@ -2,6 +2,7 @@ defmodule Indexer.Transform.AddressCoinBalances do @moduledoc """ Extracts `Explorer.Chain.Address.CoinBalance` params from other schema's params. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Explorer.Chain.TokenTransfer @@ -114,7 +115,7 @@ defmodule Indexer.Transform.AddressCoinBalances do |> (&transactions_params_chain_type_fields_reducer(transaction_params, &1)).() end - if Application.compile_env(:explorer, :chain_type) == :celo do + if @chain_type == :celo do import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0] @burn_address_hash_string burn_address_hash_string() diff --git a/apps/indexer/lib/indexer/transform/addresses.ex b/apps/indexer/lib/indexer/transform/addresses.ex index 59a9e0b8376a..ca4e4939ebff 100644 --- a/apps/indexer/lib/indexer/transform/addresses.ex +++ b/apps/indexer/lib/indexer/transform/addresses.ex @@ -47,6 +47,7 @@ defmodule Indexer.Transform.Addresses do ] } """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] alias Indexer.Helper @@ -73,7 +74,7 @@ defmodule Indexer.Transform.Addresses do %{from: :block_number, to: :fetched_coin_balance_block_number}, %{from: :to_address_hash, to: :hash} ], - if Application.compile_env(:explorer, :chain_type) == :zksync do + if @chain_type == :zksync do [ %{from: :block_number, to: :fetched_coin_balance_block_number}, %{from: :created_contract_address_hash, to: :hash} diff --git a/apps/indexer/lib/indexer/transform/scroll/l1_fee_params.ex b/apps/indexer/lib/indexer/transform/scroll/l1_fee_params.ex index 12875255817c..4615266a7519 100644 --- a/apps/indexer/lib/indexer/transform/scroll/l1_fee_params.ex +++ b/apps/indexer/lib/indexer/transform/scroll/l1_fee_params.ex @@ -3,6 +3,7 @@ defmodule Indexer.Transform.Scroll.L1FeeParams do Helper functions for transforming data for Scroll L1 fee parameters in realtime block fetcher. """ + use Utils.CompileTimeEnvHelper, chain_type: [:explorer, :chain_type] require Logger @@ -22,7 +23,7 @@ defmodule Indexer.Transform.Scroll.L1FeeParams do @spec parse([map()]) :: [Explorer.Chain.Scroll.L1FeeParam.to_import()] def parse(logs) - if Application.compile_env(:explorer, :chain_type) == :scroll do + if @chain_type == :scroll do def parse(logs) do prev_metadata = Logger.metadata() Logger.metadata(fetcher: :scroll_l1_fee_params_realtime) diff --git a/apps/indexer/mix.exs b/apps/indexer/mix.exs index c84d313fc024..17331a8bbdb8 100644 --- a/apps/indexer/mix.exs +++ b/apps/indexer/mix.exs @@ -70,7 +70,8 @@ defmodule Indexer.MixProject do # `:spandex` integration with Datadog {:spandex_datadog, "~> 1.0"}, {:logger_json, "~> 5.1"}, - {:varint, "~> 1.4"} + {:varint, "~> 1.4"}, + {:utils, in_umbrella: true} ] end diff --git a/apps/indexer/test/indexer/block/fetcher_test.exs b/apps/indexer/test/indexer/block/fetcher_test.exs index 023affce464a..6963eff33064 100644 --- a/apps/indexer/test/indexer/block/fetcher_test.exs +++ b/apps/indexer/test/indexer/block/fetcher_test.exs @@ -952,7 +952,7 @@ defmodule Indexer.Block.FetcherTest do end) # async requests need to be grouped in one expect because the order is non-deterministic while multiple expect # calls on the same name/arity are used in order - |> expect(:json_rpc, 10, fn json, _options -> + |> expect(:json_rpc, 5, fn json, _options -> case json do [ %{ @@ -1148,7 +1148,13 @@ defmodule Indexer.Block.FetcherTest do errors: [] }} = Fetcher.fetch_and_import_range(block_fetcher, block_number..block_number) - wait_for_tasks(InternalTransaction) + configuration = Application.get_env(:indexer, Indexer.Fetcher.InternalTransaction.Supervisor) + Application.put_env(:indexer, Indexer.Fetcher.InternalTransaction.Supervisor, disabled?: false) + + on_exit(fn -> + Application.put_env(:indexer, Indexer.Fetcher.InternalTransaction.Supervisor, configuration) + end) + wait_for_tasks(CoinBalanceCatchup) assert Repo.aggregate(Chain.Block, :count, :hash) == 1 diff --git a/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs b/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs index 03e6f27c1f2f..d30b3753eea7 100644 --- a/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs +++ b/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs @@ -407,6 +407,7 @@ defmodule Indexer.Fetcher.TokenInstance.HelperTest do assert instance.retries_count == 0 assert DateTime.diff(refetch_after, instance.refetch_after) < 1 assert !is_nil(instance.error) + assert not instance.is_banned end test "proper updates retries count and refetch after on retry" do @@ -438,6 +439,7 @@ defmodule Indexer.Fetcher.TokenInstance.HelperTest do assert instance.retries_count == 1 assert DateTime.diff(refetch_after, instance.refetch_after) < 1 assert !is_nil(instance.error) + assert not instance.is_banned end test "success insert after retry" do @@ -468,6 +470,7 @@ defmodule Indexer.Fetcher.TokenInstance.HelperTest do assert instance.retries_count == 1 assert DateTime.diff(refetch_after, instance.refetch_after) < 1 assert !is_nil(instance.error) + assert not instance.is_banned token_address = to_string(erc_721_token.contract_address_hash) @@ -511,6 +514,7 @@ defmodule Indexer.Fetcher.TokenInstance.HelperTest do assert instance.retries_count == 2 assert is_nil(instance.refetch_after) assert is_nil(instance.error) + assert not instance.is_banned assert instance.metadata == %{ "name" => "OMNI404 #300067000000000000", @@ -522,12 +526,29 @@ defmodule Indexer.Fetcher.TokenInstance.HelperTest do end test "Don't fail on high retries count" do - config = Application.get_env(:indexer, Indexer.Fetcher.TokenInstance.Retry) + erc_721_token = insert(:token, type: "ERC-721") - coef = config[:exp_timeout_coeff] - base = config[:exp_timeout_base] - max_refetch_interval = config[:max_refetch_interval] + token_instance = + insert(:token_instance, + token_contract_address_hash: erc_721_token.contract_address_hash, + error: "error", + metadata: nil, + retries_count: 50 + ) + + Helper.batch_fetch_instances([ + %{contract_address_hash: token_instance.token_contract_address_hash, token_id: token_instance.token_id} + ]) + + [instance] = Repo.all(Instance) + + assert instance.retries_count == 51 + assert is_nil(instance.refetch_after) + assert !is_nil(instance.error) + assert instance.is_banned + end + test "set is_banned (VM execution error) if retries_count > 9" do erc_721_token = insert(:token, type: "ERC-721") token_instance = @@ -535,21 +556,185 @@ defmodule Indexer.Fetcher.TokenInstance.HelperTest do token_contract_address_hash: erc_721_token.contract_address_hash, error: "error", metadata: nil, - retries_count: 50 + retries_count: 9 ) + token_address = to_string(erc_721_token.contract_address_hash) + + data = + "0xc87b56dd" <> + (ABI.TypeEncoder.encode([Decimal.to_integer(token_instance.token_id)], [{:uint, 256}]) + |> Base.encode16(case: :lower)) + + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn [ + %{ + id: id, + jsonrpc: "2.0", + method: "eth_call", + params: [ + %{ + data: ^data, + to: ^token_address + }, + "latest" + ] + } + ], + _options -> + {:ok, + [ + %{ + error: %{code: -32015, data: "Reverted 0x", message: "execution reverted"}, + id: id, + jsonrpc: "2.0" + } + ]} + end) + Helper.batch_fetch_instances([ %{contract_address_hash: token_instance.token_contract_address_hash, token_id: token_instance.token_id} ]) - now = DateTime.utc_now() - refetch_after = DateTime.add(now, max_refetch_interval, :millisecond) + [instance] = Repo.all(Instance) + assert instance.error == "VM execution error" + assert instance.is_banned + end + + test "don't set is_banned (VM execution error) if retries_count < 9" do + erc_721_token = insert(:token, type: "ERC-721") + + token_instance = + insert(:token_instance, + token_contract_address_hash: erc_721_token.contract_address_hash, + error: "error", + metadata: nil, + retries_count: 8 + ) + + token_address = to_string(erc_721_token.contract_address_hash) + + data = + "0xc87b56dd" <> + (ABI.TypeEncoder.encode([Decimal.to_integer(token_instance.token_id)], [{:uint, 256}]) + |> Base.encode16(case: :lower)) + + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn [ + %{ + id: id, + jsonrpc: "2.0", + method: "eth_call", + params: [ + %{ + data: ^data, + to: ^token_address + }, + "latest" + ] + } + ], + _options -> + {:ok, + [ + %{ + error: %{code: -32015, data: "Reverted 0x", message: "execution reverted"}, + id: id, + jsonrpc: "2.0" + } + ]} + end) + + Helper.batch_fetch_instances([ + %{contract_address_hash: token_instance.token_contract_address_hash, token_id: token_instance.token_id} + ]) [instance] = Repo.all(Instance) + assert instance.error =~ "VM execution error" + assert not instance.is_banned + end - assert instance.retries_count == 51 + test "don't set is_banned (429 error)", %{bypass: bypass} do + erc_721_token = insert(:token, type: "ERC-721") + + token_instance = + insert(:token_instance, + token_contract_address_hash: erc_721_token.contract_address_hash, + error: "error", + metadata: nil, + retries_count: 1000 + ) + + token_address = to_string(erc_721_token.contract_address_hash) + + data = + "0xc87b56dd" <> + (ABI.TypeEncoder.encode([Decimal.to_integer(token_instance.token_id)], [{:uint, 256}]) + |> Base.encode16(case: :lower)) + + encoded_url = + "0x" <> + (ABI.TypeEncoder.encode(["http://localhost:#{bypass.port}/api/card"], %ABI.FunctionSelector{ + function: nil, + types: [ + :string + ] + }) + |> Base.encode16(case: :lower)) + + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn [ + %{ + id: 0, + jsonrpc: "2.0", + method: "eth_call", + params: [ + %{ + data: ^data, + to: ^token_address + }, + "latest" + ] + } + ], + _options -> + {:ok, + [ + %{ + id: 0, + jsonrpc: "2.0", + result: encoded_url + } + ]} + end) + + Bypass.expect( + bypass, + "GET", + "/api/card", + fn conn -> + Conn.resp(conn, 429, "429 Too many requests") + end + ) + + Helper.batch_fetch_instances([ + %{contract_address_hash: token_instance.token_contract_address_hash, token_id: token_instance.token_id} + ]) + + now = DateTime.utc_now() + + refetch_after = + DateTime.add( + now, + Application.get_env(:indexer, Indexer.Fetcher.TokenInstance.Retry)[:max_refetch_interval], + :millisecond + ) + + [instance] = Repo.all(Instance) assert DateTime.diff(refetch_after, instance.refetch_after) < 1 - assert !is_nil(instance.error) + assert instance.error =~ "request error: 429" + assert instance.retries_count == 1001 + assert not instance.is_banned end end end diff --git a/apps/utils/.gitignore b/apps/utils/.gitignore new file mode 100644 index 000000000000..7f38206dd8d0 --- /dev/null +++ b/apps/utils/.gitignore @@ -0,0 +1,26 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +utils-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/apps/utils/lib/credo/checks/compile_env_usage.ex b/apps/utils/lib/credo/checks/compile_env_usage.ex new file mode 100644 index 000000000000..b17505011edc --- /dev/null +++ b/apps/utils/lib/credo/checks/compile_env_usage.ex @@ -0,0 +1,54 @@ +defmodule Utils.Credo.Checks.CompileEnvUsage do + @moduledoc """ + Disallows usage of Application.compile_env throughout the codebase, + except in Utils.CompileTimeEnvHelper module. + + Application.compile_env should generally be avoided as it makes the code + harder to test and configure dynamically. + """ + + @explanation [ + check: @moduledoc, + params: [] + ] + + use Credo.Check, base_priority: :high, category: :warning + + alias Credo.Code + + @doc false + @impl true + def run(%SourceFile{} = source_file, params \\ []) do + issue_meta = IssueMeta.for(source_file, params) + + # Skip check for Utils.CompileTimeEnvHelper module + if String.ends_with?(source_file.filename, "utils/compile_time_env_helper.ex") do + [] + else + Code.prewalk(source_file, &traverse(&1, &2, issue_meta)) + end + end + + defp traverse({:., _, [{:__aliases__, _, [:Application]}, :compile_env]} = ast, issues, issue_meta) do + {ast, [issue_for(issue_meta, Macro.to_string(ast)) | issues]} + end + + defp traverse({:., _, [{:__aliases__, _, [:Application]}, :compile_env!]} = ast, issues, issue_meta) do + {ast, [issue_for(issue_meta, Macro.to_string(ast)) | issues]} + end + + defp traverse(ast, issues, _issue_meta) do + {ast, issues} + end + + defp issue_for(issue_meta, trigger) do + format_issue( + issue_meta, + message: """ + Avoid using Application.compile_env, use runtime configuration instead. If you need compile-time config, use Utils.CompileTimeEnvHelper. + More details: https://github.com/blockscout/blockscout/tree/master/CONTRIBUTING.md#compile-time-environment-variables + """, + trigger: trigger + ) + end +end diff --git a/apps/utils/lib/utils/compile_time_env_helper.ex b/apps/utils/lib/utils/compile_time_env_helper.ex new file mode 100644 index 000000000000..d5f50191cd1b --- /dev/null +++ b/apps/utils/lib/utils/compile_time_env_helper.ex @@ -0,0 +1,170 @@ +defmodule Utils.CompileTimeEnvHelper do + @moduledoc """ + A module that helps with compile time environment variable handling and automatic + module recompilation when environment variables change. + + ## Motivation + + Direct use of `Application.compile_env/3` causes error when runtime value + of environment variable value do not match compile time value, + this error halts the compilation and requires recompilation of the whole app. + This module prevents this since module is being recompiled automatically when + environment variable value changes. So, this module solves two issues: + + 1. Compile time error is avoided, so the app can be run without whole recompilation. + 2. No need to recompile the whole app when environment variable value changes, that + speed up compilation of different app versions. + + ## How It Works + + The module implements the `__mix_recompile__?/0` callback which Mix uses to determine + if a module needs recompilation. It tracks the values of specified environment variables + at compile time and triggers recompilation when these values change. + + ## Configuration + + Each key-value pair in the options represents: + - Key: The desired module attribute name + - Value: A list containing two elements: + - First element: The application name (atom) + - Second element: The configuration key or list of nested keys + + ## Examples + + Simple configuration: + + use Utils.CompileTimeEnvHelper, + api_url: [:my_app, :api_url] + + Nested configuration: + + use Utils.CompileTimeEnvHelper, + db_config: [:my_app, [:database, :config]], + api_key: [:my_app, [:api, :credentials, :key]] + + ## Technical Details + + 1. **Compile Time Value Tracking** + The module stores the initial values of environment variables during compilation + in a module attribute. These values are used as a reference point for the + `__mix_recompile__?/0` function. + + 2. **Recompilation Logic** + When Mix checks if recompilation is needed, the module compares the current + environment variable values with the stored ones. If any value has changed, + it triggers recompilation of the module. + """ + + # A macro that sets up compile-time environment variable handling. + # + # ## How it works under the hood + # + # 1. When you `use Utils.CompileTimeEnvHelper`, it triggers this macro + # 2. The macro processes your environment configuration and generates necessary code + # using metaprogramming (the `quote` block) + # + # ## Example of generated code + # + # When you write: + # use Utils.CompileTimeEnvHelper, + # api_url: [:my_app, :api_url] + # + # It generates code similar to: + # Module.register_attribute(__MODULE__, :__compile_time_env_vars, accumulate: true) + # + # # Creates @api_url attribute with the compile-time value + # Module.put_attribute( + # __MODULE__, + # :api_url, + # Application.compile_env(:my_app, :api_url) + # ) + # + # # Stores the value for recompilation checking + # Module.put_attribute( + # __MODULE__, + # :__compile_time_env_vars, + # {Application.compile_env(:my_app, :api_url), {:my_app, :api_url}} + # ) + defmacro __using__(env_vars) do + alias Utils.CompileTimeEnvHelper + CompileTimeEnvHelper.__generate_attributes_and_recompile_functions__(env_vars) + end + + @doc """ + Generates the code needed for compile-time environment variable handling. + + ## Technical Details + + This function uses `quote` to create an Abstract Syntax Tree (AST) that will be + injected into the module using this helper. The generated code: + + 1. Creates a module attribute to accumulate environment variables: + ``` + Module.register_attribute(__MODULE__, :__compile_time_env_vars, accumulate: true) + ``` + + 2. For each environment variable in the configuration: + - Creates a module attribute with the compile-time value + - Stores the value and path for recompilation checking + + 3. Generates the `__mix_recompile__?/0` function that Mix uses to determine + if the module needs recompilation + + ## Example + + Given configuration: + api_url: [:my_app, :api_url] + db_host: [:my_app, [:database, :host]] + + This function generates: + # Module attributes for direct access + @api_url Application.compile_env(:my_app, :api_url) + @db_host Application.compile_env(:my_app, [:database, :host]) + + # Storage for recompilation checking + @__compile_time_env_vars [ + {, {:my_app, :api_url}}, + {, {:my_app, [:database, :host]}} + ] + + # Recompilation check function + def __mix_recompile__? do + # Check if any values changed + end + + ## Understanding the Quote Block + + The `quote do ... end` block is Elixir's metaprogramming feature that: + 1. Creates a template of code instead of executing it immediately + 2. This template will be injected into the module that uses this helper + 3. The code inside `quote` is executed when the module is compiled + """ + def __generate_attributes_and_recompile_functions__(env_vars) do + quote do + Module.register_attribute(__MODULE__, :__compile_time_env_vars, accumulate: true) + + for {attribute_name, [app, key_or_path]} <- unquote(env_vars) do + Module.put_attribute( + __MODULE__, + attribute_name, + Application.compile_env(app, key_or_path) + ) + + Module.put_attribute( + __MODULE__, + :__compile_time_env_vars, + {Application.compile_env(app, key_or_path), {app, key_or_path}} + ) + end + + def __mix_recompile__? do + @__compile_time_env_vars + |> Enum.map(fn + {value, {app, [key | path]}} -> value != get_in(Application.get_env(app, key), path) + {value, {app, key}} -> value != Application.get_env(app, key) + end) + |> Enum.any?() + end + end + end +end diff --git a/apps/utils/mix.exs b/apps/utils/mix.exs new file mode 100644 index 000000000000..a4eae3988c0d --- /dev/null +++ b/apps/utils/mix.exs @@ -0,0 +1,39 @@ +defmodule Utils.MixProject do + use Mix.Project + + def project do + [ + app: :utils, + version: "6.9.2", + build_path: "../../_build", + # config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.17", + elixirc_paths: elixirc_paths(Mix.env()), + start_permanent: Mix.env() == :prod, + deps: deps(), + preferred_cli_env: [ + credo: :test, + dialyzer: :test + ] + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:credo, "~> 1.5", only: [:test, :dev], runtime: false} + ] + end + + defp elixirc_paths(:prod), do: ["lib/utils", "lib/*"] + defp elixirc_paths(_), do: ["lib"] +end diff --git a/apps/utils/test/checks/compile_env_usage_test.exs b/apps/utils/test/checks/compile_env_usage_test.exs new file mode 100644 index 000000000000..3422a8ccb3e3 --- /dev/null +++ b/apps/utils/test/checks/compile_env_usage_test.exs @@ -0,0 +1,38 @@ +defmodule Utils.Credo.Checks.CompileEnvUsageTest do + use Credo.Test.Case + + alias Utils.Credo.Checks.CompileEnvUsage + + test "finds violations" do + """ + defmodule CredoSampleModule do + @test Application.compile_env(:blockscout, :test) + end + """ + |> to_source_file() + |> run_check(CompileEnvUsage) + |> assert_issue() + end + + test "ignores compile_time_env_helper.ex" do + """ + defmodule CredoSampleModule do + @test Application.compile_env(:blockscout, :test) + end + """ + |> to_source_file("utils/compile_time_env_helper.ex") + |> run_check(CompileEnvUsage) + |> refute_issues() + end + + test "no false positives" do + """ + defmodule CredoSampleModule do + use Utils.CompileTimeEnvHelper, test: [:blockscout, :test] + end + """ + |> to_source_file() + |> run_check(CompileEnvUsage) + |> refute_issues() + end +end diff --git a/apps/utils/test/test_helper.exs b/apps/utils/test/test_helper.exs new file mode 100644 index 000000000000..97950157e27c --- /dev/null +++ b/apps/utils/test/test_helper.exs @@ -0,0 +1 @@ +{:ok, _} = Application.ensure_all_started(:credo) diff --git a/bin/version_bump.sh b/bin/version_bump.sh index 97583f4a1f89..78f8fa576c4d 100755 --- a/bin/version_bump.sh +++ b/bin/version_bump.sh @@ -7,6 +7,7 @@ MIX_FILES=( "$(pwd)/apps/explorer/mix.exs" "$(pwd)/apps/indexer/mix.exs" "$(pwd)/apps/ethereum_jsonrpc/mix.exs" + "$(pwd)/apps/utils/mix.exs" ) CONFIG_FILE="$(pwd)/rel/config.exs" DOCKER_COMPOSE_FILE="$(pwd)/docker-compose/docker-compose.yml" diff --git a/config/runtime.exs b/config/runtime.exs index faa04a4ada3f..3c0d03f37f63 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -190,7 +190,8 @@ config :ethereum_jsonrpc, EthereumJSONRPC.HTTP, headers: %{"Content-Type" => "application/json"} |> Map.merge(ConfigHelper.parse_json_env_var("ETHEREUM_JSONRPC_HTTP_HEADERS", "{}")) - |> Map.to_list() + |> Map.to_list(), + gzip_enabled?: ConfigHelper.parse_bool_env_var("ETHEREUM_JSONRPC_HTTP_GZIP_ENABLED", "false") config :ethereum_jsonrpc, EthereumJSONRPC.Geth, block_traceable?: ConfigHelper.parse_bool_env_var("ETHEREUM_JSONRPC_GETH_TRACE_BY_BLOCK"), @@ -247,7 +248,8 @@ config :explorer, elasticity_multiplier: ConfigHelper.parse_integer_env_var("EIP_1559_ELASTICITY_MULTIPLIER", 2), base_fee_max_change_denominator: ConfigHelper.parse_integer_env_var("EIP_1559_BASE_FEE_MAX_CHANGE_DENOMINATOR", 8), csv_export_limit: ConfigHelper.parse_integer_env_var("CSV_EXPORT_LIMIT", 10_000), - shrink_internal_transactions_enabled: ConfigHelper.parse_bool_env_var("SHRINK_INTERNAL_TRANSACTIONS_ENABLED") + shrink_internal_transactions_enabled: ConfigHelper.parse_bool_env_var("SHRINK_INTERNAL_TRANSACTIONS_ENABLED"), + replica_max_lag: ConfigHelper.parse_time_env_var("REPLICA_MAX_LAG", "5m") config :explorer, :proxy, caching_implementation_data_enabled: true, diff --git a/cspell.json b/cspell.json index 0d89d8063545..9ca6de7bae94 100644 --- a/cspell.json +++ b/cspell.json @@ -78,8 +78,8 @@ "blockreward", "blockscout", "blockscoutuser", - "bools", "Boneh", + "bools", "bridgedtokenlist", "brotli", "browserconfig", @@ -255,6 +255,7 @@ "grecaptcha", "greymatter", "gtag", + "gzipped", "happygokitty", "haspopup", "Hazkne", @@ -336,6 +337,7 @@ "Menlo", "mergeable", "Merkle", + "metaprogramming", "metatags", "microsecs", "millis", @@ -434,6 +436,7 @@ "Postrge", "prederive", "prederived", + "prewalk", "progressbar", "proxiable", "proxying", @@ -640,15 +643,16 @@ "whereis", "whiler", "wysdvjkizxonu", + "xact", "xakgj", "xbaddress", "xdai", - "Xname", "xffff", "xlevel", "xlink", "xmark", "xmlhttprequest", + "Xname", "xnonsense", "xzzz", "yellowgreen", @@ -671,5 +675,5 @@ "dotenv", "html-eex", "makefile" - ], + ] } diff --git a/docker-compose/README.md b/docker-compose/README.md index fcd8f8b588b8..1a0926a0123c 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -45,7 +45,7 @@ The repo contains built-in configs for different JSON RPC clients without need t | Erigon | `docker-compose -f erigon.yml up -d` | | Geth (suitable for Reth as well) | `docker-compose -f geth.yml up -d` | | Geth Clique | `docker-compose -f geth-clique-consensus.yml up -d` | -| Nethermind, OpenEthereum | `docker-compose -f nethermind up -d` | +| Nethermind, OpenEthereum | `docker-compose -f nethermind.yml up -d` | | Ganache | `docker-compose -f ganache.yml up -d` | | HardHat network | `docker-compose -f hardhat-network.yml up -d` | diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index a20322750b4a..26b21da2da7e 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -30,13 +30,6 @@ services: context: .. dockerfile: ./docker/Dockerfile args: - CACHE_EXCHANGE_RATES_PERIOD: "" - API_V1_READ_METHODS_DISABLED: "false" - DISABLE_WEBAPP: "false" - API_V1_WRITE_METHODS_DISABLED: "false" - CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED: "" - CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL: "" - ADMIN_PANEL_ENABLED: "" RELEASE_VERSION: 6.9.2 links: - db:database diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env index 1782375eb092..df4b2670e2c7 100644 --- a/docker-compose/envs/common-blockscout.env +++ b/docker-compose/envs/common-blockscout.env @@ -1,30 +1,41 @@ ETHEREUM_JSONRPC_VARIANT=geth ETHEREUM_JSONRPC_HTTP_URL=http://host.docker.internal:8545/ -# ETHEREUM_JSONRPC_FALLBACK_HTTP_URL= DATABASE_URL=postgresql://blockscout:ceWb1MeLBEeOIfk65gU8EjF8@db:5432/blockscout + # DATABASE_EVENT_URL= # DATABASE_QUEUE_TARGET # TEST_DATABASE_URL= # TEST_DATABASE_READ_ONLY_API_URL= + +ETHEREUM_JSONRPC_TRANSPORT=http +ETHEREUM_JSONRPC_DISABLE_ARCHIVE_BALANCES=false +# ETHEREUM_JSONRPC_FALLBACK_HTTP_URL= ETHEREUM_JSONRPC_TRACE_URL=http://host.docker.internal:8545/ # ETHEREUM_JSONRPC_FALLBACK_TRACE_URL= -# ETHEREUM_JSONRPC_FALLBACK_ETH_CALL_URL= # ETHEREUM_JSONRPC_ETH_CALL_URL= -# ETHEREUM_JSONRPC_HTTP_TIMEOUT= -# CHAIN_TYPE= -NETWORK= -SUBNETWORK=Awesome chain -LOGO=/images/blockscout_logo.svg +# ETHEREUM_JSONRPC_FALLBACK_ETH_CALL_URL= # ETHEREUM_JSONRPC_WS_URL= # ETHEREUM_JSONRPC_FALLBACK_WS_URL= # ETHEREUM_JSONRPC_WS_RETRY_INTERVAL= -ETHEREUM_JSONRPC_TRANSPORT=http -ETHEREUM_JSONRPC_DISABLE_ARCHIVE_BALANCES=false # ETHEREUM_JSONRPC_ARCHIVE_BALANCES_WINDOW=200 +# ETHEREUM_JSONRPC_HTTP_TIMEOUT= # ETHEREUM_JSONRPC_HTTP_HEADERS= +# ETHEREUM_JSONRPC_HTTP_GZIP_ENABLED= # ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT= # ETHEREUM_JSONRPC_GETH_TRACE_BY_BLOCK= # ETHEREUM_JSONRPC_GETH_ALLOW_EMPTY_TRACES= +# ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT= +# ETHEREUM_JSONRPC_HTTP_URLS= +# ETHEREUM_JSONRPC_FALLBACK_HTTP_URLS= +# ETHEREUM_JSONRPC_TRACE_URLS= +# ETHEREUM_JSONRPC_FALLBACK_TRACE_URLS= +# ETHEREUM_JSONRPC_ETH_CALL_URLS= +# ETHEREUM_JSONRPC_FALLBACK_ETH_CALL_URLS= + +# CHAIN_TYPE= +NETWORK= +SUBNETWORK=Awesome chain +LOGO=/images/blockscout_logo.svg IPC_PATH= NETWORK_PATH=/ BLOCKSCOUT_HOST= @@ -127,7 +138,8 @@ CONTRACT_MAX_STRING_LENGTH_WITHOUT_TRIMMING=2040 # CONTRACT_AUDIT_REPORTS_AIRTABLE_API_KEY= # CONTRACT_CERTIFIED_LIST= UNCLES_IN_AVERAGE_BLOCK_TIME=false -DISABLE_WEBAPP=false +DISABLE_WEBAPP=true +ADMIN_PANEL_ENABLED=false API_V2_ENABLED=true API_V1_READ_METHODS_DISABLED=false API_V1_WRITE_METHODS_DISABLED=false @@ -175,7 +187,6 @@ INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER=false # INDEXER_EMPTY_BLOCKS_SANITIZER_INTERVAL= # INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE= # INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY= -# ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT= # INDEXER_BLOCK_REWARD_BATCH_SIZE= # INDEXER_BLOCK_REWARD_CONCURRENCY= # INDEXER_TOKEN_INSTANCE_USE_BASE_URI_RETRY= diff --git a/docker/Dockerfile b/docker/Dockerfile index 8d1f4cd8b813..79fe70743d08 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,26 +1,40 @@ -FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 AS builder +FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 AS builder-deps WORKDIR /app -ENV MIX_ENV="prod" +RUN apk --no-cache --update add \ + alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file gcompat libstdc++ curl ca-certificates git make + +# Cache elixir deps +COPY mix.exs mix.lock ./ +COPY apps/block_scout_web/mix.exs ./apps/block_scout_web/ +COPY apps/explorer/mix.exs ./apps/explorer/ +COPY apps/ethereum_jsonrpc/mix.exs ./apps/ethereum_jsonrpc/ +COPY apps/indexer/mix.exs ./apps/indexer/ +COPY apps/utils/mix.exs ./apps/utils/ -RUN apk --no-cache --update add alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file gcompat +ENV MIX_ENV="prod" +ENV MIX_HOME=/opt/mix +RUN mix local.hex --force +RUN mix do deps.get, local.rebar --force, deps.compile --skip-umbrella-children -RUN set -ex && \ - apk --update add libstdc++ curl ca-certificates gcompat +COPY config ./config +COPY rel ./rel +COPY apps ./apps -ARG CACHE_EXCHANGE_RATES_PERIOD +############################################################## +FROM builder-deps AS builder + +ENV DISABLE_WEBAPP=true +ENV ADMIN_PANEL_ENABLED=false +ARG DISABLE_INDEXER +ENV DISABLE_INDEXER=${DISABLE_INDEXER} +ARG DISABLE_API +ENV DISABLE_API=${DISABLE_API} ARG API_V1_READ_METHODS_DISABLED -ARG DISABLE_WEBAPP +ENV API_V1_READ_METHODS_DISABLED=${API_V1_READ_METHODS_DISABLED} ARG API_V1_WRITE_METHODS_DISABLED -ARG CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED -ARG ADMIN_PANEL_ENABLED -ARG CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL -ARG SESSION_COOKIE_DOMAIN -ARG MIXPANEL_TOKEN -ARG MIXPANEL_URL -ARG AMPLITUDE_API_KEY -ARG AMPLITUDE_URL +ENV API_V1_WRITE_METHODS_DISABLED=${API_V1_WRITE_METHODS_DISABLED} ARG CHAIN_TYPE ENV CHAIN_TYPE=${CHAIN_TYPE} ARG BRIDGED_TOKENS_ENABLED @@ -32,44 +46,18 @@ ENV SHRINK_INTERNAL_TRANSACTIONS_ENABLED=${SHRINK_INTERNAL_TRANSACTIONS_ENABLED} ARG API_GRAPHQL_MAX_COMPLEXITY ENV API_GRAPHQL_MAX_COMPLEXITY=${API_GRAPHQL_MAX_COMPLEXITY} -# Cache elixir deps -ADD mix.exs mix.lock ./ -ADD apps/block_scout_web/mix.exs ./apps/block_scout_web/ -ADD apps/explorer/mix.exs ./apps/explorer/ -ADD apps/ethereum_jsonrpc/mix.exs ./apps/ethereum_jsonrpc/ -ADD apps/indexer/mix.exs ./apps/indexer/ - -ENV MIX_HOME=/opt/mix -RUN mix local.hex --force -RUN mix do deps.get, local.rebar --force, deps.compile - -ADD apps ./apps -ADD config ./config -ADD rel ./rel -ADD *.exs ./ - # Run backend compilation RUN mix compile -RUN apk add --update git make - -RUN mkdir -p /opt/release \ - && mix release blockscout \ - && mv _build/${MIX_ENV}/rel/blockscout /opt/release +RUN mkdir -p /opt/release && \ + mix release blockscout && \ + mv _build/${MIX_ENV}/rel/blockscout /opt/release ############################################################## FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 -ARG RELEASE_VERSION -ENV RELEASE_VERSION=${RELEASE_VERSION} -ARG CHAIN_TYPE -ENV CHAIN_TYPE=${CHAIN_TYPE} -ARG BRIDGED_TOKENS_ENABLED -ENV BRIDGED_TOKENS_ENABLED=${BRIDGED_TOKENS_ENABLED} -ARG SHRINK_INTERNAL_TRANSACTIONS_ENABLED -ENV SHRINK_INTERNAL_TRANSACTIONS_ENABLED=${SHRINK_INTERNAL_TRANSACTIONS_ENABLED} -ARG BLOCKSCOUT_VERSION -ENV BLOCKSCOUT_VERSION=${BLOCKSCOUT_VERSION} +WORKDIR /app + ARG BLOCKSCOUT_USER=blockscout ARG BLOCKSCOUT_GROUP=blockscout ARG BLOCKSCOUT_UID=10001 @@ -79,7 +67,31 @@ RUN apk --no-cache --update add jq curl && \ addgroup --system --gid ${BLOCKSCOUT_GID} ${BLOCKSCOUT_GROUP} && \ adduser --system --uid ${BLOCKSCOUT_UID} --ingroup ${BLOCKSCOUT_GROUP} --disabled-password ${BLOCKSCOUT_USER} -WORKDIR /app +ENV DISABLE_WEBAPP=true +ENV ADMIN_PANEL_ENABLED=false +ARG DISABLE_INDEXER +ENV DISABLE_INDEXER=${DISABLE_INDEXER} +ARG DISABLE_API +ENV DISABLE_API=${DISABLE_API} +ARG API_V1_READ_METHODS_DISABLED +ENV API_V1_READ_METHODS_DISABLED=${API_V1_READ_METHODS_DISABLED} +ARG API_V1_WRITE_METHODS_DISABLED +ENV API_V1_WRITE_METHODS_DISABLED=${API_V1_WRITE_METHODS_DISABLED} +ARG CHAIN_TYPE +ENV CHAIN_TYPE=${CHAIN_TYPE} +ARG BRIDGED_TOKENS_ENABLED +ENV BRIDGED_TOKENS_ENABLED=${BRIDGED_TOKENS_ENABLED} +ARG MUD_INDEXER_ENABLED +ENV MUD_INDEXER_ENABLED=${MUD_INDEXER_ENABLED} +ARG SHRINK_INTERNAL_TRANSACTIONS_ENABLED +ENV SHRINK_INTERNAL_TRANSACTIONS_ENABLED=${SHRINK_INTERNAL_TRANSACTIONS_ENABLED} +ARG API_GRAPHQL_MAX_COMPLEXITY +ENV API_GRAPHQL_MAX_COMPLEXITY=${API_GRAPHQL_MAX_COMPLEXITY} + +ARG RELEASE_VERSION +ENV RELEASE_VERSION=${RELEASE_VERSION} +ARG BLOCKSCOUT_VERSION +ENV BLOCKSCOUT_VERSION=${BLOCKSCOUT_VERSION} COPY --from=builder --chown=${BLOCKSCOUT_USER}:${BLOCKSCOUT_GROUP} /opt/release/blockscout . COPY --from=builder --chown=${BLOCKSCOUT_USER}:${BLOCKSCOUT_GROUP} /app/config/config_helper.exs ./config/config_helper.exs diff --git a/docker/oldUI.Dockerfile b/docker/oldUI.Dockerfile index 1a2b1da1755a..95c4a1f9b519 100644 --- a/docker/oldUI.Dockerfile +++ b/docker/oldUI.Dockerfile @@ -1,87 +1,79 @@ -FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 AS builder +FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 AS builder-deps WORKDIR /app -ENV MIX_ENV="prod" - -RUN apk --no-cache --update add alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file gcompat - -RUN set -ex && \ - apk --update add libstdc++ curl ca-certificates gcompat - -ARG CACHE_EXCHANGE_RATES_PERIOD -ARG API_V1_READ_METHODS_DISABLED -ARG DISABLE_WEBAPP -ARG API_V1_WRITE_METHODS_DISABLED -ARG CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED -ARG ADMIN_PANEL_ENABLED -ARG CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL -ARG SESSION_COOKIE_DOMAIN -ARG MIXPANEL_TOKEN -ARG MIXPANEL_URL -ARG AMPLITUDE_API_KEY -ARG AMPLITUDE_URL -ARG CHAIN_TYPE -ENV CHAIN_TYPE=${CHAIN_TYPE} -ARG BRIDGED_TOKENS_ENABLED -ENV BRIDGED_TOKENS_ENABLED=${BRIDGED_TOKENS_ENABLED} -ARG MUD_INDEXER_ENABLED -ENV MUD_INDEXER_ENABLED=${MUD_INDEXER_ENABLED} -ARG SHRINK_INTERNAL_TRANSACTIONS_ENABLED -ENV SHRINK_INTERNAL_TRANSACTIONS_ENABLED=${SHRINK_INTERNAL_TRANSACTIONS_ENABLED} +RUN apk --no-cache --update add \ + alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 file gcompat libstdc++ curl ca-certificates git make # Cache elixir deps -ADD mix.exs mix.lock ./ -ADD apps/block_scout_web/mix.exs ./apps/block_scout_web/ -ADD apps/explorer/mix.exs ./apps/explorer/ -ADD apps/ethereum_jsonrpc/mix.exs ./apps/ethereum_jsonrpc/ -ADD apps/indexer/mix.exs ./apps/indexer/ +COPY mix.exs mix.lock ./ +COPY apps/block_scout_web/mix.exs ./apps/block_scout_web/ +COPY apps/explorer/mix.exs ./apps/explorer/ +COPY apps/ethereum_jsonrpc/mix.exs ./apps/ethereum_jsonrpc/ +COPY apps/indexer/mix.exs ./apps/indexer/ +COPY apps/utils/mix.exs ./apps/utils/ +ENV MIX_ENV="prod" ENV MIX_HOME=/opt/mix RUN mix local.hex --force -RUN mix do deps.get, local.rebar --force, deps.compile +RUN mix do deps.get, local.rebar --force, deps.compile --skip-umbrella-children -ADD apps ./apps -ADD config ./config -ADD rel ./rel -ADD *.exs ./ +COPY config ./config +COPY rel ./rel +COPY apps ./apps -RUN apk add --update nodejs npm +############################################################## +FROM builder-deps AS builder-ui -# Run backend compilation and install latest npm -RUN mix compile && npm install npm@latest +RUN apk --no-cache --update add nodejs npm && \ + npm install npm@latest # Add blockscout npm deps RUN cd apps/block_scout_web/assets/ && \ npm install && \ npm run deploy && \ cd /app/apps/explorer/ && \ - npm install && \ - apk update && \ - apk del --force-broken-world alpine-sdk gmp-dev automake libtool inotify-tools autoconf python3 - - -RUN apk add --update git make + npm install RUN mix phx.digest -RUN mkdir -p /opt/release \ - && mix release blockscout \ - && mv _build/${MIX_ENV}/rel/blockscout /opt/release - ############################################################## -FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 +FROM builder-ui AS builder -ARG RELEASE_VERSION -ENV RELEASE_VERSION=${RELEASE_VERSION} +ENV DISABLE_WEBAPP=false +ARG ADMIN_PANEL_ENABLED +ENV ADMIN_PANEL_ENABLED=${ADMIN_PANEL_ENABLED} +ARG DISABLE_INDEXER +ENV DISABLE_INDEXER=${DISABLE_INDEXER} +ARG DISABLE_API +ENV DISABLE_API=${DISABLE_API} +ARG API_V1_READ_METHODS_DISABLED +ENV API_V1_READ_METHODS_DISABLED=${API_V1_READ_METHODS_DISABLED} +ARG API_V1_WRITE_METHODS_DISABLED +ENV API_V1_WRITE_METHODS_DISABLED=${API_V1_WRITE_METHODS_DISABLED} ARG CHAIN_TYPE ENV CHAIN_TYPE=${CHAIN_TYPE} ARG BRIDGED_TOKENS_ENABLED ENV BRIDGED_TOKENS_ENABLED=${BRIDGED_TOKENS_ENABLED} +ARG MUD_INDEXER_ENABLED +ENV MUD_INDEXER_ENABLED=${MUD_INDEXER_ENABLED} ARG SHRINK_INTERNAL_TRANSACTIONS_ENABLED ENV SHRINK_INTERNAL_TRANSACTIONS_ENABLED=${SHRINK_INTERNAL_TRANSACTIONS_ENABLED} -ARG BLOCKSCOUT_VERSION -ENV BLOCKSCOUT_VERSION=${BLOCKSCOUT_VERSION} +ARG API_GRAPHQL_MAX_COMPLEXITY +ENV API_GRAPHQL_MAX_COMPLEXITY=${API_GRAPHQL_MAX_COMPLEXITY} + +# Run backend compilation +RUN mix compile + +RUN mkdir -p /opt/release && \ + mix release blockscout && \ + mv _build/${MIX_ENV}/rel/blockscout /opt/release + +############################################################## +FROM hexpm/elixir:1.17.3-erlang-27.1-alpine-3.20.3 + +WORKDIR /app + ARG BLOCKSCOUT_USER=blockscout ARG BLOCKSCOUT_GROUP=blockscout ARG BLOCKSCOUT_UID=10001 @@ -91,7 +83,32 @@ RUN apk --no-cache --update add jq curl && \ addgroup --system --gid ${BLOCKSCOUT_GID} ${BLOCKSCOUT_GROUP} && \ adduser --system --uid ${BLOCKSCOUT_UID} --ingroup ${BLOCKSCOUT_GROUP} --disabled-password ${BLOCKSCOUT_USER} -WORKDIR /app +ENV DISABLE_WEBAPP=false +ARG ADMIN_PANEL_ENABLED +ENV ADMIN_PANEL_ENABLED=${ADMIN_PANEL_ENABLED} +ARG DISABLE_INDEXER +ENV DISABLE_INDEXER=${DISABLE_INDEXER} +ARG DISABLE_API +ENV DISABLE_API=${DISABLE_API} +ARG API_V1_READ_METHODS_DISABLED +ENV API_V1_READ_METHODS_DISABLED=${API_V1_READ_METHODS_DISABLED} +ARG API_V1_WRITE_METHODS_DISABLED +ENV API_V1_WRITE_METHODS_DISABLED=${API_V1_WRITE_METHODS_DISABLED} +ARG CHAIN_TYPE +ENV CHAIN_TYPE=${CHAIN_TYPE} +ARG BRIDGED_TOKENS_ENABLED +ENV BRIDGED_TOKENS_ENABLED=${BRIDGED_TOKENS_ENABLED} +ARG MUD_INDEXER_ENABLED +ENV MUD_INDEXER_ENABLED=${MUD_INDEXER_ENABLED} +ARG SHRINK_INTERNAL_TRANSACTIONS_ENABLED +ENV SHRINK_INTERNAL_TRANSACTIONS_ENABLED=${SHRINK_INTERNAL_TRANSACTIONS_ENABLED} +ARG API_GRAPHQL_MAX_COMPLEXITY +ENV API_GRAPHQL_MAX_COMPLEXITY=${API_GRAPHQL_MAX_COMPLEXITY} + +ARG RELEASE_VERSION +ENV RELEASE_VERSION=${RELEASE_VERSION} +ARG BLOCKSCOUT_VERSION +ENV BLOCKSCOUT_VERSION=${BLOCKSCOUT_VERSION} COPY --from=builder --chown=${BLOCKSCOUT_USER}:${BLOCKSCOUT_GROUP} /opt/release/blockscout . COPY --from=builder --chown=${BLOCKSCOUT_USER}:${BLOCKSCOUT_GROUP} /app/apps/explorer/node_modules ./node_modules diff --git a/mix.exs b/mix.exs index 8cb5633b0ca7..aeb99f19332f 100644 --- a/mix.exs +++ b/mix.exs @@ -23,7 +23,8 @@ defmodule BlockScout.Mixfile do block_scout_web: :permanent, ethereum_jsonrpc: :permanent, explorer: :permanent, - indexer: :permanent + indexer: :permanent, + utils: :permanent ], steps: [:assemble, ©_prod_runtime_config/1], validate_compile_env: false @@ -53,7 +54,7 @@ defmodule BlockScout.Mixfile do defp dialyzer() do [ plt_add_deps: :app_tree, - plt_add_apps: ~w(ex_unit mix wallaby)a, + plt_add_apps: ~w(credo ex_unit mix wallaby)a, ignore_warnings: ".dialyzer-ignore", plt_core_path: "priv/plts", plt_file: {:no_warn, "priv/plts/dialyzer.plt"} diff --git a/mix.lock b/mix.lock index bc60f793db56..7a518d99dd38 100644 --- a/mix.lock +++ b/mix.lock @@ -40,7 +40,7 @@ "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "digital_token": {:hex, :digital_token, "1.0.0", "454a4444061943f7349a51ef74b7fb1ebd19e6a94f43ef711f7dae88c09347df", [:mix], [{:cldr_utils, "~> 2.17", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "8ed6f5a8c2fa7b07147b9963db506a1b4c7475d9afca6492136535b064c9e9e6"}, "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, - "ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"}, + "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, "elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},