diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml
new file mode 100644
index 0000000..b32ebc9
--- /dev/null
+++ b/.github/workflows/run-merge-e2e-tests.yml
@@ -0,0 +1,63 @@
+name: Playwright merge E2E Tests
+on:
+ pull_request:
+ branches: [main, development]
+ workflow_dispatch:
+jobs:
+ E2E-RUN:
+ runs-on: runner-dapp
+ env:
+ KEYSTORE1_JSON_B64: ${{ secrets.KEYSTORE1_JSON_B64 }}
+ KEYSTORE1_PASSWORD: ${{ secrets.KEYSTORE1_PASSWORD }}
+ KEYSTORE1_ADDRESS: ${{ secrets.KEYSTORE1_ADDRESS }}
+
+ KEYSTORE2_JSON_B64: ${{ secrets.KEYSTORE2_JSON_B64 }}
+ KEYSTORE2_PASSWORD: ${{ secrets.KEYSTORE2_PASSWORD }}
+ KEYSTORE2_ADDRESS: ${{ secrets.KEYSTORE2_ADDRESS }}
+
+ KEYSTORE3_JSON_B64: ${{ secrets.KEYSTORE3_JSON_B64 }}
+ KEYSTORE3_PASSWORD: ${{ secrets.KEYSTORE3_PASSWORD }}
+ KEYSTORE3_ADDRESS: ${{ secrets.KEYSTORE3_ADDRESS }}
+
+ KEYSTORE4_JSON_B64: ${{ secrets.KEYSTORE4_JSON_B64 }}
+ KEYSTORE4_PASSWORD: ${{ secrets.KEYSTORE4_PASSWORD }}
+ KEYSTORE4_ADDRESS: ${{ secrets.KEYSTORE4_ADDRESS }}
+
+ KEYSTORE5_PEM_B64: ${{ secrets.KEYSTORE5_PEM_B64 }}
+ KEYSTORE5_ADDRESS: ${{ secrets.KEYSTORE5_ADDRESS }}
+
+ 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
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ - name: Setup Yarn
+ run: npm install -g yarn
+ - name: Install Dependencies
+ uses: nick-fields/retry@v3
+ with:
+ timeout_minutes: 120
+ retry_on: error
+ max_attempts: 2
+ command: yarn install
+ - name: Install Playwright Browsers
+ run: npx playwright install --with-deps chromium
+ - name: Build Next.js app
+ run: yarn build:devnet
+ - name: Run Playwright E2E Tests
+ run: xvfb-run yarn run run-playwright-test
+ - name: Upload Playwright test report
+ uses: actions/upload-artifact@v4
+ if: ${{ !cancelled() }}
+ with:
+ name: playwright-report
+ path: playwright-report/
+ retention-days: 1
diff --git a/.gitignore b/.gitignore
index a85e034..d5d6897 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,8 +43,17 @@ yalc.lock
.idea
.yalc
-
#cypress
cypress/reports/
cypress/screenshots/
cypress/videos/
+
+# playwright
+playwright-report/
+test-results/
+
+# secrets (local only)
+tests/support/wallets/
+
+# metamask cache
+.cache/
\ No newline at end of file
diff --git a/cypress/assets/globalData.ts b/cypress/assets/globalData.ts
deleted file mode 100644
index f3060f0..0000000
--- a/cypress/assets/globalData.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export const userData = {
- passsword: 'Develop13#',
- adress: 'erd1z9ewlfndgp6dwu8s6cprl2e0xw70fyeazsmwa28xpwaga75qfquqmzjm29'
-};
diff --git a/cypress/assets/index.ts b/cypress/assets/index.ts
deleted file mode 100644
index 12d65e6..0000000
--- a/cypress/assets/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './globalData';
diff --git a/cypress/assets/testKeystore.json b/cypress/assets/testKeystore.json
deleted file mode 100644
index 77b9ae7..0000000
--- a/cypress/assets/testKeystore.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "version": 4,
- "id": "2c3ba9b9-0661-4e8b-85f7-7a56913e0ade",
- "kind": "mnemonic",
- "crypto": {
- "ciphertext": "822daae637f8a77af71225ed3e54ad36cbdcb3526c5f3745462ca65b136f398678db5d4c847708b7f70a8e4edf014b03e43219454327ab4958e71ed5e9bd8d0c099f4bc89eea896f39f999de486a1811c0a6ec9bc166af130827826d77f89a8f2d4016ed1a6ebecda3cd472456204affbb8c417748a438ad5ec2f0d3b822d57d3b2c08ebb9d5542753a3c4571c348db0c6",
- "cipherparams": { "iv": "7d1ff8e7e9b362c931a9e1d6113c7e39" },
- "cipher": "aes-128-ctr",
- "kdf": "scrypt",
- "kdfparams": {
- "dklen": 32,
- "salt": "1e598d67730fb6f93c62b9848f4cdb9c8dbe134f1080100d708c6124f7fb5781",
- "n": 4096,
- "r": 8,
- "p": 1
- },
- "mac": "d1605f8a4de5d4e44b78f7bc5707f796e9a529316119cb60ca75fb807f3b81bf"
- }
-}
diff --git a/cypress/constants/enums.ts b/cypress/constants/enums.ts
deleted file mode 100644
index c9a2ec7..0000000
--- a/cypress/constants/enums.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-export enum AssertionEnum {
- contain = 'contain',
- include = 'include',
- beChecked = 'be.checked'
-}
-
-export enum ErrorMessagesEnum {
- invalidAddress = 'Invalid address',
- required = 'Required'
-}
-
-export enum RoutesEnum {
- unlock = '/unlock',
- send = '/send',
- dashboard = '/dashboard'
-}
-
-export enum WalletIDEnum {
- unguardedWallet1 = 'check_0',
- unguardedWallet2 = 'check_1',
- unguardedWallet3 = 'check_2',
- unguardedWallet4 = 'check_3',
- guardedWallet = 'check_9'
-}
-
-export const enum GlobalSelectorsEnum {
- connect = 'Connect',
- signAutoSend = 'sign-auto-send',
- sendTransactions = 'send-transactions',
- swapLock = 'swap-lock',
- transactionToastTitle = 'transactionToastTitle',
- ledgerLoginButton = 'ledgerLoginButton'
-}
-
-export const enum GlobalDataEnum {
- pendingToast = 'Processing',
- confirmedToast = 'transactions successful'
-}
diff --git a/cypress/constants/globalLinks.ts b/cypress/constants/globalLinks.ts
deleted file mode 100644
index 6809dd5..0000000
--- a/cypress/constants/globalLinks.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const DEVNET_API = 'https://devnet-api.multiversx.com';
diff --git a/cypress/e2e/BatchTransactions/BatchTransactions.cy.ts b/cypress/e2e/BatchTransactions/BatchTransactions.cy.ts
deleted file mode 100644
index 7fc46a6..0000000
--- a/cypress/e2e/BatchTransactions/BatchTransactions.cy.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { signTransactions } from './helpers';
-import { WalletIDEnum, GlobalSelectorsEnum } from '../../constants/enums';
-
-describe('Batch Transaction', () => {
- beforeEach(() => {
- cy.login(WalletIDEnum.unguardedWallet1, 'Connect');
- cy.wait(5000);
- });
- afterEach(() => {
- cy.checkToast();
- cy.contains('Button', 'Close').click();
- });
- it('should successfully sign 5 transactions for auto-send batch', () => {
- signTransactions(GlobalSelectorsEnum.signAutoSend);
- });
-
- it('should successfully sign 5 transactions for send-transactions', () => {
- signTransactions(GlobalSelectorsEnum.sendTransactions);
- });
-
- it('should successfully sign 4 transactions for swap-lock', () => {
- cy.wait(3000);
- signTransactions(GlobalSelectorsEnum.swapLock);
- });
-});
diff --git a/cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts b/cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts
deleted file mode 100644
index 20cc188..0000000
--- a/cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { cancelTransactions } from './helpers';
-import { WalletIDEnum } from '../../constants/enums';
-
-describe('cancelTransactions', () => {
- beforeEach(() => {
- cy.login(WalletIDEnum.unguardedWallet1, 'Connect');
- cy.wait(5000);
- });
- afterEach(() => {
- cy.contains('Button', 'Close').click();
- });
- it('should return transaction canceled for auto-send batch ', () => {
- cancelTransactions('sign-auto-send');
- });
-
- it('should return transaction canceled for swap-lock', () => {
- cancelTransactions('swap-lock');
- });
-
- it('should return transaction canceled for send-transactions ', () => {
- cancelTransactions('send-transactions');
- });
-});
diff --git a/cypress/e2e/BatchTransactions/helpers.ts b/cypress/e2e/BatchTransactions/helpers.ts
deleted file mode 100644
index 74e0954..0000000
--- a/cypress/e2e/BatchTransactions/helpers.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { userData } from '../../assets/globalData';
-import { scSelectors } from '../SCTransactions/SCTransactionData';
-
-export const signTransactions = (selector: string) => {
- let i = selector === 'swap-lock' ? 1 : 0;
-
- const widgetInfo = [
- 'Hash',
- 'Receiver',
- 'Amount',
- 'Gas price',
- 'Gas limit',
- 'Data'
- ];
-
- cy.getSelector(selector).click();
- cy.getSelector(scSelectors.accesPass).type(userData.passsword);
- cy.getSelector(scSelectors.submitButton).click();
- for (i; i < 5; i++) {
- cy.getSelector('signBtn').click();
- }
- cy.contains('Processing transactions');
- cy.checkWidgetMsg(widgetInfo);
-};
-
-export const cancelTransactions = (selector: string) => {
- cy.getSelector(selector).click();
- cy.getSelector(scSelectors.accesPass).type(userData.passsword);
- cy.getSelector(scSelectors.submitButton).click();
- cy.getSelector('closeButton').click();
- cy.contains('Transaction canceled');
-};
diff --git a/cypress/e2e/SCTransactions/SCActions.ts b/cypress/e2e/SCTransactions/SCActions.ts
deleted file mode 100644
index f8d36b6..0000000
--- a/cypress/e2e/SCTransactions/SCActions.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { scSelectors } from './SCTransactionData';
-import { userData } from '../../assets/globalData';
-import { AssertionEnum } from '../../constants/enums';
-// Custom function to make Ping or Pong transactions
-export const scTransaction = (type: string) => {
- cy.getSelector(type).then((btn) => {
- cy.wait(1500);
- if (btn.prop('disabled')) {
- return;
- } else {
- cy.wait(1500);
- cy.getSelector(type).click();
- cy.getSelector(scSelectors.accesPass).type(userData.passsword);
- cy.getSelector(scSelectors.submitButton).click();
- cy.getSelector(scSelectors.signButton).click();
- checkPingDetails();
- }
- });
-};
-
-export const checkPingDetails = () => {
- cy.get('p')
- .should(AssertionEnum.contain, 'Contract')
- .should(AssertionEnum.contain, 'Hash')
- .should(AssertionEnum.contain, 'Receiver')
- .should(AssertionEnum.contain, 'Amount')
- .should(AssertionEnum.contain, 'Gas price')
- .should(AssertionEnum.contain, 'Gas limit')
- .should(AssertionEnum.contain, 'Data');
-};
-
-export const pingPongHandler = (type: string) => {
- cy.getSelector(`btnPing${type}`).then((btn) => {
- cy.wait(1500);
- if (btn.prop('disabled')) {
- console.log('btn prop', btn.prop('disabled'));
- scTransaction(`btnPong${type}`);
- } else {
- scTransaction(`btnPing${type}`);
- }
- });
-};
-
-export const initTransaction = () => {
- cy.getSelector('btnPongAbi').click();
- cy.getSelector(scSelectors.accesPass).type(userData.passsword);
- cy.getSelector(scSelectors.submitButton).click();
-};
diff --git a/cypress/e2e/SCTransactions/SCTransaction.cy.ts b/cypress/e2e/SCTransactions/SCTransaction.cy.ts
deleted file mode 100644
index 907984f..0000000
--- a/cypress/e2e/SCTransactions/SCTransaction.cy.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-///
-import { initTransaction, pingPongHandler } from './SCActions';
-import { WalletIDEnum } from '../../constants/enums';
-
-describe('Smart Contract Transactions', () => {
- afterEach(() => {
- cy.contains('Button', 'Close').click();
- });
-
- it('should successfully execute the Ping & Pong ABI', () => {
- cy.login(WalletIDEnum.unguardedWallet1, 'Connect');
- cy.wait(5000);
- pingPongHandler('Abi');
- cy.checkToast();
- });
-
- it('should successfully execute the Ping & Pong RAW ', () => {
- cy.login(WalletIDEnum.unguardedWallet2, 'Connect');
- cy.wait(5000);
- pingPongHandler('Raw');
- cy.checkToast();
- });
-
- it('should successfully execute the Ping & Pong Service', () => {
- cy.login(WalletIDEnum.unguardedWallet3, 'Connect');
- cy.wait(5000);
- pingPongHandler('Service');
- cy.checkToast();
- });
-
- it('should not execute ping&pong aciton', () => {
- cy.login(WalletIDEnum.unguardedWallet4, 'Connect');
- cy.wait(5000);
- initTransaction();
- cy.getSelector('closeButton').click();
- cy.contains('Transaction canceled');
- });
-
- it('should display the guardian modal', () => {
- cy.login(WalletIDEnum.guardedWallet, 'Connect');
- cy.wait(2000);
- initTransaction();
- cy.contains('Verify Guardian');
- });
-});
diff --git a/cypress/e2e/SCTransactions/SCTransactionData.ts b/cypress/e2e/SCTransactions/SCTransactionData.ts
deleted file mode 100644
index b299fae..0000000
--- a/cypress/e2e/SCTransactions/SCTransactionData.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export const SCTransactionData = {
- confirmationMessage: 'transaction successful',
- succesMessage: 'Ping transaction successful',
- modalConfirmation: 'transactionToastTitle',
- ping: 'Ping',
- pong: 'Pong',
- transactions: '/transactions'
-};
-export const scSelectors = {
- accesPass: 'accessPass',
- submitButton: 'submitButton',
- signButton: 'signBtn',
- loginBtn: 'loginBtn',
- webWalletLogin: 'webWalletLoginBtn',
- btnPingAbi: 'btnPingAbi',
- btnPongAbi: 'btnPongAbi',
- btnPingRaw: 'btnPingRaw',
- btnPongRaw: 'btnPongRaw',
- transactionBtn: '[data-cy="transactionBtn"]'
-};
diff --git a/cypress/e2e/Send/Send.cy.ts b/cypress/e2e/Send/Send.cy.ts
deleted file mode 100644
index 3fb89cb..0000000
--- a/cypress/e2e/Send/Send.cy.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { userData } from '../../assets/globalData';
-import { AssertionEnum, RoutesEnum, WalletIDEnum } from '../../constants/enums';
-describe('Send', () => {
- beforeEach(() => {
- cy.login(WalletIDEnum.unguardedWallet1, 'Send transaction');
- });
- afterEach(() => {
- cy.contains('Button', 'Close').click();
- });
- it('should successfully send a demo transaction', () => {
- cy.checkUrl(RoutesEnum.send);
- cy.getSelector('confirmData').should(AssertionEnum.contain, 'Hello_world');
- cy.getSelector('sendTrxBtn').click();
- cy.get('p')
- .should(AssertionEnum.contain, 'Sender')
- .should(
- AssertionEnum.contain,
- 'erd16xlzk48ftvhxp8dyq6d0kkfpgpfechlzycfm9xmdmwna66pvkymqvz4vzq'
- )
- .should(AssertionEnum.contain, 'Transaction status')
- .should(AssertionEnum.contain, 'succes');
- });
-
- it('should display the cancelled status', () => {
- cy.contains('Send transaction').click();
- cy.getSelector('accessPass').type(userData.passsword);
- cy.getSelector('submitButton').click();
-
- cy.getSelector('cancelTrxBtn').click();
- cy.get('p')
- .should(AssertionEnum.contain, 'Transaction status')
- .should(AssertionEnum.contain, 'cancelled');
- });
-});
diff --git a/cypress/e2e/SignMessage/SignMessage.cy.ts b/cypress/e2e/SignMessage/SignMessage.cy.ts
deleted file mode 100644
index fa5e5be..0000000
--- a/cypress/e2e/SignMessage/SignMessage.cy.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { userData } from '../../assets/globalData';
-import { AssertionEnum, RoutesEnum, WalletIDEnum } from '../../constants/enums';
-import { scSelectors } from '../SCTransactions/SCTransactionData';
-
-describe('Sign Message', () => {
- beforeEach(() => {
- cy.login(WalletIDEnum.unguardedWallet1, 'Connect');
- cy.wait(5000);
- });
- afterEach(() => {
- cy.contains('Button', 'Close').click();
- });
- it('should sign', () => {
- const widgetInfo = ['Signature', 'Encoded message', 'Decoded message'];
- cy.getSelector('signMsgBtn').should('be.disabled');
- cy.get('textarea').first().type('Test');
- cy.getSelector('signMsgBtn').click();
- cy.getSelector(scSelectors.accesPass).type(userData.passsword);
- cy.getSelector(scSelectors.submitButton).click();
- cy.getSelector('message').should('have.value', 'Test');
- cy.getSelector('signButton').click();
- widgetInfo.forEach((element) => {
- cy.get('label').should(AssertionEnum.contain, element);
- });
- cy.getSelector('closeTransactionSuccessBtn').click();
- cy.getSelector('signMsgBtn').should('be.disabled');
- });
-
- it('should not sign', () => {
- cy.get('textarea').first().type('Test');
- cy.getSelector('signMsgBtn').click();
- cy.wait(2000);
- cy.getSelector(scSelectors.accesPass).type(userData.passsword);
- cy.getSelector(scSelectors.submitButton).click();
- cy.getSelector('closeBtn').click();
- cy.checkUrl(RoutesEnum.dashboard);
- cy.contains('Transaction canceled');
- });
-});
diff --git a/cypress/e2e/Unlock/Unlock.cy.ts b/cypress/e2e/Unlock/Unlock.cy.ts
deleted file mode 100644
index aafd800..0000000
--- a/cypress/e2e/Unlock/Unlock.cy.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { GlobalSelectorsEnum } from '../../constants/enums';
-
-describe('Unlock', () => {
- beforeEach(() => {
- cy.visit('/');
- });
-
- it('should open the xPortal modal', () => {
- cy.contains('xPortal App').click();
- cy.contains('Scan the QR code using the xPortal App');
- });
-
- it('should open the ledger modal', () => {
- cy.getSelector(GlobalSelectorsEnum.ledgerLoginButton);
- cy.contains('Connect Ledger');
- });
-});
diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
deleted file mode 100644
index c8a211b..0000000
--- a/cypress/support/commands.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-///
-import { userData } from '../assets/globalData';
-import {
- AssertionEnum,
- GlobalSelectorsEnum,
- GlobalDataEnum
-} from '../constants/enums';
-import { DEVNET_API } from '../constants/globalLinks';
-
-// Check the url global function
-Cypress.Commands.add('checkUrl', (url) => {
- cy.url().should(AssertionEnum.include, url);
-});
-
-//Login with keystore global function
-Cypress.Commands.add('login', (walletID, selector) => {
- // cy.session(walletID, () => {
- cy.visit('/');
- cy.contains(selector).click();
- if (selector === GlobalSelectorsEnum.connect) {
- cy.getSelector('webWalletLoginBtn').click();
- }
- cy.getSelector('keystoreBtn').click();
- cy.checkUrl('/unlock/keystore');
- cy.getSelector('submitButton').click();
- cy.checkUrl('/unlock/keystore');
-
- cy.get('input[type=file]').selectFile('./cypress/assets/testKeystore.json', {
- force: true
- });
- cy.getSelector('accessPass').type(userData.passsword);
- cy.getSelector('submitButton').click();
-
- cy.getSelector(walletID).click();
- cy.getSelector('confirmBtn').click();
-});
-// });
-
-Cypress.Commands.add('getSelector', (selector, ...cypressAction) => {
- return cy.get(`[data-testid=${selector}]`, ...cypressAction);
-});
-
-// Add the custom command for api intercepts
-Cypress.Commands.add('apiIntercept', (method, param) => {
- cy.intercept(method, `${DEVNET_API}${param}`).as(param);
-});
-
-Cypress.on('uncaught:exception', () => {
- // Do nothing or handle the exception as per your requirements
- // You can remove the comment and add your custom handling logic here
- // console.log('An uncaught exception occurred but will be ignored');
- return false; // Prevent Cypress from failing the test
-});
-Cypress.Commands.add('checkWidgetMsg', (msgArr) => {
- msgArr.forEach((element) => {
- cy.get('p').should(AssertionEnum.contain, element);
- });
-});
-
-Cypress.Commands.add('checkToast', () => {
- cy.getSelector(GlobalSelectorsEnum.transactionToastTitle).should(
- AssertionEnum.contain,
- GlobalDataEnum.pendingToast
- );
- cy.wait(5000);
- cy.getSelector(GlobalSelectorsEnum.transactionToastTitle).should(
- AssertionEnum.contain,
- GlobalDataEnum.confirmedToast
- );
-});
diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts
deleted file mode 100644
index 1221b17..0000000
--- a/cypress/support/e2e.ts
+++ /dev/null
@@ -1 +0,0 @@
-import './commands';
diff --git a/cypress/support/index.ts b/cypress/support/index.ts
deleted file mode 100644
index 24f5588..0000000
--- a/cypress/support/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-// eslint-disable-next-line @typescript-eslint/no-namespace, @typescript-eslint/no-unused-vars
-declare namespace Cypress {
- interface Chainable {
- checkUrl: (url: string) => void;
- login: (walletID: string, selector: string) => void;
- apiIntercept: (method: string, param: string) => void;
- checkWidgetMsg: (msgArr: string[]) => void;
- checkToast: () => void;
-
- getSelector: (
- selector: string,
- ...cypressAction: []
- ) => Chainable>;
- }
-}
diff --git a/package.json b/package.json
index 3f9e4ea..91190c1 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,8 @@
"build:devnet": "yarn run copy-devnet-config & next build",
"preview": "next start",
"test": "jest",
- "cy:run": "node scripts/cypress.ts"
+ "run-playwright-test": "playwright test",
+ "run-playwright-test-ui": "playwright test --ui"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "6.5.1",
@@ -28,18 +29,20 @@
"@multiversx/sdk-dapp": "^5.x",
"@multiversx/sdk-dapp-ui": "^0.x",
"@multiversx/sdk-dapp-utils": "3.0.2",
+ "@playwright/test": "^1.57.0",
"axios": "^1.10.0",
+ "bignumber.js": "^9.x",
"classnames": "2.3.2",
"eslint": "8.50.0",
"eslint-config-next": "13.5.3",
- "bignumber.js": "^9.x",
"moment": "2.29.4",
"next": "13.5.4",
"next-transpile-modules": "10.0.1",
"protobufjs": "7.5.4",
"react": "18.2.0",
"react-dom": "18.2.0",
- "typescript": "5.2.2"
+ "typescript": "5.2.2",
+ "vite": "^7.2.4"
},
"devDependencies": {
"@swc/core": "1.3.91",
diff --git a/playwright.config.ts b/playwright.config.ts
new file mode 100644
index 0000000..bd79a2f
--- /dev/null
+++ b/playwright.config.ts
@@ -0,0 +1,75 @@
+import { defineConfig, devices } from '@playwright/test';
+import { TEST_CONFIG } from './tests/config';
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ globalSetup: './tests/support/template/globalSetup.ts',
+ /* timeout for each test */
+ timeout: TEST_CONFIG.timeout,
+ /* timeout for locators */
+ expect: { timeout: TEST_CONFIG.expectTimeout },
+ /* directory where the tests are located */
+ testDir: './tests',
+ /* pattern to match the tests */
+ testMatch: '**/*.spec.ts',
+
+ /* Run tests in files in parallel */
+ fullyParallel: TEST_CONFIG.fullyParallel,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: TEST_CONFIG.retries,
+ /* Parallel tests on CI only. */
+ workers: TEST_CONFIG.workers,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: 'https://localhost:3002',
+ ignoreHTTPSErrors: true,
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ // Default to headless mode; will be overridden by the environment variable
+ headless: true,
+
+ /* Capture screenshot on test failure */
+ screenshot: 'only-on-failure',
+
+ /* Record video on any failure */
+ video: 'retain-on-failure'
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ use: {
+ ...devices['Desktop Chrome'],
+ launchOptions: {
+ args: [
+ '--start-maximized',
+ '--disable-web-security',
+ '--disable-features=VizDisplayCompositor'
+ ]
+ }
+ }
+ }
+ ],
+ webServer: {
+ command: 'yarn start:devnet',
+ url: 'https://localhost:3002',
+ timeout: 120 * 1000,
+ reuseExistingServer: !process.env.CI,
+ stdout: 'pipe',
+ stderr: 'pipe',
+ ignoreHTTPSErrors: true
+ }
+});
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
index a0c316b..fdcb0a7 100644
--- a/src/app/dashboard/page.tsx
+++ b/src/app/dashboard/page.tsx
@@ -58,7 +58,8 @@ const WIDGETS: WidgetType[] = [
widget: NativeAuth,
description:
'A secure authentication token can be used to interact with the backend',
- reference: 'https://github.com/multiversx/mx-sdk-js-native-auth-server'
+ reference: 'https://github.com/multiversx/mx-sdk-js-native-auth-server',
+ anchor: 'native-auth'
},
{
title: 'Batch Transactions',
diff --git a/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx b/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx
index 883eefa..001c16b 100644
--- a/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx
+++ b/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx
@@ -6,27 +6,16 @@ import { OutputContainer } from '@/components/OutputContainer';
import {
useGetLoginInfo,
- useGetNetworkConfig,
- MvxFormatAmount,
- FormatAmountController,
- DIGITS,
- DECIMALS
+ useGetAccount,
+ FormatAmount
} from '@/lib';
import { useGetProfile } from './hooks';
import { Username } from '../Account/components';
export const NativeAuth = () => {
const { tokenLogin, isLoggedIn } = useGetLoginInfo();
+ const { balance } = useGetAccount();
const { isLoading, profile, getProfile } = useGetProfile();
- const { network } = useGetNetworkConfig();
-
- const { isValid, valueDecimal, valueInteger, label } =
- FormatAmountController.getData({
- digits: DIGITS,
- decimals: DECIMALS,
- egldLabel: network.egldLabel,
- input: profile?.balance ?? '0'
- });
useEffect(() => {
// On page refresh, tokenInfo is null which implies that we do not have access to loginInfo data
@@ -62,12 +51,10 @@ export const NativeAuth = () => {
-
diff --git a/src/app/unlock/page.tsx b/src/app/unlock/page.tsx
index f2b6555..56b9eeb 100644
--- a/src/app/unlock/page.tsx
+++ b/src/app/unlock/page.tsx
@@ -12,7 +12,7 @@ export default function Unlock() {
loginHandler: () => {
router.push(RouteNamesEnum.dashboard);
},
- onClose: () => {
+ onClose: async () => {
router.replace(RouteNamesEnum.home);
}
});
diff --git a/src/lib/sdkDappUI/sdkDappUI.components.ts b/src/lib/sdkDappUI/sdkDappUI.components.ts
index ec5d3e6..e903982 100644
--- a/src/lib/sdkDappUI/sdkDappUI.components.ts
+++ b/src/lib/sdkDappUI/sdkDappUI.components.ts
@@ -2,6 +2,5 @@ export {
MvxCopyButton,
MvxExplorerLink,
MvxFormatAmount,
- MvxTransactionsTable,
- MvxUnlockButton
+ MvxTransactionsTable
} from '@multiversx/sdk-dapp-ui/react';
diff --git a/tests/config.ts b/tests/config.ts
new file mode 100644
index 0000000..74d7584
--- /dev/null
+++ b/tests/config.ts
@@ -0,0 +1,14 @@
+export const TEST_CONFIG = {
+ /* Retry on CI only */
+ retries: process.env.CI ? 1 : 0,
+ /* Parallel tests on CI only. */
+ workers: 5,
+ /* Timeout for each test */
+ timeout: 120_000,
+ /* Timeout for locators */
+ expectTimeout: 60_000,
+ /* Run tests in files in parallel */
+ fullyParallel: false
+} as const;
+
+export const WALLET_URL_TIMEOUT_MS = 10_000;
diff --git a/tests/connectWallet/memoryProvider.spec.ts b/tests/connectWallet/memoryProvider.spec.ts
new file mode 100644
index 0000000..2ddc7c4
--- /dev/null
+++ b/tests/connectWallet/memoryProvider.spec.ts
@@ -0,0 +1,30 @@
+import { test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import { readValueFromFile } from '../support/template';
+import { TestDataEnums } from '../support/template/testdata';
+
+const privateKeyConfig = {
+ address: TestDataEnums.keystoreWalletAddress6,
+ privateKey: readValueFromFile(TestDataEnums.keystoreFilePath6, 'utf8').trim()
+};
+
+test.describe('Connect a wallet', () => {
+ // Connect wallet tests verify wallet connection functionality
+
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ });
+
+ test.describe('In Memory Provider Connection', () => {
+ test('should successfully connect with Address and Private Key', async ({
+ page
+ }) => {
+ await TestActions.connectInMemoryProvider({
+ page,
+ loginMethod: privateKeyConfig
+ });
+
+ await TestActions.checkConnectionToWallet(page, privateKeyConfig.address);
+ });
+ });
+});
diff --git a/tests/connectWallet/metaMask.spec.ts b/tests/connectWallet/metaMask.spec.ts
new file mode 100644
index 0000000..734bedf
--- /dev/null
+++ b/tests/connectWallet/metaMask.spec.ts
@@ -0,0 +1,94 @@
+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, UrlRegex } from '../support/template/testdata';
+import { TEST_CONSTANTS } from '../support/template/constants';
+
+// 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, {
+ timeout: TEST_CONSTANTS.URL_NAVIGATION_TIMEOUT
+ });
+
+ // Verify connection using TestActions helper
+ await TestActions.checkConnectionToWallet(page, METAMASK_ADDRESS);
+ });
+ });
+});
diff --git a/tests/connectWallet/webWallet.spec.ts b/tests/connectWallet/webWallet.spec.ts
new file mode 100644
index 0000000..b449d69
--- /dev/null
+++ b/tests/connectWallet/webWallet.spec.ts
@@ -0,0 +1,61 @@
+import { expect, test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import { TestDataEnums } from '../support/template/testdata';
+
+const keystoreConfig = {
+ keystore: TestDataEnums.keystoreFilePath1,
+ password: TestDataEnums.keystorePassword1,
+ address: TestDataEnums.keystoreWalletAddress1
+};
+
+const pemConfig = {
+ pem: TestDataEnums.keystoreFilePath5
+};
+
+test.describe('Connect a wallet', () => {
+ // Connect wallet tests verify wallet connection functionality
+
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ });
+
+ test.describe('Keystore Connection', () => {
+ test('should successfully connect with keystore file', async ({ page }) => {
+ await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig });
+
+ await TestActions.checkConnectionToWallet(
+ page,
+ TestDataEnums.keystoreWalletAddress1
+ );
+ });
+ });
+
+ test.describe('PEM Connection', () => {
+ test('should successfully connect with PEM file', async ({ page }) => {
+ await TestActions.connectWebWallet({ page, loginMethod: pemConfig });
+
+ await TestActions.checkConnectionToWallet(
+ page,
+ TestDataEnums.keystoreWalletAddress5
+ );
+ });
+ });
+
+ test.describe('Connection Validation', () => {
+ test('should handle missing password for keystore', async ({ page }) => {
+ // Test with keystore but no password
+ const invalidKeystoreConfig = {
+ keystore: TestDataEnums.keystoreFilePath1,
+ password: undefined
+ };
+
+ // This should throw an error for missing password
+ await expect(
+ TestActions.connectWebWallet({
+ page,
+ loginMethod: invalidKeystoreConfig
+ })
+ ).rejects.toThrow('Password is required when using a keystore');
+ });
+ });
+});
diff --git a/tests/support/fs/downloadFileFromUrl.ts b/tests/support/fs/downloadFileFromUrl.ts
new file mode 100644
index 0000000..53610b0
--- /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/ensureDirectoryExists.ts b/tests/support/fs/ensureDirectoryExists.ts
new file mode 100644
index 0000000..8dfd7c8
--- /dev/null
+++ b/tests/support/fs/ensureDirectoryExists.ts
@@ -0,0 +1,9 @@
+import fs from 'fs';
+import path from 'path';
+
+export const ensureDirectoryExists = (filePath: string) => {
+ const dir = path.dirname(filePath);
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true });
+ }
+};
diff --git a/tests/support/fs/readValueFromFile.ts b/tests/support/fs/readValueFromFile.ts
new file mode 100644
index 0000000..b72424e
--- /dev/null
+++ b/tests/support/fs/readValueFromFile.ts
@@ -0,0 +1,13 @@
+import fs from 'fs';
+
+export const readValueFromFile = (
+ inPath: string,
+ encoding: 'utf8' | 'buffer' = 'utf8'
+): string => {
+ if (encoding === 'buffer') {
+ const data = fs.readFileSync(inPath);
+ return data.toString('utf8');
+ }
+
+ return fs.readFileSync(inPath, 'utf8');
+};
diff --git a/tests/support/fs/writeValueToFile.ts b/tests/support/fs/writeValueToFile.ts
new file mode 100644
index 0000000..a39dcbb
--- /dev/null
+++ b/tests/support/fs/writeValueToFile.ts
@@ -0,0 +1,37 @@
+import fs from 'fs';
+import { ensureDirectoryExists } from './ensureDirectoryExists';
+
+export type FileEncoding = 'base64' | 'utf8' | 'none';
+
+export const writeValueToFile = (
+ value: string,
+ outPath: string,
+ encoding: FileEncoding,
+ skipIfExists: boolean = false
+) => {
+ // Check if file exists and skip if requested
+ if (skipIfExists && fs.existsSync(outPath)) {
+ return;
+ }
+
+ // ensure directory exists
+ ensureDirectoryExists(outPath);
+
+ 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}`);
+ }
+};
diff --git a/tests/support/metaMask/constants.ts b/tests/support/metaMask/constants.ts
new file mode 100644
index 0000000..4daa969
--- /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 0000000..12118df
--- /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 0000000..fea2626
--- /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 0000000..7c56eb6
--- /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 Array.from(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 0000000..afd5399
--- /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 = 6000;
+
+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) {
+ attempt++;
+
+ console.warn(
+ `[MetaMaskSnap] Attempt ${attempt}/${maxRetries} failed: ${
+ error instanceof Error ? error.message : 'Unknown 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) {
+ console.error(
+ `[MetaMaskSnap] Failed to click "${action.name}": ${
+ error instanceof Error ? error.message : 'Unknown 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 0000000..291af27
--- /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 0000000..899f12b
--- /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 0000000..6e1bd24
--- /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 0000000..4d2e447
--- /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 0000000..4eb5922
--- /dev/null
+++ b/tests/support/metaMask/setupMetaMaskWallet.ts
@@ -0,0 +1,116 @@
+import { ChromiumBrowserContext, 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: ChromiumBrowserContext,
+ 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.fill(firstWord);
+ await srpInput.press('Enter');
+}
diff --git a/tests/support/metaMask/unzipArchive.ts b/tests/support/metaMask/unzipArchive.ts
new file mode 100644
index 0000000..ca1b9a6
--- /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/template/checkBalanceUpdate.ts b/tests/support/template/checkBalanceUpdate.ts
new file mode 100644
index 0000000..68bdc1a
--- /dev/null
+++ b/tests/support/template/checkBalanceUpdate.ts
@@ -0,0 +1,53 @@
+import { expect, Page } from '@playwright/test';
+import { TEST_CONSTANTS } from './constants';
+import { extractBalanceFromContainer } from './extractBalanceFromContainer';
+import { CheckBalanceUpdateType } from './types';
+
+export const checkBalanceUpdate = async ({
+ page,
+ containerSelector,
+ initialBalance,
+ expectedChange
+}: CheckBalanceUpdateType) => {
+ const expectedBalance = initialBalance + expectedChange;
+
+ const pollFunction = async () => {
+ const balance = await extractBalanceFromContainer({
+ page,
+ containerSelector,
+ selectorType: 'testId'
+ });
+
+ return balance;
+ };
+
+ await expect
+ .poll(pollFunction, {
+ message: `Balance should reach ${expectedBalance} (change: ${expectedChange})`,
+ timeout: TEST_CONSTANTS.BALANCE_POLLING_TIMEOUT
+ })
+ .toBeCloseTo(expectedBalance, TEST_CONSTANTS.BALANCE_PRECISION);
+};
+
+export const checkPingPongBalanceUpdate = async ({
+ page,
+ containerSelector,
+ initialBalance,
+ isPing
+}: {
+ page: Page;
+ containerSelector: string;
+ initialBalance: number;
+ isPing: boolean;
+}) => {
+ const expectedChange = isPing
+ ? TEST_CONSTANTS.PING_BALANCE_CHANGE
+ : TEST_CONSTANTS.PONG_BALANCE_CHANGE;
+
+ await checkBalanceUpdate({
+ page,
+ containerSelector,
+ initialBalance,
+ expectedChange
+ });
+};
diff --git a/tests/support/template/checkButtonStatus.ts b/tests/support/template/checkButtonStatus.ts
new file mode 100644
index 0000000..64c79ee
--- /dev/null
+++ b/tests/support/template/checkButtonStatus.ts
@@ -0,0 +1,27 @@
+import { expect } from '@playwright/test';
+import { PingPongEnum } from './testdata';
+import { CheckButtonStatusType } from './types';
+
+export const checkButtonStatus = async ({
+ page,
+ type,
+ lastClickedButton
+}: CheckButtonStatusType) => {
+ const container = page.locator(`#ping-pong-${type}`);
+ await container.scrollIntoViewIfNeeded();
+
+ const suffix = type === PingPongEnum.abi ? 'Abi' : 'Raw';
+ const pingButton = container.getByTestId(`btnPing${suffix}`);
+ const pongButton = container.getByTestId(`btnPong${suffix}`);
+
+ // Check that ping button became disabled by looking for disabled attribute
+ if (lastClickedButton === 'ping') {
+ await expect(pingButton).toHaveAttribute('disabled');
+ return;
+ }
+
+ if (lastClickedButton === 'pong') {
+ await expect(pongButton).toHaveAttribute('disabled');
+ return;
+ }
+};
diff --git a/tests/support/template/checkClipboardContains.ts b/tests/support/template/checkClipboardContains.ts
new file mode 100644
index 0000000..1c9b9c8
--- /dev/null
+++ b/tests/support/template/checkClipboardContains.ts
@@ -0,0 +1,41 @@
+import { expect } from '@playwright/test';
+import { pasteStringFromClipboard } from './pasteStringFromClipboard';
+import { CheckClipboardContainsType } from './types';
+
+export const checkClipboardContains = async ({
+ page,
+ context,
+ text,
+ timeout = 5000 // 5 seconds
+}: CheckClipboardContainsType) => {
+ const startTime = Date.now();
+ const maxAttempts = 10;
+ let attempts = 0;
+
+ while (attempts < maxAttempts) {
+ try {
+ const clipboardText = await pasteStringFromClipboard(page, context);
+ if (clipboardText.includes(text)) {
+ return; // Success - text found
+ }
+ } catch (error) {
+ // Retry
+ }
+
+ attempts++;
+
+ // Check if we've exceeded the timeout
+ if (Date.now() - startTime > timeout) {
+ throw new Error(
+ `Clipboard check timed out after ${timeout}ms. Expected text "${text}" was not found.`
+ );
+ }
+
+ // Wait a bit before the next attempt
+ await page.waitForTimeout(500);
+ }
+
+ // Game over - we've exhausted all attempts
+ const finalClipboardText = await pasteStringFromClipboard(page, context);
+ expect(finalClipboardText).toContain(text);
+};
diff --git a/tests/support/template/checkConnectionToWallet.ts b/tests/support/template/checkConnectionToWallet.ts
new file mode 100644
index 0000000..f4cd674
--- /dev/null
+++ b/tests/support/template/checkConnectionToWallet.ts
@@ -0,0 +1,12 @@
+import { expect, Page } from '@playwright/test';
+import { SelectorsEnum } from './testdata';
+
+// Check if the template is connected to the web wallet by veryfing that
+// the template page contains the wallet address which confirms the connection
+export const checkConnectionToWallet = async (
+ page: Page,
+ walletAddress: string
+) => {
+ const addressElement = await page.getByTestId(SelectorsEnum.accountAddress);
+ await expect(addressElement).toContainText(walletAddress);
+};
diff --git a/tests/support/template/confirmPrivateKeyTransaction.ts b/tests/support/template/confirmPrivateKeyTransaction.ts
new file mode 100644
index 0000000..adaf903
--- /dev/null
+++ b/tests/support/template/confirmPrivateKeyTransaction.ts
@@ -0,0 +1,10 @@
+import { Page } from '@playwright/test';
+import { SelectorsEnum } from './testdata';
+
+export const confirmPrivateKeyTransaction = async (
+ page: Page,
+ privateKey: string
+) => {
+ await page.getByTestId(SelectorsEnum.privateKeyInput).fill(privateKey);
+ await page.getByTestId(SelectorsEnum.submitButton).click();
+};
diff --git a/tests/support/template/confirmWalletTransaction.ts b/tests/support/template/confirmWalletTransaction.ts
new file mode 100644
index 0000000..e5d284c
--- /dev/null
+++ b/tests/support/template/confirmWalletTransaction.ts
@@ -0,0 +1,38 @@
+import { Page } from '@playwright/test';
+import { SelectorsEnum } from './testdata';
+import { getTestIdSelector } from './testIdSelector';
+import { WebWalletLoginMethodType } from './types';
+
+const confirmWithKeystore = async (walletPage: Page, password: string) => {
+ await walletPage.getByTestId(SelectorsEnum.passwordInput).fill(password);
+ await walletPage.getByTestId(SelectorsEnum.submitButton).click();
+};
+
+const confirmWithPem = async (walletPage: Page, pemPath: string) => {
+ await walletPage.setInputFiles(
+ getTestIdSelector(SelectorsEnum.walletFile),
+ pemPath
+ );
+ await walletPage.getByTestId(SelectorsEnum.submitButton).click();
+};
+
+export const confirmWalletTransaction = async (
+ page: Page,
+ loginMethod: WebWalletLoginMethodType
+) => {
+ switch (true) {
+ // Authenticate with keystore
+ case Boolean(loginMethod.keystore):
+ await confirmWithKeystore(page, loginMethod.password ?? '');
+ return;
+
+ // Authenticate with PEM
+ case Boolean(loginMethod.pem):
+ await confirmWithPem(page, loginMethod.pem!);
+ return;
+
+ // No authentication method provided
+ default:
+ return;
+ }
+};
diff --git a/tests/support/template/connectInMemoryProvider.ts b/tests/support/template/connectInMemoryProvider.ts
new file mode 100644
index 0000000..5836976
--- /dev/null
+++ b/tests/support/template/connectInMemoryProvider.ts
@@ -0,0 +1,32 @@
+import { SelectorsEnum } from './testdata';
+import { InMemoryProviderType } from './types';
+
+const authenticateWithInMemoryProvider = async ({
+ page,
+ loginMethod
+}: InMemoryProviderType) => {
+ await page.locator(SelectorsEnum.addressInput).fill(loginMethod.address);
+ await page
+ .locator(SelectorsEnum.privateKeyInput)
+ .fill(loginMethod.privateKey);
+
+ await page.getByRole('button', { name: 'Submit' }).click();
+};
+
+export const connectInMemoryProvider = async ({
+ page,
+ loginMethod
+}: InMemoryProviderType) => {
+ await page.getByTestId(SelectorsEnum.inMemoryButton).click();
+
+ if (!loginMethod.address || !loginMethod.privateKey) {
+ throw new Error(
+ 'Both address and private key are required when using an in memory provider.'
+ );
+ }
+
+ await authenticateWithInMemoryProvider({
+ page,
+ loginMethod
+ });
+};
diff --git a/tests/support/template/connectWebWallet.ts b/tests/support/template/connectWebWallet.ts
new file mode 100644
index 0000000..dd2dfaf
--- /dev/null
+++ b/tests/support/template/connectWebWallet.ts
@@ -0,0 +1,120 @@
+import { TEST_CONSTANTS } from './constants';
+import { getPageAndWaitForLoad } from './getPageAndWaitForLoad';
+import { OriginPageEnum, SelectorsEnum } from './testdata';
+import { getTestIdSelector } from './testIdSelector';
+import {
+ AuthenticateWithKeystoreType,
+ AuthenticateWithPemType,
+ ConnectWebWalletType
+} from './types';
+
+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 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();
+};
+
+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();
+};
+
+export const connectWebWallet = async ({
+ page,
+ loginMethod
+}: ConnectWebWalletType) => {
+ // Click the cross-window button to open wallet
+ await page.getByTestId(SelectorsEnum.crossWindow).click();
+
+ // Wait for the web wallet page to be loaded which is the new tab
+ const walletPage = await getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.multiversxWallet
+ );
+
+ // If the web wallet page is not loaded, throw an error
+ if (!walletPage) {
+ throw new Error(
+ `Web wallet page containing ${OriginPageEnum.multiversxWallet} is not loaded.`
+ );
+ }
+
+ // Authenticate with keystore
+ if (loginMethod.keystore) {
+ if (!loginMethod.password) {
+ throw new Error('Password is required when using a keystore.');
+ }
+
+ await authenticateWithKeystore({
+ walletPage,
+ keystorePath: loginMethod.keystore,
+ keystorePassword: loginMethod.password
+ });
+
+ try {
+ await walletPage.waitForEvent('close', {
+ timeout: TEST_CONSTANTS.PAGE_CLOSE_TIMEOUT
+ });
+ } catch (error) {
+ // do nothing
+ }
+ return;
+ }
+
+ // Authenticate with PEM
+ if (loginMethod.pem) {
+ await authenticateWithPem({
+ walletPage,
+ pemPath: loginMethod.pem
+ });
+
+ try {
+ await walletPage.waitForEvent('close', {
+ timeout: TEST_CONSTANTS.PAGE_CLOSE_TIMEOUT
+ });
+ } catch (error) {
+ // do nothing
+ }
+ return;
+ }
+};
diff --git a/tests/support/template/constants.ts b/tests/support/template/constants.ts
new file mode 100644
index 0000000..af40153
--- /dev/null
+++ b/tests/support/template/constants.ts
@@ -0,0 +1,25 @@
+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
+ MIN_BALANCE_FOR_WRAP_AND_MULTI_TRANSFER: 4, // 4 EGLD
+ MIN_BALANCE_FOR_SWAP_AND_LOCK: 4, // 4 EGLD
+
+ URL_NAVIGATION_TIMEOUT: 10000, // 10 seconds
+ BALANCE_POLLING_TIMEOUT: 90000, // 90 seconds
+ PAGE_WAIT_TIMEOUT: 30000, // 30 seconds
+ TOAST_WAIT_TIMEOUT: 60000, // 60 seconds
+
+ PING_PONG_COOLDOWN: 3 * 60 * 1000, // 3 minutes in milliseconds
+ PING_BALANCE_CHANGE: -1.0, // Balance decreases by 1 EGLD + gas fees
+ PONG_BALANCE_CHANGE: 1.0, // Balance increases by 1 EGLD - gas fees
+
+ BALANCE_PRECISION: 2,
+
+ PAGE_CLOSE_TIMEOUT: 10000 // 10 seconds
+} as const;
diff --git a/tests/support/template/extractBalanceFromContainer.ts b/tests/support/template/extractBalanceFromContainer.ts
new file mode 100644
index 0000000..df6a9ad
--- /dev/null
+++ b/tests/support/template/extractBalanceFromContainer.ts
@@ -0,0 +1,39 @@
+import { expect } from '@playwright/test';
+import { SelectorsEnum } from './testdata';
+import { getTestIdSelector } from './testIdSelector';
+import { ExtractBalanceFromContainerType } from './types';
+
+export const extractBalanceFromContainer = async ({
+ page,
+ containerSelector,
+ selectorType = 'testId'
+}: ExtractBalanceFromContainerType): Promise => {
+ const containerElement =
+ selectorType === 'testId'
+ ? page.getByTestId(containerSelector)
+ : page.locator(containerSelector);
+
+ await containerElement.scrollIntoViewIfNeeded();
+
+ const balanceElement = containerElement.getByTestId(SelectorsEnum.balance);
+ await expect(balanceElement).toBeVisible();
+
+ // Integer part
+ const intText = (
+ await balanceElement
+ .locator(getTestIdSelector(SelectorsEnum.formatAmountInt))
+ .innerText()
+ )?.trim();
+
+ // Decimals part
+ const decimalsText = (
+ await balanceElement
+ .locator(getTestIdSelector(SelectorsEnum.formatAmountDecimals))
+ .innerText()
+ )?.trim();
+
+ // Combine with decimal point
+ const fullNumber = decimalsText ? `${intText}.${decimalsText}` : intText;
+
+ return parseFloat(fullNumber || '0');
+};
diff --git a/tests/support/template/getPageAndWaitForLoad.ts b/tests/support/template/getPageAndWaitForLoad.ts
new file mode 100644
index 0000000..86965a2
--- /dev/null
+++ b/tests/support/template/getPageAndWaitForLoad.ts
@@ -0,0 +1,78 @@
+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';
+ const openedPageUrls = context
+ .pages()
+ .map((p) => p.url())
+ .filter(Boolean);
+ console.warn(
+ `[getPageAndWaitForLoad] Retry ${retries}/3 after error: ${message}. Open pages (${
+ openedPageUrls.length
+ }): ${openedPageUrls.join(', ')}`
+ );
+
+ 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/template/globalSetup.ts b/tests/support/template/globalSetup.ts
new file mode 100644
index 0000000..5196214
--- /dev/null
+++ b/tests/support/template/globalSetup.ts
@@ -0,0 +1,95 @@
+// This global setup materializes secret keystore files from environment variables
+// so Playwright tests can reference stable file paths without committing secrets.
+//
+// Secrets source:
+// - On CI (GitHub Actions): injected via repository/environment Secrets
+// (e.g. KEYSTORE1_JSON_B64, KEYSTORE{N}_PASSWORD, KEYSTORE{N}_ADDRESS).
+// - Locally: provided via .env.test.local/.env and loaded here.
+//
+// Why base64?
+// - JSON keystores are stored as KEYSTORE{N}_JSON_B64 to pass safely through
+// CI env vars and avoid accidental logging. We decode and write them to
+// WALLETS_DIR on startup. Passwords/addresses are read directly from env
+// by the tests and are never written to disk.
+
+import path from 'path';
+import { loadLocalEnv } from './loadLocalEnv';
+import { writeValueToFile } from '../fs/writeValueToFile';
+import { type FileEncoding } from './types';
+
+// Load environment variables for local runs; CI already has env set
+loadLocalEnv('test');
+
+// Write keystore files from environment variables
+async function writeKeystoreFilesFromEnv(
+ 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');
+
+ const mappings: Array<{
+ envKey: string;
+ outPath: string;
+ encoding?: FileEncoding;
+ }> = [
+ {
+ envKey: 'KEYSTORE1_JSON_B64',
+ outPath: `${walletsDir}/keystoreFile1.json`,
+ encoding: 'base64'
+ },
+ {
+ envKey: 'KEYSTORE2_JSON_B64',
+ outPath: `${walletsDir}/keystoreFile2.json`,
+ encoding: 'base64'
+ },
+ {
+ envKey: 'KEYSTORE3_JSON_B64',
+ outPath: `${walletsDir}/keystoreFile3.json`,
+ encoding: 'base64'
+ },
+ {
+ envKey: 'KEYSTORE4_JSON_B64',
+ outPath: `${walletsDir}/keystoreFile4.json`,
+ encoding: 'base64'
+ },
+ {
+ envKey: 'KEYSTORE5_PEM_B64',
+ outPath: `${walletsDir}/keystoreFile5.pem`,
+ encoding: 'base64'
+ },
+ {
+ envKey: 'KEYSTORE6_PRIVATE_KEY_UTF8',
+ outPath: `${walletsDir}/keystoreFile6.key`,
+ encoding: 'none'
+ }
+ ];
+
+ // Write keystore files from environment variables
+ for (const { envKey, outPath, encoding } of mappings) {
+ const value = process.env[envKey];
+ 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('base64', true);
+}
diff --git a/tests/support/template/handlePingPong.ts b/tests/support/template/handlePingPong.ts
new file mode 100644
index 0000000..fe5f9cb
--- /dev/null
+++ b/tests/support/template/handlePingPong.ts
@@ -0,0 +1,36 @@
+import { TEST_CONSTANTS } from './constants';
+import { PingPongEnum } from './testdata';
+import { HandlePingPongType } from './types';
+
+export const handlePingPong = async ({ page, type }: HandlePingPongType) => {
+ const container = page.locator(`#ping-pong-${type}`);
+ await container.scrollIntoViewIfNeeded();
+
+ const suffix = type === PingPongEnum.abi ? 'Abi' : 'Raw';
+ const pingButton = container.getByTestId(`btnPing${suffix}`);
+ const pongButton = container.getByTestId(`btnPong${suffix}`);
+
+ // Use Playwright's isDisabled() for clarity
+ const isPingEnabled = !(await pingButton.isDisabled());
+ const isPongEnabled = !(await pongButton.isDisabled());
+
+ if (!isPingEnabled && !isPongEnabled) {
+ throw new Error('Neither Ping nor Pong button are enabled!');
+ }
+
+ if (isPingEnabled) {
+ await pingButton.click();
+ return 'ping';
+ }
+
+ if (isPongEnabled) {
+ await pongButton.click();
+ return 'pong';
+ }
+
+ throw new Error(
+ `Neither Ping nor Pong button are enabled! Did you send a Ping or Pong within ${
+ TEST_CONSTANTS.PING_PONG_COOLDOWN / 1000 / 60
+ } minutes?`
+ );
+};
diff --git a/tests/support/template/index.ts b/tests/support/template/index.ts
new file mode 100644
index 0000000..f577492
--- /dev/null
+++ b/tests/support/template/index.ts
@@ -0,0 +1,51 @@
+export { checkBalanceUpdate } from './checkBalanceUpdate';
+
+export { checkButtonStatus } from './checkButtonStatus';
+
+export { checkClipboardContains } from './checkClipboardContains';
+
+export { checkConnectionToWallet } from './checkConnectionToWallet';
+
+export { checkPingPongBalanceUpdate } from './checkBalanceUpdate';
+
+export { confirmWalletTransaction } from './confirmWalletTransaction';
+
+export { connectInMemoryProvider } from './connectInMemoryProvider';
+
+export { connectWebWallet } from './connectWebWallet';
+
+export { countTransactions } from './parseTransactionsTable';
+
+export { ensureDirectoryExists } from '../fs/ensureDirectoryExists';
+
+export { extractBalanceFromContainer } from './extractBalanceFromContainer';
+
+export { filterTransactions } from './parseTransactionsTable';
+
+export { getTestIdSelector } from './testIdSelector';
+
+export { handleMetaMaskSnap } from '../metaMask/handleMetaMaskSnap';
+
+export { handlePingPong } from './handlePingPong';
+
+export { navigateToConnectWallet } from './navigateToConnectWallet';
+
+export { parseTransactionsTable } from './parseTransactionsTable';
+
+export { pasteStringFromClipboard } from './pasteStringFromClipboard';
+
+export { readValueFromFile } from '../fs/readValueFromFile';
+
+export { signBatchTransactions } from './signBatchTransactions';
+
+export { getPageAndWaitForLoad } from './getPageAndWaitForLoad';
+
+export { waitForToastToBeClosed } from './waitForToastToBeClosed';
+
+export { waitForToastToBeDisplayed } from './waitForToastToBeDisplayed';
+
+export { waitForTransactionToastToContain } from './waitForTransactionToastToShow';
+
+export { waitUntilStable } from './waitUntilStable';
+
+export { writeValueToFile } from '../fs/writeValueToFile';
diff --git a/tests/support/template/loadLocalEnv.ts b/tests/support/template/loadLocalEnv.ts
new file mode 100644
index 0000000..cafb2cf
--- /dev/null
+++ b/tests/support/template/loadLocalEnv.ts
@@ -0,0 +1,17 @@
+import { loadEnv } from 'vite';
+
+export function loadLocalEnv(modeDefault: string = 'test'): void {
+ try {
+ const mode = process.env.MODE || modeDefault;
+ const localEnv = loadEnv(mode, process.cwd(), '');
+ for (const [key, value] of Object.entries(localEnv)) {
+ if (process.env[key] === undefined) {
+ process.env[key] = value;
+ }
+ }
+ } catch (_) {
+ // If vite's loadEnv isn't available, silently skip.
+ }
+}
+
+
diff --git a/tests/support/template/navigateToConnectWallet.ts b/tests/support/template/navigateToConnectWallet.ts
new file mode 100644
index 0000000..03f303a
--- /dev/null
+++ b/tests/support/template/navigateToConnectWallet.ts
@@ -0,0 +1,20 @@
+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 instanceof Error ? error.message : 'Unknown error'
+ }`
+ );
+ 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/template/parseTransactionsTable.ts b/tests/support/template/parseTransactionsTable.ts
new file mode 100644
index 0000000..9b65d67
--- /dev/null
+++ b/tests/support/template/parseTransactionsTable.ts
@@ -0,0 +1,340 @@
+import { SelectorsEnum } from './testdata';
+import { getTestIdSelector } from './testIdSelector';
+import {
+ ParseTransactionsTableType,
+ TransactionFilter,
+ TransactionRow
+} from './types';
+
+// Function to count transactions with given filters
+export const countTransactions = (
+ transactions: TransactionRow[],
+ filter: TransactionFilter
+): number => {
+ const filteredTransactions = filterTransactions(transactions, filter);
+ const count = filteredTransactions.length;
+
+ if (filter.enableLogging) {
+ console.log(
+ `countTransactions: Found ${count} matching transactions out of ${transactions.length} total`
+ );
+ }
+
+ return count;
+};
+
+// Helper function to parse age text into minutes
+const parseAge = (ageText: string): number => {
+ const match = ageText.match(/(\d+)\s*(sec|min|hr|day)/);
+ if (!match) {
+ return 0;
+ }
+
+ const value = parseInt(match[1]);
+ const unit = match[2].toLowerCase();
+
+ // TODO: add more units if needed besides sec, min, hr, day
+ switch (unit) {
+ case 'sec':
+ return value / 60; // seconds to minutes
+ case 'min':
+ return value;
+ case 'hr':
+ return value * 60; // hours to minutes
+ case 'day':
+ return value * 24 * 60; // days to minutes
+ default:
+ return 1000; // default in case of unexpected unit
+ }
+};
+
+// Helper function to filter transactions
+export const filterTransactions = (
+ transactions: TransactionRow[],
+ filter: TransactionFilter
+): TransactionRow[] => {
+ const enableLogging = filter.enableLogging || false;
+
+ if (enableLogging) {
+ console.log(
+ `Filtering ${transactions.length} transactions with criteria:`,
+ {
+ exactValue: filter.exactValue,
+ methods: filter.methods,
+ maxAgeInMinutes: filter.maxAgeInMinutes,
+ minAgeInMinutes: filter.minAgeInMinutes,
+ onlySuccessful: filter.onlySuccessful,
+ onlyFailed: filter.onlyFailed,
+ fromAddress: filter.fromAddress,
+ toAddress: filter.toAddress
+ }
+ );
+ }
+
+ const filteredTransactions = transactions.filter((transaction, index) => {
+ let matches = true;
+ let reason = '';
+
+ // Age filter
+ if (
+ filter.maxAgeInMinutes !== undefined &&
+ transaction.ageInMinutes > filter.maxAgeInMinutes
+ ) {
+ matches = false;
+ reason = `age ${transaction.ageInMinutes} > max ${filter.maxAgeInMinutes}`;
+ }
+ if (
+ matches &&
+ filter.minAgeInMinutes !== undefined &&
+ transaction.ageInMinutes < filter.minAgeInMinutes
+ ) {
+ matches = false;
+ reason = `age ${transaction.ageInMinutes} < min ${filter.minAgeInMinutes}`;
+ }
+
+ // Method filter
+ if (
+ matches &&
+ filter.methods &&
+ !filter.methods.includes(transaction.method)
+ ) {
+ matches = false;
+ reason = `method "${transaction.method}" not in [${filter.methods.join(
+ ', '
+ )}]`;
+ }
+
+ // Value filter
+ if (
+ matches &&
+ filter.exactValue !== undefined &&
+ transaction.value !== filter.exactValue
+ ) {
+ matches = false;
+ reason = `value ${transaction.value} !== ${filter.exactValue}`;
+ }
+
+ // Status filter
+ if (matches && filter.onlySuccessful && transaction.isFailed) {
+ matches = false;
+ reason = 'transaction failed but onlySuccessful=true';
+ }
+ if (matches && filter.onlyFailed && !transaction.isFailed) {
+ matches = false;
+ reason = 'transaction successful but onlyFailed=true';
+ }
+
+ // Address filters
+ if (
+ matches &&
+ filter.fromAddress &&
+ !transaction.fromAddress.includes(filter.fromAddress)
+ ) {
+ matches = false;
+ reason = `fromAddress "${transaction.fromAddress}" does not contain "${filter.fromAddress}"`;
+ }
+ if (
+ matches &&
+ filter.toAddress &&
+ !transaction.toAddress.includes(filter.toAddress)
+ ) {
+ matches = false;
+ reason = `toAddress "${transaction.toAddress}" does not contain "${filter.toAddress}"`;
+ }
+
+ if (enableLogging) {
+ console.log(
+ `Transaction ${index + 1}: ${
+ matches ? 'MATCH' : 'FILTERED'
+ } - method="${transaction.method}", value=${transaction.value}, age=${
+ transaction.ageInMinutes
+ }min${reason ? `, reason: ${reason}` : ''}`
+ );
+ }
+
+ return matches;
+ });
+
+ if (enableLogging) {
+ console.log(
+ `Filtered ${transactions.length} transactions down to ${filteredTransactions.length} matches`
+ );
+ }
+
+ return filteredTransactions;
+};
+
+export const parseTransactionsTable = async ({
+ page,
+ tableSelector,
+ tableType,
+ maxRows,
+ enableLogging = false
+}: ParseTransactionsTableType): Promise => {
+ // Set table selector based on table type
+ const defaultTableSelector =
+ tableType === 'ping-pong'
+ ? SelectorsEnum.transactionsPingPongTable
+ : SelectorsEnum.transactionsAllTable;
+
+ const finalTableSelector = tableSelector || defaultTableSelector;
+ const table = page.locator(finalTableSelector);
+ await table.waitFor({ state: 'visible' });
+ await table.scrollIntoViewIfNeeded();
+
+ // Get all table rows (excluding header)
+ const rows = table.locator(SelectorsEnum.transactionsTableBodyRow);
+ const totalRowCount = await rows.count();
+
+ // Limit the number of rows to process if maxRows is specified
+ const rowCount = maxRows ? Math.min(maxRows, totalRowCount) : totalRowCount;
+
+ if (enableLogging) {
+ console.log(
+ `Found ${totalRowCount} transaction rows, processing ${rowCount} rows`
+ );
+ }
+
+ const transactions: TransactionRow[] = [];
+
+ for (let i = 0; i < rowCount; i++) {
+ const row = rows.nth(i);
+
+ try {
+ if (enableLogging) {
+ console.log(`Processing row ${i + 1}/${rowCount}`);
+ }
+
+ // Extract transaction hash
+ const hashElement = row.locator(
+ getTestIdSelector(SelectorsEnum.transactionLink)
+ );
+ const hash = await hashElement.getAttribute('href');
+ const transactionHash = hash ? hash.split('/').pop() || '' : '';
+
+ // Extract age
+ const ageElement = row.locator(
+ getTestIdSelector(SelectorsEnum.transactionAge)
+ );
+ const ageElementCount = await ageElement.count();
+
+ if (enableLogging) {
+ console.log(`Row ${i + 1} age element count: ${ageElementCount}`);
+ }
+
+ let ageText = '';
+ let age = 0;
+
+ if (ageElementCount > 0) {
+ ageText = (await ageElement.textContent()) || '';
+ age = parseAge(ageText);
+ if (enableLogging) {
+ console.log(`Row ${i + 1} age text: "${ageText}" -> ${age} minutes`);
+ }
+ } else if (enableLogging) {
+ console.log(`Row ${i + 1} age element not found`);
+ }
+
+ // Extract shard info
+ const senderShardElement = row.locator(
+ getTestIdSelector(SelectorsEnum.senderShard)
+ );
+ const receiverShardElement = row.locator(
+ getTestIdSelector(SelectorsEnum.receiverShard)
+ );
+ const senderShard = (await senderShardElement.textContent()) || '';
+ const receiverShard = (await receiverShardElement.textContent()) || '';
+
+ // Extract from/to addresses - use more flexible selectors
+ const senderElement = row.locator(
+ `${getTestIdSelector(
+ SelectorsEnum.transactionSender
+ )} ${getTestIdSelector(SelectorsEnum.trimFullAddress)}`
+ );
+ const receiverElement = row.locator(
+ `${getTestIdSelector(
+ SelectorsEnum.transactionReceiver
+ )} ${getTestIdSelector(SelectorsEnum.receiverLink)}`
+ );
+
+ // Check if elements exist before trying to get text content
+ const fromAddress =
+ (await senderElement.count()) > 0
+ ? (await senderElement.textContent()) || ''
+ : '';
+ const toAddress =
+ (await receiverElement.count()) > 0
+ ? (await receiverElement.textContent()) || ''
+ : '';
+
+ // Extract method
+ const methodElement = row.locator(
+ getTestIdSelector(SelectorsEnum.method)
+ );
+ const method = (await methodElement.textContent()) || '';
+
+ // Extract value
+ const valueIntElement = row.locator(
+ getTestIdSelector(SelectorsEnum.formatAmountInt)
+ );
+ const valueDecimalsElement = row.locator(
+ getTestIdSelector(SelectorsEnum.formatAmountDecimals)
+ );
+ const valueSymbolElement = row.locator(
+ getTestIdSelector(SelectorsEnum.formatAmountSymbol)
+ );
+
+ // Check if elements exist before trying to get text content
+ const valueIntElementCount = await valueIntElement.count();
+ const valueDecimalsElementCount = await valueDecimalsElement.count();
+ const valueSymbolElementCount = await valueSymbolElement.count();
+
+ // Extract value components with fallbacks for missing elements
+ // Some transaction rows may not have all value elements (e.g., failed transactions)
+ const valueInt =
+ valueIntElementCount > 0
+ ? (await valueIntElement.textContent()) || '0'
+ : '0';
+ const valueDecimals =
+ valueDecimalsElementCount > 0
+ ? (await valueDecimalsElement.textContent()) || '.00'
+ : '.00';
+ const valueSymbol =
+ valueSymbolElementCount > 0
+ ? (await valueSymbolElement.textContent()) || ''
+ : '';
+
+ const value = parseFloat(`${valueInt}${valueDecimals}`);
+
+ // Check if transaction failed (has error icon)
+ const hasErrorIcon =
+ (await row.locator(SelectorsEnum.errorIcon).count()) > 0;
+
+ transactions.push({
+ hash: transactionHash,
+ age: ageText,
+ ageInMinutes: age,
+ senderShard,
+ receiverShard,
+ fromAddress,
+ toAddress,
+ method: method.toLowerCase(),
+ value,
+ symbol: valueSymbol,
+ isFailed: hasErrorIcon
+ });
+
+ if (enableLogging) {
+ console.log(`Successfully processed row ${i + 1}`);
+ }
+ } catch (error) {
+ if (enableLogging) {
+ console.log(`Error processing row ${i + 1}:`, error);
+ }
+ // Continue with next row instead of failing completely
+ continue;
+ }
+ }
+
+ return transactions;
+};
diff --git a/tests/support/template/pasteStringFromClipboard.ts b/tests/support/template/pasteStringFromClipboard.ts
new file mode 100644
index 0000000..49cf581
--- /dev/null
+++ b/tests/support/template/pasteStringFromClipboard.ts
@@ -0,0 +1,10 @@
+import { BrowserContext, Page } from '@playwright/test';
+
+export const pasteStringFromClipboard = async (
+ page: Page,
+ context: BrowserContext
+) => {
+ await context.grantPermissions(['clipboard-write', 'clipboard-read']);
+ const text = await page.evaluate(() => navigator.clipboard.readText());
+ return text;
+};
diff --git a/tests/support/template/signBatchTransactions.ts b/tests/support/template/signBatchTransactions.ts
new file mode 100644
index 0000000..7d0650a
--- /dev/null
+++ b/tests/support/template/signBatchTransactions.ts
@@ -0,0 +1,14 @@
+import { SelectorsEnum } from './testdata';
+import { SignBatchTransactionsType } from './types';
+
+export const signBatchTransactions = async ({
+ walletPage,
+ buttonSelector,
+ numberOfTransactions
+}: 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/template/testIdSelector.ts b/tests/support/template/testIdSelector.ts
new file mode 100644
index 0000000..1019495
--- /dev/null
+++ b/tests/support/template/testIdSelector.ts
@@ -0,0 +1,7 @@
+/**
+ * Helper function to create a data-testid selector string
+ * @param testId - The test ID value
+ * @returns CSS selector string for data-testid attribute
+ */
+export const getTestIdSelector = (testId: string): string =>
+ `[data-testid="${testId}"]`;
diff --git a/tests/support/template/testdata.ts b/tests/support/template/testdata.ts
new file mode 100644
index 0000000..4451829
--- /dev/null
+++ b/tests/support/template/testdata.ts
@@ -0,0 +1,119 @@
+import path from 'path';
+import { loadLocalEnv } from './loadLocalEnv';
+
+// Ensure local .env files (e.g., .env.test.local) are loaded when running locally.
+loadLocalEnv('test');
+
+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',
+ templateHome = 'https://localhost:3002/home',
+ templateDashboard = 'https://localhost:3002/dashboard',
+ templateUnlock = 'https://localhost:3002/unlock'
+}
+
+export const UrlRegex = {
+ templateDashboard: /https:\/\/localhost:3002\/dashboard/,
+ multiversxWallet: /devnet-wallet\.multiversx\.com/
+} as const;
+
+export enum PingPongEnum {
+ raw = 'raw',
+ abi = 'abi',
+ service = 'service'
+}
+
+export enum SelectorsEnum {
+ // TODO: arange selectors by template dashboard, web wallet, transaction table, table containers
+ // Template dashboard selectors
+ walletFile = 'walletFile',
+ passwordInput = 'accessPass',
+ submitButton = 'submitButton',
+ confirmButton = 'confirmBtn',
+ keystoreCloseModalButton = 'keystoreCloseModalBtn',
+ signButton = 'signBtn',
+ topInfoContainer = 'topInfo',
+ crossWindow = 'crossWindow',
+ keystoreButton = 'keystoreBtn',
+ inMemoryButton = 'inMemoryProvider',
+ pemButton = 'pemBtn',
+ pingButton = 'btnPingRaw',
+ pongButton = 'btnPongRaw',
+ toastTitle = 'transactionToastTitle',
+ toastContent = 'transactionToastContent',
+ toastStatus = 'transactionDetailsStatus',
+ balance = 'balance',
+ formatAmountInt = 'formatAmountInt',
+ formatAmountDecimals = 'formatAmountDecimals',
+ signMsgButton = 'signMsgBtn',
+ signMsgWalletButton = 'signButton',
+ signAndBatchButton = 'sign-auto-send',
+ wrapAndMultiTransferButton = 'wrap-multi-transfer',
+ swapAndLockButton = 'swap-lock',
+ nativeAuthContainer = '#native-auth',
+ trimFullAddress = 'trimFullAddress',
+ pingPongAbiContainer = '#ping-pong-abi',
+ batchTransactionsContainer = '#batch-transactions',
+ signMessageContainer = '#sign-message',
+ accountAddress = 'accountAddress',
+ heroTag = 'heroTag',
+ shard = 'addressShard',
+ decodedMessage = 'decodedMessage',
+ addressInput = 'input[name="address"]',
+ privateKeyInput = 'input[name="privateKey"]',
+ cancelButton = 'cancelButton',
+ sidePanel = '#side-panel',
+ sidePanelCloseIcon = 'svg',
+
+ // Web wallet selectors
+ signCancelButton = 'signCancelBtn',
+
+ // Transaction table selectors
+ transactionLink = 'transactionLink',
+ transactionAge = 'transactionAge',
+ senderShard = 'senderShard',
+ receiverShard = 'receiverShard',
+ transactionSender = 'transactionSender',
+ transactionReceiver = 'transactionReceiver',
+ receiverLink = 'receiverLink',
+ method = 'method',
+ formatAmountSymbol = 'formatAmountSymbol',
+ errorIcon = '.mvx\\:text-error',
+
+ // Table containers
+ 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 || 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,
+
+ metamaskMnemonic: process.env.METAMASK_MNEMONIC,
+ metamaskAddress: process.env.METAMASK_ADDRESS,
+ metamaskPassword: process.env.METAMASK_PASSWORD,
+
+ keystoreFilePath1: `${walletsDir}/keystoreFile1.json`,
+ keystoreFilePath2: `${walletsDir}/keystoreFile2.json`,
+ keystoreFilePath3: `${walletsDir}/keystoreFile3.json`,
+ keystoreFilePath4: `${walletsDir}/keystoreFile4.json`,
+ keystoreFilePath5: `${walletsDir}/keystoreFile5.pem`,
+ keystoreFilePath6: `${walletsDir}/keystoreFile6.key`
+} as const;
diff --git a/tests/support/template/types.ts b/tests/support/template/types.ts
new file mode 100644
index 0000000..dfb5f4f
--- /dev/null
+++ b/tests/support/template/types.ts
@@ -0,0 +1,176 @@
+import { BrowserContext, Page } from '@playwright/test';
+import { PingPongEnum } from './testdata';
+
+export type FileEncoding = 'base64' | 'utf8' | 'none';
+
+export interface AuthenticateWithKeystoreType {
+ walletPage: Page;
+ keystorePath: string;
+ keystorePassword: string;
+}
+
+export interface ConnectPasskeyWalletType {
+ page: Page;
+}
+
+export interface InMemoryProviderType {
+ page: Page;
+ loginMethod: InMemoryProviderLoginMethodType;
+}
+
+export interface AuthenticateWithPemType {
+ walletPage: Page;
+ pemPath: string;
+}
+
+export interface CheckBalanceUpdateType {
+ page: Page;
+ containerSelector: string;
+ initialBalance: number;
+ expectedChange: number;
+}
+
+export interface CheckButtonStatusType {
+ page: Page;
+ type: PingPongEnum;
+ lastClickedButton: 'ping' | 'pong';
+}
+
+export interface CheckClipboardContainsType {
+ page: Page;
+ context: BrowserContext;
+ text: string;
+ timeout?: number;
+}
+
+export interface CheckConnectionToWalletType {
+ page: Page;
+ walletAddress: string;
+}
+
+export interface CheckToastShowsTransactionsSignedType {
+ page: Page;
+ numberOfTransactions: number;
+}
+
+export interface ConfirmWalletTransactionType {
+ page: Page;
+ loginMethod: WebWalletLoginMethodType;
+}
+
+export interface ConnectWebWalletType {
+ page: Page;
+ loginMethod: WebWalletLoginMethodType;
+}
+
+export interface CreateNotFoundErrorType {
+ urlSubstring: string;
+ timeout: number;
+ currentPageUrl: string;
+ availablePagesUrls: string;
+}
+
+export interface ExtractBalanceFromContainerType {
+ page: Page;
+ containerSelector: string;
+ selectorType: 'testId' | 'locator';
+}
+
+export interface HandlePingPongType {
+ page: Page;
+ type: PingPongEnum;
+}
+
+export interface WebWalletLoginMethodType {
+ keystore?: string;
+ password?: string;
+ pem?: string;
+}
+
+export interface InMemoryProviderLoginMethodType {
+ address: string;
+ privateKey: string;
+}
+export interface NavigateToConnectWalletType {
+ page: Page;
+}
+
+export interface ParseTransactionsTableType {
+ page: Page;
+ tableSelector?: string;
+ tableType: 'all' | 'ping-pong';
+ maxRows?: number;
+ enableLogging?: boolean;
+}
+
+export interface PasteStringFromClipboardType {
+ page: Page;
+ context: BrowserContext;
+}
+
+export interface SignBatchTransactionsType {
+ walletPage: Page;
+ buttonSelector: string;
+ numberOfTransactions: number;
+}
+
+export interface TransactionFilter {
+ maxAgeInMinutes?: number;
+ minAgeInMinutes?: number;
+ methods?: string[];
+ exactValue?: number;
+ onlySuccessful?: boolean;
+ onlyFailed?: boolean;
+ fromAddress?: string;
+ toAddress?: string;
+ enableLogging?: boolean;
+}
+
+export interface TransactionRow {
+ hash: string;
+ age: string;
+ ageInMinutes: number;
+ senderShard: string;
+ receiverShard: string;
+ fromAddress: string;
+ toAddress: string;
+ method: string;
+ value: number;
+ symbol: string;
+ isFailed: boolean;
+}
+
+export interface WaitForToastToBeClosedType {
+ page: Page;
+}
+
+export interface WaitForToastToBeDisplayedType {
+ page: Page;
+}
+
+export interface WaitForTransactionToastToShowType {
+ page: Page;
+ toastTitle: string;
+ toastContent: string;
+}
+
+export interface WaitForTransactionToastToContainType {
+ page: Page;
+ toastTitle?: string;
+ toastContent?: string;
+ 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/template/waitForToastToBeClosed.ts b/tests/support/template/waitForToastToBeClosed.ts
new file mode 100644
index 0000000..8ad2ece
--- /dev/null
+++ b/tests/support/template/waitForToastToBeClosed.ts
@@ -0,0 +1,7 @@
+import { Page } from '@playwright/test';
+import { SelectorsEnum } from './testdata';
+
+export const waitForToastToBeClosed = async (page: Page) => {
+ const toast = page.getByTestId(SelectorsEnum.toastContent).first();
+ await toast.waitFor({ state: 'hidden' });
+};
diff --git a/tests/support/template/waitForToastToBeDisplayed.ts b/tests/support/template/waitForToastToBeDisplayed.ts
new file mode 100644
index 0000000..7a4b176
--- /dev/null
+++ b/tests/support/template/waitForToastToBeDisplayed.ts
@@ -0,0 +1,7 @@
+import { Page } from '@playwright/test';
+import { SelectorsEnum } from './testdata';
+
+export const waitForToastToBeDisplayed = async (page: Page) => {
+ const toast = page.getByTestId(SelectorsEnum.toastContent).first();
+ await toast.waitFor({ state: 'visible' });
+};
diff --git a/tests/support/template/waitForTransactionToastToShow.ts b/tests/support/template/waitForTransactionToastToShow.ts
new file mode 100644
index 0000000..58b8c62
--- /dev/null
+++ b/tests/support/template/waitForTransactionToastToShow.ts
@@ -0,0 +1,46 @@
+import { expect } from '@playwright/test';
+import { TEST_CONSTANTS } from './constants';
+import { SelectorsEnum } from './testdata';
+import { WaitForTransactionToastToContainType } from './types';
+
+export const waitForTransactionToastToContain = async ({
+ page,
+ toastTitle,
+ toastContent,
+ toastStatus,
+ toastIndex = 0
+}: WaitForTransactionToastToContainType) => {
+ if (!toastTitle && !toastContent && !toastStatus) {
+ throw new Error('Either toast title, content or status must be provided');
+ }
+
+ const titleLocator = page.getByTestId(SelectorsEnum.toastTitle);
+ const contentLocator = page.getByTestId(SelectorsEnum.toastContent);
+ const statusLocator = page.getByTestId(SelectorsEnum.toastStatus);
+
+ // Wait for toast visibility
+ await expect(contentLocator.nth(toastIndex)).toBeVisible({
+ timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT
+ });
+
+ if (toastTitle) {
+ await expect(titleLocator.nth(toastIndex)).toContainText(toastTitle, {
+ timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT,
+ useInnerText: true
+ });
+ }
+
+ if (toastContent) {
+ await expect(contentLocator.nth(toastIndex)).toContainText(toastContent, {
+ timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT,
+ useInnerText: true
+ });
+ }
+
+ if (toastStatus) {
+ await expect(statusLocator.nth(toastIndex)).toContainText(toastStatus, {
+ timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT,
+ useInnerText: true
+ });
+ }
+};
diff --git a/tests/support/template/waitUntilStable.ts b/tests/support/template/waitUntilStable.ts
new file mode 100644
index 0000000..d57887a
--- /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/templateActions/nativeAuth.spec.ts b/tests/templateActions/nativeAuth.spec.ts
new file mode 100644
index 0000000..a56e6a8
--- /dev/null
+++ b/tests/templateActions/nativeAuth.spec.ts
@@ -0,0 +1,53 @@
+import { expect, test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import { extractBalanceFromContainer } from '../support/template';
+import { SelectorsEnum, TestDataEnums } from '../support/template/testdata';
+
+const keystoreConfig = {
+ keystore: TestDataEnums.keystoreFilePath1,
+ password: TestDataEnums.keystorePassword1,
+ address: TestDataEnums.keystoreWalletAddress1
+};
+
+test.describe('Native auth', () => {
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig });
+ await TestActions.checkConnectionToWallet(page, keystoreConfig.address);
+ });
+
+ test('should display correct wallet address and balance in native auth', async ({
+ page
+ }) => {
+ // Get account balance before any actions
+ const accountBalance = await TestActions.extractBalanceFromContainer({
+ page,
+ containerSelector: SelectorsEnum.topInfoContainer,
+ selectorType: 'testId'
+ });
+
+ // Scroll to the native auth container into viewport
+ await page
+ .locator(SelectorsEnum.nativeAuthContainer)
+ .scrollIntoViewIfNeeded();
+
+ // Verify container is in viewport
+ const container = page.locator(SelectorsEnum.nativeAuthContainer);
+ await expect(container).toBeInViewport();
+
+ // Check that the address is displayed and matches the account address
+ const addressRow = page.locator(`${SelectorsEnum.nativeAuthContainer} p`, {
+ hasText: 'Address:'
+ });
+ await expect(addressRow).toContainText(keystoreConfig.address);
+
+ // Check that the balance is displayed and matches the account balance
+ const nativeAuthBalance = await extractBalanceFromContainer({
+ page,
+ containerSelector: SelectorsEnum.nativeAuthContainer,
+ selectorType: 'locator'
+ });
+
+ await expect(nativeAuthBalance).toBe(accountBalance);
+ });
+});
diff --git a/tests/templateActions/pingAndPongAbi.spec.ts b/tests/templateActions/pingAndPongAbi.spec.ts
new file mode 100644
index 0000000..5e5eb24
--- /dev/null
+++ b/tests/templateActions/pingAndPongAbi.spec.ts
@@ -0,0 +1,104 @@
+import { expect, test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import { TEST_CONSTANTS } from '../support/template/constants';
+import {
+ OriginPageEnum,
+ PingPongEnum,
+ SelectorsEnum,
+ TestDataEnums,
+ UrlRegex
+} from '../support/template/testdata';
+import { WALLET_URL_TIMEOUT_MS } from '../config';
+
+const pemConfig = {
+ pem: TestDataEnums.keystoreFilePath5
+};
+
+test.describe('Ping & Pong (ABI)', () => {
+ // Note: Ping/Pong buttons have a 3-minute cooldown period after being clicked
+
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ await TestActions.connectWebWallet({ page, loginMethod: pemConfig });
+ await TestActions.checkConnectionToWallet(
+ page,
+ TestDataEnums.keystoreWalletAddress5
+ );
+ });
+
+ test('should have sufficient balance for ping & pong operations', async ({
+ page
+ }) => {
+ // Get account balance before any actions
+ const accountBalance = await TestActions.extractBalanceFromContainer({
+ page,
+ containerSelector: SelectorsEnum.topInfoContainer,
+ selectorType: 'testId'
+ });
+
+ // Check that account balance is greater than 1 required for ping & pong
+ expect(accountBalance).toBeGreaterThan(
+ TEST_CONSTANTS.MIN_BALANCE_FOR_PING_PONG
+ );
+ });
+
+ test('should complete full ping/pong transaction flow', async ({ page }) => {
+ // Get account balance before any actions
+ const accountBalance = await TestActions.extractBalanceFromContainer({
+ page,
+ containerSelector: SelectorsEnum.topInfoContainer,
+ selectorType: 'testId'
+ });
+
+ // Scroll to the ping & pong container into viewport
+ await page
+ .locator(SelectorsEnum.pingPongAbiContainer)
+ .scrollIntoViewIfNeeded();
+
+ const clickedButton = await TestActions.handlePingPong({
+ page,
+ type: PingPongEnum.abi
+ });
+
+ // Switch to web wallet page
+ const walletPage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.multiversxWallet
+ );
+
+ // Verify wallet page opened
+ await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, {
+ timeout: WALLET_URL_TIMEOUT_MS
+ });
+
+ // Sign transaction by confirming with pem
+ await TestActions.confirmWalletTransaction(walletPage, pemConfig);
+
+ // Click on Sign button to confirm the transaction in the web wallet
+ await walletPage.getByTestId(SelectorsEnum.signButton).click();
+
+ // Switch to template dashboard page
+ const templatePage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.templateDashboard
+ );
+
+ // Wait for transaction toast to be displayed
+ await TestActions.waitForToastToBeDisplayed(templatePage);
+
+ // Check balance change based on the clicked button
+ await TestActions.checkPingPongBalanceUpdate({
+ page: templatePage,
+ containerSelector: SelectorsEnum.topInfoContainer,
+ initialBalance: accountBalance,
+ isPing: clickedButton === 'ping'
+ });
+
+ // Check that the button status changed after the action
+ await TestActions.checkButtonStatus({
+ page,
+ type: PingPongEnum.abi,
+ lastClickedButton: clickedButton
+ });
+ });
+});
diff --git a/tests/templateActions/signAndSendBatch.spec.ts b/tests/templateActions/signAndSendBatch.spec.ts
new file mode 100644
index 0000000..2134a21
--- /dev/null
+++ b/tests/templateActions/signAndSendBatch.spec.ts
@@ -0,0 +1,93 @@
+import { expect, test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import { TEST_CONSTANTS } from '../support/template/constants';
+import {
+ OriginPageEnum,
+ SelectorsEnum,
+ TestDataEnums,
+ UrlRegex
+} from '../support/template/testdata';
+import { WALLET_URL_TIMEOUT_MS } from '../config';
+
+const keystoreConfig = {
+ keystore: TestDataEnums.keystoreFilePath2,
+ password: TestDataEnums.keystorePassword2
+};
+
+test.describe('Sign & send batch', () => {
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig });
+ await TestActions.checkConnectionToWallet(
+ page,
+ TestDataEnums.keystoreWalletAddress2
+ );
+ });
+
+ test('should have sufficient balance for batch transactions', async ({
+ page
+ }) => {
+ // Get account balance before any actions
+ const accountBalance = await TestActions.extractBalanceFromContainer({
+ page,
+ containerSelector: SelectorsEnum.topInfoContainer,
+ selectorType: 'testId'
+ });
+
+ // Check that account balance is greater than 5 required for batch transactions
+ expect(accountBalance).toBeGreaterThan(
+ TEST_CONSTANTS.MIN_BALANCE_FOR_BATCH_TX
+ );
+ });
+
+ test('should complete full batch transaction flow', async ({ page }) => {
+ const numberOfTransactions = 5;
+
+ // Scroll to the batch transactions container into viewport
+ await page
+ .locator(SelectorsEnum.batchTransactionsContainer)
+ .scrollIntoViewIfNeeded();
+
+ // Click on the sign and batch button
+ await page.getByTestId(SelectorsEnum.signAndBatchButton).click();
+
+ // Switch to web wallet page
+ const walletPage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.multiversxWallet
+ );
+
+ // Verify wallet page opened
+ await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, {
+ timeout: WALLET_URL_TIMEOUT_MS
+ });
+
+ // Sign transaction by confirming with keystore in the web wallet
+ await TestActions.confirmWalletTransaction(walletPage, keystoreConfig);
+
+ // Sign batch transactions in the web wallet
+ await TestActions.signBatchTransactions({
+ walletPage,
+ buttonSelector: SelectorsEnum.signAndBatchButton,
+ numberOfTransactions
+ });
+
+ // Switch to template page
+ const templatePage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.templateDashboard
+ );
+
+ // Wait for transaction toast to be displayed
+ await TestActions.waitForToastToBeDisplayed(templatePage);
+
+ // Check that the transaction toast shows that all transactions are signed
+ await TestActions.waitForTransactionToastToContain({
+ page: templatePage,
+ toastStatus: '5 / 5 transactions processed'
+ });
+
+ // Wait for the transaction toast to be closed
+ await TestActions.waitForToastToBeClosed(templatePage);
+ });
+});
diff --git a/tests/templateActions/signMessage.spec.ts b/tests/templateActions/signMessage.spec.ts
new file mode 100644
index 0000000..821222e
--- /dev/null
+++ b/tests/templateActions/signMessage.spec.ts
@@ -0,0 +1,70 @@
+import { expect, test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import {
+ OriginPageEnum,
+ SelectorsEnum,
+ TestDataEnums,
+ UrlRegex
+} from '../support/template/testdata';
+import { WALLET_URL_TIMEOUT_MS } from '../config';
+
+const keystoreConfig = {
+ keystore: TestDataEnums.keystoreFilePath1,
+ password: TestDataEnums.keystorePassword1
+};
+
+test.describe('Sign Message', () => {
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig });
+ await TestActions.checkConnectionToWallet(
+ page,
+ TestDataEnums.keystoreWalletAddress1
+ );
+ });
+
+ test('should complete full message signing flow', async ({ page }) => {
+ const message = 'mvx';
+
+ // Scroll to the sign message container into viewport
+ await page
+ .locator(SelectorsEnum.signMessageContainer)
+ .scrollIntoViewIfNeeded();
+
+ // Enter message
+ await page
+ .getByRole('textbox', { name: 'Write message here' })
+ .fill(message);
+
+ // Click on Sign button
+ await page.getByTestId(SelectorsEnum.signMsgButton).click();
+
+ // Switch to web wallet page
+ const walletPage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.multiversxWallet
+ );
+
+ // Verify wallet page opened
+ await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, {
+ timeout: WALLET_URL_TIMEOUT_MS
+ });
+
+ // Sign transaction by confirming with keystore in the web wallet
+ await TestActions.confirmWalletTransaction(walletPage, keystoreConfig);
+
+ // Click on Sign button to confirm the sign message in the web wallet
+ await walletPage.getByTestId(SelectorsEnum.signMsgWalletButton).click();
+
+ // Switch to template dashboard page
+ const templatePage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.templateDashboard
+ );
+
+ // Verify the decoded message contains the expected message
+ const decodedMessage =
+ 'cb0f0cbcf70e54e0e79fb2c1a48e01883e15fb3bb686773a7bb8b26ebb69447de75dd8c8645e9af1';
+ await expect(templatePage.getByText(decodedMessage)).toBeVisible();
+ });
+});
diff --git a/tests/templateActions/swapAndLock.ts b/tests/templateActions/swapAndLock.ts
new file mode 100644
index 0000000..ab83689
--- /dev/null
+++ b/tests/templateActions/swapAndLock.ts
@@ -0,0 +1,95 @@
+import { expect, test } from '@playwright/test';
+import * as TestActions from '../support/template';
+import { TEST_CONSTANTS } from '../support/template/constants';
+import {
+ OriginPageEnum,
+ SelectorsEnum,
+ TestDataEnums,
+ UrlRegex
+} from '../support/template/testdata';
+import { WALLET_URL_TIMEOUT_MS } from '../config';
+
+const keystoreConfig = {
+ keystore: TestDataEnums.keystoreFilePath3,
+ password: TestDataEnums.keystorePassword3
+};
+
+test.describe('Swap & Lock', () => {
+ test.beforeEach(async ({ page }) => {
+ await TestActions.navigateToConnectWallet(page);
+ await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig });
+ await TestActions.checkConnectionToWallet(
+ page,
+ TestDataEnums.keystoreWalletAddress3
+ );
+ });
+
+ test('should have sufficient balance for batch transactions', async ({
+ page
+ }) => {
+ // Get account balance before any actions
+ const accountBalance = await TestActions.extractBalanceFromContainer({
+ page,
+ containerSelector: SelectorsEnum.topInfoContainer,
+ selectorType: 'testId'
+ });
+
+ // Check that account balance is greater than 4 required for swap and lock
+ expect(accountBalance).toBeGreaterThan(
+ TEST_CONSTANTS.MIN_BALANCE_FOR_SWAP_AND_LOCK
+ );
+ });
+
+ test('should complete full swap and lock transaction flow', async ({
+ page
+ }) => {
+ const numberOfTransactions = 4; // 2 transactions for wrap, 1 for swap, 1 for multi-transfer
+
+ // Scroll to the batch transactions container into viewport
+ await page
+ .locator(SelectorsEnum.batchTransactionsContainer)
+ .scrollIntoViewIfNeeded();
+
+ // Click on the swap and lock button
+ await page.getByTestId(SelectorsEnum.swapAndLockButton).click();
+
+ // Switch to web wallet page
+ const walletPage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.multiversxWallet
+ );
+
+ // Verify wallet page opened
+ await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, {
+ timeout: WALLET_URL_TIMEOUT_MS
+ });
+
+ // Sign transaction by confirming with keystore in the web wallet
+ await TestActions.confirmWalletTransaction(walletPage, keystoreConfig);
+
+ // Sign swap and lock transactions in the web wallet
+ await TestActions.signBatchTransactions({
+ walletPage,
+ buttonSelector: SelectorsEnum.signAndBatchButton,
+ numberOfTransactions
+ });
+
+ // Switch to template page
+ const templatePage = await TestActions.getPageAndWaitForLoad(
+ page.context(),
+ OriginPageEnum.templateDashboard
+ );
+
+ // Wait for transaction toast to be displayed
+ await TestActions.waitForToastToBeDisplayed(templatePage);
+
+ // Check that the transaction toast shows that all transactions were signed
+ await TestActions.waitForTransactionToastToContain({
+ page: templatePage,
+ toastStatus: '4 / 4 transactions processed'
+ });
+
+ // Wait for the transaction toast to be closed
+ await TestActions.waitForToastToBeClosed(templatePage);
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 0e682c6..83f9d29 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -12,34 +12,34 @@
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1":
- version "7.27.1"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be"
- integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7"
+ integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==
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.27.2":
- version "7.28.5"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.5.tgz#a8a4962e1567121ac0b3b487f52107443b455c7f"
- integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==
+"@babel/compat-data@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c"
+ integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==
"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9":
- version "7.28.5"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e"
- integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==
- dependencies:
- "@babel/code-frame" "^7.27.1"
- "@babel/generator" "^7.28.5"
- "@babel/helper-compilation-targets" "^7.27.2"
- "@babel/helper-module-transforms" "^7.28.3"
- "@babel/helpers" "^7.28.4"
- "@babel/parser" "^7.28.5"
- "@babel/template" "^7.27.2"
- "@babel/traverse" "^7.28.5"
- "@babel/types" "^7.28.5"
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f"
+ integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==
+ dependencies:
+ "@babel/code-frame" "^7.28.6"
+ "@babel/generator" "^7.28.6"
+ "@babel/helper-compilation-targets" "^7.28.6"
+ "@babel/helper-module-transforms" "^7.28.6"
+ "@babel/helpers" "^7.28.6"
+ "@babel/parser" "^7.28.6"
+ "@babel/template" "^7.28.6"
+ "@babel/traverse" "^7.28.6"
+ "@babel/types" "^7.28.6"
"@jridgewell/remapping" "^2.3.5"
convert-source-map "^2.0.0"
debug "^4.1.0"
@@ -47,23 +47,23 @@
json5 "^2.2.3"
semver "^6.3.1"
-"@babel/generator@^7.28.5", "@babel/generator@^7.7.2":
- version "7.28.5"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.5.tgz#712722d5e50f44d07bc7ac9fe84438742dd61298"
- integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==
+"@babel/generator@^7.28.6", "@babel/generator@^7.7.2":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1"
+ integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==
dependencies:
- "@babel/parser" "^7.28.5"
- "@babel/types" "^7.28.5"
+ "@babel/parser" "^7.28.6"
+ "@babel/types" "^7.28.6"
"@jridgewell/gen-mapping" "^0.3.12"
"@jridgewell/trace-mapping" "^0.3.28"
jsesc "^3.0.2"
-"@babel/helper-compilation-targets@^7.27.2":
- version "7.27.2"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d"
- integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==
+"@babel/helper-compilation-targets@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25"
+ integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==
dependencies:
- "@babel/compat-data" "^7.27.2"
+ "@babel/compat-data" "^7.28.6"
"@babel/helper-validator-option" "^7.27.1"
browserslist "^4.24.0"
lru-cache "^5.1.1"
@@ -74,34 +74,34 @@
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
-"@babel/helper-module-imports@^7.27.1":
- version "7.27.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204"
- integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==
+"@babel/helper-module-imports@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c"
+ integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==
dependencies:
- "@babel/traverse" "^7.27.1"
- "@babel/types" "^7.27.1"
+ "@babel/traverse" "^7.28.6"
+ "@babel/types" "^7.28.6"
-"@babel/helper-module-transforms@^7.28.3":
- version "7.28.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6"
- integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==
+"@babel/helper-module-transforms@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e"
+ integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==
dependencies:
- "@babel/helper-module-imports" "^7.27.1"
- "@babel/helper-validator-identifier" "^7.27.1"
- "@babel/traverse" "^7.28.3"
+ "@babel/helper-module-imports" "^7.28.6"
+ "@babel/helper-validator-identifier" "^7.28.5"
+ "@babel/traverse" "^7.28.6"
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0":
- version "7.27.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c"
- integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8"
+ integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==
"@babel/helper-string-parser@^7.27.1":
version "7.27.1"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
-"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5":
+"@babel/helper-validator-identifier@^7.28.5":
version "7.28.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
@@ -111,20 +111,20 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f"
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
-"@babel/helpers@^7.28.4":
- version "7.28.4"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827"
- integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==
+"@babel/helpers@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7"
+ integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==
dependencies:
- "@babel/template" "^7.27.2"
- "@babel/types" "^7.28.4"
+ "@babel/template" "^7.28.6"
+ "@babel/types" "^7.28.6"
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.27.2", "@babel/parser@^7.28.5":
- version "7.28.5"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08"
- integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd"
+ integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==
dependencies:
- "@babel/types" "^7.28.5"
+ "@babel/types" "^7.28.6"
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
@@ -155,11 +155,11 @@
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-syntax-import-attributes@^7.24.7":
- version "7.27.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07"
- integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503"
+ integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==
dependencies:
- "@babel/helper-plugin-utils" "^7.27.1"
+ "@babel/helper-plugin-utils" "^7.28.6"
"@babel/plugin-syntax-import-meta@^7.10.4":
version "7.10.4"
@@ -176,11 +176,11 @@
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-jsx@^7.7.2":
- version "7.27.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c"
- integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee"
+ integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==
dependencies:
- "@babel/helper-plugin-utils" "^7.27.1"
+ "@babel/helper-plugin-utils" "^7.28.6"
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
version "7.10.4"
@@ -239,43 +239,43 @@
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-syntax-typescript@^7.7.2":
- version "7.27.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18"
- integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2"
+ integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==
dependencies:
- "@babel/helper-plugin-utils" "^7.27.1"
+ "@babel/helper-plugin-utils" "^7.28.6"
"@babel/runtime@^7.12.5":
- version "7.28.4"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326"
- integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==
-
-"@babel/template@^7.27.2", "@babel/template@^7.3.3":
- version "7.27.2"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
- integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==
- dependencies:
- "@babel/code-frame" "^7.27.1"
- "@babel/parser" "^7.27.2"
- "@babel/types" "^7.27.1"
-
-"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.5":
- version "7.28.5"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b"
- integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==
- dependencies:
- "@babel/code-frame" "^7.27.1"
- "@babel/generator" "^7.28.5"
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b"
+ integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==
+
+"@babel/template@^7.28.6", "@babel/template@^7.3.3":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57"
+ integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==
+ dependencies:
+ "@babel/code-frame" "^7.28.6"
+ "@babel/parser" "^7.28.6"
+ "@babel/types" "^7.28.6"
+
+"@babel/traverse@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e"
+ integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==
+ dependencies:
+ "@babel/code-frame" "^7.28.6"
+ "@babel/generator" "^7.28.6"
"@babel/helper-globals" "^7.28.0"
- "@babel/parser" "^7.28.5"
- "@babel/template" "^7.27.2"
- "@babel/types" "^7.28.5"
+ "@babel/parser" "^7.28.6"
+ "@babel/template" "^7.28.6"
+ "@babel/types" "^7.28.6"
debug "^4.3.1"
-"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.3.3":
- version "7.28.5"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b"
- integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.3.3":
+ version "7.28.6"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df"
+ integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==
dependencies:
"@babel/helper-string-parser" "^7.27.1"
"@babel/helper-validator-identifier" "^7.28.5"
@@ -291,9 +291,9 @@
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@cypress/request@^3.0.0":
- version "3.0.9"
- resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.9.tgz#8ed6e08fea0c62998b5552301023af7268f11625"
- integrity sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==
+ version "3.0.10"
+ resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.10.tgz#e09c695e8460a82acafe6cfaf089cf2ca06dc054"
+ integrity sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
@@ -308,7 +308,7 @@
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
performance-now "^2.1.0"
- qs "6.14.0"
+ qs "~6.14.1"
safe-buffer "^5.1.2"
tough-cookie "^5.0.0"
tunnel-agent "^0.6.0"
@@ -323,17 +323,17 @@
lodash.once "^4.1.1"
"@emnapi/core@^1.4.3":
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.0.tgz#135de4e8858763989112281bdf38ca02439db7c3"
- integrity sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349"
+ integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==
dependencies:
"@emnapi/wasi-threads" "1.1.0"
tslib "^2.4.0"
"@emnapi/runtime@^1.4.3":
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.0.tgz#d7ef3832df8564fe5903bf0567aedbd19538ecbe"
- integrity sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5"
+ integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==
dependencies:
tslib "^2.4.0"
@@ -349,10 +349,140 @@
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745"
integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
+"@esbuild/aix-ppc64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz#521cbd968dcf362094034947f76fa1b18d2d403c"
+ integrity sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==
+
+"@esbuild/android-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz#61ea550962d8aa12a9b33194394e007657a6df57"
+ integrity sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==
+
+"@esbuild/android-arm@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.2.tgz#554887821e009dd6d853f972fde6c5143f1de142"
+ integrity sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==
+
+"@esbuild/android-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.2.tgz#a7ce9d0721825fc578f9292a76d9e53334480ba2"
+ integrity sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==
+
+"@esbuild/darwin-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz#2cb7659bd5d109803c593cfc414450d5430c8256"
+ integrity sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==
+
+"@esbuild/darwin-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz#e741fa6b1abb0cd0364126ba34ca17fd5e7bf509"
+ integrity sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==
+
+"@esbuild/freebsd-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz#2b64e7116865ca172d4ce034114c21f3c93e397c"
+ integrity sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==
+
+"@esbuild/freebsd-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz#e5252551e66f499e4934efb611812f3820e990bb"
+ integrity sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==
+
+"@esbuild/linux-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz#dc4acf235531cd6984f5d6c3b13dbfb7ddb303cb"
+ integrity sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==
+
+"@esbuild/linux-arm@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz#56a900e39240d7d5d1d273bc053daa295c92e322"
+ integrity sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==
+
+"@esbuild/linux-ia32@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz#d4a36d473360f6870efcd19d52bbfff59a2ed1cc"
+ integrity sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==
+
+"@esbuild/linux-loong64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz#fcf0ab8c3eaaf45891d0195d4961cb18b579716a"
+ integrity sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==
+
+"@esbuild/linux-mips64el@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz#598b67d34048bb7ee1901cb12e2a0a434c381c10"
+ integrity sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==
+
+"@esbuild/linux-ppc64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz#3846c5df6b2016dab9bc95dde26c40f11e43b4c0"
+ integrity sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==
+
+"@esbuild/linux-riscv64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz#173d4475b37c8d2c3e1707e068c174bb3f53d07d"
+ integrity sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==
+
+"@esbuild/linux-s390x@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz#f7a4790105edcab8a5a31df26fbfac1aa3dacfab"
+ integrity sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==
+
+"@esbuild/linux-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz#2ecc1284b1904aeb41e54c9ddc7fcd349b18f650"
+ integrity sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==
+
+"@esbuild/netbsd-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz#e2863c2cd1501845995cb11adf26f7fe4be527b0"
+ integrity sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==
+
+"@esbuild/netbsd-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz#93f7609e2885d1c0b5a1417885fba8d1fcc41272"
+ integrity sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==
+
+"@esbuild/openbsd-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz#a1985604a203cdc325fd47542e106fafd698f02e"
+ integrity sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==
+
+"@esbuild/openbsd-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz#8209e46c42f1ffbe6e4ef77a32e1f47d404ad42a"
+ integrity sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==
+
+"@esbuild/openharmony-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz#8fade4441893d9cc44cbd7dcf3776f508ab6fb2f"
+ integrity sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==
+
+"@esbuild/sunos-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz#980d4b9703a16f0f07016632424fc6d9a789dfc2"
+ integrity sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==
+
+"@esbuild/win32-arm64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz#1c09a3633c949ead3d808ba37276883e71f6111a"
+ integrity sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==
+
+"@esbuild/win32-ia32@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz#1b1e3a63ad4bef82200fef4e369e0fff7009eee5"
+ integrity sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==
+
+"@esbuild/win32-x64@0.27.2":
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz#9e585ab6086bef994c6e8a5b3a0481219ada862b"
+ integrity sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==
+
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
- version "4.9.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3"
- integrity sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==
+ version "4.9.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595"
+ integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==
dependencies:
eslint-visitor-keys "^3.4.3"
@@ -438,18 +568,6 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
-"@isaacs/cliui@^8.0.2":
- version "8.0.2"
- resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
- integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
- dependencies:
- string-width "^5.1.2"
- string-width-cjs "npm:string-width@^4.2.0"
- strip-ansi "^7.0.1"
- strip-ansi-cjs "npm:strip-ansi@^6.0.1"
- wrap-ansi "^8.1.0"
- wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
-
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@@ -720,14 +838,14 @@
rxjs "6"
semver "^7.3.5"
-"@ledgerhq/devices@8.7.0", "@ledgerhq/devices@^8.0.7", "@ledgerhq/devices@^8.3.0":
- version "8.7.0"
- resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.7.0.tgz#39e011c484c4251c92769f92cf8c23b8a0b4ce39"
- integrity sha512-3pSOULPUhClk2oOxa6UnoyXW8+05FK7r6cpq2WiTey4kyIUjmIraO7AX9lhz9IU73dGVtBMdU+NCPPO2RYJaTQ==
+"@ledgerhq/devices@8.8.0", "@ledgerhq/devices@^8.0.7", "@ledgerhq/devices@^8.3.0":
+ version "8.8.0"
+ resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.8.0.tgz#479298de2b4dd059fe52fc2c627caf120b59923f"
+ integrity sha512-ZFRAQQaESxIK/8SYrrHyqb7pQjLPO8f62PI6H16SP0/uC9fdZKR8NqOGMvIf7I6K442SkiQATnC/kxUeUTfuHA==
dependencies:
- "@ledgerhq/errors" "^6.27.0"
+ "@ledgerhq/errors" "^6.28.0"
"@ledgerhq/logs" "^6.13.0"
- rxjs "^7.8.1"
+ rxjs "7.8.2"
semver "^7.3.5"
"@ledgerhq/errors@6.12.6":
@@ -735,10 +853,10 @@
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.12.6.tgz#f89c82c91c2930f34bc3e0d86a27ec7b6e6e4f5f"
integrity sha512-D+r2B09vaRO06wfGoss+rNgwqWSoK0bCtsaJWzlD2hv1zxTtucqVtSztbRFypIqxWTCb3ix5Nh2dWHEJVTp2Xw==
-"@ledgerhq/errors@^6.12.6", "@ledgerhq/errors@^6.14.0", "@ledgerhq/errors@^6.16.4", "@ledgerhq/errors@^6.27.0":
- version "6.27.0"
- resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.27.0.tgz#3acc978ed1dbbdd8049dcedccccf4a96968f583a"
- integrity sha512-EE2hATONHdNP3YWFe3rZwwpSEzI5oN+q/xTjOulnjHZo84TLjungegEJ54A/Pzld0woulkkeVA27FbW5SAO1aA==
+"@ledgerhq/errors@^6.12.6", "@ledgerhq/errors@^6.14.0", "@ledgerhq/errors@^6.16.4", "@ledgerhq/errors@^6.28.0":
+ version "6.28.0"
+ resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.28.0.tgz#4a4ccea3b7ee28a54f4301053729c3804d8d0737"
+ integrity sha512-Rx6GN801GP/3gCfVmmiXFVZWmiaEGMuXVwjM6WOCX0dzw4v7KcB1nj4vrNC1plDI/xkPt/clYJPG7LgSt0mxlw==
"@ledgerhq/hw-transport-web-ble@6.28.6":
version "6.28.6"
@@ -781,12 +899,12 @@
events "^3.3.0"
"@ledgerhq/hw-transport@^6.30.6":
- version "6.31.13"
- resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.13.tgz#87e4a53bdcca257eeea6cbcc7a662c449a0cfa92"
- integrity sha512-MrJRDk74wY980ofiFPRpTHQBbRw1wDuKbdag1zqlO1xtJglymwwY03K2kvBNvkm1RTSCPUp/nAoNG+WThZuuew==
+ version "6.31.15"
+ resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.15.tgz#6df7c630b5e438900bbc70bf5d5849696a7283a0"
+ integrity sha512-I+hzH9XGFPaYq9K+iw+qWJUyVdhN9fdO00Df9zAkOCzju1W5Gc+cDJxbYnZApmY8oMd8mNoXTstEW3Ih5ikaVg==
dependencies:
- "@ledgerhq/devices" "8.7.0"
- "@ledgerhq/errors" "^6.27.0"
+ "@ledgerhq/devices" "8.8.0"
+ "@ledgerhq/errors" "^6.28.0"
"@ledgerhq/logs" "^6.13.0"
events "^3.3.0"
@@ -840,13 +958,14 @@
axios "^1.10.0"
bip39 "3.1.0"
-"@multiversx/sdk-dapp-ui@>=0.1.2 <0.2.0", "@multiversx/sdk-dapp-ui@^0.x":
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-ui/-/sdk-dapp-ui-0.1.2.tgz#3acc08c126e9b01e7ccc2fc92bc2fbe74d2782b9"
- integrity sha512-p6UeVVpGTY0JrpuPhEOeK4qLBQ5kcetRStJFrX5vK87xnswWU1k4DKITe89yXTPXWPlX1nRl9rcEQPO6Ht9D9g==
+"@multiversx/sdk-dapp-ui@>=0.1.3 <0.2.0", "@multiversx/sdk-dapp-ui@^0.x":
+ version "0.1.9"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-ui/-/sdk-dapp-ui-0.1.9.tgz#fcd9f284c00fce84ad3e8ab761d1cb060b6ad675"
+ integrity sha512-PSROSftUpyYw+SAD4zG+ma8b7MhhCdteXs36T41lqPqxFoAL6cEL3u7AAYr/Cngqjxbf5aIoVF1WDIMUkQkYNA==
dependencies:
- "@stencil/core" "^4.36.2"
+ "@stencil/core" "4.38.1"
"@stencil/react-output-target" "1.2.0"
+ "@stencil/vue-output-target" "0.11.8"
classnames ">=2.5.1"
lodash.capitalize "^4.2.1"
lodash.inrange "^3.3.0"
@@ -859,19 +978,18 @@
integrity sha512-x2b2Gz5j0mDPUV2UK0fyDideGq/tfznvFJUJIJUMfKRy9Frni26UXZuQXCN4ngs344fd+8XoJOeviNV6cXSFdw==
"@multiversx/sdk-dapp@^5.x":
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp/-/sdk-dapp-5.3.1.tgz#94870b044e3f933123e170286af15620c9bda325"
- integrity sha512-AnbbzjIDAQxhd0nW5vU+NBMoOAp1+Y4yxUUSSc0GZkrRGelz+l1oOB/QBU/GWIqxm3em510e78ZlkJbfx0fZnA==
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp/-/sdk-dapp-5.6.0.tgz#9e2042cb106c37a2207dcbd3d6611c5aecf9baa1"
+ integrity sha512-jLJb9ra9SJgb7z5W3gAWkwi78HwiisJIS/xHsNuuM/BxFF1FfERVV//6lkhscSL1P0uBV8hcnColWHjaxOJ5VQ==
dependencies:
"@lifeomic/axios-fetch" "3.0.1"
- "@multiversx/sdk-extension-provider" "5.1.1"
- "@multiversx/sdk-hw-provider" "8.1.1"
+ "@multiversx/sdk-extension-provider" "5.1.2"
+ "@multiversx/sdk-hw-provider" "8.1.2"
"@multiversx/sdk-native-auth-client" "2.0.1"
- "@multiversx/sdk-wallet-connect-provider" "6.1.3"
- "@multiversx/sdk-web-wallet-cross-window-provider" "3.2.1"
- "@multiversx/sdk-web-wallet-iframe-provider" "4.0.0"
- "@multiversx/sdk-web-wallet-provider" "5.1.1"
- "@multiversx/sdk-webview-provider" "3.2.5"
+ "@multiversx/sdk-wallet-connect-provider" "6.1.4"
+ "@multiversx/sdk-web-wallet-cross-window-provider" "3.2.2"
+ "@multiversx/sdk-web-wallet-iframe-provider" "4.0.1"
+ "@multiversx/sdk-webview-provider" "3.2.6"
immer "10.1.1"
linkifyjs "4.3.2"
lodash.isempty "4.4.0"
@@ -883,17 +1001,17 @@
socket.io-client "4.7.5"
zustand "4.4.7"
optionalDependencies:
- "@multiversx/sdk-dapp-ui" ">=0.1.2 <0.2.0"
+ "@multiversx/sdk-dapp-ui" ">=0.1.3 <0.2.0"
-"@multiversx/sdk-extension-provider@5.1.1":
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-extension-provider/-/sdk-extension-provider-5.1.1.tgz#aa4a76bc681b53be3937fd65eb79b89f506d1557"
- integrity sha512-q24eSFiXQ4SQG3UZU8FILGut/fw9WL9o6UjTSzF6CIUuFHtSQ/bLJnMIHM1ZHTeqhOYNfXhI6ozOIwtP3mR+xQ==
+"@multiversx/sdk-extension-provider@5.1.2":
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-extension-provider/-/sdk-extension-provider-5.1.2.tgz#a44733ef0fe66cd3d0b1a25167d26687b12b3b6c"
+ integrity sha512-jxu18WKnc8ZLaLdl6ePcLStG2aZB1f9W0m2wPJt2UbHnPMhnk/okoYZYWlHfiF/L8WZGzQn8VXwcmras/vdwlw==
-"@multiversx/sdk-hw-provider@8.1.1":
- version "8.1.1"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-hw-provider/-/sdk-hw-provider-8.1.1.tgz#642047762d8f1a2a0a3319bd6e578653cd8aa369"
- integrity sha512-vrCoqTRPmXDFyR8LeRlEk/oyrUXhD1nk9tAltXyzJgRIUcuyPJJKd45pi8mumBP0DTmzICeJKgi+A8wHxogL8g==
+"@multiversx/sdk-hw-provider@8.1.2":
+ version "8.1.2"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-hw-provider/-/sdk-hw-provider-8.1.2.tgz#24029d265ee3f6da156321fd06038952ae01c96c"
+ integrity sha512-Q/cIOi+3JiZ4/FV/608kEcaQAprv9NP2GmuxONdPW5YACIHGdS5WILsQTL6xqDxBsNEfN71DbbNHKEr7pqnq6Q==
dependencies:
"@ledgerhq/devices" "8.0.3"
"@ledgerhq/errors" "6.12.6"
@@ -916,42 +1034,35 @@
dependencies:
bech32 "^2.0.0"
-"@multiversx/sdk-wallet-connect-provider@6.1.3":
- version "6.1.3"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet-connect-provider/-/sdk-wallet-connect-provider-6.1.3.tgz#fe2f014fad9c04ca910a124f71717e86ba0c9eab"
- integrity sha512-hulgy2aXqE/nYt7sYjKKvkU+h3OSJM57+6WSdUUdyslp/J3Gqe5vc0mWMkkEMDr0pDEpMlLGMu3J1SjtbMd+9w==
+"@multiversx/sdk-wallet-connect-provider@6.1.4":
+ version "6.1.4"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet-connect-provider/-/sdk-wallet-connect-provider-6.1.4.tgz#b67affe59cb5cb4361043fe841dac478b64d46cc"
+ integrity sha512-uiRLQ9oBM4KAUxuYlh/QgbYGRjgJuxHTuvjtmDgh5GYbfdiPeXXkoQsUI01IYgCvMl/8iVv4ss4YAfgob6riOw==
dependencies:
"@walletconnect/sign-client" "2.22.4"
"@walletconnect/utils" "2.22.4"
bech32 "1.1.4"
-"@multiversx/sdk-web-wallet-cross-window-provider@3.2.1":
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-3.2.1.tgz#9d778867f6cc669a3772c1780f82bf640fccd866"
- integrity sha512-INWbQ+GXtGz+aIRZZcmFhTIfJPyf4F5X2HrG0BQu9riT31QxoIjpwSd8M91QyODbgUEJHUVCKppOe038/Xb1xw==
+"@multiversx/sdk-web-wallet-cross-window-provider@3.2.2":
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-3.2.2.tgz#262eab62356cafd1ddee34ced7667668760fcd6b"
+ integrity sha512-CBMrf+oNKoBa/YFDTqzItLrERaW4n0pJIlGsP67H0Vr6bUlFLIlc30qsOGvWNoZvMDeDxvhvR7crayypETJSJw==
dependencies:
qs "6.11.2"
-"@multiversx/sdk-web-wallet-iframe-provider@4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-4.0.0.tgz#6739dcf3778fa4efd296b3db881ec2c98240eb16"
- integrity sha512-V9eDWSublrau6yXASzQwCkdwr9ATxfQ8C8Ok27wSmx9Ok/JrSK1eCgN2XcrehFonn8nYnTHehYR1Qe0QZ6q+iw==
+"@multiversx/sdk-web-wallet-iframe-provider@4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-4.0.1.tgz#95af41206474aff8cfdae4e9860960245fea3583"
+ integrity sha512-zIIKX4G1xYk7XSBQsHuihOag7pUAVGMZ1q3vug9XpwBwcQvgcSwC5RHzrYQusPpVdkTHIn3qa3JHqjwNj1VtGA==
dependencies:
"@types/jest" "^29.5.11"
"@types/qs" "6.9.10"
qs "6.11.2"
-"@multiversx/sdk-web-wallet-provider@5.1.1":
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-provider/-/sdk-web-wallet-provider-5.1.1.tgz#ca5dbe03772df451feb733e11ffb8b5139d02ba1"
- integrity sha512-3ZKA3vhOKPkPzmpcRZRoAATBWOXnO7kOu/9yC2TEHQImQi38CoLkWCUH1uHWOlccZ32ciDsp/YIfOP/DgG1KiQ==
- dependencies:
- qs "6.10.3"
-
-"@multiversx/sdk-webview-provider@3.2.5":
- version "3.2.5"
- resolved "https://registry.yarnpkg.com/@multiversx/sdk-webview-provider/-/sdk-webview-provider-3.2.5.tgz#20013a9a9a47ef8106e436457a30a1d0c8d8a8dd"
- integrity sha512-mHpQfuJc7xVXcyMx9iz/BLxM6pBftdibfFU4RLEGivBuw57xxY2veCWyfYW/MpaN9qFa7XA/X9N5PhEb6zbRsQ==
+"@multiversx/sdk-webview-provider@3.2.6":
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/@multiversx/sdk-webview-provider/-/sdk-webview-provider-3.2.6.tgz#a1609b1b0707bb6b12700b2fcef2bc7430fdac43"
+ integrity sha512-Zq+mjdbPavnSLRvt4TuFqfIbnh0esADbEJgxs0lbGP6YxyL1zDbyxoDpWNpjYDb6o6X87buZMrO8qlHaInxQ6g==
"@napi-rs/wasm-runtime@^0.2.11":
version "0.2.12"
@@ -1091,10 +1202,12 @@
resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e"
integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==
-"@pkgjs/parseargs@^0.11.0":
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
- integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+"@playwright/test@^1.57.0":
+ version "1.57.0"
+ resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.57.0.tgz#a14720ffa9ed7ef7edbc1f60784fc6134acbb003"
+ integrity sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==
+ dependencies:
+ playwright "1.57.0"
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
@@ -1149,55 +1262,180 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+"@rollup/rollup-android-arm-eabi@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz#76e0fef6533b3ce313f969879e61e8f21f0eeb28"
+ integrity sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==
+
+"@rollup/rollup-android-arm64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz#d3cfc675a40bbdec97bda6d7fe3b3b05f0e1cd93"
+ integrity sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==
+
"@rollup/rollup-darwin-arm64@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz#363467bc49fd0b1e17075798ac8e9ad1e1e29535"
integrity sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==
+"@rollup/rollup-darwin-arm64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz#eb912b8f59dd47c77b3c50a78489013b1d6772b4"
+ integrity sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==
+
"@rollup/rollup-darwin-x64@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz#c2fe3d85fffe47f0ed0f076b3563ada22c8af19c"
integrity sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==
+"@rollup/rollup-darwin-x64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz#e7d0839fdfd1276a1d34bc5ebbbd0dfd7d0b81a0"
+ integrity sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==
+
+"@rollup/rollup-freebsd-arm64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz#7ff8118760f7351e48fd0cd3717ff80543d6aac8"
+ integrity sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==
+
+"@rollup/rollup-freebsd-x64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz#49d330dadbda1d4e9b86b4a3951b59928a9489a9"
+ integrity sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz#98c5f1f8b9776b4a36e466e2a1c9ed1ba52ef1b6"
+ integrity sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==
+
+"@rollup/rollup-linux-arm-musleabihf@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz#b9acecd3672e742f70b0c8a94075c816a91ff040"
+ integrity sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==
+
"@rollup/rollup-linux-arm64-gnu@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz#1015c9d07a99005025d13b8622b7600029d0b52f"
integrity sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==
+"@rollup/rollup-linux-arm64-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz#7a6ab06651bc29e18b09a50ed1a02bc972977c9b"
+ integrity sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==
+
"@rollup/rollup-linux-arm64-musl@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz#8f895eb5577748fc75af21beae32439626e0a14c"
integrity sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==
+"@rollup/rollup-linux-arm64-musl@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz#3c8c9072ba4a4d4ef1156b85ab9a2cbb57c1fad0"
+ integrity sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==
+
+"@rollup/rollup-linux-loong64-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz#17a7af13530f4e4a7b12cd26276c54307a84a8b0"
+ integrity sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==
+
+"@rollup/rollup-linux-loong64-musl@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz#5cd7a900fd7b077ecd753e34a9b7ff1157fe70c1"
+ integrity sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==
+
+"@rollup/rollup-linux-ppc64-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz#03a097e70243ddf1c07b59d3c20f38e6f6800539"
+ integrity sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==
+
+"@rollup/rollup-linux-ppc64-musl@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz#a5389873039d4650f35b4fa060d286392eb21a94"
+ integrity sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==
+
+"@rollup/rollup-linux-riscv64-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz#789e60e7d6e2b76132d001ffb24ba80007fb17d0"
+ integrity sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==
+
+"@rollup/rollup-linux-riscv64-musl@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz#3556fa88d139282e9a73c337c9a170f3c5fe7aa4"
+ integrity sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==
+
+"@rollup/rollup-linux-s390x-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz#c085995b10143c16747a67f1a5487512b2ff04b2"
+ integrity sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==
+
"@rollup/rollup-linux-x64-gnu@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz#7193cbd8d128212b8acda37e01b39d9e96259ef8"
integrity sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==
+"@rollup/rollup-linux-x64-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz#9563a5419dd2604841bad31a39ccfdd2891690fb"
+ integrity sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==
+
"@rollup/rollup-linux-x64-musl@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz#29a6867278ca0420b891574cfab98ecad70c59d1"
integrity sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==
+"@rollup/rollup-linux-x64-musl@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz#691bb06e6269a8959c13476b0cd2aa7458facb31"
+ integrity sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==
+
+"@rollup/rollup-openbsd-x64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz#223e71224746a59ce6d955bbc403577bb5a8be9d"
+ integrity sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==
+
+"@rollup/rollup-openharmony-arm64@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz#0817e5d8ecbfeb8b7939bf58f8ce3c9dd67fce77"
+ integrity sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==
+
"@rollup/rollup-win32-arm64-msvc@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz#89427dcac0c8e3a6d32b13a03a296a275d0de9a9"
integrity sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==
+"@rollup/rollup-win32-arm64-msvc@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz#de56d8f2013c84570ef5fb917aae034abda93e4a"
+ integrity sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==
+
+"@rollup/rollup-win32-ia32-msvc@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz#659aff5244312475aeea2c9479a6c7d397b517bf"
+ integrity sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==
+
+"@rollup/rollup-win32-x64-gnu@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz#2cb09549cbb66c1b979f9238db6dd454cac14a88"
+ integrity sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==
+
"@rollup/rollup-win32-x64-msvc@4.34.9":
version "4.34.9"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz#1973871850856ae72bc678aeb066ab952330e923"
integrity sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==
+"@rollup/rollup-win32-x64-msvc@4.55.1":
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz#f79437939020b83057faf07e98365b1fa51c458b"
+ integrity sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==
+
"@rtsao/scc@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
"@rushstack/eslint-patch@^1.3.3":
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.14.1.tgz#5f7c5c335643cff62ad8e6a9432d708a9c51e98c"
- integrity sha512-jGTk8UD/RdjsNZW8qq10r0RBvxL8OWtoT+kImlzPDFilmozzM+9QmIJsmze9UiSBrFU45ZxhTYBypn9q9z/VfQ==
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz#8184bcb37791e6d3c3c13a9bfbe4af263f66665f"
+ integrity sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==
"@scure/base@1.2.6", "@scure/base@~1.2.5":
version "1.2.6"
@@ -1245,10 +1483,10 @@
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2"
integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==
-"@stencil/core@^4.36.2":
- version "4.38.3"
- resolved "https://registry.yarnpkg.com/@stencil/core/-/core-4.38.3.tgz#2743e29db3fcf02016c8b66693c6ffecb18a2ba8"
- integrity sha512-rSDzGUfi58X8K79ySjlM6KlY+mq7D+ittzgNAdYHcsXHc70sBpdatFhnbOg25uVDiMf7xRAH9slP38pPdXnZOQ==
+"@stencil/core@4.38.1":
+ version "4.38.1"
+ resolved "https://registry.yarnpkg.com/@stencil/core/-/core-4.38.1.tgz#7c98b71e9e9ef7ba5418ac16b058737ba692f359"
+ integrity sha512-qImplYLSp2wSZJo3oMZ3HrTaI+uULcRB4Knrua7UT9VjN/va+TDfk4JAKwDyDfTDkD2laDPcy6QJP2S3hVxZFQ==
optionalDependencies:
"@rollup/rollup-darwin-arm64" "4.34.9"
"@rollup/rollup-darwin-x64" "4.34.9"
@@ -1269,6 +1507,11 @@
react-style-stringify "^1.2.0"
ts-morph "^22.0.0"
+"@stencil/vue-output-target@0.11.8":
+ version "0.11.8"
+ resolved "https://registry.yarnpkg.com/@stencil/vue-output-target/-/vue-output-target-0.11.8.tgz#34d50cd25b230cf603de1e415db6b41d2b81c4d1"
+ integrity sha512-R/kQoN15irgL7NJxWaUNSmwDLfoDBZjlYaXNnW3LHlF30TYfyez6pRgD7ZglSSTVktMtCXz6ZPhg0uq59VkhOw==
+
"@swc/core-darwin-arm64@1.3.91":
version "1.3.91"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.91.tgz#3bb751899cd208be261c48190b75c87171be79b4"
@@ -1448,6 +1691,11 @@
dependencies:
"@babel/types" "^7.28.2"
+"@types/estree@1.0.8":
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
+ integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
+
"@types/graceful-fs@^4.1.3":
version "4.1.9"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"
@@ -1510,9 +1758,9 @@
form-data "^4.0.4"
"@types/node@*", "@types/node@>=13.7.0":
- version "24.10.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.0.tgz#6b79086b0dfc54e775a34ba8114dcc4e0221f31f"
- integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==
+ version "25.0.7"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-25.0.7.tgz#afd2f0d34358631a287c6726dabe0c845abc2bae"
+ integrity sha512-C/er7DlIZgRJO7WtTdYovjIFzGsz0I95UlMyR9anTb4aCpBSRWe5Jc1/RvLKUfzmOxHPGjSE5+63HgLtndxU4w==
dependencies:
undici-types "~7.16.0"
@@ -1556,11 +1804,11 @@
integrity sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==
"@types/react@*":
- version "19.2.2"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.2.tgz#ba123a75d4c2a51158697160a4ea2ff70aa6bf36"
- integrity sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==
+ version "19.2.8"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.8.tgz#307011c9f5973a6abab8e17d0293f48843627994"
+ integrity sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==
dependencies:
- csstype "^3.0.2"
+ csstype "^3.2.2"
"@types/react@18.2.24":
version "18.2.24"
@@ -1607,16 +1855,16 @@
integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==
"@types/yargs@^16.0.0":
- version "16.0.10"
- resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.10.tgz#2376eed83bc9dbda3d7253a44e18328fc0854477"
- integrity sha512-0xbOE6Ht/oj0MTVVXCCdEZzUk7adwW3YB1Tg1ZBm95jrkrUMI0VA4sf3SgxC1TG8p5aKkn3jxT9A2BDw1mM/TQ==
+ version "16.0.11"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.11.tgz#de958fb62e77fc383fa6cd8066eabdd13da88f04"
+ integrity sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g==
dependencies:
"@types/yargs-parser" "*"
"@types/yargs@^17.0.8":
- version "17.0.34"
- resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.34.tgz#1c2f9635b71d5401827373a01ce2e8a7670ea839"
- integrity sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==
+ version "17.0.35"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24"
+ integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==
dependencies:
"@types/yargs-parser" "*"
@@ -2050,9 +2298,9 @@ abab@^2.0.6:
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
abitype@^1.0.9:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.1.1.tgz#b50ed400f8bfca5452eb4033445c309d3e1117c8"
- integrity sha512-Loe5/6tAgsBukY95eGaPSDmQHIjRZYQq8PB1MpsNccDIK8WiV+Uw6WzaIXipvaxTEL2yEB0OpEaQv3gs8pkS9Q==
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4"
+ integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==
acorn-globals@^7.0.0:
version "7.0.1"
@@ -2143,11 +2391,6 @@ ansi-styles@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
-ansi-styles@^6.1.0:
- version "6.2.3"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041"
- integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==
-
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
@@ -2368,9 +2611,9 @@ aws4@^1.8.0:
integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==
axe-core@^4.10.0:
- version "4.11.0"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.11.0.tgz#16f74d6482e343ff263d4f4503829e9ee91a86b6"
- integrity sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==
+ version "4.11.1"
+ resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.11.1.tgz#052ff9b2cbf543f5595028b583e4763b40c78ea7"
+ integrity sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==
axios@^1.10.0:
version "1.13.2"
@@ -2464,10 +2707,10 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-baseline-browser-mapping@^2.8.19:
- version "2.8.25"
- resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz#947dc6f81778e0fa0424a2ab9ea09a3033e71109"
- integrity sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==
+baseline-browser-mapping@^2.9.0:
+ version "2.9.14"
+ resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz#3b6af0bc032445bca04de58caa9a87cfe921cbb3"
+ integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
@@ -2566,15 +2809,15 @@ braces@^3.0.3, braces@~3.0.2:
fill-range "^7.1.1"
browserslist@^4.21.10, browserslist@^4.24.0:
- version "4.27.0"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.27.0.tgz#755654744feae978fbb123718b2f139bc0fa6697"
- integrity sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==
+ version "4.28.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95"
+ integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==
dependencies:
- baseline-browser-mapping "^2.8.19"
- caniuse-lite "^1.0.30001751"
- electron-to-chromium "^1.5.238"
- node-releases "^2.0.26"
- update-browserslist-db "^1.1.4"
+ baseline-browser-mapping "^2.9.0"
+ caniuse-lite "^1.0.30001759"
+ electron-to-chromium "^1.5.263"
+ node-releases "^2.0.27"
+ update-browserslist-db "^1.2.0"
bs-logger@0.x:
version "0.2.6"
@@ -2688,10 +2931,10 @@ camelcase@^6.2.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001751:
- version "1.0.30001754"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz#7758299d9a72cce4e6b038788a15b12b44002759"
- integrity sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==
+caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001759:
+ version "1.0.30001764"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz#03206c56469f236103b90f9ae10bcb8b9e1f6005"
+ integrity sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==
caseless@~0.12.0:
version "0.12.0"
@@ -2949,7 +3192,7 @@ create-jest@^29.7.0:
jest-util "^29.7.0"
prompts "^2.0.1"
-cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
@@ -2987,10 +3230,10 @@ cssstyle@^2.3.0:
dependencies:
cssom "~0.3.6"
-csstype@^3.0.2:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
- integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+csstype@^3.0.2, csstype@^3.2.2:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
+ integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
cypress-mochawesome-reporter@3.7.0:
version "3.7.0"
@@ -3110,7 +3353,7 @@ dayjs@^1.10.4:
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938"
integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==
-debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0:
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@~4.4.1:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
@@ -3142,9 +3385,9 @@ decimal.js@^10.4.2:
integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==
dedent@^1.0.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.0.tgz#c1f9445335f0175a96587be245a282ff451446ca"
- integrity sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.1.tgz#364661eea3d73f3faba7089214420ec2f8f13e15"
+ integrity sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==
deep-equal@^2.0.5:
version "2.2.3"
@@ -3320,11 +3563,6 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1:
es-errors "^1.3.0"
gopd "^1.2.0"
-eastasianwidth@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
- integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
-
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
@@ -3349,10 +3587,10 @@ ed2curve@0.3.0:
dependencies:
tweetnacl "1.x.x"
-electron-to-chromium@^1.5.238:
- version "1.5.248"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.248.tgz#e69941494efbc69ebf2803517f4e85d016013d4b"
- integrity sha512-zsur2yunphlyAO4gIubdJEXCK6KOVvtpiuDfCIqbM9FjcnMYiyn0ICa3hWfPr0nc41zcLWobgy1iL7VvoOyA2Q==
+electron-to-chromium@^1.5.263:
+ version "1.5.267"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7"
+ integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==
emittery@^0.13.1:
version "0.13.1"
@@ -3393,9 +3631,9 @@ engine.io-parser@~5.2.1:
integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==
enhanced-resolve@^5.10.0:
- version "5.18.3"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz#9b5f4c5c076b8787c78fe540392ce76a88855b44"
- integrity sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==
+ version "5.18.4"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz#c22d33055f3952035ce6a144ce092447c525f828"
+ integrity sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
@@ -3425,10 +3663,10 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0:
- version "1.24.0"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328"
- integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==
+es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0, es-abstract@^1.24.1:
+ version "1.24.1"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.1.tgz#f0c131ed5ea1bb2411134a8dd94def09c46c7899"
+ integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==
dependencies:
array-buffer-byte-length "^1.0.2"
arraybuffer.prototype.slice "^1.0.4"
@@ -3511,25 +3749,25 @@ es-get-iterator@^1.1.3:
stop-iteration-iterator "^1.0.0"
es-iterator-helpers@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75"
- integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz#d979a9f686e2b0b72f88dbead7229924544720bc"
+ integrity sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==
dependencies:
call-bind "^1.0.8"
- call-bound "^1.0.3"
+ call-bound "^1.0.4"
define-properties "^1.2.1"
- es-abstract "^1.23.6"
+ es-abstract "^1.24.1"
es-errors "^1.3.0"
- es-set-tostringtag "^2.0.3"
+ es-set-tostringtag "^2.1.0"
function-bind "^1.1.2"
- get-intrinsic "^1.2.6"
+ get-intrinsic "^1.3.0"
globalthis "^1.0.4"
gopd "^1.2.0"
has-property-descriptors "^1.0.2"
has-proto "^1.2.0"
has-symbols "^1.1.0"
internal-slot "^1.1.0"
- iterator.prototype "^1.1.4"
+ iterator.prototype "^1.1.5"
safe-array-concat "^1.1.3"
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
@@ -3539,7 +3777,7 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
dependencies:
es-errors "^1.3.0"
-es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0:
+es-set-tostringtag@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
@@ -3570,6 +3808,38 @@ es-toolkit@1.39.3:
resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.39.3.tgz#934b2cab9578c496dcbc0305cae687258cb14aee"
integrity sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww==
+esbuild@^0.27.0:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.2.tgz#d83ed2154d5813a5367376bb2292a9296fc83717"
+ integrity sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.27.2"
+ "@esbuild/android-arm" "0.27.2"
+ "@esbuild/android-arm64" "0.27.2"
+ "@esbuild/android-x64" "0.27.2"
+ "@esbuild/darwin-arm64" "0.27.2"
+ "@esbuild/darwin-x64" "0.27.2"
+ "@esbuild/freebsd-arm64" "0.27.2"
+ "@esbuild/freebsd-x64" "0.27.2"
+ "@esbuild/linux-arm" "0.27.2"
+ "@esbuild/linux-arm64" "0.27.2"
+ "@esbuild/linux-ia32" "0.27.2"
+ "@esbuild/linux-loong64" "0.27.2"
+ "@esbuild/linux-mips64el" "0.27.2"
+ "@esbuild/linux-ppc64" "0.27.2"
+ "@esbuild/linux-riscv64" "0.27.2"
+ "@esbuild/linux-s390x" "0.27.2"
+ "@esbuild/linux-x64" "0.27.2"
+ "@esbuild/netbsd-arm64" "0.27.2"
+ "@esbuild/netbsd-x64" "0.27.2"
+ "@esbuild/openbsd-arm64" "0.27.2"
+ "@esbuild/openbsd-x64" "0.27.2"
+ "@esbuild/openharmony-arm64" "0.27.2"
+ "@esbuild/sunos-x64" "0.27.2"
+ "@esbuild/win32-arm64" "0.27.2"
+ "@esbuild/win32-ia32" "0.27.2"
+ "@esbuild/win32-x64" "0.27.2"
+
escalade@^3.1.1, escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
@@ -3801,9 +4071,9 @@ esprima@^4.0.0, esprima@^4.0.1:
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esquery@^1.4.2:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
- integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d"
+ integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==
dependencies:
estraverse "^5.1.0"
@@ -3945,9 +4215,9 @@ fast-levenshtein@^2.0.6:
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
fastq@^1.6.0:
- version "1.19.1"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5"
- integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.20.1.tgz#ca750a10dc925bc8b18839fd203e3ef4b3ced675"
+ integrity sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==
dependencies:
reusify "^1.0.4"
@@ -4033,23 +4303,15 @@ for-each@^0.3.3, for-each@^0.3.5:
dependencies:
is-callable "^1.2.7"
-foreground-child@^3.1.0:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f"
- integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==
- dependencies:
- cross-spawn "^7.0.6"
- signal-exit "^4.0.1"
-
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==
form-data@^4.0.0, form-data@^4.0.4, form-data@~4.0.4:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4"
- integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053"
+ integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
@@ -4095,7 +4357,12 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-fsevents@^2.3.2, fsevents@~2.3.2:
+fsevents@2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
+fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
@@ -4244,18 +4511,6 @@ glob@7.1.7:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^10.3.10:
- version "10.4.5"
- resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
- integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
- dependencies:
- foreground-child "^3.1.0"
- jackspeak "^3.1.2"
- minimatch "^9.0.4"
- minipass "^7.1.2"
- package-json-from-dist "^1.0.0"
- path-scurry "^1.11.1"
-
glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@@ -4385,10 +4640,10 @@ hasown@^2.0.2:
dependencies:
function-bind "^1.1.2"
-html-dom-parser@5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.1.1.tgz#9efb2cfa055f6a71de1bb2f07c5b019db5004f9e"
- integrity sha512-+o4Y4Z0CLuyemeccvGN4bAO20aauB2N9tFEAep5x4OW34kV4PTarBHm6RL02afYt2BMKcr0D2Agep8S3nJPIBg==
+html-dom-parser@5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.1.2.tgz#0fceac1b8e7d917de6e883991b7d71f0b3fd63b9"
+ integrity sha512-9nD3Rj3/FuQt83AgIa1Y3ruzspwFFA54AJbQnohXN+K6fL1/bhcDQJJY5Ne4L4A163ADQFVESd/0TLyNoV0mfg==
dependencies:
domhandler "5.0.3"
htmlparser2 "10.0.0"
@@ -4406,14 +4661,14 @@ html-escaper@^2.0.0:
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
html-react-parser@^5.2.2:
- version "5.2.8"
- resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.2.8.tgz#96bc08c669c8ffb1f24e1f256924eaa1de52e4b6"
- integrity sha512-09WaI81tbpwhXWeMe1m9VptZVJUcigo0l59zVt+2HUIQT7+baU38/oNhllj6MKhOuGXqh0nrlwOgxbxbm6xXHw==
+ version "5.2.11"
+ resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.2.11.tgz#7d36b16468e7b5400f183380a1e77a916ca3f465"
+ integrity sha512-WnSQVn/D1UTj64nSz5y8MriL+MrbsZH80Ytr1oqKqs8DGZnphWY1R1pl3t7TY3rpqTSu+FHA21P80lrsmrdNBA==
dependencies:
domhandler "5.0.3"
- html-dom-parser "5.1.1"
+ html-dom-parser "5.1.2"
react-property "2.0.2"
- style-to-js "1.1.19"
+ style-to-js "1.1.21"
htmlparser2@10.0.0:
version "10.0.0"
@@ -4532,10 +4787,10 @@ ini@2.0.0:
resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
-inline-style-parser@0.2.6:
- version "0.2.6"
- resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.6.tgz#e6bbb5288a635f6284a6249ce754da55c4bd1ff5"
- integrity sha512-gtGXVaBdl5mAes3rPcMedEBm12ibjt1kDMFfheul1wUAOVEJW60voNdMVzVkfLN06O7ZaD/rxhfKgtlgtTbMjg==
+inline-style-parser@0.2.7:
+ version "0.2.7"
+ resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.7.tgz#b1fc68bfc0313b8685745e4464e37f9376b9c909"
+ integrity sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==
internal-slot@^1.1.0:
version "1.1.0"
@@ -4884,7 +5139,7 @@ istanbul-reports@^3.1.3:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
-iterator.prototype@^1.1.4:
+iterator.prototype@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39"
integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==
@@ -4896,15 +5151,6 @@ iterator.prototype@^1.1.4:
has-symbols "^1.1.0"
set-function-name "^2.0.2"
-jackspeak@^3.1.2:
- version "3.4.3"
- resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
- integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
- dependencies:
- "@isaacs/cliui" "^8.0.2"
- optionalDependencies:
- "@pkgjs/parseargs" "^0.11.0"
-
jest-changed-files@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a"
@@ -5306,17 +5552,17 @@ jiti@^1.18.2:
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@^3.13.1:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
- integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+ version "3.14.2"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0"
+ integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
- integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b"
+ integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
dependencies:
argparse "^2.0.1"
@@ -5661,7 +5907,7 @@ loose-envify@^1.1.0, loose-envify@^1.4.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
-lru-cache@^10.2.0, lru-cache@^10.4.3:
+lru-cache@^10.4.3:
version "10.4.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
@@ -5760,7 +6006,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
-minimatch@^9.0.3, minimatch@^9.0.4:
+minimatch@^9.0.3:
version "9.0.5"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
@@ -5772,11 +6018,6 @@ minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
-"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
- integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
-
mkdirp@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50"
@@ -5946,11 +6187,11 @@ node-int64@^0.4.0:
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
node-mock-http@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.3.tgz#4e55e093267a3b910cded7354389ce2d02c89e77"
- integrity sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.4.tgz#21f2ab4ce2fe4fbe8a660d7c5195a1db85e042a4"
+ integrity sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==
-node-releases@^2.0.26:
+node-releases@^2.0.27:
version "2.0.27"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e"
integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==
@@ -5973,9 +6214,9 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1:
path-key "^3.0.0"
nwsapi@^2.2.2:
- version "2.2.22"
- resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.22.tgz#109f9530cda6c156d6a713cdf5939e9f0de98b9d"
- integrity sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==
+ version "2.2.23"
+ resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.23.tgz#59712c3a88e6de2bb0b6ccc1070397267019cf6c"
+ integrity sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==
object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
@@ -6056,7 +6297,7 @@ object.values@^1.1.6, object.values@^1.2.1:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
-ofetch@^1.5.0:
+ofetch@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.5.1.tgz#5c43cc56e03398b273014957060344254505c5c7"
integrity sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==
@@ -6169,11 +6410,6 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-package-json-from-dist@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
- integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
-
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -6223,14 +6459,6 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-path-scurry@^1.11.1:
- version "1.11.1"
- resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
- integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
- dependencies:
- lru-cache "^10.2.0"
- minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
-
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
@@ -6286,9 +6514,9 @@ pino-abstract-transport@^2.0.0:
split2 "^4.0.0"
pino-std-serializers@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b"
- integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz#a7b0cd65225f29e92540e7853bd73b07479893fc"
+ integrity sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==
pino@10.0.0:
version "10.0.0"
@@ -6324,6 +6552,20 @@ platform@1.3.6:
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
+playwright-core@1.57.0:
+ version "1.57.0"
+ resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.57.0.tgz#3dcc9a865af256fa9f0af0d67fc8dd54eecaebf5"
+ integrity sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==
+
+playwright@1.57.0:
+ version "1.57.0"
+ resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.57.0.tgz#74d1dacff5048dc40bf4676940b1901e18ad0f46"
+ integrity sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==
+ dependencies:
+ playwright-core "1.57.0"
+ optionalDependencies:
+ fsevents "2.3.2"
+
pngjs@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
@@ -6387,7 +6629,7 @@ postcss@8.4.31:
picocolors "^1.0.0"
source-map-js "^1.0.2"
-postcss@^8.4.23:
+postcss@^8.4.23, postcss@^8.5.6:
version "8.5.6"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c"
integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==
@@ -6523,13 +6765,6 @@ qrcode@>=1.5.4:
pngjs "^5.0.0"
yargs "^15.3.1"
-qs@6.10.3:
- version "6.10.3"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e"
- integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==
- dependencies:
- side-channel "^1.0.4"
-
qs@6.11.2:
version "6.11.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
@@ -6537,10 +6772,10 @@ qs@6.11.2:
dependencies:
side-channel "^1.0.4"
-qs@6.14.0:
- version "6.14.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
- integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
+qs@~6.14.1:
+ version "6.14.1"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.1.tgz#a41d85b9d3902f31d27861790506294881871159"
+ integrity sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==
dependencies:
side-channel "^1.1.0"
@@ -6785,6 +7020,40 @@ ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.3:
hash-base "^3.1.2"
inherits "^2.0.4"
+rollup@^4.43.0:
+ version "4.55.1"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.55.1.tgz#4ec182828be440648e7ee6520dc35e9f20e05144"
+ integrity sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==
+ dependencies:
+ "@types/estree" "1.0.8"
+ optionalDependencies:
+ "@rollup/rollup-android-arm-eabi" "4.55.1"
+ "@rollup/rollup-android-arm64" "4.55.1"
+ "@rollup/rollup-darwin-arm64" "4.55.1"
+ "@rollup/rollup-darwin-x64" "4.55.1"
+ "@rollup/rollup-freebsd-arm64" "4.55.1"
+ "@rollup/rollup-freebsd-x64" "4.55.1"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.55.1"
+ "@rollup/rollup-linux-arm-musleabihf" "4.55.1"
+ "@rollup/rollup-linux-arm64-gnu" "4.55.1"
+ "@rollup/rollup-linux-arm64-musl" "4.55.1"
+ "@rollup/rollup-linux-loong64-gnu" "4.55.1"
+ "@rollup/rollup-linux-loong64-musl" "4.55.1"
+ "@rollup/rollup-linux-ppc64-gnu" "4.55.1"
+ "@rollup/rollup-linux-ppc64-musl" "4.55.1"
+ "@rollup/rollup-linux-riscv64-gnu" "4.55.1"
+ "@rollup/rollup-linux-riscv64-musl" "4.55.1"
+ "@rollup/rollup-linux-s390x-gnu" "4.55.1"
+ "@rollup/rollup-linux-x64-gnu" "4.55.1"
+ "@rollup/rollup-linux-x64-musl" "4.55.1"
+ "@rollup/rollup-openbsd-x64" "4.55.1"
+ "@rollup/rollup-openharmony-arm64" "4.55.1"
+ "@rollup/rollup-win32-arm64-msvc" "4.55.1"
+ "@rollup/rollup-win32-ia32-msvc" "4.55.1"
+ "@rollup/rollup-win32-x64-gnu" "4.55.1"
+ "@rollup/rollup-win32-x64-msvc" "4.55.1"
+ fsevents "~2.3.2"
+
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@@ -6799,7 +7068,7 @@ rxjs@6:
dependencies:
tslib "^1.9.0"
-rxjs@^7.5.1, rxjs@^7.8.1:
+rxjs@7.8.2, rxjs@^7.5.1, rxjs@^7.8.1:
version "7.8.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b"
integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==
@@ -6985,11 +7254,6 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
-signal-exit@^4.0.1:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
- integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
-
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
@@ -7039,12 +7303,12 @@ socket.io-client@4.7.5:
socket.io-parser "~4.2.4"
socket.io-parser@~4.2.4:
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
- integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
+ version "4.2.5"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.5.tgz#3f41b8d369129a93268f2abecba94b5292850099"
+ integrity sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
- debug "~4.3.1"
+ debug "~4.4.1"
sonic-boom@^4.0.1:
version "4.2.0"
@@ -7137,15 +7401,6 @@ string-length@^5.0.1:
char-regex "^2.0.0"
strip-ansi "^7.0.1"
-"string-width-cjs@npm:string-width@^4.2.0":
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@@ -7155,15 +7410,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string-width@^5.0.1, string-width@^5.1.2:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
- integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
- dependencies:
- eastasianwidth "^0.2.0"
- emoji-regex "^9.2.2"
- strip-ansi "^7.0.1"
-
string.prototype.includes@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92"
@@ -7246,13 +7492,6 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
@@ -7287,19 +7526,19 @@ strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-style-to-js@1.1.19:
- version "1.1.19"
- resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.19.tgz#f3f671e74764c1e8eebfba95a9a672acf5c19011"
- integrity sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ==
+style-to-js@1.1.21:
+ version "1.1.21"
+ resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.21.tgz#2908941187f857e79e28e9cd78008b9a0b3e0e8d"
+ integrity sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==
dependencies:
- style-to-object "1.0.12"
+ style-to-object "1.0.14"
-style-to-object@1.0.12:
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.12.tgz#03a30e7f4e555bf50845f8b55c7d5bc2248e03f0"
- integrity sha512-ddJqYnoT4t97QvN2C95bCgt+m7AAgXjVnkk/jxAfmp7EAB8nnqqZYEbMd3em7/vEomDb2LAQKAy1RFfv41mdNw==
+style-to-object@1.0.14:
+ version "1.0.14"
+ resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.14.tgz#1d22f0e7266bb8c6d8cae5caf4ec4f005e08f611"
+ integrity sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==
dependencies:
- inline-style-parser "0.2.6"
+ inline-style-parser "0.2.7"
styled-jsx@5.1.1:
version "5.1.1"
@@ -7309,16 +7548,16 @@ styled-jsx@5.1.1:
client-only "0.0.1"
sucrase@^3.32.0:
- version "3.35.0"
- resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
- integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==
+ version "3.35.1"
+ resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.1.tgz#4619ea50393fe8bd0ae5071c26abd9b2e346bfe1"
+ integrity sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.2"
commander "^4.0.0"
- glob "^10.3.10"
lines-and-columns "^1.1.6"
mz "^2.7.0"
pirates "^4.0.1"
+ tinyglobby "^0.2.11"
ts-interface-checker "^0.1.9"
supports-color@^7.1.0:
@@ -7435,7 +7674,7 @@ through@^2.3.8:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
-tinyglobby@^0.2.13:
+tinyglobby@^0.2.11, tinyglobby@^0.2.13, tinyglobby@^0.2.15:
version "0.2.15"
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2"
integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==
@@ -7647,9 +7886,9 @@ typescript@5.2.2:
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
ufo@^1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b"
- integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.2.tgz#aaf4d46b98425b2fb5031abe8d65ca069e93e755"
+ integrity sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==
uint8arrays@3.1.1, uint8arrays@^3.0.0:
version "3.1.1"
@@ -7726,9 +7965,9 @@ unrs-resolver@^1.6.2:
"@unrs/resolver-binding-win32-x64-msvc" "1.11.1"
unstorage@^1.9.0:
- version "1.17.2"
- resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.17.2.tgz#543d06f24e5b2005b2e9c15ea4180782df987a11"
- integrity sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w==
+ version "1.17.3"
+ resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.17.3.tgz#805acbeab7f7b97f0d0492427af18e650eda4e57"
+ integrity sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==
dependencies:
anymatch "^3.1.3"
chokidar "^4.0.3"
@@ -7736,7 +7975,7 @@ unstorage@^1.9.0:
h3 "^1.15.4"
lru-cache "^10.4.3"
node-fetch-native "^1.6.7"
- ofetch "^1.5.0"
+ ofetch "^1.5.1"
ufo "^1.6.1"
untildify@^4.0.0:
@@ -7744,10 +7983,10 @@ untildify@^4.0.0:
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
-update-browserslist-db@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz#7802aa2ae91477f255b86e0e46dbc787a206ad4a"
- integrity sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==
+update-browserslist-db@^1.2.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d"
+ integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==
dependencies:
escalade "^3.2.0"
picocolors "^1.1.1"
@@ -7799,9 +8038,9 @@ v8-to-istanbul@^9.0.1:
convert-source-map "^2.0.0"
validator@^13.6.0:
- version "13.15.20"
- resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.20.tgz#054e9238109538a1bf46ae3e1290845a64fa2186"
- integrity sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==
+ version "13.15.26"
+ resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.26.tgz#36c3deeab30e97806a658728a155c66fcaa5b944"
+ integrity sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==
verror@1.10.0:
version "1.10.0"
@@ -7812,6 +8051,20 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
+vite@^7.2.4:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.1.tgz#7f6cfe8fb9074138605e822a75d9d30b814d6507"
+ integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==
+ dependencies:
+ esbuild "^0.27.0"
+ fdir "^6.5.0"
+ picomatch "^4.0.3"
+ postcss "^8.5.6"
+ rollup "^4.43.0"
+ tinyglobby "^0.2.15"
+ optionalDependencies:
+ fsevents "~2.3.3"
+
w3c-xmlserializer@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073"
@@ -7934,15 +8187,6 @@ word-wrap@^1.2.5:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
@@ -7961,15 +8205,6 @@ wrap-ansi@^7.0.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^8.1.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
- integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
- dependencies:
- ansi-styles "^6.1.0"
- string-width "^5.0.1"
- strip-ansi "^7.0.1"
-
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -7989,9 +8224,9 @@ ws@^7.5.1:
integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
ws@^8.11.0:
- version "8.18.3"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472"
- integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==
+ version "8.19.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b"
+ integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==
ws@~8.17.1:
version "8.17.1"
@@ -8029,9 +8264,9 @@ yallist@^3.0.2:
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
yaml@^2.3.4:
- version "2.8.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79"
- integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==
+ version "2.8.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.2.tgz#5694f25eca0ce9c3e7a9d9e00ce0ddabbd9e35c5"
+ integrity sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==
yargs-parser@^18.1.2:
version "18.1.3"