diff --git a/.env b/.env index d42a352f..6073e57d 100644 --- a/.env +++ b/.env @@ -1,28 +1,14 @@ VITE_JAM_DEFAULT_THEME=dark -VITE_JAM_REPO_URL=https://github.com/joinmarket-webui/jam -VITE_JAM_DOCS_URL=https://jamdocs.org -VITE_JAM_MATRIX_URL=https://matrix.to/#/%23jam:bitcoin.kyoto -VITE_JAM_TELEGRAM_URL=https://t.me/JoinMarketWebUI -VITE_JAM_JMNG_REPO_URL=https://github.com/joinmarket-ng/joinmarket-ng -VITE_JM_API_BASE_URL= +VITE_JM_API_BASE_URL=/api/v1 VITE_JM_API_AUTH_TOKEN_EXPIRY_SECONDS=1800 VITE_JAM_JM_SESSION_REFRESH_INTERVAL=30000 VITE_JAM_RESCAN_PROGRESS_INTERVAL=10000 VITE_JAM_SEED_MODAL_TIMEOUT=30000 -VITE_JAM_SWEEP_DESTINATION_ADDRESSES_MIN_COUNT=3 -VITE_JAM_SWEEP_DESTINATION_ADDRESSES_DEFAULT_COUNT=3 - VITE_JM_WEBSOCKET_ENDPOINT_PATH=/jmws VITE_JM_WEBSOCKET_CONNECTION_HEALTHY_DURATION=1000 VITE_JM_WEBSOCKET_CONNECTION_AUTHENTICATED_DURATION=3000 VITE_JM_WEBSOCKET_KEEPALIVE_MESSAGE_INTERVAL=30000 VITE_JM_WEBSOCKET_RECONNECT_INTERVAL_MIN=5000 VITE_JM_WEBSOCKET_RECONNECT_INTERVAL_MAX=60000 - -VITE_JAM_SWEEP_MIN_ROUNDING_CHANCE_PERCENT=10 -VITE_JAM_SWEEP_MAX_ROUNDING_CHANCE_PERCENT=90 - -VITE_JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS=true -VITE_JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS_DELAY=1000 diff --git a/.env.development b/.env.development index 9b4b3df4..ea09cf5e 100644 --- a/.env.development +++ b/.env.development @@ -5,13 +5,3 @@ VITE_JM_WEBSOCKET_RECONNECT_INTERVAL_MIN=3000 VITE_JM_WEBSOCKET_RECONNECT_INTERVAL_MAX=30000 VITE_JAM_SEED_MODAL_TIMEOUT=21000 - -VITE_JAM_SWEEP_MAKER_SESSION_IDLE_MIN_TIMEOUT_SECONDS=59 -VITE_JAM_SWEEP_MAKER_SESSION_IDLE_TIMEOUT_SECONDS=59 - -VITE_JAM_SWEEP_DESTINATION_ADDRESSES_MIN_COUNT=1 -VITE_JAM_SWEEP_DESTINATION_ADDRESSES_DEFAULT_COUNT=3 - -VITE_JAM_SWEEP_MIN_MIN_NUMBER_OF_COLLABORATORS=1 - -VITE_JAM_RUNNING_SCHEDULE_POLLING_INTERVAL=5000 diff --git a/.env.test b/.env.test deleted file mode 100644 index 214a58a6..00000000 --- a/.env.test +++ /dev/null @@ -1,7 +0,0 @@ -VITE_JAM_SWEEP_DESTINATION_ADDRESSES_MIN_COUNT=1 -VITE_JAM_SWEEP_DESTINATION_ADDRESSES_DEFAULT_COUNT=3 - -VITE_JAM_SWEEP_MAKER_SESSION_IDLE_MIN_TIMEOUT_SECONDS=1 -VITE_JAM_SWEEP_MAKER_SESSION_IDLE_TIMEOUT_SECONDS=1 - -VITE_JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS_DELAY=1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db7f7bd4..862ef55f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,14 +11,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: ['v26.5.0'] + node-version: ['v26.3.0'] steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v6 - name: Setup (Node.js ${{ matrix.node-version }}) - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} @@ -30,7 +30,7 @@ jobs: run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').packages['node_modules/@playwright/test'].version)")" >> $GITHUB_ENV - name: Cache Playwright - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + uses: actions/cache@v5 id: playwright-cache with: path: | @@ -50,7 +50,7 @@ jobs: run: npm run format:check - name: Test - run: npm run test:coverage + run: npm test -- --coverage.enabled - name: Build run: npm run build @@ -59,4 +59,4 @@ jobs: # Set if: always() to also generate the report if tests are failing # Only works if you set `reportOnFailure: true` in vite config if: ${{ always() && hashFiles('coverage/coverage-summary.json') != '' }} - uses: davelosert/vitest-coverage-report-action@8b157684c6a6b259b97d45e72b44242865c0f6a5 # v2.12.2 + uses: davelosert/vitest-coverage-report-action@v2 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ae329291..e89f19fa 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,9 +41,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v7 - with: - persist-credentials: false + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/storybook-build.yml b/.github/workflows/storybook-build.yml index 01d50de6..35594961 100644 --- a/.github/workflows/storybook-build.yml +++ b/.github/workflows/storybook-build.yml @@ -12,12 +12,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false + uses: actions/checkout@v6 - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@v6 with: node-version-file: .nvmrc diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index e23a3876..a0cdacb5 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -24,10 +24,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + uses: actions/checkout@v6 - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@v6 with: node-version-file: .nvmrc @@ -38,13 +38,13 @@ jobs: run: npm run storybook:build-gh-pages - name: Configure Pages - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + uses: actions/configure-pages@v6 - name: Upload Pages artifact - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + uses: actions/upload-pages-artifact@v5 with: path: storybook-static - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 + uses: actions/deploy-pages@v5 diff --git a/.husky/pre-push b/.husky/pre-push index 9814e1a5..72c4429b 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1 +1 @@ -npm run test -- --bail=1 +npm test diff --git a/.nvmrc b/.nvmrc index eacd4817..84a2f4a2 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v26.5.0 +v26.3.0 diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index b6009ab1..ad3798d6 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -2,12 +2,11 @@ import { Suspense, useEffect } from 'react' import type { Preview } from '@storybook/react-vite' import { QueryClientProvider, QueryClient } from '@tanstack/react-query' -import { mswLoader } from 'msw-storybook-addon/csf3' -import { setupWorker } from 'msw/browser' +import { initialize, mswLoader } from 'msw-storybook-addon' import { ThemeProvider } from 'next-themes' import { I18nextProvider } from 'react-i18next' import { MemoryRouter } from 'react-router-dom' -import type { CoreTypes, GlobalTypes } from 'storybook/internal/csf' +import { CoreTypes, GlobalTypes } from 'storybook/internal/csf' import { DEFAULT_VIEWPORT, MINIMAL_VIEWPORTS, INITIAL_VIEWPORTS } from 'storybook/viewport' import { JamDisplayContextProvider } from '../src/context/JamDisplayContextProvider' import { JamWalletInfoContextProvider } from '../src/context/JamWalletInfoContextProvider' @@ -18,6 +17,15 @@ import mswHandlers from './msw-handlers' // needed if you want to use msw on a subpath (e.g. github pages /) const mswServiceWorkerUrl = import.meta.env.STORYBOOK_MSW_SERVICE_WORKER_URL ?? '/mockServiceWorker.js' +// Initialize MSW (https://github.com/mswjs/msw-storybook-addon) +initialize({ + onUnhandledRequest: 'bypass', + serviceWorker: { + url: mswServiceWorkerUrl, + }, + quiet: true, +}) + const locales = [ { value: 'en', title: 'en' }, { value: 'fr', title: 'fr' }, @@ -77,28 +85,12 @@ const preview: Preview = { viewport: { options: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS }, }, - // this approach is deprecated as of v3.0.0 - // but it seems the new approach does not work as expected (404 response for our handlers) - // revisit after next update (last checked 2026-07-30) - // see: https://github.com/mswjs/msw-storybook-addon/blob/v3.0.0/MIGRATION.md#parametersmsw-is-deprecated-in-favor-of-beforeeach msw: { handlers: mswHandlers, }, }, // Provide the MSW addon loader globally - loaders: [ - mswLoader(async () => { - const worker = setupWorker() - await worker.start({ - onUnhandledRequest: 'bypass', - serviceWorker: { - url: mswServiceWorkerUrl, - }, - quiet: true, - }) - return worker - }), - ], + loaders: [mswLoader], } const withTheme = (Story: React.ComponentType, context: GlobalContext) => { diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7fcaab5..edc48612 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,12 +5,12 @@ The aim of this document is to help you get setup for participating in all areas ## Understanding the Components Involved -Jam is a web UI for [JoinMarket NG](https://github.com/joinmarket-ng/joinmarket-ng) with focus on user-friendliness. -The web UI's purpose is to be a rather lightweight front end for the JoinMarket NG API. -To function, the web UI needs to connect to an instance of JoinMarket NG with [the API service](https://joinmarket-ng.github.io/joinmarket-ng/README-jmwalletd/) running. +Jam is a web UI for [JoinMarket](https://github.com/JoinMarket-Org/joinmarket-clientserver/) with focus on user-friendliness. +The web UI's purpose is to be a rather lightweight front end for the JoinMarket API. +To function, the web UI needs to connect to an instance of JoinMarket with [the API service](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/JSON-RPC-API-using-jmwalletd.md) running. You don't need to worry about that, though. -To ease development and testing, we provide a Docker setup that runs JoinMarket NG and its API service in a regtest setup. +To ease development and testing, we provide a Docker setup that runs JoinMarket and its API service in a regtest setup. ## Local setup (regtest and UI) @@ -22,7 +22,7 @@ Install dependencies: npm install ``` -Start the JoinMarket NG HTTP API service in regtest. +Start the JoinMarket HTTP API service in regtest. It isn't needed to dig deeper into how it works to use it. However, if you want to find out more about it, see [docker/regtest/readme.md](docker/regtest/readme.md). diff --git a/README.md b/README.md index 8a14fd41..6025f179 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ --- -Jam is a web interface for [JoinMarket NG](https://github.com/joinmarket-ng/joinmarket-ng) focusing on user-friendliness and ease-of-use. +Jam is a web interface for [JoinMarket](https://github.com/JoinMarket-Org/joinmarket-clientserver/) focusing on user-friendliness and ease-of-use. It aims to provide sensible defaults and be easy to use for beginners while still having the features advanced users expect. - 💬 Join our [Matrix room](https://matrix.to/#/%23jam:bitcoin.kyoto) to get help and [contribute](https://joinmarket-webui.github.io/jamdocs/contribute/)! @@ -88,4 +88,4 @@ Want to get your hands dirty with code? Great! [CONTRIBUTING.md](CONTRIBUTING.md This project builds upon the [jm-web-client](https://github.com/JoinMarket-Org/jm-web-client) which was developed by [Shobhitaa](https://github.com/shobhitaa), [Abhishek](https://github.com/abhishek0405), and [waxwing](https://github.com/AdamISZ) himself. Many people contributed over time, some of which are [listed here](https://github.com/joinmarket-webui/jam/graphs/contributors). -Jam and JoinMarket NG are separate projects. For more information on JoinMarket NG, see the [JoinMarket NG GitHub Page](https://github.com/joinmarket-ng/joinmarket-ng). +Jam and JoinMarket are separate projects. For more information on JoinMarket, see the [JoinMarket GitHub Page](https://github.com/JoinMarket-Org/joinmarket-clientserver). diff --git a/docker/regtest/docker-compose-common.yml b/docker/regtest/docker-compose-common.yml index 0bd00c63..46490da6 100644 --- a/docker/regtest/docker-compose-common.yml +++ b/docker/regtest/docker-compose-common.yml @@ -12,6 +12,10 @@ services: jm_rpc_host: bitcoind jm_rpc_port: 43782 jm_directory_nodes: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} + jm_socks5_host: tor + jm_socks5_port: 9050 + jm_tor_control_host: tor + jm_tor_control_port: 9051 jm_minimum_makers: 1 # necessary to do coinjoins with this regtest setup; default is 4 jm_taker_utxo_age: 1 # faster testing of scheduler runs; default is 5 jm_maker_timeout_sec: 30 # easier testing of maker timeouts on regtest (and "Stall Monitor" retries); default is 60 @@ -41,6 +45,10 @@ services: jm_rpc_host: bitcoind jm_rpc_port: 43782 jm_directory_nodes: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} + jm_socks5_host: tor + jm_socks5_port: 9050 + jm_tor_control_host: tor + jm_tor_control_port: 9051 jm_minimum_makers: 1 # necessary to do coinjoins with this regtest setup; default is 4 jm_taker_utxo_age: 1 # faster testing of scheduler runs; default is 5 expose: @@ -59,16 +67,6 @@ services: context: ./dockerfile-deps/joinmarket/webui-standalone-ng dockerfile: Dockerfile restart: unless-stopped - environment: - JMWALLETD_HOST: 0.0.0.0 - BITCOIN__BACKEND_TYPE: descriptor_wallet - BITCOIN__RPC_URL: http://bitcoind:43782 - BITCOIN__RPC_USER: regtest - BITCOIN__RPC_PASSWORD: regtest - LOGGING__LEVEL: DEBUG - NETWORK_CONFIG__NETWORK: testnet - NETWORK_CONFIG__BITCOIN_NETWORK: regtest - NETWORK_CONFIG__DIRECTORY_SERVERS: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} expose: - 80 # nginx - 28183 # jmwalletd api @@ -79,6 +77,7 @@ services: environment: JOINMARKET_DATA_DIR: /root/.joinmarket-ng JMWALLETD_HOST: 0.0.0.0 + JMWALLETD_NO_TLS: ${JMWALLETD_NO_TLS:-false} BITCOIN__BACKEND_TYPE: descriptor_wallet BITCOIN__RPC_URL: http://bitcoind:43782 BITCOIN__RPC_USER: regtest @@ -86,8 +85,7 @@ services: NETWORK_CONFIG__NETWORK: testnet NETWORK_CONFIG__BITCOIN_NETWORK: regtest NETWORK_CONFIG__DIRECTORY_SERVERS: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} - ORDERBOOK_WATCHER__HTTP_HOST: joinmarket_ng_orderbook_watcher - ORDERBOOK_WATCHER__HTTP_PORT: 8000 + DIRECTORY_NODES: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} OBWATCH_URL: http://joinmarket_ng_orderbook_watcher:8000 TOR__SOCKS_HOST: tor TOR__SOCKS_PORT: 9050 @@ -99,6 +97,7 @@ services: expose: - 8000 # obwatch - 28183 # jmwalletd api + - 28283 # jmwalletd websocket healthcheck: test: [ @@ -119,6 +118,7 @@ services: environment: JOINMARKET_DATA_DIR: /root/.joinmarket-ng JMWALLETD_HOST: 0.0.0.0 + JMWALLETD_NO_TLS: ${JMWALLETD_NO_TLS:-false} BITCOIN__BACKEND_TYPE: descriptor_wallet BITCOIN__RPC_URL: http://bitcoind:43782 BITCOIN__RPC_USER: regtest @@ -126,8 +126,7 @@ services: NETWORK_CONFIG__NETWORK: testnet NETWORK_CONFIG__BITCOIN_NETWORK: regtest NETWORK_CONFIG__DIRECTORY_SERVERS: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} - ORDERBOOK_WATCHER__HTTP_HOST: joinmarket_ng_orderbook_watcher - ORDERBOOK_WATCHER__HTTP_PORT: 8000 + DIRECTORY_NODES: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} OBWATCH_URL: http://joinmarket_ng_orderbook_watcher:8000 TOR__SOCKS_HOST: tor TOR__SOCKS_PORT: 9050 @@ -138,6 +137,7 @@ services: expose: - 8000 # obwatch - 28183 # jmwalletd api + - 28283 # jmwalletd websocket healthcheck: test: [ diff --git a/docker/regtest/docker-compose.yml b/docker/regtest/docker-compose.yml index 9adaeeca..a33c7d8e 100644 --- a/docker/regtest/docker-compose.yml +++ b/docker/regtest/docker-compose.yml @@ -6,10 +6,12 @@ services: service: joinmarket_ng_native environment: READY_FILE: /root/.regtest-initializer/btc_fully_synched - BITCOIN__RPC_USER: joinmarket - BITCOIN__RPC_PASSWORD: joinmarket + BITCOIN__RPC_USER: regtest + BITCOIN__RPC_PASSWORD: regtest + BITCOIN__DESCRIPTOR_WALLET_NAME: jm_primary ports: - - '28183:28183' # jmwalletd api (exposed for "init setup" routine) + - '28183:28183' # jmwalletd api + - '28283:28283' # jmwalletd websocket volumes: - 'joinmarket_datadir:/root/.joinmarket-ng' - 'initializer_datadir:/root/.regtest-initializer' @@ -30,13 +32,20 @@ services: file: docker-compose-common.yml service: joinmarket_jam_standalone_ng environment: - BITCOIN__RPC_USER: joinmarket2 - BITCOIN__RPC_PASSWORD: joinmarket2 + ENSURE_WALLET: 'true' + BITCOIN__RPC_URL: http://bitcoind:43782 + BITCOIN__RPC_USER: regtest + BITCOIN__RPC_PASSWORD: regtest + BITCOIN__DESCRIPTOR_WALLET_NAME: jm_secondary + LOGGING__LEVEL: DEBUG + NETWORK_CONFIG__NETWORK: testnet + NETWORK_CONFIG__BITCOIN_NETWORK: regtest + NETWORK_CONFIG__DIRECTORY_SERVERS: ${JM_ALL_DIRECTORY_NODES:?You must set the directory node addresses in generated env file} TAKER__MINIMUM_MAKERS: 2 # necessary to do coinjoins with this regtest setup TAKER__MAKER_TIMEOUT_SEC: 30 # easier testing of maker timeouts on regtest ports: - '29080:80' - - '29183:28183' # jmwalletd api (exposed for "init setup" routine) + - '29183:28183' # exposed for "init setup" routine volumes: - 'joinmarket2_datadir:/root/.joinmarket-ng' depends_on: @@ -55,11 +64,10 @@ services: jm_rpc_wallet_file: jm_tertiary jm_rpc_user: joinmarket3 jm_rpc_password: joinmarket3 - CREATE_WALLET_PARAMS_DESCRIPTORS: 'false' ports: - - '30601:62601' # obwatch - - '30183:28183' # jmwalletd api (exposed for "init setup" routine) - - '30283:28283' # jmwalletd websocket + - '30601:62601' # obwatch + - '30183:28183' # jmwalletd api + - '30283:28283' # jmwalletd websocket volumes: - 'joinmarket3_datadir:/root/.joinmarket' - 'initializer_datadir:/root/.regtest-initializer' @@ -85,7 +93,7 @@ services: jm_rpc_cookie_file: /root/.bitcoin_data/regtest/.cookie ports: - '31080:80' - - '31183:28183' # jmwalletd api (exposed for "init setup" routine) + - '31183:28183' # exposed for "init setup" routine volumes: - 'joinmarket4_datadir:/root/.joinmarket' - 'bitcoin_datadir:/root/.bitcoin_data' # mount bitcoind dir to access .cookie file @@ -105,8 +113,12 @@ services: extends: file: docker-compose-common.yml service: joinmarket_ng_peer + environment: + BITCOIN__RPC_USER: regtest + BITCOIN__RPC_PASSWORD: regtest + BITCOIN__DESCRIPTOR_WALLET_NAME: jm_quinary ports: - - '32183:28183' # jmwalletd api (exposed for "init setup" routine) + - '32183:28183' volumes: - 'joinmarket5_datadir:/root/.joinmarket-ng' - 'tor_datadir:/var/lib/tor:ro' @@ -120,8 +132,8 @@ services: tor: condition: service_healthy - joinmarket_clientserver_directory_node: - container_name: jm_regtest_joinmarket_clientserver_directory_node + joinmarket_directory_node: + container_name: jm_regtest_joinmarket_directory_node build: context: ./dockerfile-deps/joinmarket/directory_node dockerfile: Dockerfile @@ -129,10 +141,15 @@ services: environment: jm_hidden_service_dir: \/root\/.joinmarket\/hidden_service_dir jm_directory_nodes: ${JM_REF_DIRECTORY_NODES:?You must set the reference directory node address in generated env file} + jm_socks5_host: localhost + jm_socks5_port: 9050 + jm_tor_control_host: localhost + jm_tor_control_port: 9051 + jm_daemon_host: 0.0.0.0 jm_blockchain_source: regtest jm_network: testnet volumes: - - 'joinmarket_clientserver_directory_node_datadir:/root/.joinmarket' + - 'joinmarket_directory_node_datadir:/root/.joinmarket' - './out/hidden_service_dir:/root/.joinmarket/hidden_service_dir:z' healthcheck: test: ['CMD', 'supervisorctl', 'status'] @@ -144,6 +161,9 @@ services: depends_on: tor: condition: service_healthy + networks: + default: + ipv4_address: 172.30.0.20 joinmarket_ng_orderbook_watcher: container_name: jm_regtest_joinmarket_ng_orderbook_watcher @@ -156,8 +176,6 @@ services: TOR__SOCKS_HOST: tor TOR__SOCKS_PORT: 9050 LOGGING__LEVEL: DEBUG - ORDERBOOK_WATCHER__HTTP_HOST: 0.0.0.0 - ORDERBOOK_WATCHER__HTTP_PORT: 8000 expose: - 8000 ports: @@ -225,10 +243,11 @@ services: [ 'sh', '-c', - 'mkdir -p /var/lib/tor/ng-directory && cp -f /source/ng/* /var/lib/tor/ng-directory/ && chown -R 1000:1000 /var/lib/tor && chmod 700 /var/lib/tor/ng-directory && chmod 600 /var/lib/tor/ng-directory/*', + 'mkdir -p /var/lib/tor/ref-directory /var/lib/tor/ng-directory && cp -f /source/ref/* /var/lib/tor/ref-directory/ && cp -f /source/ng/* /var/lib/tor/ng-directory/ && chown -R 1000:1000 /var/lib/tor && chmod 700 /var/lib/tor/ref-directory /var/lib/tor/ng-directory && chmod 600 /var/lib/tor/ref-directory/* /var/lib/tor/ng-directory/*', ] volumes: - 'tor_datadir:/var/lib/tor' + - './out/hidden_service_dir:/source/ref:ro,z' - './out/ng_directory_hidden_service:/source/ng:ro,z' irc: @@ -243,7 +262,7 @@ services: bitcoind: container_name: jm_regtest_bitcoind restart: unless-stopped - image: polarlightning/bitcoind:29.0@sha256:4521294ac25fdbf1492a8cc5ea987463a5f244b82546d29bbe8451db39f36f3a + image: polarlightning/bitcoind:28.0@sha256:ff435d758c89f01823924e057d5d5e4206d350ae69dff5e0dc1bbc9c6a36d010 command: # rpcauth (user=regtest; password=regtest) # rpcauth (user=joinmarket; password=joinmarket) @@ -369,7 +388,7 @@ volumes: joinmarket3_datadir: joinmarket4_datadir: joinmarket5_datadir: - joinmarket_clientserver_directory_node_datadir: + joinmarket_directory_node_datadir: tor_datadir: irc_datadir: diff --git a/docker/regtest/dockerfile-deps/joinmarket/directory_node/README.md b/docker/regtest/dockerfile-deps/joinmarket/directory_node/README.md index c1c3b127..0f790880 100644 --- a/docker/regtest/dockerfile-deps/joinmarket/directory_node/README.md +++ b/docker/regtest/dockerfile-deps/joinmarket/directory_node/README.md @@ -9,7 +9,7 @@ and provide the correct onion hostname via `directory_nodes` yourself! e.g. in a docker-compose setup: ```yml - joinmarket_clientserver_directory_node: + joinmarket_directory_node: [...] environment: jm_hidden_service_dir: \/root\/.joinmarket\/hidden_service_dir diff --git a/docker/regtest/dockerfile-deps/joinmarket/latest/jam-entrypoint.sh b/docker/regtest/dockerfile-deps/joinmarket/latest/jam-entrypoint.sh index c760ccb8..b3e0a4ba 100644 --- a/docker/regtest/dockerfile-deps/joinmarket/latest/jam-entrypoint.sh +++ b/docker/regtest/dockerfile-deps/joinmarket/latest/jam-entrypoint.sh @@ -93,7 +93,7 @@ if [ "${ENSURE_WALLET}" = "true" ]; then \"method\":\"createwallet\",\ \"params\":{\ \"wallet_name\":\"${wallet_name}\",\ - \"descriptors\":$( [[ "${CREATE_WALLET_PARAMS_DESCRIPTORS,,}" == "false" ]] && echo false || echo true ),\ + \"descriptors\":false,\ \"load_on_startup\":true\ }\ }" diff --git a/docker/regtest/dockerfile-deps/joinmarket/latest/torrc b/docker/regtest/dockerfile-deps/joinmarket/latest/torrc index ece59b60..acca9872 100644 --- a/docker/regtest/dockerfile-deps/joinmarket/latest/torrc +++ b/docker/regtest/dockerfile-deps/joinmarket/latest/torrc @@ -1,7 +1,7 @@ # Default JoinMarket Tor configuration # taken from v0.9.6 on 2022-07-18: # https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/v0.9.6/install.sh#L388-L393 -Log notice stdout +Log warn stderr SOCKSPort 9050 IsolateDestAddr IsolateDestPort ControlPort 9051 CookieAuthentication 1 diff --git a/docker/regtest/init-setup.sh b/docker/regtest/init-setup.sh index b1f7e03e..a5093503 100755 --- a/docker/regtest/init-setup.sh +++ b/docker/regtest/init-setup.sh @@ -16,9 +16,7 @@ set -Eeuo pipefail script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) # fund wallet in primary JoinMarket NG container -. "$script_dir/fund-wallet.sh" --container jm_regtest_joinmarket --mixdepth 0 --unmatured --blocks 1 -. "$script_dir/fund-wallet.sh" --container jm_regtest_joinmarket --mixdepth 1 --unmatured --blocks 2 # outputs should be flagged as "reused" -. "$script_dir/fund-wallet.sh" --container jm_regtest_joinmarket --mixdepth 4 --unmatured --blocks 1 +. "$script_dir/fund-wallet.sh" --container jm_regtest_joinmarket --unmatured --blocks 3 # fund wallet in ng standalone secondary container . "$script_dir/fund-wallet.sh" --container jm_regtest_joinmarket2 --unmatured --blocks 50 @@ -37,14 +35,10 @@ script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) dummy_wallet_address1='bcrt1q6rz28mcfaxtmd6v789l9rrlrusdprr9pz3cppk' # 1st address of jar A (m/84'/1'/0'/0/0) dummy_wallet_address2='bcrt1qt5yxk3xzrx66q9wd5sdyynklqynqcyf7uh74j3' # 8th address of jar C (m/84'/1'/2'/0/7) dummy_wallet_address3='bcrt1qn8804dw5fahuc5cwqteuq5j4xlhk2cnkq7a8kw' # 21st change address of jar E (m/84'/1'/4'/1/21) -dummy_wallet_address_fb0='bcrt1q7war3lusq3ez633rzzfkp75unfcgrqqcu80sgp0ellhrdvkzxh5swspygk' # 1st fb address (m/84'/1'/0'/2/0) -dummy_wallet_address_fb959='bcrt1q6rlcknptmqhf4w20928tpz6px4y70960gyupd029c7vx7kdjwt0q46nk9c' # 960th fb address (m/84'/1'/0'/2/959) -# make block rewards spendable: 100 + 5 (default of `taker_utxo_age`) + 1 = at least 106 blocks +# make block rewards spendable: 100 + 5 (default of `taker_utxo_age`) + 1 = 106 . "$script_dir/mine-block.sh" 2 "$dummy_wallet_address1" &>/dev/null . "$script_dir/mine-block.sh" 2 "$dummy_wallet_address2" &>/dev/null . "$script_dir/mine-block.sh" 2 "$dummy_wallet_address3" &>/dev/null -. "$script_dir/mine-block.sh" 1 "$dummy_wallet_address_fb0" &>/dev/null -. "$script_dir/mine-block.sh" 1 "$dummy_wallet_address_fb959" &>/dev/null . "$script_dir/mine-block.sh" 100 &>/dev/null start_maker() { diff --git a/docker/regtest/readme.md b/docker/regtest/readme.md index 318a7d21..de09968d 100644 --- a/docker/regtest/readme.md +++ b/docker/regtest/readme.md @@ -120,7 +120,7 @@ Port mapping overview: | Container | Ports | | --------------------------------------- | ---------------------------------------------- | -| `joinmarket` (ng native) | `28183` (API) | +| `joinmarket` (ng native) | `28183` (API), `28283` (WS), `62601` (obwatch) | | `joinmarket2` (ng standalone) | `29080` (UI), `29183` (API) | | `joinmarket3` (clientserver native) | `30183` (API), `30283` (WS), `30601` (obwatch) | | `joinmarket4` (clientserver standalone) | `31080` (UI, basic auth), `31183` (API) | diff --git a/docker/regtest/tor/conf/torrc b/docker/regtest/tor/conf/torrc index 7a7d630c..6e7ef81a 100644 --- a/docker/regtest/tor/conf/torrc +++ b/docker/regtest/tor/conf/torrc @@ -9,6 +9,11 @@ ControlPort 0.0.0.0:9051 CookieAuthentication 1 CookieAuthFile /var/lib/tor/control_auth_cookie +# Hidden service for JoinMarket reference directory node +HiddenServiceDir /var/lib/tor/ref-directory +HiddenServicePort 5222 172.30.0.20:8080 +HiddenServiceVersion 3 + # Hidden service for JoinMarket NG directory node HiddenServiceDir /var/lib/tor/ng-directory HiddenServicePort 5222 172.30.0.21:5223 diff --git a/docs/developing.md b/docs/developing.md index 1355b4c7..183490e5 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -6,9 +6,9 @@ A place to collect useful information for developers that doesn't really fit els ## JoinMarket Development Environment -For a complete development environment you need a local JoinMarket NG instance that the web UI can interact with. We provide a regtest environment that should give you everything needed to get started developing with JoinMarket NG. You can find details here: [docker/regtest/readme.md](../docker/regtest/readme.md). +For a complete development environment you need a local JoinMarket instance that the web UI can interact with. We provide a regtest environment that should give you everything needed to get started developing with JoinMarket. You can find details here: [docker/regtest/readme.md](../docker/regtest/readme.md). -## Running Jam Against JoinMarket NG +## Running Jam Against JoinMarket-NG Jam v2 can talk directly to a separately running `jmwalletd` / orderbook watcher from `joinmarket-ng`. You do not need to run the Jam regtest compose or the reference implementation for this workflow. @@ -26,7 +26,7 @@ If your separately running joinmarket-ng services use different ports, you can o JAM_BACKEND=joinmarket-ng \ JMWALLETD_API_PORT=28183 \ JMWALLETD_WEBSOCKET_PORT=28283 \ -JMOBWATCH_PORT=8000 \ +JMOBWATCH_PORT=8080 \ npm run dev ``` @@ -86,17 +86,17 @@ By default, the hook will be installed automatically as an [NPM postinstall scri If you're having issues with Husky not using the correct `$PATH`, you may need to setup a `~/.huskyrc` which will let you set up your path before the hook is run. See [here](https://typicode.github.io/husky/#/?id=command-not-found) for more info. -## Running the Web UI Locally and Connecting to a Remote JoinMarket NG Instance +## Running the Web UI Locally and Connecting to a Remote JoinMarket Instance -These instructions assume you want to run the web UI locally and connect it to a JoinMarket NG instance on your RaspiBlitz. +These instructions assume you want to run the web UI locally and connect it to a JoinMarket instance on your RaspiBlitz. The process should be similar for other setups. -If you run the Web UI and JoinMarket NG on the same system, simply skip the SSH tunnel step. +If you run the Web UI and JoinMarket on the same system, simply skip the SSH tunnel step. -### 🚨 Prerequisite: JoinMarket NG +### 🚨 Prerequisite: JoinMarket -To run the web UI locally you need to connect it to a running JoinMarket NG instance. +To run the web UI locally you need to connect it to a running JoinMarket instance. -#### 1. Install JoinMarket NG +#### 1. Install JoinMarket Install [JoininBox](https://github.com/openoms/joininbox) on your [RaspiBlitz](https://github.com/rootzoll/raspiblitz): @@ -104,38 +104,38 @@ Install [JoininBox](https://github.com/openoms/joininbox) on your [RaspiBlitz](h Services > j [BTC JoinMarket+JoininBox menu] ``` -Or follow the JoinMarket NG [installation guide](https://joinmarket-ng.github.io/joinmarket-ng/install/) if you're on another system. +Or follow the JoinMarket [installation guide](https://github.com/JoinMarket-Org/joinmarket-clientserver#quickstart---recommended-installation-method-linux-and-macos-only) if you're on another system. -### 🚨 Prerequisite: JoinMarket NG API Service +### 🚨 Prerequisite: JoinMarket API Service -This app makes use of the JoinMarket NG API. +This app makes use of the JoinMarket RPC API. For this, you will need JoinMarket version 0.9.3 or higher. If needed you can upgrade JoinMarket to the latest commit via the JoininBox menu on your RaspiBlitz: Type `jm` in the command line and select `UPDATE > ADVANCED > JMCOMMIT`. This will install the latest development version from JoinMarket's master branch. #### 2. SSL Certificate -As the joinmarket user on your RaspiBlitz, generate a self-signed certificate for the JoinMarket NG API Service as described [here](https://linuxize.com/post/creating-a-self-signed-ssl-certificate/), and put the certificate and the key in the `~/.joinmarket-ng/ssl/` directory. +As the joinmarket user on your RaspiBlitz, generate a self-signed certificate for the JoinMarket API Service as described [here](https://linuxize.com/post/creating-a-self-signed-ssl-certificate/), and put the certificate and the key in the `~/.joinmarket/ssl/` directory. _Hint:_ To login as the JoinMarket user, you can ssh into your RaspiBlitz, type `jm`, and exit the JoininBox menu. Create the SSL directory: ```bash -(jmvenv) joinmarket@raspberrypi:~ $ mkdir ~/.joinmarket-ng/ssl/ +(jmvenv) joinmarket@raspberrypi:~ $ mkdir ~/.joinmarket/ssl/ ``` Generate the certificate and associated key: ```bash -openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes -out ~/.joinmarket-ng/ssl/cert.pem -keyout ~/.joinmarket-ng/ssl/key.pem +openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes -out ~/.joinmarket/ssl/cert.pem -keyout ~/.joinmarket/ssl/key.pem ``` _Hint:_ You don't have to enter anything meaningful, you can just hit the return key a couple of times. #### 3. API Service -Start the JoinMarket NG [API service](https://joinmarket-ng.github.io/joinmarket-ng/README-jmwalletd/): +Start the JoinMarket [API service](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/JSON-RPC-API-using-jmwalletd.md): ```bash -(jmvenv) joinmarket@raspberrypi:~/joinmarket-ng $ jmwalletd serve +(jmvenv) joinmarket@raspberrypi:~/joinmarket-clientserver/scripts $ python jmwalletd.py ``` You should see the following: diff --git a/eslint.config.js b/eslint.config.js index 24065352..d96a277e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -125,12 +125,6 @@ export default defineConfig( }, }, ], - 'unicorn/number-literal-case': [ - 'error', - { - hexadecimalValue: 'lowercase', - }, - ], 'unicorn/switch-case-braces': ['off'], // TODO: enable 'unicorn/no-null': ['off'], // TODO: enable diff --git a/index.html b/index.html index 46e28189..98330135 100644 --- a/index.html +++ b/index.html @@ -2,12 +2,11 @@ - - + Jam for JoinMarket diff --git a/package-lock.json b/package-lock.json index e386f3e3..555a064a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,167 +1,164 @@ { "name": "jam", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jam", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.0", "license": "MIT", "dependencies": { - "@hookform/resolvers": "5.7.1", - "@joinmarket-webui/joinmarket-ng-api-ts": "1.0.0", - "@noble/hashes": "2.3.0", - "@radix-ui/react-accordion": "1.2.20", - "@radix-ui/react-avatar": "1.2.6", - "@radix-ui/react-checkbox": "1.3.11", - "@radix-ui/react-dialog": "1.1.23", - "@radix-ui/react-dropdown-menu": "2.1.24", - "@radix-ui/react-label": "2.1.15", - "@radix-ui/react-popover": "1.1.23", - "@radix-ui/react-radio-group": "1.4.7", - "@radix-ui/react-select": "2.3.7", - "@radix-ui/react-separator": "1.1.15", - "@radix-ui/react-slider": "1.4.7", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-switch": "1.3.7", - "@radix-ui/react-tabs": "1.1.21", - "@radix-ui/react-tooltip": "1.2.16", + "@hookform/resolvers": "5.4.0", + "@joinmarket-webui/joinmarket-api-ts": "0.3.0", + "@noble/hashes": "2.2.0", + "@radix-ui/react-accordion": "1.2.14", + "@radix-ui/react-avatar": "1.2.0", + "@radix-ui/react-checkbox": "1.3.5", + "@radix-ui/react-dialog": "1.1.17", + "@radix-ui/react-dropdown-menu": "2.1.18", + "@radix-ui/react-label": "2.1.10", + "@radix-ui/react-popover": "1.1.17", + "@radix-ui/react-radio-group": "1.4.1", + "@radix-ui/react-select": "2.3.1", + "@radix-ui/react-separator": "1.1.10", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-switch": "1.3.1", + "@radix-ui/react-tabs": "1.1.15", + "@radix-ui/react-tooltip": "1.2.10", "@scure/bip32": "2.2.0", "@scure/bip39": "2.2.0", - "@tailwindcss/vite": "4.3.3", + "@tailwindcss/vite": "4.3.1", "@tanstack/match-sorter-utils": "8.19.4", - "@tanstack/react-query": "5.101.4", + "@tanstack/react-query": "5.101.0", "@tanstack/react-table": "8.21.3", "bitcoin-address-validation": "3.0.0", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "html5-qrcode": "2.3.8", "i18next-browser-languagedetector": "8.2.1", - "lucide-react": "1.30.0", + "lucide-react": "1.20.0", "next-themes": "0.4.6", "qrcode": "1.5.4", - "radix-ui": "1.6.7", - "react": "19.2.8", - "react-dom": "19.2.8", - "react-hook-form": "7.84.0", - "react-i18next": "17.0.11", - "react-router-dom": "7.18.2", + "radix-ui": "1.6.0", + "react": "19.2.7", + "react-dom": "19.2.7", + "react-hook-form": "7.79.0", + "react-i18next": "17.0.8", + "react-router-dom": "7.18.0", "react-use-websocket": "4.13.0", "sonner": "2.0.7", "tailwind-merge": "3.6.0", - "tailwindcss": "4.3.3", + "tailwindcss": "4.3.1", "tw-animate-css": "1.4.0", "yup": "1.7.1", "zustand": "5.0.14" }, "devDependencies": { - "@chromatic-com/storybook": "5.3.0", - "@eslint/js": "9.39.5", - "@playwright/test": "1.62.0", - "@storybook/addon-a11y": "10.5.7", - "@storybook/addon-docs": "10.5.7", - "@storybook/addon-vitest": "10.5.7", - "@storybook/react-vite": "10.5.7", - "@tanstack/eslint-plugin-query": "5.101.4", - "@testing-library/jest-dom": "7.0.0", + "@chromatic-com/storybook": "5.2.1", + "@eslint/js": "9.39.4", + "@playwright/test": "1.61.0", + "@storybook/addon-a11y": "10.4.6", + "@storybook/addon-docs": "10.4.6", + "@storybook/addon-vitest": "10.4.6", + "@storybook/react-vite": "10.4.6", + "@tanstack/eslint-plugin-query": "5.101.0", + "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "16.3.2", - "@testing-library/user-event": "14.6.3", + "@testing-library/user-event": "14.6.1", "@trivago/prettier-plugin-sort-imports": "6.0.2", - "@types/node": "26.1.2", + "@types/node": "24.12.4", "@types/qrcode": "1.5.6", - "@types/react": "19.2.18", - "@types/react-dom": "19.2.4", - "@vitejs/plugin-react": "6.0.5", - "@vitest/browser": "4.1.10", - "@vitest/browser-playwright": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "conventional-changelog": "8.1.1", - "eslint": "9.39.5", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", + "@vitejs/plugin-react": "6.0.2", + "@vitest/browser": "4.1.9", + "@vitest/browser-playwright": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "conventional-changelog": "7.2.0", + "eslint": "9.39.4", "eslint-plugin-compat": "7.0.2", "eslint-plugin-react-hooks": "7.1.1", "eslint-plugin-react-refresh": "0.5.3", - "eslint-plugin-storybook": "10.5.7", - "eslint-plugin-unicorn": "65.0.1", - "globals": "17.9.0", + "eslint-plugin-storybook": "10.4.6", + "eslint-plugin-unicorn": "64.0.0", + "globals": "17.6.0", "husky": "9.1.7", - "jsdom": "30.0.1", - "lint-staged": "17.3.0", - "msw": "2.15.0", - "msw-storybook-addon": "3.0.0", - "prettier": "3.9.6", - "prettier-plugin-tailwindcss": "0.8.1", - "storybook": "10.5.7", + "jsdom": "29.1.1", + "lint-staged": "17.0.7", + "msw": "2.14.6", + "msw-storybook-addon": "2.0.7", + "prettier": "3.8.4", + "prettier-plugin-tailwindcss": "0.8.0", + "storybook": "10.4.6", "typescript": "6.0.3", - "typescript-eslint": "8.66.0", - "vite": "8.2.1", - "vitest": "4.1.10" + "typescript-eslint": "8.61.1", + "vite": "8.0.16", + "vitest": "4.1.9" }, "engines": { - "node": ">=26.3.0", - "npm": ">=11.16.0" + "node": ">=24.11.1", + "npm": ">=11.6.2" } }, "node_modules/@adobe/css-tools": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", - "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", "dev": true, "license": "MIT" }, "node_modules/@asamuzakjp/css-color": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-6.0.5.tgz", - "integrity": "sha512-mbhpPMmnw/kwW19aRNmSUl1QzLbdGo1SCuE49BT98MNwqF6zaHb3o2owssFc/PEO/4t2UjqtCNwocuDtJornzA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^3.2.1", - "@csstools/css-color-parser": "^4.1.9", + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "lru-cache": "^11.5.2" + "@csstools/css-tokenizer": "^4.0.0" }, "engines": { - "node": "^22.13.0 || >=24.0.0" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-8.3.0.tgz", - "integrity": "sha512-UJLfKXBhrc8i1vH2eJXuYQMwlsLKWFw3O+CPqXSuVEiikeAim3UgrfWX0k4tA/X8cRFM8iZ7OaqBokFGbYusdg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", "dev": true, "license": "MIT", "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.5.2" + "is-potential-custom-element-name": "^1.0.1" }, "engines": { - "node": "^22.13.0 || >=24.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -375,9 +372,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -462,14 +459,14 @@ } }, "node_modules/@chromatic-com/storybook": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-5.3.0.tgz", - "integrity": "sha512-gMAfVYJnF/tjdY8C3Q54KYz/low2NFjPIZMpCqSFuMUiTJ2DNWCTb7mFhuuzZ1iduWFDhewlJyilFmvKcEDYRA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-5.2.1.tgz", + "integrity": "sha512-z6I7NJk/0VngA64y5TNYaB4Hc2X8+90n4op6lBt9PvWk5TmIlFLDqdX33rlrwbNRkkYijVgA/wO04rVYXi5Mlg==", "dev": true, "license": "MIT", "dependencies": { "@neoconfetti/react": "^1.0.0", - "chromatic": "^18.0.1", + "chromatic": "16.10.0", "jsonfile": "^6.1.0", "strip-ansi": "^7.1.0" }, @@ -482,22 +479,22 @@ } }, "node_modules/@conventional-changelog/git-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.1.0.tgz", - "integrity": "sha512-Tqa/gHco2WJWa740NRjOrfKVvzIqxkZpecb8bemaQ8sKM5PXb1UK4uTyTb/1wIqNuOVaDOFxyBdhTIQZn6gdjQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", + "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", "dev": true, "license": "MIT", "dependencies": { - "@simple-libs/child-process-utils": "^2.0.0", - "@simple-libs/stream-utils": "^2.0.0", + "@simple-libs/child-process-utils": "^1.0.0", + "@simple-libs/stream-utils": "^1.2.0", "semver": "^7.5.2" }, "engines": { - "node": ">=22" + "node": ">=18" }, "peerDependencies": { - "conventional-commits-filter": "^6.0.1", - "conventional-commits-parser": "^7.0.1" + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.4.0" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -508,20 +505,10 @@ } } }, - "node_modules/@conventional-changelog/template": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.2.1.tgz", - "integrity": "sha512-TzlTVpKPjaqW6qOYjQcYUDuGsLCNsvFHVBXkYGTAnf5V37jCWrE5haKNXzz0WZUtVHjrpV76L1buANjwXMfT8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22" - } - }, "node_modules/@csstools/color-helpers": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", - "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -539,9 +526,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", - "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", "dev": true, "funding": [ { @@ -563,9 +550,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", - "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz", + "integrity": "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==", "dev": true, "funding": [ { @@ -579,8 +566,8 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.1.0", - "@csstools/css-calc": "^3.3.0" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.1" }, "engines": { "node": ">=20.19.0" @@ -614,9 +601,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", - "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", + "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", "dev": true, "funding": [ { @@ -659,20 +646,30 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "license": "MIT", "optional": true, "dependencies": { @@ -1150,9 +1147,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -1200,9 +1197,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { @@ -1212,7 +1209,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.3.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, @@ -1223,27 +1220,10 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -1264,13 +1244,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -1285,9 +1258,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { @@ -1322,9 +1295,9 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", - "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", "dev": true, "license": "MIT", "engines": { @@ -1340,31 +1313,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", - "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.12" + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/dom": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", - "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.8.0", - "@floating-ui/utils": "^0.2.12" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", - "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.8.0" + "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", @@ -1372,119 +1345,21 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", - "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, "node_modules/@hookform/resolvers": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.7.1.tgz", - "integrity": "sha512-8wS/P4UDr5sQDe4nFaV51TVyfDPrWgNIXweqG0Bs9Z5LSuzKLb+RQNPvkN2oHM5SRrJyWrVH/F+LOUcFjUyvwQ==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.4.0.tgz", + "integrity": "sha512-EIsqr/t/qbinPIhGjMdtvutIN1Kk4uwbROE9/UQ93CAVGR7GkA7Y92+fX80OzXi/OB67jVFYwKGO1WzkxmkFZw==", "license": "MIT", "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { - "@sinclair/typebox": ">=0.25.24", - "@standard-schema/spec": "^1.0.0", - "@typeschema/main": ">=0.13.7", - "@vinejs/vine": "^2.0.0 || ^3.0.0 || ^4.0.0", - "ajv": "^8.12.0", - "ajv-errors": "^3.0.0", - "ajv-formats": "^2.1.1", - "arktype": "^2.0.0", - "ata-validator": "^1.2.0", - "class-transformer": ">=0.4.0", - "class-validator": ">=0.12.0", - "computed-types": "^1.0.0", - "effect": "^3.10.3", - "fluentvalidation-ts": "^3.0.0", - "fp-ts": "^2.7.0", - "io-ts": "^2.0.0", - "joi": "^17.0.0", - "nope-validator": ">=0.12.0", - "react-hook-form": "^7.55.0", - "superstruct": ">=0.12.0", - "typanion": "^3.3.2", - "valibot": ">=0.31.0 || ^1.0.0-beta.4 || ^1.0.0-rc", - "vest": ">=3.0.0", - "yup": "^1.0.0", - "zod": "^3.25.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "@sinclair/typebox": { - "optional": true - }, - "@standard-schema/spec": { - "optional": true - }, - "@typeschema/main": { - "optional": true - }, - "@vinejs/vine": { - "optional": true - }, - "ajv": { - "optional": true - }, - "ajv-errors": { - "optional": true - }, - "ajv-formats": { - "optional": true - }, - "arktype": { - "optional": true - }, - "ata-validator": { - "optional": true - }, - "class-transformer": { - "optional": true - }, - "class-validator": { - "optional": true - }, - "computed-types": { - "optional": true - }, - "effect": { - "optional": true - }, - "fluentvalidation-ts": { - "optional": true - }, - "fp-ts": { - "optional": true - }, - "io-ts": { - "optional": true - }, - "joi": { - "optional": true - }, - "nope-validator": { - "optional": true - }, - "superstruct": { - "optional": true - }, - "typanion": { - "optional": true - }, - "valibot": { - "optional": true - }, - "vest": { - "optional": true - }, - "yup": { - "optional": true - }, - "zod": { - "optional": true - } + "react-hook-form": "^7.55.0" } }, "node_modules/@humanfs/core": { @@ -1640,18 +1515,13 @@ } } }, - "node_modules/@joinmarket-webui/joinmarket-ng-api-ts": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@joinmarket-webui/joinmarket-ng-api-ts/-/joinmarket-ng-api-ts-1.0.0.tgz", - "integrity": "sha512-/6ykwDbQiSgENLv3il/mqH+M7qIY8dse1Jj8ZkUMbwBKjaO9Knis18CSXL+xrorkJYnXQZ5omNAxrLMMQgjREQ==", + "node_modules/@joinmarket-webui/joinmarket-api-ts": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@joinmarket-webui/joinmarket-api-ts/-/joinmarket-api-ts-0.3.0.tgz", + "integrity": "sha512-Ta7C+jTIHz8zt7kzrdVPH7g0AXUQj7G15VWxGCloYjlTyQofmGwm4cCMXuJYVuybp5qbxPLQilgeyqkY4gJZIQ==", "license": "MIT", - "peerDependencies": { - "@tanstack/react-query": "$@tanstack/react-query" - }, - "peerDependenciesMeta": { - "@tanstack/react-query": { - "optional": true - } + "optionalDependencies": { + "@tanstack/react-query": "5.90.9" } }, "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { @@ -1770,13 +1640,13 @@ "license": "MIT" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.3" + "@tybys/wasm-util": "^0.10.1" }, "funding": { "type": "github", @@ -1809,7 +1679,7 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { + "node_modules/@noble/hashes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", @@ -1821,18 +1691,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/hashes": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz", - "integrity": "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@open-draft/deferred-promise": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-3.0.0.tgz", @@ -1985,9 +1843,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2005,9 +1860,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2025,9 +1877,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2045,9 +1894,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2065,9 +1911,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2085,9 +1928,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2105,9 +1945,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2125,9 +1962,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2173,6 +2007,29 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@oxc-parser/binding-win32-arm64-msvc": { "version": "0.127.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.127.0.tgz", @@ -2235,9 +2092,9 @@ } }, "node_modules/@oxc-resolver/binding-android-arm-eabi": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.24.2.tgz", - "integrity": "sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.20.0.tgz", + "integrity": "sha512-IjfWOXRgJFNdORDl+Uf1aibNgZY2guOD3zmOhx1BGVb/MIiqlFTdmjpQNplSN58lhWehnX4UNqC3QwpUo8pjJg==", "cpu": [ "arm" ], @@ -2249,9 +2106,9 @@ ] }, "node_modules/@oxc-resolver/binding-android-arm64": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.24.2.tgz", - "integrity": "sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.20.0.tgz", + "integrity": "sha512-QqslZAuFQG8Q9xm7JuIn8JUbvywhSBMVhuQHtYW+auirZJloS41oxUUaBXk7uUhZJgp44c5zQLeVvmFaDQB+2Q==", "cpu": [ "arm64" ], @@ -2263,9 +2120,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.24.2.tgz", - "integrity": "sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.20.0.tgz", + "integrity": "sha512-MUcavykj2ewlR+kc5arpg4tC2RvzJkUxWtNv74pf7lcNk00GpIpN43vXMj+j6r4eMmfZhlb8hueKoIb8e9kAGQ==", "cpu": [ "arm64" ], @@ -2277,9 +2134,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.24.2.tgz", - "integrity": "sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.20.0.tgz", + "integrity": "sha512-BGB16nRUK5Etiv//ihPyzj8Lj1px0mhh4YIfe0FDf045ywknfSm0GEbiRESpr6Q4K82AvnyaRIhhluHByvS4bg==", "cpu": [ "x64" ], @@ -2291,9 +2148,9 @@ ] }, "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.24.2.tgz", - "integrity": "sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.20.0.tgz", + "integrity": "sha512-JZgtePaqj3qmD5XFHJaSLWzHRxQu0LaPkdoM1KJXYADvAaa83ijXHclV3ej3CueeW0wxfIAbGCZVP45J0CA7uQ==", "cpu": [ "x64" ], @@ -2305,9 +2162,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.24.2.tgz", - "integrity": "sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.20.0.tgz", + "integrity": "sha512-hOQ/p3ry3v3SchUBXicrrnszaI/UmYzM4wtS4RGfwgVUX7a+HbyQSzJ5aOzu+o6XZkFkS3ZXN4PZAzhOb77OSg==", "cpu": [ "arm" ], @@ -2319,9 +2176,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.24.2.tgz", - "integrity": "sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.20.0.tgz", + "integrity": "sha512-2ArPksaw0AqeuGBfoS715VF+JvJQAhD2niWgjE5hVO+L+nAfikVQopvngCMX9x4BD8itWoQ3dnikrQyl5Ho5Jg==", "cpu": [ "arm" ], @@ -2333,16 +2190,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.24.2.tgz", - "integrity": "sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.20.0.tgz", + "integrity": "sha512-0bJnmYFp62JdZ4nVMDUZ/C58BCZOCcqgKtnUlp7L9Ojf/czIN+3j72YlLPeWLkzlr6SlYvIQA4SGV/HyO0d+qg==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2350,16 +2204,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.24.2.tgz", - "integrity": "sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.20.0.tgz", + "integrity": "sha512-wKHHzPKZo7Ufhv/Bt6yxT7FOgnIgW4gwXcJUipkShGp68W3wGVqvr1Sr0fY65lN0Oy6y41+g2kIDvkgZaMMUkw==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2367,16 +2218,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.24.2.tgz", - "integrity": "sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.20.0.tgz", + "integrity": "sha512-RN8goF7Ie0B79L4i4G6OeBocTgSC56vJbQ65VJje+oXnldVpLnOU7j/AQ/dP94TcCS+Yh6WG8u3Qt4ETteXFNQ==", "cpu": [ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2384,16 +2232,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.24.2.tgz", - "integrity": "sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.20.0.tgz", + "integrity": "sha512-5l1yU6/xQEqLZRzxqmMxJfWPslpwCmBsdDGaBvABPehxquCXDC7dd7oraNdKSJUMDXSM7VvVj8H2D2FTjU7oWw==", "cpu": [ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2401,16 +2246,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.24.2.tgz", - "integrity": "sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.20.0.tgz", + "integrity": "sha512-xHEvkbgz6UC+A3JOyDQy76LkUaxsNSfIr3/GV8slwZsnuooJiIB34gzJfsyvR4JdCYNUUPsRJc/w/oWkODu+hg==", "cpu": [ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2418,16 +2260,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.24.2.tgz", - "integrity": "sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.20.0.tgz", + "integrity": "sha512-aWPDUUmSeyHvlW+SoEUd+JIJsQhVhu6a5tBpDRMu058naPAchTgAVGCFy35zjbnFlt0i8hLWziff6HX0D3LU4g==", "cpu": [ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2435,16 +2274,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.24.2.tgz", - "integrity": "sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.20.0.tgz", + "integrity": "sha512-x2YeSimvhJjKLVD8KSu8f/rqU1potcdEMkApIPJqjZWN7c2Fpt4g2X32WDg1p+XDAmyT7nuQGe0vnhvXeLbH+g==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2452,16 +2288,13 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.24.2.tgz", - "integrity": "sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.20.0.tgz", + "integrity": "sha512-kcRLEIxpZefeYfLChjpgFf3ilBzRDZ+yobMrpRsQlSrxuFGtm3U6PMU7AaEpMqo3NfDGVyJJseAjnRLzMFHjwQ==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2469,9 +2302,9 @@ ] }, "node_modules/@oxc-resolver/binding-openharmony-arm64": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.24.2.tgz", - "integrity": "sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.20.0.tgz", + "integrity": "sha512-HHcfnApSZGtKhTiHqe8OZruOZe5XuFQH5/E0Yhj3u8fnFvzkM4/k6WjacUf4SvA0SPEAbfbgYmVPuo0VX/fIBQ==", "cpu": [ "arm64" ], @@ -2483,9 +2316,9 @@ ] }, "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.24.2.tgz", - "integrity": "sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.20.0.tgz", + "integrity": "sha512-Tn0y1XOFYHNfK1wp1Z5QK8Rcld/bsOwRISQXfqAZ5IBpv8Gz1IvV39fUWNprqNdRizgcvFhOzWwFun2zkJsyBg==", "cpu": [ "wasm32" ], @@ -2493,41 +2326,30 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.11.2", - "@emnapi/runtime": "1.11.2", - "@napi-rs/wasm-runtime": "^1.1.6" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.2", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -2536,9 +2358,9 @@ } }, "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.24.2.tgz", - "integrity": "sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.20.0.tgz", + "integrity": "sha512-qPi25YNPe4YenS8MgsQU2+bIFHxxpLx1LVna2444cEHqNPhNjvWf9zqj4aWE43H9LpAsTmkkAlA3eL5ElBU3mA==", "cpu": [ "arm64" ], @@ -2550,9 +2372,9 @@ ] }, "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.24.2.tgz", - "integrity": "sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.20.0.tgz", + "integrity": "sha512-Wb14jWEW8huH6It9F6sXd9vrYmIS7pMrgkU6sxpLxkP+9z+wRgs71hUEhRpcn8FOXAFa27FVWfY2tRpbfTzfLw==", "cpu": [ "x64" ], @@ -2564,19 +2386,19 @@ ] }, "node_modules/@playwright/test": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.0.tgz", - "integrity": "sha512-9zOJ6ZQRAena31MpOH9VSzIz8Ou3YJ/wtY/eQm5T2uhfhG7/U3COrMS8xOtUrZrp9OgdmzEnIYODye3nY1VqzA==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.0.tgz", + "integrity": "sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.62.0" + "playwright": "1.61.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/@polka/url": { @@ -2587,24 +2409,24 @@ "license": "MIT" }, "node_modules/@radix-ui/number": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.3.tgz", - "integrity": "sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.2.tgz", + "integrity": "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==", "license": "MIT" }, "node_modules/@radix-ui/primitive": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz", - "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz", + "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==", "license": "MIT" }, "node_modules/@radix-ui/react-accessible-icon": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.15.tgz", - "integrity": "sha512-WTQwcAvQf5sOcuUyi90lKPbhwcvQ+j55cjrSmeaN+L2vKU3DooOvlKw2MDeiJ5IkV5N905KW0/fGojKOBhD11A==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.10.tgz", + "integrity": "sha512-TraSwZUqTcVbiDV2/RXzAXC7aeVVXchq0daPFZE7zAxYFaMzjOUggLOfQH9KFLgRizuwVKZO/crveV1eeO3/ZQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-visually-hidden": "1.2.11" + "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", @@ -2622,20 +2444,20 @@ } }, "node_modules/@radix-ui/react-accordion": { - "version": "1.2.20", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.20.tgz", - "integrity": "sha512-jDhG9FvAEnlhnjrsINbNXcUa4G+L1KqSkJSunkbKEzFRcAb52jvM0PjPxPRvhe1HNc5F5yc0yzzWeeqlH4yBIg==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.14.tgz", + "integrity": "sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collapsible": "1.1.20", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collapsible": "1.1.14", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -2653,16 +2475,16 @@ } }, "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.23.tgz", - "integrity": "sha512-VAYOiQRqj3GPpYJE0I9J+X8Ip05cyVlNdKOFeiGS2Ou1HHGfpl0BxOyZm6nmVDyU+W+NF3/XLzmjHmVGydhwgA==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.17.tgz", + "integrity": "sha512-563ygGeyWPrxyVCNp7OV4rE2aIXhFPknpFyo4wbDlcyMMPZ6ySh+zC5WTvY0ZFLgPTg/QB6tA8PyDQyJ2b4cPg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dialog": "1.1.23", - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dialog": "1.1.17", + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -2680,12 +2502,12 @@ } }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz", - "integrity": "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.10.tgz", + "integrity": "sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -2703,12 +2525,12 @@ } }, "node_modules/@radix-ui/react-aspect-ratio": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.15.tgz", - "integrity": "sha512-fy+dyVR+90nelK8rqIznFlxzx7uPcGbhxH8Nfr2bHb4UfSe+e3hklOC0luK0hDwVwnRX7xTRySpsrQVeW+/oNQ==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.10.tgz", + "integrity": "sha512-kbI7NrqhDeuytYrq7JjAsoXczvL8wgj2tc1MyaYWm+50bMKHCHQtVWCryslx4cCpmCTTkBcwQckE4CmmGV2haQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -2726,17 +2548,16 @@ } }, "node_modules/@radix-ui/react-avatar": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.2.6.tgz", - "integrity": "sha512-4ULOTJ/mqy2hT9GlWa/MFHxHSvH3nJzHnZM1waNsc5Bonv7i70aNenghXmD97S6OJ81ekXONGGt4nT1r0PfEdA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.2.0.tgz", + "integrity": "sha512-am/CwltXtmtdtP+5FbYblYDnMa/zuKcMJP1i3/SJMDXXfj2mG+BTqLH2wucqeyyiQMursUtg/5cK+Nh2pCaSOA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-is-hydrated": "0.1.3", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -2754,18 +2575,19 @@ } }, "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.11.tgz", - "integrity": "sha512-Gnptr9pDDQxD3hgq2dtPbtrp/c2qH1mBwIzw3X/ivrMb2e1t0jMTi606fVEqFPaQR1ggXIVQWKj3P2WW9v7zGQ==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.5.tgz", + "integrity": "sha512-pREzrmNnVwGvYaBoM64huTRK7B3lrTRuwj8A9nwhPiEtMb+yudiWh6zWAqEtP0Dzd5+iBa1Ki7V1pCxV8ExMdA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-size": "1.1.4" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -2783,19 +2605,19 @@ } }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.20.tgz", - "integrity": "sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.14.tgz", + "integrity": "sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -2813,15 +2635,15 @@ } }, "node_modules/@radix-ui/react-collection": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.15.tgz", - "integrity": "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.10.tgz", + "integrity": "sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-slot": "1.3.3" + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -2839,9 +2661,9 @@ } }, "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", - "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", + "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2854,9 +2676,9 @@ } }, "node_modules/@radix-ui/react-context": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.2.tgz", - "integrity": "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz", + "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2869,16 +2691,16 @@ } }, "node_modules/@radix-ui/react-context-menu": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.3.7.tgz", - "integrity": "sha512-CtXP35dxaB5T3zXSd+E3uHe/QpXcpYnZmxp6OaIbfthtfW4wyb77M23BG+bwIJDtsMwEP/YssdsmNyZu7jhWew==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.3.1.tgz", + "integrity": "sha512-XbrxS68W5dyiE4fAb96yvJwSVU5x66B20A99sD5Mk3xSWK/LqeOnx6TZnim1KieMjXS/CTFq8reOAjWxas2G8Q==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-menu": "2.1.24", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -2896,24 +2718,23 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz", - "integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.17.tgz", + "integrity": "sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-focus-guards": "1.1.6", - "@radix-ui/react-focus-scope": "1.1.16", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -2933,9 +2754,9 @@ } }, "node_modules/@radix-ui/react-direction": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.4.tgz", - "integrity": "sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", + "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2948,16 +2769,16 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz", - "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.13.tgz", + "integrity": "sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-effect-event": "0.0.5" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-escape-keydown": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -2975,18 +2796,18 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.24.tgz", - "integrity": "sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g==", + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.18.tgz", + "integrity": "sha512-PZGV82gFk0WltDRI//SsG28ZIjlo9ANTmoNYg0jLNzXXiDsAy5PkOOYQaVD1pPxY6t7gxffb1QMD6qaUvsBZdw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-menu": "2.1.24", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3004,9 +2825,9 @@ } }, "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz", - "integrity": "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", + "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3019,14 +2840,14 @@ } }, "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz", - "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.10.tgz", + "integrity": "sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4" + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3044,17 +2865,17 @@ } }, "node_modules/@radix-ui/react-form": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.16.tgz", - "integrity": "sha512-Q4TLEn2A7TAypxwmd6R9EwrlXDvkfYSDMrq9/887AXAGh+G1rH+kYJKSTv+Si9Y0JPKTwKYv6PviAJosysNimA==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.10.tgz", + "integrity": "sha512-1NfuvctVtX4sU3Mmq/IdrR8UunxiCMiVg3A5UENKhFzxUBeOyaQQ+lmaQaV7Tc8cqvBKsJL3/KGBsixK0D8WFg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-label": "2.1.15", - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-label": "2.1.10", + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -3072,20 +2893,20 @@ } }, "node_modules/@radix-ui/react-hover-card": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.23.tgz", - "integrity": "sha512-H8qONfZd3ltrU3+jHCIgITbWo6e1iTKvP9DHdrvYbX48ooRM5FjEDTn16AMwdfuOGkWdZEhpl3PLL/Wk/AnHDQ==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.17.tgz", + "integrity": "sha512-GjZQIEANVkuuWeztlKz6QEHe31ZX2iDfHzcTMCQVZXC0JyQrgfKWSC+LOOEw6aVV64zyjzobIzSA4AU4eKWrHA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-popper": "1.3.7", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3103,12 +2924,12 @@ } }, "node_modules/@radix-ui/react-id": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", - "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz", + "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3121,12 +2942,12 @@ } }, "node_modules/@radix-ui/react-label": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.15.tgz", - "integrity": "sha512-o/rdYEwZTTo5tjknnPeyQFU45kUC4i/XyeDPP+HGyi6XqpOP6Zf5Ya5vh/Yfe9Id5JiuWnnAx2XqIeD3UYZt0g==", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.10.tgz", + "integrity": "sha512-ib0zvq2ZsAqKm5tRnqGJn3vOxSgIts5ToxsXT0q1S/GfLD1Zj7UOEnkw8u2w6sRmn47djpQWuSU1DCL1R29/yw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -3144,27 +2965,27 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.24.tgz", - "integrity": "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==", + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.18.tgz", + "integrity": "sha512-lj8Rxjtn6zJq1oSbE/uDtAwCbB9BnxgHD+8MwJMuTh6u1dPamYhW9iuELr/Z8d0D/UysFblYYHeBPwi7T4k0YQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-focus-guards": "1.1.6", - "@radix-ui/react-focus-scope": "1.1.16", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-popper": "1.3.7", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-use-callback-ref": "1.1.4", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -3184,21 +3005,21 @@ } }, "node_modules/@radix-ui/react-menubar": { - "version": "1.1.24", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.24.tgz", - "integrity": "sha512-eeVs0vf7cuqXaM0qLQCPcufImiJNVBXdJDLu7ZGYl2732UH23Qat/foNGrr6vYV3/DdTsBqASoggUFgH14OcZA==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.18.tgz", + "integrity": "sha512-hX7EGx/oFq6DPY27GQuP/2wP48GHf5LG6r06VgNJlG+znmDS8OfopZcRcGly3L4lsB9FqpmLx6JQSE9P3BUpyw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-menu": "2.1.24", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3216,25 +3037,25 @@ } }, "node_modules/@radix-ui/react-navigation-menu": { - "version": "1.2.22", - "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.22.tgz", - "integrity": "sha512-ou7iLEJ+yrhQndkkA4U21XIdS/CS45F4iXIkTZcb6/Ne9EMsOuDudVmCwmDnfFZZ+y1FZqXRNSIgBy+YMvZVZg==", + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.16.tgz", + "integrity": "sha512-nJ0SkrSQgudyYhMiYeHA1ayLVuduEJCFLan1RZZN7c9kqzzCFLaU9kuy81uNtqzweM9YaQPgWzxi9MwQ9jZ04g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-use-previous": "1.1.4", - "@radix-ui/react-visually-hidden": "1.2.11" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", @@ -3252,23 +3073,23 @@ } }, "node_modules/@radix-ui/react-one-time-password-field": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.16.tgz", - "integrity": "sha512-Tj9P6ntAJEw52oq/F0AGknXR4XncxEt7XU47O3xJQOiWfLzEy3d9gtgKfvjSzGxzHkfL+VzvxGu2KTFsloJqXw==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.10.tgz", + "integrity": "sha512-GHkcJ+WVj91At+OvUVTD4R3W0/wxw9t/sG5xFUBYXaCbtWiooZX5Md376QjJqgH4VsVyXrbVNHO2O4NYcmjfVg==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.3", - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-effect-event": "0.0.5", - "@radix-ui/react-use-is-hydrated": "0.1.3", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3286,19 +3107,19 @@ } }, "node_modules/@radix-ui/react-password-toggle-field": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.11.tgz", - "integrity": "sha512-4gvFnmDXu3dgj21CqsufzIameRvlRd4SBqaWhcrlrNhRo0Y5i/49AmRJYe1fdAM3G2VNBbmin4b0D6cdQocwgw==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.5.tgz", + "integrity": "sha512-fVuA82u0b/fClpbEJv8yp1nU9eSvoSEOERsU/hhf3FXGPIvkmE7oEaHEu8poowoXO39/Va7zq2E0TUcYr1dBRg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-effect-event": "0.0.5", - "@radix-ui/react-use-is-hydrated": "0.1.3" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-is-hydrated": "0.1.1" }, "peerDependencies": { "@types/react": "*", @@ -3316,24 +3137,24 @@ } }, "node_modules/@radix-ui/react-popover": { - "version": "1.1.23", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.23.tgz", - "integrity": "sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.17.tgz", + "integrity": "sha512-/YSAOdJ7YJvdn7bn5sdSx2egW+SKY+u7O5RyAVs94Ymrg2fg5QTSFPMRkzvhGyFuE4/qsmPBdrwYoZMZh/4f+g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-focus-guards": "1.1.6", - "@radix-ui/react-focus-scope": "1.1.16", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-popper": "1.3.7", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-use-controllable-state": "1.2.6", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -3353,21 +3174,21 @@ } }, "node_modules/@radix-ui/react-popper": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.7.tgz", - "integrity": "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.1.tgz", + "integrity": "sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-use-rect": "1.1.4", - "@radix-ui/react-use-size": "1.1.4", - "@radix-ui/rect": "1.1.3" + "@radix-ui/react-arrow": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-rect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3385,13 +3206,13 @@ } }, "node_modules/@radix-ui/react-portal": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz", - "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.12.tgz", + "integrity": "sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3409,12 +3230,12 @@ } }, "node_modules/@radix-ui/react-presence": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz", - "integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz", + "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3432,12 +3253,12 @@ } }, "node_modules/@radix-ui/react-primitive": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz", - "integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz", + "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.3.3" + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -3455,13 +3276,13 @@ } }, "node_modules/@radix-ui/react-progress": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.16.tgz", - "integrity": "sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.10.tgz", + "integrity": "sha512-JYzEg60lk79PwKM27WZyKd7PW8O4OM5jOaFfRPfOyeXmMw7tLJh5kSj+CEjVTehszuwml/AdCzPGMXBTGf4BBw==", "license": "MIT", "dependencies": { - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -3479,20 +3300,21 @@ } }, "node_modules/@radix-ui/react-radio-group": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.4.7.tgz", - "integrity": "sha512-cgYFEkntCxppHZgtSZ+7vh0wbZQ+IC7PPMw8DSnRG27B6kDd32/Zw0OJt7dGDigCoprMuWHjg2PvUn3PYvPFoQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.4.1.tgz", + "integrity": "sha512-/SSxZdKEo2Eo29FFRKd06EfFDYp8HryKg0WYg7QLXaydPzl52YfSvCH2a3QDBRdtcuwACroJT8UVjQVgOJ7P9A==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-size": "1.1.4" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3510,22 +3332,20 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz", - "integrity": "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.13.tgz", + "integrity": "sha512-9gkwneI0guf8JDmrFxPjJF6Ozzgioyw+/lonYNCwefS9ZHA05er0BVHiXr+LbWGHxUfczvMY6G1oiZZi1VzjRw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-is-hydrated": "0.1.3", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3543,20 +3363,20 @@ } }, "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.18", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.18.tgz", - "integrity": "sha512-Zn5Cd171wxsO3Dfg8HaW6RifTb9CYTKQJHs/G4+LN1GfmJpaQMZQyQxMprVPHpaz7QY4l9BxK2JwQuzHsXC8nA==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.12.tgz", + "integrity": "sha512-xuafVzQiTCLsyEjakowTdG3OgTXsmO7IdCiO77otIa+z44xoLNs9Do5eg7POFumIOCjtG6djfm6RKUKpUa/csA==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.3", - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3574,31 +3394,31 @@ } }, "node_modules/@radix-ui/react-select": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.7.tgz", - "integrity": "sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.1.tgz", + "integrity": "sha512-w6eDvY78LE9ZUiNnXCA1QVK8RYN7k9galFv09kjVydJqBAgHd7Y9A6h0UJ/6DCZNGZMZrB2ohcSW1Bo9d8+wWA==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.3", - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-focus-guards": "1.1.6", - "@radix-ui/react-focus-scope": "1.1.16", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-popper": "1.3.7", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-use-previous": "1.1.4", - "@radix-ui/react-visually-hidden": "1.2.11", + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, @@ -3618,12 +3438,12 @@ } }, "node_modules/@radix-ui/react-separator": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.15.tgz", - "integrity": "sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.10.tgz", + "integrity": "sha512-Y6K6jLQCVfCnTL2MEtGxDLffkhNfEfHsEg3Wa8JU+IWdn3EWbLXd3OuOfQRN7p/W/cUce1WyTk3QeuAoDBzN9g==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -3641,22 +3461,22 @@ } }, "node_modules/@radix-ui/react-slider": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.4.7.tgz", - "integrity": "sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.4.1.tgz", + "integrity": "sha512-r91WSpQucNGFKAIxT8FT0H0zyjd5tJlqObLp7LOMV4z49KoDCwjy01w3vDOU4e1wxhF9IgjYco7SB6byOW7Buw==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.3", - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-use-previous": "1.1.4", - "@radix-ui/react-use-size": "1.1.4" + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3674,12 +3494,12 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.3.tgz", - "integrity": "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.5" + "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", @@ -3692,17 +3512,18 @@ } }, "node_modules/@radix-ui/react-switch": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.3.7.tgz", - "integrity": "sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.3.1.tgz", + "integrity": "sha512-55bQtCnOB0BohomSHi6qvQXpJEEqUGDm6hRrM0Bph5OXwhSegqkd8IqgBAQkM1IlgUlWZIxpxRcpOEfRIgimyw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-size": "1.1.4" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3720,19 +3541,19 @@ } }, "node_modules/@radix-ui/react-tabs": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.21.tgz", - "integrity": "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.15.tgz", + "integrity": "sha512-kxc9gI6/HfcU4nfMMVS3AmQK414kbU1IE6UCJmMmxjhO3cRPXOyYnmvyKD+ODt7q56nRq9l7Wovi6uaGwKgMlg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3750,23 +3571,23 @@ } }, "node_modules/@radix-ui/react-toast": { - "version": "1.2.23", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.23.tgz", - "integrity": "sha512-ofhyAsYaocRGOs/n0XWdUOSVzEAG6BfrMVM8z0c0kLEWY38w/0WuMFPTJP/HVaZPYkMvHZoKIIhNcjbTCBILPg==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.17.tgz", + "integrity": "sha512-uL4kyyWy000pPL43fGGCV5qT6ZchCWEQZOSlkYiPwPt8Hy1iW38RjeptIvz1/SZesrW6Vn58Ct3sV7tfEfiAbw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-visually-hidden": "1.2.11" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", @@ -3784,14 +3605,14 @@ } }, "node_modules/@radix-ui/react-toggle": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.18.tgz", - "integrity": "sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.12.tgz", + "integrity": "sha512-AsAVsYNZIlRBsci7BhE+QyQeKd1h6TffJYt+lF0QQkd5OpQ3klfIByPsCb4G0h/Fq6PJwh1FYNluzBFYzhk4+w==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3809,18 +3630,18 @@ } }, "node_modules/@radix-ui/react-toggle-group": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.19.tgz", - "integrity": "sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.13.tgz", + "integrity": "sha512-Xb9PLtlvU66F36LiKba6dFswu6V2mDkgidO4fNSbQHQwmZ9ObxMIO17MN/LJ4aWJecVuSVLAHPZjyeMzJrgeiA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-toggle": "1.1.18", - "@radix-ui/react-use-controllable-state": "1.2.6" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-toggle": "1.1.12", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3838,18 +3659,18 @@ } }, "node_modules/@radix-ui/react-toolbar": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.19.tgz", - "integrity": "sha512-Ph0IvtYw4VB12ZnZg+YtrGs8yJQsnizwo/zu0R4Y/nWugtJzA7Pg1eWeuDR9+LSqn+xjamss+UOSOJJJ4gx8jw==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.13.tgz", + "integrity": "sha512-Za1l4f6fzTkGgz/iynAMN8iaqiKff2wm2/QwiLmHPtDQreWEBrvSimgQFIekxMUdRPhILM7xdIXxuS/o/DGZag==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-separator": "1.1.15", - "@radix-ui/react-toggle-group": "1.1.19" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-separator": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.13" }, "peerDependencies": { "@types/react": "*", @@ -3867,24 +3688,23 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.16.tgz", - "integrity": "sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.10.tgz", + "integrity": "sha512-NlNe8D0dWEpVfXFli90IO6X07Josx/b1iu98tDnx9Xv0HT4wLIL+m2VOheMHhK7qbp2HoTBqALEFzGyZs/levw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-id": "1.1.4", - "@radix-ui/react-popper": "1.3.7", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-visually-hidden": "1.2.11" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", @@ -3902,9 +3722,9 @@ } }, "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz", - "integrity": "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", + "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3917,14 +3737,13 @@ } }, "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz", - "integrity": "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", + "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-use-effect-event": "0.0.5", - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3937,12 +3756,12 @@ } }, "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", - "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", + "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3955,12 +3774,12 @@ } }, "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.5.tgz", - "integrity": "sha512-ge3ipobwSXTj4JyVtswQ7qZj0ZHdtbGuOno/LrgAAeSxtsJ6Vs4Gz5IkPH2bmqpjcLUFoqGhA/mueuIf63UXlA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.2.tgz", + "integrity": "sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.4" + "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -3973,9 +3792,9 @@ } }, "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz", - "integrity": "sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.1.tgz", + "integrity": "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3988,9 +3807,9 @@ } }, "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", - "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", + "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -4003,9 +3822,9 @@ } }, "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.4.tgz", - "integrity": "sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.2.tgz", + "integrity": "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -4018,12 +3837,12 @@ } }, "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz", - "integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz", + "integrity": "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==", "license": "MIT", "dependencies": { - "@radix-ui/rect": "1.1.3" + "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -4036,12 +3855,12 @@ } }, "node_modules/@radix-ui/react-use-size": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz", - "integrity": "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz", + "integrity": "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.4" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -4054,12 +3873,12 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz", - "integrity": "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.6.tgz", + "integrity": "sha512-jCE0WljWifTI4niIMCll06kGpsJTAPiZVU9H4WR1N6qW7At9ystHbN7dDB+we2xH535roFHj7qKS+RGj0FMDWQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.10" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -4077,15 +3896,15 @@ } }, "node_modules/@radix-ui/rect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz", - "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.2.tgz", + "integrity": "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==", "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.1.tgz", - "integrity": "sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", "cpu": [ "arm64" ], @@ -4099,9 +3918,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.1.tgz", - "integrity": "sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", "cpu": [ "arm64" ], @@ -4115,9 +3934,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.1.tgz", - "integrity": "sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", "cpu": [ "x64" ], @@ -4131,9 +3950,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.1.tgz", - "integrity": "sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", "cpu": [ "x64" ], @@ -4147,9 +3966,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.1.tgz", - "integrity": "sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", "cpu": [ "arm" ], @@ -4163,15 +3982,12 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.1.tgz", - "integrity": "sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4182,15 +3998,12 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.1.tgz", - "integrity": "sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4201,15 +4014,12 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.1.tgz", - "integrity": "sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4220,15 +4030,12 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.1.tgz", - "integrity": "sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4239,15 +4046,12 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.1.tgz", - "integrity": "sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4258,15 +4062,12 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.1.tgz", - "integrity": "sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4277,9 +4078,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.1.tgz", - "integrity": "sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", "cpu": [ "arm64" ], @@ -4293,76 +4094,48 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.1.tgz", - "integrity": "sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "2.0.0-alpha.3", - "@emnapi/runtime": "2.0.0-alpha.3", - "@napi-rs/wasm-runtime": "^1.2.0" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "2.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz", - "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "2.0.1", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "2.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz", - "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz", - "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.1.tgz", - "integrity": "sha512-KjZdi8Q1wh89gsVmghvbrMgWl6ZWmRmHV6wjB7/g4Zf0dyO+hH3neZUtuDNPO00qq5YE5RITVWvrIZKRaAmzGQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.1.tgz", - "integrity": "sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", "cpu": [ "arm64" ], @@ -4376,9 +4149,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.1.tgz", - "integrity": "sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", "cpu": [ "x64" ], @@ -4398,9 +4171,9 @@ "license": "MIT" }, "node_modules/@rollup/pluginutils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", - "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4443,18 +4216,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@scure/bip39": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.2.0.tgz", @@ -4468,72 +4229,43 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@simple-libs/child-process-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-2.0.0.tgz", - "integrity": "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-1.0.2.tgz", + "integrity": "sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==", "dev": true, "license": "MIT", "dependencies": { - "@simple-libs/stream-utils": "^2.0.0" + "@simple-libs/stream-utils": "^1.2.0" }, "engines": { - "node": ">=22" + "node": ">=18" }, "funding": { "url": "https://ko-fi.com/dangreen" } }, "node_modules/@simple-libs/hosted-git-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@simple-libs/hosted-git-info/-/hosted-git-info-2.0.0.tgz", - "integrity": "sha512-55XwK/GYgV58PuN8lZFhI1qRxdKoMLJocXl/yM1EPqazFDmM4QWY7q6BxPCPDNKTNunj794DSD4h0H7SrqUdMg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@simple-libs/hosted-git-info/-/hosted-git-info-1.0.2.tgz", + "integrity": "sha512-aAmGQdMH+ZinytKuA2832u0ATeOFNYNk4meBEXtB5xaPotUgggYNhq5tYU/v17wEbmTW5P9iHNqNrFyrhnqBAg==", "dev": true, "license": "MIT", "engines": { - "node": ">=22" - }, - "funding": { - "url": "https://ko-fi.com/dangreen" - } - }, - "node_modules/@simple-libs/normalize-package-data": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@simple-libs/normalize-package-data/-/normalize-package-data-1.0.0.tgz", - "integrity": "sha512-/EOmFBekV9tGee8gac/k+5Ox3twkypNqh5TfxA9vTkmcJkjm6f1xqrlstDNOrEhTvnYyVtU6Du2ZhY/IV1+9GA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@simple-libs/hosted-git-info": "^2.0.0", - "semver": "^7.8.5" - }, - "engines": { - "node": ">=22" + "node": ">=18" }, "funding": { "url": "https://ko-fi.com/dangreen" } }, "node_modules/@simple-libs/stream-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-2.0.0.tgz", - "integrity": "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.2.0.tgz", + "integrity": "sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==", "dev": true, "license": "MIT", "engines": { - "node": ">=22" + "node": ">=18" }, "funding": { "url": "https://ko-fi.com/dangreen" @@ -4543,7 +4275,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@standard-schema/utils": { @@ -4553,9 +4285,9 @@ "license": "MIT" }, "node_modules/@storybook/addon-a11y": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-10.5.7.tgz", - "integrity": "sha512-I30rsNz6aA3xg3811MEry40uJDHP3l5SOkfqtmNkp7y4NdqTDdKhmbhhDAZQX1WWEk6GeMBGr3AJ3TCz7r7JmQ==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-10.4.6.tgz", + "integrity": "sha512-XCJy+f0DFOiCgUU9knRDlLDxVFI+AAQ3/wE/NF85zB9iDPPS2DwkSN+mas3zDgHt66zhN8Cq3/UiyCDUweV9Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -4567,20 +4299,20 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^10.5.7" + "storybook": "^10.4.6" } }, "node_modules/@storybook/addon-docs": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-10.5.7.tgz", - "integrity": "sha512-KNARJfjICaizinsR3INMEiipZm1ObYo+xw+E26gteu50Bcy2dIZUtk5uHY5XdtardU3AXX6yRXoBZ2HCY3lbHA==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-10.4.6.tgz", + "integrity": "sha512-aWAfP5JMiT5a3zBJizwroCRzOCqZwDTJmvsYvwMD3ilIEa/kT1vhf6Xrbk4XIPhDwbh8Hpb/Gfnka1xBYEISWg==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "10.5.7", + "@storybook/csf-plugin": "10.4.6", "@storybook/icons": "^2.0.2", - "@storybook/react-dom-shim": "10.5.7", + "@storybook/react-dom-shim": "10.4.6", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -4591,7 +4323,7 @@ }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.5.7" + "storybook": "^10.4.6" }, "peerDependenciesMeta": { "@types/react": { @@ -4600,9 +4332,9 @@ } }, "node_modules/@storybook/addon-vitest": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/addon-vitest/-/addon-vitest-10.5.7.tgz", - "integrity": "sha512-7NK7Kzazc2vb2h8nGlH15QlUn5J6/LV0xF70VziAK0bxu3r1JupLCoBvckX39vHzFXiAZljXZtt1Wq/OidBxow==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-vitest/-/addon-vitest-10.4.6.tgz", + "integrity": "sha512-VvskHge0GZy86LG6kcY5Ww34z8rDV8JBxqSdUpcJVsWfIvyX6MfAbqI76LlereSyBIJGZJZsqaLwRXsQoVY+0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4617,7 +4349,7 @@ "@vitest/browser": "^3.0.0 || ^4.0.0", "@vitest/browser-playwright": "^4.0.0", "@vitest/runner": "^3.0.0 || ^4.0.0", - "storybook": "^10.5.7", + "storybook": "^10.4.6", "vitest": "^3.0.0 || ^4.0.0" }, "peerDependenciesMeta": { @@ -4636,13 +4368,13 @@ } }, "node_modules/@storybook/builder-vite": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.5.7.tgz", - "integrity": "sha512-fShF/aQaITqcJuMCLr42BGNUAbhDi4IboqvlbZqXAwgrrTslnZEUnY8GcEcvpZmjl11VwlmazhMJdH50fIgBPg==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.4.6.tgz", + "integrity": "sha512-BHBtD81HiXUiDQz/CaFynLtWmm7AFUQn8VnXuHipZ8KlnUANopa4yqdVuy/Gwz8ub254uFI5NMZsW/KlgWNgNg==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "10.5.7", + "@storybook/csf-plugin": "10.4.6", "ts-dedent": "^2.0.0" }, "funding": { @@ -4650,14 +4382,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^10.5.7", + "storybook": "^10.4.6", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.5.7.tgz", - "integrity": "sha512-IaX8FlM0H36HNFhJ2+4L9bCldqfvHGqcLg841SJNyK/DhfMlM7JsvY/GDH2ZFuWrUf8FSOx96GRRnHq6XfRKag==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.4.6.tgz", + "integrity": "sha512-NILLxDqpA/JR/AazGWpsz+4fadJwRU4uhHephGtYpVOWnQA/DkJfKT6zpcJVq8+QA8A2zKMLX3GVKsXIrxjuDA==", "dev": true, "license": "MIT", "dependencies": { @@ -4670,7 +4402,7 @@ "peerDependencies": { "esbuild": "*", "rollup": "*", - "storybook": "^10.5.7", + "storybook": "^10.4.6", "vite": "*", "webpack": "*" }, @@ -4697,24 +4429,25 @@ "license": "MIT" }, "node_modules/@storybook/icons": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-2.1.0.tgz", - "integrity": "sha512-Fxh9vYpX9bQqFeHRiY8h2ApeRGDzRSMLwJwNZ/AIRqnyOKHxRKL+yFe+ctEkVJmuptRE9u1Hrn8ZZNHyfDKKNg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-2.0.2.tgz", + "integrity": "sha512-KZBCpXsshAIjczYNXR/rlxEtCUX/eAbpFNwKi8bcOomrLA4t/SyPz5RF+lVPO2oZBUE4sAkt43mfJUevQDSEEw==", "dev": true, "license": "MIT", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@storybook/react": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.5.7.tgz", - "integrity": "sha512-uFvty2MMdFXzW5PcQe1JqDAZkz6cQq7q/9G/cbGVnBEvP6zsOVeL+bmrQ0/WBlFQN0Ko9+ZoCTvaQ9s65zBa5g==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.4.6.tgz", + "integrity": "sha512-9Y7YecrVFe1/01KYjfOLxVqTg2Aq+IO6TEv6sC2U0PfD0AWCSCmQ91QqgBpN/XW4aFFWoiZNinyXMUlU8zxy2w==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "10.5.7", + "@storybook/react-dom-shim": "10.4.6", "react-docgen": "^8.0.2", "react-docgen-typescript": "^2.2.2" }, @@ -4727,7 +4460,7 @@ "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.5.7", + "storybook": "^10.4.6", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -4743,9 +4476,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.5.7.tgz", - "integrity": "sha512-lxOkyh+wu/MiBXvYQHjZfD+DRKOa4bHBzbuGuiHXnHXmdOcTRdcrQTsoeN2FPtfugmmOG66cZUEgDwNX+k5eRA==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.4.6.tgz", + "integrity": "sha512-iGNmKzrq9vgl2PDrYAnZKI+yvac3Ym+lJXXuQaqlFRS23zA5MNm4EBX+rAG7WulqchoK6NaZ0KQOs2mAgEpTMg==", "dev": true, "license": "MIT", "funding": { @@ -4757,7 +4490,7 @@ "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.5.7" + "storybook": "^10.4.6" }, "peerDependenciesMeta": { "@types/react": { @@ -4769,19 +4502,19 @@ } }, "node_modules/@storybook/react-vite": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-10.5.7.tgz", - "integrity": "sha512-eEo3eVa2pvqrzQukKxAzx7YvswDAA1s6k/y+tdMxmRvWyHX6QEOsb9Tda6wcVaa7c8BeJM7Ggq+289cRMTH6Iw==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-10.4.6.tgz", + "integrity": "sha512-0arEQtybqGYXHbXpTot+Wv9YtG+V5Vp43QayXavPKQ20M8mpEzhyCPKd0EhqMGSC1Z1UEt0hm365WUBhI9LfKA==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "^0.7.0", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "10.5.7", - "@storybook/react": "10.5.7", + "@storybook/builder-vite": "10.4.6", + "@storybook/react": "10.4.6", "empathic": "^2.0.0", "magic-string": "^0.30.0", - "react-docgen": "^8.0.2", + "react-docgen": "^8.0.0", "resolve": "^1.22.8", "tsconfig-paths": "^4.2.0" }, @@ -4792,58 +4525,52 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "storybook": "^10.5.7", - "typescript": ">= 4.9.x", + "storybook": "^10.4.6", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, "node_modules/@tailwindcss/node": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", - "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.24.1", + "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.3.3" + "tailwindcss": "4.3.1" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", - "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", "license": "MIT", "engines": { "node": ">= 20" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.3", - "@tailwindcss/oxide-darwin-arm64": "4.3.3", - "@tailwindcss/oxide-darwin-x64": "4.3.3", - "@tailwindcss/oxide-freebsd-x64": "4.3.3", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", - "@tailwindcss/oxide-linux-x64-musl": "4.3.3", - "@tailwindcss/oxide-wasm32-wasi": "4.3.3", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", - "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", "cpu": [ "arm64" ], @@ -4857,9 +4584,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", - "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", "cpu": [ "arm64" ], @@ -4873,9 +4600,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", - "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", "cpu": [ "x64" ], @@ -4889,9 +4616,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", - "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", "cpu": [ "x64" ], @@ -4905,9 +4632,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", - "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", "cpu": [ "arm" ], @@ -4921,15 +4648,12 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", - "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4940,15 +4664,12 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", - "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4959,15 +4680,12 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", - "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4978,15 +4696,12 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", - "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4997,9 +4712,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", - "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -5014,9 +4729,9 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.11.1", - "@emnapi/runtime": "^1.11.1", - "@emnapi/wasi-threads": "^1.2.2", + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" @@ -5026,9 +4741,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", - "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", "cpu": [ "arm64" ], @@ -5042,9 +4757,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", - "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", "cpu": [ "x64" ], @@ -5058,23 +4773,23 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", - "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.1.tgz", + "integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==", "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.3.3", - "@tailwindcss/oxide": "4.3.3", - "tailwindcss": "4.3.3" + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "tailwindcss": "4.3.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "node_modules/@tanstack/eslint-plugin-query": { - "version": "5.101.4", - "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.101.4.tgz", - "integrity": "sha512-jqAZJWXGd5PthJYH9wmC2O5Ry5xAN2/7zxi9qcANQ+Xix8V5JkqNRjZ8Fh+rYzqzVYGiHqbrHekt+uh38OZVpw==", + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.101.0.tgz", + "integrity": "sha512-wsfg821y4yw21J7nKI2oM5yyGSz3vASXqgWbmWCXZpnyY9ObLrBCcXivwZKj4YHF2fUWiqoOIRX2pbE79cf6gQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5111,9 +4826,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.101.4", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.4.tgz", - "integrity": "sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==", + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.0.tgz", + "integrity": "sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==", "license": "MIT", "funding": { "type": "github", @@ -5121,12 +4836,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.101.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.4.tgz", - "integrity": "sha512-yRg2pfOCxIs4ZJW3XYYHU/WgtD04FHSnfHlpRT7h7pR77hwkdRG4wxbKe4aq6P0RvXUTBSQpQeadS1SUYUe+KA==", + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.0.tgz", + "integrity": "sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.101.4" + "@tanstack/query-core": "5.101.0" }, "funding": { "type": "github", @@ -5175,6 +4890,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -5190,9 +4906,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-7.0.0.tgz", - "integrity": "sha512-HKAH9C6mBo5yBG6yRO5i43L2iisencAo5z+o5P/saHUoY+miC5ivXRxHBJcFyB5ypPNxHJdK3BoF/3O4DIptMg==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", "dev": true, "license": "MIT", "dependencies": { @@ -5204,12 +4920,9 @@ "redent": "^3.0.0" }, "engines": { - "node": ">=22", + "node": ">=14", "npm": ">=6", "yarn": ">=1" - }, - "peerDependencies": { - "@testing-library/dom": ">=10 <11" } }, "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { @@ -5248,9 +4961,9 @@ } }, "node_modules/@testing-library/user-event": { - "version": "14.6.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.3.tgz", - "integrity": "sha512-6dBq67jT8lE+JTE8Exm02Kt6ze43hz1jdiSpSJwtTZiT1xQQ6b7nZYTTQ9njdArdU8XklOwaDp/AbT/eYSKF4g==", + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", "dev": true, "license": "MIT", "engines": { @@ -5303,9 +5016,9 @@ } }, "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "license": "MIT", "optional": true, "dependencies": { @@ -5317,7 +5030,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -5404,22 +5118,29 @@ "license": "MIT" }, "node_modules/@types/mdx": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", - "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "26.1.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", - "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", "devOptional": true, "license": "MIT", "dependencies": { - "undici-types": "~8.3.0" + "undici-types": "~7.16.0" } }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/qrcode": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz", @@ -5431,9 +5152,9 @@ } }, "node_modules/@types/react": { - "version": "19.2.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", - "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5441,9 +5162,9 @@ } }, "node_modules/@types/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -5475,17 +5196,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", - "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz", + "integrity": "sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/type-utils": "8.66.0", - "@typescript-eslint/utils": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/type-utils": "8.61.1", + "@typescript-eslint/utils": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -5498,15 +5219,15 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.66.0", + "@typescript-eslint/parser": "^8.61.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -5514,16 +5235,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", - "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.1.tgz", + "integrity": "sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", "debug": "^4.4.3" }, "engines": { @@ -5539,14 +5260,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", - "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", + "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.66.0", - "@typescript-eslint/types": "^8.66.0", + "@typescript-eslint/tsconfig-utils": "^8.61.1", + "@typescript-eslint/types": "^8.61.1", "debug": "^4.4.3" }, "engines": { @@ -5561,14 +5282,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz", - "integrity": "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", + "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0" + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5579,9 +5300,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", - "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", + "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", "dev": true, "license": "MIT", "engines": { @@ -5596,15 +5317,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", - "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz", + "integrity": "sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/utils": "8.66.0", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -5621,9 +5342,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz", - "integrity": "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", + "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", "dev": true, "license": "MIT", "engines": { @@ -5635,16 +5356,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", - "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", + "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.66.0", - "@typescript-eslint/tsconfig-utils": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", + "@typescript-eslint/project-service": "8.61.1", + "@typescript-eslint/tsconfig-utils": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/visitor-keys": "8.61.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -5673,26 +5394,26 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.8" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -5702,16 +5423,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", - "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", + "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0" + "@typescript-eslint/scope-manager": "8.61.1", + "@typescript-eslint/types": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5726,13 +5447,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz", - "integrity": "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", + "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/types": "8.61.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -5757,13 +5478,13 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz", - "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "^1.0.1" + "@rolldown/pluginutils": "^1.0.0" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -5783,15 +5504,15 @@ } }, "node_modules/@vitest/browser": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", - "integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.9.tgz", + "integrity": "sha512-j1BKtWmPcqpMhmx/L9EPLgAJpCb0zKfwoWLmqBbxaogCXHjOwHFSEoHCBfnGtx93xKQwilZ26m+UOsHqHMkRNg==", "dev": true, "license": "MIT", "dependencies": { "@blazediff/core": "1.9.1", - "@vitest/mocker": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/mocker": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pngjs": "^7.0.0", "sirv": "^3.0.2", @@ -5802,18 +5523,18 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "4.1.10" + "vitest": "4.1.9" } }, "node_modules/@vitest/browser-playwright": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.10.tgz", - "integrity": "sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.9.tgz", + "integrity": "sha512-Bq1rOGf9waevzG3EOkO/dene6bvKTUsZMVg8S1i+WH3JcMjuXEjiahP9rAqZRELUqjBySOJsvvSWqK/B3wjKQw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/browser": "4.1.10", - "@vitest/mocker": "4.1.10", + "@vitest/browser": "4.1.9", + "@vitest/mocker": "4.1.9", "tinyrainbow": "^3.1.0" }, "funding": { @@ -5821,7 +5542,7 @@ }, "peerDependencies": { "playwright": "*", - "vitest": "4.1.10" + "vitest": "4.1.9" }, "peerDependenciesMeta": { "playwright": { @@ -5830,14 +5551,14 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", - "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.9.tgz", + "integrity": "sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.9", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -5851,8 +5572,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.10", - "vitest": "4.1.10" + "@vitest/browser": "4.1.9", + "vitest": "4.1.9" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -5929,13 +5650,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", + "@vitest/spy": "4.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -5966,9 +5687,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", "dev": true, "license": "MIT", "dependencies": { @@ -5979,13 +5700,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.10", + "@vitest/utils": "4.1.9", "pathe": "^2.0.3" }, "funding": { @@ -5993,14 +5714,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -6009,9 +5730,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", "dev": true, "license": "MIT", "funding": { @@ -6019,13 +5740,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", + "@vitest/pretty-format": "4.1.9", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -6041,9 +5762,9 @@ "license": "MIT" }, "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -6063,6 +5784,39 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6094,19 +5848,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/argue-cli": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/argue-cli/-/argue-cli-3.1.0.tgz", - "integrity": "sha512-DhBpBfXL4SS2uC0N922MMajKR3CdrTG0u2or1PNYgXMsrSzViJrbtvT0nCLlLGUI0plam/ZZCs7aAauHtW9thw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22" - }, - "funding": { - "url": "https://ko-fi.com/dangreen" - } - }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", @@ -6170,9 +5911,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.4.tgz", - "integrity": "sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz", + "integrity": "sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==", "dev": true, "license": "MIT", "dependencies": { @@ -6199,9 +5940,9 @@ "license": "MIT" }, "node_modules/axe-core": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", - "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz", + "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==", "dev": true, "license": "MPL-2.0", "engines": { @@ -6226,9 +5967,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.43", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz", - "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", + "version": "2.10.30", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.30.tgz", + "integrity": "sha512-xjOFN16Ha1+Rz4nFYKqHU/LSB+gx/Vi3yQLX7r7sAW+Wa+8hhF2h4pvqTrTMc8+WcDBEunnUurr46Jvv0jk3Vg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6266,9 +6007,9 @@ } }, "node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -6276,9 +6017,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.6.tgz", - "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -6296,10 +6037,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.42", - "caniuse-lite": "^1.0.30001803", - "electron-to-chromium": "^1.5.389", - "node-releases": "^2.0.51", + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { @@ -6310,9 +6051,9 @@ } }, "node_modules/builtin-modules": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.3.0.tgz", - "integrity": "sha512-hMQUl2bUFG339QygPM97E+mc8OY1IAchORZxm4a/frcYwKzozMzRVDBwHW0NjOqGElLm2O37AVQE8ikxlZHrMQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.2.0.tgz", + "integrity": "sha512-02yxLeyxF4dNl6SlY6/5HfRSrSdZ/sCPoxy2kZNP5dZZX8LSAD9aE2gtJIUgWrsQTiMPl3mxESyrobSwvRGisQ==", "dev": true, "license": "MIT", "engines": { @@ -6358,9 +6099,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001805", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001805.tgz", - "integrity": "sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -6430,9 +6171,9 @@ } }, "node_modules/chromatic": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-18.1.0.tgz", - "integrity": "sha512-I9av8lUc5CQRlYzwKpmOG9cwYvZ4AFmTvtHeNrzOMC1353F9xYw45CHpSNIsNKuOiqqmzci9esXQd5akl0fi6w==", + "version": "16.10.0", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-16.10.0.tgz", + "integrity": "sha512-nFsztmnu7rFiGafUJgXvLUNpqmRylz92eNvzBoJNTKKQj4EQUyxznwnfpf1dTs7hXtWD8JwcH92jADydaHA1sw==", "dev": true, "license": "MIT", "dependencies": { @@ -6443,9 +6184,6 @@ "chromatic": "dist/bin.cjs", "chromatic-cli": "dist/bin.cjs" }, - "engines": { - "node": ">=22.0.0" - }, "peerDependencies": { "@chromatic-com/cypress": "^0.*.* || ^1.0.0", "@chromatic-com/playwright": "^0.*.* || ^1.0.0", @@ -6491,6 +6229,62 @@ "url": "https://polar.sh/cva" } }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -6502,25 +6296,20 @@ } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "license": "ISC", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6530,7 +6319,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -6545,7 +6333,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -6555,10 +6342,9 @@ } }, "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -6566,10 +6352,7 @@ "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/clsx": { @@ -6607,83 +6390,84 @@ "license": "MIT" }, "node_modules/conventional-changelog": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-8.1.1.tgz", - "integrity": "sha512-my0arqBpzr8mg+7RKDGnw8OiDvBr8/QVJIxazYJlIDeKx/2GCBYxZELaDYpbRhM5gNKfZB8h9SHuetrUFxd5HQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-7.2.0.tgz", + "integrity": "sha512-BEdgG+vPl53EVlTTk9sZ96aagFp0AQ5pw/ggiQMy2SClLbTo1r0l+8dSg79gkLOO5DS1Lswuhp5fWn6RwE+ivg==", "dev": true, "license": "MIT", "dependencies": { - "@conventional-changelog/git-client": "^3.1.0", - "@simple-libs/hosted-git-info": "^2.0.0", - "@simple-libs/normalize-package-data": "^1.0.0", - "argue-cli": "^3.1.0", - "conventional-changelog-preset-loader": "^6.0.1", - "conventional-changelog-writer": "^9.2.0", - "conventional-commits-parser": "^7.1.2", - "fd-package-json": "^2.0.0" + "@conventional-changelog/git-client": "^2.6.0", + "@simple-libs/hosted-git-info": "^1.0.2", + "@types/normalize-package-data": "^2.4.4", + "conventional-changelog-preset-loader": "^5.0.0", + "conventional-changelog-writer": "^8.3.0", + "conventional-commits-parser": "^6.3.0", + "fd-package-json": "^2.0.0", + "meow": "^13.0.0", + "normalize-package-data": "^7.0.0" }, "bin": { "conventional-changelog": "dist/cli/index.js" }, "engines": { - "node": ">=22" + "node": ">=18" } }, "node_modules/conventional-changelog-preset-loader": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-6.0.1.tgz", - "integrity": "sha512-GZ8E3RQzXQb3JFy0pKl8oeSf7ENIhvAMvJr+PlWkavZOesLHHdhkfNJ4SvW35eo1Fu2+EyVxWQ1tVvtzAG2iWg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-5.0.0.tgz", + "integrity": "sha512-SetDSntXLk8Jh1NOAl1Gu5uLiCNSYenB5tm0YVeZKePRIgDW9lQImromTwLa3c/Gae298tsgOM+/CYT9XAl0NA==", "dev": true, "license": "MIT", "engines": { - "node": ">=22" + "node": ">=18" } }, "node_modules/conventional-changelog-writer": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-9.2.0.tgz", - "integrity": "sha512-eACD5BaAQCYjeI3RExkCZopNaaIuXzCP4kaAb2lEFXcGa/KOuxJfj8v/SnjhvF6377pYn0A2Gji+6GhwUK8rEA==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.4.0.tgz", + "integrity": "sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g==", "dev": true, "license": "MIT", "dependencies": { - "@conventional-changelog/template": "^1.2.1", - "@simple-libs/stream-utils": "^2.0.0", - "argue-cli": "^3.1.0", - "conventional-commits-filter": "^6.0.1", + "@simple-libs/stream-utils": "^1.2.0", + "conventional-commits-filter": "^5.0.0", + "handlebars": "^4.7.7", + "meow": "^13.0.0", "semver": "^7.5.2" }, "bin": { "conventional-changelog-writer": "dist/cli/index.js" }, "engines": { - "node": ">=22" + "node": ">=18" } }, "node_modules/conventional-commits-filter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-6.0.1.tgz", - "integrity": "sha512-cs+LadpH7Kpw0M3k8wurk+sOVVDAENA0iK4OBOrkL94j5lEVYRJ4j3zd2bhY9qgzyrPqthdcYT3axzRN7AliMg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", + "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=22" + "node": ">=18" } }, "node_modules/conventional-commits-parser": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.2.tgz", - "integrity": "sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", + "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", "dev": true, "license": "MIT", "dependencies": { - "@simple-libs/stream-utils": "^2.0.0", - "argue-cli": "^3.1.0" + "@simple-libs/stream-utils": "^1.2.0", + "meow": "^13.0.0" }, "bin": { "conventional-commits-parser": "dist/cli/index.js" }, "engines": { - "node": ">=22" + "node": ">=18" } }, "node_modules/convert-source-map": { @@ -6881,19 +6665,6 @@ "node": ">=6" } }, - "node_modules/detect-indent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz", - "integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -6933,12 +6704,13 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/electron-to-chromium": { - "version": "1.5.389", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.389.tgz", - "integrity": "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==", + "version": "1.5.357", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.357.tgz", + "integrity": "sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==", "dev": true, "license": "ISC" }, @@ -6959,9 +6731,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.24.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", - "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -6984,6 +6756,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", @@ -6995,9 +6780,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, @@ -7067,9 +6852,9 @@ } }, "node_modules/eslint": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7078,8 +6863,8 @@ "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.6", - "@eslint/js": "9.39.5", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -7192,24 +6977,23 @@ } }, "node_modules/eslint-plugin-storybook": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-10.5.7.tgz", - "integrity": "sha512-mLpamG1Rsica2jYbUzIZOEuy7Fm1IMtVLMvvxGTpjTVKUMxTXJsANx3MBpH2VSbGQB8Yzlt5399WL/O07K97Ig==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-10.4.6.tgz", + "integrity": "sha512-CfGSXn6zFspeYTU8R7v797MOmJFj8xc6MWf/oGuRwbKeMoSwnliR+OlXSjMZYM1D6gfmwiuH1VX58LSHdn+ZPg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.60.0", - "@typescript-eslint/utils": "^8.60.0" + "@typescript-eslint/utils": "^8.48.0" }, "peerDependencies": { "eslint": ">=8", - "storybook": "^10.5.7" + "storybook": "^10.4.6" } }, "node_modules/eslint-plugin-unicorn": { - "version": "65.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-65.0.1.tgz", - "integrity": "sha512-daCrQrgxOoOz2uMPWB3Y3vvv/5q+ncwICI8IjoebiwtW87CaY4tAN5EEiRXTYVnf7qi1v1BGBdHOSnZLV0rx6A==", + "version": "64.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-64.0.0.tgz", + "integrity": "sha512-rNZwalHh8i0UfPlhNwg5BTUO1CMdKNmjqe+TgzOTZnpKoi8VBgsW7u9qCHIdpxEzZ1uwrJrPF0uRb7l//K38gA==", "dev": true, "license": "MIT", "dependencies": { @@ -7217,14 +7001,15 @@ "@eslint-community/eslint-utils": "^4.9.1", "change-case": "^5.4.4", "ci-info": "^4.4.0", + "clean-regexp": "^1.0.0", "core-js-compat": "^3.49.0", - "detect-indent": "^7.0.2", "find-up-simple": "^1.0.1", "globals": "^17.4.0", "indent-string": "^5.0.0", "is-builtin-module": "^5.0.0", "jsesc": "^3.1.0", "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", "regjsparser": "^0.13.0", "semver": "^7.7.4", "strip-indent": "^4.1.1" @@ -7269,27 +7054,10 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", - "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -7310,13 +7078,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -7428,10 +7189,17 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -7621,6 +7389,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -7672,16 +7453,16 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" } }, "node_modules/glob/node_modules/minimatch": { @@ -7701,9 +7482,9 @@ } }, "node_modules/globals": { - "version": "17.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.9.0.tgz", - "integrity": "sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", "dev": true, "license": "MIT", "engines": { @@ -7720,15 +7501,37 @@ "license": "ISC" }, "node_modules/graphql": { - "version": "16.14.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.2.tgz", - "integrity": "sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==", + "version": "16.14.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.1.tgz", + "integrity": "sha512-cQOsSMS/IrDz82PVyRDvf/Q1F/bRbBVjJlh+xYOkI1qw2bWRvWGiWc+m2O0d6l4Bt1fyY+8kzJ8JFWGJqNeDBg==", "dev": true, "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7763,6 +7566,13 @@ "set-cookie-parser": "^3.0.1" } }, + "node_modules/headers-polyfill/node_modules/set-cookie-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", + "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==", + "dev": true, + "license": "MIT" + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -7780,6 +7590,26 @@ "hermes-estree": "0.25.1" } }, + "node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", @@ -7801,12 +7631,12 @@ "license": "MIT" }, "node_modules/html-parse-stringify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-4.0.1.tgz", - "integrity": "sha512-0zHsZJrK7S3K2aucXWL6ycoYJ/iNtIcFHC/nYQgFklPtrv5LpJctIiSCroWZWeuoXvuyFdzp6KzjJQ+OT5MfFw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", "license": "MIT", - "funding": { - "url": "https://locize.com" + "dependencies": { + "void-elements": "3.1.0" } }, "node_modules/html5-qrcode": { @@ -7832,9 +7662,9 @@ } }, "node_modules/i18next": { - "version": "26.3.6", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.6.tgz", - "integrity": "sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==", + "version": "26.3.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.1.tgz", + "integrity": "sha512-txQqd5EULsqEh9OJqRH15aCaOuy/nLJyhw5EHCSKLKJE1aBbb3Zve2+uQIxgWhPm1QqUQoWyQBm2kfmmIrzkcQ==", "funding": [ { "type": "individual", @@ -7852,7 +7682,7 @@ "license": "MIT", "peer": true, "peerDependencies": { - "typescript": "^5 || ^6 || ^7" + "typescript": "^5 || ^6" }, "peerDependenciesMeta": { "typescript": { @@ -7977,6 +7807,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -8109,9 +7955,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, "funding": [ { @@ -8132,39 +7978,39 @@ } }, "node_modules/jsdom": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.0.1.tgz", - "integrity": "sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^6.0.5", - "@asamuzakjp/dom-selector": "^8.3.0", + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.7", - "@exodus/bytes": "^1.15.1", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", "css-tree": "^3.2.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.5.2", + "lru-cache": "^11.3.5", "parse5": "^8.0.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.2", - "undici": "^8.9.0", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^17.1.0", + "whatwg-url": "^16.0.1", "xml-name-validator": "^5.0.0" }, "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" }, "peerDependencies": { - "canvas": "^3.2.3" + "canvas": "^3.0.0" }, "peerDependenciesMeta": { "canvas": { @@ -8173,30 +8019,15 @@ } }, "node_modules/jsdom/node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, - "node_modules/jsdom/node_modules/whatwg-url": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.0.tgz", - "integrity": "sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.15.1", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, - "engines": { - "node": "^22.14.0 || >=24.0.0" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -8217,6 +8048,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -8237,13 +8075,6 @@ "node": ">=6" } }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT" - }, "node_modules/jsonfile": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", @@ -8417,9 +8248,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8440,9 +8268,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8463,9 +8288,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8486,9 +8308,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8543,13 +8362,14 @@ } }, "node_modules/lint-staged": { - "version": "17.3.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.3.0.tgz", - "integrity": "sha512-woZS3vNe3UKqBaLPvbLOtKRY4tLANpWQhom12MGWqC8Mh1lCOO+WgSwmX2amjJAqTY9BkXYW87fCUH5H9Ph6xw==", + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.0.7.tgz", + "integrity": "sha512-JrSobt+tW3rH8IOMi8tDZd3foorM5yPEkLD/V2NxobgHrFfHWGee4MOLVuZeScgxftEwbHrPHIFA/ZL+nUJeuA==", "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^4.0.5", + "listr2": "^10.2.1", + "picomatch": "^4.0.4", "string-argv": "^0.3.2", "tinyexec": "^1.2.4" }, @@ -8566,6 +8386,23 @@ "yaml": "^2.9.0" } }, + "node_modules/listr2": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", + "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.2.0", + "eventemitter3": "^5.0.4", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^10.0.0" + }, + "engines": { + "node": ">=22.13.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8603,6 +8440,99 @@ "dev": true, "license": "MIT" }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/loupe": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", @@ -8621,9 +8551,9 @@ } }, "node_modules/lucide-react": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.30.0.tgz", - "integrity": "sha512-tUIr2jXLbWpCkdtH8XP7P7YppM9ueWgTky99lpWDY6z5REs6B+O6ZQ3U5tHkUUY59ANyOv/PBcs8E4Fe3KO3eA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.20.0.tgz", + "integrity": "sha512-jhXLeC/7m0/tjL1nzMdKk6x256zWA6AtbhTVreHOiKPoeX2d6MK4FbyIQPpVq0E6iPWBisyy1TW+pEge/uMEuQ==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -8635,6 +8565,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -8683,6 +8614,32 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -8747,9 +8704,9 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.15.0.tgz", - "integrity": "sha512-2wQAmKkQKxRuXvYJxVhPGG0wZNBQyD06oJvxqw90XqLvptdqxdlHrFUfEteKkpaNORX3Xzc+HtEl/q0nfmN2wQ==", + "version": "2.14.6", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.14.6.tgz", + "integrity": "sha512-ALe+N10S72cyx94cMcy3Zs4HhXCj35sgeAL4c+WTvKi0zWnbd8/h0lcFqv0mb2P+aSgAdD7p9HzvA0DiUPxsyg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -8792,17 +8749,142 @@ } }, "node_modules/msw-storybook-addon": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/msw-storybook-addon/-/msw-storybook-addon-3.0.0.tgz", - "integrity": "sha512-tyYmYAwSGcfFSHhrE5yzun/OXuVIkBGOt4YTsH5IR94N38F+hzZhvGqe5scu1ENJh/hOApI/8ZRQkWdFNFsKcw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/msw-storybook-addon/-/msw-storybook-addon-2.0.7.tgz", + "integrity": "sha512-TGmlxXy2TsaB6QcClVKRxqvay5f93xoLguHOihRFQ+gIEIyiyvcoQjkEeuOe7Y9qvddzGB1LyFomzPo9/EpnuQ==", "dev": true, "license": "MIT", - "bin": { - "msw-storybook-migrate": "build/migrate.mjs" + "dependencies": { + "is-node-process": "^1.0.1" }, "peerDependencies": { - "msw": ">=2", - "storybook": ">=9" + "msw": "^2.0.0" + } + }, + "node_modules/msw/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/msw/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/msw/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/msw/node_modules/type-fest": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz", + "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/msw/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/msw/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/msw/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" } }, "node_modules/mute-stream": { @@ -8816,9 +8898,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -8840,6 +8922,13 @@ "dev": true, "license": "MIT" }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, "node_modules/next-themes": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", @@ -8851,27 +8940,52 @@ } }, "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "version": "2.0.44", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz", + "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-7.0.1.tgz", + "integrity": "sha512-linxNAT6M0ebEYZOx2tO6vBEFsVgnPpv+AVjk0wJHfaUIbq31Jm3T6vvZaarnOeWDh8ShnwXuaAyM7WT3RzErA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, "engines": { - "node": ">=18" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/obug": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", - "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "dev": true, "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" ], + "license": "MIT" + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, "engines": { - "node": ">=12.20.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/open": { @@ -8957,34 +9071,34 @@ } }, "node_modules/oxc-resolver": { - "version": "11.24.2", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.24.2.tgz", - "integrity": "sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==", + "version": "11.20.0", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.20.0.tgz", + "integrity": "sha512-CblytBiV/a/ZXY34dsVU2NxhIOxMXst8CvDCtyBelVITgd7PLrKzbEbA6oKLdPjvDKDzCiW48qzmzZ+mYaqn+g==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-resolver/binding-android-arm-eabi": "11.24.2", - "@oxc-resolver/binding-android-arm64": "11.24.2", - "@oxc-resolver/binding-darwin-arm64": "11.24.2", - "@oxc-resolver/binding-darwin-x64": "11.24.2", - "@oxc-resolver/binding-freebsd-x64": "11.24.2", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.24.2", - "@oxc-resolver/binding-linux-arm-musleabihf": "11.24.2", - "@oxc-resolver/binding-linux-arm64-gnu": "11.24.2", - "@oxc-resolver/binding-linux-arm64-musl": "11.24.2", - "@oxc-resolver/binding-linux-ppc64-gnu": "11.24.2", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.24.2", - "@oxc-resolver/binding-linux-riscv64-musl": "11.24.2", - "@oxc-resolver/binding-linux-s390x-gnu": "11.24.2", - "@oxc-resolver/binding-linux-x64-gnu": "11.24.2", - "@oxc-resolver/binding-linux-x64-musl": "11.24.2", - "@oxc-resolver/binding-openharmony-arm64": "11.24.2", - "@oxc-resolver/binding-wasm32-wasi": "11.24.2", - "@oxc-resolver/binding-win32-arm64-msvc": "11.24.2", - "@oxc-resolver/binding-win32-x64-msvc": "11.24.2" + "@oxc-resolver/binding-android-arm-eabi": "11.20.0", + "@oxc-resolver/binding-android-arm64": "11.20.0", + "@oxc-resolver/binding-darwin-arm64": "11.20.0", + "@oxc-resolver/binding-darwin-x64": "11.20.0", + "@oxc-resolver/binding-freebsd-x64": "11.20.0", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.20.0", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.20.0", + "@oxc-resolver/binding-linux-arm64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-arm64-musl": "11.20.0", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-riscv64-musl": "11.20.0", + "@oxc-resolver/binding-linux-s390x-gnu": "11.20.0", + "@oxc-resolver/binding-linux-x64-gnu": "11.20.0", + "@oxc-resolver/binding-linux-x64-musl": "11.20.0", + "@oxc-resolver/binding-openharmony-arm64": "11.20.0", + "@oxc-resolver/binding-wasm32-wasi": "11.20.0", + "@oxc-resolver/binding-win32-arm64-msvc": "11.20.0", + "@oxc-resolver/binding-win32-x64-msvc": "11.20.0" } }, "node_modules/p-limit": { @@ -9115,9 +9229,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -9155,9 +9269,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -9167,35 +9281,35 @@ } }, "node_modules/playwright": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.0.tgz", - "integrity": "sha512-Z14dG305dgaLu6foB1TXQagFiW8JfSUIUaUuPaKQ6NtBPKF1P/qXcqfh6c6K/icPqdy37JmjbiBXf6JNg6Sylw==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz", + "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.62.0" + "playwright-core": "1.61.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=20" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.0.tgz", - "integrity": "sha512-nsNRyq0r2zsG8AcRHWknc9QRA5XCueC7gWMrs+Gx2tlZn9hcl8zudfh00lhJPY1DE7NmZ6bDsT9g2yey8mXljA==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz", + "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==", "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/pluralize": { @@ -9219,9 +9333,9 @@ } }, "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -9238,7 +9352,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.17", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -9257,9 +9371,9 @@ } }, "node_modules/prettier": { - "version": "3.9.6", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", - "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { @@ -9273,9 +9387,9 @@ } }, "node_modules/prettier-plugin-tailwindcss": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.8.1.tgz", - "integrity": "sha512-iaFMYqDsE4ffdDkn5qup0j5f2aCEBFZrdrZnvu9QKTlWx/iGPeQ4HHu7b7fCPMxeo9nwQBiOAh2nSypdFYWJkw==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.8.0.tgz", + "integrity": "sha512-V8ITGH87yuBDF6JpEZTOVlUz/saAwqb8f3HRgUj8Lh+tGCcrmorhsLpYqzygwFwK0PE2Ib6Mv3M7T/uE2tZV1g==", "dev": true, "license": "MIT", "engines": { @@ -9357,6 +9471,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -9372,6 +9487,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -9412,78 +9528,6 @@ "node": ">=10.13.0" } }, - "node_modules/qrcode/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/qrcode/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/qrcode/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/qrcode/node_modules/pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -9493,148 +9537,67 @@ "node": ">=10.13.0" } }, - "node_modules/qrcode/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/qrcode/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/radix-ui": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.6.7.tgz", - "integrity": "sha512-QBdhh1arIEUvPC0dQ5+nwWAxt7+N+oP/9jPwjJkGFoSk/sqxg32gJtSXGtFh8frAIcS6oC9cx2Q+7KYCQLOAeA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.6.0.tgz", + "integrity": "sha512-EUEC70O03EgxWMP5aoqfBZ6iLC5bczFagGy7zhSYRt8o5DP7IWNiP3ywetse3L9b8843ExB0OGWZvgbYVJuNeg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.7", - "@radix-ui/react-accessible-icon": "1.1.15", - "@radix-ui/react-accordion": "1.2.20", - "@radix-ui/react-alert-dialog": "1.1.23", - "@radix-ui/react-arrow": "1.1.15", - "@radix-ui/react-aspect-ratio": "1.1.15", - "@radix-ui/react-avatar": "1.2.6", - "@radix-ui/react-checkbox": "1.3.11", - "@radix-ui/react-collapsible": "1.1.20", - "@radix-ui/react-collection": "1.1.15", - "@radix-ui/react-compose-refs": "1.1.5", - "@radix-ui/react-context": "1.2.2", - "@radix-ui/react-context-menu": "2.3.7", - "@radix-ui/react-dialog": "1.1.23", - "@radix-ui/react-direction": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.19", - "@radix-ui/react-dropdown-menu": "2.1.24", - "@radix-ui/react-focus-guards": "1.1.6", - "@radix-ui/react-focus-scope": "1.1.16", - "@radix-ui/react-form": "0.1.16", - "@radix-ui/react-hover-card": "1.1.23", - "@radix-ui/react-label": "2.1.15", - "@radix-ui/react-menu": "2.1.24", - "@radix-ui/react-menubar": "1.1.24", - "@radix-ui/react-navigation-menu": "1.2.22", - "@radix-ui/react-one-time-password-field": "0.1.16", - "@radix-ui/react-password-toggle-field": "0.1.11", - "@radix-ui/react-popover": "1.1.23", - "@radix-ui/react-popper": "1.3.7", - "@radix-ui/react-portal": "1.1.17", - "@radix-ui/react-presence": "1.1.10", - "@radix-ui/react-primitive": "2.1.10", - "@radix-ui/react-progress": "1.1.16", - "@radix-ui/react-radio-group": "1.4.7", - "@radix-ui/react-roving-focus": "1.1.19", - "@radix-ui/react-scroll-area": "1.2.18", - "@radix-ui/react-select": "2.3.7", - "@radix-ui/react-separator": "1.1.15", - "@radix-ui/react-slider": "1.4.7", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-switch": "1.3.7", - "@radix-ui/react-tabs": "1.1.21", - "@radix-ui/react-toast": "1.2.23", - "@radix-ui/react-toggle": "1.1.18", - "@radix-ui/react-toggle-group": "1.1.19", - "@radix-ui/react-toolbar": "1.1.19", - "@radix-ui/react-tooltip": "1.2.16", - "@radix-ui/react-use-callback-ref": "1.1.4", - "@radix-ui/react-use-controllable-state": "1.2.6", - "@radix-ui/react-use-effect-event": "0.0.5", - "@radix-ui/react-use-escape-keydown": "1.1.5", - "@radix-ui/react-use-is-hydrated": "0.1.3", - "@radix-ui/react-use-layout-effect": "1.1.4", - "@radix-ui/react-use-size": "1.1.4", - "@radix-ui/react-visually-hidden": "1.2.11" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-accessible-icon": "1.1.10", + "@radix-ui/react-accordion": "1.2.14", + "@radix-ui/react-alert-dialog": "1.1.17", + "@radix-ui/react-arrow": "1.1.10", + "@radix-ui/react-aspect-ratio": "1.1.10", + "@radix-ui/react-avatar": "1.2.0", + "@radix-ui/react-checkbox": "1.3.5", + "@radix-ui/react-collapsible": "1.1.14", + "@radix-ui/react-collection": "1.1.10", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-context-menu": "2.3.1", + "@radix-ui/react-dialog": "1.1.17", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.13", + "@radix-ui/react-dropdown-menu": "2.1.18", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.10", + "@radix-ui/react-form": "0.1.10", + "@radix-ui/react-hover-card": "1.1.17", + "@radix-ui/react-label": "2.1.10", + "@radix-ui/react-menu": "2.1.18", + "@radix-ui/react-menubar": "1.1.18", + "@radix-ui/react-navigation-menu": "1.2.16", + "@radix-ui/react-one-time-password-field": "0.1.10", + "@radix-ui/react-password-toggle-field": "0.1.5", + "@radix-ui/react-popover": "1.1.17", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-progress": "1.1.10", + "@radix-ui/react-radio-group": "1.4.1", + "@radix-ui/react-roving-focus": "1.1.13", + "@radix-ui/react-scroll-area": "1.2.12", + "@radix-ui/react-select": "2.3.1", + "@radix-ui/react-separator": "1.1.10", + "@radix-ui/react-slider": "1.4.1", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-switch": "1.3.1", + "@radix-ui/react-tabs": "1.1.15", + "@radix-ui/react-toast": "1.2.17", + "@radix-ui/react-toggle": "1.1.12", + "@radix-ui/react-toggle-group": "1.1.13", + "@radix-ui/react-toolbar": "1.1.13", + "@radix-ui/react-tooltip": "1.2.10", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-escape-keydown": "1.1.2", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", @@ -9652,9 +9615,9 @@ } }, "node_modules/react": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", - "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9693,21 +9656,21 @@ } }, "node_modules/react-dom": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", - "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.8" + "react": "^19.2.7" } }, "node_modules/react-hook-form": { - "version": "7.84.0", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.84.0.tgz", - "integrity": "sha512-+hWvQP6GLco56mDwrbU4XnHix8t1z90ltZsDIrREl+jnQFQxYLX8oAzqe/Xn8nHpmoXTY5M6oEXrAhbP1qevNQ==", + "version": "7.79.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.79.0.tgz", + "integrity": "sha512-mhYp/MTmXvzYX6AJcJVko0rktoIhhmRnEouObj4wF5i/tCttgJvnp1+9wRkpITZjDTqpo4IOSJqu0dBlPlV/Lw==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -9721,19 +9684,19 @@ } }, "node_modules/react-i18next": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.11.tgz", - "integrity": "sha512-cDtkXgxjuFTWUH6V+aQn1Ve5vDiUztCNPWW5GtSHDccsgRXO1nE6QFWCEmc1KAutrb3OUv87wFShJL5RhUwPXg==", + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.8.tgz", + "integrity": "sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.2", - "html-parse-stringify": "^4.0.1", + "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 26.2.0", "react": ">= 16.8.0", - "typescript": "^5 || ^6 || ^7" + "typescript": "^5 || ^6" }, "peerDependenciesMeta": { "react-dom": { @@ -9752,7 +9715,8 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/react-remove-scroll": { "version": "2.7.2", @@ -9802,9 +9766,9 @@ } }, "node_modules/react-router": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz", - "integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz", + "integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -9824,12 +9788,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.2.tgz", - "integrity": "sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz", + "integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==", "license": "MIT", "dependencies": { - "react-router": "7.18.2" + "react-router": "7.18.0" }, "engines": { "node": ">=20.0.0" @@ -9839,12 +9803,6 @@ "react-dom": ">=18" } }, - "node_modules/react-router/node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", - "license": "MIT" - }, "node_modules/react-style-singleton": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", @@ -9874,9 +9832,9 @@ "license": "MIT" }, "node_modules/recast": { - "version": "0.23.19", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.19.tgz", - "integrity": "sha512-T98lym7kH+pnZmRaD8yDRdaNqyUbwnbEBx0MuchrzMFOEMray4AO3ZJoTUZ5r78Ao78X/OhzW0DL8GB85w/I2w==", + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", "dev": true, "license": "MIT", "dependencies": { @@ -9927,10 +9885,20 @@ "node": ">=8" } }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, "node_modules/regjsparser": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", - "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -10003,6 +9971,23 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/rettime": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.11.11.tgz", @@ -10010,13 +9995,20 @@ "dev": true, "license": "MIT" }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rolldown": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.1.tgz", - "integrity": "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.142.0", + "@oxc-project/types": "=0.133.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -10026,27 +10018,27 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.1", - "@rolldown/binding-darwin-arm64": "1.2.1", - "@rolldown/binding-darwin-x64": "1.2.1", - "@rolldown/binding-freebsd-x64": "1.2.1", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.1", - "@rolldown/binding-linux-arm64-gnu": "1.2.1", - "@rolldown/binding-linux-arm64-musl": "1.2.1", - "@rolldown/binding-linux-ppc64-gnu": "1.2.1", - "@rolldown/binding-linux-s390x-gnu": "1.2.1", - "@rolldown/binding-linux-x64-gnu": "1.2.1", - "@rolldown/binding-linux-x64-musl": "1.2.1", - "@rolldown/binding-openharmony-arm64": "1.2.1", - "@rolldown/binding-wasm32-wasi": "1.2.1", - "@rolldown/binding-win32-arm64-msvc": "1.2.1", - "@rolldown/binding-win32-x64-msvc": "1.2.1" + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, "node_modules/rolldown/node_modules/@oxc-project/types": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", - "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -10085,9 +10077,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", "dev": true, "license": "ISC", "bin": { @@ -10104,10 +10096,9 @@ "license": "ISC" }, "node_modules/set-cookie-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz", - "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==", - "dev": true, + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/sha256-uint8array": { @@ -10174,6 +10165,36 @@ "node": ">=18" } }, + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/sonner": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", @@ -10203,6 +10224,42 @@ "node": ">=0.10.0" } }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -10221,36 +10278,34 @@ } }, "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, "node_modules/storybook": { - "version": "10.5.7", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.5.7.tgz", - "integrity": "sha512-oiKvWIwIoOhFP1i6dASYyMXwPHKEtVZMshqSB7EvIVYjWRh0l9H7gHEt1z4Gh2rLGFMekWdsm4s94rvwpR7gkg==", + "version": "10.4.6", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.4.6.tgz", + "integrity": "sha512-6wkA6LxfDSSilloITsrFOJfsnw0mDUP2h8Ls+lRt8oRsudtz2RWFhLv+Toiwg6NW7hUpdTDc2hzR7DztJid6+A==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2", - "@testing-library/dom": "^10.4.1", - "@testing-library/jest-dom": "6.9.1", + "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "@webcontainer/env": "^1.1.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0", - "jsonc-parser": "^3.3.1", "open": "^10.2.0", "oxc-parser": "^0.127.0", "oxc-resolver": "^11.19.1", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", - "ws": "^8.21.1" + "ws": "^8.18.0" }, "bin": { "storybook": "dist/bin/dispatcher.js" @@ -10262,7 +10317,7 @@ "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "prettier": "^2 || ^3", - "vite-plus": "^0.1.15 || ^0.2.0" + "vite-plus": "^0.1.15" }, "peerDependenciesMeta": { "@types/react": { @@ -10276,26 +10331,6 @@ } } }, - "node_modules/storybook/node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - } - }, "node_modules/storybook/node_modules/@vitest/spy": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", @@ -10309,13 +10344,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/storybook/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, "node_modules/strict-event-emitter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", @@ -10333,6 +10361,23 @@ "node": ">=0.6.19" } }, + "node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -10455,9 +10500,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", - "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", "license": "MIT" }, "node_modules/tapable": { @@ -10540,22 +10585,22 @@ } }, "node_modules/tldts": { - "version": "7.4.8", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.8.tgz", - "integrity": "sha512-htwgN/8KRB3z3vnC0BOETVh2m499g5GmyTK9Wq5JBLX3FNz6tSBveAd+fQhzy9hkjif8vy2jwDMR1sGhLtZl2A==", + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.30.tgz", + "integrity": "sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.4.8" + "tldts-core": "^7.0.30" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.4.8", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.8.tgz", - "integrity": "sha512-c1P7u0EhACHj7lPy4MJm8iTFEU8+nB0LCtddH0fhP7noaVoXAqafMtOOeX+ulpuPBqnrRgRhw494RICT3mbhnw==", + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.30.tgz", + "integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==", "dev": true, "license": "MIT" }, @@ -10576,9 +10621,9 @@ } }, "node_modules/tough-cookie": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", - "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -10615,9 +10660,9 @@ } }, "node_modules/ts-dedent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", - "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", "dev": true, "license": "MIT", "engines": { @@ -10668,16 +10713,12 @@ } }, "node_modules/type-fest": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz", - "integrity": "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==", - "dev": true, + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "license": "(MIT OR CC0-1.0)", - "dependencies": { - "tagged-tag": "^1.0.0" - }, "engines": { - "node": ">=20" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10698,16 +10739,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.66.0.tgz", - "integrity": "sha512-QlEbBPz/RuJ1XUHj29nm3t0F/O/cSlEnntozqPOYHnnTGAXFamnMBu5i9Vn6vhUPHGAjR+Vl+5J8vPN/BMUrJw==", + "version": "8.61.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.1.tgz", + "integrity": "sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.66.0", - "@typescript-eslint/parser": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/utils": "8.66.0" + "@typescript-eslint/eslint-plugin": "8.61.1", + "@typescript-eslint/parser": "8.61.1", + "@typescript-eslint/typescript-estree": "8.61.1", + "@typescript-eslint/utils": "8.61.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -10721,20 +10762,34 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undici": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", - "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=22.19.0" + "node": ">=20.18.1" } }, "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "devOptional": true, "license": "MIT" }, @@ -10867,16 +10922,27 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vite": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", - "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "license": "MIT", "dependencies": { - "lightningcss": "^1.33.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.25", - "rolldown": "~1.2.1", + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", "tinyglobby": "^0.2.17" }, "bin": { @@ -10893,7 +10959,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", + "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -10958,281 +11024,20 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/vite/node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/vite/node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -11260,12 +11065,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@vitest/browser-playwright": "4.1.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -11310,16 +11115,16 @@ } }, "node_modules/vitest/node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -11337,6 +11142,15 @@ "node": ">=18" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", @@ -11451,10 +11265,48 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", + "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/ws": { - "version": "8.21.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", - "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { @@ -11507,14 +11359,10 @@ "license": "MIT" }, "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" }, "node_modules/yallist": { "version": "3.1.1", @@ -11540,49 +11388,105 @@ } }, "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", - "dev": true, + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "license": "MIT", "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { - "node": ">=12" + "node": ">=8" } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, "engines": { - "node": ">=12" + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -11597,7 +11501,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -11631,23 +11534,11 @@ "type-fest": "^2.19.0" } }, - "node_modules/yup/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zod": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "devOptional": true, + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 5953be25..15465d79 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { "name": "jam", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.0", "private": true, "description": "Your sats. Your privacy. Your profit.", "repository": "git@github.com:joinmarket-webui/jam.git", "license": "MIT", "type": "module", "engines": { - "node": ">=26.3.0", - "npm": ">=11.16.0" + "node": ">=24.11.1", + "npm": ">=11.6.2" }, "scripts": { "dev": "npm run dev:ng:native", @@ -32,7 +32,6 @@ "test": "NODE_OPTIONS=--no-webstorage vitest run", "test:unit": "NODE_OPTIONS=--no-webstorage vitest run --project unit", "test:storybook": "NODE_OPTIONS=--no-webstorage vitest run --project storybook", - "test:coverage": "npm test -- --coverage.enabled", "check": "npm run format && npm run test && npm run build", "regtest:build": "npm run regtest:clear && npm run regtest:pull && docker compose --env-file docker/regtest/.env.example --file docker/regtest/docker-compose.yml build --pull", "regtest:pull": "docker compose --env-file docker/regtest/.env.example --file docker/regtest/docker-compose.yml pull", @@ -42,18 +41,14 @@ "regtest:down": "docker compose --env-file docker/regtest/.env.example --file docker/regtest/docker-compose.yml down", "regtest:logs:all": "docker compose --env-file docker/regtest/.env.example --file docker/regtest/docker-compose.yml logs --follow", "regtest:logs": "npm run regtest:logs:ng:native:jmwalletd", - "regtest:logs:obwatch": "npm run regtest:logs:ng:obwatch", - "regtest:logs:directory_node": "npm run regtest:logs:ng:directory_node", "regtest:logs:ng:native:jmwalletd": "docker logs -f jm_regtest_joinmarket", "regtest:logs:ng:obwatch": "docker logs -f jm_regtest_joinmarket_ng_orderbook_watcher", - "regtest:logs:ng:directory_node": "docker logs -f jm_regtest_joinmarket_ng_directory_node", - "regtest:logs:clientserver:directory_node": "docker exec -t jm_regtest_joinmarket_clientserver_directory_node tail -f /var/log/jam/directory_node_stdout.log -n 200", + "regtest:logs:obwatch": "npm run regtest:logs:ng:obwatch", + "regtest:logs:ng:directory_node": "docker exec -t jm_regtest_joinmarket_directory_node tail -f /var/log/jam/directory_node_stdout.log -n 200", "regtest:logs:clientserver:native:jmwalletd": "docker exec -t jm_regtest_joinmarket3 tail -f /var/log/jam/jmwalletd_stdout.log", - "regtest:logs:clientserver:native:tor": "docker exec -t jm_regtest_joinmarket3 tail -f /var/log/jam/tor_stdout.log", "regtest:logs:clientserver:native:schedule": "docker exec -t jm_regtest_joinmarket3 tail -f /root/.joinmarket/logs/TUMBLE.schedule", "regtest:init": "./docker/regtest/init-setup.sh", - "regtest:mine": "watch -n 11 ./docker/regtest/mine-block.sh", - "regtest:listwallets": "docker exec -t jm_regtest_bitcoind bitcoin-cli -datadir=/home/bitcoin/data -regtest -rpcport=43782 listwallets" + "regtest:mine": "watch -n 11 ./docker/regtest/mine-block.sh" }, "lint-staged": { "*.{js,jsx,ts,tsx}": [ @@ -71,97 +66,96 @@ ] }, "dependencies": { - "@hookform/resolvers": "5.7.1", - "@joinmarket-webui/joinmarket-ng-api-ts": "1.0.0", - "@noble/hashes": "2.3.0", - "@radix-ui/react-accordion": "1.2.20", - "@radix-ui/react-avatar": "1.2.6", - "@radix-ui/react-checkbox": "1.3.11", - "@radix-ui/react-dialog": "1.1.23", - "@radix-ui/react-dropdown-menu": "2.1.24", - "@radix-ui/react-label": "2.1.15", - "@radix-ui/react-popover": "1.1.23", - "@radix-ui/react-radio-group": "1.4.7", - "@radix-ui/react-select": "2.3.7", - "@radix-ui/react-separator": "1.1.15", - "@radix-ui/react-slider": "1.4.7", - "@radix-ui/react-slot": "1.3.3", - "@radix-ui/react-switch": "1.3.7", - "@radix-ui/react-tabs": "1.1.21", - "@radix-ui/react-tooltip": "1.2.16", + "@hookform/resolvers": "5.4.0", + "@joinmarket-webui/joinmarket-api-ts": "0.3.0", + "@noble/hashes": "2.2.0", + "@radix-ui/react-accordion": "1.2.14", + "@radix-ui/react-avatar": "1.2.0", + "@radix-ui/react-checkbox": "1.3.5", + "@radix-ui/react-dialog": "1.1.17", + "@radix-ui/react-dropdown-menu": "2.1.18", + "@radix-ui/react-label": "2.1.10", + "@radix-ui/react-popover": "1.1.17", + "@radix-ui/react-radio-group": "1.4.1", + "@radix-ui/react-select": "2.3.1", + "@radix-ui/react-separator": "1.1.10", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-switch": "1.3.1", + "@radix-ui/react-tabs": "1.1.15", + "@radix-ui/react-tooltip": "1.2.10", "@scure/bip32": "2.2.0", "@scure/bip39": "2.2.0", - "@tailwindcss/vite": "4.3.3", + "@tailwindcss/vite": "4.3.1", "@tanstack/match-sorter-utils": "8.19.4", - "@tanstack/react-query": "5.101.4", + "@tanstack/react-query": "5.101.0", "@tanstack/react-table": "8.21.3", "bitcoin-address-validation": "3.0.0", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "html5-qrcode": "2.3.8", "i18next-browser-languagedetector": "8.2.1", - "lucide-react": "1.30.0", + "lucide-react": "1.20.0", "next-themes": "0.4.6", "qrcode": "1.5.4", - "radix-ui": "1.6.7", - "react": "19.2.8", - "react-dom": "19.2.8", - "react-hook-form": "7.84.0", - "react-i18next": "17.0.11", - "react-router-dom": "7.18.2", + "radix-ui": "1.6.0", + "react": "19.2.7", + "react-dom": "19.2.7", + "react-hook-form": "7.79.0", + "react-i18next": "17.0.8", + "react-router-dom": "7.18.0", "react-use-websocket": "4.13.0", "sonner": "2.0.7", "tailwind-merge": "3.6.0", - "tailwindcss": "4.3.3", + "tailwindcss": "4.3.1", "tw-animate-css": "1.4.0", "yup": "1.7.1", "zustand": "5.0.14" }, "devDependencies": { - "@chromatic-com/storybook": "5.3.0", - "@eslint/js": "9.39.5", - "@playwright/test": "1.62.0", - "@storybook/addon-a11y": "10.5.7", - "@storybook/addon-docs": "10.5.7", - "@storybook/addon-vitest": "10.5.7", - "@storybook/react-vite": "10.5.7", - "@tanstack/eslint-plugin-query": "5.101.4", - "@testing-library/jest-dom": "7.0.0", + "@chromatic-com/storybook": "5.2.1", + "@eslint/js": "9.39.4", + "@playwright/test": "1.61.0", + "@storybook/addon-a11y": "10.4.6", + "@storybook/addon-docs": "10.4.6", + "@storybook/addon-vitest": "10.4.6", + "@storybook/react-vite": "10.4.6", + "@tanstack/eslint-plugin-query": "5.101.0", + "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "16.3.2", - "@testing-library/user-event": "14.6.3", + "@testing-library/user-event": "14.6.1", "@trivago/prettier-plugin-sort-imports": "6.0.2", - "@types/node": "26.1.2", + "@types/node": "24.12.4", "@types/qrcode": "1.5.6", - "@types/react": "19.2.18", - "@types/react-dom": "19.2.4", - "@vitejs/plugin-react": "6.0.5", - "@vitest/browser": "4.1.10", - "@vitest/browser-playwright": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "conventional-changelog": "8.1.1", - "eslint": "9.39.5", + "@types/react": "19.2.17", + "@types/react-dom": "19.2.3", + "@vitejs/plugin-react": "6.0.2", + "@vitest/browser": "4.1.9", + "@vitest/browser-playwright": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "conventional-changelog": "7.2.0", + "eslint": "9.39.4", "eslint-plugin-compat": "7.0.2", "eslint-plugin-react-hooks": "7.1.1", "eslint-plugin-react-refresh": "0.5.3", - "eslint-plugin-storybook": "10.5.7", - "eslint-plugin-unicorn": "65.0.1", - "globals": "17.9.0", + "eslint-plugin-storybook": "10.4.6", + "eslint-plugin-unicorn": "64.0.0", + "globals": "17.6.0", "husky": "9.1.7", - "jsdom": "30.0.1", - "lint-staged": "17.3.0", - "msw": "2.15.0", - "msw-storybook-addon": "3.0.0", - "prettier": "3.9.6", - "prettier-plugin-tailwindcss": "0.8.1", - "storybook": "10.5.7", + "jsdom": "29.1.1", + "lint-staged": "17.0.7", + "msw": "2.14.6", + "msw-storybook-addon": "2.0.7", + "prettier": "3.8.4", + "prettier-plugin-tailwindcss": "0.8.0", + "storybook": "10.4.6", "typescript": "6.0.3", - "typescript-eslint": "8.66.0", - "vite": "8.2.1", - "vitest": "4.1.10" + "typescript-eslint": "8.61.1", + "vite": "8.0.16", + "vitest": "4.1.9" }, "overrides": { "storybook": "$storybook", - "@joinmarket-webui/joinmarket-ng-api-ts": { + "@joinmarket-webui/joinmarket-api-ts": { "@tanstack/react-query": "$@tanstack/react-query" } }, diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js index 0c970efc..d20cd4e0 100644 --- a/public/mockServiceWorker.js +++ b/public/mockServiceWorker.js @@ -7,8 +7,8 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.15.0' -const INTEGRITY_CHECKSUM = '03cb67ac84128e63d7cd722a6e5b7f1e' +const PACKAGE_VERSION = '2.14.6' +const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() @@ -98,10 +98,7 @@ addEventListener('fetch', function (event) { // Opening the DevTools triggers the "only-if-cached" request // that cannot be handled by the worker. Bypass such requests. - if ( - event.request.cache === 'only-if-cached' && - event.request.mode !== 'same-origin' - ) { + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { return } @@ -124,12 +121,7 @@ addEventListener('fetch', function (event) { async function handleRequest(event, requestId, requestInterceptedAt) { const client = await resolveMainClient(event) const requestCloneForEvents = event.request.clone() - const response = await getResponse( - event, - client, - requestId, - requestInterceptedAt, - ) + const response = await getResponse(event, client, requestId, requestInterceptedAt) // Send back the response clone for the "response:*" life-cycle events. // Ensure MSW is active and ready to handle the message, otherwise @@ -137,18 +129,8 @@ async function handleRequest(event, requestId, requestInterceptedAt) { if (client && activeClientIds.has(client.id)) { const serializedRequest = await serializeRequest(requestCloneForEvents) - // Omit the body of server-sent event stream responses. - // Cloning such responses would prevent client-side stream cancelations - // from reaching the original stream (a teed stream only cancels its - // source once both of its branches cancel) and would buffer the - // entire stream into the unconsumed clone indefinitely. - const isEventStreamResponse = response.headers - .get('content-type') - ?.toLowerCase() - .startsWith('text/event-stream') - // Clone the response so both the client and the library could consume it. - const responseClone = isEventStreamResponse ? null : response.clone() + const responseClone = response.clone() sendToClient( client, @@ -161,17 +143,15 @@ async function handleRequest(event, requestId, requestInterceptedAt) { ...serializedRequest, }, response: { - type: response.type, - status: response.status, - statusText: response.statusText, - headers: Object.fromEntries(response.headers.entries()), - body: responseClone ? responseClone.body : null, + type: responseClone.type, + status: responseClone.status, + statusText: responseClone.statusText, + headers: Object.fromEntries(responseClone.headers.entries()), + body: responseClone.body, }, }, }, - responseClone && responseClone.body - ? [serializedRequest.body, responseClone.body] - : [], + responseClone.body ? [serializedRequest.body, responseClone.body] : [], ) } @@ -236,9 +216,7 @@ async function getResponse(event, client, requestId, requestInterceptedAt) { const acceptHeader = headers.get('accept') if (acceptHeader) { const values = acceptHeader.split(',').map((value) => value.trim()) - const filteredValues = values.filter( - (value) => value !== 'msw/passthrough', - ) + const filteredValues = values.filter((value) => value !== 'msw/passthrough') if (filteredValues.length > 0) { headers.set('accept', filteredValues.join(', ')) @@ -309,10 +287,7 @@ function sendToClient(client, message, transferrables = []) { resolve(event.data) } - client.postMessage(message, [ - channel.port2, - ...transferrables.filter(Boolean), - ]) + client.postMessage(message, [channel.port2, ...transferrables.filter(Boolean)]) }) } diff --git a/scripts/changelog.mjs b/scripts/changelog.mjs index 668038d0..c7fa8d14 100644 --- a/scripts/changelog.mjs +++ b/scripts/changelog.mjs @@ -58,7 +58,7 @@ const generateChangelog = (newVersion) => { }) changelogStream.on('end', () => { - changelog = changelog.replaceAll(/###\s(\w+)/g, '#### $1').replaceAll('\n'.repeat(3), '\n\n') + changelog = changelog.replaceAll(/###\s(\w+)/g, '#### $1').replaceAll('\n\n\n', '\n\n') const finalChangelog = header + '\n' + (changelog + oldContent).replaceAll(/\n+$/, '\n') fs.writeFileSync(file, finalChangelog, 'utf8') return resolve() diff --git a/src/App.test.tsx b/src/App.test.tsx index fd8e198c..b6314dc8 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -67,10 +67,6 @@ vi.mock('./store/jmSessionStore', () => ({ jmSessionStore: { getState: () => ({ state: holders.jmSession }) }, })) -vi.mock('./store/jmTxStore', () => ({ - jmTxStore: { getState: () => ({ state: {} }) }, -})) - vi.mock('@/store/jamSettingsStore', () => ({ jamSettingsStore: { getState: () => ({ state: { developerMode: holders.developerMode } }) }, useDeveloperMode: () => ({ enabled: holders.developerMode }), @@ -86,11 +82,11 @@ vi.mock('@tanstack/react-query', () => ({ useMutation: () => ({ mutateAsync }), })) -vi.mock('@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query', () => ({ +vi.mock('@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query', () => ({ lockwalletOptions: () => ({ queryKey: ['lock'] }), })) -vi.mock('@joinmarket-webui/joinmarket-ng-api-ts/jm', () => ({ +vi.mock('@joinmarket-webui/joinmarket-api-ts/jm', () => ({ token: vi.fn().mockResolvedValue({ data: { token: 't', refresh_token: 'r' } }), })) diff --git a/src/App.tsx b/src/App.tsx index d3887a78..df450130 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import { lazy, Suspense, useEffect, useMemo, useRef, useState } from 'react' import type { PropsWithChildren } from 'react' -import { lockwalletOptions } from '@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query' -import { token } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' +import { lockwalletOptions } from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query' +import { token } from '@joinmarket-webui/joinmarket-api-ts/jm' import { QueryClientProvider, useMutation, useQuery } from '@tanstack/react-query' import type { TFunction } from 'i18next' import { ThemeProvider } from 'next-themes' @@ -45,10 +45,8 @@ import { setIntervalDebounced, walletDisplayName, type WalletFileName } from '@/ import { authStore } from '@/store/authStore' import { jamSettingsStore, useDeveloperMode } from '@/store/jamSettingsStore' import { EarnReportPage } from './components/earn/report/EarnReportPage' -import { RootLayout } from './components/layout/RootLayout' import { LockWalletConfirmDialog } from './components/ui/jam/LockWalletConfirmDialog' import { Spinner } from './components/ui/spinner' -import { TxHistoryPage } from './components/wallet/TxHistoryPage' import { WalletJarsDetailsPage } from './components/wallet/WalletJarsDetailsPage' import { useJamSessionInfoContext } from './context/JamSessionInfoContext' import { JamSessionInfoContextProvider } from './context/JamSessionInfoContextProvider' @@ -56,7 +54,6 @@ import { useJamWalletInfoContext } from './context/JamWalletInfoContext' import { JmWebsocketContextProvider } from './context/JmWebsocketContextProvider' import { getErrorReason } from './lib/errorReason' import { jmSessionStore } from './store/jmSessionStore' -import { jmTxStore, type JmTxInfos } from './store/jmTxStore' import type { Milliseconds } from './types/global' const DevSetupPage = lazy(() => import('@/components/dev/DevSetupPage')) @@ -156,15 +153,7 @@ function App() { const router = createBrowserRouter( createRoutesFromElements( - - - - } - errorElement={} - > + } errorElement={}> : } /> } /> } /> - } - /> + } /> } /> - } /> {isDeveloperMode && isDebugFeatureEnabled('devPage') && ( { const reason = getErrorReason(error, t('global.errors.reason_unknown')) - const errorMessage = t('settings.fees.error_loading_fee_config_failed', { reason }) + // TODO: i18n + const errorMessage = t('Error while loading fee values.: {{ reason }}', { reason }) toast.error(errorMessage) console.error(errorMessage) }) @@ -393,7 +379,6 @@ const RELOAD_WALLET_INFO_DELAY: { AFTER_UTXO_CHANGE: Milliseconds AFTER_BLOCK_HEIGHT_CHANGE: Milliseconds AFTER_TAKER_STOPPED: Milliseconds - AFTER_TX_MESSAGE: Milliseconds } = { // After rescanning, it is necessary to give the JM backend some time to synchronize. // A couple of seconds should be enough, however, this depends on the user hardware @@ -411,9 +396,6 @@ const RELOAD_WALLET_INFO_DELAY: { // Small delay is sufficient after block height change AFTER_TAKER_STOPPED: 210, - - // Small delay is sufficient after an incoming tx message via websocket - AFTER_TX_MESSAGE: 210, } /** @@ -435,9 +417,6 @@ const WalletInfoAutoReload = () => { const previousBlockHeightRef = useRef(currentBlockHeight) const previousTakerRunningRef = useRef(currentTakerRunning) - const jmTxs = useStore(jmTxStore, (state) => state.state) - const previousJmTxsRef = useRef(jmTxs) - const { refetch: refetchWalletBalance, utxosHashHex } = useJamWalletInfoContext() useEffect( @@ -507,26 +486,6 @@ const WalletInfoAutoReload = () => { [refetchWalletBalance, utxosHashHex], ) - useEffect( - function refetchWalletInfoAfterTxMessage() { - const txsChanged = previousJmTxsRef.current !== jmTxs - previousJmTxsRef.current = jmTxs - if (!txsChanged) { - return - } - - const delayBefore = RELOAD_WALLET_INFO_DELAY.AFTER_TX_MESSAGE - console.debug('Trigger refetch looking for funds AFTER_TX_MESSAGE with delay %d...', delayBefore) - - const abortCtrl = new AbortController() - refetchWalletBalance({ delayBefore, signal: abortCtrl.signal }).catch((error: unknown) => { - console.warn('Error while auto-reloading wallet info AFTER_TX_MESSAGE finished', error) - }) - return () => abortCtrl.abort('useEffect(AFTER_TX_MESSAGE) ended') - }, - [refetchWalletBalance, jmTxs], - ) - useEffect( function refetchWalletInfoAfterTakerStopped() { const takerStopped = previousTakerRunningRef.current === true && currentTakerRunning === false diff --git a/src/components/LogsOverlay.tsx b/src/components/LogsOverlay.tsx index d1a8b7c7..10901ca1 100644 --- a/src/components/LogsOverlay.tsx +++ b/src/components/LogsOverlay.tsx @@ -11,7 +11,7 @@ export function LogsOverlay({ open, onOpenChange }: LogsOverlayProps) { const { t } = useTranslation() return ( onOpenChange(false)}> - + diff --git a/src/components/MainWalletPage.test.tsx b/src/components/MainWalletPage.test.tsx index 555a5081..cfb44ec8 100644 --- a/src/components/MainWalletPage.test.tsx +++ b/src/components/MainWalletPage.test.tsx @@ -1,8 +1,8 @@ +import type { ReactNode } from 'react' import { fireEvent, render, screen } from '@testing-library/react' import { describe, expect, it, vi, beforeEach } from 'vitest' import type { Jar } from '@/context/JamWalletInfoContext' import type { WalletFileName } from '@/lib/utils' -import type { JarIndex } from '@/types/global' import MainWalletPage from './MainWalletPage' const navigateMock = vi.fn() @@ -32,38 +32,23 @@ vi.mock('@/context/JamWalletInfoContext', () => ({ useJars: () => ({ jars }), })) -vi.mock('@/store/jamSettingsStore', () => ({ - usePreviewFeatures: () => ({ - 'tx-history': true, - }), +vi.mock('@/lib/utils', () => ({ + cn: (...args: unknown[]) => args.filter(Boolean).join(' '), + shortenStringMiddle: (s: string) => s, + walletDisplayName: (s: string) => s, +})) + +vi.mock('@/components/ui/jam/ClickableJar', () => ({ + ClickableJar: ({ name, onClick }: { name: string; onClick: () => void }) => , })) vi.mock('./wallet/WalletJarsDetailsOverlay', () => ({ - WalletJarsDetailsOverlay: ({ - open, - onOpenChange, - selectedJarIndex, - }: { - open: boolean - onOpenChange?: (open: boolean) => void - selectedJarIndex?: JarIndex - }) => ( -
- {open ? 'open' : 'closed'} - {open ? 'open' : 'closed'} - {selectedJarIndex ?? 'undefined'} - -
+ WalletJarsDetailsOverlay: ({ open }: { open: boolean }) => ( +
{open ? 'open' : 'closed'}
), })) -vi.mock('./wallet/TxHistoryContent', () => ({ - TxHistoryContent: () =>
, -})) - -vi.mock('@/components/ui/jam/Balance', () => ({ +vi.mock('./ui/jam/Balance', () => ({ Balance: ({ valueString, onClick }: { valueString: string; onClick?: () => void }) => ( {valueString} ), @@ -73,6 +58,23 @@ vi.mock('./ui/spinner', () => ({ Spinner: () =>
, })) +vi.mock('@/components/ui/tooltip', () => ({ + Tooltip: ({ children }: { children?: ReactNode }) =>
{children}
, + TooltipTrigger: ({ children }: { children?: ReactNode }) =>
{children}
, + TooltipContent: ({ children }: { children?: ReactNode }) =>
{children}
, +})) + +vi.mock('@/components/ui/alert', () => ({ + Alert: ({ children }: { children?: ReactNode }) =>
{children}
, + AlertDescription: ({ children }: { children?: ReactNode }) =>
{children}
, +})) + +vi.mock('@/components/ui/button', () => ({ + Button: ({ children, onClick }: { children?: ReactNode; onClick?: () => void }) => ( + + ), +})) + const walletFileName = 'wallet.jmdat' as WalletFileName const makeJar = (jarIndex: number, name: string): Jar => @@ -84,7 +86,6 @@ const makeJar = (jarIndex: number, name: string): Jar => calculatedTotalBalanceInSats: 100, calculatedAvailableBalanceInSats: 100, calculatedFrozenOrLockedBalanceInSats: 0, - calculatedAvailableFrozenBalanceInSats: 0, }, }) as unknown as Jar @@ -104,20 +105,10 @@ describe('MainWalletPage', () => { it('renders balance and jars, and opens the jar overlay on click', () => { render() expect(screen.getByText('5000')).toBeInTheDocument() - expect(screen.getByTestId('WalletJarsDetailsOverlay#open')).toHaveTextContent('closed') - expect(screen.getByTestId('WalletJarsDetailsOverlay#selectedJarIndex')).toHaveTextContent('undefined') + expect(screen.getByTestId('overlay')).toHaveTextContent('closed') - fireEvent.click(screen.getByText(jars[0].name)) - expect(screen.getByTestId('WalletJarsDetailsOverlay#open')).toHaveTextContent('open') - expect(screen.getByTestId('WalletJarsDetailsOverlay#selectedJarIndex')).toHaveTextContent(String(jars[0].jarIndex)) - - fireEvent.click(screen.getByTestId('WalletJarsDetailsOverlay#onOpenChange')) - expect(screen.getByTestId('WalletJarsDetailsOverlay#open')).toHaveTextContent('closed') - expect(screen.getByTestId('WalletJarsDetailsOverlay#selectedJarIndex')).toHaveTextContent('undefined') - - fireEvent.click(screen.getByTestId('WalletJarsDetailsOverlay#onOpenChange')) - expect(screen.getByTestId('WalletJarsDetailsOverlay#open')).toHaveTextContent('open') - expect(screen.getByTestId('WalletJarsDetailsOverlay#selectedJarIndex')).toHaveTextContent('undefined') + fireEvent.click(screen.getByText('Jar 0')) + expect(screen.getByTestId('overlay')).toHaveTextContent('open') }) it('navigates to deposit and withdraw routes', () => { @@ -135,14 +126,10 @@ describe('MainWalletPage', () => { expect(refetch).toHaveBeenCalled() }) - it('keeps jars visible and clickable while fetching in the background', () => { + it('shows a jars spinner while fetching and refreshes on click', () => { walletInfo = { ...walletInfo, isFetching: true } render() - expect(screen.getByText(jars[0].name)).toBeInTheDocument() - - fireEvent.click(screen.getByText(jars[0].name)) - expect(screen.getByTestId('WalletJarsDetailsOverlay#open')).toHaveTextContent('open') - expect(screen.getByTestId('WalletJarsDetailsOverlay#selectedJarIndex')).toHaveTextContent(String(jars[0].jarIndex)) + expect(screen.getByTestId('spinner')).toBeInTheDocument() fireEvent.click(screen.getByText('global.refresh')) expect(refetch).toHaveBeenCalled() }) @@ -152,17 +139,4 @@ describe('MainWalletPage', () => { fireEvent.click(screen.getByText('5000')) expect(toggleDisplayMode).toHaveBeenCalled() }) - - it('expands and collapses transaction history via accordion toggle button', () => { - render() - expect(screen.queryByTestId('TxHistoryContent')).not.toBeInTheDocument() - - const toggleButton = screen.getByTitle('tx_history.expand_history') - fireEvent.click(toggleButton) - expect(screen.getByTestId('TxHistoryContent')).toBeInTheDocument() - - const collapseButton = screen.getByTitle('tx_history.collapse_history') - fireEvent.click(collapseButton) - expect(screen.queryByTestId('TxHistoryContent')).not.toBeInTheDocument() - }) }) diff --git a/src/components/MainWalletPage.tsx b/src/components/MainWalletPage.tsx index 68b8aa9b..0d4b511e 100644 --- a/src/components/MainWalletPage.tsx +++ b/src/components/MainWalletPage.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import { ChevronDownIcon, DownloadIcon, InfoIcon, RefreshCwIcon, UploadIcon } from 'lucide-react' +import { DownloadIcon, InfoIcon, RefreshCwIcon, UploadIcon } from 'lucide-react' import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom' import { Alert, AlertDescription } from '@/components/ui/alert' @@ -14,14 +14,10 @@ import { useWalletBalanceSummary, type Jar as JarObject, } from '@/context/JamWalletInfoContext' -import { getErrorReason } from '@/lib/errorReason' import type { WalletFileName } from '@/lib/utils' import { cn, shortenStringMiddle, walletDisplayName } from '@/lib/utils' -import { usePreviewFeatures } from '@/store/jamSettingsStore' import { Balance } from './ui/jam/Balance' import { Spinner } from './ui/spinner' -import { TxHistoryContent } from './wallet/TxHistoryContent' -import { TxHistoryOverlay } from './wallet/TxHistoryOverlay' import { WalletJarsDetailsOverlay } from './wallet/WalletJarsDetailsOverlay' interface MainWalletPageProps { @@ -31,11 +27,8 @@ interface MainWalletPageProps { export default function MainWalletPage({ walletFileName }: MainWalletPageProps) { const { t } = useTranslation() const navigate = useNavigate() - const previewFeatures = usePreviewFeatures() const [selectedJar, setSelectedJar] = useState() const [isWalletJarsDetailsOpen, setIsWalletJarsDetailsOpen] = useState(false) - const [isTxHistoryOpen, setIsTxHistoryOpen] = useState(false) - const [isHistoryExpanded, setIsHistoryExpanded] = useState(false) const { toggleDisplayMode } = useJamDisplayContext() const { isLoading, isFetching, error, refetch: refetchWalletData } = useJamWalletInfoContext() @@ -61,10 +54,6 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps) walletFileName={walletFileName} selectedJarIndex={selectedJar?.jarIndex} /> - {previewFeatures?.['tx-history'] === true ? ( - - ) : null} -

@@ -78,7 +67,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps) {t('global.loading')}

) : ( -
+
toggleDisplayMode()} valueString={String(walletBalanceSummary.calculatedTotalBalanceInSats)} @@ -87,7 +76,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
)}
-
+
- - {previewFeatures?.['tx-history'] === true ? ( -
-
- -
-
- ) : null}
- {isHistoryExpanded && ( - setIsTxHistoryOpen(true)} - className="w-full max-w-6xl" - /> - )} - - {error ? ( + {error && ( {t('global.errors.error_loading_wallet_failed', { - reason: getErrorReason(error, t('global.errors.reason_unknown')), + reason: error.message || t('global.errors.reason_unknown'), })} - - ) : null} + )}
@@ -155,7 +115,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
- {isLoading ? ( + {isFetching ? (
{t('global.loading')} @@ -186,7 +146,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
- diff --git a/src/components/create/CreateStepConfirm.tsx b/src/components/create/CreateStepConfirm.tsx index 729954cf..fff9b984 100644 --- a/src/components/create/CreateStepConfirm.tsx +++ b/src/components/create/CreateStepConfirm.tsx @@ -29,7 +29,13 @@ const createFormSchema = (t: TFunction) => { return yup .object({ revealSensitiveInfo: yup.boolean().required(), - backupConfirmed: yup.boolean().isTrue(t('create_wallet.subtitle_wallet_created')), + backupConfirmed: yup + .boolean() + .isTrue( + /* TODO: i18n */ t( + 'Please write down your seed phrase and password! Without this information you will not be able to access and recover your wallet!', + ), + ), }) .required() } @@ -71,10 +77,10 @@ export const CreateStepConfirm = ({ useEffect(() => { if (backupConfirmed) return - const toastId = toast.info(t('create_wallet.alert_save_seed_title'), { + const toastId = toast.info(/* TODO: i18n */ 'Save Your Seed Phrase', { id: 'save-seed-phrase-reminder', icon: , - description: t('create_wallet.subtitle_wallet_created'), + description: /* TODO: change i18n key ("alert_description") */ t('create_wallet.subtitle_wallet_created'), duration: Number.POSITIVE_INFINITY, }) @@ -112,22 +118,15 @@ export const CreateStepConfirm = ({
- + setValue('revealSensitiveInfo', checked, { shouldValidate: true, shouldTouch: true }) } /> - - {t('create_wallet.confirmation_toggle_reveal_info')} - + {t('create_wallet.confirmation_toggle_reveal_info')} {errors.revealSensitiveInfo?.message && (
{errors.revealSensitiveInfo.message}
@@ -135,16 +134,15 @@ export const CreateStepConfirm = ({
- + setValue('backupConfirmed', checked, { shouldValidate: true })} /> - + {t('create_wallet.confirmation_toggle_info_written_down')} diff --git a/src/components/create/CreateStepVerifyMnemonic.tsx b/src/components/create/CreateStepVerifyMnemonic.tsx index f73a1c74..4612718f 100644 --- a/src/components/create/CreateStepVerifyMnemonic.tsx +++ b/src/components/create/CreateStepVerifyMnemonic.tsx @@ -87,7 +87,7 @@ export const CreateStepVerifyMnemonic = ({ mnemonicPhrase, onVerified, onBack }:
-
+
{!isCorrect && mnemonicPhrase.map((_, index) => { const word = selectedWords[index] @@ -112,13 +112,10 @@ export const CreateStepVerifyMnemonic = ({ mnemonicPhrase, onVerified, onBack }: return (
{isFilled ? ( - {isHidden ? : word} + {isHidden ? : word} ) : ( ··· )} @@ -138,7 +135,7 @@ export const CreateStepVerifyMnemonic = ({ mnemonicPhrase, onVerified, onBack }: })}
{allSelected && isCorrect && ( -
+
{t('create_wallet.verify_mnemonic.feedback_mnemonic_confirmed')}
@@ -146,7 +143,7 @@ export const CreateStepVerifyMnemonic = ({ mnemonicPhrase, onVerified, onBack }:
{!allSelected && ( -
+
{shuffledWords.map((word, index) => { const isPicked = pickedIndicesSet.has(index) const isWrong = wrongButtonIndex === index @@ -157,7 +154,7 @@ export const CreateStepVerifyMnemonic = ({ mnemonicPhrase, onVerified, onBack }: size="lg" variant={isWrong ? 'destructive' : isPicked ? 'outline' : 'secondary'} disabled={isPicked || wrongButtonIndex !== undefined} - className={cn('min-w-0 px-2 font-mono text-sm transition-all', { + className={cn('font-mono text-sm transition-all', { 'pointer-events-none opacity-25': isPicked, 'animate-shake': isWrong, })} @@ -170,21 +167,24 @@ export const CreateStepVerifyMnemonic = ({ mnemonicPhrase, onVerified, onBack }:
)} -
+
{skipWalletBackupVerification && !isCorrect && (
diff --git a/src/components/create/CreateStepWalletDetails.tsx b/src/components/create/CreateStepWalletDetails.tsx index 2c52e5c6..2dbdb57a 100644 --- a/src/components/create/CreateStepWalletDetails.tsx +++ b/src/components/create/CreateStepWalletDetails.tsx @@ -1,6 +1,5 @@ import type { ComponentProps } from 'react' -import type { SessionResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' -import { useTranslation } from 'react-i18next' +import type { SessionResponse } from '@joinmarket-webui/joinmarket-api-ts/jm' import { Link } from 'react-router-dom' import { Button } from '@/components/ui/button' import { routes } from '@/constants/routes' @@ -13,24 +12,20 @@ type CreateStepWalletDetailsProps = ComponentProps & { } export const CreateStepWalletDetails = ({ sessionInfo, ...createFormProps }: CreateStepWalletDetailsProps) => { - const { t } = useTranslation() - return (
{sessionInfo?.session === true ? ( - + ) : ( )}

- {t('create_wallet.text_login_hint')}{' '} + {/* TODO: i18n */} + Already have a wallet?{' '}

diff --git a/src/components/create/CreateWalletForm.tsx b/src/components/create/CreateWalletForm.tsx index 834d735e..9e16a7a2 100644 --- a/src/components/create/CreateWalletForm.tsx +++ b/src/components/create/CreateWalletForm.tsx @@ -6,7 +6,7 @@ import { useForm, type Mode, type SubmitHandler } from 'react-hook-form' import { useTranslation } from 'react-i18next' import * as yup from 'yup' import { Button } from '@/components/ui/button' -import { Field, FieldError, FieldLabel } from '@/components/ui/field' +import { Field, FieldLabel } from '@/components/ui/field' import { Input } from '@/components/ui/input' import { InputGroup, InputGroupAddon, InputGroupInput } from '@/components/ui/input-group' import { Spinner } from '@/components/ui/spinner' @@ -91,81 +91,89 @@ export const CreateWalletForm = ({ return (
void doOnSubmit(event)} className={cn('flex flex-col gap-4', className)} noValidate> - - {t('create_wallet.label_wallet_name')} - - {errors.walletName?.message && {errors.walletName.message}} - - - - {t('create_wallet.label_password')} - - + + {t('create_wallet.label_wallet_name')} + - - - - - - - - {errors.password?.message && {errors.password.message}} - + + {errors.walletName?.message &&
{errors.walletName.message}
} +
- - {t('create_wallet.label_password_confirm')} - - - - - - - - - - {errors.confirmPassword?.message && {errors.confirmPassword?.message}} - +
+ + {t('create_wallet.label_password')} + + + + + + + + + + + {errors.password?.message &&
{errors.password.message}
} +
+ +
+ + {t('create_wallet.label_password_confirm')} + + + + + + + + + + + {errors.confirmPassword?.message && ( +
{errors.confirmPassword?.message}
+ )} +
)} - - + + ) } + const isLoading = freezeUtxo.isPending || directSend.isPending + return ( - handleOpenChange(false)} - onPrimary={() => void handleNext()} - primaryDisabled={!canProceed()} - isLoading={freezeUtxo.isPending || directSend.isPending} - primaryLabel={ - step === 'freeze_utxos' + + {step !== 'select_date' && ( + + )} + + + ) } return ( - - - + + + + {t('earn.fidelity_bond.create_fidelity_bond.title')} + {t('earn.fidelity_bond.subtitle')} + + + {step !== 'creating' && step !== 'success' && } + + {error && ( + + + {error} + + )} + +
+ +
+ + {renderFooter()} +
+
) } diff --git a/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.test.tsx b/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.test.tsx index fd0afdd3..0be8d438 100644 --- a/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.test.tsx +++ b/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.test.tsx @@ -13,59 +13,20 @@ vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }), })) +vi.mock('@/components/ui/jam/BitcoinQrCode', () => ({ + BitcoinAddressQrCode: () =>
QR
, +})) + vi.mock('@/lib/utils', () => ({ cn: (...args: unknown[]) => args.filter(Boolean).join(' '), formatSats: (sats: number) => `${sats} sats`, clamp: (val: number, min: number, max: number) => Math.min(Math.max(val, min), max), })) -vi.mock('@/components/ui/jam/Address', () => ({ - Address: ({ value }: { value: string }) => {value}, -})) - -vi.mock('@/components/ui/jam/Balance', () => ({ - Balance: ({ valueString }: { valueString: string }) => {valueString} sats, -})) - vi.mock('@/lib/fidelityBondUtils', () => ({ utxo: { isFidelityBond: vi.fn(), }, - lockdate: { - toDateLabel: () => 'January 1, 2025', - }, -})) - -vi.mock('@/store/jamSettingsStore', () => ({ - useDeveloperMode: () => ({ enabled: false }), -})) - -vi.mock('@/context/JamWalletInfoContext', () => ({ - useJamWalletInfoContext: () => ({ - jars: [ - { jarIndex: 0, name: 'Jar 0', color: '#000', balanceSummary: {}, utxos: [] }, - { jarIndex: 1, name: 'Jar 1', color: '#111', balanceSummary: {}, utxos: [] }, - ], - walletBalanceSummary: { calculatedTotalBalanceInSats: 14000 }, - }), -})) - -vi.mock('@/components/ui/jam/SelectableJar', () => ({ - SelectableJar: ({ - name, - onSelect, - disabled, - isSelected, - }: { - name?: string - onSelect?: () => void - disabled?: boolean - isSelected?: boolean - }) => ( - - ), })) const getBaseWizard = (): Wizard => @@ -73,8 +34,15 @@ const getBaseWizard = (): Wizard => step: 'select_date', setSelectedLockdate: vi.fn(), selectedLockdate: '2025-01', + selectedYear: '2025', + selectedMonth: '01', + minYear: 2024, + minMonth: 1, + yearOptions: [{ value: '2025', label: '2025' }], + monthOptions: [{ value: '01', label: 'Jan' }], + clampLockdate: vi.fn((x: unknown) => x), hasDuplicateLockdate: false, - existingFbLockdates: [], + selectedDateLabel: 'Jan 2025', selectedJarIndex: 0, setSelectedJarIndex: vi.fn(), jarsWithUtxos: [], @@ -83,6 +51,8 @@ const getBaseWizard = (): Wizard => utxoPage: 0, setUtxoPage: vi.fn(), toggleUtxoSelection: vi.fn(), + selectAllUtxos: vi.fn(), + deselectAllUtxos: vi.fn(), totalAmount: 1000, isUsingAllFunds: false, utxosToFreeze: [], @@ -102,7 +72,7 @@ describe('CreateFidelityBondDialogSteps', () => { expect(screen.getByText('earn.fidelity_bond.select_date.description')).toBeInTheDocument() expect(screen.getByText('earn.fidelity_bond.select_date.form_label_month')).toBeInTheDocument() - expect(screen.getByText('January 1, 2025')).toBeInTheDocument() + expect(screen.getByText('Jan 2025')).toBeInTheDocument() }) it('renders select_jar step with jars', () => { @@ -120,9 +90,8 @@ describe('CreateFidelityBondDialogSteps', () => { render() expect(screen.getByText('earn.fidelity_bond.select_jar.title')).toBeInTheDocument() - // Jar 0 is eligible, Jar 1 has no eligible utxos and is disabled - expect(screen.getByText('Jar 0')).toBeEnabled() - expect(screen.getByText('Jar 1')).toBeDisabled() + expect(screen.getByText('Jar 0')).toBeInTheDocument() + expect(screen.getByText('5000 sats')).toBeInTheDocument() }) it('renders select_utxos step', () => { @@ -158,7 +127,7 @@ describe('CreateFidelityBondDialogSteps', () => { expect(screen.getByText('earn.fidelity_bond.review_inputs.label_lock_date')).toBeInTheDocument() expect(screen.getByText('bc1...')).toBeInTheDocument() - expect(screen.queryByTestId('qr-code')).not.toBeInTheDocument() + expect(screen.getByTestId('qr-code')).toBeInTheDocument() }) it('renders creating step', () => { @@ -172,18 +141,18 @@ describe('CreateFidelityBondDialogSteps', () => { it('renders success step', () => { const wizard = getBaseWizard() wizard.step = 'success' - wizard.txResult = { txinfo: { txid: '1234abcd', hex: '' } } + wizard.txResult = { txinfo: { txid: '1234abcd' } } render() expect(screen.getByText('earn.fidelity_bond.create_fidelity_bond.success_text')).toBeInTheDocument() expect(screen.getByText('1234abcd')).toBeInTheDocument() }) - it('passes existing fidelity-bond lock dates to the date selector', () => { + it('warns about a duplicate lock date on the select_date step', () => { const wizard = getBaseWizard() - wizard.existingFbLockdates = ['2025-01'] + wizard.hasDuplicateLockdate = true render() - expect(screen.getByText('January 1, 2025')).toBeInTheDocument() + expect(screen.getByTestId('trans-earn.fidelity_bond.select_date.warning_fb_with_same_expiry')).toBeInTheDocument() }) it('highlights the selected jar and shows the no-jars alert state', () => { @@ -208,7 +177,7 @@ describe('CreateFidelityBondDialogSteps', () => { ] as unknown as Wizard['jarsWithUtxos'] render() expect(screen.getByText('Jar 0')).toBeInTheDocument() - expect(screen.getByText('Jar 1')).toHaveAttribute('data-selected', 'true') + expect(screen.getByText('Jar 1')).toBeInTheDocument() }) it('renders select_utxos with a selected utxo, pagination, and the all-funds warning', () => { diff --git a/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.tsx b/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.tsx index fc8b803b..8e3e01d5 100644 --- a/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.tsx +++ b/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondDialogSteps.tsx @@ -1,7 +1,23 @@ -import { AlertTriangleIcon, CheckIcon, CalendarIcon, WalletIcon, CoinsIcon, LockIcon } from 'lucide-react' +import { + AlertTriangleIcon, + CheckCircle2Icon, + CheckIcon, + CopyIcon, + Loader2Icon, + CalendarIcon, + WalletIcon, + CoinsIcon, + LockIcon, +} from 'lucide-react' import { Trans } from 'react-i18next' +import { toast } from 'sonner' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +import { Button } from '@/components/ui/button' +import { buttonVariants } from '@/components/ui/button-variants' import { Card, CardContent } from '@/components/ui/card' +import { BitcoinAddressQrCode } from '@/components/ui/jam/BitcoinQrCode' +import { CopyButton } from '@/components/ui/jam/CopyButton' +import { Label } from '@/components/ui/label' import { Pagination, PaginationContent, @@ -9,22 +25,11 @@ import { PaginationNext, PaginationPrevious, } from '@/components/ui/pagination' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Spinner } from '@/components/ui/spinner' +import { Switch } from '@/components/ui/switch' import * as fb from '@/lib/fidelityBondUtils' -import { clamp, cn } from '@/lib/utils' -import { - AddressPreview, - ConfirmationToggle, - CopyableField, - FidelityBondAmount, - InfoCard, - InlineLoading, - JarBadge, - PendingStep, - StepIntro, - SuccessHeading, -} from '../fidelity-bond/FidelityBondDialogParts' -import { FidelityBondJarSelector } from '../fidelity-bond/FidelityBondJarSelector' -import { LockdateSelect } from '../fidelity-bond/LockdateSelect' +import { clamp, cn, formatSats } from '@/lib/utils' import type { useCreateFidelityBondWizard } from './useCreateFidelityBondWizard' type Wizard = ReturnType @@ -38,7 +43,15 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial step, setSelectedLockdate, selectedLockdate, - existingFbLockdates, + selectedYear, + selectedMonth, + minYear, + minMonth, + yearOptions, + monthOptions, + clampLockdate, + hasDuplicateLockdate, + selectedDateLabel, selectedJarIndex, setSelectedJarIndex, jarsWithUtxos, @@ -47,6 +60,8 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial utxoPage, setUtxoPage, toggleUtxoSelection, + selectAllUtxos, + deselectAllUtxos, totalAmount, isUsingAllFunds, utxosToFreeze, @@ -59,42 +74,144 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial t, } = wizard - const selectedJar = jarsWithUtxos.find((jar) => jar.jarIndex === selectedJarIndex) - const selectedDateLabel = selectedLockdate ? fb.lockdate.toDateLabel(selectedLockdate) : null - switch (step) { case 'select_date': return (
- +
+
+ +
+
+

{t('earn.fidelity_bond.select_date.description')}

+

{t('earn.fidelity_bond.select_date.subtitle')}

+
+
- +
+
+ + +
+
+ + +
+
+ + {selectedLockdate && ( +
+

+ {t('earn.fidelity_bond.select_date.label_selected_lock_date')} +

+

{selectedDateLabel}

+
+ )} + + {hasDuplicateLockdate && ( + + + + + Warning: A fidelity bond with the same expiry date already exists. + + + + )}
) case 'select_jar': return (
- +
+
+ +
+
+

{t('earn.fidelity_bond.select_jar.title')}

+

{t('earn.fidelity_bond.select_jar.description')}

+
+
- !jarsWithUtxos.some((eligible) => eligible.jarIndex === jar.jarIndex)} - /> +
+ {jarsWithUtxos.map((jar) => { + const isSelected = selectedJarIndex === jar.jarIndex + return ( + setSelectedJarIndex(jar.jarIndex)} + > + +
+
+
+

{jar.name}

+

+ {t('earn.fidelity_bond.select_jar.text_available_utxos', { + count: jar.utxos.filter((u) => !u.frozen && !fb.utxo.isFidelityBond(u)).length, + })} +

+
+
+
+

+ {formatSats(jar.balanceSummary.calculatedAvailableBalanceInSats)} +

+ {isSelected && } +
+ + + ) + })} +
{jarsWithUtxos.length === 0 && ( @@ -107,11 +224,27 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial case 'select_utxos': return (
- +
+
+ +
+
+

{t('earn.fidelity_bond.select_utxos.title')}

+

+ {t('earn.fidelity_bond.select_utxos.description', { jar: selectedJarIndex })} +

+
+
+ +
+ + +
{(() => { @@ -136,7 +269,7 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial
- +

+ {formatSats(utxo.value)} +

@@ -192,11 +324,9 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial {selectedUtxos.length > 0 && (
-
- - {t('earn.fidelity_bond.select_utxos.label_total_selected')} - - +
+ {t('earn.fidelity_bond.select_utxos.label_total_selected')} + {formatSats(totalAmount)}
)} @@ -220,14 +350,18 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial case 'freeze_utxos': return (
- +
+
+ +
+
+

{t('earn.fidelity_bond.freeze_utxos.title')}

+

{t('earn.fidelity_bond.freeze_utxos.subtitle')}

+
+
-
+

{t('earn.fidelity_bond.freeze_utxos.label_selected_utxos', { count: selectedUtxos.length })}

@@ -235,14 +369,14 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial {selectedUtxos.map((utxo) => (
{utxo.utxo.slice(0, 24)}... - + {formatSats(utxo.value)}
))}
{utxosToFreeze.length > 0 && ( -
+

{t('earn.fidelity_bond.freeze_utxos.label_utxos_to_freeze', { count: utxosToFreeze.length })}

@@ -255,7 +389,7 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial {utxosToFreeze.map((utxo) => (
{utxo.utxo.slice(0, 24)}... - + {formatSats(utxo.value)}
))}
@@ -269,24 +403,57 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial return (
-
- +
+
+

+ {t('earn.fidelity_bond.review_inputs.label_lock_date')} +

{selectedDateLabel}

- - - - +
+
+

{t('earn.fidelity_bond.review_inputs.label_jar')}

+

+ {t('earn.fidelity_bond.review_inputs.label_jar_n', { jar: selectedJarIndex })} +

+
- - - +
+

{t('earn.fidelity_bond.review_inputs.label_amount')}

+

{formatSats(totalAmount)}

+
{timelockAddressQuery.isLoading ? ( - +
+
+ +

{t('earn.fidelity_bond.text_loading')}

+
+
) : ( - address && + address && ( +
+
+ +
+
+ +
+ {address} + } + successText={} + className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} + onSuccess={() => toast.success(t('receive.text_copy_address'))} + onError={() => toast.error(t('receive.error_copy_address_failed'))} + /> +
+
+
+ ) )} @@ -300,50 +467,105 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial - +
+ setConfirmationChecked(checked)} + /> +
+ +

+ {t('earn.fidelity_bond.create_form.confirmation_toggle_subtitle')} +

+
+
) case 'creating': return ( - +
+
+ +
+ +
+
+

{t('earn.fidelity_bond.text_creating')}

+

{t('earn.fidelity_bond.text_creating_subtitle')}

+
) case 'success': return (
- +
+
+ +
+

{t('earn.fidelity_bond.create_fidelity_bond.success_text')}

+

+ {t('earn.fidelity_bond.create_fidelity_bond.text_success_subtitle')} +

+
- +
+

+ {t('earn.fidelity_bond.create_fidelity_bond.label_lock_date')} +

{selectedDateLabel}

- +
{address && ( - +
+ +
+ {address} + } + successText={} + className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} + onSuccess={() => toast.success(t('receive.text_copy_address'))} + onError={() => toast.error(t('receive.error_copy_address_failed'))} + /> +
+
)} {txResult?.txinfo?.txid && ( - +
+ +
+ + {txResult.txinfo.txid} + + } + successText={} + className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} + onSuccess={() => + toast.success(t('earn.fidelity_bond.create_fidelity_bond.text_copy_transaction_id')) + } + onError={(error) => { + const reason = + (error instanceof Error ? error.message : undefined) || t('global.errors.reason_unknown') + toast.error(t('global.errors.error_copy_to_clipboard_failed', { reason })) + }} + /> +
+
)}
diff --git a/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondFormSchema.ts b/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondFormSchema.ts index 1d4b1e8a..b07a30aa 100644 --- a/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondFormSchema.ts +++ b/src/components/earn/CreateFidelityBondDialog/CreateFidelityBondFormSchema.ts @@ -1,7 +1,6 @@ import type { TFunction } from 'i18next' import * as yup from 'yup' import * as fb from '@/lib/fidelityBondUtils' -import { sourceJarField } from '@/lib/formValidation' import type { JarIndex } from '@/types/global' export type SourceValue = { @@ -30,8 +29,10 @@ export const createFidelityBondFormSchema = ( t: TFunction<'translation', undefined>, ): yup.ObjectSchema => { const requiredMessage = t('global.errors.reason_unknown') - /* TODO: i18n: provide dedicated fidelity-bond source-jar validation copy */ - const invalidSourceJarFeedbackMessage = t('receive.feedback_invalid_source_jar') + const invalidSourceJarFeedbackMessage = t('receive.feedback_invalid_source_jar', { + /* TODO: i18n: provide dedicated fidelity-bond source-jar validation copy */ + defaultValue: 'Please select a source jar.', + }) const validLockdates = lockdateOptions.map((option) => option.value) return yup @@ -39,7 +40,15 @@ export const createFidelityBondFormSchema = ( lockdate: yup.string().oneOf(validLockdates, requiredMessage).required(requiredMessage), source: yup .object({ - fromJar: sourceJarField(invalidSourceJarFeedbackMessage, (jarIndex) => jarIndexes.includes(jarIndex)), + fromJar: yup + .number() + .integer(invalidSourceJarFeedbackMessage) + .required(invalidSourceJarFeedbackMessage) + .test( + 'valid-source-jar-index-test', + invalidSourceJarFeedbackMessage, + (value) => typeof value === 'number' && jarIndexes.includes(value), + ), }) .required(), utxoIds: yup.array().of(yup.string().required(requiredMessage)).min(1, requiredMessage).required(requiredMessage), diff --git a/src/components/earn/fidelity-bond/StepProgress.test.tsx b/src/components/earn/CreateFidelityBondDialog/StepProgress.test.tsx similarity index 60% rename from src/components/earn/fidelity-bond/StepProgress.test.tsx rename to src/components/earn/CreateFidelityBondDialog/StepProgress.test.tsx index 5a9c2dbb..825a33e5 100644 --- a/src/components/earn/fidelity-bond/StepProgress.test.tsx +++ b/src/components/earn/CreateFidelityBondDialog/StepProgress.test.tsx @@ -1,29 +1,22 @@ -import { render, screen } from '@testing-library/react' +import { render } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' import { StepProgress } from './StepProgress' -vi.mock('react-i18next', () => ({ - useTranslation: () => ({ - t: (key: string, options?: Record) => key + (options ? ' ' + JSON.stringify(options) : ''), - }), -})) - vi.mock('@/lib/utils', () => ({ cn: (...args: unknown[]) => args.filter(Boolean).join(' '), })) describe('StepProgress', () => { - it('renders correct number of steps and the step label', () => { + it('renders correct number of steps', () => { const { container } = render() - const steps = container.querySelectorAll('.rounded-full') + const steps = container.firstChild?.childNodes expect(steps).toHaveLength(3) - expect(screen.getByText('global.step_label {"current":1,"total":3}')).toBeInTheDocument() }) it('applies correct classes based on currentStep', () => { const { container } = render() - const steps = container.querySelectorAll('.rounded-full') + const steps = container.firstChild?.childNodes as NodeListOf // Step 0: completed (i < currentStep) expect(steps[0].className).toContain('bg-primary w-8') diff --git a/src/components/earn/CreateFidelityBondDialog/StepProgress.tsx b/src/components/earn/CreateFidelityBondDialog/StepProgress.tsx new file mode 100644 index 00000000..2b628090 --- /dev/null +++ b/src/components/earn/CreateFidelityBondDialog/StepProgress.tsx @@ -0,0 +1,22 @@ +import { cn } from '@/lib/utils' + +type StepProgressProps = { + currentStep: number + totalSteps: number +} + +export function StepProgress({ currentStep, totalSteps }: StepProgressProps) { + return ( +
+ {Array.from({ length: totalSteps }, (_, i) => ( +
+ ))} +
+ ) +} diff --git a/src/components/earn/CreateFidelityBondDialog/types.test.ts b/src/components/earn/CreateFidelityBondDialog/types.test.ts deleted file mode 100644 index 21889412..00000000 --- a/src/components/earn/CreateFidelityBondDialog/types.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { generateLockdateOptions } from './types' - -describe('generateLockdateOptions', () => { - it.each([false, true])('generates well-formed, ordered YYYY-MM values (developer mode: %s)', (isDeveloperMode) => { - const values = generateLockdateOptions(isDeveloperMode).map((option) => option.value) - - for (const value of values) { - expect(value).toMatch(/^\d{4}-(0[1-9]|1[0-2])$/) - } - // zero-padded YYYY-MM sorts lexicographically === chronologically - expect(values.toSorted()).toEqual(values) - }) - - it('includes the past 12 months in developer mode', () => { - const values = generateLockdateOptions(true).map((option) => option.value) - const now = new Date() - const oneYearAgo = `${now.getUTCFullYear() - 1}-${String(now.getUTCMonth() + 1).padStart(2, '0')}` - - expect(values[0]).toBe(oneYearAgo) - expect(values).toHaveLength(133) // -12 .. +120 months - }) -}) diff --git a/src/components/earn/CreateFidelityBondDialog/types.ts b/src/components/earn/CreateFidelityBondDialog/types.ts index 916564c7..3fd6332d 100644 --- a/src/components/earn/CreateFidelityBondDialog/types.ts +++ b/src/components/earn/CreateFidelityBondDialog/types.ts @@ -24,8 +24,7 @@ export function generateLockdateOptions(isDeveloperMode: boolean): { value: fb.L for (let i = startOffset; i <= 120; i++) { const monthOffset = startMonth + i const year = startYear + Math.floor(monthOffset / 12) - // floored modulo — monthOffset is negative for past months in dev mode - const month = (((monthOffset % 12) + 12) % 12) + 1 + const month = (monthOffset % 12) + 1 const lockdate = `${year}-${month.toString().padStart(2, '0')}` as fb.Lockdate const date = new Date(Date.UTC(year, month - 1, 1)) const label = date.toLocaleDateString(undefined, { year: 'numeric', month: 'long' }) diff --git a/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.test.ts b/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.test.ts index 1e7eb60d..6e09b64b 100644 --- a/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.test.ts +++ b/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.test.ts @@ -2,31 +2,22 @@ import { act, renderHook, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import type { Jar } from '@/context/JamWalletInfoContext' import type { Utxo } from '@/hooks/useQueryUtxos' -import { BALANCE_SUMMARY_EMPTY } from '@/lib/balanceSummary' -import { generateLockdateOptions } from './types' import { useCreateFidelityBondWizard } from './useCreateFidelityBondWizard' -const mocks = vi.hoisted(() => { - const addressSummary: Record = { - bcrt1qsource: { status: 'cj-out' }, - } - return { - directSendMutateAsync: vi.fn(), - freezeMutateAsync: vi.fn(), - walletInfoRefetch: vi.fn(), - toastSuccess: vi.fn(), - queryAddress: undefined as string | undefined, - isDeveloperMode: false, - walletInfo: { - jars: [] as Jar[], - fidelityBondSummary: { fbOutputs: [] as Utxo[] }, - addressSummary, - refetch: vi.fn(), - }, - } -}) +const mocks = vi.hoisted(() => ({ + directSendMutateAsync: vi.fn(), + freezeMutateAsync: vi.fn(), + walletInfoRefetch: vi.fn(), + toastSuccess: vi.fn(), + queryAddress: undefined as string | undefined, + walletInfo: { + jars: [] as Jar[], + fidelityBondSummary: { fbOutputs: [] as Utxo[] }, + refetch: vi.fn(), + }, +})) -vi.mock('@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query', () => ({ +vi.mock('@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query', () => ({ directsendMutation: vi.fn(() => ({ mutationKey: ['directsend'] })), freezeMutation: vi.fn(() => ({ mutationKey: ['freeze'] })), gettimelockaddressOptions: vi.fn(() => ({ queryKey: ['timelock-address'] })), @@ -67,7 +58,7 @@ vi.mock('@/hooks/useApiClient', () => ({ vi.mock('@/store/jamSettingsStore', async (importOriginal) => ({ ...(await importOriginal()), - useDeveloperMode: () => ({ enabled: mocks.isDeveloperMode }), + useDeveloperMode: () => ({ enabled: false }), })) const utxo = (overrides: Partial): Utxo => ({ @@ -91,12 +82,12 @@ const jar = (jarIndex: number, utxos: Utxo[]): Jar => jarIndex, name: `Jar ${jarIndex}`, color: '#808080', - balanceSummary: BALANCE_SUMMARY_EMPTY, + balanceSummary: {}, utxos, }) as unknown as Jar -const minLockdateOption = (isDeveloperMode = false) => { - const lockdate = generateLockdateOptions(isDeveloperMode).at(0)?.value +const lockdateFromWizard = (wizard: ReturnType) => { + const lockdate = wizard.clampLockdate('1900-01') if (!lockdate) throw new Error('Expected a generated lockdate option') return lockdate } @@ -109,11 +100,7 @@ describe('useCreateFidelityBondWizard', () => { mocks.walletInfoRefetch.mockResolvedValue(undefined) mocks.walletInfo.refetch = mocks.walletInfoRefetch mocks.queryAddress = 'bcrt1qtimelockdestination' - mocks.isDeveloperMode = false mocks.walletInfo.fidelityBondSummary = { fbOutputs: [] } - mocks.walletInfo.addressSummary = { - bcrt1qsource: { status: 'cj-out' }, - } mocks.walletInfo.jars = [ jar(0, [ utxo({ utxo: 'small:0', value: 10_000 }), @@ -130,26 +117,26 @@ describe('useCreateFidelityBondWizard', () => { ] }) - it('derives selectable utxos and keeps selection to one utxo', async () => { + it('derives selectable utxos and selection totals from wallet state', async () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) act(() => result.current.setSelectedJarIndex(0)) expect(result.current.availableUtxos.map((entry) => entry.utxo)).toEqual(['large:0', 'small:0']) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) - expect(result.current.selectedUtxos.map((entry) => entry.utxo)).toEqual(['large:0']) - expect(result.current.totalAmount).toBe(50_000) - expect(result.current.utxosToFreeze.map((entry) => entry.utxo)).toEqual(['small:0']) + expect(result.current.selectedUtxos.map((entry) => entry.utxo)).toEqual(['large:0', 'small:0']) + expect(result.current.totalAmount).toBe(60_000) + expect(result.current.utxosToFreeze.map((entry) => entry.utxo)).toEqual([]) expect(result.current.isUsingAllFunds).toBe(false) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[1])) + act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) expect(result.current.selectedUtxos.map((entry) => entry.utxo)).toEqual(['small:0']) expect(result.current.utxosToFreeze.map((entry) => entry.utxo)).toEqual(['large:0']) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[1])) + act(() => result.current.deselectAllUtxos()) await waitFor(() => expect(result.current.selectedUtxos).toHaveLength(0)) }) @@ -157,7 +144,7 @@ describe('useCreateFidelityBondWizard', () => { it('skips jar selection when only one jar has eligible utxos', async () => { mocks.walletInfo.jars = [jar(0, [utxo({ utxo: 'only:0', value: 25_000 })])] const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - const lockdate = minLockdateOption() + const lockdate = lockdateFromWizard(result.current) act(() => result.current.setSelectedLockdate(lockdate)) await act(async () => result.current.handleNext()) @@ -165,7 +152,7 @@ describe('useCreateFidelityBondWizard', () => { expect(result.current.step).toBe('select_utxos') expect(result.current.selectedJarIndex).toBe(0) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) await act(async () => result.current.handleNext()) expect(result.current.step).toBe('review') @@ -189,7 +176,7 @@ describe('useCreateFidelityBondWizard', () => { it('freezes unselected utxos before review and supports back navigation', async () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - const lockdate = minLockdateOption() + const lockdate = lockdateFromWizard(result.current) act(() => result.current.setSelectedLockdate(lockdate)) await act(async () => result.current.handleNext()) @@ -224,11 +211,7 @@ describe('useCreateFidelityBondWizard', () => { act(() => { result.current.setStep('success') result.current.setSelectedJarIndex(0) - }) - act(() => { - result.current.toggleUtxoSelection(result.current.availableUtxos[0]) - }) - act(() => { + result.current.selectAllUtxos() result.current.handleOpenChange(false) }) @@ -252,8 +235,40 @@ describe('useCreateFidelityBondWizard', () => { expect(result.current.step).toBe('review') }) + it('exposes lockdate boundaries and clamps out-of-range values', () => { + const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) + + const { minYear, minMonth, yearOptions, monthOptions } = result.current + expect(minYear).toBeGreaterThan(0) + expect(minMonth).toBeGreaterThanOrEqual(1) + expect(yearOptions.length).toBeGreaterThan(0) + expect(monthOptions.length).toBe(12) + + const min = result.current.clampLockdate('1900-01') + const max = result.current.clampLockdate('9999-12') + expect(min).not.toBe('') + expect(max).not.toBe('') + expect(min < max).toBe(true) + + // empty input clamps to min + expect(result.current.clampLockdate('')).toBe(min) + // a value already inside the range is returned untouched + expect(result.current.clampLockdate(min)).toBe(min) + + // derived year/month default to empty before a selection + expect(result.current.selectedYear).toBe('') + expect(result.current.selectedMonth).toBe('') + + act(() => result.current.setSelectedLockdate(min)) + + expect(result.current.selectedYear).toBe(min.slice(0, 4)) + expect(result.current.selectedMonth).toBe(min.slice(5, 7)) + expect(result.current.selectedDateLabel).not.toBeNull() + }) + it('flags duplicate lockdates against existing fidelity bonds', () => { - const lockdate = minLockdateOption() + const { result: probe } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) + const lockdate = lockdateFromWizard(probe.current) const timestampSeconds = Math.floor(new Date(`${lockdate}-01T00:00:00Z`).getTime() / 1000) mocks.walletInfo.fidelityBondSummary = { @@ -272,31 +287,6 @@ describe('useCreateFidelityBondWizard', () => { expect(result.current.hasDuplicateLockdate).toBeFalsy() act(() => result.current.setSelectedLockdate(lockdate)) expect(result.current.hasDuplicateLockdate).toBe(true) - expect(result.current.canProceed()).toBe(false) - }) - - it('blocks a lock date already used by an expired fidelity bond', () => { - mocks.isDeveloperMode = true - const expiredLockdate = minLockdateOption(true) - const timestampSeconds = Math.floor(new Date(`${expiredLockdate}-01T00:00:00Z`).getTime() / 1000) - - mocks.walletInfo.fidelityBondSummary = { - fbOutputs: [ - utxo({ - utxo: 'expired-bond:0', - value: 100_000, - locktime: `${expiredLockdate}-01 00:00:00`, - path: `m/84'/1'/0'/0/0:${timestampSeconds}`, - }), - ], - } - - const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - - expect(result.current.existingFbLockdates).toContain(expiredLockdate) - act(() => result.current.setSelectedLockdate(expiredLockdate)) - expect(result.current.hasDuplicateLockdate).toBe(true) - expect(result.current.canProceed()).toBe(false) }) it('ignores existing fidelity bonds whose locktime cannot be derived', () => { @@ -313,7 +303,7 @@ describe('useCreateFidelityBondWizard', () => { } const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - const lockdate = minLockdateOption() + const lockdate = lockdateFromWizard(result.current) act(() => result.current.setSelectedLockdate(lockdate)) expect(result.current.hasDuplicateLockdate).toBeFalsy() @@ -323,8 +313,8 @@ describe('useCreateFidelityBondWizard', () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) act(() => result.current.setSelectedJarIndex(0)) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) - expect(result.current.selectedUtxos.map((entry) => entry.utxo)).toEqual(['large:0']) + act(() => result.current.selectAllUtxos()) + expect(result.current.selectedUtxos.map((entry) => entry.utxo)).toEqual(['large:0', 'small:0']) // switch to a jar that does not contain the previously selected ids act(() => result.current.setSelectedJarIndex(1)) @@ -332,26 +322,9 @@ describe('useCreateFidelityBondWizard', () => { await waitFor(() => expect(result.current.selectedUtxos).toEqual([])) }) - it('only exposes unfrozen cj-out utxos for fidelity-bond creation', () => { - mocks.walletInfo.addressSummary = { - bcrt1qcj: { status: 'cj-out' }, - bcrt1qdeposit: { status: 'deposit' }, - } - mocks.walletInfo.jars = [ - jar(0, [utxo({ utxo: 'cj:0', address: 'bcrt1qcj' }), utxo({ utxo: 'deposit:0', address: 'bcrt1qdeposit' })]), - jar(1, [utxo({ utxo: 'deposit-only:0', address: 'bcrt1qdeposit', mixdepth: 1 })]), - ] - - const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - - expect(result.current.jarsWithUtxos.map((entry) => entry.jarIndex)).toEqual([0]) - act(() => result.current.setSelectedJarIndex(0)) - expect(result.current.availableUtxos.map((entry) => entry.utxo)).toEqual(['cj:0']) - }) - it('reflects canProceed gating for each step', () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - const lockdate = minLockdateOption() + const lockdate = lockdateFromWizard(result.current) // select_date expect(result.current.canProceed()).toBe(false) @@ -367,7 +340,7 @@ describe('useCreateFidelityBondWizard', () => { // select_utxos act(() => result.current.setStep('select_utxos')) expect(result.current.canProceed()).toBe(false) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) expect(result.current.canProceed()).toBe(true) // freeze_utxos always proceeds @@ -446,16 +419,19 @@ describe('useCreateFidelityBondWizard', () => { expect(result.current.step).toBe('select_utxos') }) - it('skips freezing and moves straight to review when the selected utxo is the only one in the jar', async () => { - mocks.walletInfo.jars = [jar(0, [utxo({ utxo: 'only:0', value: 25_000 })])] + it('skips freezing and moves straight to review when all utxos are selected', async () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) - const lockdate = minLockdateOption() + const lockdate = lockdateFromWizard(result.current) act(() => result.current.setSelectedLockdate(lockdate)) await act(async () => result.current.handleNext()) + expect(result.current.step).toBe('select_jar') + + act(() => result.current.setSelectedJarIndex(0)) + await act(async () => result.current.handleNext()) expect(result.current.step).toBe('select_utxos') - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) await act(async () => result.current.handleNext()) expect(result.current.step).toBe('review') @@ -467,7 +443,7 @@ describe('useCreateFidelityBondWizard', () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) act(() => result.current.setSelectedJarIndex(0)) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) act(() => result.current.setStep('review')) // confirmation not accepted -> trigger() fails the whole form await act(async () => result.current.handleNext()) @@ -491,7 +467,7 @@ describe('useCreateFidelityBondWizard', () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) act(() => result.current.setSelectedJarIndex(0)) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) act(() => result.current.setStep('select_utxos')) act(() => result.current.handleBack()) @@ -505,7 +481,7 @@ describe('useCreateFidelityBondWizard', () => { const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) act(() => result.current.setSelectedJarIndex(0)) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) act(() => result.current.setStep('select_utxos')) act(() => result.current.handleBack()) @@ -524,11 +500,10 @@ describe('useCreateFidelityBondWizard', () => { }) it('returns from review to select_utxos when nothing was frozen', () => { - mocks.walletInfo.jars = [jar(0, [utxo({ utxo: 'only:0', value: 25_000 })])] const { result } = renderHook(() => useCreateFidelityBondWizard(true, vi.fn(), 'wallet.jmdat')) act(() => result.current.setSelectedJarIndex(0)) - act(() => result.current.toggleUtxoSelection(result.current.availableUtxos[0])) + act(() => result.current.selectAllUtxos()) act(() => result.current.setStep('review')) expect(result.current.utxosToFreeze).toEqual([]) act(() => result.current.handleBack()) diff --git a/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.ts b/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.ts index b19b0f49..81425e1f 100644 --- a/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.ts +++ b/src/components/earn/CreateFidelityBondDialog/useCreateFidelityBondWizard.ts @@ -1,30 +1,30 @@ import { useState, useMemo } from 'react' import { yupResolver } from '@hookform/resolvers/yup' -import { gettimelockaddressOptions } from '@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query' -import type { DirectSendResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' -import { useQuery } from '@tanstack/react-query' +import { + directsendMutation, + freezeMutation, + gettimelockaddressOptions, +} from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query' +import type { DirectSendResponse, ErrorMessage } from '@joinmarket-webui/joinmarket-api-ts/jm' +import { useMutation, useQuery } from '@tanstack/react-query' import { useForm, useWatch } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' -import { - JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS, - JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS_DELAY, -} from '@/constants/jam' import { useJamWalletInfoContext } from '@/context/JamWalletInfoContext' import { useApiClient } from '@/hooks/useApiClient' import type { Utxo } from '@/hooks/useQueryUtxos' +import { getErrorReason } from '@/lib/errorReason' import * as fb from '@/lib/fidelityBondUtils' -import { delayedPromise, type WalletFileName } from '@/lib/utils' +import type { WalletFileName } from '@/lib/utils' import { useDeveloperMode } from '@/store/jamSettingsStore' import type { JarIndex } from '@/types/global' -import { useFidelityBondMutations } from '../fidelity-bond/useFidelityBondMutations' import { CREATE_FIDELITY_BOND_FORM_DEFAULT_VALUES, createFidelityBondFormSchema, type CreateFidelityBondFormValues, } from './CreateFidelityBondFormSchema' import type { Step } from './types' -import { generateLockdateOptions } from './types' +import { generateLockdateOptions, getYearOptions, getMonthOptions } from './types' export function useCreateFidelityBondWizard( open: boolean, @@ -40,29 +40,13 @@ export function useCreateFidelityBondWizard( const [frozenUtxos, setFrozenUtxos] = useState([]) const [utxoPage, setUtxoPage] = useState(0) const [txResult, setTxResult] = useState() - - const { freezeUtxo, unfreezeUtxo, directSend, error, setError } = useFidelityBondMutations({ - unfreezeErrorKey: 'earn.fidelity_bond.error_unfreezing_utxos', - sendErrorKey: 'earn.fidelity_bond.error_creating_fidelity_bond', - }) + const [error, setError] = useState() const lockdateOptions = useMemo(() => generateLockdateOptions(isDeveloperMode), [isDeveloperMode]) - const existingFbLockdates = useMemo(() => { - return walletInfo.fidelityBondSummary.fbOutputs - .map((fbUtxo) => { - const locktime = fb.utxo.getLocktime(fbUtxo) - return locktime ? fb.lockdate.fromTimestamp(locktime) : null - }) - .filter(Boolean) as fb.Lockdate[] - }, [walletInfo.fidelityBondSummary.fbOutputs]) - const availableLockdateOptions = useMemo( - () => lockdateOptions.filter((option) => !existingFbLockdates.includes(option.value)), - [existingFbLockdates, lockdateOptions], - ) const jarIndexes = useMemo(() => walletInfo.jars.map((jar) => jar.jarIndex), [walletInfo.jars]) const formSchema = useMemo( - () => createFidelityBondFormSchema(availableLockdateOptions, jarIndexes, t), - [availableLockdateOptions, jarIndexes, t], + () => createFidelityBondFormSchema(lockdateOptions, jarIndexes, t), + [lockdateOptions, jarIndexes, t], ) const form = useForm({ mode: 'onChange', @@ -71,7 +55,7 @@ export function useCreateFidelityBondWizard( }) const watchedLockdate = useWatch({ control: form.control, name: 'lockdate' }) - const selectedLockdate: fb.Lockdate | '' = watchedLockdate ?? '' + const selectedLockdate = watchedLockdate ?? '' const selectedJarIndex = useWatch({ control: form.control, name: 'source.fromJar' }) const selectedUtxoIds = useWatch({ control: form.control, @@ -84,6 +68,20 @@ export function useCreateFidelityBondWizard( defaultValue: CREATE_FIDELITY_BOND_FORM_DEFAULT_VALUES.confirmationAccepted, }) + const yearOptions = useMemo(() => getYearOptions(lockdateOptions), [lockdateOptions]) + const monthOptions = useMemo(() => getMonthOptions(), []) + + const minLockdate = lockdateOptions.at(0)?.value ?? '' + const maxLockdate = lockdateOptions.at(-1)?.value ?? '' + const clampLockdate = (lockdate: string): fb.Lockdate | '' => { + if (!lockdate || lockdate < minLockdate) return minLockdate || '' + if (lockdate > maxLockdate) return maxLockdate || '' + return lockdate as fb.Lockdate + } + const selectedYear = selectedLockdate ? selectedLockdate.slice(0, 4) : '' + const selectedMonth = selectedLockdate ? selectedLockdate.slice(5, 7) : '' + const minYear = minLockdate ? Number.parseInt(minLockdate.slice(0, 4), 10) : 0 + const minMonth = minLockdate ? Number.parseInt(minLockdate.slice(5, 7), 10) : 1 const setSelectedLockdate = (lockdate: fb.Lockdate | '') => { form.setValue('lockdate', lockdate || undefined, { shouldDirty: true, shouldTouch: true, shouldValidate: true }) } @@ -101,6 +99,16 @@ export function useCreateFidelityBondWizard( }) } + const existingFbLockdates = useMemo(() => { + return walletInfo.fidelityBondSummary.fbOutputs + .filter((fbUtxo) => fb.utxo.isLocked(fbUtxo)) + .map((fbUtxo) => { + const locktime = fb.utxo.getLocktime(fbUtxo) + return locktime ? fb.lockdate.fromTimestamp(locktime) : null + }) + .filter(Boolean) as fb.Lockdate[] + }, [walletInfo.fidelityBondSummary.fbOutputs]) + const hasDuplicateLockdate = selectedLockdate && existingFbLockdates.includes(selectedLockdate) const selectedJar = useMemo(() => { @@ -110,19 +118,21 @@ export function useCreateFidelityBondWizard( const jarsWithUtxos = useMemo(() => { return walletInfo.jars.filter((jar) => { - const availableUtxos = jar.utxos.filter((utxo) => - fb.utxo.isEligibleForCreation(utxo, walletInfo.addressSummary[utxo.address]?.status), - ) + // TODO: let's allow selecting frozen utxos - unfreeze them before sending the transaction + const availableUtxos = jar.utxos.filter((utxo) => !utxo.frozen && !fb.utxo.isFidelityBond(utxo)) return availableUtxos.length > 0 }) - }, [walletInfo.addressSummary, walletInfo.jars]) + }, [walletInfo.jars]) const availableUtxos = useMemo(() => { if (selectedJar === undefined) return [] - return selectedJar.utxos - .filter((utxo) => fb.utxo.isEligibleForCreation(utxo, walletInfo.addressSummary[utxo.address]?.status)) - .toSorted((a, b) => b.value - a.value) - }, [selectedJar, walletInfo.addressSummary]) + return ( + selectedJar.utxos + // TODO: let's allow selecting frozen utxos - unfreeze them before sending the transaction + .filter((utxo) => !utxo.frozen && !fb.utxo.isFidelityBond(utxo)) + .toSorted((a, b) => b.value - a.value) + ) + }, [selectedJar]) const selectedUtxos = useMemo(() => { const availableUtxosById = new Map(availableUtxos.map((utxo) => [utxo.utxo, utxo])) @@ -161,6 +171,30 @@ export function useCreateFidelityBondWizard( const address = timelockAddressQuery.data?.address + const freezeUtxo = useMutation({ + ...freezeMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.error_freezing_utxos')} ${reason}`) + }, + }) + + const unfreezeUtxo = useMutation({ + ...freezeMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.error_unfreezing_utxos')} ${reason}`) + }, + }) + + const directSend = useMutation({ + ...directsendMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.error_creating_fidelity_bond')} ${reason}`) + }, + }) + const handleReset = () => { setStep('select_date') form.reset(CREATE_FIDELITY_BOND_FORM_DEFAULT_VALUES) @@ -277,15 +311,17 @@ export function useCreateFidelityBondWizard( setStep('creating') try { - // TODO: refactor: use the sweep functionality from `useFidelityBondSweep` here const result = await directSend.mutateAsync({ path: { walletname: walletFileName }, body: { mixdepth: selectedJar.jarIndex, - amount_sats: 0, // 0 := sweep! + amount_sats: 0, destination: address, }, }) + setTxResult(result) + setStep('success') + toast.success(t('earn.fidelity_bond.create_fidelity_bond.success_text')) // Best-effort cleanup — tx already broadcast, don't throw on unfreeze failure for (const utxo of frozenUtxos) { @@ -293,33 +329,12 @@ export function useCreateFidelityBondWizard( await unfreezeUtxo.mutateAsync({ path: { walletname: walletFileName }, body: { 'utxo-string': utxo.utxo, freeze: false }, - throwOnError: true, }) - } catch (_ignoredOnPurpose: unknown) { - // only debug output - console.debug('Error while unfreezing previously frozen UTXO.') + } catch { + // logged via onError } } - // freeze resulting fidelity bond output - if (JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS) { - try { - await delayedPromise(JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS_DELAY) - const fbUtxoId = `${result.txinfo.txid}:0` // sent with a sweep, so it is a single output - await freezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': fbUtxoId, freeze: true }, - throwOnError: true, - }) - } catch (_ignoredOnPurpose: unknown) { - console.warn('Error while freezing Fidelity Bond UTXO - continuing.') - } - } - - setTxResult(result) - setStep('success') - toast.success(t('earn.fidelity_bond.create_fidelity_bond.success_text')) - await walletInfo.refetch() } catch { // Best-effort rollback — unfreeze UTXOs that were frozen for this operation @@ -329,9 +344,8 @@ export function useCreateFidelityBondWizard( path: { walletname: walletFileName }, body: { 'utxo-string': utxo.utxo, freeze: false }, }) - } catch (_ignoredOnPurpose: unknown) { - // only debug output - console.debug('Error while unfreezing previously frozen UTXO in error handling.') + } catch { + // logged via onError } } setFrozenUtxos([]) @@ -356,14 +370,28 @@ export function useCreateFidelityBondWizard( } const toggleUtxoSelection = (utxo: Utxo) => { + // TODO: select/deselect all utxos to the same address const isSelected = selectedUtxoIds.includes(utxo.utxo) - setSelectedUtxoIds(isSelected ? [] : [utxo.utxo]) + setSelectedUtxoIds( + isSelected ? selectedUtxoIds.filter((utxoId) => utxoId !== utxo.utxo) : [...selectedUtxoIds, utxo.utxo], + ) } + const selectAllUtxos = () => setSelectedUtxoIds(availableUtxos.map((utxo) => utxo.utxo)) + const deselectAllUtxos = () => setSelectedUtxoIds([]) + + const selectedDateLabel = selectedLockdate + ? new Date(fb.lockdate.toTimestamp(selectedLockdate)).toLocaleDateString(undefined, { + year: 'numeric', + month: 'long', + day: 'numeric', + }) + : null + const canProceed = () => { switch (step) { case 'select_date': - return !!selectedLockdate && !hasDuplicateLockdate + return !!selectedLockdate case 'select_jar': return selectedJar !== undefined case 'select_utxos': @@ -387,8 +415,15 @@ export function useCreateFidelityBondWizard( setStep, setSelectedLockdate, selectedLockdate, + selectedYear, + selectedMonth, + minYear, + minMonth, + yearOptions, + monthOptions, + clampLockdate, hasDuplicateLockdate, - existingFbLockdates, + selectedDateLabel, selectedJarIndex, setSelectedJarIndex, jarsWithUtxos, @@ -397,6 +432,8 @@ export function useCreateFidelityBondWizard( utxoPage, setUtxoPage, toggleUtxoSelection, + selectAllUtxos, + deselectAllUtxos, totalAmount, isUsingAllFunds, utxosToFreeze, diff --git a/src/components/earn/EarnForm.test.tsx b/src/components/earn/EarnForm.test.tsx index ac54bc8c..f1e5b9c3 100644 --- a/src/components/earn/EarnForm.test.tsx +++ b/src/components/earn/EarnForm.test.tsx @@ -9,6 +9,10 @@ vi.mock('react-i18next', () => ({ }), })) +vi.mock('@/components/ui/jam/CurrencySymbol', () => ({ + SatSymbol: (props: Record) => sat-symbol, +})) + vi.mock('../dev/DevBadge', () => ({ DevBadge: ({ className }: { className?: string }) => dev-badge, })) diff --git a/src/components/earn/EarnForm.tsx b/src/components/earn/EarnForm.tsx index 9a4d7243..e2186199 100644 --- a/src/components/earn/EarnForm.tsx +++ b/src/components/earn/EarnForm.tsx @@ -3,7 +3,7 @@ import { yupResolver } from '@hookform/resolvers/yup' import type { TFunction } from 'i18next' import { HandshakeIcon, PercentIcon } from 'lucide-react' import { useForm, useWatch } from 'react-hook-form' -import type { SubmitHandler } from 'react-hook-form' +import type { Resolver, SubmitHandler } from 'react-hook-form' import { useTranslation } from 'react-i18next' import * as yup from 'yup' import { Button } from '@/components/ui/button' @@ -17,7 +17,7 @@ import { cn, factorToPercentage, isValidInteger, isValidNumber } from '@/lib/uti import type { AmountSats } from '@/types/global' import { DevBadge } from '../dev/DevBadge' import { Card, CardContent, CardHeader } from '../ui/card' -import { Field, FieldDescription, FieldError, FieldLabel } from '../ui/field' +import { Field, FieldDescription, FieldLabel } from '../ui/field' import { InputGroup, InputGroupAddon, InputGroupInput } from '../ui/input-group' import { Spinner } from '../ui/spinner' @@ -90,8 +90,8 @@ const OfferTypeInput = (props: React.ComponentProps) => { const id = useId() return ( - -
+ +
) => {
-
+
({ mode: 'onSubmit', defaultValues: FORM_INPUT_DEFAULT_VALUES, - resolver: yupResolver(schema), + // force type (see https://github.com/react-hook-form/resolvers/issues/807) + resolver: yupResolver(schema) as Resolver, }) const values = useWatch({ control }) @@ -202,81 +203,89 @@ export function EarnForm({ /> - - - {t('earn.label_abs_fee', { - fee: '', // empty on purpose - })} - - {t('earn.description_abs_fee')} - - + + + {t('earn.label_abs_fee', { + fee: '', // empty on purpose })} - type="number" - step={1} - /> - {FieldPrefixSatSymbol} - - - {errors.offerAbsoluteFee?.message && {errors.offerAbsoluteFee.message}} - + + {t('earn.description_abs_fee')} + + + {FieldPrefixSatSymbol} + + + {errors.offerAbsoluteFee?.message && ( +
{errors.offerAbsoluteFee.message}
+ )} +
- - - {t('earn.label_rel_fee', { - fee: getValues('offerRelativeFeeInPercent') ? `(${getValues('offerRelativeFeeInPercent')!}%)` : '', - })} - - {t('earn.description_rel_fee')} - - + + + {t('earn.label_rel_fee', { + fee: getValues('offerRelativeFeeInPercent') ? `(${getValues('offerRelativeFeeInPercent')!}%)` : '', })} - type="number" - step={factorToPercentage(JAM.OFFER_FEE_REL_STEP)} - /> - % - - {errors.offerRelativeFeeInPercent && {errors.offerRelativeFeeInPercent.message}} - + + {t('earn.description_rel_fee')} + + + % + + + {errors.offerRelativeFeeInPercent && ( +
{errors.offerRelativeFeeInPercent.message}
+ )} +
- - {t('earn.label_min_amount_input')} - {t('earn.description_min_amount_input')} - - - {FieldPrefixSatSymbol} - +
+ + {t('earn.label_min_amount_input')} + {t('earn.description_min_amount_input')} + + + {FieldPrefixSatSymbol} + + {errors.offerMinAmount && ( - +
{offerMinsizeMax < JAM.OFFER_MINSIZE_MIN ? ( <>{t('earn.feedback_invalid_min_amount_insufficient_funds')} ) : ( <>{errors.offerMinAmount?.message || t('earn.feedback_invalid_min_amount')} )} - +
)} - - +
+
+ {feeConfigValidation.maxFeesConfigMissing && ( setShowFeeConfigDialog(true)} className="mb-4" /> )} @@ -242,7 +236,7 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => { {jmSession.coinjoin_in_process === true && ( - {t('send.text_coinjoin_already_running')} + {t('send.text_coinjoin_already_running')} )} @@ -255,13 +249,13 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => { {isWaitingMakerStart && ( - {t('earn.alert_waiting_start_title')} + {/* TODO: i18n */ t('Waiting for maker to start...')} )} {isWaitingMakerStop && ( - {t('earn.alert_waiting_stop_title')} + {/* TODO: i18n */ t('Waiting for maker to stop...')} )} {waitingForOfferUpdate && ( @@ -271,33 +265,11 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => { )} - {!isWaitingMakerStart && !isWaitingMakerStop && !jmSession.maker_running && earnPreconditionWarning && ( - <> - {earnPreconditionWarning === 'non-frozen-fb-present' ? ( - - ) : null} - {earnPreconditionWarning === 'missing-utxos' ? ( - - ) : null} - {earnPreconditionWarning === 'missing-confirmations' ? : null} - - )} - -
- -
- {jmSession.offer_list && jmSession.offer_list.length > 0 && (
) : ( -
+ <> {/* Fidelity Bonds exist */}

{t('earn.title_fidelity_bonds', { count: walletInfo.fidelityBondSummary.fbOutputs.length })}

{t('earn.subtitle_fidelity_bonds')}

-
+
{walletInfo.fidelityBondSummary.fbOutputs.map((it) => { const isExpired = !fb.utxo.isLocked(it) - const actionsEnabled = isExpired && isFidelityBondActionsEnabled + const actionsEnabled = + isExpired && + !jmSession.rescanning && + !jmSession.maker_running && + !waitingForMakerUpdate && + !waitingForOfferUpdate && + !walletInfo.isFetching return ( - {isExpired && ( -
- - @@ -428,21 +373,7 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => { ) })}
- - {showCreateAdditionalFidelityBond && ( -
- - -
- )} -
+ )} {/* Fee Configuration Dialog */} @@ -487,11 +418,11 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => {
- walletInfo.fidelityBondSummary.fbOutputs: + walletInfo.fidelityBondSummary.fbOutputs:
{JSON.stringify(walletInfo.fidelityBondSummary.fbOutputs, null, 2)}
- jmSessionState.offer_list: + jmSessionState.offer_list:
{JSON.stringify(jmSession.offer_list, null, 2)}
diff --git a/src/components/earn/EarnPreconditionAlerts.tsx b/src/components/earn/EarnPreconditionAlerts.tsx deleted file mode 100644 index a95b1afe..00000000 --- a/src/components/earn/EarnPreconditionAlerts.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { AlertTriangleIcon } from 'lucide-react' -import { Trans, useTranslation } from 'react-i18next' -import { Link } from 'react-router-dom' -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' -import { routes } from '@/constants/routes' - -export const UnconfirmedBalanceAlert = ({ numberOfMissingConfirmations }: { numberOfMissingConfirmations: number }) => { - const { t } = useTranslation() - - return ( - - - {t('earn.precondition.title')} - -
    -
  • - {t('earn.precondition.hint_missing_confirmations', { - count: numberOfMissingConfirmations, - })} -
  • -
-
-
- ) -} - -export const NoSpendableBalanceAlert = () => { - const { t } = useTranslation() - - return ( - - - {t('earn.precondition.title')} - -
    -
  • - - - Fund your wallet - - to start earning. - -
  • -
-
-
- ) -} - -export const NonFrozenFidelityBondsAlert = ({ - numberOfNonFrozenFidelityBondOutputs, -}: { - numberOfNonFrozenFidelityBondOutputs: number -}) => { - const { t } = useTranslation() - - return ( - - - {t('earn.precondition.title')} - - -
    -
  • - , - }} - /> -
  • -
-
-
- ) -} diff --git a/src/components/earn/FidelityBondCard.test.tsx b/src/components/earn/FidelityBondCard.test.tsx index b7cffbfc..60b17a50 100644 --- a/src/components/earn/FidelityBondCard.test.tsx +++ b/src/components/earn/FidelityBondCard.test.tsx @@ -34,7 +34,7 @@ vi.mock('../ui/jam/Address', () => ({ Address: ({ value }: { value?: string }) => {value}, })) -vi.mock('@/components/ui/jam/Balance', () => ({ +vi.mock('../ui/jam/Balance', () => ({ Balance: ({ valueString }: { valueString?: string }) => {valueString}, })) diff --git a/src/components/earn/FidelityBondCard.tsx b/src/components/earn/FidelityBondCard.tsx index ef254522..0a4c108a 100644 --- a/src/components/earn/FidelityBondCard.tsx +++ b/src/components/earn/FidelityBondCard.tsx @@ -2,19 +2,18 @@ import { useMemo, type PropsWithChildren } from 'react' import { ClockIcon, CoinsIcon, CopyIcon } from 'lucide-react' import { Trans, useTranslation } from 'react-i18next' import { Card, CardContent, CardAction, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' -import { Balance } from '@/components/ui/jam/Balance' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import type { FidelityBondUtxo } from '@/hooks/useQueryUtxos' import * as fb from '@/lib/fidelityBondUtils' -import { cn, time } from '@/lib/utils' +import { time } from '@/lib/utils' import { Address } from '../ui/jam/Address' +import { Balance } from '../ui/jam/Balance' interface FidelityBondCardProps { value: FidelityBondUtxo - className?: string } -export function FidelityBondCard({ value, className, children }: PropsWithChildren) { +export function FidelityBondCard({ value, children }: PropsWithChildren) { const { t, i18n } = useTranslation() const isExpired = !fb.utxo.isLocked(value) @@ -32,7 +31,7 @@ export function FidelityBondCard({ value, className, children }: PropsWithChildr } return ( - + {isExpired ? ( @@ -43,7 +42,7 @@ export function FidelityBondCard({ value, className, children }: PropsWithChildr t('earn.fidelity_bond.existing.title_active') )} - + {value.path} @@ -55,29 +54,29 @@ export function FidelityBondCard({ value, className, children }: PropsWithChildr -
- -
+
+ +
-
- -
+
+ +
{t(`earn.fidelity_bond.existing.${isExpired ? 'label_expired_on' : 'label_locked_until'}`)} - + {value.locktime} ({humanReadableLockDuration})
-
- -
+
+ +
{t('earn.fidelity_bond.existing.label_address')} diff --git a/src/components/earn/MoveToJarDialog.schema.test.ts b/src/components/earn/MoveToJarDialog.schema.test.ts deleted file mode 100644 index efa65a6a..00000000 --- a/src/components/earn/MoveToJarDialog.schema.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { createMoveToJarFormSchema } from './MoveToJarDialog.schema' - -describe('createMoveToJarFormSchema', () => { - const schema = createMoveToJarFormSchema([0, 2]) - - it('accepts an available destination jar', async () => { - await expect(schema.validate({ destinationJarIndex: 2 })).resolves.toEqual({ destinationJarIndex: 2 }) - }) - - it.each([{ destinationJarIndex: 1 }, { destinationJarIndex: undefined }])( - 'rejects an unavailable destination jar', - async (values) => { - await expect(schema.isValid(values)).resolves.toBe(false) - }, - ) -}) diff --git a/src/components/earn/MoveToJarDialog.schema.ts b/src/components/earn/MoveToJarDialog.schema.ts deleted file mode 100644 index a14aa72a..00000000 --- a/src/components/earn/MoveToJarDialog.schema.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as yup from 'yup' -import type { JarIndex } from '@/types/global' - -export type MoveToJarFormValues = { - destinationJarIndex: JarIndex -} - -export const createMoveToJarFormSchema = (availableJarIndexes: JarIndex[]): yup.ObjectSchema => - yup - .object({ - destinationJarIndex: yup.number().oneOf(availableJarIndexes).required(), - }) - .required() diff --git a/src/components/earn/MoveToJarDialog.test.tsx b/src/components/earn/MoveToJarDialog.test.tsx index d9a23d55..6f03b3c4 100644 --- a/src/components/earn/MoveToJarDialog.test.tsx +++ b/src/components/earn/MoveToJarDialog.test.tsx @@ -4,20 +4,17 @@ import { describe, expect, it, vi, beforeEach } from 'vitest' import type { FidelityBondUtxo } from '@/hooks/useQueryUtxos' import { MoveToJarDialog } from './MoveToJarDialog' -type MutationOptions = { mutationFn: (input: unknown) => Promise } - type ChildrenProps = { children: ReactNode } type DialogProps = ChildrenProps & { open?: boolean; onOpenChange?: (open: boolean) => void } type ValueProps = { value: string } const h = vi.hoisted(() => ({ - fetchAddressQueryData: { + queryReturn: { data: undefined as { address?: string } | undefined, isLoading: false, isError: false, }, - directSendAsync: vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'movetxid99' } }), - freezeAsync: vi.fn<() => Promise>().mockResolvedValue({}), + mutateAsync: vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'movetxid99' } }), isPending: false, refetch: vi.fn(), extraUtxos: [] as Array<{ utxo: string; value: number; frozen: boolean }>, @@ -30,16 +27,13 @@ vi.mock('react-i18next', () => ({ })) vi.mock('@tanstack/react-query', () => ({ - useQuery: () => h.fetchAddressQueryData, - useMutation: vi.fn((options: MutationOptions) => ({ - isPending: false, - mutateAsync: async (input: unknown) => await options.mutationFn(input), - })), + useQuery: () => h.queryReturn, + useMutation: () => ({ mutateAsync: h.mutateAsync, isPending: h.isPending }), })) -vi.mock('@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query', () => ({ - directsendMutation: vi.fn(() => ({ mutationFn: h.directSendAsync })), - freezeMutation: vi.fn(() => ({ mutationFn: h.freezeAsync })), +vi.mock('@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query', () => ({ + directsendMutation: vi.fn(() => ({})), + freezeMutation: vi.fn(() => ({})), getaddressOptions: vi.fn(() => ({ queryKey: ['mock'], queryFn: vi.fn() })), })) @@ -70,29 +64,10 @@ vi.mock('@/context/JamWalletInfoContext', () => ({ utxos: [], }, ], - walletBalanceSummary: { calculatedTotalBalanceInSats: 6000 }, refetch: h.refetch, }), })) -vi.mock('@/components/ui/jam/SelectableJar', () => ({ - SelectableJar: ({ - name, - onSelect, - disabled, - isSelected, - }: { - name?: string - onSelect?: () => void - disabled?: boolean - isSelected?: boolean - }) => ( - - ), -})) - vi.mock('@/components/ui/dialog', () => ({ Dialog: ({ children, open, onOpenChange }: DialogProps) => open ? ( @@ -118,10 +93,6 @@ vi.mock('@/components/ui/jam/Address', () => ({ Address: ({ value }: ValueProps) =>
{value}
, })) -vi.mock('@/components/ui/jam/Balance', () => ({ - Balance: ({ valueString }: { valueString: string }) => {valueString} sats, -})) - vi.mock('@/components/ui/jam/CopyButton', () => ({ CopyButton: ({ value }: ValueProps) =>
{value}
, })) @@ -147,14 +118,13 @@ const renderDialog = (props?: { utxo?: FidelityBondUtxo; onOpenChange?: (open: b const goToConfirm = () => { fireEvent.click(screen.getByText('Jar 1')) - fireEvent.click(screen.getByText('global.next')) + fireEvent.click(screen.getByText('earn.fidelity_bond.select_date.text_primary_button')) } describe('MoveToJarDialog', () => { beforeEach(() => { - h.fetchAddressQueryData = { data: { address: 'bc111' }, isLoading: false, isError: false } - h.directSendAsync = vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'movetxid99' } }) - h.freezeAsync = vi.fn<() => Promise>().mockResolvedValue({}) + h.queryReturn = { data: { address: 'bc111' }, isLoading: false, isError: false } + h.mutateAsync = vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'movetxid99' } }) h.isPending = false h.refetch = vi.fn() h.extraUtxos = [] @@ -164,35 +134,35 @@ describe('MoveToJarDialog', () => { renderDialog() expect(screen.getByText('earn.fidelity_bond.move.title')).toBeInTheDocument() expect(screen.getByText('earn.fidelity_bond.move.select_jar.description')).toBeInTheDocument() - expect(screen.getByText('Jar 0')).toBeEnabled() expect(screen.getByText('Jar 1')).toBeInTheDocument() }) it('moves to the confirm step and shows the destination address', () => { renderDialog() goToConfirm() - expect(screen.getByText('Jar 1')).toBeInTheDocument() + expect(screen.getByText('earn.fidelity_bond.review_inputs.label_jar_n {"jar":1}')).toBeInTheDocument() expect(screen.getByTestId('address')).toHaveTextContent('bc111') }) it('shows a loading indicator while the destination address loads', () => { - h.fetchAddressQueryData = { data: undefined, isLoading: true, isError: false } + h.queryReturn = { data: undefined, isLoading: true, isError: false } renderDialog() goToConfirm() expect(screen.getByText('earn.fidelity_bond.move.text_loading')).toBeInTheDocument() }) it('shows an error alert when the address query fails', () => { - h.fetchAddressQueryData = { data: undefined, isLoading: false, isError: true } + h.queryReturn = { data: undefined, isLoading: false, isError: true } renderDialog() goToConfirm() - expect(screen.getByText('global.errors.error_loading_address_failed')).toBeInTheDocument() + expect(screen.getByText('earn.fidelity_bond.move.error_loading_address')).toBeInTheDocument() }) it('completes the move flow and reaches the success step', async () => { h.extraUtxos = [{ utxo: 'tx2:0', value: 500, frozen: false }] renderDialog() goToConfirm() + fireEvent.click(screen.getByTestId('confirm-switch')) fireEvent.click(screen.getByText('earn.fidelity_bond.move.text_button_submit')) await waitFor(() => expect(screen.getByText('earn.fidelity_bond.move.success_text')).toBeInTheDocument()) @@ -204,17 +174,19 @@ describe('MoveToJarDialog', () => { const frozenUtxo = { ...utxo, frozen: true } as unknown as FidelityBondUtxo renderDialog({ utxo: frozenUtxo }) goToConfirm() + fireEvent.click(screen.getByTestId('confirm-switch')) fireEvent.click(screen.getByText('earn.fidelity_bond.move.text_button_submit')) await waitFor(() => expect(screen.getByText('earn.fidelity_bond.move.success_text')).toBeInTheDocument()) - const calls = h.freezeAsync.mock.calls as unknown as Array<[{ body?: { freeze?: boolean } }]> + const calls = h.mutateAsync.mock.calls as unknown as Array<[{ body?: { freeze?: boolean } }]> expect(calls.some((call) => call[0]?.body?.freeze === false)).toBe(true) }) it('returns to the confirm step when sending fails', async () => { - h.directSendAsync = vi.fn<() => Promise>().mockRejectedValue(new Error('send failed')) + h.mutateAsync = vi.fn<() => Promise>().mockRejectedValue(new Error('send failed')) renderDialog() goToConfirm() + fireEvent.click(screen.getByTestId('confirm-switch')) fireEvent.click(screen.getByText('earn.fidelity_bond.move.text_button_submit')) await waitFor(() => diff --git a/src/components/earn/MoveToJarDialog.tsx b/src/components/earn/MoveToJarDialog.tsx index e6d714d4..09e6d98f 100644 --- a/src/components/earn/MoveToJarDialog.tsx +++ b/src/components/earn/MoveToJarDialog.tsx @@ -1,39 +1,48 @@ -import { useMemo, useState } from 'react' -import { yupResolver } from '@hookform/resolvers/yup' -import { getaddressOptions } from '@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query' -import type { DirectSendResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' -import { useQuery } from '@tanstack/react-query' -import { AlertTriangleIcon, UnlockIcon } from 'lucide-react' -import { useForm, useWatch } from 'react-hook-form' +import { useState, useMemo } from 'react' +import { + directsendMutation, + freezeMutation, + getaddressOptions, +} from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query' +import type { DirectSendResponse, ErrorMessage } from '@joinmarket-webui/joinmarket-api-ts/jm' +import { useMutation, useQuery } from '@tanstack/react-query' +import { + AlertTriangleIcon, + CheckCircle2Icon, + ChevronLeftIcon, + CopyIcon, + CheckIcon, + UnlockIcon, + Loader2Icon, +} from 'lucide-react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' -import { Alert, AlertTitle } from '@/components/ui/alert' +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' +import { buttonVariants } from '@/components/ui/button-variants' +import { Card, CardContent } from '@/components/ui/card' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { CopyButton } from '@/components/ui/jam/CopyButton' +import { Label } from '@/components/ui/label' +import { Spinner } from '@/components/ui/spinner' +import { Switch } from '@/components/ui/switch' import { useJamWalletInfoContext } from '@/context/JamWalletInfoContext' import { useApiClient } from '@/hooks/useApiClient' -import type { FidelityBondUtxo } from '@/hooks/useQueryUtxos' -import type { WalletFileName } from '@/lib/utils' -import { createMoveToJarFormSchema, type MoveToJarFormValues } from './MoveToJarDialog.schema' -import { FidelityBondDialogLayout } from './fidelity-bond/FidelityBondDialogLayout' -import { - AddressPreview, - CopyableField, - FidelityBondAmount, - InfoCard, - InlineLoading, - JarBadge, - PendingStep, - StepIntro, - SuccessHeading, -} from './fidelity-bond/FidelityBondDialogParts' -import { FidelityBondJarSelector } from './fidelity-bond/FidelityBondJarSelector' -import { WizardStepFooter } from './fidelity-bond/WizardStepFooter' -import { useFidelityBondSweep } from './fidelity-bond/useFidelityBondSweep' +import type { FidelityBondUtxo, Utxo } from '@/hooks/useQueryUtxos' +import { getErrorReason } from '@/lib/errorReason' +import { cn, formatSats, type WalletFileName } from '@/lib/utils' +import type { JarIndex } from '@/types/global' +import { Address } from '../ui/jam/Address' type Step = 'select_jar' | 'confirm' | 'sending' | 'success' -const WIZARD_STEPS: Step[] = ['select_jar', 'confirm'] - interface MoveToJarDialogProps { open: boolean onOpenChange: (open: boolean) => void @@ -47,33 +56,23 @@ export function MoveToJarDialog({ open, onOpenChange, walletFileName, utxo }: Mo const walletInfo = useJamWalletInfoContext() const [step, setStep] = useState('select_jar') + const [selectedJarIndex, setSelectedJarIndex] = useState() + const [confirmationChecked, setConfirmationChecked] = useState(false) const [txResult, setTxResult] = useState() + const [error, setError] = useState() - const availableJarIndexes = useMemo(() => walletInfo.jars.map((jar) => jar.jarIndex), [walletInfo.jars]) - const formSchema = useMemo(() => createMoveToJarFormSchema(availableJarIndexes), [availableJarIndexes]) - const { - control, - handleSubmit, - reset, - setValue, - formState: { isSubmitting }, - } = useForm({ - mode: 'onChange', - defaultValues: { - destinationJarIndex: undefined, - }, - resolver: yupResolver(formSchema), - }) - const selectedJarIndex = useWatch({ control, name: 'destinationJarIndex' }) + const sourceJar = walletInfo.jars.find((jar) => jar.jarIndex === utxo.mixdepth) - const { sweep, isLoading, error, setError, sourceJar } = useFidelityBondSweep({ - walletFileName, - utxo, - unfreezeErrorKey: 'earn.fidelity_bond.move.error_unfreezing_fidelity_bond', - sendErrorKey: 'earn.fidelity_bond.move.error_spending_fidelity_bond', - }) + // All jars except the FB's source jar are valid destinations + const destinationJars = useMemo(() => { + return walletInfo.jars.filter((jar) => jar.jarIndex !== utxo.mixdepth) + }, [walletInfo.jars, utxo.mixdepth]) - const destinationJar = walletInfo.jars.find((jar) => jar.jarIndex === selectedJarIndex) + // UTXOs in the source jar that are NOT this FB — they need to be frozen during sweep + const utxosToFreeze = useMemo(() => { + if (!sourceJar) return [] + return sourceJar.utxos.filter((u) => u.utxo !== utxo.utxo && !u.frozen) + }, [sourceJar, utxo.utxo]) const getAddressQueryOptions = getaddressOptions({ client, @@ -90,12 +89,40 @@ export function MoveToJarDialog({ open, onOpenChange, walletFileName, utxo }: Mo retry: false, }) + if (getAddressQuery.isError && !error) { + setError(t('earn.fidelity_bond.move.error_loading_address')) + } + const destinationAddress = getAddressQuery.data?.address - const displayError = error ?? (getAddressQuery.isError ? t('global.errors.error_loading_address_failed') : undefined) + + const freezeUtxo = useMutation({ + ...freezeMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.move.error_freezing_utxos')} ${reason}`) + }, + }) + + const unfreezeUtxo = useMutation({ + ...freezeMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.move.error_unfreezing_fidelity_bond')} ${reason}`) + }, + }) + + const directSend = useMutation({ + ...directsendMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.move.error_spending_fidelity_bond')} ${reason}`) + }, + }) const handleReset = () => { setStep('select_jar') - reset() + setSelectedJarIndex(undefined) + setConfirmationChecked(false) setTxResult(undefined) setError(undefined) } @@ -107,131 +134,293 @@ export function MoveToJarDialog({ open, onOpenChange, walletFileName, utxo }: Mo onOpenChange(newOpen) } - const submitMove = handleSubmit(async () => { - if (!destinationAddress) return + const handleSubmit = async () => { + if (selectedJarIndex === undefined || !destinationAddress) return setStep('sending') - const txResult = await sweep({ - destination: destinationAddress, - tryFreezeAfterBroadcast: false, - }) + setError(undefined) - setTxResult(txResult) + const frozen: Utxo[] = [] + try { + // Freeze other UTXOs in the source jar so only the FB gets swept + for (const u of utxosToFreeze) { + await freezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': u.utxo, freeze: true }, + }) + frozen.push(u) + } - if (txResult) { + if (utxo.frozen) { + await unfreezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': utxo.utxo, freeze: false }, + }) + } + + const result = await directSend.mutateAsync({ + path: { walletname: walletFileName }, + body: { + mixdepth: utxo.mixdepth, + amount_sats: 0, + destination: destinationAddress, + }, + }) + + setTxResult(result) setStep('success') toast.success(t('earn.fidelity_bond.move.success_text')) - } else { - setStep('confirm') - } - }) - const renderFooter = () => { - switch (step) { - case 'select_jar': - return ( - handleOpenChange(false)} - onPrimary={() => setStep('confirm')} - primaryDisabled={selectedJarIndex === undefined} - primaryLabel={t('global.next')} - /> - ) - case 'confirm': - return ( - setStep('select_jar')} - onCancel={() => handleOpenChange(false)} - onPrimary={() => void submitMove()} - primaryDisabled={!destinationAddress} - isLoading={isLoading || isSubmitting} - primaryLabel={t('earn.fidelity_bond.move.text_button_submit')} - /> - ) - case 'sending': - return null - case 'success': - return + // Best-effort cleanup — tx already broadcast, don't throw on unfreeze failure + for (const u of frozen) { + try { + await unfreezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': u.utxo, freeze: false }, + }) + } catch { + // logged via onError + } + } + + await walletInfo.refetch() + } catch { + // Best-effort rollback — unfreeze UTXOs that were frozen before the error + for (const u of frozen) { + try { + await unfreezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': u.utxo, freeze: false }, + }) + } catch { + // logged via onError + } + } + setStep('confirm') } } + const isLoading = freezeUtxo.isPending || unfreezeUtxo.isPending || directSend.isPending + return ( - - {step === 'select_jar' && ( -
- + + + + {t('earn.fidelity_bond.move.title')} + {t('earn.fidelity_bond.subtitle')} + - - - - - - setValue('destinationJarIndex', jarIndex, { - shouldDirty: true, - shouldTouch: true, - shouldValidate: true, - }) - } - isJarDisabled={() => false} - /> -
- )} - - {step === 'confirm' && ( -
-
- - - - - - -
- - - - - - {getAddressQuery.isLoading ? ( - - ) : ( - destinationAddress && ( - - ) - )} - - + {error && ( + - {t('earn.fidelity_bond.move.confirm_send_modal.title')} + {error} -
- )} + )} - {step === 'sending' && } +
+ {step === 'select_jar' && ( +
+
+
+ +
+
+

{t('earn.fidelity_bond.move.select_jar.description')}

+
+
- {step === 'success' && ( -
- +
+

+ {t('earn.fidelity_bond.review_inputs.label_amount')} +

+

{formatSats(utxo.value)}

+
- {txResult?.txinfo?.txid && ( - +
+ {destinationJars.map((jar) => { + const isSelected = selectedJarIndex === jar.jarIndex + return ( + setSelectedJarIndex(jar.jarIndex)} + > + +
+
+
+

{jar.name}

+
+
+
+

+ {formatSats(jar.balanceSummary.calculatedAvailableBalanceInSats)} +

+ {isSelected && } +
+ + + ) + })} +
+
+ )} + + {step === 'confirm' && ( +
+
+
+

+ {t('earn.fidelity_bond.review_inputs.label_jar')} +

+

+ {t('earn.fidelity_bond.review_inputs.label_jar_n', { jar: utxo.mixdepth })} +

+
+
+

{t('earn.fidelity_bond.move.label_destination')}

+

+ {t('earn.fidelity_bond.review_inputs.label_jar_n', { jar: selectedJarIndex })} +

+
+
+ +
+

+ {t('earn.fidelity_bond.review_inputs.label_amount')} +

+

{formatSats(utxo.value)}

+
+ + {getAddressQuery.isLoading ? ( +
+ +

{t('earn.fidelity_bond.move.text_loading')}

+
+ ) : ( + destinationAddress && ( +
+ +
+
+
+
+ ) + )} + + + + {t('earn.fidelity_bond.move.confirm_send_modal.title')} + + +
+ setConfirmationChecked(checked)} + /> +
+ +
+
+
+ )} + + {step === 'sending' && ( +
+
+ +
+ +
+
+

{t('earn.fidelity_bond.move.text_sending')}

+
+ )} + + {step === 'success' && ( +
+
+
+ +
+

{t('earn.fidelity_bond.move.success_text')}

+
+ + {txResult?.txinfo?.txid && ( +
+ +
+ + {txResult.txinfo.txid} + + } + successText={} + className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} + onSuccess={() => + toast.success(t('earn.fidelity_bond.create_fidelity_bond.text_copy_transaction_id')) + } + onError={() => toast.error(t('global.errors.reason_unknown'))} + /> +
+
+ )} +
)}
- )} - + + {step === 'select_jar' && ( + + + + + )} + + {step === 'confirm' && ( + + + + + + )} + + {step === 'success' && ( + + + + )} + +
) } diff --git a/src/components/earn/OfferCard.test.tsx b/src/components/earn/OfferCard.test.tsx index 150e93c9..9b8722ad 100644 --- a/src/components/earn/OfferCard.test.tsx +++ b/src/components/earn/OfferCard.test.tsx @@ -1,7 +1,6 @@ -import type { SessionResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' +import type { SessionResponse } from '@joinmarket-webui/joinmarket-api-ts/jm' import { render, screen } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import { withRuntimeLocale } from '@/test/withRuntimeLocale' import { OfferCard } from './OfferCard' type Offer = NonNullable[number] @@ -19,7 +18,7 @@ vi.mock('@/lib/utils', () => ({ isRelativeOffer: (type: string) => type === 'sw0relo', })) -vi.mock('@/components/ui/jam/Balance', () => ({ +vi.mock('../ui/jam/Balance', () => ({ Balance: ({ valueString }: { valueString?: string }) => {valueString}, })) @@ -65,7 +64,7 @@ describe('OfferCard', () => { }) it('renders without txfee', () => { - const offer = { ...baseOffer, ordertype: 'sw0abso', txfee: undefined } as unknown as Offer + const offer = { ...baseOffer, ordertype: 'sw0abso', txfee: undefined } render() expect(screen.queryByText('earn.current.text_txfee')).not.toBeInTheDocument() @@ -80,41 +79,4 @@ describe('OfferCard', () => { expect(screen.getByTestId('child')).toBeInTheDocument() }) - - it('shows whether the offer is visible in the local orderbook', () => { - const { rerender } = render() - - expect(screen.getByText('earn.current.text_orderbook_visible')).toBeInTheDocument() - - rerender() - expect(screen.getByText('earn.current.text_orderbook_missing')).toBeInTheDocument() - }) - - it('shows the advertised fidelity bond details', () => { - withRuntimeLocale('de-DE', () => { - render( - , - ) - - expect(screen.getByText('earn.current.text_fidelity_bond')).toBeInTheDocument() - expect(screen.getByText('earn.current.text_bond_value: 42.000')).toBeInTheDocument() - expect(screen.getByText('100000')).toBeInTheDocument() - expect(screen.getByText(/earn\.current\.text_bond_locktime/u)).toBeInTheDocument() - }) - }) }) diff --git a/src/components/earn/OfferCard.tsx b/src/components/earn/OfferCard.tsx index 9880cdaa..e42d5d28 100644 --- a/src/components/earn/OfferCard.tsx +++ b/src/components/earn/OfferCard.tsx @@ -1,22 +1,11 @@ import type { PropsWithChildren } from 'react' -import type { SessionResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' +import type { SessionResponse } from '@joinmarket-webui/joinmarket-api-ts/jm' import type { TFunction } from 'i18next' -import { - CircleAlertIcon, - CircleCheckIcon, - FingerprintIcon, - HandCoinsIcon, - Maximize2Icon, - Minimize2Icon, - PickaxeIcon, - SearchIcon, - ShieldCheckIcon, -} from 'lucide-react' +import { FingerprintIcon, HandCoinsIcon, Maximize2Icon, Minimize2Icon } from 'lucide-react' import { useTranslation } from 'react-i18next' import { Badge } from '@/components/ui/badge' import { Card, CardContent, CardAction, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import type { OrderbookFidelityBond, OrderbookOffer } from '@/lib/api/orderbook' import { cn, factorToPercentage, isAbsoluteOffer, isRelativeOffer } from '@/lib/utils' import { Balance } from '../ui/jam/Balance' import { Label } from '../ui/label' @@ -26,71 +15,33 @@ type Offer = NonNullable[number] const OfferTypeBadge = ({ value }: { value: Offer }) => { const { t } = useTranslation() const text = renderOfferText(value, t) - return ( - - {text} - - ) + return {text} } const renderOfferText = (value: Offer, t: TFunction<'translation', undefined>) => { - if (isAbsoluteOffer(String(value?.ordertype || ''))) { + if (isAbsoluteOffer(value?.ordertype || '')) { return t('earn.current.text_offer_type_absolute') } - if (isRelativeOffer(String(value?.ordertype || ''))) { + if (isRelativeOffer(value?.ordertype || '')) { return t('earn.current.text_offer_type_relative') } - return String(value?.ordertype || '') + return value?.ordertype } interface OfferCardProps { className?: string value: Offer nickname: SessionResponse['nickname'] - orderbookStatus?: 'checking' | 'visible' | 'missing' | 'error' - orderbookOffer?: OrderbookOffer - fidelityBond?: OrderbookFidelityBond } -const orderbookStatusEntry = (value: OfferCardProps['orderbookStatus'], t: TFunction) => { - return value === 'visible' - ? { icon: CircleCheckIcon, text: t('earn.current.text_orderbook_visible'), variant: 'success' as const } - : value === 'missing' - ? { icon: SearchIcon, text: t('earn.current.text_orderbook_missing'), variant: 'warning' as const } - : value === 'error' - ? { icon: CircleAlertIcon, text: t('earn.current.text_orderbook_error'), variant: 'destructive' as const } - : value === 'checking' - ? { icon: SearchIcon, text: t('earn.current.text_orderbook_checking'), variant: 'muted' as const } - : undefined -} - -export function OfferCard({ - className, - value, - nickname, - orderbookStatus, - orderbookOffer, - fidelityBond, - children, -}: PropsWithChildren) { +export function OfferCard({ className, value, nickname, children }: PropsWithChildren) { const { t } = useTranslation() - const bondValue = Number(orderbookOffer?.fidelity_bond_value) || 0 - - const offerInOrderbookStatus = orderbookStatusEntry(orderbookStatus, t) - const bondWarning = bondValue === 0 || orderbookOffer?.fidelity_bond_verification_stale === true return ( - + {t('earn.current.text_offer')} - - {offerInOrderbookStatus && ( - - - {offerInOrderbookStatus.text} - - )} - + @@ -101,43 +52,41 @@ export function OfferCard({ -
- -
+
+ +
- + {nickname}:{value?.oid}
-
- -
+
+ +
- {isRelativeOffer(String(value?.ordertype || '')) ? ( - - {factorToPercentage(Number.parseFloat(String(value?.cjfee || '')) || 0)}% - + {isRelativeOffer(value?.ordertype || '') ? ( + {factorToPercentage(Number.parseFloat(value?.cjfee || '') || 0)}% ) : ( )}
-
- -
+
+ +
-
- -
+
+ +
@@ -145,9 +94,8 @@ export function OfferCard({
{!!value?.txfee && ( -
- -
+
+
@@ -155,45 +103,6 @@ export function OfferCard({
)} - {fidelityBond !== undefined && ( -
- 0, - 'text-brand-warning': bondWarning, - })} - /> -
- -
-
- - {t('earn.current.text_bond_value')}: {Math.floor(bondValue).toLocaleString()} - -
-
- - - {t('earn.current.text_bond_locktime', { - date: new Date(fidelityBond.locktime * 1_000).toLocaleDateString(undefined, { - year: 'numeric', - month: 'long', - day: 'numeric', - }), - })} - -
-
-
-
- )} {children} diff --git a/src/components/earn/RenewBondDialog.schema.test.ts b/src/components/earn/RenewBondDialog.schema.test.ts deleted file mode 100644 index 2053bb0a..00000000 --- a/src/components/earn/RenewBondDialog.schema.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { renewBondFormSchema } from './RenewBondDialog.schema' - -describe('renewBondFormSchema', () => { - it('accepts a lockdate after confirmation', async () => { - const values = { lockdate: '2030-01' as const, confirmationAccepted: true } - await expect(renewBondFormSchema.validate(values)).resolves.toEqual(values) - }) - - it.each([ - { lockdate: undefined, confirmationAccepted: true }, - { lockdate: '2030-01' as const, confirmationAccepted: false }, - ])('rejects incomplete renewal values', async (values) => { - await expect(renewBondFormSchema.isValid(values)).resolves.toBe(false) - }) -}) diff --git a/src/components/earn/RenewBondDialog.schema.ts b/src/components/earn/RenewBondDialog.schema.ts deleted file mode 100644 index a36649f9..00000000 --- a/src/components/earn/RenewBondDialog.schema.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as yup from 'yup' -import * as fb from '@/lib/fidelityBondUtils' - -export type RenewBondFormValues = { - lockdate?: fb.Lockdate - confirmationAccepted: boolean -} - -export const RENEW_BOND_FORM_DEFAULT_VALUES: RenewBondFormValues = { - lockdate: undefined, - confirmationAccepted: false, -} - -export const renewBondFormSchema: yup.ObjectSchema = yup - .object({ - lockdate: yup.string().required(), - confirmationAccepted: yup.boolean().oneOf([true]).required(), - }) - .required() diff --git a/src/components/earn/RenewBondDialog.test.tsx b/src/components/earn/RenewBondDialog.test.tsx index 1b181058..0fc68cfa 100644 --- a/src/components/earn/RenewBondDialog.test.tsx +++ b/src/components/earn/RenewBondDialog.test.tsx @@ -4,15 +4,13 @@ import { describe, expect, it, vi, beforeEach } from 'vitest' import type { FidelityBondUtxo } from '@/hooks/useQueryUtxos' import { RenewBondDialog } from './RenewBondDialog' -type MutationOptions = { mutationFn: (input: unknown) => Promise } - type ChildrenProps = { children?: ReactNode } type ValueProps = { value: string } const h = vi.hoisted(() => ({ - fetchAddressQueryData: { data: undefined as { address: string } | undefined, isLoading: false, isError: false }, - directSendAsync: vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'abcd1234' } }), - freezeAsync: vi.fn<() => Promise>().mockResolvedValue({}), + queryReturn: { data: undefined as { address: string } | undefined, isLoading: false, isError: false }, + mutateAsync: vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'abcd1234' } }), + isPending: false, refetch: vi.fn(), utxoFrozen: false, extraUtxos: [] as Array<{ utxo: string; value: number; frozen: boolean }>, @@ -26,16 +24,13 @@ vi.mock('react-i18next', () => ({ })) vi.mock('@tanstack/react-query', () => ({ - useQuery: () => h.fetchAddressQueryData, - useMutation: vi.fn((options: MutationOptions) => ({ - isPending: false, - mutateAsync: async (input: unknown) => await options.mutationFn(input), - })), + useQuery: () => h.queryReturn, + useMutation: () => ({ mutateAsync: h.mutateAsync, isPending: h.isPending }), })) -vi.mock('@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query', () => ({ - directsendMutation: vi.fn(() => ({ mutationFn: h.directSendAsync })), - freezeMutation: vi.fn(() => ({ mutationFn: h.freezeAsync })), +vi.mock('@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query', () => ({ + directsendMutation: vi.fn(() => ({})), + freezeMutation: vi.fn(() => ({})), gettimelockaddressOptions: vi.fn(() => ({ queryKey: ['mock'], queryFn: vi.fn() })), })) @@ -61,7 +56,7 @@ vi.mock('@/context/JamWalletInfoContext', () => ({ vi.mock('@/lib/errorReason', () => ({ getErrorReason: () => 'reason' })) vi.mock('@/lib/fidelityBondUtils', () => ({ - lockdate: { toDateLabel: () => 'January 1, 2030' }, + lockdate: { toTimestamp: () => 1_893_456_000_000 }, })) vi.mock('@/lib/utils', async (importOriginal) => ({ @@ -141,10 +136,6 @@ vi.mock('@/components/ui/jam/CopyButton', () => ({ CopyButton: ({ value }: ValueProps) =>
{value}
, })) -vi.mock('@/components/ui/jam/Balance', () => ({ - Balance: ({ valueString }: { valueString: string }) => {valueString} sats, -})) - vi.mock('@/components/ui/label', () => ({ Label: ({ children }: ChildrenProps) => })) vi.mock('../ui/jam/Address', () => ({ @@ -175,15 +166,15 @@ const selectYear = (value: string) => { const goToConfirm = () => { selectMonth('06') - fireEvent.click(screen.getByText('global.next')) + fireEvent.click(screen.getByText('earn.fidelity_bond.select_date.text_primary_button')) } describe('RenewBondDialog', () => { beforeEach(() => { vi.clearAllMocks() - h.fetchAddressQueryData = { data: { address: 'bc1timelock' }, isLoading: false, isError: false } - h.directSendAsync = vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'abcd1234' } }) - h.freezeAsync = vi.fn<() => Promise>().mockResolvedValue({}) + h.queryReturn = { data: { address: 'bc1timelock' }, isLoading: false, isError: false } + h.mutateAsync = vi.fn<() => Promise>().mockResolvedValue({ txinfo: { txid: 'abcd1234' } }) + h.isPending = false h.utxoFrozen = false h.extraUtxos = [] h.selectHandlers = [] @@ -198,13 +189,13 @@ describe('RenewBondDialog', () => { it('selecting a month enables the next button and shows the chosen date', () => { renderDialog() selectMonth('06') - expect(screen.getByText('earn.fidelity_bond.select_date.label_selected_lock_date')).toBeInTheDocument() + expect(screen.getByText('earn.fidelity_bond.review_inputs.label_lock_date')).toBeInTheDocument() }) it('selecting a year computes a clamped lock date', () => { renderDialog() selectYear('2027') - expect(screen.getByText('earn.fidelity_bond.select_date.label_selected_lock_date')).toBeInTheDocument() + expect(screen.getByText('earn.fidelity_bond.review_inputs.label_lock_date')).toBeInTheDocument() }) it('selecting an early month bumps the year forward', () => { @@ -212,7 +203,7 @@ describe('RenewBondDialog', () => { // a month earlier than the minimum month forces year = minYear + 1 selectMonth('06') selectYear('2026') - expect(screen.getByText('earn.fidelity_bond.select_date.label_selected_lock_date')).toBeInTheDocument() + expect(screen.getByText('earn.fidelity_bond.review_inputs.label_lock_date')).toBeInTheDocument() }) it('moves to the confirm step and shows the timelock address', () => { @@ -222,33 +213,27 @@ describe('RenewBondDialog', () => { }) it('shows a loading spinner while the timelock address loads', () => { - h.fetchAddressQueryData = { data: undefined, isLoading: true, isError: false } + h.queryReturn = { data: undefined, isLoading: true, isError: false } renderDialog() goToConfirm() expect(screen.getByText('earn.fidelity_bond.renew.text_loading')).toBeInTheDocument() }) it('shows an error alert when the address query fails', () => { - h.fetchAddressQueryData = { data: undefined, isLoading: false, isError: true } + h.queryReturn = { data: undefined, isLoading: false, isError: true } renderDialog() expect(screen.getByText('earn.fidelity_bond.error_loading_address')).toBeInTheDocument() }) it('completes the renew flow and reaches the success step', async () => { h.extraUtxos = [{ utxo: 'tx2:0', value: 500, frozen: false }] - renderDialog() - - expect(screen.queryByText('earn.fidelity_bond.renew.success_text')).not.toBeInTheDocument() - goToConfirm() - fireEvent.click(screen.getByTestId('confirm-switch')) fireEvent.click(screen.getByText('earn.fidelity_bond.renew.text_button_submit')) await waitFor(() => expect(screen.getByText('earn.fidelity_bond.renew.success_text')).toBeInTheDocument()) expect(screen.getAllByText('abcd1234').length).toBeGreaterThan(0) - expect(h.refetch).toHaveBeenCalled() }) @@ -260,40 +245,13 @@ describe('RenewBondDialog', () => { fireEvent.click(screen.getByText('earn.fidelity_bond.renew.text_button_submit')) await waitFor(() => expect(screen.getByText('earn.fidelity_bond.renew.success_text')).toBeInTheDocument()) - const calls = h.freezeAsync.mock.calls as unknown as Array< - [{ body?: { 'utxo-string'?: string; freeze?: boolean } }] - > - expect( - calls.some((call) => call[0]?.body?.['utxo-string'] === frozenUtxo.utxo && call[0]?.body?.freeze === false), - ).toBe(true) - }) - - it('freezes a fidelity bond after sending', async () => { - const frozenUtxo = { ...utxo, frozen: true } as unknown as FidelityBondUtxo - render() - goToConfirm() - fireEvent.click(screen.getByTestId('confirm-switch')) - fireEvent.click(screen.getByText('earn.fidelity_bond.renew.text_button_submit')) - - await waitFor(() => expect(screen.getByText('earn.fidelity_bond.renew.success_text')).toBeInTheDocument()) - - const calls = h.freezeAsync.mock.calls as unknown as Array< - [{ body?: { 'utxo-string'?: string; freeze?: boolean } }] - > - // unfreezes the expired fb utxo - expect( - calls.some((call) => call[0]?.body?.['utxo-string'] === frozenUtxo.utxo && call[0]?.body?.freeze === false), - ).toBe(true) - - // freezes the renewed fb utxo - expect( - calls.some((call) => call[0]?.body?.['utxo-string'] === 'abcd1234:0' && call[0]?.body?.freeze === true), - ).toBe(true) + const calls = h.mutateAsync.mock.calls as unknown as Array<[{ body?: { freeze?: boolean } }]> + expect(calls.some((call) => call[0]?.body?.freeze === false)).toBe(true) }) it('returns to the confirm step when sending fails', async () => { h.extraUtxos = [{ utxo: 'tx2:0', value: 500, frozen: false }] - h.directSendAsync = vi.fn<() => Promise>().mockRejectedValue(new Error('send failed')) + h.mutateAsync = vi.fn<() => Promise>().mockRejectedValue(new Error('send failed')) renderDialog() goToConfirm() fireEvent.click(screen.getByTestId('confirm-switch')) diff --git a/src/components/earn/RenewBondDialog.tsx b/src/components/earn/RenewBondDialog.tsx index 6896c20d..de458991 100644 --- a/src/components/earn/RenewBondDialog.tsx +++ b/src/components/earn/RenewBondDialog.tsx @@ -1,41 +1,50 @@ -import { useState } from 'react' -import { yupResolver } from '@hookform/resolvers/yup' -import { gettimelockaddressOptions } from '@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query' -import type { DirectSendResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' -import { useQuery } from '@tanstack/react-query' -import { AlertTriangleIcon, CalendarIcon, RefreshCwIcon } from 'lucide-react' -import { useForm, useWatch } from 'react-hook-form' +import { useState, useMemo } from 'react' +import { + directsendMutation, + freezeMutation, + gettimelockaddressOptions, +} from '@joinmarket-webui/joinmarket-api-ts/@tanstack/react-query' +import type { DirectSendResponse, ErrorMessage } from '@joinmarket-webui/joinmarket-api-ts/jm' +import { useMutation, useQuery } from '@tanstack/react-query' +import { + AlertTriangleIcon, + CalendarIcon, + CheckCircle2Icon, + CheckIcon, + ChevronLeftIcon, + CopyIcon, + RefreshCwIcon, +} from 'lucide-react' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' -import { JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS } from '@/constants/jam' -import { useApiClient } from '@/hooks/useApiClient' -import type { FidelityBondUtxo } from '@/hooks/useQueryUtxos' -import * as fb from '@/lib/fidelityBondUtils' -import type { WalletFileName } from '@/lib/utils' -import { RENEW_BOND_FORM_DEFAULT_VALUES, renewBondFormSchema, type RenewBondFormValues } from './RenewBondDialog.schema' -import { FidelityBondDialogLayout } from './fidelity-bond/FidelityBondDialogLayout' +import { buttonVariants } from '@/components/ui/button-variants' import { - AddressPreview, - ConfirmationToggle, - CopyableField, - FidelityBondAmount, - InfoCard, - InlineLoading, - JarBadge, - PendingStep, - StepIntro, - SuccessHeading, -} from './fidelity-bond/FidelityBondDialogParts' -import { LockdateSelect } from './fidelity-bond/LockdateSelect' -import { WizardStepFooter } from './fidelity-bond/WizardStepFooter' -import { useFidelityBondSweep } from './fidelity-bond/useFidelityBondSweep' + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { CopyButton } from '@/components/ui/jam/CopyButton' +import { Label } from '@/components/ui/label' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Spinner } from '@/components/ui/spinner' +import { Switch } from '@/components/ui/switch' +import { useJamWalletInfoContext } from '@/context/JamWalletInfoContext' +import { useApiClient } from '@/hooks/useApiClient' +import type { FidelityBondUtxo, Utxo } from '@/hooks/useQueryUtxos' +import { getErrorReason } from '@/lib/errorReason' +import * as fb from '@/lib/fidelityBondUtils' +import { cn, formatSats, type WalletFileName } from '@/lib/utils' +import { useDeveloperMode } from '@/store/jamSettingsStore' +import { Address } from '../ui/jam/Address' +import { generateLockdateOptions, getYearOptions, getMonthOptions } from './CreateFidelityBondDialog/types' type Step = 'select_date' | 'confirm' | 'sending' | 'success' -const WIZARD_STEPS: Step[] = ['select_date', 'confirm'] - interface RenewBondDialogProps { open: boolean onOpenChange: (open: boolean) => void @@ -46,35 +55,46 @@ interface RenewBondDialogProps { export function RenewBondDialog({ open, onOpenChange, walletFileName, utxo }: RenewBondDialogProps) { const { t } = useTranslation() const client = useApiClient() + const walletInfo = useJamWalletInfoContext() + const { enabled: isDeveloperMode } = useDeveloperMode() const [step, setStep] = useState('select_date') + const [selectedLockdate, setSelectedLockdate] = useState('') + const [confirmationChecked, setConfirmationChecked] = useState(false) const [txResult, setTxResult] = useState() + const [error, setError] = useState() - const { - control, - handleSubmit, - reset, - setValue, - formState: { isSubmitting }, - } = useForm({ - mode: 'onChange', - defaultValues: RENEW_BOND_FORM_DEFAULT_VALUES, - resolver: yupResolver(renewBondFormSchema), - }) - const selectedLockdate = useWatch({ control, name: 'lockdate' }) - const confirmationChecked = useWatch({ - control, - name: 'confirmationAccepted', - }) + const lockdateOptions = useMemo(() => generateLockdateOptions(isDeveloperMode), [isDeveloperMode]) + const yearOptions = useMemo(() => getYearOptions(lockdateOptions), [lockdateOptions]) + const monthOptions = useMemo(() => getMonthOptions(), []) - const { sweep, isLoading, error, setError, sourceJar } = useFidelityBondSweep({ - walletFileName, - utxo, - unfreezeErrorKey: 'earn.fidelity_bond.error_unfreezing_utxos', - sendErrorKey: 'earn.fidelity_bond.renew.error_renewing_fidelity_bond', - }) + const minLockdate = lockdateOptions.at(0)?.value ?? '' + const maxLockdate = lockdateOptions.at(-1)?.value ?? '' + const clampLockdate = (lockdate: string): fb.Lockdate | '' => { + if (!lockdate || lockdate < minLockdate) return minLockdate || '' + if (lockdate > maxLockdate) return maxLockdate || '' + return lockdate as fb.Lockdate + } + const selectedYear = selectedLockdate ? selectedLockdate.slice(0, 4) : '' + const selectedMonth = selectedLockdate ? selectedLockdate.slice(5, 7) : '' + const minYear = minLockdate ? Number.parseInt(minLockdate.slice(0, 4), 10) : 0 + const minMonth = minLockdate ? Number.parseInt(minLockdate.slice(5, 7), 10) : 1 - const selectedDateLabel = selectedLockdate ? fb.lockdate.toDateLabel(selectedLockdate) : null + const selectedDateLabel = selectedLockdate + ? new Date(fb.lockdate.toTimestamp(selectedLockdate)).toLocaleDateString(undefined, { + year: 'numeric', + month: 'long', + day: 'numeric', + }) + : null + + const sourceJar = walletInfo.jars.find((jar) => jar.jarIndex === utxo.mixdepth) + + // UTXOs in the source jar that are NOT this FB — they need to be frozen during sweep + const utxosToFreeze = useMemo(() => { + if (!sourceJar) return [] + return sourceJar.utxos.filter((u) => u.utxo !== utxo.utxo && !u.frozen) + }, [sourceJar, utxo.utxo]) const timelockAddressQuery = useQuery({ ...gettimelockaddressOptions({ @@ -89,13 +109,40 @@ export function RenewBondDialog({ open, onOpenChange, walletFileName, utxo }: Re retry: false, }) + if (timelockAddressQuery.isError && !error) { + setError(t('earn.fidelity_bond.error_loading_address')) + } + const destinationAddress = timelockAddressQuery.data?.address - const displayError = - error ?? (timelockAddressQuery.isError ? t('earn.fidelity_bond.error_loading_address') : undefined) + + const freezeUtxo = useMutation({ + ...freezeMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.error_freezing_utxos')} ${reason}`) + }, + }) + + const unfreezeUtxo = useMutation({ + ...freezeMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.error_unfreezing_utxos')} ${reason}`) + }, + }) + + const directSend = useMutation({ + ...directsendMutation({ client }), + onError: (error: ErrorMessage) => { + const reason = getErrorReason(error, t('global.errors.reason_unknown')) + setError(`${t('earn.fidelity_bond.renew.error_renewing_fidelity_bond')} ${reason}`) + }, + }) const handleReset = () => { setStep('select_date') - reset(RENEW_BOND_FORM_DEFAULT_VALUES) + setSelectedLockdate('') + setConfirmationChecked(false) setTxResult(undefined) setError(undefined) } @@ -107,161 +154,348 @@ export function RenewBondDialog({ open, onOpenChange, walletFileName, utxo }: Re onOpenChange(newOpen) } - const submitRenewal = handleSubmit(async () => { + const handleSubmit = async () => { if (!destinationAddress) return setStep('sending') + setError(undefined) - const txResult = await sweep({ - destination: destinationAddress, - tryFreezeAfterBroadcast: JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS, - }) + const frozen: Utxo[] = [] + try { + // Freeze other UTXOs in the source jar so only the FB gets swept + for (const u of utxosToFreeze) { + await freezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': u.utxo, freeze: true }, + }) + frozen.push(u) + } - setTxResult(txResult) - if (txResult) { + if (utxo.frozen) { + await unfreezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': utxo.utxo, freeze: false }, + }) + } + + const result = await directSend.mutateAsync({ + path: { walletname: walletFileName }, + body: { + mixdepth: utxo.mixdepth, + amount_sats: 0, + destination: destinationAddress, + }, + }) + + setTxResult(result) setStep('success') toast.success(t('earn.fidelity_bond.renew.success_text')) - } else { - setStep('confirm') - } - }) - const renderFooter = () => { - switch (step) { - case 'select_date': - return ( - handleOpenChange(false)} - onPrimary={() => setStep('confirm')} - primaryDisabled={!selectedLockdate} - primaryLabel={t('global.next')} - /> - ) - case 'confirm': - return ( - setStep('select_date')} - onCancel={() => handleOpenChange(false)} - onPrimary={() => void submitRenewal()} - primaryDisabled={!confirmationChecked || !destinationAddress} - isLoading={isLoading || isSubmitting} - primaryLabel={t('earn.fidelity_bond.renew.text_button_submit')} - /> - ) - case 'sending': - return null - case 'success': - return + // Best-effort cleanup — tx already broadcast, don't throw on unfreeze failure + for (const u of frozen) { + try { + await unfreezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': u.utxo, freeze: false }, + }) + } catch { + // logged via onError + } + } + + await walletInfo.refetch() + } catch { + // Best-effort rollback — unfreeze UTXOs that were frozen before the error + for (const u of frozen) { + try { + await unfreezeUtxo.mutateAsync({ + path: { walletname: walletFileName }, + body: { 'utxo-string': u.utxo, freeze: false }, + }) + } catch { + // logged via onError + } + } + setStep('confirm') } } + const isLoading = freezeUtxo.isPending || unfreezeUtxo.isPending || directSend.isPending + return ( - - {step === 'select_date' && ( -
- + + + + {t('earn.fidelity_bond.renew.title')} + {t('earn.fidelity_bond.subtitle')} + - - - - - - setValue('lockdate', lockdate || undefined, { - shouldDirty: true, - shouldTouch: true, - shouldValidate: true, - }) - } - /> -
- )} - - {step === 'confirm' && ( -
-
- -

{selectedDateLabel}

-
- - - -
- - - - - - {timelockAddressQuery.isLoading ? ( - - ) : ( - destinationAddress && ( - - ) - )} - - - - {t('earn.fidelity_bond.renew.confirm_send_modal.title')} - - {t('earn.fidelity_bond.confirm_modal.body', { - /* TODO: fix human readable duration */ - humanReadableDuration: selectedDateLabel ? `until ${selectedDateLabel}` : '', - date: selectedDateLabel || '', - })} - + {error && ( + + + {error} + )} - - setValue('confirmationAccepted', checked, { - shouldDirty: true, - shouldTouch: true, - shouldValidate: true, - }) - } - /> -
- )} +
+ {step === 'select_date' && ( +
+
+
+ +
+
+

{t('earn.fidelity_bond.select_date.description')}

+
+
- {step === 'sending' && } +
+

+ {t('earn.fidelity_bond.review_inputs.label_amount')} +

+

{formatSats(utxo.value)}

+
- {step === 'success' && ( -
- +
+
+ + +
+
+ + +
+
- {destinationAddress && ( - + {selectedLockdate && ( +
+

+ {t('earn.fidelity_bond.review_inputs.label_lock_date')} +

+

{selectedDateLabel}

+
+ )} +
)} - {txResult?.txinfo?.txid && ( - + {step === 'confirm' && ( +
+
+
+

+ {t('earn.fidelity_bond.review_inputs.label_lock_date')} +

+

{selectedDateLabel}

+
+
+

{t('earn.fidelity_bond.review_inputs.label_jar')}

+

+ {t('earn.fidelity_bond.review_inputs.label_jar_n', { jar: utxo.mixdepth })} +

+
+
+ +
+

{t('earn.fidelity_bond.review_inputs.label_amount')}

+

{formatSats(utxo.value)}

+
+ + {timelockAddressQuery.isLoading ? ( +
+ + {t('earn.fidelity_bond.renew.text_loading')} +
+ ) : ( + destinationAddress && ( +
+ +
+
+
+
+ ) + )} + + + + {t('earn.fidelity_bond.renew.confirm_send_modal.title')} + + {t('earn.fidelity_bond.confirm_modal.body', { + /* TODO: fix human readable duration */ + humanReadableDuration: selectedDateLabel ? `until ${selectedDateLabel}` : '', + date: selectedDateLabel || '', + })} + + + +
+ setConfirmationChecked(checked)} + /> +
+ +

+ {t('earn.fidelity_bond.create_form.confirmation_toggle_subtitle')} +

+
+
+
+ )} + + {step === 'sending' && ( +
+
+ +
+ +
+
+

{t('earn.fidelity_bond.renew.text_sending')}

+
+ )} + + {step === 'success' && ( +
+
+
+ +
+

{t('earn.fidelity_bond.renew.success_text')}

+
+ + {destinationAddress && ( +
+ +
+ + {destinationAddress} + + } + successText={} + className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} + onSuccess={() => toast.success(t('receive.text_copy_address'))} + onError={() => toast.error(t('global.errors.reason_unknown'))} + /> +
+
+ )} + + {txResult?.txinfo?.txid && ( +
+ +
+ + {txResult.txinfo.txid} + + } + successText={} + className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} + onSuccess={() => + toast.success(t('earn.fidelity_bond.create_fidelity_bond.text_copy_transaction_id')) + } + onError={() => toast.error(t('global.errors.reason_unknown'))} + /> +
+
+ )} +
)}
- )} - + + {step === 'select_date' && ( + + + + + )} + + {step === 'confirm' && ( + + + + + + )} + + {step === 'success' && ( + + + + )} + + ) } diff --git a/src/components/earn/fidelity-bond/FidelityBondDialogLayout.tsx b/src/components/earn/fidelity-bond/FidelityBondDialogLayout.tsx deleted file mode 100644 index 443522a5..00000000 --- a/src/components/earn/fidelity-bond/FidelityBondDialogLayout.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import type { ComponentProps, ReactNode } from 'react' -import { AlertTriangleIcon } from 'lucide-react' -import { useTranslation } from 'react-i18next' -import { Alert, AlertDescription } from '@/components/ui/alert' -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { StepProgress } from './StepProgress' - -type FidelityBondDialogLayoutProps = Omit, 'children'> & { - title: string - /** zero-based wizard step, or undefined to hide the progress indicator (pending/success states) */ - currentStep?: number - totalSteps: number - error?: string - footer: ReactNode - children: ReactNode -} - -export function FidelityBondDialogLayout({ - title, - currentStep, - totalSteps, - error, - footer, - children, - ...dialogProps -}: FidelityBondDialogLayoutProps) { - const { t } = useTranslation() - return ( - - - - {title} - {t('earn.fidelity_bond.subtitle')} - - - {currentStep !== undefined && } - - {error && ( - - - {error} - - )} - - {/* negative margin + matching padding keep the scrollbar in the dialog padding, clear of content */} -
{children}
- - {footer && {footer}} -
-
- ) -} diff --git a/src/components/earn/fidelity-bond/FidelityBondDialogParts.tsx b/src/components/earn/fidelity-bond/FidelityBondDialogParts.tsx deleted file mode 100644 index e50493ea..00000000 --- a/src/components/earn/fidelity-bond/FidelityBondDialogParts.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import type { ReactNode } from 'react' -import { CheckCircle2Icon, CheckIcon, CopyIcon, type LucideIcon } from 'lucide-react' -import { useTranslation } from 'react-i18next' -import { toast } from 'sonner' -import { Badge } from '@/components/ui/badge' -import { jarBadgeVariant } from '@/components/ui/badge-variants' -import { buttonVariants } from '@/components/ui/button-variants' -import { Item, ItemTitle, ItemDescription, ItemContent, ItemMedia } from '@/components/ui/item' -import { Address } from '@/components/ui/jam/Address' -import { Balance } from '@/components/ui/jam/Balance' -import { CopyButton } from '@/components/ui/jam/CopyButton' -import { Label } from '@/components/ui/label' -import { Spinner } from '@/components/ui/spinner' -import { Switch } from '@/components/ui/switch' -import { cn } from '@/lib/utils' -import type { AmountSats, JarIndex } from '@/types/global' - -/** icon + title/subtitle block shown at the top of a wizard step */ -export function StepIntro({ icon: Icon, title, subtitle }: { icon: LucideIcon; title: string; subtitle?: string }) { - return ( - - - - - - {title} - {subtitle} - - - ) -} - -/** labeled summary card used on review/confirm steps */ -export function InfoCard({ - label, - highlight = false, - children, -}: { - label: string - highlight?: boolean - children: ReactNode -}) { - return ( -
-

{label}

- {children} -
- ) -} - -export function FidelityBondAmount({ value, className }: { value: AmountSats; className?: string }) { - return -} - -/* TODO: move component to different namespace */ -export function JarBadge({ jarIndex, name }: { jarIndex: JarIndex | undefined; name?: string }) { - const { t } = useTranslation() - return ( - - {name ? ( - <> - {name} #{jarIndex} - - ) : ( - /* TODO: i18n - move key to different namespace */ - t('earn.fidelity_bond.review_inputs.label_jar_n', { jar: jarIndex }) - )} - - ) -} - -export function ConfirmationToggle({ - id, - checked, - onCheckedChange, -}: { - id: string - checked: boolean - onCheckedChange: (checked: boolean) => void -}) { - const { t } = useTranslation() - return ( -
- -
- -

- {t('earn.fidelity_bond.create_form.confirmation_toggle_subtitle')} -

-
-
- ) -} - -/** labeled value with a copy-to-clipboard button, used on success steps */ -export function CopyableField({ - label, - value, - copiedMessage, -}: { - label: string - value: string - copiedMessage: string -}) { - const { t } = useTranslation() - return ( -
- -
- {value} - } - successText={} - className={cn(buttonVariants({ variant: 'outline', size: 'icon' }), 'h-10 w-10 shrink-0')} - onSuccess={() => toast.success(copiedMessage)} - onError={(error) => { - const reason = (error instanceof Error ? error.message : undefined) || t('global.errors.reason_unknown') - toast.error(t('global.errors.error_copy_to_clipboard_failed', { reason })) - }} - /> -
-
- ) -} - -/** labeled read-only address preview, used on confirm steps */ -export function AddressPreview({ label, address }: { label: string; address: string }) { - return ( -
- -
-
-
-
- ) -} - -export function InlineLoading({ text }: { text: string }) { - return ( -
- - {text} -
- ) -} - -/** full-step spinner shown while a transaction is in flight */ -export function PendingStep({ icon: Icon, title, subtitle }: { icon: LucideIcon; title: string; subtitle?: string }) { - return ( -
-
- -
- -
-
-

{title}

- {subtitle &&

{subtitle}

} -
- ) -} - -export function SuccessHeading({ title, subtitle }: { title: string; subtitle?: string }) { - return ( -
-
- -
-

{title}

- {subtitle &&

{subtitle}

} -
- ) -} diff --git a/src/components/earn/fidelity-bond/FidelityBondJarSelector.tsx b/src/components/earn/fidelity-bond/FidelityBondJarSelector.tsx deleted file mode 100644 index db4db5f7..00000000 --- a/src/components/earn/fidelity-bond/FidelityBondJarSelector.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { SelectableJar } from '@/components/ui/jam/SelectableJar' -import { useJamWalletInfoContext, type Jar } from '@/context/JamWalletInfoContext' -import type { JarIndex } from '@/types/global' - -type FidelityBondJarSelectorProps = { - selectedJarIndex: JarIndex | undefined - onSelect: (jarIndex: JarIndex) => void - isJarDisabled: (jar: Jar) => boolean -} - -/** jar selection grid shared by the fidelity bond flows, same look as the send flow's jar selector */ -export function FidelityBondJarSelector({ selectedJarIndex, onSelect, isJarDisabled }: FidelityBondJarSelectorProps) { - const { jars, walletBalanceSummary } = useJamWalletInfoContext() - - return ( -
- {jars.map((jar) => ( - onSelect(jar.jarIndex)} - disabled={isJarDisabled(jar)} - /> - ))} -
- ) -} diff --git a/src/components/earn/fidelity-bond/LockdateSelect.tsx b/src/components/earn/fidelity-bond/LockdateSelect.tsx deleted file mode 100644 index 4dd6f133..00000000 --- a/src/components/earn/fidelity-bond/LockdateSelect.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { useMemo } from 'react' -import { useTranslation } from 'react-i18next' -import { Label } from '@/components/ui/label' -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' -import * as fb from '@/lib/fidelityBondUtils' -import { useDeveloperMode } from '@/store/jamSettingsStore' -import { generateLockdateOptions, getMonthOptions, getYearOptions } from '../CreateFidelityBondDialog/types' - -type LockdateSelectProps = { - /** prefix for the month/year element ids */ - id: string - value: fb.Lockdate | '' - onChange: (value: fb.Lockdate | '') => void - unavailableValues?: readonly fb.Lockdate[] -} - -export function LockdateSelect({ id, value, onChange, unavailableValues = [] }: LockdateSelectProps) { - const { t } = useTranslation() - const { enabled: isDeveloperMode } = useDeveloperMode() - - const lockdateOptions = useMemo(() => generateLockdateOptions(isDeveloperMode), [isDeveloperMode]) - const unavailableSet = useMemo(() => new Set(unavailableValues), [unavailableValues]) - const availableLockdateOptions = useMemo( - () => lockdateOptions.filter((option) => !unavailableSet.has(option.value)), - [lockdateOptions, unavailableSet], - ) - const yearOptions = useMemo(() => getYearOptions(lockdateOptions), [lockdateOptions]) - const monthOptions = useMemo(() => getMonthOptions(), []) - - const selectedYear = value ? value.slice(0, 4) : '' - const selectedMonth = value ? value.slice(5, 7) : '' - - return ( - <> -
-
- - -
-
- - -
-
- - {value && ( -
-

- {t('earn.fidelity_bond.select_date.label_selected_lock_date')} -

-

{fb.lockdate.toDateLabel(value)}

-
- )} - - ) -} diff --git a/src/components/earn/fidelity-bond/StepProgress.tsx b/src/components/earn/fidelity-bond/StepProgress.tsx deleted file mode 100644 index 25125b6f..00000000 --- a/src/components/earn/fidelity-bond/StepProgress.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useTranslation } from 'react-i18next' -import { cn } from '@/lib/utils' - -type StepProgressProps = { - currentStep: number - totalSteps: number -} - -export function StepProgress({ currentStep, totalSteps }: StepProgressProps) { - const { t } = useTranslation() - return ( -
-
- {Array.from({ length: totalSteps }, (_, i) => ( -
- ))} -
-

- {t('global.step_label', { current: currentStep + 1, total: totalSteps })} -

-
- ) -} diff --git a/src/components/earn/fidelity-bond/WizardStepFooter.tsx b/src/components/earn/fidelity-bond/WizardStepFooter.tsx deleted file mode 100644 index f8643ff4..00000000 --- a/src/components/earn/fidelity-bond/WizardStepFooter.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import type { ReactNode } from 'react' -import { ChevronLeftIcon } from 'lucide-react' -import { useTranslation } from 'react-i18next' -import { Button } from '@/components/ui/button' -import { Spinner } from '@/components/ui/spinner' - -type WizardStepFooterProps = { - /** omit to hide the back button (first step) */ - onBack?: () => void - onCancel: () => void - primaryLabel: ReactNode - onPrimary: () => void - primaryDisabled?: boolean - isLoading?: boolean -} - -export function WizardStepFooter({ - onBack, - onCancel, - primaryLabel, - onPrimary, - primaryDisabled = false, - isLoading = false, -}: WizardStepFooterProps) { - const { t } = useTranslation() - return ( - <> - {onBack && ( - - )} - - - - ) -} diff --git a/src/components/earn/fidelity-bond/useFidelityBondMutations.ts b/src/components/earn/fidelity-bond/useFidelityBondMutations.ts deleted file mode 100644 index c47f4d5a..00000000 --- a/src/components/earn/fidelity-bond/useFidelityBondMutations.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { useState } from 'react' -import { directsendMutation, freezeMutation } from '@joinmarket-webui/joinmarket-ng-api-ts/@tanstack/react-query' -import { useMutation } from '@tanstack/react-query' -import { useTranslation } from 'react-i18next' -import { useApiClient } from '@/hooks/useApiClient' -import { getErrorReason } from '@/lib/errorReason' - -/** - * The freeze/unfreeze/direct-send mutations shared by all fidelity bond flows, - * reporting failures through a common error state. The unfreeze/send error - * messages differ per flow (create/renew/move) and are passed as i18n keys. - */ -export function useFidelityBondMutations({ - unfreezeErrorKey, - sendErrorKey, -}: { - unfreezeErrorKey: string - sendErrorKey: string -}) { - const { t } = useTranslation() - const client = useApiClient() - const [error, setError] = useState() - - const setErrorWithReason = (error: unknown, message: string) => - setError(`${message} ${getErrorReason(error, t('global.errors.reason_unknown'))}`) - - const freezeUtxo = useMutation({ - ...freezeMutation({ client }), - retry: false, - onError: (error) => setErrorWithReason(error, t('global.errors.error_freezing_utxos')), - }) - - const unfreezeUtxo = useMutation({ - ...freezeMutation({ client }), - retry: false, - onError: (error) => setErrorWithReason(error, t(unfreezeErrorKey)), - }) - - const directSend = useMutation({ - ...directsendMutation({ client }), - retry: false, - onError: (error) => setErrorWithReason(error, t(sendErrorKey)), - }) - - return { freezeUtxo, unfreezeUtxo, directSend, error, setError } -} diff --git a/src/components/earn/fidelity-bond/useFidelityBondSweep.test.ts b/src/components/earn/fidelity-bond/useFidelityBondSweep.test.ts deleted file mode 100644 index ca985da0..00000000 --- a/src/components/earn/fidelity-bond/useFidelityBondSweep.test.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { renderHook } from '@testing-library/react' -import { beforeEach, describe, expect, it, vi } from 'vitest' -import type { Jar } from '@/context/JamWalletInfoContext' -import type { FidelityBondUtxo, Utxo } from '@/hooks/useQueryUtxos' -import { BALANCE_SUMMARY_EMPTY } from '@/lib/balanceSummary' -import { useFidelityBondSweep } from './useFidelityBondSweep' - -const mocks = vi.hoisted(() => ({ - freezeMutateAsync: vi.fn(), - unfreezeMutateAsync: vi.fn(), - directSendMutateAsync: vi.fn(), - setError: vi.fn(), - walletInfoRefetch: vi.fn(), - walletInfo: { - jars: [] as Jar[], - refetch: vi.fn(), - }, -})) - -// `useFidelityBondSweep` only talks to the network through these two hooks — -// mock at that boundary and let the hook's own orchestration logic run for real. -vi.mock('@tanstack/react-query', () => ({ - useMutation: vi.fn((options: { mutationFn: (variables: unknown) => Promise }) => ({ - mutateAsync: options.mutationFn, - isPending: false, - })), -})) - -vi.mock('./useFidelityBondMutations', () => ({ - useFidelityBondMutations: () => ({ - freezeUtxo: { mutateAsync: mocks.freezeMutateAsync }, - unfreezeUtxo: { mutateAsync: mocks.unfreezeMutateAsync }, - directSend: { mutateAsync: mocks.directSendMutateAsync }, - error: undefined, - setError: mocks.setError, - }), -})) - -vi.mock('@/context/JamWalletInfoContext', async (importOriginal) => ({ - ...(await importOriginal()), - useJamWalletInfoContext: () => mocks.walletInfo, -})) - -vi.mock('@/lib/utils', async (importOriginal) => ({ - ...(await importOriginal()), - delayedPromise: vi.fn(() => Promise.resolve()), -})) - -const utxo = (overrides: Partial): Utxo => ({ - utxo: 'tx:0', - address: 'bcrt1qsource', - path: "m/84'/1'/0'/0/0", - label: '', - value: 100_000, - tries: 0, - tries_remaining: 3, - external: false, - mixdepth: 0, - confirmations: 6, - frozen: false, - locktime: undefined, - ...overrides, -}) - -const bondUtxo = (overrides: Partial): FidelityBondUtxo => ({ - ...utxo({ utxo: 'bond:0', frozen: true, ...overrides }), - locktime: '2999-01-01 00:00:00', -}) - -const jar = (jarIndex: number, utxos: Utxo[]): Jar => - ({ - jarIndex, - name: `Jar ${jarIndex}`, - color: '#808080', - balanceSummary: BALANCE_SUMMARY_EMPTY, - utxos, - }) as unknown as Jar - -describe('useFidelityBondSweep', () => { - beforeEach(() => { - vi.clearAllMocks() - mocks.freezeMutateAsync.mockResolvedValue(undefined) - mocks.unfreezeMutateAsync.mockResolvedValue(undefined) - mocks.walletInfoRefetch.mockResolvedValue(undefined) - mocks.walletInfo.refetch = mocks.walletInfoRefetch - }) - - it('re-freezes the fidelity bond after a failed sweep that had unfrozen it', async () => { - const bond = bondUtxo({ mixdepth: 0 }) - const other = utxo({ utxo: 'other:0', mixdepth: 0, frozen: false }) - mocks.walletInfo.jars = [jar(0, [bond, other])] - mocks.directSendMutateAsync.mockRejectedValue(new Error('broadcast failed')) - - const { result } = renderHook(() => - useFidelityBondSweep({ - walletFileName: 'wallet.jmdat', - utxo: bond, - unfreezeErrorKey: 'earn.fidelity_bond.error_unfreezing_utxos', - sendErrorKey: 'earn.fidelity_bond.renew.error_renewing_fidelity_bond', - }), - ) - - const txResult = await result.current.sweep({ - destination: 'bcrt1qdestination', - tryFreezeAfterBroadcast: false, - }) - - expect(txResult).toBeUndefined() - - // the other jar utxo was frozen then correctly rolled back - expect(mocks.freezeMutateAsync).toHaveBeenCalledWith({ - path: { walletname: 'wallet.jmdat' }, - body: { 'utxo-string': 'other:0', freeze: true }, - }) - expect(mocks.unfreezeMutateAsync).toHaveBeenCalledWith( - expect.objectContaining({ body: { 'utxo-string': 'other:0', freeze: false } }), - ) - - // the bond itself was unfrozen before the failed send, and MUST be re-frozen in rollback - expect(mocks.unfreezeMutateAsync).toHaveBeenCalledWith({ - path: { walletname: 'wallet.jmdat' }, - body: { 'utxo-string': 'bond:0', freeze: false }, - }) - expect(mocks.freezeMutateAsync).toHaveBeenCalledWith( - expect.objectContaining({ body: { 'utxo-string': 'bond:0', freeze: true } }), - ) - }) - - it('does not attempt to re-freeze the bond on failure when it was never unfrozen', async () => { - const bond = bondUtxo({ mixdepth: 0, frozen: false }) - mocks.walletInfo.jars = [jar(0, [bond])] - mocks.directSendMutateAsync.mockRejectedValue(new Error('broadcast failed')) - - const { result } = renderHook(() => - useFidelityBondSweep({ - walletFileName: 'wallet.jmdat', - utxo: bond, - unfreezeErrorKey: 'earn.fidelity_bond.error_unfreezing_utxos', - sendErrorKey: 'earn.fidelity_bond.renew.error_renewing_fidelity_bond', - }), - ) - - await result.current.sweep({ destination: 'bcrt1qdestination', tryFreezeAfterBroadcast: false }) - - expect(mocks.unfreezeMutateAsync).not.toHaveBeenCalled() - expect(mocks.freezeMutateAsync).not.toHaveBeenCalledWith( - expect.objectContaining({ body: { 'utxo-string': 'bond:0', freeze: true } }), - ) - }) - - it('sweeps successfully: freezes other utxos, unfreezes the bond, then restores the others', async () => { - const bond = bondUtxo({ mixdepth: 0 }) - const other = utxo({ utxo: 'other:0', mixdepth: 0, frozen: false }) - mocks.walletInfo.jars = [jar(0, [bond, other])] - mocks.directSendMutateAsync.mockResolvedValue({ txinfo: { txid: 'renewed-tx' } }) - - const { result } = renderHook(() => - useFidelityBondSweep({ - walletFileName: 'wallet.jmdat', - utxo: bond, - unfreezeErrorKey: 'earn.fidelity_bond.error_unfreezing_utxos', - sendErrorKey: 'earn.fidelity_bond.renew.error_renewing_fidelity_bond', - }), - ) - - const txResult = await result.current.sweep({ - destination: 'bcrt1qdestination', - tryFreezeAfterBroadcast: false, - }) - - expect(txResult).toEqual({ txinfo: { txid: 'renewed-tx' } }) - expect(mocks.directSendMutateAsync).toHaveBeenCalledWith({ - path: { walletname: 'wallet.jmdat' }, - body: { mixdepth: 0, amount_sats: 0, destination: 'bcrt1qdestination' }, - }) - // the other utxo ends up unfrozen again post-broadcast - expect(mocks.unfreezeMutateAsync).toHaveBeenCalledWith( - expect.objectContaining({ body: { 'utxo-string': 'other:0', freeze: false } }), - ) - expect(mocks.walletInfoRefetch).toHaveBeenCalled() - }) - - it('does not re-freeze the bond if the sweep broadcast but the refetch after it fails', async () => { - const bond = bondUtxo({ mixdepth: 0 }) - mocks.walletInfo.jars = [jar(0, [bond])] - mocks.directSendMutateAsync.mockResolvedValue({ txinfo: { txid: 'renewed-tx' } }) - mocks.walletInfoRefetch.mockRejectedValue(new Error('refetch failed')) - - const { result } = renderHook(() => - useFidelityBondSweep({ - walletFileName: 'wallet.jmdat', - utxo: bond, - unfreezeErrorKey: 'earn.fidelity_bond.error_unfreezing_utxos', - sendErrorKey: 'earn.fidelity_bond.renew.error_renewing_fidelity_bond', - }), - ) - - const txResult = await result.current.sweep({ - destination: 'bcrt1qdestination', - tryFreezeAfterBroadcast: false, - }) - - expect(txResult).toEqual({ txinfo: { txid: 'renewed-tx' } }) - expect(mocks.freezeMutateAsync).not.toHaveBeenCalledWith( - expect.objectContaining({ body: { 'utxo-string': 'bond:0', freeze: true } }), - ) - }) -}) diff --git a/src/components/earn/fidelity-bond/useFidelityBondSweep.ts b/src/components/earn/fidelity-bond/useFidelityBondSweep.ts deleted file mode 100644 index 80c877e8..00000000 --- a/src/components/earn/fidelity-bond/useFidelityBondSweep.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { useMemo } from 'react' -import type { DirectSendResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' -import { useMutation } from '@tanstack/react-query' -import { JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS_DELAY } from '@/constants/jam' -import { useJamWalletInfoContext } from '@/context/JamWalletInfoContext' -import type { FidelityBondUtxo, Utxo } from '@/hooks/useQueryUtxos' -import { delayedPromise, type WalletFileName } from '@/lib/utils' -import { useFidelityBondMutations } from './useFidelityBondMutations' - -/** - * Sweeps a fidelity bond UTXO to a destination address: freezes all other - * UTXOs in the source jar, unfreezes the bond if needed, direct-sends the - * whole jar balance, then restores the frozen UTXOs. Shared by the renew - * and move-to-jar flows. - */ -export function useFidelityBondSweep({ - walletFileName, - utxo, - unfreezeErrorKey, - sendErrorKey, -}: { - walletFileName: WalletFileName - utxo: FidelityBondUtxo - unfreezeErrorKey: string - sendErrorKey: string -}) { - const { jars, refetch: walletInfoRefetch } = useJamWalletInfoContext() - const { freezeUtxo, unfreezeUtxo, directSend, error, setError } = useFidelityBondMutations({ - unfreezeErrorKey, - sendErrorKey, - }) - - const sourceJar = jars.find((jar) => jar.jarIndex === utxo.mixdepth) - - // UTXOs in the source jar that are NOT this FB — they need to be frozen during sweep - const utxosToFreeze = useMemo(() => { - if (!sourceJar) return [] - return sourceJar.utxos.filter((u) => u.utxo !== utxo.utxo && !u.frozen) - }, [sourceJar, utxo.utxo]) - - /** - * Runs the sweep. `onBroadcast` fires as soon as the transaction is sent, - * before the frozen UTXOs are restored. Returns false when the sweep failed - * (after a best-effort rollback). - */ - const { isPending, mutateAsync: sweep } = useMutation({ - mutationFn: async ({ - destination, - tryFreezeAfterBroadcast, - onBroadcastSuccess, - }: { - destination: string - tryFreezeAfterBroadcast: boolean - onBroadcastSuccess?: (result: DirectSendResponse) => Promise - }): Promise => { - setError(undefined) - - const frozen: Utxo[] = [] - let bondWasUnfrozen = false - let sweepBroadcasted = false - - try { - // Freeze other UTXOs in the source jar so only the FB gets swept - for (const u of utxosToFreeze) { - await freezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': u.utxo, freeze: true }, - }) - frozen.push(u) - } - - if (utxo.frozen) { - await unfreezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': utxo.utxo, freeze: false }, - }) - bondWasUnfrozen = true - } - - const result = await directSend.mutateAsync({ - path: { walletname: walletFileName }, - body: { - mixdepth: utxo.mixdepth, - amount_sats: 0, // 0 := sweep! - destination, - }, - }) - sweepBroadcasted = true - - // Best-effort cleanup — tx already broadcast, don't throw on unfreeze failure - for (const u of frozen) { - try { - await unfreezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': u.utxo, freeze: false }, - throwOnError: true, - }) - } catch (_ignoredOnPurpose: unknown) { - // only debug output - console.debug('Error while unfreezing previously frozen UTXO.') - } - } - - if (tryFreezeAfterBroadcast) { - try { - await delayedPromise(JAM_TRY_FREEZE_CREATED_FIDELITY_BOND_OUTPUTS_DELAY) - - const fbUtxoId = `${result.txinfo.txid}:0` // sent with a sweep, so it is a single output - await freezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': fbUtxoId, freeze: true }, - throwOnError: true, - }) - } catch (_ignoredOnPurpose: unknown) { - console.warn('Error while freezing Fidelity Bond UTXO - continuing.') - } - } - - try { - await onBroadcastSuccess?.(result) - } catch (error: unknown) { - console.warn('onBroadcastSuccess failed', error) - } - - return result - } catch (_ignoredOnPurpose: unknown) { - // Best-effort rollback — unfreeze UTXOs that were frozen before the error - for (const u of frozen) { - try { - await unfreezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': u.utxo, freeze: false }, - throwOnError: true, - }) - } catch (_ignoredOnPurpose: unknown) { - // only debug output - console.debug('Error while unfreezing previously frozen UTXO in error handling.') - } - } - - // re-freeze the bond if it was unfrozen before the error. skip once the - // sweep already broadcast, the bond utxo is spent by then - if (bondWasUnfrozen && !sweepBroadcasted) { - try { - await freezeUtxo.mutateAsync({ - path: { walletname: walletFileName }, - body: { 'utxo-string': utxo.utxo, freeze: true }, - throwOnError: true, - }) - } catch (_ignoredOnPurpose: unknown) { - console.debug('Error while re-freezing fidelity bond UTXO in error handling.') - } - } - - return undefined - } finally { - // refetch only if the sweep broadcast, and don't let a refetch error - // get treated as a sweep failure - if (sweepBroadcasted) { - try { - await walletInfoRefetch() - } catch (error: unknown) { - console.warn('Error while refetching wallet info after sweep.', error) - } - } - } - }, - retry: false, - }) - - return { sweep, isLoading: isPending, error, setError, sourceJar } -} diff --git a/src/components/earn/report/EarnReportContent.test.tsx b/src/components/earn/report/EarnReportContent.test.tsx index 11955426..4ebb14e0 100644 --- a/src/components/earn/report/EarnReportContent.test.tsx +++ b/src/components/earn/report/EarnReportContent.test.tsx @@ -118,49 +118,24 @@ describe('EarnReportContent', () => { vi.restoreAllMocks() }) - it('renders loading and report states', () => { + it('renders loading and empty report states', () => { mocks.isLoading = true - mocks.isRefetching = false - mocks.entries = [] const { rerender } = render() expect(screen.getByText('spinner')).toBeInTheDocument() - expect(screen.queryByRole('button', { name: 'global.refresh' })).not.toBeInTheDocument() - expect(screen.queryByRole('button', { name: 'global.download' })).not.toBeInTheDocument() mocks.isLoading = false - mocks.isRefetching = true mocks.entries = [] rerender() expect(screen.getByText('earn.alert_empty_report')).toBeInTheDocument() - expect(screen.getByRole('button', { name: 'global.refresh' })).toBeDisabled() - expect(screen.getByRole('button', { name: 'global.download' })).toBeDisabled() - - mocks.isLoading = false - mocks.isRefetching = false - mocks.entries = [] - rerender() - - expect(screen.queryByText('earn.alert_empty_report')).toBeInTheDocument() - expect(screen.getByRole('button', { name: 'global.refresh' })).toBeEnabled() - expect(screen.getByRole('button', { name: 'global.download' })).toBeDisabled() - - mocks.isLoading = false - mocks.isRefetching = false - mocks.entries = [entry({ earnedAmount: 100, notes: 'first maker note' })] - rerender() - - expect(screen.queryByText('earn.alert_empty_report')).not.toBeInTheDocument() - expect(screen.getByRole('button', { name: 'global.refresh' })).toBeEnabled() - expect(screen.getByRole('button', { name: 'global.download' })).toBeEnabled() + expect(screen.getByRole('button', { name: /earn\.report\.text_button_download_csv/u })).toBeDisabled() }) it('summarizes, filters, refreshes, paginates, and exports report rows', async () => { const anchorClick = vi.fn() const createElement = vi.spyOn(document, 'createElement') createElement.mockImplementation((tagName: string) => { - // eslint-disable-next-line unicorn/prefer-https -- XHTML namespace URI is an identifier that must be http const element = document.createElementNS('http://www.w3.org/1999/xhtml', tagName) if (tagName === 'a') { Object.defineProperty(element, 'click', { @@ -176,78 +151,37 @@ describe('EarnReportContent', () => { expect(screen.getByText('chart:3')).toBeInTheDocument() expect(screen.getByText('balance:600')).toBeInTheDocument() expect(screen.getAllByText('balance:300').length).toBeGreaterThan(0) - expect(screen.getByText('earn.report.text_report_summary:{"count":3}')).toBeInTheDocument() - expect(screen.queryByText(/earn\.report\.text_report_summary_filtered:/u)).not.toBeInTheDocument() + expect(screen.getByText(/earn\.report\.text_report_summary:\{"count":3\}/u)).toBeInTheDocument() expect(screen.getByText('first maker note')).toBeInTheDocument() fireEvent.change(screen.getByPlaceholderText('earn.report.placeholder_search'), { target: { value: 'second' }, }) - - expect(screen.queryByText(/earn\.report\.text_report_summary:/u)).not.toBeInTheDocument() - expect(screen.getByText('earn.report.text_report_summary_filtered:{"count":1}')).toBeInTheDocument() + expect(screen.getByText(/earn\.report\.text_report_summary_filtered/u)).toBeInTheDocument() expect(screen.queryByText('first maker note')).not.toBeInTheDocument() expect(screen.getByText('second maker note')).toBeInTheDocument() - const downloadButton = screen.getByRole('button', { name: 'global.download' }) - expect(downloadButton).toBeEnabled() - - fireEvent.click(downloadButton) + fireEvent.click(screen.getByRole('button', { name: /earn\.report\.text_button_download_csv/u })) expect(mocks.createObjectURL).toHaveBeenCalled() expect(anchorClick).toHaveBeenCalled() fireEvent.click(screen.getByRole('button', { name: 'first-page' })) fireEvent.click(screen.getByRole('button', { name: 'show-all' })) fireEvent.click(screen.getByRole('button', { name: 'show-page-size' })) - - const refreshButton = screen.getByRole('button', { name: 'global.refresh' }) - expect(refreshButton).toBeEnabled() - - fireEvent.click(refreshButton) + fireEvent.click(screen.getByRole('button', { name: '' })) await waitFor(() => expect(mocks.refetch).toHaveBeenCalled()) createElement.mockRestore() }) - it('exports all filtered rows regardless of pagination', async () => { - mocks.entries = Array.from({ length: 30 }, (_, index) => - entry({ - notes: `maker note ${index + 1}`, - timestamp: new Date(Date.UTC(2026, 0, index + 1, 12)), - }), - ) - - render() - - expect(screen.getByText('pagination:30')).toBeInTheDocument() - expect(screen.getAllByText(/maker note/u)).toHaveLength(25) - - fireEvent.click(screen.getByRole('button', { name: 'global.download' })) - - const blob = mocks.createObjectURL.mock.calls[0]?.[0] - expect(blob).toBeInstanceOf(Blob) - if (!blob) { - throw new Error('CSV blob was not created') - } - - const csv = await blob.text() - const lines = csv.trim().split('\n') - - expect(lines).toHaveLength(31) - expect(lines[1]).toContain('2026-01-30T12:00:00.000Z') - expect(lines.at(-1)).toContain('2026-01-01T12:00:00.000Z') - }) - it('adds demo rows in developer mode', () => { mocks.developerMode = true render() - expect(screen.getByText('dev-badge')).toBeInTheDocument() - expect(screen.getByText('earn.report.text_report_summary:{"count":3}')).toBeInTheDocument() - fireEvent.click(screen.getByRole('button', { name: /earn\.report\.text_button_generate_demo_report/u })) - expect(screen.getByText('earn.report.text_report_summary:{"count":4}')).toBeInTheDocument() + expect(screen.getByText('dev-badge')).toBeInTheDocument() + expect(screen.getByText(/earn\.report\.text_report_summary:\{"count":4\}/u)).toBeInTheDocument() }) }) diff --git a/src/components/earn/report/EarnReportContent.tsx b/src/components/earn/report/EarnReportContent.tsx index 6e6cf12b..7902de48 100644 --- a/src/components/earn/report/EarnReportContent.tsx +++ b/src/components/earn/report/EarnReportContent.tsx @@ -11,14 +11,14 @@ import { type SortingState, useReactTable, } from '@tanstack/react-table' -import { DownloadIcon, PlusIcon, RefreshCwIcon, SearchIcon, XIcon } from 'lucide-react' +import { DownloadIcon, PlusIcon, RefreshCwIcon, SearchIcon } from 'lucide-react' import { useTranslation } from 'react-i18next' import { DevBadge } from '@/components/dev/DevBadge' import { useQueryYieldgenReport, type EarnReportEntry } from '@/components/earn/report/hooks/useQueryYieldgenReport' import { Alert, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' -import { InputGroup, InputGroupAddon, InputGroupInput } from '@/components/ui/input-group' +import { Input } from '@/components/ui/input' import { Balance } from '@/components/ui/jam/Balance' import { SortIcon } from '@/components/ui/jam/SortIcon' import { TablePagination } from '@/components/ui/jam/TablePagination' @@ -144,11 +144,11 @@ export const EarnReportContent = ({ className, enabled }: EarnReportContentProps }, [isShowAll, allEntries.length, table]) const visibleRows = table.getRowModel().rows - const exportRows = table.getSortedRowModel().rows + // Export visible entries as CSV const downloadCsv = useCallback(() => { const header = 'timestamp,cj_amount,input_count,input_amount,fee,earned,confirm_minutes,notes' - const rows = exportRows.map((row) => + const rows = visibleRows.map((row) => [ row.original.timestamp.toISOString(), row.original.cjTotalAmount ?? '', @@ -170,7 +170,7 @@ export const EarnReportContent = ({ className, enabled }: EarnReportContentProps setTimeout(() => { URL.revokeObjectURL(url) }, 0) - }, [exportRows]) + }, [visibleRows]) const earnedTotal = useMemo(() => sumEarned(allEntries, BITCOIN_GENESIS_DATE), [allEntries]) @@ -180,7 +180,7 @@ export const EarnReportContent = ({ className, enabled }: EarnReportContentProps const earned24Hours = useMemo(() => sumEarned(allEntries, new Date(now - MILLISECONDS_IN_A_DAY)), [allEntries, now]) return ( -
+
{isLoading ? (
@@ -188,7 +188,7 @@ export const EarnReportContent = ({ className, enabled }: EarnReportContentProps ) : (
{/* Stats row */} -
+
{( [ { label: t('earn.report.stats.earned_total'), value: earnedTotal }, @@ -212,46 +212,23 @@ export const EarnReportContent = ({ className, enabled }: EarnReportContentProps {/* Toolbar: search + refresh */} -
-
- - table.setGlobalFilter(event.target.value)} - placeholder={t('earn.report.placeholder_search')} - /> - - - - - - - - - - +
+
+ + table.setGlobalFilter(event.target.value)} + className="pl-8" + />
+ + {globalFilter === '' @@ -259,7 +236,7 @@ export const EarnReportContent = ({ className, enabled }: EarnReportContentProps : t('earn.report.text_report_summary_filtered', { count: table.getFilteredRowModel().rows.length })} {isDeveloperMode ? ( -
{stacktrace && (
{t('error_page.heading_stacktrace')}
-
+          
             {stacktrace}
           
diff --git a/src/components/import/ImportDetailsForm.test.tsx b/src/components/import/ImportDetailsForm.test.tsx index 1dd18e8b..f6ca64c5 100644 --- a/src/components/import/ImportDetailsForm.test.tsx +++ b/src/components/import/ImportDetailsForm.test.tsx @@ -1,11 +1,7 @@ import type { ReactNode } from 'react' -import type { SessionResponse } from '@joinmarket-webui/joinmarket-ng-api-ts/jm' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import { DUMMY_SEED_PHRASE, pseudoRandomInteger } from '@/lib/utils' import { flushActUpdates } from '@/test/flushActUpdates' -import { withRuntimeLocale } from '@/test/withRuntimeLocale' -import type { BlockHeight } from '@/types/global' import { ImportDetailsForm } from './ImportDetailsForm' vi.mock('react-i18next', () => ({ @@ -14,6 +10,8 @@ vi.mock('react-i18next', () => ({ }), })) +vi.mock('../dev/DevBadge', () => ({ DevBadge: () => })) + vi.mock('../ui/accordion', () => ({ Accordion: ({ children }: { children?: ReactNode }) =>
{children}
, AccordionItem: ({ children }: { children?: ReactNode }) =>
{children}
, @@ -21,79 +19,95 @@ vi.mock('../ui/accordion', () => ({ AccordionContent: ({ children }: { children?: ReactNode }) =>
{children}
, })) -const VALID_MNEMONIC = DUMMY_SEED_PHRASE.join(' ') +vi.mock('../ui/alert', () => ({ + Alert: ({ children, variant }: { children?: ReactNode; variant?: string }) => ( +
{children}
+ ), + AlertDescription: ({ children }: { children?: ReactNode }) =>
{children}
, + AlertTitle: ({ children }: { children?: ReactNode }) =>
{children}
, +})) + +vi.mock('@/components/ui/field', () => ({ + Field: ({ children }: { children?: ReactNode }) =>
{children}
, + FieldDescription: ({ children }: { children?: ReactNode }) =>
{children}
, + FieldLabel: ({ children }: { children?: ReactNode }) => , +})) + +vi.mock('../ui/input-group', () => ({ + InputGroup: ({ children }: { children?: ReactNode }) =>
{children}
, + InputGroupAddon: ({ children }: { children?: ReactNode }) =>
{children}
, + InputGroupInput: (props: Record) => , +})) + +vi.mock('../ui/textarea', () => ({ + Textarea: (props: Record) =>