diff --git a/.eslintrc b/.eslintrc index 4c08ec30..31bbc5d7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -37,7 +37,6 @@ ], "plugins": ["react-hooks", "prettier", "import", "sort-exports"], "rules": { - "sort-exports/sort-exports": "error", "sort-imports": [ "error", { diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml index 4a1cbc3e..37b21ef3 100644 --- a/.github/workflows/run-merge-e2e-tests.yml +++ b/.github/workflows/run-merge-e2e-tests.yml @@ -4,21 +4,8 @@ on: branches: [main] workflow_dispatch: jobs: - Slack-Notification: - runs-on: runner-dapp - steps: - - name: Slack Notification - uses: rtCamp/action-slack-notify@master - env: - if: always() - SLACK_ICON_EMOJI: ':robot_face:' - SLACK_USERNAME: Playwright Bot - SLACK_MESSAGE: E2E merge tests are now running. A new notification will be sent when completed. - SLACK_TITLE : 'Playwright E2E Template RUN' - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} E2E-RUN: runs-on: runner-dapp - needs: Slack-Notification env: KEYSTORE1_JSON_B64: ${{ secrets.KEYSTORE1_JSON_B64 }} KEYSTORE1_PASSWORD: ${{ secrets.KEYSTORE1_PASSWORD }} @@ -41,6 +28,10 @@ jobs: KEYSTORE6_PRIVATE_KEY_UTF8: ${{ secrets.KEYSTORE6_PRIVATE_KEY_UTF8 }} KEYSTORE6_ADDRESS: ${{ secrets.KEYSTORE6_ADDRESS }} + + METAMASK_MNEMONIC: ${{ secrets.METAMASK_MNEMONIC }} + METAMASK_ADDRESS: ${{ secrets.METAMASK_ADDRESS }} + METAMASK_PASSWORD: ${{ secrets.METAMASK_PASSWORD }} steps: - name: Checkout uses: actions/checkout@v4 @@ -60,7 +51,7 @@ jobs: - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps - name: Run Playwright E2E Tests - run: pnpm run run-playwright-test + run: xvfb-run pnpm run run-playwright-test - name: Upload Playwright test report uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} @@ -72,18 +63,18 @@ jobs: uses: rtCamp/action-slack-notify@master if: success() env: - SLACK_ICON_EMOJI: ':white_check_mark:' + SLACK_ICON_EMOJI: ':robot_face:' SLACK_USERNAME: Playwright Bot - SLACK_MESSAGE: 'E2E merge Tests completed successfully! All tests passed. πŸ“Š Test Report: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + SLACK_MESSAGE: 'E2E merge Tests completed successfully!' SLACK_TITLE: 'Playwright E2E Tests - SUCCESS' SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - name: Slack Failure Notification uses: rtCamp/action-slack-notify@master if: failure() env: - SLACK_ICON_EMOJI: ':red_circle:' + SLACK_ICON_EMOJI: ':robot_face:' SLACK_USERNAME: Playwright Bot - SLACK_MESSAGE: 'E2E merge Tests failed. Please check the logs for details. πŸ“Š Test Report: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + SLACK_MESSAGE: 'E2E merge Tests failed!' SLACK_TITLE: 'Playwright E2E Tests - FAILED' SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/run-night-e2e-tests.yml b/.github/workflows/run-night-e2e-tests.yml index d8d612f7..a0a5e677 100644 --- a/.github/workflows/run-night-e2e-tests.yml +++ b/.github/workflows/run-night-e2e-tests.yml @@ -4,21 +4,8 @@ on: - cron: '0 20 * * *' workflow_dispatch: jobs: - Slack-Notification: - runs-on: runner-dapp - steps: - - name: Slack Notification - uses: rtCamp/action-slack-notify@master - env: - if: always() - SLACK_ICON_EMOJI: ':robot_face:' - SLACK_USERNAME: Playwright Bot - SLACK_MESSAGE: E2E night tests are now running. A new notification will be sent when completed. - SLACK_TITLE : 'Playwright E2E Template RUN' - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} E2E-RUN: runs-on: runner-dapp - needs: Slack-Notification env: KEYSTORE1_JSON_B64: ${{ secrets.KEYSTORE1_JSON_B64 }} KEYSTORE1_PASSWORD: ${{ secrets.KEYSTORE1_PASSWORD }} @@ -41,6 +28,10 @@ jobs: KEYSTORE6_PRIVATE_KEY_UTF8: ${{ secrets.KEYSTORE6_PRIVATE_KEY_UTF8 }} KEYSTORE6_ADDRESS: ${{ secrets.KEYSTORE6_ADDRESS }} + + METAMASK_MNEMONIC: ${{ secrets.METAMASK_MNEMONIC }} + METAMASK_ADDRESS: ${{ secrets.METAMASK_ADDRESS }} + METAMASK_PASSWORD: ${{ secrets.METAMASK_PASSWORD }} steps: - name: Checkout uses: actions/checkout@v4 @@ -60,7 +51,8 @@ jobs: - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps - name: Run Playwright E2E Tests - run: pnpm run run-playwright-test + working-directory: tests + run: xvfb-run pnpm run run-playwright-test - name: Upload Playwright test report uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} @@ -72,17 +64,17 @@ jobs: uses: rtCamp/action-slack-notify@master if: success() env: - SLACK_ICON_EMOJI: ':white_check_mark:' + SLACK_ICON_EMOJI: ':robot_face:' SLACK_USERNAME: Playwright Bot - SLACK_MESSAGE: 'E2E Night Tests completed successfully! All tests passed. πŸ“Š Test Report: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + SLACK_MESSAGE: 'E2E Night Tests completed successfully!' SLACK_TITLE: 'Playwright E2E Tests - SUCCESS' SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - name: Slack Failure Notification uses: rtCamp/action-slack-notify@master if: failure() env: - SLACK_ICON_EMOJI: ':x:' + SLACK_ICON_EMOJI: ':robot_face:' SLACK_USERNAME: Playwright Bot - SLACK_MESSAGE: 'E2E Night Tests failed. Please check the logs for details. πŸ“Š Test Report: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' + SLACK_MESSAGE: 'E2E Night Tests failed!' SLACK_TITLE: 'Playwright E2E Tests - FAILED' SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index f797e8c0..2844053d 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ node_modules/ /playwright/.cache/ /certificates/ /temps/ - +.cache + # secrets (local only) tests/support/wallets/ \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 605f87f5..e6f87062 100644 --- a/jest.config.js +++ b/jest.config.js @@ -15,9 +15,7 @@ module.exports = { }, transformIgnorePatterns: ['node_modules/(^.+\\\\.(ts|js)$)'], testMatch: ['**/src/**/?(*.)+(spec|test|bgTest).ts?(x)'], - moduleNameMapper: { - '\\.(css|sass|scss)$': 'identity-obj-proxy' - }, + moduleFileExtensions: [ // Place tsx and ts to beginning as suggestion from Jest team // https://jestjs.io/docs/configuration#modulefileextensions-arraystring @@ -25,6 +23,9 @@ module.exports = { 'ts', 'web.js', 'js', + 'jsx', + 'cjs', + 'mjs', 'web.ts', 'web.tsx', 'json', diff --git a/package.json b/package.json index 8ee8ab56..4e55cc7c 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "axios": "1.10.0", "bignumber.js": "^9.x", "classnames": "2.3.2", - "moment": "2.29.4", + "luxon": "3.5.0", "motion": "^12.23.12", "protobufjs": "^7.5.3", "react": "18.2.0", @@ -40,8 +40,7 @@ "copy-mainnet-config": "cp ./src/config/config.mainnet.ts ./src/config/index.ts", "test": "jest", "run-playwright-test": "playwright test", - "run-playwright-test-ui": "playwright test --ui", - "run-playwright-test-grep": "playwright test --grep \"$npm_config_grep\"" + "run-playwright-test-ui": "playwright test --ui" }, "browserslist": [ ">0.2%", @@ -58,7 +57,9 @@ "@testing-library/jest-dom": "6.1.3", "@testing-library/react": "14.0.0", "@testing-library/user-event": "14.5.1", + "@types/fs-extra": "11.0.4", "@types/jest": "29.5.5", + "@types/luxon": "3.4.2", "@types/node": "20.7.1", "@types/react": "18.2.23", "@types/react-dom": "^19.1.7", diff --git a/playwright.config.ts b/playwright.config.ts index 2f7c4a74..9448c948 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,7 +10,7 @@ import { TEST_CONFIG } from './tests/config'; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - globalSetup: './tests/support/globalSetup.ts', + globalSetup: './tests/support/template/globalSetup.ts', /* timeout for each test */ timeout: TEST_CONFIG.timeout, /* timeout for locators */ @@ -54,14 +54,22 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'], launchOptions: { - args: ['--start-maximized'] + args: [ + '--start-maximized', + '--disable-web-security', + '--disable-features=VizDisplayCompositor' + ] } } } ], webServer: { command: 'pnpm run start-devnet', + url: 'https://localhost:3000', timeout: 120 * 1000, - reuseExistingServer: !process.env.CI + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + stderr: 'pipe', + ignoreHTTPSErrors: true } }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 165e2c93..42ca3b6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,16 +28,16 @@ importers: version: 0.2.0(@fortawesome/fontawesome-svg-core@6.5.1)(react@18.2.0) '@multiversx/sdk-core': specifier: ^15.x - version: 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + version: 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) '@multiversx/sdk-dapp': specifier: ^5.x - version: 5.2.6(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-dapp-utils@3.0.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1))(@types/react@18.2.23)(axios@1.10.0)(bignumber.js@9.3.1)(protobufjs@7.5.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2) + version: 5.2.13(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-dapp-utils@3.0.2(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1))(@types/react@18.2.23)(axios@1.10.0)(bignumber.js@9.3.1)(protobufjs@7.5.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2)(zod@3.22.4) '@multiversx/sdk-dapp-ui': specifier: ^0.x - version: 0.0.35(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 0.1.1(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@multiversx/sdk-dapp-utils': specifier: ^3.x - version: 3.0.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1) + version: 3.0.2(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1) axios: specifier: 1.10.0 version: 1.10.0 @@ -47,12 +47,12 @@ importers: classnames: specifier: 2.3.2 version: 2.3.2 - moment: - specifier: 2.29.4 - version: 2.29.4 + luxon: + specifier: 3.5.0 + version: 3.5.0 motion: specifier: ^12.23.12 - version: 12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0) protobufjs: specifier: ^7.5.3 version: 7.5.4 @@ -64,13 +64,13 @@ importers: version: 18.2.0(react@18.2.0) react-modal-sheet: specifier: ^4.4.0 - version: 4.4.0(motion@12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0) + version: 4.4.0(motion@12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0) react-router-dom: specifier: 6.16.0 version: 6.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-tooltip: specifier: ^5.28.0 - version: 5.29.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 5.30.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) devDependencies: '@playwright/test': specifier: 1.49.1 @@ -99,9 +99,15 @@ importers: '@testing-library/user-event': specifier: 14.5.1 version: 14.5.1(@testing-library/dom@9.3.4) + '@types/fs-extra': + specifier: 11.0.4 + version: 11.0.4 '@types/jest': specifier: 29.5.5 version: 29.5.5 + '@types/luxon': + specifier: 3.4.2 + version: 3.4.2 '@types/node': specifier: 20.7.1 version: 20.7.1 @@ -110,7 +116,7 @@ importers: version: 18.2.23 '@types/react-dom': specifier: ^19.1.7 - version: 19.2.0(@types/react@18.2.23) + version: 19.2.2(@types/react@18.2.23) '@types/react-router-dom': specifier: 5.3.3 version: 5.3.3 @@ -197,7 +203,7 @@ importers: version: 4.0.15 ts-jest: specifier: 29.1.1 - version: 29.1.1(@babel/core@7.28.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest@29.7.0(@types/node@20.7.1)(ts-node@10.9.2(@swc/core@1.3.90)(@types/node@20.7.1)(typescript@5.2.2)))(typescript@5.2.2) + version: 29.1.1(@babel/core@7.28.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest@29.7.0(@types/node@20.7.1)(ts-node@10.9.2(@swc/core@1.3.90)(@types/node@20.7.1)(typescript@5.2.2)))(typescript@5.2.2) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.3.90)(@types/node@20.7.1)(typescript@5.2.2) @@ -209,10 +215,10 @@ importers: version: 4.4.9(@types/node@20.7.1)(lightningcss@1.30.1) vite-plugin-node-polyfills: specifier: 0.14.1 - version: 0.14.1(rollup@3.29.5)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)) + version: 0.14.1(rollup@4.52.5)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)) vite-plugin-svgr: specifier: 4.0.0 - version: 4.0.0(rollup@3.29.5)(typescript@5.2.2)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)) + version: 4.0.0(rollup@4.52.5)(typescript@5.2.2)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)) vite-tsconfig-paths: specifier: 4.2.1 version: 4.2.1(typescript@5.2.2)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)) @@ -237,16 +243,16 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.4': - resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.27.2': @@ -275,8 +281,8 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.27.1': @@ -287,8 +293,8 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -403,12 +409,12 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -559,8 +565,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/eslintrc@2.1.4': @@ -783,14 +789,14 @@ packages: resolution: {integrity: sha512-c0tIdQUnbBLSt6NYU+OpeGPYdL0+GV547HeHT8Xc0BKQ7Cj0v82QUoA2QRtWrR1G4MNZmLsIacZSsf6DrIS2Bw==} engines: {node: '>=8.9.0'} - '@multiversx/sdk-core@15.2.0': - resolution: {integrity: sha512-Qqcrs52ujsg+xFd2TdWKHx6ueL+mQTY/nxxW7MdemBGB8wNpmLWxNE34zbLmzkWauOQopThq573QgO7IOv3iGg==} + '@multiversx/sdk-core@15.3.0': + resolution: {integrity: sha512-A//LW0QlRHO2hVDdDchzYdOotqyBfjmU2/TFrR2bHCZB/YA9SR4xq0lYtg5bLO8fRhw9qdzccF/CLHQte6Tecg==} peerDependencies: bignumber.js: ^9.0.1 protobufjs: ^7.2.6 - '@multiversx/sdk-dapp-ui@0.0.35': - resolution: {integrity: sha512-b56hPvnKCsorz27y9jFgN2+a1En2ut+pRkE1noDEfPk9wQuKfv1NOsT3SVBP149COknnfFP2hzWlJ8ddWzEKKQ==} + '@multiversx/sdk-dapp-ui@0.1.1': + resolution: {integrity: sha512-LaZqqfeD/ojcjm2Z2XYcfThoM4B9HoNEMJ5TN5F3yU7sblS85scA5Aa4xkRf5ZrQAfOBp8JUvSIisloKMO8k7g==} engines: {node: '>=20.19.0'} '@multiversx/sdk-dapp-utils@3.0.2': @@ -799,8 +805,8 @@ packages: '@multiversx/sdk-core': ^14.0.0 || ^15.0.0 bignumber.js: ^9.x - '@multiversx/sdk-dapp@5.2.6': - resolution: {integrity: sha512-+sgX5UhVS+EP8KDHW0ouLtHjR39VDbD8bxiG5osZwx1LJV9evZ0HFu2Rluhof4NNPJE5G4Dtd7Rw7cNiUq9FEg==} + '@multiversx/sdk-dapp@5.2.13': + resolution: {integrity: sha512-GZFKpgzmkLWLHc6NKnXFkfDcjgmppaScz4LDMDlQYBJ3iO1htc/kiwmADsTZW4wIfwOhnIPc28taW4BG/5hhzA==} peerDependencies: '@multiversx/sdk-core': ^14.x || ^15.x '@multiversx/sdk-dapp-utils': ^3.x @@ -826,8 +832,8 @@ packages: '@multiversx/sdk-transaction-decoder@1.0.2': resolution: {integrity: sha512-j43QsKquu8N51WLmVlJ7dV2P3A1448R7/ktvl8r3i6wRMpfdtzDPNofTdHmMRT7DdQdvs4+RNgz8hVKL11Etsw==} - '@multiversx/sdk-wallet-connect-provider@6.1.2': - resolution: {integrity: sha512-VoGKH6w0TyzEHB8NU85Ppcbw/9CprW3QsAu60ZZWk73VFH+hiKd4Sq0XSL6Vi3QE73T6qj1yzW5PcYhZIlE0AA==} + '@multiversx/sdk-wallet-connect-provider@6.1.3': + resolution: {integrity: sha512-hulgy2aXqE/nYt7sYjKKvkU+h3OSJM57+6WSdUUdyslp/J3Gqe5vc0mWMkkEMDr0pDEpMlLGMu3J1SjtbMd+9w==} peerDependencies: '@multiversx/sdk-core': ^14.0.0 || ^15.0.0 @@ -849,8 +855,8 @@ packages: peerDependencies: '@multiversx/sdk-core': ^14.0.0 || ^15.0.0 - '@multiversx/sdk-webview-provider@3.2.1': - resolution: {integrity: sha512-EhuxYawcnFRTsTnzcX5RUb8KC55dOPoHwXWBLGvmKV0XE3SqxYB2amjDGYOuHmjbMIo7/zKTSBpIIdz3jocGrQ==} + '@multiversx/sdk-webview-provider@3.2.3': + resolution: {integrity: sha512-VjNkzfA2yRSka9a33/zKInCrIXlvHebKTI8yfZFsFxZczp/s5a7WA8+DS7UnCJ19/owrZ9OX8gDRIS6JVkMlUQ==} peerDependencies: '@multiversx/sdk-core': ^14.0.0 || ^15.0.0 '@multiversx/sdk-web-wallet-cross-window-provider': ^3.x @@ -867,8 +873,8 @@ packages: resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.9.2': - resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==} + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} engines: {node: ^14.21.3 || >=16} '@noble/ed25519@1.7.3': @@ -1062,46 +1068,156 @@ packages: rollup: optional: true + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.34.9': resolution: {integrity: sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.34.9': resolution: {integrity: sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.34.9': resolution: {integrity: sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-arm64-musl@4.34.9': resolution: {integrity: sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + cpu: [s390x] + os: [linux] + '@rollup/rollup-linux-x64-gnu@4.34.9': resolution: {integrity: sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + cpu: [x64] + os: [linux] + '@rollup/rollup-linux-x64-musl@4.34.9': resolution: {integrity: sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + cpu: [arm64] + os: [openharmony] + '@rollup/rollup-win32-arm64-msvc@4.34.9': resolution: {integrity: sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.34.9': resolution: {integrity: sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + cpu: [x64] + os: [win32] + '@scure/base@1.2.6': resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} @@ -1127,8 +1243,8 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@stencil/core@4.38.0': - resolution: {integrity: sha512-oC3QFKO0X1yXVvETgc8OLY525MNKhn9vISBrbtKnGoPlokJ6rI8Vk1RK22TevnNrHLI4SExNLbcDnqilKR35JQ==} + '@stencil/core@4.38.2': + resolution: {integrity: sha512-opyjA+DYAtaKmaSnuC8Bb/PH7nuO+1GhVn6amsN8XT+TlT9biptlcpz4YWETwYZ+XxtX+nLdxWbW0TVafrqsvQ==} engines: {node: '>=16.0.0', npm: '>=7.10.0'} hasBin: true @@ -1610,6 +1726,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} @@ -1643,6 +1762,12 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + + '@types/luxon@3.4.2': + resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} + '@types/mocha@10.0.10': resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} @@ -1669,8 +1794,8 @@ packages: peerDependencies: '@types/react': ^18.0.0 - '@types/react-dom@19.2.0': - resolution: {integrity: sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg==} + '@types/react-dom@19.2.2': + resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} peerDependencies: '@types/react': ^19.2.0 @@ -1704,11 +1829,11 @@ packages: '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - '@types/yargs@16.0.9': - resolution: {integrity: sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==} + '@types/yargs@16.0.10': + resolution: {integrity: sha512-0xbOE6Ht/oj0MTVVXCCdEZzUk7adwW3YB1Tg1ZBm95jrkrUMI0VA4sf3SgxC1TG8p5aKkn3jxT9A2BDw1mM/TQ==} - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yargs@17.0.34': + resolution: {integrity: sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==} '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} @@ -1792,9 +1917,9 @@ packages: '@vitest/snapshot@2.1.9': resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} - '@walletconnect/core@2.21.8': - resolution: {integrity: sha512-MD1SY7KAeHWvufiBK8C1MwP9/pxxI7SnKi/rHYfjco2Xvke+M+Bbm2OzvuSN7dYZvwLTkZCiJmBccTNVPCpSUQ==} - engines: {node: '>=18'} + '@walletconnect/core@2.22.4': + resolution: {integrity: sha512-ZQnyDDpqDPAk5lyLV19BRccQ3wwK3LmAwibuIv3X+44aT/dOs2kQGu9pla3iW2LgZ5qRMYvgvvfr5g3WlDGceQ==} + engines: {node: '>=18.20.8'} '@walletconnect/environment@1.0.1': resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} @@ -1825,8 +1950,8 @@ packages: '@react-native-async-storage/async-storage': optional: true - '@walletconnect/logger@2.1.2': - resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + '@walletconnect/logger@3.0.0': + resolution: {integrity: sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==} '@walletconnect/relay-api@1.0.11': resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} @@ -1837,17 +1962,17 @@ packages: '@walletconnect/safe-json@1.0.2': resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} - '@walletconnect/sign-client@2.21.8': - resolution: {integrity: sha512-lTcUbMjQ0YUZ5wzCLhpBeS9OkWYgLLly6BddEp2+pm4QxiwCCU2Nao0nBJXgzKbZYQOgrEGqtdm/7ze67gjzRA==} + '@walletconnect/sign-client@2.22.4': + resolution: {integrity: sha512-la+sol0KL33Fyx5DRlupHREIv8wA6W33bRfuLAfLm8pINRTT06j9rz0IHIqJihiALebFxVZNYzJnF65PhV0q3g==} '@walletconnect/time@1.0.2': resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} - '@walletconnect/types@2.21.8': - resolution: {integrity: sha512-xuLIPrLxe6viMu8Uk28Nf0sgyMy+4oT0mroOjBe5Vqyft8GTiwUBKZXmrGU9uDzZsYVn1FXLO9CkuNHXda3ODA==} + '@walletconnect/types@2.22.4': + resolution: {integrity: sha512-KJdiS9ezXzx1uASanldYaaenDwb42VOQ6Rj86H7FRwfYddhNnYnyEaDjDKOdToGRGcpt5Uzom6qYUOnrWEbp5g==} - '@walletconnect/utils@2.21.8': - resolution: {integrity: sha512-HtMraGJ9qXo55l4wGSM1aZvyz0XVv460iWhlRGAyRl9Yz8RQeKyXavDhwBfcTFha/6kwLxPExqQ+MURtKeVVXw==} + '@walletconnect/utils@2.22.4': + resolution: {integrity: sha512-coAPrNiTiD+snpiXQyXakMVeYcddqVqII7aLU39TeILdPoXeNPc2MAja+MF7cKNM/PA3tespljvvxck/oTm4+Q==} '@walletconnect/window-getters@1.0.1': resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} @@ -1931,19 +2056,19 @@ packages: resolution: {integrity: sha512-W0ArrZbs4M23POv8+FPsgHDFxg+wwklfZgLSsjVq2kpCmBCfIPxKSAOgTo/XrcH4We/OnshgBzxLcI+BHDgi4w==} engines: {node: ^16.13 || >=18} - '@zip.js/zip.js@2.8.7': - resolution: {integrity: sha512-8daf29EMM3gUpH/vSBSCYo2bY/wbamgRPxPpE2b+cDnbOLBHAcZikWad79R4Guemth/qtipzEHrZMq1lFXxWIA==} + '@zip.js/zip.js@2.8.8': + resolution: {integrity: sha512-v0KutehhSAuaoFAFGLp+V4+UiZ1mIxQ8vNOYMD7k9ZJaBbtQV49MYlg568oRLiuwWDg2Di58Iw3Q0ESNWR+5JA==} engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=18.0.0'} abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead - abitype@1.0.8: - resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==} + abitype@1.1.1: + resolution: {integrity: sha512-Loe5/6tAgsBukY95eGaPSDmQHIjRZYQq8PB1MpsNccDIK8WiV+Uw6WzaIXipvaxTEL2yEB0OpEaQv3gs8pkS9Q==} peerDependencies: typescript: '>=5.0.4' - zod: ^3 >=3.22.0 + zod: ^3.22.0 || ^4.0.0 peerDependenciesMeta: typescript: optional: true @@ -2160,11 +2285,16 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - bare-events@2.7.0: - resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==} + bare-events@2.8.1: + resolution: {integrity: sha512-oxSAxTS1hRfnyit2CL5QpAOS5ixfBjj6ex3yTNvXyY/kE719jQ/IjuESJBK2w5v4wwQRAHGseVJXx9QBYOtFGQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true - bare-fs@4.4.5: - resolution: {integrity: sha512-TCtu93KGLu6/aiGWzMr12TmSRS6nKdfhAnzTQRbXoSWxkbb9eRd53jQ51jG7g1gYjjtto3hbBrrhzg6djcgiKg==} + bare-fs@4.5.0: + resolution: {integrity: sha512-GljgCjeupKZJNetTqxKaQArLK10vpmK28or0+RwWjEl5Rk+/xG3wkpmkv+WrcBm3q1BwHKlnhXzR8O37kcvkXQ==} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -2190,8 +2320,8 @@ packages: bare-events: optional: true - bare-url@2.2.2: - resolution: {integrity: sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==} + bare-url@2.3.1: + resolution: {integrity: sha512-v2yl0TnaZTdEnelkKtXZGnotiV6qATBlnNuUMrHl6v9Lmmrh9mw9RYyImPU7/4RahumSwQS1k2oKXcRfXcbjJw==} base-x@5.0.1: resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} @@ -2199,8 +2329,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.12: - resolution: {integrity: sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==} + baseline-browser-mapping@2.8.20: + resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} hasBin: true basic-ftp@5.0.5: @@ -2283,8 +2413,8 @@ packages: browserify-zlib@0.2.0: resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - browserslist@4.26.3: - resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + browserslist@4.27.0: + resolution: {integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2352,8 +2482,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001748: - resolution: {integrity: sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==} + caniuse-lite@1.0.30001751: + resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} @@ -2445,8 +2575,8 @@ packages: code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} - collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -2641,10 +2771,6 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} - decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -2792,9 +2918,6 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - duplexify@4.1.3: - resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -2820,8 +2943,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.230: - resolution: {integrity: sha512-A6A6Fd3+gMdaed9wX83CvHYJb4UuapPD5X5SLq72VZJzxHSY0/LUweGXRWmQlh2ln7KV7iw7jnwXK7dlPoOnHQ==} + electron-to-chromium@1.5.243: + resolution: {integrity: sha512-ZCphxFW3Q1TVhcgS9blfut1PX8lusVi2SvXQgmEEnK4TCmE1JhH2JkjJN+DNt0pJJwfBri5AROBnz2b/C+YU9g==} elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} @@ -3116,10 +3239,6 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} - fast-xml-parser@4.5.3: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true @@ -3152,10 +3271,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} - find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3211,8 +3326,8 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@12.23.22: - resolution: {integrity: sha512-ZgGvdxXCw55ZYvhoZChTlG6pUuehecgvEAJz0BHoC5pQKW1EC5xf1Mul1ej5+ai+pVY0pylyFfdl45qnM1/GsA==} + framer-motion@12.23.24: + resolution: {integrity: sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -3312,8 +3427,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} get-uri@6.0.5: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} @@ -3446,8 +3561,8 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - html-react-parser@5.2.6: - resolution: {integrity: sha512-qcpPWLaSvqXi+TndiHbCa+z8qt0tVzjMwFGFBAa41ggC+ZA5BHaMIeMJla9g3VSp4SmiZb9qyQbmbpHYpIfPOg==} + html-react-parser@5.2.7: + resolution: {integrity: sha512-WzIAcqQoZoF49J9aev8NBDLz9TJvt2RmipeYA+/5+5x0sWCwFxqKiq0lysieiSA/G6dbUZ6KGGy65Cx2fjie5Q==} peerDependencies: '@types/react': 0.14 || 15 || 16 || 17 || 18 || 19 react: 0.14 || 15 || 16 || 17 || 18 || 19 @@ -3733,11 +3848,6 @@ packages: resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} engines: {node: '>=10'} - isows@1.0.7: - resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} - peerDependencies: - ws: '*' - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -4266,12 +4376,16 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + luxon@3.5.0: + resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==} + engines: {node: '>=12'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.30.19: - resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -4389,17 +4503,14 @@ packages: resolution: {integrity: sha512-Ghw8JhQFizF0Vjbtp9B0i//+BOkV5OWcQCPpbO0NGOoxV33o+gKDYU0Pr2pGxkIHnqZ+g5mYiXF7GMNgAcDpSg==} hasBin: true - moment@2.29.4: - resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} - - motion-dom@12.23.21: - resolution: {integrity: sha512-5xDXx/AbhrfgsQmSE7YESMn4Dpo6x5/DTZ4Iyy4xqDvVHWvFVoV+V2Ri2S/ksx+D40wrZ7gPYiMWshkdoqNgNQ==} + motion-dom@12.23.23: + resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} motion-utils@12.23.6: resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} - motion@12.23.22: - resolution: {integrity: sha512-iSq6X9vLHbeYwmHvhK//+U74ROaPnZmBuy60XZzqNl0QtZkWfoZyMDHYnpKuWFv0sNMqHgED8aCXk94LCoQPGg==} + motion@12.23.24: + resolution: {integrity: sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -4484,8 +4595,8 @@ packages: node-mock-http@1.0.3: resolution: {integrity: sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==} - node-releases@2.0.23: - resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + node-releases@2.0.26: + resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} node-stdlib-browser@1.3.1: resolution: {integrity: sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==} @@ -4558,11 +4669,12 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - ofetch@1.4.1: - resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + ofetch@1.5.0: + resolution: {integrity: sha512-A7llJ7eZyziA5xq9//3ZurA8OhFqtS99K5/V1sLBJ5j137CM/OAjlbA/TEJXBuOWwOfLqih+oH5U3ran4za1FQ==} - on-exit-leak-free@0.2.0: - resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -4598,8 +4710,8 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - ox@0.7.1: - resolution: {integrity: sha512-+k9fY9PRNuAMHRFIUbiK9Nt5seYHHzSQs9Bj+iMETcGtlpS7SmBzcGSVUQO3+nqGLEiNK4598pHNFlVRaZbRsg==} + ox@0.9.3: + resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==} peerDependencies: typescript: '>=5.4.0' peerDependenciesMeta: @@ -4730,14 +4842,14 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pino-abstract-transport@0.5.0: - resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} - pino-std-serializers@4.0.0: - resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} - pino@7.11.0: - resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} + pino@10.0.0: + resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==} hasBin: true pirates@4.0.7: @@ -4812,8 +4924,8 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - process-warning@1.0.0: - resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} @@ -4893,10 +5005,6 @@ packages: query-selector-shadow-dom@1.0.1: resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} - query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} - querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} engines: {node: '>=0.4.x'} @@ -4968,8 +5076,8 @@ packages: resolution: {integrity: sha512-88JZckqgbfXJaGcDQoTFKRmBwHBF0Ddaxz3PL9Q+vywAJruBY+NdN+ZiKSBe7r/pWtjbt0naZdtH5oNI1X3FLA==} engines: {node: '>=14.0.0'} - react-tooltip@5.29.1: - resolution: {integrity: sha512-rmJmEb/p99xWhwmVT7F7riLG08wwKykjHiMGbDPloNJk3tdI73oHsVOwzZ4SRjqMdd5/xwb/4nmz0RcoMfY7Bw==} + react-tooltip@5.30.0: + resolution: {integrity: sha512-Yn8PfbgQ/wmqnL7oBpz1QiDaLKrzZMdSUUdk7nVeGTwzbxCAJiJzR4VSYW+eIO42F1INt57sPUmpgKv0KwJKtg==} peerDependencies: react: '>=16.14.0' react-dom: '>=16.14.0' @@ -5008,8 +5116,8 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - real-require@0.1.0: - resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} recursive-readdir@2.2.3: @@ -5060,8 +5168,8 @@ packages: resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} engines: {node: '>=10'} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true @@ -5105,6 +5213,11 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-async@3.0.0: resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} engines: {node: '>=0.12.0'} @@ -5164,8 +5277,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -5241,6 +5354,9 @@ packages: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} + slow-redact@0.3.2: + resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -5264,8 +5380,8 @@ packages: resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - sonic-boom@2.8.0: - resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -5293,10 +5409,6 @@ packages: spdx-license-ids@3.0.22: resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} - split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} - split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -5322,16 +5434,9 @@ packages: stream-http@3.2.0: resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} - strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -5405,11 +5510,11 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - style-to-js@1.1.17: - resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} + style-to-js@1.1.18: + resolution: {integrity: sha512-JFPn62D4kJaPTnhFUI244MThx+FEGbi+9dw1b9yBBQ+1CZpV7QAT8kUtJ7b7EUNdHajjF/0x8fT+16oLJoojLg==} - style-to-object@1.0.9: - resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} + style-to-object@1.0.11: + resolution: {integrity: sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow==} supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -5478,8 +5583,8 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thread-stream@0.15.2: - resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -5730,8 +5835,8 @@ packages: uploadthing: optional: true - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -5775,18 +5880,10 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - validator@13.15.15: - resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==} + validator@13.15.20: + resolution: {integrity: sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==} engines: {node: '>= 0.10'} - viem@2.31.0: - resolution: {integrity: sha512-U7OMQ6yqK+bRbEIarf2vqxL7unSEQvNxvML/1zG7suAmKuJmipqdVTVJGKBCJiYsm/EremyO2FS4dHIPpGv+eA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - vite-plugin-node-polyfills@0.14.1: resolution: {integrity: sha512-S5ofYUkXea/d94AHzDwiTA7Pv/yEwzagnjgVEuBZdy7E72GBfK17qpljAlyK3CD+CRcDzAwwl/4bEjKdvZmTGQ==} peerDependencies: @@ -5994,18 +6091,6 @@ packages: utf-8-validate: optional: true - ws@8.18.2: - resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -6102,6 +6187,9 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} + zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + zustand@4.4.7: resolution: {integrity: sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==} engines: {node: '>=12.7.0'} @@ -6132,23 +6220,23 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.4': {} + '@babel/compat-data@7.28.5': {} - '@babel/core@7.28.4': + '@babel/core@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3(supports-color@8.1.1) @@ -6158,19 +6246,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.3': + '@babel/generator@7.28.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.3 + browserslist: 4.27.0 lru-cache: 5.1.1 semver: 6.3.1 @@ -6178,17 +6266,17 @@ snapshots: '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -6196,112 +6284,112 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/parser@7.28.4': + '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.4)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.4)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.4)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.4)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/runtime@7.28.4': {} @@ -6309,25 +6397,25 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 - '@babel/traverse@7.28.4': + '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - '@babel/types@7.28.4': + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 '@bcoe/v8-coverage@0.2.3': {} @@ -6408,7 +6496,7 @@ snapshots: eslint: 8.50.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.12.2': {} '@eslint/eslintrc@2.1.4': dependencies: @@ -6592,7 +6680,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 '@types/node': 20.7.1 chalk: 4.1.2 - collect-v8-coverage: 1.0.2 + collect-v8-coverage: 1.0.3 exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 @@ -6626,7 +6714,7 @@ snapshots: '@jest/console': 29.7.0 '@jest/types': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2 + collect-v8-coverage: 1.0.3 '@jest/test-sequencer@29.7.0': dependencies: @@ -6637,7 +6725,7 @@ snapshots: '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 6.1.1 @@ -6660,7 +6748,7 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 20.7.1 - '@types/yargs': 16.0.9 + '@types/yargs': 16.0.10 chalk: 4.1.2 '@jest/types@29.6.3': @@ -6669,7 +6757,7 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 20.7.1 - '@types/yargs': 17.0.33 + '@types/yargs': 17.0.34 chalk: 4.1.2 '@jridgewell/gen-mapping@0.3.13': @@ -6698,17 +6786,17 @@ snapshots: '@ledgerhq/devices@8.0.3': dependencies: - '@ledgerhq/errors': 6.26.0 + '@ledgerhq/errors': 6.12.6 '@ledgerhq/logs': 6.13.0 rxjs: 6.6.7 - semver: 7.7.2 + semver: 7.7.3 '@ledgerhq/devices@8.6.1': dependencies: '@ledgerhq/errors': 6.26.0 '@ledgerhq/logs': 6.13.0 rxjs: 7.8.2 - semver: 7.7.2 + semver: 7.7.3 '@ledgerhq/errors@6.12.6': {} @@ -6768,7 +6856,7 @@ snapshots: '@multiversx/sdk-bls-wasm@0.3.5': optional: true - '@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)': + '@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)': dependencies: '@multiversx/sdk-transaction-decoder': 1.0.2 '@noble/ed25519': 1.7.3 @@ -6792,10 +6880,10 @@ snapshots: transitivePeerDependencies: - debug - '@multiversx/sdk-dapp-ui@0.0.35(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@multiversx/sdk-dapp-ui@0.1.1(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@stencil/core': 4.38.0 - '@stencil/react-output-target': 1.2.0(@stencil/core@4.38.0)(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@stencil/core': 4.38.2 + '@stencil/react-output-target': 1.2.0(@stencil/core@4.38.2)(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 lodash.capitalize: 4.2.1 lodash.inrange: 3.3.6 @@ -6806,24 +6894,24 @@ snapshots: - react - react-dom - '@multiversx/sdk-dapp-utils@3.0.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1)': + '@multiversx/sdk-dapp-utils@3.0.2(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1)': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) bignumber.js: 9.3.1 - '@multiversx/sdk-dapp@5.2.6(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-dapp-utils@3.0.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1))(@types/react@18.2.23)(axios@1.10.0)(bignumber.js@9.3.1)(protobufjs@7.5.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2)': + '@multiversx/sdk-dapp@5.2.13(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-dapp-utils@3.0.2(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1))(@types/react@18.2.23)(axios@1.10.0)(bignumber.js@9.3.1)(protobufjs@7.5.4)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2)(zod@3.22.4)': dependencies: '@lifeomic/axios-fetch': 3.0.1 - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) - '@multiversx/sdk-dapp-utils': 3.0.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1) - '@multiversx/sdk-extension-provider': 5.1.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) - '@multiversx/sdk-hw-provider': 8.1.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-dapp-utils': 3.0.2(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(bignumber.js@9.3.1) + '@multiversx/sdk-extension-provider': 5.1.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) + '@multiversx/sdk-hw-provider': 8.1.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) '@multiversx/sdk-native-auth-client': 2.0.1(axios@1.10.0) - '@multiversx/sdk-wallet-connect-provider': 6.1.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(typescript@5.2.2) - '@multiversx/sdk-web-wallet-cross-window-provider': 3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) - '@multiversx/sdk-web-wallet-iframe-provider': 4.0.0(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))) - '@multiversx/sdk-web-wallet-provider': 5.1.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) - '@multiversx/sdk-webview-provider': 3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))) + '@multiversx/sdk-wallet-connect-provider': 6.1.3(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(typescript@5.2.2)(zod@3.22.4) + '@multiversx/sdk-web-wallet-cross-window-provider': 3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) + '@multiversx/sdk-web-wallet-iframe-provider': 4.0.0(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))) + '@multiversx/sdk-web-wallet-provider': 5.1.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) + '@multiversx/sdk-webview-provider': 3.2.3(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))) axios: 1.10.0 bignumber.js: 9.3.1 immer: 10.1.1 @@ -6838,7 +6926,7 @@ snapshots: socket.io-client: 4.7.5 zustand: 4.4.7(@types/react@18.2.23)(immer@10.1.1)(react@18.2.0) optionalDependencies: - '@multiversx/sdk-dapp-ui': 0.0.35(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@multiversx/sdk-dapp-ui': 0.1.1(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -6868,11 +6956,11 @@ snapshots: - utf-8-validate - zod - '@multiversx/sdk-extension-provider@5.1.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': + '@multiversx/sdk-extension-provider@5.1.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) - '@multiversx/sdk-hw-provider@8.1.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': + '@multiversx/sdk-hw-provider@8.1.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': dependencies: '@ledgerhq/devices': 8.0.3 '@ledgerhq/errors': 6.12.6 @@ -6880,7 +6968,7 @@ snapshots: '@ledgerhq/hw-transport-web-ble': 6.28.6 '@ledgerhq/hw-transport-webhid': 6.28.6 '@ledgerhq/hw-transport-webusb': 6.28.6 - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) buffer: 6.0.3 platform: 1.3.6 @@ -6892,11 +6980,11 @@ snapshots: dependencies: bech32: 2.0.0 - '@multiversx/sdk-wallet-connect-provider@6.1.2(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(typescript@5.2.2)': + '@multiversx/sdk-wallet-connect-provider@6.1.3(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(typescript@5.2.2)(zod@3.22.4)': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) - '@walletconnect/sign-client': 2.21.8(typescript@5.2.2) - '@walletconnect/utils': 2.21.8(typescript@5.2.2) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@walletconnect/sign-client': 2.22.4(typescript@5.2.2)(zod@3.22.4) + '@walletconnect/utils': 2.22.4(typescript@5.2.2)(zod@3.22.4) bech32: 1.1.4 transitivePeerDependencies: - '@azure/app-configuration' @@ -6923,28 +7011,28 @@ snapshots: - utf-8-validate - zod - '@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': + '@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) qs: 6.11.2 - '@multiversx/sdk-web-wallet-iframe-provider@4.0.0(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)))': + '@multiversx/sdk-web-wallet-iframe-provider@4.0.0(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)))': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) - '@multiversx/sdk-web-wallet-cross-window-provider': 3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-web-wallet-cross-window-provider': 3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) '@types/jest': 29.5.14 '@types/qs': 6.9.10 qs: 6.11.2 - '@multiversx/sdk-web-wallet-provider@5.1.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': + '@multiversx/sdk-web-wallet-provider@5.1.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) qs: 6.10.3 - '@multiversx/sdk-webview-provider@3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)))': + '@multiversx/sdk-webview-provider@3.2.3(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4))(@multiversx/sdk-web-wallet-cross-window-provider@3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)))': dependencies: - '@multiversx/sdk-core': 15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4) - '@multiversx/sdk-web-wallet-cross-window-provider': 3.2.1(@multiversx/sdk-core@15.2.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) + '@multiversx/sdk-core': 15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4) + '@multiversx/sdk-web-wallet-cross-window-provider': 3.2.1(@multiversx/sdk-core@15.3.0(bignumber.js@9.3.1)(protobufjs@7.5.4)) '@noble/ciphers@1.3.0': {} @@ -6956,7 +7044,7 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 - '@noble/curves@1.9.2': + '@noble/curves@1.9.7': dependencies: '@noble/hashes': 1.8.0 @@ -7088,6 +7176,7 @@ snapshots: optionalDependencies: typescript: 5.2.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a - supports-color @@ -7101,56 +7190,123 @@ snapshots: unbzip2-stream: 1.4.3 yargs: 17.7.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a - supports-color '@remix-run/router@1.9.0': {} - '@rollup/plugin-inject@5.0.5(rollup@3.29.5)': + '@rollup/plugin-inject@5.0.5(rollup@4.52.5)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@3.29.5) + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) estree-walker: 2.0.2 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: - rollup: 3.29.5 + rollup: 4.52.5 - '@rollup/pluginutils@5.3.0(rollup@3.29.5)': + '@rollup/pluginutils@5.3.0(rollup@4.52.5)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 3.29.5 + rollup: 4.52.5 + + '@rollup/rollup-android-arm-eabi@4.52.5': + optional: true + + '@rollup/rollup-android-arm64@4.52.5': + optional: true '@rollup/rollup-darwin-arm64@4.34.9': optional: true + '@rollup/rollup-darwin-arm64@4.52.5': + optional: true + '@rollup/rollup-darwin-x64@4.34.9': optional: true + '@rollup/rollup-darwin-x64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.34.9': optional: true + '@rollup/rollup-linux-arm64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-arm64-musl@4.34.9': optional: true + '@rollup/rollup-linux-arm64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-x64-gnu@4.34.9': optional: true + '@rollup/rollup-linux-x64-gnu@4.52.5': + optional: true + '@rollup/rollup-linux-x64-musl@4.34.9': optional: true + '@rollup/rollup-linux-x64-musl@4.52.5': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.5': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.34.9': optional: true + '@rollup/rollup-win32-arm64-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.5': + optional: true + '@rollup/rollup-win32-x64-msvc@4.34.9': optional: true + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + '@scure/base@1.2.6': {} '@scure/bip32@1.7.0': dependencies: - '@noble/curves': 1.9.2 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 @@ -7173,7 +7329,7 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} - '@stencil/core@4.38.0': + '@stencil/core@4.38.2': optionalDependencies: '@rollup/rollup-darwin-arm64': 4.34.9 '@rollup/rollup-darwin-x64': 4.34.9 @@ -7184,11 +7340,11 @@ snapshots: '@rollup/rollup-win32-arm64-msvc': 4.34.9 '@rollup/rollup-win32-x64-msvc': 4.34.9 - '@stencil/react-output-target@1.2.0(@stencil/core@4.38.0)(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@stencil/react-output-target@1.2.0(@stencil/core@4.38.2)(@types/react@18.2.23)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@lit/react': 1.0.8(@types/react@18.2.23) - '@stencil/core': 4.38.0 - html-react-parser: 5.2.6(@types/react@18.2.23)(react@18.2.0) + '@stencil/core': 4.38.2 + html-react-parser: 5.2.7(@types/react@18.2.23)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-style-stringify: 1.2.0 @@ -7196,54 +7352,54 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-preset@8.1.0(@babel/core@7.28.4)': + '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.4) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) '@svgr/core@8.1.0(typescript@5.2.2)': dependencies: - '@babel/core': 7.28.4 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) camelcase: 6.3.0 cosmiconfig: 8.3.6(typescript@5.2.2) snake-case: 3.0.4 @@ -7253,13 +7409,13 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.2.2))': dependencies: - '@babel/core': 7.28.4 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) '@svgr/core': 8.1.0(typescript@5.2.2) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 @@ -7351,7 +7507,7 @@ snapshots: enhanced-resolve: 5.18.3 jiti: 2.6.1 lightningcss: 1.30.1 - magic-string: 0.30.19 + magic-string: 0.30.21 source-map-js: 1.2.1 tailwindcss: 4.1.11 @@ -7588,27 +7744,32 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/estree@1.0.8': {} + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 20.7.1 + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 20.7.1 @@ -7647,6 +7808,12 @@ snapshots: '@types/json5@0.0.29': {} + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 20.7.1 + + '@types/luxon@3.4.2': {} + '@types/mocha@10.0.10': {} '@types/node-fetch@2.6.13': @@ -7668,7 +7835,7 @@ snapshots: dependencies: '@types/react': 18.2.23 - '@types/react-dom@19.2.0(@types/react@18.2.23)': + '@types/react-dom@19.2.2(@types/react@18.2.23)': dependencies: '@types/react': 18.2.23 @@ -7705,11 +7872,11 @@ snapshots: '@types/yargs-parser@21.0.3': {} - '@types/yargs@16.0.9': + '@types/yargs@16.0.10': dependencies: '@types/yargs-parser': 21.0.3 - '@types/yargs@17.0.33': + '@types/yargs@17.0.34': dependencies: '@types/yargs-parser': 21.0.3 @@ -7720,7 +7887,7 @@ snapshots: '@typescript-eslint/eslint-plugin@6.7.0(@typescript-eslint/parser@6.7.0(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2)': dependencies: - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 6.7.0(eslint@8.50.0)(typescript@5.2.2) '@typescript-eslint/scope-manager': 6.7.0 '@typescript-eslint/type-utils': 6.7.0(eslint@8.50.0)(typescript@5.2.2) @@ -7731,7 +7898,7 @@ snapshots: graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - semver: 7.7.2 + semver: 7.7.3 ts-api-utils: 1.4.3(typescript@5.2.2) optionalDependencies: typescript: 5.2.2 @@ -7777,7 +7944,7 @@ snapshots: debug: 4.4.3(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.7.2 + semver: 7.7.3 ts-api-utils: 1.4.3(typescript@5.2.2) optionalDependencies: typescript: 5.2.2 @@ -7793,7 +7960,7 @@ snapshots: '@typescript-eslint/types': 6.7.0 '@typescript-eslint/typescript-estree': 6.7.0(typescript@5.2.2) eslint: 8.50.0 - semver: 7.7.2 + semver: 7.7.3 transitivePeerDependencies: - supports-color - typescript @@ -7809,9 +7976,9 @@ snapshots: '@vitejs/plugin-react@4.1.0(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1))': dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 vite: 4.4.9(@types/node@20.7.1)(lightningcss@1.30.1) @@ -7824,17 +7991,17 @@ snapshots: '@vitest/snapshot@1.6.1': dependencies: - magic-string: 0.30.19 + magic-string: 0.30.21 pathe: 1.1.2 pretty-format: 29.7.0 '@vitest/snapshot@2.1.9': dependencies: '@vitest/pretty-format': 2.1.9 - magic-string: 0.30.19 + magic-string: 0.30.21 pathe: 1.1.2 - '@walletconnect/core@2.21.8(typescript@5.2.2)': + '@walletconnect/core@2.22.4(typescript@5.2.2)(zod@3.22.4)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -7842,13 +8009,13 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16 '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 + '@walletconnect/logger': 3.0.0 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.8 - '@walletconnect/utils': 2.21.8(typescript@5.2.2) + '@walletconnect/types': 2.22.4 + '@walletconnect/utils': 2.22.4(typescript@5.2.2)(zod@3.22.4) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.39.3 events: 3.3.0 @@ -7945,10 +8112,10 @@ snapshots: - ioredis - uploadthing - '@walletconnect/logger@2.1.2': + '@walletconnect/logger@3.0.0': dependencies: '@walletconnect/safe-json': 1.0.2 - pino: 7.11.0 + pino: 10.0.0 '@walletconnect/relay-api@1.0.11': dependencies: @@ -7966,16 +8133,16 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/sign-client@2.21.8(typescript@5.2.2)': + '@walletconnect/sign-client@2.22.4(typescript@5.2.2)(zod@3.22.4)': dependencies: - '@walletconnect/core': 2.21.8(typescript@5.2.2) + '@walletconnect/core': 2.22.4(typescript@5.2.2)(zod@3.22.4) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 + '@walletconnect/logger': 3.0.0 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.8 - '@walletconnect/utils': 2.21.8(typescript@5.2.2) + '@walletconnect/types': 2.22.4 + '@walletconnect/utils': 2.22.4(typescript@5.2.2)(zod@3.22.4) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -8006,13 +8173,13 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/types@2.21.8': + '@walletconnect/types@2.22.4': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 + '@walletconnect/logger': 3.0.0 events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -8035,28 +8202,28 @@ snapshots: - ioredis - uploadthing - '@walletconnect/utils@2.21.8(typescript@5.2.2)': + '@walletconnect/utils@2.22.4(typescript@5.2.2)(zod@3.22.4)': dependencies: '@msgpack/msgpack': 3.1.2 '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.2 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.0 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.8 + '@walletconnect/types': 2.22.4 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 blakejs: 1.2.1 bs58: 6.0.0 detect-browser: 5.3.0 - query-string: 7.1.3 + ox: 0.9.3(typescript@5.2.2)(zod@3.22.4) uint8arrays: 3.1.1 - viem: 2.31.0(typescript@5.2.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -8074,12 +8241,10 @@ snapshots: - '@vercel/functions' - '@vercel/kv' - aws4fetch - - bufferutil - db0 - ioredis - typescript - uploadthing - - utf-8-validate - zod '@walletconnect/window-getters@1.0.1': @@ -8118,6 +8283,7 @@ snapshots: webdriverio: 8.33.1(typescript@5.2.2) yargs: 17.7.2 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - devtools @@ -8144,6 +8310,7 @@ snapshots: glob: 10.4.5 import-meta-resolve: 4.2.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color @@ -8158,6 +8325,7 @@ snapshots: glob: 10.4.5 import-meta-resolve: 4.2.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color @@ -8167,6 +8335,7 @@ snapshots: expect-webdriverio: 4.15.4(typescript@5.2.2) webdriverio: 8.32.4(typescript@5.2.2) transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - devtools @@ -8181,6 +8350,7 @@ snapshots: expect-webdriverio: 4.15.4(typescript@5.2.2) webdriverio: 8.33.1(typescript@5.2.2) transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - devtools @@ -8201,6 +8371,7 @@ snapshots: split2: 4.2.0 stream-buffers: 3.0.3 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - devtools @@ -8241,6 +8412,7 @@ snapshots: '@wdio/utils': 8.32.4 mocha: 10.8.2 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color @@ -8273,6 +8445,7 @@ snapshots: webdriver: 8.32.4 webdriverio: 8.32.4(typescript@5.2.2) transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - devtools @@ -8310,6 +8483,7 @@ snapshots: split2: 4.2.0 wait-port: 1.1.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color @@ -8330,17 +8504,19 @@ snapshots: split2: 4.2.0 wait-port: 1.1.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color - '@zip.js/zip.js@2.8.7': {} + '@zip.js/zip.js@2.8.8': {} abab@2.0.6: {} - abitype@1.0.8(typescript@5.2.2): + abitype@1.1.1(typescript@5.2.2)(zod@3.22.4): optionalDependencies: typescript: 5.2.2 + zod: 3.22.4 abort-controller@3.0.0: dependencies: @@ -8430,6 +8606,7 @@ snapshots: tar-stream: 3.1.7 zip-stream: 5.0.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a archiver@7.0.1: @@ -8442,6 +8619,7 @@ snapshots: tar-stream: 3.1.7 zip-stream: 6.0.1 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a arg@4.1.3: {} @@ -8548,8 +8726,8 @@ snapshots: autoprefixer@10.4.16(postcss@8.4.30): dependencies: - browserslist: 4.26.3 - caniuse-lite: 1.0.30001748 + browserslist: 4.27.0 + caniuse-lite: 1.0.30001751 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -8570,13 +8748,13 @@ snapshots: b4a@1.7.3: {} - babel-jest@29.7.0(@babel/core@7.28.4): + babel-jest@29.7.0(@babel/core@7.28.5): dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.28.4) + babel-preset-jest: 29.6.3(@babel/core@7.28.5) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -8596,47 +8774,48 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 - babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.4): - dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.4) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.4) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.4) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.4) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.4) - - babel-preset-jest@29.6.3(@babel/core@7.28.4): - dependencies: - '@babel/core': 7.28.4 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.5): + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.5) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.5) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) + + babel-preset-jest@29.6.3(@babel/core@7.28.5): + dependencies: + '@babel/core': 7.28.5 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) balanced-match@1.0.2: {} - bare-events@2.7.0: {} + bare-events@2.8.1: {} - bare-fs@4.4.5: + bare-fs@4.5.0: dependencies: - bare-events: 2.7.0 + bare-events: 2.8.1 bare-path: 3.0.0 - bare-stream: 2.7.0(bare-events@2.7.0) - bare-url: 2.2.2 + bare-stream: 2.7.0(bare-events@2.8.1) + bare-url: 2.3.1 fast-fifo: 1.3.2 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a optional: true @@ -8648,16 +8827,17 @@ snapshots: bare-os: 3.6.2 optional: true - bare-stream@2.7.0(bare-events@2.7.0): + bare-stream@2.7.0(bare-events@2.8.1): dependencies: streamx: 2.23.0 optionalDependencies: - bare-events: 2.7.0 + bare-events: 2.8.1 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a optional: true - bare-url@2.2.2: + bare-url@2.3.1: dependencies: bare-path: 3.0.0 optional: true @@ -8666,7 +8846,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.8.12: {} + baseline-browser-mapping@2.8.20: {} basic-ftp@5.0.5: {} @@ -8728,7 +8908,7 @@ snapshots: browser-resolve@2.0.0: dependencies: - resolve: 1.22.10 + resolve: 1.22.11 browser-stdout@1.3.1: {} @@ -8776,13 +8956,13 @@ snapshots: dependencies: pako: 1.0.11 - browserslist@4.26.3: + browserslist@4.27.0: dependencies: - baseline-browser-mapping: 2.8.12 - caniuse-lite: 1.0.30001748 - electron-to-chromium: 1.5.230 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) + baseline-browser-mapping: 2.8.20 + caniuse-lite: 1.0.30001751 + electron-to-chromium: 1.5.243 + node-releases: 2.0.26 + update-browserslist-db: 1.1.4(browserslist@4.27.0) bs-logger@0.2.6: dependencies: @@ -8851,7 +9031,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001748: {} + caniuse-lite@1.0.30001751: {} chalk@3.0.0: dependencies: @@ -8940,7 +9120,7 @@ snapshots: code-block-writer@13.0.3: {} - collect-v8-coverage@1.0.2: {} + collect-v8-coverage@1.0.3: {} color-convert@2.0.1: dependencies: @@ -9144,8 +9324,6 @@ snapshots: decimal.js@10.6.0: {} - decode-uri-component@0.2.2: {} - decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -9291,13 +9469,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - duplexify@4.1.3: - dependencies: - end-of-stream: 1.4.5 - inherits: 2.0.4 - readable-stream: 3.6.2 - stream-shift: 1.0.3 - eastasianwidth@0.2.0: {} easy-table@1.2.0: @@ -9324,7 +9495,7 @@ snapshots: edgedriver@5.6.1: dependencies: '@wdio/logger': 8.38.0 - '@zip.js/zip.js': 2.8.7 + '@zip.js/zip.js': 2.8.8 decamelize: 6.0.1 edge-paths: 3.0.5 fast-xml-parser: 4.5.3 @@ -9335,7 +9506,7 @@ snapshots: dependencies: jake: 10.9.4 - electron-to-chromium@1.5.230: {} + electron-to-chromium@1.5.243: {} elliptic@6.6.1: dependencies: @@ -9550,7 +9721,7 @@ snapshots: dependencies: debug: 3.2.7 is-core-module: 2.16.1 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color @@ -9562,7 +9733,7 @@ snapshots: eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.7.0(eslint@8.50.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.50.0) eslint-plugin-import: 2.28.1(@typescript-eslint/parser@6.7.0(eslint@8.50.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.50.0) fast-glob: 3.3.3 - get-tsconfig: 4.10.1 + get-tsconfig: 4.13.0 is-core-module: 2.16.1 is-glob: 4.0.3 transitivePeerDependencies: @@ -9657,7 +9828,7 @@ snapshots: eslint@8.50.0: dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@8.50.0) - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/regexpp': 4.12.2 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.50.0 '@humanwhocodes/config-array': 0.11.14 @@ -9724,7 +9895,9 @@ snapshots: events-universal@1.0.1: dependencies: - bare-events: 2.7.0 + bare-events: 2.8.1 + transitivePeerDependencies: + - bare-abort-controller events@3.3.0: {} @@ -9766,10 +9939,11 @@ snapshots: jest-matcher-utils: 29.7.0 lodash.isequal: 4.5.0 optionalDependencies: - '@wdio/globals': 8.33.1(typescript@5.2.2) + '@wdio/globals': 8.32.4(typescript@5.2.2) '@wdio/logger': 8.28.0 - webdriverio: 8.33.1(typescript@5.2.2) + webdriverio: 8.32.4(typescript@5.2.2) transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - devtools @@ -9795,7 +9969,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.3.4 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -9823,8 +9997,6 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-redact@3.5.0: {} - fast-xml-parser@4.5.3: dependencies: strnum: 1.1.2 @@ -9863,8 +10035,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - filter-obj@1.1.0: {} - find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -9917,9 +10087,9 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + framer-motion@12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - motion-dom: 12.23.21 + motion-dom: 12.23.23 motion-utils: 12.23.6 tslib: 2.8.1 optionalDependencies: @@ -9968,7 +10138,7 @@ snapshots: geckodriver@4.5.1: dependencies: '@wdio/logger': 9.18.0 - '@zip.js/zip.js': 2.8.7 + '@zip.js/zip.js': 2.8.8 decamelize: 6.0.1 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -9976,6 +10146,7 @@ snapshots: tar-fs: 3.1.1 which: 4.0.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a - supports-color @@ -10022,7 +10193,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.10.1: + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -10030,7 +10201,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.3.4 transitivePeerDependencies: - supports-color @@ -10201,13 +10372,13 @@ snapshots: html-escaper@2.0.2: {} - html-react-parser@5.2.6(@types/react@18.2.23)(react@18.2.0): + html-react-parser@5.2.7(@types/react@18.2.23)(react@18.2.0): dependencies: domhandler: 5.0.3 html-dom-parser: 5.1.1 react: 18.2.0 react-property: 2.0.2 - style-to-js: 1.1.17 + style-to-js: 1.1.18 optionalDependencies: '@types/react': 18.2.23 @@ -10485,16 +10656,12 @@ snapshots: isomorphic-timers-promises@1.0.1: {} - isows@1.0.7(ws@8.18.2): - dependencies: - ws: 8.18.2 - istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -10503,11 +10670,11 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.2 + semver: 7.7.3 transitivePeerDependencies: - supports-color @@ -10608,10 +10775,10 @@ snapshots: jest-config@29.7.0(@types/node@20.7.1)(ts-node@10.9.2(@swc/core@1.3.90)(@types/node@20.7.1)(typescript@5.2.2)): dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.4) + babel-jest: 29.7.0(@babel/core@7.28.5) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -10749,7 +10916,7 @@ snapshots: jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) jest-util: 29.7.0 jest-validate: 29.7.0 - resolve: 1.22.10 + resolve: 1.22.11 resolve.exports: 2.0.3 slash: 3.0.0 @@ -10791,7 +10958,7 @@ snapshots: '@types/node': 20.7.1 chalk: 4.1.2 cjs-module-lexer: 1.4.3 - collect-v8-coverage: 1.0.2 + collect-v8-coverage: 1.0.3 glob: 7.2.3 graceful-fs: 4.2.11 jest-haste-map: 29.7.0 @@ -10808,15 +10975,15 @@ snapshots: jest-snapshot@29.7.0: dependencies: - '@babel/core': 7.28.4 - '@babel/generator': 7.28.3 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) - '@babel/types': 7.28.4 + '@babel/core': 7.28.5 + '@babel/generator': 7.28.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/types': 7.28.5 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -10827,7 +10994,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.2 + semver: 7.7.3 transitivePeerDependencies: - supports-color @@ -11183,15 +11350,17 @@ snapshots: lru-cache@7.18.3: {} + luxon@3.5.0: {} + lz-string@1.5.0: {} - magic-string@0.30.19: + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 make-error@1.3.6: {} @@ -11312,20 +11481,18 @@ snapshots: prop-types: 15.8.1 tcomb: 3.2.29 tcomb-validation: 3.4.1 - validator: 13.15.15 + validator: 13.15.20 yargs: 17.7.2 - moment@2.29.4: {} - - motion-dom@12.23.21: + motion-dom@12.23.23: dependencies: motion-utils: 12.23.6 motion-utils@12.23.6: {} - motion@12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + motion@12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - framer-motion: 12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + framer-motion: 12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0) tslib: 2.8.1 optionalDependencies: react: 18.2.0 @@ -11378,7 +11545,7 @@ snapshots: node-mock-http@1.0.3: {} - node-releases@2.0.23: {} + node-releases@2.0.26: {} node-stdlib-browser@1.3.1: dependencies: @@ -11413,7 +11580,7 @@ snapshots: normalize-package-data@6.0.2: dependencies: hosted-git-info: 7.0.2 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} @@ -11485,13 +11652,13 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - ofetch@1.4.1: + ofetch@1.5.0: dependencies: destr: 2.0.5 node-fetch-native: 1.6.7 ufo: 1.6.1 - on-exit-leak-free@0.2.0: {} + on-exit-leak-free@2.1.2: {} once@1.4.0: dependencies: @@ -11538,15 +11705,15 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - ox@0.7.1(typescript@5.2.2): + ox@0.9.3(typescript@5.2.2)(zod@3.22.4): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.2 + '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.2.2) + abitype: 1.1.1(typescript@5.2.2)(zod@3.22.4) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.2.2 @@ -11585,7 +11752,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.3.4 get-uri: 6.0.5 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -11676,26 +11843,25 @@ snapshots: picomatch@4.0.3: {} - pino-abstract-transport@0.5.0: + pino-abstract-transport@2.0.0: dependencies: - duplexify: 4.1.3 split2: 4.2.0 - pino-std-serializers@4.0.0: {} + pino-std-serializers@7.0.0: {} - pino@7.11.0: + pino@10.0.0: dependencies: atomic-sleep: 1.0.0 - fast-redact: 3.5.0 - on-exit-leak-free: 0.2.0 - pino-abstract-transport: 0.5.0 - pino-std-serializers: 4.0.0 - process-warning: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 quick-format-unescaped: 4.0.4 - real-require: 0.1.0 + real-require: 0.2.0 safe-stable-stringify: 2.5.0 - sonic-boom: 2.8.0 - thread-stream: 0.15.2 + slow-redact: 0.3.2 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 pirates@4.0.7: {} @@ -11761,7 +11927,7 @@ snapshots: process-nextick-args@2.0.1: {} - process-warning@1.0.0: {} + process-warning@5.0.0: {} process@0.11.10: {} @@ -11796,7 +11962,7 @@ snapshots: proxy-agent@6.3.0: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.3.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -11809,7 +11975,7 @@ snapshots: proxy-agent@6.3.1: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.3.4 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -11854,6 +12020,7 @@ snapshots: optionalDependencies: typescript: 5.2.2 transitivePeerDependencies: + - bare-abort-controller - bufferutil - encoding - react-native-b4a @@ -11882,13 +12049,6 @@ snapshots: query-selector-shadow-dom@1.0.1: {} - query-string@7.1.3: - dependencies: - decode-uri-component: 0.2.2 - filter-obj: 1.1.0 - split-on-first: 1.1.0 - strict-uri-encode: 2.0.0 - querystring-es3@0.2.1: {} querystringify@2.2.0: {} @@ -11922,9 +12082,9 @@ snapshots: react-is@18.3.1: {} - react-modal-sheet@4.4.0(motion@12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0): + react-modal-sheet@4.4.0(motion@12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0): dependencies: - motion: 12.23.22(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + motion: 12.23.24(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-property@2.0.2: {} @@ -11947,7 +12107,7 @@ snapshots: dependencies: '@emotion/unitless': 0.10.0 - react-tooltip@5.29.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-tooltip@5.30.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@floating-ui/dom': 1.7.4 classnames: 2.3.2 @@ -12005,7 +12165,7 @@ snapshots: readdirp@4.1.2: {} - real-require@0.1.0: {} + real-require@0.2.0: {} recursive-readdir@2.2.3: dependencies: @@ -12056,7 +12216,7 @@ snapshots: resolve.exports@2.0.3: {} - resolve@1.22.10: + resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 @@ -12100,6 +12260,35 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + rollup@4.52.5: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 + fsevents: 2.3.3 + optional: true + run-async@3.0.0: {} run-parallel@1.2.0: @@ -12159,7 +12348,7 @@ snapshots: semver@6.3.1: {} - semver@7.7.2: {} + semver@7.7.3: {} serialize-error@11.0.3: dependencies: @@ -12245,6 +12434,8 @@ snapshots: slash@5.1.0: {} + slow-redact@0.3.2: {} + smart-buffer@4.2.0: {} snake-case@3.0.4: @@ -12273,7 +12464,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.3.4 socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -12283,7 +12474,7 @@ snapshots: ip-address: 10.0.1 smart-buffer: 4.2.0 - sonic-boom@2.8.0: + sonic-boom@4.2.0: dependencies: atomic-sleep: 1.0.0 @@ -12312,8 +12503,6 @@ snapshots: spdx-license-ids@3.0.22: {} - split-on-first@1.1.0: {} - split2@4.2.0: {} sprintf-js@1.0.3: {} @@ -12341,18 +12530,15 @@ snapshots: readable-stream: 3.6.2 xtend: 4.0.2 - stream-shift@1.0.3: {} - streamx@2.23.0: dependencies: events-universal: 1.0.1 fast-fifo: 1.3.2 text-decoder: 1.2.3 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a - strict-uri-encode@2.0.0: {} - string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -12446,11 +12632,11 @@ snapshots: strnum@1.1.2: {} - style-to-js@1.1.17: + style-to-js@1.1.18: dependencies: - style-to-object: 1.0.9 + style-to-object: 1.0.11 - style-to-object@1.0.9: + style-to-object@1.0.11: dependencies: inline-style-parser: 0.2.4 @@ -12489,6 +12675,7 @@ snapshots: pump: 3.0.3 tar-stream: 3.1.7 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a tar-fs@3.1.1: @@ -12496,9 +12683,10 @@ snapshots: pump: 3.0.3 tar-stream: 3.1.7 optionalDependencies: - bare-fs: 4.4.5 + bare-fs: 4.5.0 bare-path: 3.0.0 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - react-native-b4a @@ -12508,6 +12696,7 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.23.0 transitivePeerDependencies: + - bare-abort-controller - react-native-b4a tar@7.5.1: @@ -12538,9 +12727,9 @@ snapshots: text-table@0.2.0: {} - thread-stream@0.15.2: + thread-stream@3.1.0: dependencies: - real-require: 0.1.0 + real-require: 0.2.0 through@2.3.8: {} @@ -12583,7 +12772,7 @@ snapshots: dependencies: typescript: 5.2.2 - ts-jest@29.1.1(@babel/core@7.28.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.4))(jest@29.7.0(@types/node@20.7.1)(ts-node@10.9.2(@swc/core@1.3.90)(@types/node@20.7.1)(typescript@5.2.2)))(typescript@5.2.2): + ts-jest@29.1.1(@babel/core@7.28.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest@29.7.0(@types/node@20.7.1)(ts-node@10.9.2(@swc/core@1.3.90)(@types/node@20.7.1)(typescript@5.2.2)))(typescript@5.2.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -12592,13 +12781,13 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.2 + semver: 7.7.3 typescript: 5.2.2 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.4) + babel-jest: 29.7.0(@babel/core@7.28.5) ts-morph@22.0.0: dependencies: @@ -12731,14 +12920,14 @@ snapshots: h3: 1.15.4 lru-cache: 10.4.3 node-fetch-native: 1.6.7 - ofetch: 1.4.1 + ofetch: 1.5.0 ufo: 1.6.1 optionalDependencies: idb-keyval: 6.2.2 - update-browserslist-db@1.1.3(browserslist@4.26.3): + update-browserslist-db@1.1.4(browserslist@4.27.0): dependencies: - browserslist: 4.26.3 + browserslist: 4.27.0 escalade: 3.2.0 picocolors: 1.1.1 @@ -12787,28 +12976,11 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - validator@13.15.15: {} - - viem@2.31.0(typescript@5.2.2): - dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.2.2) - isows: 1.0.7(ws@8.18.2) - ox: 0.7.1(typescript@5.2.2) - ws: 8.18.2 - optionalDependencies: - typescript: 5.2.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod + validator@13.15.20: {} - vite-plugin-node-polyfills@0.14.1(rollup@3.29.5)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)): + vite-plugin-node-polyfills@0.14.1(rollup@4.52.5)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)): dependencies: - '@rollup/plugin-inject': 5.0.5(rollup@3.29.5) + '@rollup/plugin-inject': 5.0.5(rollup@4.52.5) buffer-polyfill: buffer@6.0.3 node-stdlib-browser: 1.3.1 process: 0.11.10 @@ -12816,9 +12988,9 @@ snapshots: transitivePeerDependencies: - rollup - vite-plugin-svgr@4.0.0(rollup@3.29.5)(typescript@5.2.2)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)): + vite-plugin-svgr@4.0.0(rollup@4.52.5)(typescript@5.2.2)(vite@4.4.9(@types/node@20.7.1)(lightningcss@1.30.1)): dependencies: - '@rollup/pluginutils': 5.3.0(rollup@3.29.5) + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) '@svgr/core': 8.1.0(typescript@5.2.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.2.2)) vite: 4.4.9(@types/node@20.7.1)(lightningcss@1.30.1) @@ -12886,6 +13058,7 @@ snapshots: ky: 0.33.3 ws: 8.18.3 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - react-native-b4a @@ -12906,6 +13079,7 @@ snapshots: ky: 0.33.3 ws: 8.18.3 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - react-native-b4a @@ -12939,6 +13113,7 @@ snapshots: serialize-error: 11.0.3 webdriver: 8.32.4 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - encoding @@ -12974,6 +13149,7 @@ snapshots: serialize-error: 11.0.3 webdriver: 8.33.1 transitivePeerDependencies: + - bare-abort-controller - bare-buffer - bufferutil - encoding @@ -13088,8 +13264,6 @@ snapshots: ws@8.17.1: {} - ws@8.18.2: {} - ws@8.18.3: {} xml-name-validator@4.0.0: {} @@ -13191,6 +13365,9 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 + zod@3.22.4: + optional: true + zustand@4.4.7(@types/react@18.2.23)(immer@10.1.1)(react@18.2.0): dependencies: use-sync-external-store: 1.2.0(react@18.2.0) diff --git a/src/App.tsx b/src/App.tsx index 79804dd0..7638e3b6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,9 +1,7 @@ import { Route, BrowserRouter as Router, Routes } from 'react-router-dom'; - import { PageNotFound } from 'pages/PageNotFound/PageNotFound'; import { routes } from 'routes'; import { AxiosInterceptors, BatchTransactionsContextProvider } from 'wrappers'; - import { Layout } from './components'; export const App = () => { diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index a99adc41..31c4bacc 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,8 +1,6 @@ import { ComponentProps } from 'react'; - import { MvxButton } from 'lib'; -// prettier-ignore const styles = { button: 'button h-8 lg:h-10' } satisfies Record; diff --git a/src/components/Drawer/Drawer.tsx b/src/components/Drawer/Drawer.tsx index 47ac06fa..9918aed7 100644 --- a/src/components/Drawer/Drawer.tsx +++ b/src/components/Drawer/Drawer.tsx @@ -1,9 +1,7 @@ import classNames from 'classnames'; import { Fragment, MouseEvent, PropsWithChildren, ReactNode } from 'react'; import { Sheet } from 'react-modal-sheet'; - import { WithClassnameType } from 'types'; - import styles from './drawer.styles'; interface DrawerPropsType extends PropsWithChildren, WithClassnameType { diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 99d4757f..ebe923f6 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -1,12 +1,10 @@ import { faHeart } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import moment from 'moment'; +import { DateTime } from 'luxon'; import { MouseEvent } from 'react'; import { useNavigate } from 'react-router-dom'; - import { useGetNetworkConfig } from 'lib'; import { RouteNamesEnum } from 'localConstants'; - import { version } from '../../../package.json'; // prettier-ignore @@ -22,7 +20,7 @@ const styles = { export const Footer = () => { const { network } = useGetNetworkConfig(); const navigate = useNavigate(); - const currentYear = moment().year(); + const currentYear = DateTime.now().year; const handleDisclaimerClick = (event: MouseEvent) => { event.preventDefault(); diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 61a8b55a..7733ae54 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -6,10 +6,9 @@ import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import classNames from 'classnames'; import { MouseEvent } from 'react'; import { useNavigate } from 'react-router-dom'; -import classNames from 'classnames'; - import { Logo, Tooltip } from 'components'; import { GITHUB_REPO_URL } from 'config'; import { @@ -23,7 +22,6 @@ import { useGetNetworkConfig } from 'lib'; import { RouteNamesEnum } from 'localConstants'; - import { ThemeTooltip } from './components'; import styles from './header.styles'; diff --git a/src/components/Header/components/ThemeTooltip/ThemeTooltip.tsx b/src/components/Header/components/ThemeTooltip/ThemeTooltip.tsx index 9d76beb9..02ecee8e 100644 --- a/src/components/Header/components/ThemeTooltip/ThemeTooltip.tsx +++ b/src/components/Header/components/ThemeTooltip/ThemeTooltip.tsx @@ -4,13 +4,11 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; - import { Tooltip } from 'components/Tooltip/Tooltip'; import { - useHandleThemeManagement, - ThemeOptionType + ThemeOptionType, + useHandleThemeManagement } from 'hooks/useHandleThemeManagement'; - import { ThemeTooltipDots } from './components'; import styles from './themeTooltip.styles'; diff --git a/src/components/Header/components/ThemeTooltip/components/ThemeTooltipDots/ThemeTooltipDots.tsx b/src/components/Header/components/ThemeTooltip/components/ThemeTooltipDots/ThemeTooltipDots.tsx index 7275f74e..61ddb99a 100644 --- a/src/components/Header/components/ThemeTooltip/components/ThemeTooltipDots/ThemeTooltipDots.tsx +++ b/src/components/Header/components/ThemeTooltip/components/ThemeTooltipDots/ThemeTooltipDots.tsx @@ -1,5 +1,4 @@ import classNames from 'classnames'; - import { ThemeTooltipDotsPropsType } from './themeTooltipDots.types'; // prettier-ignore diff --git a/src/components/OutputContainer/components/PingPongOutput.tsx b/src/components/OutputContainer/components/PingPongOutput.tsx index 499b603c..e3295b8d 100644 --- a/src/components/OutputContainer/components/PingPongOutput.tsx +++ b/src/components/OutputContainer/components/PingPongOutput.tsx @@ -1,6 +1,5 @@ import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - import { Label } from 'components'; import { contractAddress } from 'config'; import { @@ -10,10 +9,8 @@ import { SignedTransactionType, useGetNetworkConfig } from 'lib'; - import { TransactionsOutput } from './TransactionsOutput'; -// prettier-ignore const styles = { pingPongAddressContainer: 'ping-pong-address-container flex gap-3 mb-4', pingPongButtons: 'ping-pong-buttons flex gap-2', diff --git a/src/components/OutputContainer/components/TransactionOutput.tsx b/src/components/OutputContainer/components/TransactionOutput.tsx index 948e81a5..32cab425 100644 --- a/src/components/OutputContainer/components/TransactionOutput.tsx +++ b/src/components/OutputContainer/components/TransactionOutput.tsx @@ -1,6 +1,5 @@ import { faArrowUpRightFromSquare } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - import { Label } from 'components'; import { ACCOUNTS_ENDPOINT, @@ -12,7 +11,6 @@ import { useGetNetworkConfig } from 'lib'; -// prettier-ignore const styles = { transactionContainer: 'transaction-container flex flex-col', transactionElementContainer: 'transaction-elem-container flex gap-2', diff --git a/src/components/OutputContainer/components/TransactionsOutput.tsx b/src/components/OutputContainer/components/TransactionsOutput.tsx index 885222e8..528a5dad 100644 --- a/src/components/OutputContainer/components/TransactionsOutput.tsx +++ b/src/components/OutputContainer/components/TransactionsOutput.tsx @@ -1,8 +1,6 @@ import { SignedTransactionType } from 'lib'; - import { TransactionOutput } from './TransactionOutput'; -// prettier-ignore const styles = { transactionsOutput: 'transactions-output flex flex-col gap-4' } satisfies Record; diff --git a/src/components/PingPongComponent/PingPongComponent.tsx b/src/components/PingPongComponent/PingPongComponent.tsx index dc312823..425c8980 100644 --- a/src/components/PingPongComponent/PingPongComponent.tsx +++ b/src/components/PingPongComponent/PingPongComponent.tsx @@ -1,9 +1,8 @@ -import { useEffect, useState } from 'react'; import { faArrowDown, faArrowUp } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { TokenLoginType } from '@multiversx/sdk-dapp/out/types/login.types'; -import moment from 'moment'; - +import { Duration } from 'luxon'; +import { useEffect, useState } from 'react'; import { Label, MissingNativeAuthError, @@ -21,7 +20,6 @@ import { import { ACCOUNTS_ENDPOINT, Transaction, useGetPendingTransactions } from 'lib'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; -// prettier-ignore const styles = { pingPongContainer: 'ping-pong-container flex flex-col gap-6', infosContainer: 'infos-container flex flex-col gap-2', @@ -133,10 +131,9 @@ export const PingPongComponent = ({ setCurrentSessionId(sessionId); }; - const timeRemaining = moment() - .startOf('day') - .seconds(secondsLeft ?? 0) - .format('mm:ss'); + const timeRemaining = Duration.fromObject({ + seconds: secondsLeft ?? 0 + }).toFormat('mm:ss'); const pongAllowed = secondsLeft === 0; diff --git a/src/components/Tooltip/tooltip.types.ts b/src/components/Tooltip/tooltip.types.ts index 1a1b4ea0..a8068c65 100644 --- a/src/components/Tooltip/tooltip.types.ts +++ b/src/components/Tooltip/tooltip.types.ts @@ -1,6 +1,5 @@ import { ReactNode } from 'react'; import { ITooltip as ReactTooltipPropsType } from 'react-tooltip'; - import { WithClassnameType } from 'types'; export enum TooltipPlaceEnum { diff --git a/src/components/TransactionsTable/TransactionsTable.tsx b/src/components/TransactionsTable/TransactionsTable.tsx index 101976bd..de1c5d50 100644 --- a/src/components/TransactionsTable/TransactionsTable.tsx +++ b/src/components/TransactionsTable/TransactionsTable.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react'; - import { MvxTransactionsTable, ServerTransactionType, diff --git a/src/hooks/useHandleThemeManagement.ts b/src/hooks/useHandleThemeManagement.ts index 36d1d16f..6ae277b3 100644 --- a/src/hooks/useHandleThemeManagement.ts +++ b/src/hooks/useHandleThemeManagement.ts @@ -1,5 +1,4 @@ import { MouseEvent, useEffect, useState } from 'react'; - import { ThemesEnum } from 'lib'; export interface ThemeOptionType { diff --git a/src/index.tsx b/src/index.tsx index db88c350..aa757899 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,7 +1,5 @@ import ReactDOM from 'react-dom/client'; - import { initApp } from 'lib'; - import { App } from './App'; import { config } from './initConfig'; diff --git a/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx b/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx index 7d948149..cb725baf 100644 --- a/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx +++ b/src/lib/sdkDapp/components/ExplorerLink/ExplorerLink.tsx @@ -1,5 +1,4 @@ import { PropsWithChildren } from 'react'; - import { useGetNetworkConfig } from 'lib/sdkDapp/sdkDapp.hooks'; import { MvxExplorerLink } from 'lib/sdkDappUI/sdkDappUI.components'; import { WithClassnameType } from 'types/components.types'; diff --git a/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx b/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx index ab8dcf94..b6736ec8 100644 --- a/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx +++ b/src/lib/sdkDapp/components/FormatAmount/FormatAmount.tsx @@ -1,5 +1,4 @@ import { WithClassnameType } from 'types'; - import { MvxFormatAmount } from '../../../sdkDappUI/sdkDappUI.components'; import { MvxFormatAmountPropsType } from '../../../sdkDappUI/sdkDappUI.types'; import { DECIMALS, DIGITS } from '../../../sdkDappUtils'; diff --git a/src/pages/Dashboard/Dashboard.tsx b/src/pages/Dashboard/Dashboard.tsx index 3d040d05..0d6bd4de 100644 --- a/src/pages/Dashboard/Dashboard.tsx +++ b/src/pages/Dashboard/Dashboard.tsx @@ -1,10 +1,9 @@ import classNames from 'classnames'; import { useEffect, useState } from 'react'; - import { contractAddress } from 'config'; import { WidgetType } from 'types/widget.types'; - import { DashboardHeader, LeftPanel, Widget } from './components'; +import styles from './dashboard.styles'; import { BatchTransactions, NativeAuth, @@ -14,7 +13,6 @@ import { SignMessage, Transactions } from './widgets'; -import styles from './dashboard.styles'; const dashboardWidgets: WidgetType[] = [ { diff --git a/src/pages/Dashboard/components/LeftPanel/LeftPanel.tsx b/src/pages/Dashboard/components/LeftPanel/LeftPanel.tsx index e38442d8..acf502b8 100644 --- a/src/pages/Dashboard/components/LeftPanel/LeftPanel.tsx +++ b/src/pages/Dashboard/components/LeftPanel/LeftPanel.tsx @@ -6,7 +6,6 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import { useNavigate } from 'react-router-dom'; - import { ReactComponent as IconExpand } from 'assets/img/expand-up-down.svg'; import { Logo } from 'components'; import { @@ -18,7 +17,6 @@ import { useGetNetworkConfig } from 'lib'; import { RouteNamesEnum } from 'localConstants'; - import { Account, SideMenu } from './components'; import styles from './leftPanel.styles'; diff --git a/src/pages/Dashboard/components/LeftPanel/components/Account/Account.tsx b/src/pages/Dashboard/components/LeftPanel/components/Account/Account.tsx index 6e7be33b..b646700f 100644 --- a/src/pages/Dashboard/components/LeftPanel/components/Account/Account.tsx +++ b/src/pages/Dashboard/components/LeftPanel/components/Account/Account.tsx @@ -6,15 +6,13 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import { ReactNode, useState } from 'react'; - import { ReactComponent as XLogo } from 'assets/img/x-logo.svg'; import { Label } from 'components'; import { FormatAmount, MvxTrim, useGetAccount } from 'lib'; import { DataTestIdsEnum } from 'localConstants'; - +import styles from './account.styles'; import { Username } from './components'; import { useGetUserHerotag } from './hooks/useGetUserHerotag'; -import styles from './account.styles'; interface AccountDetailsType { icon: ReactNode; diff --git a/src/pages/Dashboard/components/LeftPanel/components/Account/components/Username.tsx b/src/pages/Dashboard/components/LeftPanel/components/Account/components/Username.tsx index 67f73a35..ddb057f3 100644 --- a/src/pages/Dashboard/components/LeftPanel/components/Account/components/Username.tsx +++ b/src/pages/Dashboard/components/LeftPanel/components/Account/components/Username.tsx @@ -1,9 +1,7 @@ import { trimUsernameDomain } from 'lib'; import { DataTestIdsEnum } from 'localConstants'; - import { useGetUserHerotag } from '../hooks/useGetUserHerotag'; -// prettier-ignore const styles = { usernameContainer: 'username-container flex gap-0.5', herotag: 'herotag text-accent transition-all duration-200 ease-out' diff --git a/src/pages/Dashboard/components/LeftPanel/components/Account/hooks/useGetUserHerotag.tsx b/src/pages/Dashboard/components/LeftPanel/components/Account/hooks/useGetUserHerotag.tsx index 004cd06c..54d85853 100644 --- a/src/pages/Dashboard/components/LeftPanel/components/Account/hooks/useGetUserHerotag.tsx +++ b/src/pages/Dashboard/components/LeftPanel/components/Account/hooks/useGetUserHerotag.tsx @@ -1,6 +1,5 @@ import axios from 'axios'; import { useEffect, useState } from 'react'; - import { ID_API_URL, USERS_API_URL } from 'config/config.mainnet'; import { useGetAccount } from 'lib'; diff --git a/src/pages/Dashboard/components/LeftPanel/components/SideMenu/SideMenu.tsx b/src/pages/Dashboard/components/LeftPanel/components/SideMenu/SideMenu.tsx index 7ed9f395..32f3c9d4 100644 --- a/src/pages/Dashboard/components/LeftPanel/components/SideMenu/SideMenu.tsx +++ b/src/pages/Dashboard/components/LeftPanel/components/SideMenu/SideMenu.tsx @@ -9,14 +9,12 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import { useState } from 'react'; - import { ReactComponent as IconBatch } from 'assets/img/batch-tx.svg'; import { ReactComponent as IconAbi } from 'assets/img/ping-pong-abi.svg'; import { ReactComponent as IconBackend } from 'assets/img/ping-pong-backend.svg'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; - -import styles from './sideMenu.styles'; import { ItemIcon } from './components'; +import styles from './sideMenu.styles'; import { MenuItemsType, SideMenuPropsType } from './sideMenu.types'; const menuItems: MenuItemsType[] = [ diff --git a/src/pages/Dashboard/components/LeftPanel/components/SideMenu/components/ItemIcon/ItemIcon.tsx b/src/pages/Dashboard/components/LeftPanel/components/SideMenu/components/ItemIcon/ItemIcon.tsx index 2798dd75..d4a9b327 100644 --- a/src/pages/Dashboard/components/LeftPanel/components/SideMenu/components/ItemIcon/ItemIcon.tsx +++ b/src/pages/Dashboard/components/LeftPanel/components/SideMenu/components/ItemIcon/ItemIcon.tsx @@ -1,6 +1,6 @@ -import { FunctionComponent, SVGProps } from 'react'; import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { FunctionComponent, SVGProps } from 'react'; interface ItemIconPropsType { icon: IconDefinition | FunctionComponent>; diff --git a/src/pages/Dashboard/components/LeftPanel/components/SideMenu/sideMenu.types.ts b/src/pages/Dashboard/components/LeftPanel/components/SideMenu/sideMenu.types.ts index 60328c8e..0c520cbd 100644 --- a/src/pages/Dashboard/components/LeftPanel/components/SideMenu/sideMenu.types.ts +++ b/src/pages/Dashboard/components/LeftPanel/components/SideMenu/sideMenu.types.ts @@ -1,6 +1,5 @@ -import { FunctionComponent, SVGProps } from 'react'; import { IconDefinition } from '@fortawesome/free-solid-svg-icons'; - +import { FunctionComponent, SVGProps } from 'react'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; export interface SideMenuPropsType { diff --git a/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx b/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx index d5d8d6a4..79d11aeb 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx +++ b/src/pages/Dashboard/widgets/BatchTransactions/BatchTransactions.tsx @@ -1,20 +1,18 @@ +import { useState } from 'react'; import { faArrowsRotate, faPaperPlane, IconDefinition } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useState } from 'react'; - -import { MvxButton, useGetPendingTransactionsSessions } from 'lib'; import { OutputContainer, TransactionsOutput } from 'components'; +import { MvxButton, useGetPendingTransactionsSessions } from 'lib'; import { useGetAccount, useGetNetworkConfig, useGetPendingTransactions } from 'lib'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; - import { signAndAutoSendBatchTransactions, swapAndLockTokens, diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts index bd258851..ab4938bd 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getBatchTransactions.ts @@ -1,5 +1,4 @@ import BigNumber from 'bignumber.js'; - import { Address, Transaction, diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getWrapAndMultiTransferTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getWrapAndMultiTransferTransactions.ts index 8e67cdbd..f21d91fc 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/getWrapAndMultiTransferTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/getWrapAndMultiTransferTransactions.ts @@ -7,11 +7,10 @@ import { TransferTransactionsFactory, U32Value } from '@multiversx/sdk-core/out'; - import { BATCH_TRANSACTIONS_SC } from 'config'; +import { contractAddress } from 'config'; import { Address } from 'lib'; import { TransactionProps } from 'types'; -import { contractAddress } from 'config'; export const getWrapAndMultiTransferTransactions = async ({ address, diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts index a4c9b76a..8bdd28a6 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/signAndAutoSendBatchTransactions.ts @@ -1,6 +1,5 @@ import { getAccountProvider, TransactionsDisplayInfoType } from 'lib'; import { TransactionProps } from 'types'; - import { getBatchTransactions } from './getBatchTransactions'; import { sendAndTrackTransactions } from './sendAndTrackTransactions'; diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts index 6418308c..ab004916 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/swapAndLockTokens.ts @@ -1,15 +1,13 @@ import { createRoot } from 'react-dom/client'; - import { getAccountProvider, ToastManager, TransactionsDisplayInfoType } from 'lib'; import { TransactionProps } from 'types'; - +import { ToastContent } from '../components'; import { getSwapAndLockTransactions } from './getSwapAndLockTransactions'; import { sendAndTrackTransactions } from './sendAndTrackTransactions'; -import { ToastContent } from '../components'; export const swapAndLockTokens = async ({ address, diff --git a/src/pages/Dashboard/widgets/BatchTransactions/helpers/wrapAndMultiTransferTransactions.ts b/src/pages/Dashboard/widgets/BatchTransactions/helpers/wrapAndMultiTransferTransactions.ts index c94a4a65..41e52188 100644 --- a/src/pages/Dashboard/widgets/BatchTransactions/helpers/wrapAndMultiTransferTransactions.ts +++ b/src/pages/Dashboard/widgets/BatchTransactions/helpers/wrapAndMultiTransferTransactions.ts @@ -4,9 +4,8 @@ import { TransactionsDisplayInfoType } from 'lib'; import { TransactionProps } from 'types'; - -import { sendAndTrackTransactions } from './sendAndTrackTransactions'; import { getWrapAndMultiTransferTransactions } from './getWrapAndMultiTransferTransactions'; +import { sendAndTrackTransactions } from './sendAndTrackTransactions'; interface WrapAndMultiTransferTransactionsType extends TransactionProps { transactionsDisplayInfo?: TransactionsDisplayInfoType; diff --git a/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx b/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx index 9b12b66a..38f593f2 100644 --- a/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx +++ b/src/pages/Dashboard/widgets/NativeAuth/NativeAuth.tsx @@ -1,5 +1,4 @@ import { useEffect } from 'react'; - import { Label, MissingNativeAuthError, OutputContainer } from 'components'; import { ACCOUNTS_ENDPOINT, @@ -11,7 +10,6 @@ import { } from 'lib'; import { Username } from 'pages/Dashboard/components/LeftPanel/components/Account/components'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; - import { useGetProfile } from './hooks'; // prettier-ignore diff --git a/src/pages/Dashboard/widgets/NativeAuth/hooks/useGetProfile.ts b/src/pages/Dashboard/widgets/NativeAuth/hooks/useGetProfile.ts index 1d02bc0b..97c99839 100644 --- a/src/pages/Dashboard/widgets/NativeAuth/hooks/useGetProfile.ts +++ b/src/pages/Dashboard/widgets/NativeAuth/hooks/useGetProfile.ts @@ -1,6 +1,5 @@ import axios from 'axios'; import { useState } from 'react'; - import { API_URL } from 'config'; import { ProfileType } from 'types'; diff --git a/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx b/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx index 1e6a4814..f5680f37 100644 --- a/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx +++ b/src/pages/Dashboard/widgets/PingPongAbi/PingPongAbi.tsx @@ -1,6 +1,5 @@ import { PingPongComponent, PingTransactionPayloadType } from 'components'; import { useSendPingPongTransaction } from 'hooks'; - import { useGetPingAmount, useGetTimeToPong } from './hooks'; export const PingPongAbi = () => { diff --git a/src/pages/Dashboard/widgets/PingPongAbi/hooks/useGetPingAmount.ts b/src/pages/Dashboard/widgets/PingPongAbi/hooks/useGetPingAmount.ts index 27f22e2e..75300c1f 100644 --- a/src/pages/Dashboard/widgets/PingPongAbi/hooks/useGetPingAmount.ts +++ b/src/pages/Dashboard/widgets/PingPongAbi/hooks/useGetPingAmount.ts @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react'; - import { contractAddress } from 'config'; import pingPongAbi from 'contracts/ping-pong.abi.json'; import { diff --git a/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx b/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx index 344dd323..043545a0 100644 --- a/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx +++ b/src/pages/Dashboard/widgets/PingPongRaw/PingPongRaw.tsx @@ -1,6 +1,5 @@ import { PingPongComponent, PingTransactionPayloadType } from 'components'; import { useSendPingPongTransaction } from 'hooks'; - import { useGetPingAmount, useGetTimeToPong } from './hooks'; // Raw transaction are being done by directly requesting to API instead of calling the smartcontract diff --git a/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetPingAmount.ts b/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetPingAmount.ts index 80d19603..e18867c8 100644 --- a/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetPingAmount.ts +++ b/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetPingAmount.ts @@ -1,10 +1,8 @@ import axios from 'axios'; import BigNumber from 'bignumber.js'; import { useEffect, useState } from 'react'; - import { contractAddress } from 'config'; import { useGetNetworkConfig } from 'lib'; - import { PingPongResponseType } from '../types'; const decodeAmount = (data: PingPongResponseType) => { diff --git a/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetTimeToPong.ts b/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetTimeToPong.ts index 6b065dba..d887dc48 100644 --- a/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetTimeToPong.ts +++ b/src/pages/Dashboard/widgets/PingPongRaw/hooks/useGetTimeToPong.ts @@ -1,9 +1,7 @@ import axios from 'axios'; import BigNumber from 'bignumber.js'; - import { contractAddress } from 'config'; import { Address, useGetAccount, useGetNetworkConfig } from 'lib'; - import { PingPongResponseType } from '../types'; const decodeTime = (data: PingPongResponseType) => { diff --git a/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx b/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx index fcb5fbc3..bda27f12 100644 --- a/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx +++ b/src/pages/Dashboard/widgets/PingPongService/PingPongService.tsx @@ -1,7 +1,6 @@ import { PingPongComponent, PingTransactionPayloadType } from 'components'; import { useSendPingPongTransaction } from 'hooks'; import { useGetLoginInfo } from 'lib'; - import { useGetPingTransaction, useGetPongTransaction, diff --git a/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPingTransaction.test.ts b/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPingTransaction.test.ts index dc6641bb..add8bd74 100644 --- a/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPingTransaction.test.ts +++ b/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPingTransaction.test.ts @@ -1,6 +1,5 @@ import { renderHook } from '@testing-library/react'; import axios from 'axios'; - import { useGetPingTransaction } from '../useGetPingTransaction'; const pingTransaction = { @@ -24,7 +23,12 @@ describe('useGetPingTransaction', () => { const { result } = renderHook(() => useGetPingTransaction()); const transactionReceived = await result.current(); - expect(transactionReceived).toBe(pingTransaction); + expect(transactionReceived).not.toBeNull(); + + if (transactionReceived) { + const plainTx = transactionReceived.toPlainObject(); + expect(plainTx.data).toBe(pingTransaction.data); + } }); it('should return null', async () => { diff --git a/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPongTransaction.test.ts b/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPongTransaction.test.ts index fc41faec..0059e138 100644 --- a/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPongTransaction.test.ts +++ b/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetPongTransaction.test.ts @@ -1,6 +1,5 @@ import { renderHook } from '@testing-library/react'; import axios from 'axios'; - import { useGetPongTransaction } from '../useGetPongTransaction'; const pongTransaction = { @@ -24,7 +23,12 @@ describe('useGetPongTransaction', () => { const { result } = renderHook(() => useGetPongTransaction()); const transactionReceived = await result.current(); - expect(transactionReceived).toBe(pongTransaction); + expect(transactionReceived).not.toBeNull(); + + if (transactionReceived) { + const plainTx = transactionReceived.toPlainObject(); + expect(plainTx.data).toBe(pongTransaction.data); + } }); it('should return null', async () => { diff --git a/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetTimeToPong.test.ts b/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetTimeToPong.test.ts index 367cd535..63e34053 100644 --- a/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetTimeToPong.test.ts +++ b/src/pages/Dashboard/widgets/PingPongService/hooks/tests/useGetTimeToPong.test.ts @@ -1,6 +1,5 @@ import { renderHook } from '@testing-library/react'; import axios from 'axios'; - import { useGetTimeToPong } from '../useGetTimeToPong'; describe('useGetTimeToPong', () => { diff --git a/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPingTransaction.ts b/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPingTransaction.ts index 1e34bf8c..4b4c718c 100644 --- a/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPingTransaction.ts +++ b/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPingTransaction.ts @@ -1,5 +1,4 @@ import axios from 'axios'; - import { API_URL } from 'config'; import { Transaction } from 'lib'; diff --git a/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPongTransaction.ts b/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPongTransaction.ts index 8ddf59e5..e93297f9 100644 --- a/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPongTransaction.ts +++ b/src/pages/Dashboard/widgets/PingPongService/hooks/useGetPongTransaction.ts @@ -1,5 +1,4 @@ import axios from 'axios'; - import { API_URL } from 'config'; import { Transaction } from 'lib'; diff --git a/src/pages/Dashboard/widgets/PingPongService/hooks/useGetTimeToPong.ts b/src/pages/Dashboard/widgets/PingPongService/hooks/useGetTimeToPong.ts index cb4e8773..e6d46ab1 100644 --- a/src/pages/Dashboard/widgets/PingPongService/hooks/useGetTimeToPong.ts +++ b/src/pages/Dashboard/widgets/PingPongService/hooks/useGetTimeToPong.ts @@ -1,7 +1,5 @@ import axios from 'axios'; - import { API_URL } from 'config'; - import { TimeToPongResponseType } from '../types'; export const useGetTimeToPong = () => { diff --git a/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx b/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx index 4930b72d..59b70125 100644 --- a/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx +++ b/src/pages/Dashboard/widgets/SignMessage/SignMessage.tsx @@ -7,11 +7,9 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { MvxButton } from '@multiversx/sdk-dapp-ui/react'; import { MouseEvent, useState } from 'react'; - import { OutputContainer } from 'components'; import { Address, getAccountProvider, Message, useGetAccount } from 'lib'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; - import { SignFailure, SignSuccess } from './components'; // prettier-ignore diff --git a/src/pages/Dashboard/widgets/SignMessage/components/SignFailure.tsx b/src/pages/Dashboard/widgets/SignMessage/components/SignFailure.tsx index 88f86c0a..f27e4393 100644 --- a/src/pages/Dashboard/widgets/SignMessage/components/SignFailure.tsx +++ b/src/pages/Dashboard/widgets/SignMessage/components/SignFailure.tsx @@ -1,4 +1,3 @@ -// prettier-ignore const styles = { signFailureContainer: 'sign-failure-container flex flex-col', signFailureErrorMessage: 'sign-failure-error-message flex gap-1' diff --git a/src/pages/Dashboard/widgets/SignMessage/components/SignSuccess.tsx b/src/pages/Dashboard/widgets/SignMessage/components/SignSuccess.tsx index 3e47d96e..a74a49db 100644 --- a/src/pages/Dashboard/widgets/SignMessage/components/SignSuccess.tsx +++ b/src/pages/Dashboard/widgets/SignMessage/components/SignSuccess.tsx @@ -1,7 +1,6 @@ import { Label } from 'components'; import { CopyButton, Message } from 'lib'; import { DataTestIdsEnum } from 'localConstants'; - import { decodeMessage } from '../helpers'; // prettier-ignore diff --git a/src/pages/Dashboard/widgets/SignMessage/helpers/tests/decodeMessage.test.ts b/src/pages/Dashboard/widgets/SignMessage/helpers/tests/decodeMessage.test.ts index 0a05085d..2441251b 100644 --- a/src/pages/Dashboard/widgets/SignMessage/helpers/tests/decodeMessage.test.ts +++ b/src/pages/Dashboard/widgets/SignMessage/helpers/tests/decodeMessage.test.ts @@ -1,5 +1,4 @@ import { Message } from '@multiversx/sdk-core/out'; - import { decodeMessage } from '../decodeMessage'; const signature = diff --git a/src/pages/Dashboard/widgets/Transactions/Transactions.tsx b/src/pages/Dashboard/widgets/Transactions/Transactions.tsx index 9825081f..fb6f0f68 100644 --- a/src/pages/Dashboard/widgets/Transactions/Transactions.tsx +++ b/src/pages/Dashboard/widgets/Transactions/Transactions.tsx @@ -3,7 +3,6 @@ import { useEffect } from 'react'; import { OutputContainer, TransactionsTable } from 'components'; import { getActiveTransactionsStatus } from 'lib'; import { ItemsIdentifiersEnum } from 'pages/Dashboard/dashboard.types'; - import { useGetTransactions } from './hooks'; // prettier-ignore diff --git a/src/pages/Dashboard/widgets/Transactions/hooks/useGetTransactions.ts b/src/pages/Dashboard/widgets/Transactions/hooks/useGetTransactions.ts index 63e1c7f4..22fb9717 100644 --- a/src/pages/Dashboard/widgets/Transactions/hooks/useGetTransactions.ts +++ b/src/pages/Dashboard/widgets/Transactions/hooks/useGetTransactions.ts @@ -1,5 +1,4 @@ import { useState } from 'react'; - import { apiTimeout, transactionSize } from 'config'; import { getInterpretedTransaction, @@ -8,7 +7,6 @@ import { useGetAccount, useGetNetworkConfig } from 'lib'; - import { TransactionsPropsType } from '../Transactions'; export const useGetTransactions = (payload?: TransactionsPropsType) => { @@ -33,8 +31,9 @@ export const useGetTransactions = (payload?: TransactionsPropsType) => { ...(payload ?? {}) }); - const interpretedTransactions = data.map((transaction) => - getInterpretedTransaction({ transaction, address, explorerAddress }) + const interpretedTransactions = data.map( + (transaction: ServerTransactionType) => + getInterpretedTransaction({ transaction, address, explorerAddress }) ); setTransactions(interpretedTransactions); diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx index 0b794669..633b0a83 100644 --- a/src/pages/Home/Home.tsx +++ b/src/pages/Home/Home.tsx @@ -1,7 +1,6 @@ import { Outlet } from 'react-router-dom'; - -import { HomeHero } from './components/HomeHero'; import { HomeConnect } from './components/HomeConnect'; +import { HomeHero } from './components/HomeHero'; // prettier-ignore const styles = { diff --git a/src/pages/Home/components/HomeConnect/components/ExtensionConnect/ExtensionConnect.tsx b/src/pages/Home/components/HomeConnect/components/ExtensionConnect/ExtensionConnect.tsx index 46a66cbf..21cd4e93 100644 --- a/src/pages/Home/components/HomeConnect/components/ExtensionConnect/ExtensionConnect.tsx +++ b/src/pages/Home/components/HomeConnect/components/ExtensionConnect/ExtensionConnect.tsx @@ -1,7 +1,6 @@ import { faArrowRightLong } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FunctionComponent, SVGProps } from 'react'; - import { ReactComponent as ArcLogo } from 'assets/img/arc-logo.svg'; import { ReactComponent as BraveLogo } from 'assets/img/brave-logo.svg'; import { ReactComponent as ChromeLogo } from 'assets/img/chrome-logo.svg'; @@ -12,9 +11,8 @@ import { ReactComponent as WalletBraveLogo } from 'assets/img/wallet-brave-logo. import { ReactComponent as WalletChromeLogo } from 'assets/img/wallet-chrome-logo.svg'; import { ReactComponent as WalletFirefoxLogo } from 'assets/img/wallet-firefox-logo.svg'; import { ReactComponent as WalletIcon } from 'assets/img/web-wallet-icon.svg'; -import { CHROME_EXTENSION_LINK, FIREFOX_ADDON_LINK } from 'localConstants'; import { BrowserEnum, getDetectedBrowser } from 'lib'; - +import { CHROME_EXTENSION_LINK, FIREFOX_ADDON_LINK } from 'localConstants'; import { BrowserFrame } from './components'; import styles from './extensionConnect.styles'; diff --git a/src/pages/Home/components/HomeHero/HomeHero.tsx b/src/pages/Home/components/HomeHero/HomeHero.tsx index 19e11bef..7ecc2706 100644 --- a/src/pages/Home/components/HomeHero/HomeHero.tsx +++ b/src/pages/Home/components/HomeHero/HomeHero.tsx @@ -1,18 +1,16 @@ +import classNames from 'classnames'; import { Fragment, FunctionComponent, MouseEvent, SVGProps } from 'react'; -import { ReactComponent as ArrowUpRightIcon } from 'assets/icons/arrow-up-right-icon.svg'; import { useNavigate } from 'react-router-dom'; -import classNames from 'classnames'; - -import { - useHandleThemeManagement, - ThemeOptionType -} from 'hooks/useHandleThemeManagement'; +import { ReactComponent as ArrowUpRightIcon } from 'assets/icons/arrow-up-right-icon.svg'; +import { ReactComponent as HomeDarkThemeIcon } from 'assets/icons/home-dark-theme-icon.svg'; import { ReactComponent as HomeLightThemeIcon } from 'assets/img/bright-light-icon.svg'; import { ReactComponent as HomeVibeThemeIcon } from 'assets/img/vibe-mode-icon.svg'; -import { ReactComponent as HomeDarkThemeIcon } from 'assets/icons/home-dark-theme-icon.svg'; import { Button } from 'components'; +import { + ThemeOptionType, + useHandleThemeManagement +} from 'hooks/useHandleThemeManagement'; import { DOCUMENTATION_LINK, RouteNamesEnum } from 'localConstants'; - import styles from './homeHero.styles'; interface HomeThemeOptionType extends ThemeOptionType { diff --git a/src/pages/Unlock/Unlock.tsx b/src/pages/Unlock/Unlock.tsx index cb053740..88fb046e 100644 --- a/src/pages/Unlock/Unlock.tsx +++ b/src/pages/Unlock/Unlock.tsx @@ -1,6 +1,5 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; - import { UnlockPanelManager, useGetLoginInfo } from 'lib'; import { RouteNamesEnum } from 'localConstants'; diff --git a/src/provider/inMemoryProvider.ts b/src/provider/inMemoryProvider.ts index d206bd02..7722717d 100644 --- a/src/provider/inMemoryProvider.ts +++ b/src/provider/inMemoryProvider.ts @@ -10,7 +10,6 @@ import { UserSecretKey, UserSigner } from 'lib'; - import { LoginModal } from './LoginModal'; const notInitializedError = (caller: string) => () => { diff --git a/src/wrappers/AuthRedirectWrapper/AuthRedirectWrapper.tsx b/src/wrappers/AuthRedirectWrapper/AuthRedirectWrapper.tsx index 87c69c74..1094a620 100644 --- a/src/wrappers/AuthRedirectWrapper/AuthRedirectWrapper.tsx +++ b/src/wrappers/AuthRedirectWrapper/AuthRedirectWrapper.tsx @@ -1,6 +1,5 @@ import { PropsWithChildren, useEffect } from 'react'; import { matchPath, useLocation, useNavigate } from 'react-router-dom'; - import { useGetIsLoggedIn } from 'lib'; import { RouteNamesEnum } from 'localConstants'; import { routes } from 'routes'; diff --git a/src/wrappers/AxiosInterceptors/AxiosInterceptors.tsx b/src/wrappers/AxiosInterceptors/AxiosInterceptors.tsx index 7c748ac8..45028336 100644 --- a/src/wrappers/AxiosInterceptors/AxiosInterceptors.tsx +++ b/src/wrappers/AxiosInterceptors/AxiosInterceptors.tsx @@ -1,5 +1,4 @@ import { PropsWithChildren, useEffect } from 'react'; - import { sampleAuthenticatedDomains } from 'config'; import { setAxiosInterceptors, useGetLoginInfo } from 'lib'; diff --git a/tests/ConnectWallet/memoryProvider.spec.ts b/tests/ConnectWallet/memoryProvider.spec.ts index e930a9c1..92426bf4 100644 --- a/tests/ConnectWallet/memoryProvider.spec.ts +++ b/tests/ConnectWallet/memoryProvider.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { readValueFromFile } from '../support'; -import { SelectorsEnum, TestDataEnums } from '../support/testdata'; +import * as TestActions from '../support/template'; +import { readValueFromFile } from '../support/template'; +import { SelectorsEnum, TestDataEnums } from '../support/template/testdata'; const privateKeyConfig = { address: TestDataEnums.keystoreWalletAddress6, diff --git a/tests/ConnectWallet/metaMask.spec.ts b/tests/ConnectWallet/metaMask.spec.ts new file mode 100644 index 00000000..a6a89272 --- /dev/null +++ b/tests/ConnectWallet/metaMask.spec.ts @@ -0,0 +1,167 @@ +import { BrowserContext, expect, Page, test } from '@playwright/test'; +import { setupMetaMaskWallet } from '../support/metaMask/setupMetaMaskWallet'; +import * as TestActions from '../support/template'; +import { getPageAndWaitForLoad } from '../support/template/getPageAndWaitForLoad'; +import { + OriginPageEnum, + SelectorsEnum, + UrlRegex +} from '../support/template/testdata'; + +// TODO: Load variables from .env.test.local when running locally +// Get password and address from environment variables +const METAMASK_MNEMONIC = process.env.METAMASK_MNEMONIC || ''; +const METAMASK_ADDRESS = process.env.METAMASK_ADDRESS || ''; +const METAMASK_PASSWORD = process.env.METAMASK_PASSWORD || ''; + +// Validate that required environment variables are present +if (!METAMASK_PASSWORD || !METAMASK_ADDRESS || !METAMASK_MNEMONIC) { + throw new Error( + 'METAMASK_PASSWORD, METAMASK_MNEMONIC, and METAMASK_ADDRESS environment variables are missing. Please set them in .env.test.local for local development or as a GitHub Secret for CI.' + ); +} + +test.describe('Connect a wallet', () => { + let metamaskContext: BrowserContext; + let extensionId: string; + let dAppPage: Page; + + test.beforeEach(async () => { + // Setup MetaMask for each test + const result = await setupMetaMaskWallet( + METAMASK_MNEMONIC, + METAMASK_PASSWORD + ); + metamaskContext = result.context; + extensionId = result.extensionId; + + // Create a page in the MetaMask context for the dApp + dAppPage = await metamaskContext.newPage(); + await TestActions.navigateToConnectWallet(dAppPage); + }); + + test.afterEach(async () => { + // Close the browser context to free up resources + if (metamaskContext) { + try { + await metamaskContext.close(); + // Wait a moment to ensure the context is fully closed + // Persistent contexts need a bit more time to release the userDataDir lock + await new Promise((resolve) => setTimeout(resolve, 2000)); + } catch (error) { + // Context might already be closed, ignore the error + } + } + }); + + test.describe('MetaMask Connection', () => { + test('should successfully connect with MetaMask', async () => { + // Use the MetaMask context and dApp page from beforeEach + const context = metamaskContext; + const page = dAppPage; + + // Click the connect MetaMask button + await page.getByTestId('metamask').click(); + + // Get the notification page and wait for it to load in the MetaMask context + const notificationPage = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/notification.html`, + { + viewport: { width: 360, height: 592 } + } + ); + + // Handle MetaMask Snap privacy warning + await TestActions.handleMetaMaskSnap( + context, + extensionId, + notificationPage + ); + + // Switch to template page + const templatePage = await getPageAndWaitForLoad( + context, + OriginPageEnum.templateDashboard + ); + + // Verify template page opened + await expect(templatePage).toHaveURL(UrlRegex.templateDashboard); + + // Verify connection using TestActions helper + await TestActions.checkConnectionToWallet(page, METAMASK_ADDRESS); + }); + + test('should display all connected account details correctly', async () => { + // Use the MetaMask context and dApp page from beforeEach + const context = metamaskContext; + const page = dAppPage; + + // Click the connect MetaMask button + await page.getByTestId('metamask').click(); + + // Get the notification page and wait for it to load in the MetaMask context + const notificationPage = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/notification.html`, + { + viewport: { width: 360, height: 592 } + } + ); + + // Handle MetaMask Snap privacy warning + await TestActions.handleMetaMaskSnap( + context, + extensionId, + notificationPage + ); + + // Switch to template page + const templatePage = await getPageAndWaitForLoad( + context, + OriginPageEnum.templateDashboard + ); + + // Verify template page opened + await expect(templatePage).toHaveURL(UrlRegex.templateDashboard); + + // Verify connection using TestActions helper + await TestActions.checkConnectionToWallet(page, METAMASK_ADDRESS); + + // Verify the topInfo container is visible + const topInfoContainer = page.getByTestId(SelectorsEnum.topInfoContainer); + await expect(topInfoContainer).toBeVisible(); + + // Verify account address is displayed + const addressElement = topInfoContainer + .getByTestId(SelectorsEnum.accountAddress) + .getByTestId(SelectorsEnum.trimFullAddress); + await expect(addressElement).toBeVisible(); + await expect(addressElement).toContainText(METAMASK_ADDRESS); + + // Verify herotag section is present and should be N/A + const herotagElement = topInfoContainer.getByTestId( + SelectorsEnum.heroTag + ); + await expect(herotagElement).toBeVisible(); + await expect(herotagElement).toContainText('N/A'); + + // Verify shard information is displayed + const shardElement = topInfoContainer.getByTestId(SelectorsEnum.shard); + await expect(shardElement).toBeVisible(); + // Shard should contain a number (0, 1, or 2) + const shardText = await shardElement.textContent(); + expect(shardText).toMatch(/^[0-2]$/); + + // Verify balance is displayed and extract the value + const balance = await TestActions.extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.topInfoContainer, + selectorType: 'testId' + }); + + // Verify balance is a positive number + expect(balance).toBeGreaterThan(0); + }); + }); +}); diff --git a/tests/ConnectWallet/webWallet.spec.ts b/tests/ConnectWallet/webWallet.spec.ts index bc7b8b01..a33442d2 100644 --- a/tests/ConnectWallet/webWallet.spec.ts +++ b/tests/ConnectWallet/webWallet.spec.ts @@ -1,6 +1,6 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { SelectorsEnum, TestDataEnums } from '../support/testdata'; +import * as TestActions from '../support/template'; +import { SelectorsEnum, TestDataEnums } from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath1, diff --git a/tests/Other/CancelTransactionFromSidePanel.spec.ts b/tests/Other/CancelTransactionFromSidePanel.spec.ts index 92554e1e..d6145bd2 100644 --- a/tests/Other/CancelTransactionFromSidePanel.spec.ts +++ b/tests/Other/CancelTransactionFromSidePanel.spec.ts @@ -1,7 +1,7 @@ import { test } from '@playwright/test'; -import * as TestActions from '../support'; -import { readValueFromFile } from '../support'; -import { SelectorsEnum, TestDataEnums } from '../support/testdata'; +import * as TestActions from '../support/template'; +import { readValueFromFile } from '../support/template'; +import { SelectorsEnum, TestDataEnums } from '../support/template/testdata'; const privateKeyConfig = { address: TestDataEnums.keystoreWalletAddress6, @@ -53,8 +53,11 @@ test.describe('cancel transaction from side panel', () => { // Wait for side panel to be visible await page.locator(SelectorsEnum.sidePanel).waitFor({ state: 'visible' }); - // Cancel the transaction from the modal close button - await page.locator(SelectorsEnum.sidePanelCloseIcon).click(); + // Click the close icon + await page + .locator(SelectorsEnum.sidePanel) + .locator(SelectorsEnum.sidePanelCloseIcon) + .click(); // Wait for toast to be displayed await TestActions.waitForToastToBeDisplayed(page); diff --git a/tests/Other/CancelTransactionFromWallet.spec.ts b/tests/Other/CancelTransactionFromWallet.spec.ts index 6d011a8b..6308ef09 100644 --- a/tests/Other/CancelTransactionFromWallet.spec.ts +++ b/tests/Other/CancelTransactionFromWallet.spec.ts @@ -1,10 +1,11 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; +import * as TestActions from '../support/template'; import { OriginPageEnum, SelectorsEnum, - TestDataEnums -} from '../support/testdata'; + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath3, @@ -30,11 +31,11 @@ test.describe('cancel transaction from wallet window', () => { await page.getByTestId(SelectorsEnum.signAndBatchButton).click(); // Switch to web wallet page - const walletPage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); - await expect(walletPage).toHaveURL(/devnet-wallet\.multiversx\.com/); + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet); // Cancel the transaction from the wallet window await walletPage @@ -42,10 +43,10 @@ test.describe('cancel transaction from wallet window', () => { .click(); // Switch back to template dashboard and verify a toast is shown - const templatePage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.templateDashboard - }); + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); // Wait for toast to be displayed await TestActions.waitForToastToBeDisplayed(templatePage); diff --git a/tests/SidePanel/memoryProvider.spec.ts b/tests/SidePanel/memoryProvider.spec.ts index bf497c4b..932be7ce 100644 --- a/tests/SidePanel/memoryProvider.spec.ts +++ b/tests/SidePanel/memoryProvider.spec.ts @@ -1,11 +1,11 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { readValueFromFile } from '../support'; +import * as TestActions from '../support/template'; +import { readValueFromFile } from '../support/template'; import { PingPongEnum, SelectorsEnum, TestDataEnums -} from '../support/testdata'; +} from '../support/template/testdata'; const privateKeyConfig = { address: TestDataEnums.keystoreWalletAddress6, diff --git a/tests/TemplateActions/nativeAuth.spec.ts b/tests/TemplateActions/nativeAuth.spec.ts index e09b2eaa..6c381f1d 100644 --- a/tests/TemplateActions/nativeAuth.spec.ts +++ b/tests/TemplateActions/nativeAuth.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { extractBalanceFromContainer } from '../support'; -import { SelectorsEnum, TestDataEnums } from '../support/testdata'; +import * as TestActions from '../support/template'; +import { extractBalanceFromContainer } from '../support/template'; +import { SelectorsEnum, TestDataEnums } from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath1, diff --git a/tests/TemplateActions/pingAndPongAbi.spec.ts b/tests/TemplateActions/pingAndPongAbi.spec.ts index 08f0fb90..8568b970 100644 --- a/tests/TemplateActions/pingAndPongAbi.spec.ts +++ b/tests/TemplateActions/pingAndPongAbi.spec.ts @@ -1,12 +1,13 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { TEST_CONSTANTS } from '../support/constants'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; import { OriginPageEnum, PingPongEnum, SelectorsEnum, - TestDataEnums -} from '../support/testdata'; + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; const pemConfig = { pem: TestDataEnums.keystoreFilePath5 @@ -96,13 +97,13 @@ test.describe('Ping & Pong (ABI)', () => { }); // Switch to web wallet page - const walletPage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); // Verify wallet page opened - await expect(walletPage).toHaveURL(/devnet-wallet\.multiversx\.com/); + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet); // Sign transaction by confirming with pem await TestActions.confirmWalletTransaction(walletPage, pemConfig); @@ -111,10 +112,10 @@ test.describe('Ping & Pong (ABI)', () => { await walletPage.getByTestId(SelectorsEnum.signButton).click(); // Switch to template dashboard page - const templatePage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.templateDashboard - }); + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); // Wait for transaction toast to be displayed await TestActions.waitForToastToBeDisplayed(templatePage); diff --git a/tests/TemplateActions/signAndSendBatch.spec.ts b/tests/TemplateActions/signAndSendBatch.spec.ts index 476de220..18ef5459 100644 --- a/tests/TemplateActions/signAndSendBatch.spec.ts +++ b/tests/TemplateActions/signAndSendBatch.spec.ts @@ -1,11 +1,12 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { TEST_CONSTANTS } from '../support/constants'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; import { OriginPageEnum, SelectorsEnum, - TestDataEnums -} from '../support/testdata'; + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath2, @@ -49,9 +50,9 @@ test.describe('Sign & send batch', () => { .locator(SelectorsEnum.batchTransactionsContainer) .waitFor({ state: 'visible' }); - // Verify batch transactions container is in viewport + // Verify batch transactions container is visible const container = page.locator(SelectorsEnum.batchTransactionsContainer); - await expect(container).toBeInViewport(); + await expect(container).toBeVisible(); }); test('should complete full batch transaction flow', async ({ page }) => { @@ -65,13 +66,13 @@ test.describe('Sign & send batch', () => { await page.getByTestId(SelectorsEnum.signAndBatchButton).click(); // Switch to web wallet page - const walletPage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); // Verify wallet page opened - await expect(walletPage).toHaveURL(/devnet-wallet\.multiversx\.com/); + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet); // Sign transaction by confirming with keystore in the web wallet await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); @@ -84,10 +85,10 @@ test.describe('Sign & send batch', () => { }); // Switch to template page - const templatePage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.templateDashboard - }); + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); // Wait for transaction toast to be displayed await TestActions.waitForToastToBeDisplayed(templatePage); diff --git a/tests/TemplateActions/signMessage.spec.ts b/tests/TemplateActions/signMessage.spec.ts index fb34ecca..7cf03c60 100644 --- a/tests/TemplateActions/signMessage.spec.ts +++ b/tests/TemplateActions/signMessage.spec.ts @@ -1,10 +1,11 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; +import * as TestActions from '../support/template'; import { OriginPageEnum, SelectorsEnum, - TestDataEnums -} from '../support/testdata'; + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath1, @@ -73,13 +74,13 @@ test.describe('Sign Message', () => { await page.getByTestId(SelectorsEnum.signMsgButton).click(); // Switch to web wallet page - const walletPage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); // Verify wallet page opened - await expect(walletPage).toHaveURL(/devnet-wallet\.multiversx\.com/); + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet); // Sign transaction by confirming with keystore in the web wallet await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); @@ -88,16 +89,16 @@ test.describe('Sign Message', () => { await walletPage.getByTestId(SelectorsEnum.signMsgWalletButton).click(); // Switch to template dashboard page - const templatePage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.templateDashboard - }); + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); // Verify the decoded message matches the original message const decodedMessage = templatePage.getByTestId( SelectorsEnum.decodedMessage ); await expect(decodedMessage).toBeVisible(); - await expect(decodedMessage).toHaveValue(message); + await expect(decodedMessage).toHaveText(message); }); }); diff --git a/tests/TemplateActions/swapAndLock.ts b/tests/TemplateActions/swapAndLock.ts index 71677c69..d51c006e 100644 --- a/tests/TemplateActions/swapAndLock.ts +++ b/tests/TemplateActions/swapAndLock.ts @@ -1,11 +1,12 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { TEST_CONSTANTS } from '../support/constants'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; import { OriginPageEnum, SelectorsEnum, - TestDataEnums -} from '../support/testdata'; + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath3, @@ -49,9 +50,9 @@ test.describe('Swap & Lock', () => { .locator(SelectorsEnum.batchTransactionsContainer) .waitFor({ state: 'visible' }); - // Verify batch transactions container is in viewport + // Verify batch transactions container is visible const container = page.locator(SelectorsEnum.batchTransactionsContainer); - await expect(container).toBeInViewport(); + await expect(container).toBeVisible(); }); test('should complete full swap and lock transaction flow', async ({ @@ -69,13 +70,13 @@ test.describe('Swap & Lock', () => { await page.getByTestId(SelectorsEnum.swapAndLockButton).click(); // Switch to web wallet page - const walletPage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); // Verify wallet page opened - await expect(walletPage).toHaveURL(/devnet-wallet\.multiversx\.com/); + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet); // Sign transaction by confirming with keystore in the web wallet await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); @@ -88,10 +89,10 @@ test.describe('Swap & Lock', () => { }); // Switch to template page - const templatePage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.templateDashboard - }); + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); // Wait for transaction toast to be displayed await TestActions.waitForToastToBeDisplayed(templatePage); diff --git a/tests/TemplateActions/wrapAndMultiTransfer.spec.ts b/tests/TemplateActions/wrapAndMultiTransfer.spec.ts index 9b9cb234..121bfdd2 100644 --- a/tests/TemplateActions/wrapAndMultiTransfer.spec.ts +++ b/tests/TemplateActions/wrapAndMultiTransfer.spec.ts @@ -1,11 +1,12 @@ import { expect, test } from '@playwright/test'; -import * as TestActions from '../support'; -import { TEST_CONSTANTS } from '../support/constants'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; import { OriginPageEnum, SelectorsEnum, - TestDataEnums -} from '../support/testdata'; + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; const keystoreConfig = { keystore: TestDataEnums.keystoreFilePath4, @@ -49,9 +50,9 @@ test.describe('Wrap & Multi-Transfer', async () => { .locator(SelectorsEnum.batchTransactionsContainer) .waitFor({ state: 'visible' }); - // Verify batch transactions container is in viewport + // Verify batch transactions container is visible const container = page.locator(SelectorsEnum.batchTransactionsContainer); - await expect(container).toBeInViewport(); + await expect(container).toBeVisible(); }); test('should complete full batch transaction flow', async ({ page }) => { @@ -65,13 +66,13 @@ test.describe('Wrap & Multi-Transfer', async () => { await page.getByTestId(SelectorsEnum.wrapAndMultiTransferButton).click(); // Switch to web wallet page - const walletPage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); // Verify wallet page opened - await expect(walletPage).toHaveURL(/devnet-wallet\.multiversx\.com/); + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet); // Sign transaction by confirming with keystore in the web wallet await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); @@ -84,10 +85,10 @@ test.describe('Wrap & Multi-Transfer', async () => { }); // Switch to template page - const templatePage = await TestActions.waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.templateDashboard - }); + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); // Wait for transaction toast to be displayed await TestActions.waitForToastToBeDisplayed(templatePage); diff --git a/tests/config.ts b/tests/config.ts index 721e08b1..d5f883f8 100644 --- a/tests/config.ts +++ b/tests/config.ts @@ -4,9 +4,9 @@ export const TEST_CONFIG = { /* Parallel tests on CI only. */ workers: 10, /* Timeout for each test */ - timeout: 90_000, + timeout: 120_000, /* Timeout for locators */ expectTimeout: 60_000, /* Run tests in files in parallel */ - fullyParallel: true + fullyParallel: false } as const; diff --git a/tests/support/fs/downloadFileFromUrl.ts b/tests/support/fs/downloadFileFromUrl.ts new file mode 100644 index 00000000..53610b00 --- /dev/null +++ b/tests/support/fs/downloadFileFromUrl.ts @@ -0,0 +1,63 @@ +import { createWriteStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { pipeline } from 'stream/promises'; +import axios from 'axios'; + +type DownloaderOptions = { + url: string; + outputDir: string; + fileName: string; + overrideFile?: boolean; +}; + +type DownloadFileResult = { + filePath: string; + downloadSkipped: boolean; +}; + +export async function downloadFileFromUrl( + options: DownloaderOptions +): Promise { + try { + const { url, outputDir, fileName, overrideFile } = options; + const filePath = path.join(outputDir, fileName); + + await fs.mkdir(outputDir, { recursive: true }); + + const fileExists = await fileExistsSafe(filePath); + if (fileExists && !overrideFile) { + return { + filePath, + downloadSkipped: true + }; + } + + const response = await axios.get(url, { + responseType: 'stream' + }); + + const writer = createWriteStream(filePath); + await pipeline(response.data, writer); + + return { + filePath, + downloadSkipped: false + }; + } catch (error) { + throw new Error( + `Failed to download file: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); + } +} + +async function fileExistsSafe(p: string): Promise { + try { + await fs.access(p); + return true; + } catch { + return false; + } +} diff --git a/tests/support/fs/readValueFromFile.ts b/tests/support/fs/readValueFromFile.ts index 06813398..b72424ed 100644 --- a/tests/support/fs/readValueFromFile.ts +++ b/tests/support/fs/readValueFromFile.ts @@ -6,7 +6,8 @@ export const readValueFromFile = ( ): string => { if (encoding === 'buffer') { const data = fs.readFileSync(inPath); - return Buffer.from(data.buffer).toString('utf8'); + return data.toString('utf8'); } + return fs.readFileSync(inPath, 'utf8'); }; diff --git a/tests/support/fs/writeValueToFile.ts b/tests/support/fs/writeValueToFile.ts index 78198f68..c4538870 100644 --- a/tests/support/fs/writeValueToFile.ts +++ b/tests/support/fs/writeValueToFile.ts @@ -5,22 +5,32 @@ import { ensureDirectoryExists } from './ensureDirectoryExists'; export const writeValueToFile = ( value: string, outPath: string, - encoding: FileEncoding + encoding: FileEncoding, + skipIfExists: boolean = false ) => { + // Check if file exists and skip if requested + if (skipIfExists && fs.existsSync(outPath)) { + return; + } + // ensure directory exists ensureDirectoryExists(outPath); - // base64 -> write buffer with base64 encoding - if (encoding === 'base64') { - const buffer = Buffer.from(value, 'base64'); - fs.writeFileSync(outPath, new Uint8Array(buffer)); - return; - } - // utf8 -> write string with utf8 encoding - if (encoding === 'utf8') { - fs.writeFileSync(outPath, value, { encoding: 'utf8' }); - return; + switch (encoding) { + case 'base64': + fs.writeFileSync( + outPath, + Buffer.from(value, 'base64').toString('utf8'), + 'utf8' + ); + break; + case 'utf8': + fs.writeFileSync(outPath, value, 'utf8'); + break; + case 'none': + fs.writeFileSync(outPath, value); + break; + default: + throw new Error(`Unsupported encoding: ${encoding}`); } - // no encoding -> write raw string with no encoding - fs.writeFileSync(outPath, value); }; diff --git a/tests/support/metaMask/constants.ts b/tests/support/metaMask/constants.ts new file mode 100644 index 00000000..4daa9691 --- /dev/null +++ b/tests/support/metaMask/constants.ts @@ -0,0 +1,7 @@ +export const DEFAULT_METAMASK_VERSION = '13.6.0'; + +export const resolveMetamaskVersion = () => + process.env.METAMASK_VERSION?.trim() || DEFAULT_METAMASK_VERSION; + +export const buildMetamaskZipUrl = (version: string) => + `https://github.com/MetaMask/metamask-extension/releases/download/v${version}/metamask-chrome-${version}.zip`; diff --git a/tests/support/metaMask/createPassword.ts b/tests/support/metaMask/createPassword.ts new file mode 100644 index 00000000..12118df5 --- /dev/null +++ b/tests/support/metaMask/createPassword.ts @@ -0,0 +1,43 @@ +import { Page } from '@playwright/test'; + +const DEFAULT_TIMEOUT = 10000; + +const createPasswordSelectors = { + newPasswordInput: '[data-testid="create-password-new-input"]', + confirmPasswordInput: '[data-testid="create-password-confirm-input"]', + termsCheckbox: '[data-testid="create-password-terms"]', + submitButton: '[data-testid="create-password-submit"]' +}; + +export async function createPassword(page: Page, password: string) { + await enterPassword(page, password); + await confirmPassword(page, password); + await acceptTerms(page); + await submitPasswordForm(page); +} + +async function enterPassword(page: Page, password: string) { + const passwordField = page.locator(createPasswordSelectors.newPasswordInput); + await passwordField.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await passwordField.fill(password); +} + +async function confirmPassword(page: Page, password: string) { + const confirmField = page.locator( + createPasswordSelectors.confirmPasswordInput + ); + await confirmField.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await confirmField.fill(password); +} + +async function acceptTerms(page: Page) { + const checkbox = page.locator(createPasswordSelectors.termsCheckbox); + await checkbox.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await checkbox.click(); +} + +async function submitPasswordForm(page: Page) { + const submitButton = page.locator(createPasswordSelectors.submitButton); + await submitButton.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await submitButton.click(); +} diff --git a/tests/support/metaMask/downloadMetaMask.ts b/tests/support/metaMask/downloadMetaMask.ts new file mode 100644 index 00000000..fea26266 --- /dev/null +++ b/tests/support/metaMask/downloadMetaMask.ts @@ -0,0 +1,55 @@ +// downloadFileFromUrl.ts +import { createWriteStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { pipeline } from 'stream/promises'; +import axios from 'axios'; + +type Options = { + url: string; + outputDir: string; + fileName: string; + overwrite?: boolean; +}; + +export async function downloadFileFromUrl({ + url, + outputDir, + fileName, + overwrite = false +}: Options): Promise<{ filePath: string; downloadSkipped: boolean }> { + const filePath = path.join(outputDir, fileName); + + await fs.mkdir(outputDir, { recursive: true }); + + if (!overwrite && (await exists(filePath))) { + return { filePath, downloadSkipped: true }; + } + + const response = await axios.get(url, { + responseType: 'stream', + validateStatus: () => true + }); + if (response.status !== 200) { + throw new Error(`Download failed (${response.status}) for ${url}`); + } + + const tmpPath = `${filePath}.part`; + await pipeline(response.data, createWriteStream(tmpPath)); + // remove target file if exists, then rename + try { + await fs.rm(filePath, { force: true }); + } catch {} + await fs.rename(tmpPath, filePath); + + return { filePath, downloadSkipped: false }; +} + +async function exists(p: string): Promise { + try { + await fs.access(p); + return true; + } catch { + return false; + } +} diff --git a/tests/support/metaMask/fillSecretRecoveryPhrase.ts b/tests/support/metaMask/fillSecretRecoveryPhrase.ts new file mode 100644 index 00000000..bf83a846 --- /dev/null +++ b/tests/support/metaMask/fillSecretRecoveryPhrase.ts @@ -0,0 +1,50 @@ +import { Page } from '@playwright/test'; + +const secretRecoverySelectors = { + wordInput: (index: number) => `[data-testid="import-srp__srp-word-${index}"]`, + confirmButton: '[data-testid="import-srp-confirm"]', + errorMessage: '[data-testid="import-srp__error"]' +}; + +export async function fillSecretRecoveryPhrase(page: Page, seedPhrase: string) { + const words = seedPhrase.split(' '); + await fillSeedWords(page, words); + await confirmSeedPhrase(page); +} + +async function fillSeedWords(page: Page, words: string[]) { + // Skip first word (already filled in the textarea) + const remainingWords = words.slice(1); + + for (const [index, word] of remainingWords.entries()) { + const inputSelector = secretRecoverySelectors.wordInput(index + 1); + await fillSingleWord(page, inputSelector, word); + } +} + +async function fillSingleWord(page: Page, selector: string, word: string) { + const input = page.locator(selector); + await input.fill(word); + await input.press('Enter'); +} + +async function confirmSeedPhrase(page: Page) { + const confirmButton = page.locator(secretRecoverySelectors.confirmButton); + + if (await confirmButton.isDisabled()) { + const errorText = await getErrorText(page); + throw new Error( + `[ConfirmSecretRecoveryPhrase] Invalid seed phrase. MetaMask error: ${errorText}` + ); + } + + await confirmButton.click(); +} + +async function getErrorText(page: Page): Promise { + return ( + (await page + .locator(secretRecoverySelectors.errorMessage) + .textContent({ timeout: 1000 })) || 'Unknown error' + ); +} diff --git a/tests/support/metaMask/handleMetaMaskSnap.ts b/tests/support/metaMask/handleMetaMaskSnap.ts new file mode 100644 index 00000000..2f7d29d6 --- /dev/null +++ b/tests/support/metaMask/handleMetaMaskSnap.ts @@ -0,0 +1,150 @@ +import { BrowserContext, Page } from '@playwright/test'; +import { getPageAndWaitForLoad } from '../template/getPageAndWaitForLoad'; +import { waitUntilStable } from '../template/waitUntilStable'; + +const RETRY_DELAY_BASE_MS = 500; +const CLICK_TIMEOUT_MS = 2500; + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +const snapSelectors = { + confirmationSubmitButton: '[data-testid="confirmation-submit-button"]', + actions: [ + { type: 'testId', name: 'snap-privacy-warning-scroll' }, + { type: 'button', name: 'Accept' }, + { type: 'button', name: 'Connect' }, + { type: 'button', name: 'Confirm' }, + { type: 'checkbox', name: 'MultiversX' }, + { type: 'testId', name: 'snap-install-warning-modal-confirm' }, + { type: 'button', name: 'Ok' }, + { type: 'button', name: 'Approve' } + ] as const +}; + +export async function handleMetaMaskSnap( + context: BrowserContext, + extensionId: string, + initialPage: Page, + maxRetries = 5 +): Promise { + let page = initialPage; + let attempt = 0; + let currentActionIndex = 0; + + while (attempt <= maxRetries) { + try { + await waitUntilStable(page); + + if (await clickIfConfirmationVisible(page)) return; + + for (let i = currentActionIndex; i < snapSelectors.actions.length; i++) { + const action = snapSelectors.actions[i]; + currentActionIndex = i; + await attemptClick(page, action); + } + + return; // All steps completed successfully + } catch (error: any) { + attempt++; + + console.warn( + `[MetaMaskSnap] Attempt ${attempt}/${maxRetries} failed: ${ + error?.message || error + }` + ); + console.warn( + '[MetaMaskSnap] Open pages at failure:', + context.pages().map((p) => p.url()) + ); + + if (attempt > maxRetries) { + throw new Error('[MetaMaskSnap] Max retries reached.'); + } + + page = await reacquireNotificationPage(context, extensionId); + await exponentialBackoff(attempt); + } + } + + throw new Error('[MetaMaskSnap] Unexpected end of flow.'); +} + +async function attemptClick( + page: Page, + action: { type: 'testId' | 'checkbox' | 'button'; name: string } +) { + const element = getLocator(page, action); + + try { + await element.waitFor({ state: 'visible', timeout: CLICK_TIMEOUT_MS }); + await element.click(); + } catch (error: any) { + console.error( + `[MetaMaskSnap] Failed to click "${action.name}": ${ + error?.message || error + }` + ); + console.error( + `[MetaMaskSnap] Page state -> closed: ${page.isClosed()}, url: ${page.url()}` + ); + throw error; + } +} + +function getLocator( + page: Page, + action: { type: 'testId' | 'checkbox' | 'button'; name: string } +) { + switch (action.type) { + case 'testId': + return page.getByTestId(action.name); + case 'checkbox': + return page.getByRole('checkbox', { name: action.name }); + case 'button': + return page.getByRole('button', { name: action.name }); + default: + throw new Error(`Unknown action type: ${action.type}`); + } +} + +async function clickIfConfirmationVisible(page: Page): Promise { + const confirmationButton = page.locator( + snapSelectors.confirmationSubmitButton + ); + const isVisible = await confirmationButton.isVisible().catch(() => false); + + if (isVisible) { + await confirmationButton.click(); + return true; + } + + return false; +} + +async function reacquireNotificationPage( + context: BrowserContext, + extensionId: string +): Promise { + try { + const page = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/notification.html`, + { viewport: { width: 360, height: 592 } } + ); + await waitUntilStable(page); + console.warn('[MetaMaskSnap] Reacquired notification page.'); + return page; + } catch (error) { + throw new Error( + `[MetaMaskSnap] Failed to reacquire notification page: ${ + (error as Error).message + }` + ); + } +} + +async function exponentialBackoff(attempt: number) { + const delay = RETRY_DELAY_BASE_MS * 2 ** (attempt - 1); + console.warn(`[MetaMaskSnap] Retrying in ${delay}ms...`); + await sleep(delay); +} diff --git a/tests/support/metaMask/handleMetrics.ts b/tests/support/metaMask/handleMetrics.ts new file mode 100644 index 00000000..291af27c --- /dev/null +++ b/tests/support/metaMask/handleMetrics.ts @@ -0,0 +1,36 @@ +import { Page } from '@playwright/test'; + +const DEFAULT_TIMEOUT = 10000; + +const metaMetricsSelectors = { + checkbox: '#metametrics-opt-in', + continueButton: '[data-testid="metametrics-i-agree"]', + doneButton: '[data-testid="onboarding-complete-done"]' +}; + +export async function handleMetaMetrics(page: Page) { + await ensureMetaMetricsOptOut(page); + await clickContinue(page); + await clickDone(page); +} + +async function ensureMetaMetricsOptOut(page: Page) { + const checkbox = page.locator(metaMetricsSelectors.checkbox); + await checkbox.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + + if (await checkbox.isChecked()) { + await checkbox.click(); + } +} + +async function clickContinue(page: Page) { + const button = page.locator(metaMetricsSelectors.continueButton); + await button.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await button.click(); +} + +async function clickDone(page: Page) { + const button = page.locator(metaMetricsSelectors.doneButton); + await button.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await button.click(); +} diff --git a/tests/support/metaMask/importWallet.ts b/tests/support/metaMask/importWallet.ts new file mode 100644 index 00000000..899f12bd --- /dev/null +++ b/tests/support/metaMask/importWallet.ts @@ -0,0 +1,160 @@ +import path from 'node:path'; +import { chromium, ChromiumBrowserContext, Page } from '@playwright/test'; +import { METAMASK_CACHE_DIR_NAME } from '../template/constants'; +import { waitUntilStable } from '../template/waitUntilStable'; +import { prepareExtension } from './prepareExtension'; + +const DEFAULT_VIEWPORT = { width: 360, height: 592 }; +const CONTEXT_CLOSE_GRACE_MS = 1_000; +const EXT_ID_RETRIES = 5; +const EXT_ID_RETRY_DELAY_MS = 300; +const METAMASK_USER_DIR = 'metamask-user-data'; + +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +function assertTruthy( + value: T, + msg: string +): asserts value is NonNullable { + if (value === null || value === undefined) { + throw new Error(msg); + } +} + +function toAbsolutePath(p: string) { + return path.resolve(p); +} + +function getUserDataDir(): string { + return path.join(process.cwd(), METAMASK_CACHE_DIR_NAME, METAMASK_USER_DIR); +} + +async function firstPageOrThrow( + context: ChromiumBrowserContext +): Promise { + const [page] = context.pages(); + assertTruthy(page, 'No pages were opened by the extension context.'); + return page; +} + +async function tryGetExtensionIdOnce( + context: ChromiumBrowserContext +): Promise { + // Prefer service workers (MV3); background pages are rare in MV3. + const sw = context.serviceWorkers(); + for (const worker of sw) { + try { + const url = worker.url(); + if (url.startsWith('chrome-extension://')) { + const id = url.split('/')[2]; + if (id) return id; + } + } catch { + // ignore and continue + } + } + + // Fallback: parse from any extension page if present + for (const page of context.pages()) { + try { + const url = page.url(); + if (url.startsWith('chrome-extension://')) { + const id = url.split('/')[2]; + if (id) return id; + } + } catch { + // ignore and continue + } + } + + return null; +} + +async function getExtensionIdWithRetry( + context: ChromiumBrowserContext +): Promise { + for (let attempt = 1; attempt <= EXT_ID_RETRIES; attempt++) { + const id = await tryGetExtensionIdOnce(context); + if (id) return id; + await sleep(EXT_ID_RETRY_DELAY_MS); + } + throw new Error( + 'Could not determine extension ID (service worker/background not ready).' + ); +} + +export async function createBrowserContextWithExtension( + extensionPath: string +): Promise { + assertTruthy(extensionPath, 'Extension path is required'); + + const absoluteExtensionPath = toAbsolutePath(extensionPath); + const userDataDir = getUserDataDir(); + + // Give any previous persistent context time to release file locks. + await sleep(CONTEXT_CLOSE_GRACE_MS); + + try { + const context = await chromium.launchPersistentContext(userDataDir, { + headless: false, + args: [ + `--disable-extensions-except=${absoluteExtensionPath}`, + `--load-extension=${absoluteExtensionPath}` + ], + viewport: DEFAULT_VIEWPORT + }); + + assertTruthy(context, 'Failed to create Chromium persistent context'); + return context; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + if ( + msg.includes('Target page, context or browser has been closed') || + msg.includes('userDataDir') || + msg.includes('already in use') + ) { + throw new Error( + `Failed to create browser context: a previous persistent context may still be closing or userDataDir is locked. Original error: ${msg}` + ); + } + throw new Error(`Failed to create browser context: ${msg}`); + } +} + +export async function getExtensionId( + context: ChromiumBrowserContext, + _extensionName: string // kept for signature parity; reserved for future filtering +): Promise { + assertTruthy(context, 'Browser context is required'); + try { + return await getExtensionIdWithRetry(context); + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to get extension ID: ${msg}`); + } +} + +// Downloads (if needed), loads MetaMask as an extension, and returns the context + extensionId. +export async function setupMetaMaskExtension(): Promise<{ + context: ChromiumBrowserContext; + extensionId: string; +}> { + try { + const extensionPath = await prepareExtension(); + assertTruthy(extensionPath, 'Failed to prepare MetaMask extension'); + + const context = await createBrowserContextWithExtension(extensionPath); + + // Ensure the initial extension page is stable before querying workers/pages + const first = await firstPageOrThrow(context); + await waitUntilStable(first); + + const extensionId = await getExtensionId(context, 'MetaMask'); + assertTruthy(extensionId, 'Failed to resolve MetaMask extension ID'); + + return { context, extensionId }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to setup MetaMask extension: ${msg}`); + } +} diff --git a/tests/support/metaMask/loadExtension.ts b/tests/support/metaMask/loadExtension.ts new file mode 100644 index 00000000..6e1bd247 --- /dev/null +++ b/tests/support/metaMask/loadExtension.ts @@ -0,0 +1,123 @@ +import path from 'node:path'; +import { chromium, type ChromiumBrowserContext } from '@playwright/test'; +import { METAMASK_CACHE_DIR_NAME } from '../template/constants'; +import { waitUntilStable } from '../template/waitUntilStable'; +import { prepareExtension } from './prepareExtension'; + +const METAMASK_USER_DIR = 'metamask-user-data'; +const CONTEXT_RELEASE_GRACE_MS = 1000; +const SERVICE_WORKER_RETRIES = 3; +const SERVICE_WORKER_RETRY_DELAY_MS = 300; + +// Utility: delay +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +// Utility: fail early with types preserved +function ensure(value: T | null | undefined, message: string): T { + if (value == null) throw new Error(message); + return value; +} + +// Extract extension id from a service worker url +function extractExtensionIdFromUrl(url: string): string | null { + if (!url.startsWith('chrome-extension://')) return null; + const id = url.split('/')[2]; + return id && id.length > 0 ? id : null; +} + +// Try to read the extension id from existing service workers (with a small retry window for CI flakiness). +export async function getExtensionId( + context: ChromiumBrowserContext, + _extensionName: string // kept for signature parity / future filtering if needed +): Promise { + if (!context) throw new Error('Browser context is required'); + + for (let attempt = 0; attempt <= SERVICE_WORKER_RETRIES; attempt++) { + const workers = context.serviceWorkers(); + for (const sw of workers) { + const id = extractExtensionIdFromUrl(sw.url()); + if (id) return id; + } + if (attempt < SERVICE_WORKER_RETRIES) { + await sleep(SERVICE_WORKER_RETRY_DELAY_MS); + } + } + + throw new Error( + 'Could not find extension ID from service workers. The extension may not be loaded yet.' + ); +} + +// Launch a persistent Chromium context with a single loaded extension. +export async function createBrowserContextWithExtension( + extensionPath: string +): Promise { + const absoluteExtensionPath = path.resolve( + ensure(extensionPath, 'Extension path is required') + ); + + const userDataDir = path.join( + process.cwd(), + METAMASK_CACHE_DIR_NAME, + METAMASK_USER_DIR + ); + + // Give the previous persistent context time to fully release its lock on userDataDir. + await sleep(CONTEXT_RELEASE_GRACE_MS); + + try { + const context = await chromium.launchPersistentContext(userDataDir, { + headless: false, + args: [ + `--disable-extensions-except=${absoluteExtensionPath}`, + `--load-extension=${absoluteExtensionPath}` + ] + }); + + return ensure(context, 'Failed to create browser context'); + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + const isBusy = + msg.includes('Target page, context or browser has been closed') || + msg.includes('userDataDir') || + msg.includes('already in use'); + + if (isBusy) { + throw new Error( + 'Failed to create browser context: previous persistent context may still be closing. ' + + `Ensure contexts are closed before launching a new one. Original error: ${msg}` + ); + } + throw new Error(`Failed to create browser context with extension: ${msg}`); + } +} + +// Prepare the MetaMask extension, start a browser context, stabilize, and return the context + extensionId. +export async function setupMetaMaskExtension(): Promise<{ + context: ChromiumBrowserContext; + extensionId: string; +}> { + // 1) Ensure extension bits exist on disk (download/unzip if needed). + const extensionPath = ensure( + await prepareExtension(), + 'Failed to prepare MetaMask extension' + ); + + // 2) Launch a persistent context with the extension. + const context = await createBrowserContextWithExtension(extensionPath); + + // 3) Wait for the first page to be interactive (extension often opens a tab). + const firstPage = ensure( + context.pages()[0], + 'Extension did not open an initial page' + ); + await waitUntilStable(firstPage); + + // 4) Resolve the extension id via service worker. + const extensionId = ensure( + await getExtensionId(context, 'MetaMask'), + 'Failed to get extension ID' + ); + + return { context, extensionId }; +} diff --git a/tests/support/metaMask/prepareExtension.ts b/tests/support/metaMask/prepareExtension.ts new file mode 100644 index 00000000..4d2e4474 --- /dev/null +++ b/tests/support/metaMask/prepareExtension.ts @@ -0,0 +1,29 @@ +// prepareExtension.ts +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { downloadFileFromUrl } from '../fs/downloadFileFromUrl'; +import { buildMetamaskZipUrl, resolveMetamaskVersion } from './constants'; +import { unzipArchive } from './unzipArchive'; + +export async function prepareExtension(forceCache = true): Promise { + const version = resolveMetamaskVersion(); + + const outputDir = forceCache + ? path.join(process.cwd(), '.cache') + : path.resolve('./', 'downloads'); + + await fs.mkdir(outputDir, { recursive: true }); + + const fileName = `metamask-chrome-${version}.zip`; + const url = buildMetamaskZipUrl(version); + + const { filePath } = await downloadFileFromUrl({ + url, + outputDir, + fileName, + overrideFile: false + }); + + const { outputPath } = await unzipArchive({ archivePath: filePath }); + return outputPath; +} diff --git a/tests/support/metaMask/setupMetaMaskWallet.ts b/tests/support/metaMask/setupMetaMaskWallet.ts new file mode 100644 index 00000000..9d81cdf2 --- /dev/null +++ b/tests/support/metaMask/setupMetaMaskWallet.ts @@ -0,0 +1,113 @@ +import { Page } from '@playwright/test'; +import { handleMetaMetrics } from '../metaMask/handleMetrics'; +import { getPageAndWaitForLoad } from '../template/getPageAndWaitForLoad'; +import { waitUntilStable } from '../template/waitUntilStable'; +import { createPassword } from './createPassword'; +import { fillSecretRecoveryPhrase } from './fillSecretRecoveryPhrase'; +import { setupMetaMaskExtension } from './loadExtension'; + +const DEFAULT_PAGE_TIMEOUT = 10000; + +const metaMaskSelectors = { + unlockPasswordInput: '[data-testid="unlock-password"]', + importWalletButton: '[data-testid="onboarding-import-wallet"]', + importWithSRPButton: '[data-testid="onboarding-import-with-srp-button"]', + srpNoteInput: '[data-testid="srp-input-import__srp-note"]' +}; + +export async function setupMetaMaskWallet(mnemonic: string, password: string) { + try { + const { context, extensionId } = await initializeMetaMaskExtension(); + const metamaskPage = await openAndPrepareExtensionPage( + context, + extensionId + ); + + const onboardingState = await detectOnboardingState(metamaskPage); + + if (onboardingState === 'unlock') { + await unlockExistingWallet(metamaskPage, password); + return { context, extensionId, metamaskPage }; + } + + await importWalletFlow(metamaskPage, mnemonic, password); + await handleMetaMetrics(metamaskPage); + + return { context, extensionId, metamaskPage }; + } catch (error) { + throw new Error( + `Failed to setup MetaMask wallet: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); + } +} + +async function initializeMetaMaskExtension() { + const { context, extensionId } = await setupMetaMaskExtension(); + if (!extensionId) throw new Error('Failed to get MetaMask extension ID'); + return { context, extensionId }; +} + +async function openAndPrepareExtensionPage(context: any, extensionId: string) { + const metamaskPage = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/` + ); + await waitUntilStable(metamaskPage); + return metamaskPage; +} + +async function detectOnboardingState(page: Page) { + const unlockPassword = page.locator(metaMaskSelectors.unlockPasswordInput); + const importWallet = page.locator(metaMaskSelectors.importWalletButton); + + return Promise.race([ + unlockPassword + .waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }) + .then(() => 'unlock' as const), + importWallet + .waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }) + .then(() => 'import' as const) + ]).catch(() => { + throw new Error( + 'Neither "unlock-password" nor "onboarding-import-wallet" appeared within timeout' + ); + }); +} + +async function unlockExistingWallet(page: Page, password: string) { + const passwordInput = page.locator(metaMaskSelectors.unlockPasswordInput); + await passwordInput.fill(password); + await passwordInput.press('Enter'); +} + +async function importWalletFlow( + page: Page, + mnemonic: string, + password: string +) { + await startImportProcess(page); + await fillFirstSecretRecoveryPhraseWord(page, mnemonic); + await fillSecretRecoveryPhrase(page, mnemonic); + await createPassword(page, password); +} + +async function startImportProcess(page: Page) { + const importButton = page.locator(metaMaskSelectors.importWalletButton); + await importButton.click(); + + const srpButton = page.locator(metaMaskSelectors.importWithSRPButton); + await srpButton.waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }); + await srpButton.click(); +} + +async function fillFirstSecretRecoveryPhraseWord(page: Page, mnemonic: string) { + const srpInput = page.locator(metaMaskSelectors.srpNoteInput); + await srpInput.waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }); + await srpInput.click(); + + const [firstWord] = mnemonic.split(' '); + await srpInput.type(firstWord); + await srpInput.press('Enter'); +} diff --git a/tests/support/metaMask/unzipArchive.ts b/tests/support/metaMask/unzipArchive.ts new file mode 100644 index 00000000..ca1b9a66 --- /dev/null +++ b/tests/support/metaMask/unzipArchive.ts @@ -0,0 +1,81 @@ +import { execFile } from 'node:child_process'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { promisify } from 'node:util'; + +const execFileAsync = promisify(execFile); + +type UnzipArchiveOptions = { + archivePath: string; + overwrite?: boolean; +}; + +type UnzipArchiveResult = { + outputPath: string; + unzipSkipped: boolean; +}; + +// Unzips an archive using the system `unzip` command. +//Returns the extraction path and whether extraction was skipped due to cache. +export async function unzipArchive( + options: UnzipArchiveOptions +): Promise { + const { archivePath, overwrite = false } = options; + const outputPath = deriveOutputPath(archivePath); + + if (await shouldSkipUnzip(outputPath, overwrite)) { + return { outputPath, unzipSkipped: true }; + } + + await ensureCleanOutputDir(outputPath, overwrite); + await extractZipArchive(archivePath, outputPath); + + return { outputPath, unzipSkipped: false }; +} + +function deriveOutputPath(archivePath: string): string { + const { dir, name } = path.parse(archivePath); + return path.join(dir, name); +} + +async function shouldSkipUnzip( + outputPath: string, + overwrite: boolean +): Promise { + try { + await fs.access(outputPath); + return !overwrite; + } catch { + return false; + } +} + +async function ensureCleanOutputDir( + outputPath: string, + overwrite: boolean +): Promise { + try { + if (overwrite) { + await fs.rm(outputPath, { recursive: true, force: true }); + } + } catch { + // ignore + } + await fs.mkdir(outputPath, { recursive: true }); +} + +// Extracts a ZIP archive using the system `unzip` utility. +// Requires `unzip` to be available on the system (default on macOS/Linux, available via WSL on Windows). +async function extractZipArchive( + archivePath: string, + outputPath: string +): Promise { + try { + await execFileAsync('unzip', ['-o', archivePath, '-d', outputPath]); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error( + `[unzipArchive] Failed to extract ${archivePath}: ${message}` + ); + } +} diff --git a/tests/support/metaMask/waitForMetaMaskLoad.ts b/tests/support/metaMask/waitForMetaMaskLoad.ts new file mode 100644 index 00000000..7295988c --- /dev/null +++ b/tests/support/metaMask/waitForMetaMaskLoad.ts @@ -0,0 +1,90 @@ +import { errors, Page } from '@playwright/test'; +import { waitUntilStable } from '../template/waitUntilStable'; + +const DEFAULT_TIMEOUT = 10_000; +const DEFAULT_POST_DELAY_MS = 300; + +// Core loading indicators commonly found in MetaMask screens +const BASE_LOADING_SELECTORS: readonly string[] = [ + '.loading-logo', + '.loading-spinner', + '.loading-overlay', + '.loading-overlay__spinner', + '.loading-span', + '.loading-indicator', + '#loading__logo', + '#loading__spinner', + '.mm-button-base__icon-loading', + '.loading-swaps-quotes', + '.loading-heartbeat', + '.spinner' +]; + +type WaitForMetaMaskLoadOptions = { + // Per-selector timeout while waiting to become hidden (defaults to 10s). + selectorTimeoutMs?: number; + // Additional page selectors that should also be hidden before continuing. + extraLoadingSelectors?: string[]; + // Milliseconds to sleep after the page looks ready (defaults to 300ms). + postDelayMs?: number; + // Skip the initial stable wait if you’ve already done it. + skipInitialStabilityWait?: boolean; +}; + +// Waits for MetaMask UI to become usable: +// 1) (optionally) waits for DOM/network to settle +// 2) waits for known loading indicators to disappear (best-effort) +// 3) small post-delay to avoid flakiness on slow CI +export async function waitForMetaMaskLoad( + page: Page, + options: WaitForMetaMaskLoadOptions = {} +): Promise { + const { + selectorTimeoutMs = DEFAULT_TIMEOUT, + extraLoadingSelectors = [], + postDelayMs = DEFAULT_POST_DELAY_MS, + skipInitialStabilityWait = false + } = options; + + try { + if (!skipInitialStabilityWait) { + await waitUntilStable(page); + } + + const selectors = [...BASE_LOADING_SELECTORS, ...extraLoadingSelectors]; + + await waitForSelectorsHidden(page, selectors, selectorTimeoutMs); + } catch (err) { + // Don’t fail the test β€” UI might still be interactive + const msg = err instanceof Error ? err.message : String(err); + console.warn(`[waitForMetaMaskLoad] Non-fatal warning: ${msg}`); + } + + await page.waitForTimeout(postDelayMs); + return page; +} + +// Wait until each selector is hidden; ignore timeouts (selector may not exist on this screen). +async function waitForSelectorsHidden( + page: Page, + selectors: string[], + perSelectorTimeoutMs: number +): Promise { + await Promise.all( + selectors.map(async (selector) => { + try { + await waitUntilStable(page); + await page.waitForSelector(selector, { + state: 'hidden', + timeout: perSelectorTimeoutMs + }); + } catch (err) { + if (err instanceof errors.TimeoutError) { + // OK: selector may never appear on this view; continue + return; + } + throw err; + } + }) + ); +} diff --git a/tests/support/navigateToConnectWallet.ts b/tests/support/navigateToConnectWallet.ts deleted file mode 100644 index fe26621e..00000000 --- a/tests/support/navigateToConnectWallet.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Page } from '@playwright/test'; - -export const navigateToConnectWallet = async (page: Page) => { - await page.goto('/', { waitUntil: 'load' }); - await page.getByRole('button', { name: 'Connect' }).first().click(); -}; diff --git a/tests/support/checkBalanceUpdate.ts b/tests/support/template/checkBalanceUpdate.ts similarity index 100% rename from tests/support/checkBalanceUpdate.ts rename to tests/support/template/checkBalanceUpdate.ts diff --git a/tests/support/checkButtonStatus.ts b/tests/support/template/checkButtonStatus.ts similarity index 100% rename from tests/support/checkButtonStatus.ts rename to tests/support/template/checkButtonStatus.ts diff --git a/tests/support/checkClipboardContains.ts b/tests/support/template/checkClipboardContains.ts similarity index 100% rename from tests/support/checkClipboardContains.ts rename to tests/support/template/checkClipboardContains.ts diff --git a/tests/support/checkConnectionToWallet.ts b/tests/support/template/checkConnectionToWallet.ts similarity index 52% rename from tests/support/checkConnectionToWallet.ts rename to tests/support/template/checkConnectionToWallet.ts index 4f1fb756..d734e55e 100644 --- a/tests/support/checkConnectionToWallet.ts +++ b/tests/support/template/checkConnectionToWallet.ts @@ -7,7 +7,10 @@ export const checkConnectionToWallet = async ( page: Page, walletAddress: string ) => { - await expect(page.getByTestId(SelectorsEnum.topInfoContainer)).toContainText( - walletAddress - ); + const topInfoContainer = page.getByTestId(SelectorsEnum.topInfoContainer); + + const addressElement = topInfoContainer + .getByTestId(SelectorsEnum.accountAddress) + .getByTestId(SelectorsEnum.trimFullAddress); + await expect(addressElement).toContainText(walletAddress); }; diff --git a/tests/support/confirmPrivateKeyTransaction.ts b/tests/support/template/confirmPrivateKeyTransaction.ts similarity index 100% rename from tests/support/confirmPrivateKeyTransaction.ts rename to tests/support/template/confirmPrivateKeyTransaction.ts diff --git a/tests/support/confirmWalletTransaction.ts b/tests/support/template/confirmWalletTransaction.ts similarity index 100% rename from tests/support/confirmWalletTransaction.ts rename to tests/support/template/confirmWalletTransaction.ts diff --git a/tests/support/connectInMemoryProvider.ts b/tests/support/template/connectInMemoryProvider.ts similarity index 100% rename from tests/support/connectInMemoryProvider.ts rename to tests/support/template/connectInMemoryProvider.ts diff --git a/tests/support/connectWebWallet.ts b/tests/support/template/connectWebWallet.ts similarity index 79% rename from tests/support/connectWebWallet.ts rename to tests/support/template/connectWebWallet.ts index 6e43ed4a..dd2dfaf8 100644 --- a/tests/support/connectWebWallet.ts +++ b/tests/support/template/connectWebWallet.ts @@ -1,5 +1,5 @@ -import { expect } from '@playwright/test'; import { TEST_CONSTANTS } from './constants'; +import { getPageAndWaitForLoad } from './getPageAndWaitForLoad'; import { OriginPageEnum, SelectorsEnum } from './testdata'; import { getTestIdSelector } from './testIdSelector'; import { @@ -7,24 +7,35 @@ import { AuthenticateWithPemType, ConnectWebWalletType } from './types'; -import { waitForPageByUrlSubstring } from './waitForPageByUrlSubstring'; const authenticateWithKeystore = async ({ walletPage, keystorePath, keystorePassword }: AuthenticateWithKeystoreType) => { + // Click the keystore button await walletPage.getByTestId(SelectorsEnum.keystoreButton).click(); + + // Upload the keystore file await walletPage.setInputFiles( getTestIdSelector(SelectorsEnum.walletFile), keystorePath ); + // Wait for file processing to complete + await walletPage.waitForLoadState(); + + // Fill the password input const passwordInput = walletPage.getByTestId(SelectorsEnum.passwordInput); - await expect(passwordInput).toBeVisible(); await passwordInput.fill(keystorePassword); + // Wait for file processing to complete + await walletPage.waitForLoadState(); + + // Click the submit button await walletPage.getByTestId(SelectorsEnum.submitButton).click(); + + // Click the confirm button await walletPage.getByTestId(SelectorsEnum.confirmButton).click(); }; @@ -32,11 +43,19 @@ const authenticateWithPem = async ({ walletPage, pemPath }: AuthenticateWithPemType) => { + // Click the PEM button await walletPage.getByTestId(SelectorsEnum.pemButton).click(); + + // Upload the PEM file await walletPage.setInputFiles( getTestIdSelector(SelectorsEnum.walletFile), pemPath ); + + // Wait for file processing to complete + await walletPage.waitForLoadState(); + + // Click the submit button await walletPage.getByTestId(SelectorsEnum.submitButton).click(); }; @@ -48,10 +67,10 @@ export const connectWebWallet = async ({ await page.getByTestId(SelectorsEnum.crossWindow).click(); // Wait for the web wallet page to be loaded which is the new tab - const walletPage = await waitForPageByUrlSubstring({ - page, - urlSubstring: OriginPageEnum.multiversxWallet - }); + const walletPage = await getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); // If the web wallet page is not loaded, throw an error if (!walletPage) { diff --git a/tests/support/constants.ts b/tests/support/template/constants.ts similarity index 93% rename from tests/support/constants.ts rename to tests/support/template/constants.ts index e13f166e..af401530 100644 --- a/tests/support/constants.ts +++ b/tests/support/template/constants.ts @@ -2,6 +2,8 @@ export const PATHS = { WALLETS_DIR: 'tests/support/wallets' } as const; +export const METAMASK_CACHE_DIR_NAME = '.cache'; + export const TEST_CONSTANTS = { MIN_BALANCE_FOR_PING_PONG: 1, // 1 EGLD MIN_BALANCE_FOR_BATCH_TX: 5, // 5 EGLD diff --git a/tests/support/extractBalanceFromContainer.ts b/tests/support/template/extractBalanceFromContainer.ts similarity index 100% rename from tests/support/extractBalanceFromContainer.ts rename to tests/support/template/extractBalanceFromContainer.ts diff --git a/tests/support/template/getPageAndWaitForLoad.ts b/tests/support/template/getPageAndWaitForLoad.ts new file mode 100644 index 00000000..90a3aa03 --- /dev/null +++ b/tests/support/template/getPageAndWaitForLoad.ts @@ -0,0 +1,72 @@ +import { BrowserContext, Page } from '@playwright/test'; +import { waitUntilStable } from './waitUntilStable'; + +const DEFAULT_WAIT_TIMEOUT = 15_000; + +export async function getPageAndWaitForLoad( + context: BrowserContext, + pageUrlFragment: string, + options?: { viewport?: { width: number; height: number }; timeout?: number } +): Promise { + let retries = 0; + const maxRetries = 3; + + while (retries < maxRetries) { + try { + const timeoutMs = options?.timeout || DEFAULT_WAIT_TIMEOUT; + + // Try to find an already open page or wait (by polling) for a page to + // navigate to the expected URL. Relying on the 'page' event can + // miss cases where the page already exists (about:blank) and then + // navigates later, or when navigation happens in the same tab. + const page = + context.pages().find((p) => p.url().includes(pageUrlFragment)) || + (await waitForPageByUrlFragment(context, pageUrlFragment, timeoutMs)); + + if (!page) throw new Error('Notification page not found'); + + if (options?.viewport) { + await page.setViewportSize(options.viewport); + } + + // Wait for the page to be stable + await waitUntilStable(page); + + return page; + } catch (error) { + retries++; + const message = error instanceof Error ? error.message : 'Unknown error'; + console.warn( + `[getPageAndWaitForLoad] Retry ${retries}/3 after error: ${message}` + ); + + if (retries >= maxRetries) throw error; + await new Promise((r) => setTimeout(r, 1000 * retries)); + } + } + + throw new Error('getPageAndWaitForLoad: Unexpected end of retries'); +} + +async function waitForPageByUrlFragment( + context: BrowserContext, + fragment: string, + timeoutMs: number +): Promise { + const pollIntervalMs = 250; + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + const match = context.pages().find((p) => p.url().includes(fragment)); + if (match) return match; + + // Briefly wait for any new page to appear; ignore timeouts and keep polling. + try { + await context.waitForEvent('page', { timeout: pollIntervalMs }); + } catch { + // no-op; continue polling + } + } + + return null; +} diff --git a/tests/support/globalSetup.ts b/tests/support/template/globalSetup.ts similarity index 80% rename from tests/support/globalSetup.ts rename to tests/support/template/globalSetup.ts index 968b7786..3de45d44 100644 --- a/tests/support/globalSetup.ts +++ b/tests/support/template/globalSetup.ts @@ -14,7 +14,7 @@ import path from 'path'; import { loadEnv } from 'vite'; -import { writeValueToFile } from '../support'; +import { writeValueToFile } from '../fs/writeValueToFile'; import { type FileEncoding } from './types'; // Load environment variables for local runs using Vite's loadEnv @@ -33,12 +33,14 @@ try { // Write keystore files from environment variables async function writeKeystoreFilesFromEnv( - defaultEncoding: FileEncoding = 'base64' + defaultEncoding: FileEncoding = 'base64', + skipIfExists: boolean = false ) { // Resolve wallets directory without relying on process.cwd const walletsDir = process.env.WALLETS_DIR ? path.resolve(process.env.WALLETS_DIR) - : path.resolve(__dirname, 'wallets'); + : path.resolve(__dirname, '..', 'wallets'); + const mappings: Array<{ envKey: string; outPath: string; @@ -79,13 +81,26 @@ async function writeKeystoreFilesFromEnv( // Write keystore files from environment variables for (const { envKey, outPath, encoding } of mappings) { const value = process.env[envKey]; - if (value && value.trim().length > 0) { - writeValueToFile(value, outPath, encoding ?? defaultEncoding); + if (!value?.trim()) { + console.warn(`[globalSetup] Missing or empty env var: ${envKey}`); + continue; + } + + try { + writeValueToFile( + value, + outPath, + encoding ?? defaultEncoding, + skipIfExists + ); + console.log(`[globalSetup] Wrote ${outPath}`); + } catch (error) { + console.error(`[globalSetup] Failed to write ${outPath}:`, error); } } } // Global setup function export default async function globalSetup() { - await writeKeystoreFilesFromEnv(); + await writeKeystoreFilesFromEnv('base64', true); } diff --git a/tests/support/handlePingPong.ts b/tests/support/template/handlePingPong.ts similarity index 100% rename from tests/support/handlePingPong.ts rename to tests/support/template/handlePingPong.ts diff --git a/tests/support/index.ts b/tests/support/template/index.ts similarity index 77% rename from tests/support/index.ts rename to tests/support/template/index.ts index f9afb9d7..f5774923 100644 --- a/tests/support/index.ts +++ b/tests/support/template/index.ts @@ -16,7 +16,7 @@ export { connectWebWallet } from './connectWebWallet'; export { countTransactions } from './parseTransactionsTable'; -export { ensureDirectoryExists } from './fs/ensureDirectoryExists'; +export { ensureDirectoryExists } from '../fs/ensureDirectoryExists'; export { extractBalanceFromContainer } from './extractBalanceFromContainer'; @@ -24,6 +24,8 @@ export { filterTransactions } from './parseTransactionsTable'; export { getTestIdSelector } from './testIdSelector'; +export { handleMetaMaskSnap } from '../metaMask/handleMetaMaskSnap'; + export { handlePingPong } from './handlePingPong'; export { navigateToConnectWallet } from './navigateToConnectWallet'; @@ -32,11 +34,11 @@ export { parseTransactionsTable } from './parseTransactionsTable'; export { pasteStringFromClipboard } from './pasteStringFromClipboard'; -export { readValueFromFile } from './fs/readValueFromFile'; +export { readValueFromFile } from '../fs/readValueFromFile'; export { signBatchTransactions } from './signBatchTransactions'; -export { waitForPageByUrlSubstring } from './waitForPageByUrlSubstring'; +export { getPageAndWaitForLoad } from './getPageAndWaitForLoad'; export { waitForToastToBeClosed } from './waitForToastToBeClosed'; @@ -44,4 +46,6 @@ export { waitForToastToBeDisplayed } from './waitForToastToBeDisplayed'; export { waitForTransactionToastToContain } from './waitForTransactionToastToShow'; -export { writeValueToFile } from './fs/writeValueToFile'; +export { waitUntilStable } from './waitUntilStable'; + +export { writeValueToFile } from '../fs/writeValueToFile'; diff --git a/tests/support/template/navigateToConnectWallet.ts b/tests/support/template/navigateToConnectWallet.ts new file mode 100644 index 00000000..d19919fd --- /dev/null +++ b/tests/support/template/navigateToConnectWallet.ts @@ -0,0 +1,18 @@ +import { Page } from '@playwright/test'; + +export const navigateToConnectWallet = async (page: Page) => { + const maxRetries = 5; + for (let i = 0; i < maxRetries; i++) { + try { + await page.goto('/', { waitUntil: 'load', timeout: 60 * 1000 }); // Increase timeout + break; + } catch (error) { + console.warn( + `[navigateToConnectWallet] Attempt ${i + 1} failed: ${error.message}` + ); + if (i === maxRetries - 1) throw error; + await page.waitForTimeout(5000); // Increase wait time + } + } + await page.getByRole('button', { name: 'Connect' }).first().click(); +}; diff --git a/tests/support/parseTransactionsTable.ts b/tests/support/template/parseTransactionsTable.ts similarity index 100% rename from tests/support/parseTransactionsTable.ts rename to tests/support/template/parseTransactionsTable.ts diff --git a/tests/support/pasteStringFromClipboard.ts b/tests/support/template/pasteStringFromClipboard.ts similarity index 100% rename from tests/support/pasteStringFromClipboard.ts rename to tests/support/template/pasteStringFromClipboard.ts diff --git a/tests/support/signBatchTransactions.ts b/tests/support/template/signBatchTransactions.ts similarity index 90% rename from tests/support/signBatchTransactions.ts rename to tests/support/template/signBatchTransactions.ts index b2b83a89..7d0650ae 100644 --- a/tests/support/signBatchTransactions.ts +++ b/tests/support/template/signBatchTransactions.ts @@ -8,6 +8,7 @@ export const signBatchTransactions = async ({ }: SignBatchTransactionsType) => { let i = buttonSelector === 'swap-lock' ? 1 : 0; for (i; i < numberOfTransactions; i++) { + await walletPage.waitForLoadState(); await walletPage.getByTestId(SelectorsEnum.signButton).click(); } }; diff --git a/tests/support/testIdSelector.ts b/tests/support/template/testIdSelector.ts similarity index 100% rename from tests/support/testIdSelector.ts rename to tests/support/template/testIdSelector.ts diff --git a/tests/support/testdata.ts b/tests/support/template/testdata.ts similarity index 65% rename from tests/support/testdata.ts rename to tests/support/template/testdata.ts index ec6169db..261c5095 100644 --- a/tests/support/testdata.ts +++ b/tests/support/template/testdata.ts @@ -1,12 +1,23 @@ -import { PATHS } from './constants'; +import path from 'path'; -const walletsDir = process.env.WALLETS_DIR || PATHS.WALLETS_DIR; +const walletsDir = process.env.WALLETS_DIR + ? path.resolve(process.env.WALLETS_DIR) + : path.resolve(__dirname, '..', 'wallets'); + +export const NA = 'N/A'; export enum OriginPageEnum { - multiversxWallet = '/devnet-wallet.multiversx.com/', - templateDashboard = '/dashboard' + multiversxWallet = 'devnet-wallet.multiversx.com', + templateHome = 'localhost:3000/home', + templateDashboard = 'localhost:3000/dashboard', + templateUnlock = 'localhost:3000/unlock' } +export const UrlRegex = { + templateDashboard: /localhost:3000\/dashboard/, + multiversxWallet: /devnet-wallet\.multiversx\.com/ +} as const; + export enum PingPongEnum { raw = 'raw', abi = 'abi', @@ -53,7 +64,7 @@ export enum SelectorsEnum { privateKeyInput = 'privateKeyInput', cancelButton = 'cancelButton', sidePanel = '#side-panel', - sidePanelCloseIcon = 'mvx-close-icon', + sidePanelCloseIcon = 'svg', // Web wallet selectors signCancelButton = 'signCancelBtn', @@ -71,25 +82,29 @@ export enum SelectorsEnum { errorIcon = '.mvx\\:text-error', // Table containers - transactionsAllTable = '#transactions-all table.transactions-table', - transactionsPingPongTable = '#transactions-ping-pong table.transactions-table', + transactionsAllTable = '#transactions-all table', + transactionsPingPongTable = '#transactions-ping-pong table', transactionsTableBodyRow = 'tbody tr.transactions-table-body-row' } // Test data is parameterized via environment variables so secrets (passwords, // addresses, keystores) come from GitHub Secrets in CI or from local .env. export const TestDataEnums = { - keystorePassword1: process.env.KEYSTORE1_PASSWORD || '', - keystorePassword2: process.env.KEYSTORE2_PASSWORD || '', - keystorePassword3: process.env.KEYSTORE3_PASSWORD || '', - keystorePassword4: process.env.KEYSTORE4_PASSWORD || '', + keystorePassword1: process.env.KEYSTORE1_PASSWORD || NA, + keystorePassword2: process.env.KEYSTORE2_PASSWORD || NA, + keystorePassword3: process.env.KEYSTORE3_PASSWORD || NA, + keystorePassword4: process.env.KEYSTORE4_PASSWORD || NA, + + keystoreWalletAddress1: process.env.KEYSTORE1_ADDRESS || NA, + keystoreWalletAddress2: process.env.KEYSTORE2_ADDRESS || NA, + keystoreWalletAddress3: process.env.KEYSTORE3_ADDRESS || NA, + keystoreWalletAddress4: process.env.KEYSTORE4_ADDRESS || NA, + keystoreWalletAddress5: process.env.KEYSTORE5_ADDRESS || NA, + keystoreWalletAddress6: process.env.KEYSTORE6_ADDRESS || NA, - keystoreWalletAddress1: process.env.KEYSTORE1_ADDRESS || '', - keystoreWalletAddress2: process.env.KEYSTORE2_ADDRESS || '', - keystoreWalletAddress3: process.env.KEYSTORE3_ADDRESS || '', - keystoreWalletAddress4: process.env.KEYSTORE4_ADDRESS || '', - keystoreWalletAddress5: process.env.KEYSTORE5_ADDRESS || '', - keystoreWalletAddress6: process.env.KEYSTORE6_ADDRESS || '', + metamaskMnemonic: process.env.METAMASK_MNEMONIC, + metamaskAddress: process.env.METAMASK_ADDRESS, + metamaskPassword: process.env.METAMASK_PASSWORD, keystoreFilePath1: `${walletsDir}/keystoreFile1.json`, keystoreFilePath2: `${walletsDir}/keystoreFile2.json`, diff --git a/tests/support/types.ts b/tests/support/template/types.ts similarity index 89% rename from tests/support/types.ts rename to tests/support/template/types.ts index 5222f977..43a556a3 100644 --- a/tests/support/types.ts +++ b/tests/support/template/types.ts @@ -1,6 +1,5 @@ /* eslint-disable sort-exports/sort-exports */ -import { Page } from '@playwright/test'; -import { BrowserContext } from '@playwright/test'; +import { BrowserContext, Page } from '@playwright/test'; import { PingPongEnum } from './testdata'; export type FileEncoding = 'base64' | 'utf8' | 'none'; @@ -138,12 +137,6 @@ export interface TransactionRow { isFailed: boolean; } -export interface WaitForPageByUrlSubstringType { - page: Page; - urlSubstring: string; - timeout?: number; -} - export interface WaitForToastToBeClosedType { page: Page; } @@ -165,3 +158,16 @@ export interface WaitForTransactionToastToContainType { toastStatus?: string; toastIndex?: number; } + +export interface GetPageAndWaitForLoadOptions { + maxRetries?: number; + timeout?: number; + viewport?: { width: number; height: number }; + waitForReady?: (page: Page) => Promise; +} + +export type GetPageAndWaitForLoad = ( + context: BrowserContext, + urlSubstring: string | RegExp, + options?: GetPageAndWaitForLoadOptions +) => Promise; diff --git a/tests/support/waitForToastToBeClosed.ts b/tests/support/template/waitForToastToBeClosed.ts similarity index 100% rename from tests/support/waitForToastToBeClosed.ts rename to tests/support/template/waitForToastToBeClosed.ts diff --git a/tests/support/waitForToastToBeDisplayed.ts b/tests/support/template/waitForToastToBeDisplayed.ts similarity index 100% rename from tests/support/waitForToastToBeDisplayed.ts rename to tests/support/template/waitForToastToBeDisplayed.ts diff --git a/tests/support/waitForTransactionToastToShow.ts b/tests/support/template/waitForTransactionToastToShow.ts similarity index 100% rename from tests/support/waitForTransactionToastToShow.ts rename to tests/support/template/waitForTransactionToastToShow.ts diff --git a/tests/support/template/waitUntilStable.ts b/tests/support/template/waitUntilStable.ts new file mode 100644 index 00000000..d57887ac --- /dev/null +++ b/tests/support/template/waitUntilStable.ts @@ -0,0 +1,21 @@ +import { Page } from '@playwright/test'; + +const DEFAULT_TIMEOUT = 10000; +const RESOURCES_LOAD_DELAY = 1000; // Extra delay for font resources to load + +export const waitUntilStable = async (page: Page) => { + try { + await page.waitForLoadState('domcontentloaded', { + timeout: DEFAULT_TIMEOUT + }); + await page.waitForLoadState('load', { timeout: DEFAULT_TIMEOUT }); + + await new Promise((resolve) => setTimeout(resolve, RESOURCES_LOAD_DELAY)); + } catch (error) { + throw new Error( + `Failed to wait for page stability: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); + } +}; diff --git a/tests/support/waitForPageByUrlSubstring.ts b/tests/support/waitForPageByUrlSubstring.ts deleted file mode 100644 index c75b3f0e..00000000 --- a/tests/support/waitForPageByUrlSubstring.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Page } from '@playwright/test'; -import { TEST_CONSTANTS } from './constants'; -import { - CreateNotFoundErrorType, - WaitForPageByUrlSubstringType -} from './types'; - -const getPagesSafely = async (page: Page): Promise => { - try { - return await page.context().pages(); - } catch (error) { - throw new Error( - 'Browser context is closed or invalid. Cannot access pages. ' + - `Original error: ${error}` - ); - } -}; - -const findPageByUrl = (pages: Page[], urlSubstring: string): Page | undefined => - pages.find((browserPage) => browserPage.url().includes(urlSubstring)); - -const getPageUrlSafely = (page: Page): string => { - try { - return page.url(); - } catch { - return 'Unable to get page URL'; - } -}; - -const createNotFoundError = ({ - urlSubstring, - timeout, - currentPageUrl, - availablePagesUrls -}: CreateNotFoundErrorType): Error => - new Error( - `No page found with URL containing "${urlSubstring}" after ${timeout}ms. ` + - `Current page URL: ${currentPageUrl}, Available pages: ${availablePagesUrls}` - ); - -export const waitForPageByUrlSubstring = async ({ - page, - urlSubstring, - timeout = TEST_CONSTANTS.PAGE_WAIT_TIMEOUT -}: WaitForPageByUrlSubstringType) => { - const startTime = Date.now(); - const searchInterval = 100; // Check every 100ms - - // Search for the page by URL substring - while (Date.now() - startTime < timeout) { - const allPages = await getPagesSafely(page); - const foundPage = findPageByUrl(allPages, urlSubstring); - - if (foundPage) { - return foundPage; - } - - // Wait before next search - await new Promise((resolve) => setTimeout(resolve, searchInterval)); - } - - // Timeout reached - create detailed error message of all available pages - const allPages = await getPagesSafely(page); - const currentPageUrl = getPageUrlSafely(page); - const availablePagesUrls = allPages - .map((p) => getPageUrlSafely(p)) - .join(', '); - - throw createNotFoundError({ - urlSubstring, - timeout, - currentPageUrl, - availablePagesUrls - }); -}; diff --git a/tests/test/wallet-setup/basic.setup.ts b/tests/test/wallet-setup/basic.setup.ts new file mode 100644 index 00000000..84f00e15 --- /dev/null +++ b/tests/test/wallet-setup/basic.setup.ts @@ -0,0 +1,34 @@ +import { defineWalletSetup } from '@synthetixio/synpress'; +import { getExtensionId, MetaMask } from '@synthetixio/synpress/playwright'; + +// Get password and mnemonic from environment variables +const METAMASK_ADDRESS = process.env.METAMASK_ADDRESS; +const METAMASK_MNEMONIC = process.env.METAMASK_MNEMONIC; +const METAMASK_PASSWORD = process.env.METAMASK_PASSWORD; + +// Validate that required environment variables are present +if (!METAMASK_PASSWORD || !METAMASK_MNEMONIC || !METAMASK_ADDRESS) { + throw new Error( + 'METAMASK_PASSWORD, METAMASK_MNEMONIC, and METAMASK_ADDRESS environment variables are missing. Please set them in .env.test.local for local development or as a GitHub Secret for CI.' + ); +} + +// Define the basic wallet setup with hash override to fix cache mismatch issue +// This is a workaround for the Synpress cache hash calculation difference between CLI and test runtime +const walletSetup = { + ...defineWalletSetup(METAMASK_PASSWORD, async (context, walletPage) => { + const extensionId = await getExtensionId(context, 'MetaMask'); + const metamask = new MetaMask( + context, + walletPage, + METAMASK_PASSWORD, + extensionId + ); + await metamask.importWallet(METAMASK_MNEMONIC); + }), + // Harcode hash to fix cache mismatch issue + // Find a better way to fix this in the future + hash: '880a8ff1e48d99ce5f2d' +}; + +export default walletSetup; diff --git a/vite.config.ts b/vite.config.ts index 59354118..adeeedc5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,7 +13,8 @@ export default defineConfig({ https: true, watch: { usePolling: false, - useFsEvents: false + useFsEvents: false, + ignored: ['**/.cache/**'] }, hmr: { overlay: false