diff --git a/.gitignore b/.gitignore index 244d380..ff0ff6d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ node_modules .cache *.log .DS_Store +**/.DS_Store # builds build @@ -18,7 +19,6 @@ out .husky # misc -.DS_Store .env .env.local .env.development.local @@ -29,5 +29,5 @@ out npm-debug.log* yarn-debug.log* yarn-error.log* - +.yarnrc coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index 2914113..5192a0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [[0.0.0-alpha.10](https://github.com/multiversx/mx-sdk-dapp-core/pull/56)] - 2024-12-23 + +- [Added transactions interpretation helpers](https://github.com/multiversx/mx-sdk-dapp-core/pull/55) +- [Added transaction toasts](https://github.com/multiversx/mx-sdk-dapp-core/pull/53) +- [Added transactions helpers](https://github.com/multiversx/mx-sdk-dapp-core/pull/52) +- [Added transactions tracking](https://github.com/multiversx/mx-sdk-dapp-core/pull/51) +- [Added provider constants and getTransactions API call](https://github.com/multiversx/mx-sdk-dapp-core/pull/50) +- [Added pending transactions](https://github.com/multiversx/mx-sdk-dapp-core/pull/48) +- [Added transaction manager](https://github.com/multiversx/mx-sdk-dapp-core/pull/41) +- [Added custom web socket url support](https://github.com/multiversx/mx-sdk-dapp-core/pull/35) +- [Metamask integration](https://github.com/multiversx/mx-sdk-dapp-core/pull/27) +- [Extension integration](https://github.com/multiversx/mx-sdk-dapp-core/pull/26) +- [Ledger integration](https://github.com/multiversx/mx-sdk-dapp-core/pull/22) +- [Added sign, send, & track transactions with websocket connection](https://github.com/multiversx/mx-sdk-dapp-core/pull/21) +- [Added restore provider after page reload](https://github.com/multiversx/mx-sdk-dapp-core/pull/19) +- [Added signMessage](https://github.com/multiversx/mx-sdk-dapp-core/pull/18) + ## [[0.0.0-alpha.9]](https://github.com/multiversx/mx-sdk-dapp-core)] - 2024-08-29 + - [CrossWindow login](https://github.com/multiversx/mx-sdk-dapp-core/pull/13) + ## [[v0.0.0-alpha.8]](https://github.com/multiversx/mx-sdk-dapp-core/pull/16) - 2024-08-27 + - [Added sdk-web-wallet-cross-window-provider as peer dependency](https://github.com/multiversx/mx-sdk-dapp-core/pull/14) - [Generic login + ExtensionProvider login](https://github.com/multiversx/mx-sdk-dapp-core/pull/12) - [Make middlewares registration more scalable](https://github.com/multiversx/mx-sdk-dapp-core/pull/11) diff --git a/README.md b/README.md index 0efd702..7186d8d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,41 @@ ## Usage +In your project, make sure to use the `preserveSymlinks` option in the server configuration to ensure that the symlinks are preserved, for ease of development. + +``` js + resolve: { + preserveSymlinks: true, // 👈 + alias: { + src: "/src", + }, + }, ``` // TODO: DEMONSTRATE API + + +```mermaid +flowchart TB; + id1{index.tsx} + + -- sdk-dpp-core config --> + + F( + persistance + network + custom providers + ) + + -- await config --> + + id2{/unlock} + + -- user presses login --> + + Provider.login + + -- redirect --> + + /dashboard ``` diff --git a/eslint.config.js b/eslint.config.mjs similarity index 58% rename from eslint.config.js rename to eslint.config.mjs index ddd388d..b3bd4b6 100644 --- a/eslint.config.js +++ b/eslint.config.mjs @@ -1,17 +1,35 @@ -[ +import globals from 'globals'; +import pluginJs from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import importPlugin from 'eslint-plugin-import'; +import prettierPlugin from 'eslint-plugin-prettier'; +import jestPlugin from 'eslint-plugin-jest'; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ { - env: { - es2021: true, - node: true - }, - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 2021, - sourceType: 'module', - ecmaFeatures: { - jsx: true + files: ['**/*.{js,mjs,cjs,ts,tsx}', '**/*.{test,spec}.{js,ts,tsx}'], + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + ...globals.jest }, - project: './tsconfig.json' + parser: tseslint.parser, + parserOptions: { + ecmaVersion: 2021, + sourceType: 'module', + ecmaFeatures: { + jsx: true + }, + project: './tsconfig.json' + } + }, + plugins: { + import: importPlugin, + prettier: prettierPlugin, + jest: jestPlugin, + '@typescript-eslint': tseslint.plugin }, settings: { 'import/parsers': { @@ -27,13 +45,10 @@ } } }, - extends: [ - 'plugin:@typescript-eslint/recommended', - 'prettier', - 'plugin:prettier/recommended' - ], - plugins: ['prettier', 'import'], rules: { + ...jestPlugin.configs.recommended.rules, + ...pluginJs.configs.recommended.rules, + ...tseslint.configs.recommended.rules, 'import/order': [ 'warn', { @@ -52,12 +67,7 @@ } } ], - 'prettier/prettier': [ - 'error', - { - endOfLine: 'lf' - } - ], + 'prettier/prettier': ['error', { endOfLine: 'lf' }], '@typescript-eslint/indent': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-use-before-define': [ @@ -68,13 +78,20 @@ '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-unused-vars': [ 'error', - { argsIgnorePattern: '^_' } + { + argsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_' + } ], '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/explicit-function-return-type': 'off', 'linebreak-style': ['error', 'unix'], quotes: ['error', 'single'], semi: ['error', 'always'], + 'no-unused-vars': ['off'], + 'no-prototype-builtins': 'off', + 'jest/no-mocks-import': 'off', + 'no-async-promise-executor': 'off', 'object-curly-newline': 'off', 'arrow-body-style': 'off', 'implicit-arrow-linebreak': 'off', diff --git a/package.json b/package.json index 35afdd1..565fc0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@multiversx/sdk-dapp-core", - "version": "0.0.0-alpha.9", + "version": "0.0.0-alpha.10", "main": "out/index.js", "module": "out/index.js", "types": "out/index.d.ts", @@ -19,11 +19,13 @@ "url": "git+https://github.com/multiversx/mx-sdk-dapp-core.git" }, "scripts": { + "unpublish-verdaccio": "npm unpublish @multiversx/sdk-dapp-core --force --registry http://localhost:4873", + "publish-verdaccio": "npm run unpublish-verdaccio && npm run compile-next && npm publish --registry http://localhost:4873/", "compile": "tsc && tsc-alias", "build-esbuild": "rimraf out && node esbuild.js", - "publish-verdaccio": "npm unpublish --registry http://localhost:4873 @multiversx/sdk-dapp-core@0.0.0-alpha.3 && rimraf out && yarn compile && npm publish --registry http://localhost:4873", "build": "yarn build-esbuild && yarn compile", "test": "jest", + "lint": "eslint --fix src", "compile-next": "rimraf out && tsc --p tsconfig.next.json && tsc-alias --project tsconfig.next.json" }, "publishConfig": { @@ -31,62 +33,73 @@ }, "dependencies": { "@lifeomic/axios-fetch": "3.0.1", - "@multiversx/sdk-extension-provider": "3.0.0", - "@multiversx/sdk-hw-provider": "6.4.0", - "@multiversx/sdk-metamask-provider": "0.0.5", + "@multiversx/sdk-core": ">= 13.5.0", + "@multiversx/sdk-dapp-utils": ">= 1.0.2", + "@multiversx/sdk-extension-provider": "4.0.0", + "@multiversx/sdk-hw-provider": "7.0.0", + "@multiversx/sdk-metamask-provider": "1.0.0", "@multiversx/sdk-native-auth-client": "^1.0.8", "@multiversx/sdk-opera-provider": "1.0.0-alpha.1", - "@multiversx/sdk-wallet-connect-provider": "4.1.2", + "@multiversx/sdk-wallet": "4.5.1", + "@multiversx/sdk-wallet-connect-provider": "5.0.1", + "@multiversx/sdk-web-wallet-cross-window-provider": ">= 2.0.4", + "@multiversx/sdk-web-wallet-iframe-provider": "2.0.1", "@multiversx/sdk-web-wallet-provider": "3.2.1", - "@types/lodash": "^4.17.4", - "isomorphic-fetch": "^3.0.0", - "lodash": "^4.17.21", - "zustand": "^4.4.7" + "isomorphic-fetch": "3.0.0", + "lodash": "4.17.21", + "protobufjs": "7.3.0", + "socket.io-client": "4.7.5", + "zustand": "4.4.7" }, "peerDependencies": { - "@multiversx/sdk-core": ">= 13.0.0", - "@multiversx/sdk-dapp-utils": ">= 0.1.0", - "@multiversx/sdk-web-wallet-cross-window-provider": ">= 1.0.0", + "@multiversx/sdk-core": ">= 13.5.0", + "@multiversx/sdk-dapp-utils": ">= 1.0.2", + "@multiversx/sdk-web-wallet-cross-window-provider": ">= 2.0.4", "axios": ">=1.6.5", - "bignumber.js": "9.x" + "bignumber.js": "9.x", + "immer": "10.x" + }, + "optionalDependencies": { + "@multiversx/sdk-dapp-core-ui": "0.0.0-alpha.0" }, "resolutions": { "string-width": "4.1.0" }, "devDependencies": { - "@multiversx/sdk-core": ">= 13.0.0", - "@multiversx/sdk-dapp-utils": ">= 0.1.0", - "@multiversx/sdk-web-wallet-cross-window-provider": ">= 1.0.0", + "@eslint/js": "9.15.0", "@swc/core": "^1.4.17", "@swc/jest": "^0.2.36", + "@types/jest": "29.5.13", + "@types/lodash": "4.17.4", "@types/node": "20.12.8", - "@typescript-eslint/eslint-plugin": "7.8.0", - "@typescript-eslint/parser": "7.8.0", + "@typescript-eslint/eslint-plugin": "8.15.0", + "@typescript-eslint/parser": "8.15.0", "axios": ">=1.6.5", - "axios-mock-adapter": "^1.22.0", + "axios-mock-adapter": "1.22.0", "bignumber.js": "9.x", - "esbuild": "^0.21.1", + "esbuild": "0.21.1", "esbuild-node-externals": "1.14.0", - "eslint": "9.1.1", + "eslint": "9.15.0", "eslint-config-prettier": "9.1.0", "eslint-config-standard": "17.1.0", - "eslint-import-resolver-typescript": "3.6.1", - "eslint-plugin-import": "2.29.1", + "eslint-import-resolver-typescript": "3.6.3", + "eslint-plugin-import": "2.31.0", + "eslint-plugin-jest": "28.9.0", "eslint-plugin-node": "11.1.0", - "eslint-plugin-prettier": "5.1.3", - "eslint-plugin-promise": "6.1.1", - "glob": "^10.3.14", + "eslint-plugin-prettier": "5.2.1", + "eslint-plugin-promise": "7.1.0", + "glob": "10.3.14", "immer": "^10.1.1", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "msw": "1.3.1", "node-stdlib-browser": "1.2.0", "prettier": "3.2.5", - "protobufjs": "^7.3.0", "react": "^18.3.1", "rimraf": "^5.0.6", "ts-jest": "29.1.2", "tsc-alias": "^1.8.9", - "typescript": "^5.4.5" + "typescript": "5.4.5", + "typescript-eslint": "8.15.0" } } diff --git a/src/__mocks__/utils/mockWindowHistory.ts b/src/__mocks__/utils/mockWindowHistory.ts index 71b0e74..b1baa73 100644 --- a/src/__mocks__/utils/mockWindowHistory.ts +++ b/src/__mocks__/utils/mockWindowHistory.ts @@ -5,11 +5,9 @@ export const mockWindowHistory = () => { const history = window.history; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore delete window.history; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.history = Object.defineProperties( {}, diff --git a/src/__mocks__/utils/mockWindowLocation.ts b/src/__mocks__/utils/mockWindowLocation.ts index 765ea51..5fbc666 100644 --- a/src/__mocks__/utils/mockWindowLocation.ts +++ b/src/__mocks__/utils/mockWindowLocation.ts @@ -5,11 +5,9 @@ export const mockWindowLocation = () => { const location = window.location; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore delete window.location; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.location = Object.defineProperties( {}, diff --git a/src/apiCalls/accounts/getAccountFromApi.ts b/src/apiCalls/account/getAccountFromApi.ts similarity index 87% rename from src/apiCalls/accounts/getAccountFromApi.ts rename to src/apiCalls/account/getAccountFromApi.ts index 001403f..e4b687c 100644 --- a/src/apiCalls/accounts/getAccountFromApi.ts +++ b/src/apiCalls/account/getAccountFromApi.ts @@ -1,6 +1,7 @@ import { ACCOUNTS_ENDPOINT } from 'apiCalls/endpoints'; import { axiosInstance } from 'apiCalls/utils/axiosInstance'; import { getCleanApiAddress } from 'apiCalls/utils/getCleanApiAddress'; +import { TIMEOUT } from 'constants/network.constants'; import { AccountType } from 'types/account.types'; export const accountFetcher = (address: string | null) => { @@ -8,7 +9,8 @@ export const accountFetcher = (address: string | null) => { const url = `${apiAddress}/${ACCOUNTS_ENDPOINT}/${address}?withGuardianInfo=true`; // we need to get it with an axios instance because of cross-window user interaction issues return axiosInstance.get(url, { - baseURL: apiAddress + baseURL: apiAddress, + timeout: TIMEOUT }); }; @@ -20,7 +22,7 @@ export const getAccountFromApi = async (address?: string) => { try { const { data } = await accountFetcher(address); return data as AccountType; - } catch (err) { + } catch (_err) { console.error('error fetching configuration for ', address); } diff --git a/src/apiCalls/account/getScamAddressData.ts b/src/apiCalls/account/getScamAddressData.ts new file mode 100644 index 0000000..ee1a55e --- /dev/null +++ b/src/apiCalls/account/getScamAddressData.ts @@ -0,0 +1,18 @@ +import axios from 'axios'; +import { getCleanApiAddress } from 'apiCalls/utils'; +import { TIMEOUT } from 'constants/index'; +import { ScamInfoType } from 'types/account.types'; +import { ACCOUNTS_ENDPOINT } from '../endpoints'; + +export async function getScamAddressData(addressToVerify: string) { + const apiAddress = getCleanApiAddress(); + + const { data } = await axios.get<{ + scamInfo?: ScamInfoType; + code?: string; + }>(`${apiAddress}/${ACCOUNTS_ENDPOINT}/${addressToVerify}`, { + timeout: TIMEOUT + }); + + return data; +} diff --git a/src/apiCalls/accounts/index.ts b/src/apiCalls/account/index.ts similarity index 100% rename from src/apiCalls/accounts/index.ts rename to src/apiCalls/account/index.ts diff --git a/src/apiCalls/configuration/getNetworkConfigFromApi.ts b/src/apiCalls/configuration/getNetworkConfigFromApi.ts index 85b831f..627a6b6 100644 --- a/src/apiCalls/configuration/getNetworkConfigFromApi.ts +++ b/src/apiCalls/configuration/getNetworkConfigFromApi.ts @@ -27,7 +27,7 @@ export async function getNetworkConfigFromApi() { if (data != null) { return data?.data?.config; } - } catch (err) { + } catch (_err) { console.error('error fetching configuration for ', configUrl); } return null; diff --git a/src/apiCalls/configuration/getServerConfiguration.ts b/src/apiCalls/configuration/getServerConfiguration.ts index a1cfc6a..6e2ccdd 100644 --- a/src/apiCalls/configuration/getServerConfiguration.ts +++ b/src/apiCalls/configuration/getServerConfiguration.ts @@ -7,8 +7,27 @@ export async function getServerConfiguration(apiAddress: string) { try { const { data } = await axios.get(configUrl); - return data; - } catch (err) { + if (data != null) { + // TODO: egldDenomination will be removed from API when dapp-core v1 will be discontinued + const egldDenomination = 'egldDenomination'; + if (egldDenomination in data) { + const { + [egldDenomination]: decimals, + decimals: digits, + ...rest + } = data as NetworkType & { + [egldDenomination]: string; + }; + const networkConfig: NetworkType = { + ...rest, + decimals, + digits + }; + return networkConfig; + } + return data; + } + } catch (_err) { console.error('error fetching configuration for ', configUrl); } return null; diff --git a/src/apiCalls/economics/getEconomics.ts b/src/apiCalls/economics/getEconomics.ts new file mode 100644 index 0000000..f977aeb --- /dev/null +++ b/src/apiCalls/economics/getEconomics.ts @@ -0,0 +1,25 @@ +import axios from 'axios'; +import { ECONOMICS_ENDPOINT } from 'apiCalls/endpoints'; +import { getCleanApiAddress } from 'apiCalls/utils/getCleanApiAddress'; + +export interface EconomicsInfoType { + totalSupply: number; + circulatingSupply: number; + staked: number; + price: number; + marketCap: number; + apr: number; + topUpApr: number; +} + +export async function getEconomics(url = ECONOMICS_ENDPOINT) { + const apiAddress = getCleanApiAddress(); + const configUrl = `${apiAddress}/${url}`; + try { + const { data } = await axios.get(configUrl); + return data; + } catch (err) { + console.error('err fetching economics info', err); + return null; + } +} diff --git a/src/apiCalls/index.ts b/src/apiCalls/index.ts index 28f2150..12953a4 100644 --- a/src/apiCalls/index.ts +++ b/src/apiCalls/index.ts @@ -1,2 +1,6 @@ +export * from './account'; export * from './configuration'; export * from './endpoints'; +export * from './tokens'; +export * from './utils'; +export * from './websocket'; diff --git a/src/apiCalls/tokens/getPersistedToken.ts b/src/apiCalls/tokens/getPersistedToken.ts new file mode 100644 index 0000000..952a11f --- /dev/null +++ b/src/apiCalls/tokens/getPersistedToken.ts @@ -0,0 +1,25 @@ +import { getCleanApiAddress } from 'apiCalls/utils'; +import { axiosInstance } from 'apiCalls/utils/axiosInstance'; +import { TIMEOUT } from 'constants/network.constants'; +import { tokenDataStorage } from './tokenDataStorage'; + +export async function getPersistedToken(url: string): Promise { + const apiAddress = getCleanApiAddress(); + + const config = { + baseURL: apiAddress, + timeout: TIMEOUT + }; + + const cachedToken: T | null = await tokenDataStorage.getItem(url); + + if (cachedToken) { + return cachedToken; + } + + const response = await axiosInstance.get(url, config); + + await tokenDataStorage.setItem(url, response.data); + + return response.data; +} diff --git a/src/apiCalls/tokens/getPersistedTokenDetails.ts b/src/apiCalls/tokens/getPersistedTokenDetails.ts new file mode 100644 index 0000000..21e59c6 --- /dev/null +++ b/src/apiCalls/tokens/getPersistedTokenDetails.ts @@ -0,0 +1,104 @@ +import { NFTS_ENDPOINT, TOKENS_ENDPOINT } from 'apiCalls/endpoints'; +import { getPersistedToken } from 'apiCalls/tokens/getPersistedToken'; +import { networkSelector } from 'store/selectors/networkSelectors'; +import { getState } from 'store/store'; + +import { NftEnumType } from 'types/tokens.types'; +import { getIdentifierType } from 'utils/validation/getIdentifierType'; + +export interface TokenAssets { + description: string; + status: string; + svgUrl: string; + website?: string; + pngUrl?: string; + social?: any; + extraTokens?: string[]; + lockedAccounts?: { [key: string]: string }; +} + +export interface TokenMediaType { + url?: string; + originalUrl?: string; + thumbnailUrl?: string; + fileType?: string; + fileSize?: number; +} + +export interface TokenOptionType { + tokenLabel: string; + tokenDecimals: number; + tokenImageUrl: string; + assets?: TokenAssets; + type?: NftEnumType; + error?: string; + esdtPrice?: number; + ticker?: string; + identifier?: string; + name?: string; +} + +interface TokenInfoResponse { + identifier: string; + name: string; + ticker: string; + decimals: number; + type?: NftEnumType; + assets: TokenAssets; + media?: TokenMediaType[]; + price: number; +} + +export async function getPersistedTokenDetails({ + tokenId +}: { + tokenId?: string; +}): Promise { + const network = networkSelector(getState()); + + const noData = { + tokenDecimals: Number(network.decimals), + tokenLabel: '', + tokenImageUrl: '' + }; + + const { isNft } = getIdentifierType(tokenId); + + const tokenIdentifier = tokenId; + const tokenEndpoint = isNft ? NFTS_ENDPOINT : TOKENS_ENDPOINT; + + if (!tokenIdentifier) { + return noData; + } + + try { + const selectedToken = await getPersistedToken( + `${network.apiAddress}/${tokenEndpoint}/${tokenIdentifier}` + ); + + const tokenDecimals = selectedToken + ? selectedToken?.decimals + : Number(network.decimals); + const tokenLabel = selectedToken ? selectedToken?.name : ''; + const tokenImageUrl = selectedToken + ? selectedToken?.assets?.svgUrl ?? selectedToken?.media?.[0]?.thumbnailUrl + : ''; + + return { + tokenDecimals: tokenDecimals, + tokenLabel, + type: selectedToken?.type, + tokenImageUrl, + identifier: selectedToken?.identifier, + assets: selectedToken?.assets, + esdtPrice: selectedToken?.price, + ticker: selectedToken?.ticker, + name: selectedToken?.name + }; + } catch (error) { + return { + ...noData, + error: `${error}` + }; + } +} diff --git a/src/apiCalls/tokens/getTokenDetails.ts b/src/apiCalls/tokens/getTokenDetails.ts new file mode 100644 index 0000000..1d3b603 --- /dev/null +++ b/src/apiCalls/tokens/getTokenDetails.ts @@ -0,0 +1,60 @@ +import { NFTS_ENDPOINT, TOKENS_ENDPOINT } from 'apiCalls/endpoints'; +import { axiosInstance } from 'apiCalls/utils/axiosInstance'; +import { networkSelector } from 'store/selectors'; +import { getState } from 'store/store'; +import { TokenOptionType, TokenInfoResponse } from 'types/tokens.types'; +import { getIdentifierType } from 'utils/validation/getIdentifierType'; + +export async function getTokenDetails({ + tokenId +}: { + tokenId: string; +}): Promise { + const network = networkSelector(getState()); + const { isNft } = getIdentifierType(tokenId); + + const tokenIdentifier = tokenId; + const tokenEndpoint = isNft ? NFTS_ENDPOINT : TOKENS_ENDPOINT; + + if (!tokenIdentifier) { + return { + tokenDecimals: Number(network.decimals), + tokenLabel: '', + tokenAvatar: '' + }; + } + + try { + const { data: selectedToken } = await axiosInstance.get( + `${network.apiAddress}/${tokenEndpoint}/${tokenIdentifier}` + ); + + const tokenDecimals = selectedToken + ? selectedToken?.decimals + : Number(network.decimals); + const tokenLabel = selectedToken ? selectedToken?.name : ''; + const tokenAvatar = selectedToken + ? selectedToken?.assets?.svgUrl ?? selectedToken?.media?.[0]?.thumbnailUrl + : ''; + + return { + tokenDecimals: tokenDecimals, + tokenLabel, + type: selectedToken?.type, + tokenAvatar, + identifier: selectedToken?.identifier, + assets: selectedToken?.assets, + esdtPrice: selectedToken?.price, + ticker: selectedToken?.ticker, + name: selectedToken?.name + }; + } catch (error: any) { + return { + error: `Error fetching token ${tokenIdentifier}: ${error.toString()}`, + tokenDecimals: Number(network.decimals), + tokenLabel: '', + tokenAvatar: '', + identifier: tokenIdentifier + }; + } +} diff --git a/src/apiCalls/tokens/index.ts b/src/apiCalls/tokens/index.ts new file mode 100644 index 0000000..671c5a3 --- /dev/null +++ b/src/apiCalls/tokens/index.ts @@ -0,0 +1 @@ +export * from './getTokenDetails'; diff --git a/src/apiCalls/tokens/tokenDataStorage.ts b/src/apiCalls/tokens/tokenDataStorage.ts new file mode 100644 index 0000000..e30a7d9 --- /dev/null +++ b/src/apiCalls/tokens/tokenDataStorage.ts @@ -0,0 +1,33 @@ +let memoryCache: Record = {}; + +export let tokenDataStorage = { + setItem: async (key: string, tokenData: T) => { + try { + memoryCache[key] = JSON.stringify(tokenData); + } catch (e) { + console.error('tokenDataStorage unable to serialize', e); + } + }, + getItem: async (key: string) => { + if (!memoryCache[key]) { + return null; + } + try { + return JSON.parse(memoryCache[key]); + } catch (e) { + console.error('tokenDataStorage unable to parse', e); + } + }, + clear: async () => { + memoryCache = {}; + }, + removeItem: async (key: string) => { + delete memoryCache[key]; + } +}; + +export const setTokenDataStorage = ( + tokenDataCacheStorage: typeof tokenDataStorage +) => { + tokenDataStorage = tokenDataCacheStorage; +}; diff --git a/src/apiCalls/transactions/getTransactionByHash.ts b/src/apiCalls/transactions/getTransactionByHash.ts new file mode 100644 index 0000000..98a514c --- /dev/null +++ b/src/apiCalls/transactions/getTransactionByHash.ts @@ -0,0 +1,16 @@ +import axios from 'axios'; +import { TRANSACTIONS_ENDPOINT } from 'apiCalls/endpoints'; +import { networkSelector } from 'store/selectors'; +import { getState } from 'store/store'; +import { ServerTransactionType } from 'types/serverTransactions.types'; + +export const getTransactionByHash = (hash: string) => { + const { apiAddress } = networkSelector(getState()); + + return axios.get( + `${apiAddress}/${TRANSACTIONS_ENDPOINT}/${hash}`, + { + timeout: 10000 // 10sec + } + ); +}; diff --git a/src/apiCalls/transactions/getTransactions.ts b/src/apiCalls/transactions/getTransactions.ts new file mode 100644 index 0000000..913b631 --- /dev/null +++ b/src/apiCalls/transactions/getTransactions.ts @@ -0,0 +1,63 @@ +import axios from 'axios'; +import { TRANSACTIONS_ENDPOINT } from 'apiCalls/endpoints'; +import { TransactionServerStatusesEnum } from 'types/enums.types'; +import { ServerTransactionType } from 'types/serverTransactions.types'; + +export interface GetTransactionsType { + apiAddress: string; + apiTimeout?: string | number; + sender?: string; + receiver?: string; + page?: number; + transactionSize?: number; + after?: number; + condition?: 'should' | 'must'; + before?: number; + withScResults?: boolean; + withUsername?: boolean; + status?: TransactionServerStatusesEnum; + /** + * Search in data object + */ + search?: string; +} + +export const getTransactions = ({ + apiAddress, + apiTimeout, + sender, + receiver, + page = 1, + transactionSize = 15, + condition = 'should', + withScResults = true, + after, + before, + search, + status, + withUsername +}: GetTransactionsType) => { + const params = { + sender, + receiver, + condition, + after, + before, + search, + from: (page - 1) * transactionSize, + ...(transactionSize > 0 ? { size: transactionSize } : {}), + withScResults, + withUsername, + status + }; + + const timeout = apiTimeout ? { timeout: parseInt(String(apiTimeout)) } : {}; + + return axios.get( + `${apiAddress}/${TRANSACTIONS_ENDPOINT}`, + { + params, + ...timeout + } + ); +}; diff --git a/src/apiCalls/transactions/getTransactionsByHashes.ts b/src/apiCalls/transactions/getTransactionsByHashes.ts new file mode 100644 index 0000000..0b0fa0d --- /dev/null +++ b/src/apiCalls/transactions/getTransactionsByHashes.ts @@ -0,0 +1,53 @@ +import axios from 'axios'; +import { TRANSACTIONS_ENDPOINT } from 'apiCalls/endpoints'; + +import { networkSelector } from 'store/selectors'; +import { getState } from 'store/store'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; +import { ServerTransactionType } from 'types/serverTransactions.types'; +import { + GetTransactionsByHashesReturnType, + PendingTransactionsType +} from 'types/transactions.types'; + +export const getTransactionsByHashes = async ( + pendingTransactions: PendingTransactionsType +): Promise => { + const { apiAddress } = networkSelector(getState()); + const hashes = pendingTransactions.map((tx) => tx.hash); + + const { data: responseData } = await axios.get( + `${apiAddress}/${TRANSACTIONS_ENDPOINT}`, + { + params: { + hashes: hashes.join(','), + withScResults: true + } + } + ); + + return pendingTransactions.map(({ hash, previousStatus }) => { + const txOnNetwork = responseData.find( + (txResponse: ServerTransactionType) => txResponse?.txHash === hash + ); + + return { + hash, + data: txOnNetwork?.data ?? '', + invalidTransaction: txOnNetwork == null, + status: txOnNetwork?.status as + | TransactionServerStatusesEnum + | TransactionBatchStatusesEnum, + results: txOnNetwork?.results ?? [], + sender: txOnNetwork?.sender ?? '', + receiver: txOnNetwork?.receiver ?? '', + previousStatus, + hasStatusChanged: Boolean( + txOnNetwork && txOnNetwork.status !== previousStatus + ) + }; + }); +}; diff --git a/src/apiCalls/utils/getScamAddressData.ts b/src/apiCalls/utils/getScamAddressData.ts index 8e1779b..ceef614 100644 --- a/src/apiCalls/utils/getScamAddressData.ts +++ b/src/apiCalls/utils/getScamAddressData.ts @@ -1,8 +1,8 @@ import axios from 'axios'; -import { ScamInfoType } from 'types/account.types'; -import { ACCOUNTS_ENDPOINT } from '../endpoints'; import { networkSelector } from 'store/selectors'; import { getState } from 'store/store'; +import { ScamInfoType } from 'types/account.types'; +import { ACCOUNTS_ENDPOINT } from '../endpoints'; export async function getScamAddressData(addressToVerify: string) { const { apiAddress, apiTimeout } = networkSelector(getState()); diff --git a/src/apiCalls/websocket/getWebsocketUrl.ts b/src/apiCalls/websocket/getWebsocketUrl.ts new file mode 100644 index 0000000..58bb9bc --- /dev/null +++ b/src/apiCalls/websocket/getWebsocketUrl.ts @@ -0,0 +1,13 @@ +import axios from 'axios'; + +export async function getWebsocketUrl(apiAddress: string) { + try { + const { data } = await axios.get<{ url: string }>( + `${apiAddress}/websocket/config` + ); + return `wss://${data.url}`; + } catch (err) { + console.error(err); + throw new Error('Can not get websocket url'); + } +} diff --git a/src/apiCalls/websocket/index.ts b/src/apiCalls/websocket/index.ts new file mode 100644 index 0000000..a1842b1 --- /dev/null +++ b/src/apiCalls/websocket/index.ts @@ -0,0 +1 @@ +export * from './getWebsocketUrl'; diff --git a/src/constants/index.ts b/src/constants/index.ts index 9ebad72..9f201b0 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,7 +1,9 @@ +export * from './browser.constants'; +export * from './errorMessages.constants'; +export * from './ledger.constants'; +export * from './mvx.constants'; export * from './network.constants'; export * from './placeholders.constants'; export * from './storage.constants'; +export * from './webWalletProvider.constants'; export * from './window.constants'; -export * from './browser.constants'; -export * from './errorMessages.constants'; -export * from './ledger.constants'; diff --git a/src/constants/ledger.constants.ts b/src/constants/ledger.constants.ts index 7941247..aba5076 100644 --- a/src/constants/ledger.constants.ts +++ b/src/constants/ledger.constants.ts @@ -1 +1,94 @@ -export const LEDGER_CONTRACT_DATA_ENABLED_VALUE = 1; +export const LEDGER_MULTI_ACCOUNT_MINIMUM_VERSION = '1.0.8'; +export const LEDGER_HASH_SIGN_MINIMUM_VERSION = '1.0.11'; +export const LEDGER_SIGN_AUTH_TOKEN_MINIMUM_VERSION = '1.0.15'; +export const LEDGER_WITH_WHITELISTED_TOKENS_MINIMUM_VERSION = '1.0.17'; +export const LEDGER_WITH_GUARDIANS_MINIMUM_VERSION = '1.0.22'; +export const LEDGER_WITH_USERNAMES_MINIMUM_VERSION = '1.0.23'; + +export const ledgerErrorCodes = { + 0x9000: { + code: 'codeSuccess', + message: 'Success' + }, + 0x6985: { + code: 'ERR_USER_DENIED', + message: 'Rejected by user' + }, + 0x6d00: { + code: 'ERR_UNKNOWN_INSTRUCTION', + message: 'Unknown instruction' + }, + 0x6e00: { + code: 'ERR_WRONG_CLA', + message: 'Wrong CLA' + }, + 0x6e01: { + code: 'ERR_INVALID_ARGUMENTS', + message: 'Invalid arguments' + }, + 0x6e02: { + code: 'ERR_INVALID_MESSAGE', + message: 'Invalid message' + }, + 0x6e03: { + code: 'ERR_INVALID_P1', + message: 'Invalid P1' + }, + 0x6e04: { + code: 'ERR_MESSAGE_TOO_LONG', + message: 'Message too long' + }, + 0x6e05: { + code: 'ERR_RECEIVER_TOO_LONG', + message: 'Receiver too long' + }, + 0x6e06: { + code: 'ERR_AMOUNT_TOO_LONG', + message: 'Amount too long' + }, + 0x6e07: { + code: 'ERR_CONTRACT_DATA_DISABLED', + message: 'Contract data disabled in app options' + }, + 0x6e08: { + code: 'ERR_MESSAGE_INCOMPLETE', + message: 'Message incomplete' + }, + 0x6e10: { + code: 'ERR_SIGNATURE_FAILED', + message: 'Signature failed' + }, + 0x6e09: { + code: 'ERR_WRONG_TX_VERSION', + message: 'Wrong TX version' + }, + 0x6e0a: { + code: 'ERR_NONCE_TOO_LONG', + message: 'Nonce too long' + }, + 0x6e0b: { + code: 'ERR_INVALID_AMOUNT', + message: 'Invalid amount' + }, + 0x6e0c: { + code: 'ERR_INVALID_FEE', + message: 'Invalid fee' + }, + 0x6e0d: { + code: 'ERR_PRETTY_FAILED', + message: 'Pretty failed' + }, + 0x6e0e: { + code: 'ERR_DATA_TOO_LONG', + message: 'Data too long' + }, + 0x6e0f: { + code: 'ERR_WRONG_TX_OPTIONS', + message: 'Invalid transaction options' + }, + 0x6e11: { + code: 'ERR_SIGN_TX_DEPRECATED', + message: + 'Regular transaction signing is deprecated in this version. Use hash signing.' + } +}; diff --git a/src/constants/mvx.constants.ts b/src/constants/mvx.constants.ts new file mode 100644 index 0000000..341ad72 --- /dev/null +++ b/src/constants/mvx.constants.ts @@ -0,0 +1,15 @@ +export const GAS_PRICE_MODIFIER = 0.01; +export const GAS_PER_DATA_BYTE = 1500; +export const GAS_LIMIT = 50000; +/** + * Extra gas limit for guarded transactions + */ +export const EXTRA_GAS_LIMIT_GUARDED_TX = 50000; +export const GAS_PRICE = 1000000000; +export const DECIMALS = 18; +export const DIGITS = 4; +export const VERSION = 1; +export const LEDGER_CONTRACT_DATA_ENABLED_VALUE = 1; +export const METACHAIN_SHARD_ID = 4294967295; +export const ALL_SHARDS_SHARD_ID = 4294967280; +export const REFUNDED_GAS = 'refundedGas'; diff --git a/src/constants/network.constants.ts b/src/constants/network.constants.ts index d8b5490..356b994 100644 --- a/src/constants/network.constants.ts +++ b/src/constants/network.constants.ts @@ -18,10 +18,12 @@ export const fallbackNetworkConfigurations: Record< walletConnectBridgeAddresses: ['https://bridge.walletconnect.org'], walletConnectV2RelayAddresses: ['wss://relay.walletconnect.com'], walletAddress: 'https://devnet-wallet.multiversx.com', + iframeWalletAddress: 'https://devnet-snap-wallet.multiversx.com', xAliasAddress: 'https://devnet.xalias.com', apiAddress: 'https://devnet-api.multiversx.com', explorerAddress: 'http://devnet-explorer.multiversx.com', - apiTimeout: '4000' + apiTimeout: '4000', + roundDuration: 6000 }, testnet: { id: 'testnet', @@ -36,10 +38,12 @@ export const fallbackNetworkConfigurations: Record< walletConnectBridgeAddresses: ['https://bridge.walletconnect.org'], walletConnectV2RelayAddresses: ['wss://relay.walletconnect.com'], walletAddress: 'https://testnet-wallet.multiversx.com', + iframeWalletAddress: 'https://testnet-snap-wallet.multiversx.com', xAliasAddress: 'https://testnet.xalias.com', apiAddress: 'https://testnet-api.multiversx.com', explorerAddress: 'http://testnet-explorer.multiversx.com', - apiTimeout: '4000' + apiTimeout: '4000', + roundDuration: 6000 }, mainnet: { id: 'mainnet', @@ -54,10 +58,12 @@ export const fallbackNetworkConfigurations: Record< walletConnectBridgeAddresses: ['https://bridge.walletconnect.org'], walletConnectV2RelayAddresses: ['wss://relay.walletconnect.com'], walletAddress: 'https://wallet.multiversx.com', + iframeWalletAddress: 'https://snap-wallet.multiversx.com', xAliasAddress: 'https://xalias.com', apiAddress: 'https://api.multiversx.com', explorerAddress: 'https://explorer.multiversx.com', - apiTimeout: '4000' + apiTimeout: '4000', + roundDuration: 6000 } }; diff --git a/src/constants/placeholders.ts b/src/constants/placeholders.ts deleted file mode 100644 index 70dd268..0000000 --- a/src/constants/placeholders.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Not Applicable - * @value N/A - */ -export const N_A = 'N/A'; - -export const ZERO = '0'; -export const ELLIPSIS = '...'; diff --git a/src/constants/transactions.constants.ts b/src/constants/transactions.constants.ts new file mode 100644 index 0000000..625c86d --- /dev/null +++ b/src/constants/transactions.constants.ts @@ -0,0 +1,7 @@ +export const CANCEL_TRANSACTION_TOAST_ID = 'cancel-transaction-toast'; +export const AVERAGE_TX_DURATION_MS = 6000; +export const CROSS_SHARD_ROUNDS = 5; +export const TRANSACTIONS_STATUS_POLLING_INTERVAL_MS = 90 * 1000; // 90sec +export const TRANSACTIONS_STATUS_DROP_INTERVAL_MS = 10 * 60 * 1000; // 10min +export const CANCEL_TRANSACTION_TOAST_DEFAULT_DURATION = 20000; +export const BATCH_TRANSACTIONS_ID_SEPARATOR = '-'; diff --git a/src/constants/webWalletProvider.constants.ts b/src/constants/webWalletProvider.constants.ts new file mode 100644 index 0000000..f28efdb --- /dev/null +++ b/src/constants/webWalletProvider.constants.ts @@ -0,0 +1,12 @@ +export { + WALLET_PROVIDER_MAINNET, + WALLET_PROVIDER_DEVNET, + WALLET_PROVIDER_TESTNET, + WALLET_PROVIDER_CONNECT_URL, + WALLET_PROVIDER_DISCONNECT_URL, + WALLET_PROVIDER_SEND_TRANSACTION_URL, + WALLET_PROVIDER_SIGN_TRANSACTION_URL, + WALLET_PROVIDER_SIGN_MESSAGE_URL, + WALLET_PROVIDER_CALLBACK_PARAM, + WALLET_PROVIDER_CALLBACK_PARAM_TX_SIGNED +} from '@multiversx/sdk-web-wallet-provider'; diff --git a/src/core/managers/LedgerConnectStateManager/LedgerConnectStateManager.ts b/src/core/managers/LedgerConnectStateManager/LedgerConnectStateManager.ts new file mode 100644 index 0000000..47d27e8 --- /dev/null +++ b/src/core/managers/LedgerConnectStateManager/LedgerConnectStateManager.ts @@ -0,0 +1,150 @@ +import { + IAccountScreenData, + IConfirmScreenData, + IConnectScreenData, + ILedgerAccount, + ILedgerConnectModalData, + LedgerConnectEventsEnum +} from 'core/providers/strategies/LedgerProviderStrategy/types'; +import { IEventBus } from 'types/manager.types'; + +const notInitializedError = () => new Error('Event bus not initialized'); + +export class LedgerConnectStateManager< + T extends + IEventBus = IEventBus +> { + private static instance: LedgerConnectStateManager< + IEventBus + > | null = null; + public readonly addressesPerPage = 10; + + private eventBus: T = { + publish: notInitializedError, + subscribe: notInitializedError, + unsubscribe: notInitializedError + } as unknown as T; + + private allAccounts: ILedgerAccount[] = []; + + // first screen data + private initialConnectScreenData: IConnectScreenData = {}; + private connectScreenData: IConnectScreenData = { + ...this.initialConnectScreenData + }; + + // second screen data + private initialAccountScreenData: IAccountScreenData = { + accounts: this.allAccounts, + startIndex: 0, + addressesPerPage: this.addressesPerPage, + isLoading: true + }; + private accountScreenData: IAccountScreenData = { + ...this.initialAccountScreenData + }; + + // third screen data + private initialConfirmScreenData: IConfirmScreenData = { + selectedAddress: '' + }; + private confirmScreenData: IConfirmScreenData = { + ...this.initialConfirmScreenData + }; + + // whole data to be sent on update events + private initialData: ILedgerConnectModalData = { + connectScreenData: this.initialConnectScreenData, + accountScreenData: null, + confirmScreenData: null + }; + + private data: ILedgerConnectModalData = { ...this.initialData }; + + private constructor(eventBus: T) { + this.eventBus = eventBus; + this.resetData(); + } + + public static getInstance>( + eventBus?: U + ): LedgerConnectStateManager | null { + if (!eventBus) { + return null; + } + if (!LedgerConnectStateManager.instance) { + LedgerConnectStateManager.instance = new LedgerConnectStateManager( + eventBus + ); + } + return LedgerConnectStateManager.instance as LedgerConnectStateManager; + } + + public updateAllAccounts(accounts: ILedgerAccount[]): void { + this.allAccounts = accounts; + this.accountScreenData.accounts = accounts; + } + + public updateStartIndex(startIndex: number): void { + this.accountScreenData.startIndex = startIndex; + } + + private resetData(): void { + this.accountScreenData = { ...this.initialAccountScreenData }; + this.confirmScreenData = { ...this.initialConfirmScreenData }; + this.connectScreenData = { ...this.initialConnectScreenData }; + this.data = { ...this.initialData }; + } + + public closeAndReset(): void { + this.data.shouldClose = true; + this.notifyDataUpdate(); + this.resetData(); + } + + public updateConnectScreen(members: Partial): void { + this.connectScreenData = { + ...this.connectScreenData, + ...members + }; + this.data.confirmScreenData = null; + this.data.accountScreenData = null; + this.notifyDataUpdate(); + } + + public updateAccountScreen(members: Partial): void { + this.accountScreenData = { + ...this.accountScreenData, + ...members + }; + this.data.confirmScreenData = null; + this.data.accountScreenData = this.accountScreenData; + this.notifyDataUpdate(); + } + + public updateConfirmScreen(members: Partial): void { + this.confirmScreenData = { + ...this.confirmScreenData, + ...members + }; + this.data.accountScreenData = null; + this.data.confirmScreenData = this.confirmScreenData; + this.notifyDataUpdate(); + } + + private notifyDataUpdate(): void { + this.eventBus.publish(LedgerConnectEventsEnum.DATA_UPDATE, this.data); + } + + public getAccountScreenData(): IAccountScreenData | null { + return this.data.accountScreenData; + } + + public getConfirmScreenData(): IConfirmScreenData | null { + return this.data.confirmScreenData; + } + + public getAllAccounts(): ILedgerAccount[] { + return this.allAccounts; + } +} diff --git a/src/core/managers/LedgerConnectStateManager/index.ts b/src/core/managers/LedgerConnectStateManager/index.ts new file mode 100644 index 0000000..6827f07 --- /dev/null +++ b/src/core/managers/LedgerConnectStateManager/index.ts @@ -0,0 +1 @@ +export * from './LedgerConnectStateManager'; diff --git a/src/core/managers/PendingTransactionsStateManager/PendingTransactionsStateManagement.ts b/src/core/managers/PendingTransactionsStateManager/PendingTransactionsStateManagement.ts new file mode 100644 index 0000000..c6abb54 --- /dev/null +++ b/src/core/managers/PendingTransactionsStateManager/PendingTransactionsStateManagement.ts @@ -0,0 +1,57 @@ +import { IEventBus } from 'types/manager.types'; +import { + IPendingTransactionsModalData, + PendingTransactionsEventsEnum +} from './types'; + +export class PendingTransactionsStateManager< + T extends + IEventBus = IEventBus +> { + private static instance: PendingTransactionsStateManager< + IEventBus + > | null = null; + private eventBus: T; + + private initialData: IPendingTransactionsModalData = { + isPending: false, + title: '', + subtitle: '', + shouldClose: false + }; + + private data: IPendingTransactionsModalData = { ...this.initialData }; + + private constructor(eventBus: T) { + this.eventBus = eventBus; + } + + public static getInstance>( + eventBus: U + ): PendingTransactionsStateManager { + if (!PendingTransactionsStateManager.instance) { + PendingTransactionsStateManager.instance = + new PendingTransactionsStateManager(eventBus); + } + return PendingTransactionsStateManager.instance as PendingTransactionsStateManager; + } + + public closeAndReset(): void { + this.data.shouldClose = true; + this.notifyDataUpdate(); + this.resetData(); + } + + private resetData(): void { + this.data = { ...this.initialData }; + } + + public updateData(newData: IPendingTransactionsModalData): void { + this.data = { ...this.data, ...newData }; + this.notifyDataUpdate(); + } + + private notifyDataUpdate(): void { + this.eventBus.publish(PendingTransactionsEventsEnum.DATA_UPDATE, this.data); + } +} diff --git a/src/core/managers/PendingTransactionsStateManager/index.ts b/src/core/managers/PendingTransactionsStateManager/index.ts new file mode 100644 index 0000000..d941f9d --- /dev/null +++ b/src/core/managers/PendingTransactionsStateManager/index.ts @@ -0,0 +1,2 @@ +export * from './PendingTransactionsStateManagement'; +export * from './types'; diff --git a/src/core/managers/PendingTransactionsStateManager/types/index.ts b/src/core/managers/PendingTransactionsStateManager/types/index.ts new file mode 100644 index 0000000..4f9a4f3 --- /dev/null +++ b/src/core/managers/PendingTransactionsStateManager/types/index.ts @@ -0,0 +1 @@ +export * from './pendingTransactions.types'; diff --git a/src/core/managers/PendingTransactionsStateManager/types/pendingTransactions.types.ts b/src/core/managers/PendingTransactionsStateManager/types/pendingTransactions.types.ts new file mode 100644 index 0000000..8133161 --- /dev/null +++ b/src/core/managers/PendingTransactionsStateManager/types/pendingTransactions.types.ts @@ -0,0 +1,12 @@ +// types here need to be synced with the types in sdk-dapp-core-ui +export enum PendingTransactionsEventsEnum { + 'CLOSE' = 'CLOSE', + 'DATA_UPDATE' = 'DATA_UPDATE' +} + +export interface IPendingTransactionsModalData { + isPending: boolean; + title: string; + subtitle?: string; + shouldClose?: boolean; +} diff --git a/src/core/managers/SignTransactionsStateManager/SignTransactionsStateManager.ts b/src/core/managers/SignTransactionsStateManager/SignTransactionsStateManager.ts new file mode 100644 index 0000000..044ffb1 --- /dev/null +++ b/src/core/managers/SignTransactionsStateManager/SignTransactionsStateManager.ts @@ -0,0 +1,111 @@ +import { IEventBus } from 'types/manager.types'; +import { NftEnumType } from 'types/tokens.types'; +import { + FungibleTransactionType, + ISignTransactionsModalData, + SignEventsEnum, + TokenType +} from './types/signTransactionsModal.types'; + +const notInitializedError = () => new Error('Event bus not initialized'); + +export class SignTransactionsStateManager< + T extends + IEventBus = IEventBus +> { + private static instance: SignTransactionsStateManager< + IEventBus + > | null = null; + public readonly addressesPerPage = 10; + + private eventBus: T = { + publish: notInitializedError, + subscribe: notInitializedError, + unsubscribe: notInitializedError + } as unknown as T; + + // whole data to be sent on update events + private initialData: ISignTransactionsModalData = { + commonData: { transactionsCount: 0, egldLabel: '', currentIndex: 0 }, + tokenTransaction: null, + nftTransaction: null, + sftTransaction: null + }; + + private data: ISignTransactionsModalData = { ...this.initialData }; + + private constructor(eventBus: T) { + this.eventBus = eventBus; + this.resetData(); + } + + public static getInstance>( + eventBus?: U + ): SignTransactionsStateManager | null { + if (!eventBus) { + return null; + } + if (!SignTransactionsStateManager.instance) { + SignTransactionsStateManager.instance = new SignTransactionsStateManager( + eventBus + ); + } + return SignTransactionsStateManager.instance as SignTransactionsStateManager; + } + + public updateCommonData( + members: Partial + ): void { + this.data.commonData = { + ...this.data.commonData, + ...members + }; + this.notifyDataUpdate(); + } + + private resetData(): void { + this.data = { ...this.initialData }; + } + + public closeAndReset(): void { + this.data.shouldClose = true; + this.notifyDataUpdate(); + this.resetData(); + } + + private notifyDataUpdate(): void { + this.eventBus.publish(SignEventsEnum.DATA_UPDATE, this.data); + } + + public updateTokenTransaction( + tokenData: ISignTransactionsModalData['tokenTransaction'] + ): void { + this.data.tokenTransaction = tokenData; + this.data.sftTransaction = null; + this.data.nftTransaction = null; + + this.notifyDataUpdate(); + } + + public updateFungibleTransaction( + type: TokenType, + fungibleData: FungibleTransactionType + ): void { + switch (type) { + case NftEnumType.NonFungibleESDT: + this.data.nftTransaction = fungibleData; + this.data.tokenTransaction = null; + this.data.sftTransaction = null; + break; + case NftEnumType.SemiFungibleESDT: + this.data.sftTransaction = fungibleData; + this.data.nftTransaction = null; + this.data.tokenTransaction = null; + break; + default: + break; + } + + this.notifyDataUpdate(); + } +} diff --git a/src/core/managers/SignTransactionsStateManager/index.ts b/src/core/managers/SignTransactionsStateManager/index.ts new file mode 100644 index 0000000..34b447a --- /dev/null +++ b/src/core/managers/SignTransactionsStateManager/index.ts @@ -0,0 +1 @@ +export * from './SignTransactionsStateManager'; diff --git a/src/core/managers/SignTransactionsStateManager/types/index.ts b/src/core/managers/SignTransactionsStateManager/types/index.ts new file mode 100644 index 0000000..6f89536 --- /dev/null +++ b/src/core/managers/SignTransactionsStateManager/types/index.ts @@ -0,0 +1 @@ +export * from './signTransactionsModal.types'; diff --git a/src/core/managers/SignTransactionsStateManager/types/signTransactionsModal.types.ts b/src/core/managers/SignTransactionsStateManager/types/signTransactionsModal.types.ts new file mode 100644 index 0000000..10e8c95 --- /dev/null +++ b/src/core/managers/SignTransactionsStateManager/types/signTransactionsModal.types.ts @@ -0,0 +1,50 @@ +export interface ITransactionData { + receiver?: string; + data?: string; + value?: string; +} + +export type FungibleTransactionType = { + amount: string; + identifier?: string; + imageURL: string; +}; + +export type TokenType = + | 'SemiFungibleESDT' + | 'NonFungibleESDT' + | 'FungibleESDT' + | null; + +export interface ISignTransactionsModalData { + shouldClose?: true; + commonData: { + receiver?: string; + data?: string; + transactionsCount: number; + /** + * Token type of the transaction. + * @param {string} `null` - if is EGLD or MultiEsdt transaction. + */ + tokenType?: TokenType; + egldLabel: string; + feeLimit?: string; + feeInFiatLimit?: string | null; + currentIndex: number; + }; + tokenTransaction: { + identifier?: string; + amount: string; + usdValue: string; + } | null; + nftTransaction: FungibleTransactionType | null; + sftTransaction: FungibleTransactionType | null; +} + +export enum SignEventsEnum { + 'SIGN_TRANSACTION' = 'SIGN_TRANSACTION', + 'NEXT_PAGE' = 'NEXT_PAGE', + 'PREV_PAGE' = 'PREV_PAGE', + 'CLOSE' = 'CLOSE', + 'DATA_UPDATE' = 'DATA_UPDATE' +} diff --git a/src/core/managers/ToastManager/ToastManager.ts b/src/core/managers/ToastManager/ToastManager.ts new file mode 100644 index 0000000..a69b961 --- /dev/null +++ b/src/core/managers/ToastManager/ToastManager.ts @@ -0,0 +1,204 @@ +import { TransactionToastList } from 'lib/sdkDappCoreUi'; +import { removeTransactionToast } from 'store/actions/toasts/toastsActions'; +import { isServerTransactionPending } from 'store/actions/trackedTransactions/transactionStateByStatus'; +import { ToastsSliceState } from 'store/slices/toast/toastSlice.types'; +import { getStore } from 'store/store'; +import { + ProviderErrorsEnum, + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types'; +import { SignedTransactionType } from 'types/transactions.types'; +import { createModalElement } from 'utils/createModalElement'; +import { + GetToastsOptionsDataPropsType, + ITransactionToast, + TransactionsDefaultTitles, + TransactionToastEventsEnum, + IToastDataState +} from './types'; + +export class ToastManager { + private transactionToastsList: TransactionToastList | undefined; + private unsubscribe: () => void = () => null; + store = getStore(); + + constructor() {} + + public init() { + const { toasts, trackedTransactions } = this.store.getState(); + this.onToastListChange(toasts); + + let previousToasts = toasts; + let previousTrackedTransactions = trackedTransactions; + this.unsubscribe = this.store.subscribe(() => { + const { toasts, trackedTransactions } = this.store.getState(); + const currentToasts = toasts; + + const currentTrackedTransactions = trackedTransactions; + + if ( + previousToasts !== currentToasts || + previousTrackedTransactions !== currentTrackedTransactions + ) { + previousToasts = currentToasts; + previousTrackedTransactions = currentTrackedTransactions; + this.onToastListChange(currentToasts); + } + }); + } + + private async onToastListChange(toastList: ToastsSliceState) { + const { trackedTransactions, account } = this.store.getState(); + const transactionToasts: ITransactionToast[] = []; + + toastList.transactionToasts.forEach(async (toast) => { + const sessionTransactions = trackedTransactions[toast.toastId]; + if (!sessionTransactions) { + return; + } + + const transaction: ITransactionToast = { + toastDataState: this.getToastDataStateByStatus({ + address: account.address, + sender: sessionTransactions.transactions[0].sender, + toastId: toast.toastId, + status: sessionTransactions.status + }), + processedTransactionsStatus: this.getToastProceededStatus( + sessionTransactions.transactions + ), + toastId: toast.toastId, + transactions: sessionTransactions.transactions.map((transaction) => ({ + hash: transaction.hash, + status: transaction.status + })) + }; + + transactionToasts.push(transaction); + }); + await this.renderUIToasts(transactionToasts); + } + + private async renderUIToasts(transactionsToasts: ITransactionToast[]) { + if (!this.transactionToastsList) { + this.transactionToastsList = + await createModalElement( + 'transaction-toast-list' + ); + } + + const eventBus = await this.transactionToastsList.getEventBus(); + + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + eventBus.publish( + TransactionToastEventsEnum.TRANSACTION_TOAST_DATA_UPDATE, + transactionsToasts + ); + eventBus.subscribe( + TransactionToastEventsEnum.CLOSE_TOAST, + (toastId: string) => { + removeTransactionToast(toastId); + } + ); + return this.transactionToastsList; + } + + private getToastDataStateByStatus = ({ + address, + sender, + status, + toastId + }: GetToastsOptionsDataPropsType) => { + const successToastData: IToastDataState = { + id: toastId, + icon: 'check', + hasCloseButton: true, + title: TransactionsDefaultTitles.success, + iconClassName: 'success' + }; + + const receivedToastData: IToastDataState = { + id: toastId, + icon: 'check', + hasCloseButton: true, + title: TransactionsDefaultTitles.received, + iconClassName: 'success' + }; + + const pendingToastData: IToastDataState = { + id: toastId, + icon: 'hourglass', + hasCloseButton: false, + title: TransactionsDefaultTitles.pending, + iconClassName: 'warning' + }; + + const failToastData: IToastDataState = { + id: toastId, + icon: 'times', + title: TransactionsDefaultTitles.failed, + hasCloseButton: true, + iconClassName: 'danger' + }; + + const invalidToastData: IToastDataState = { + id: toastId, + icon: 'ban', + title: TransactionsDefaultTitles.invalid, + hasCloseButton: true, + iconClassName: 'warning' + }; + + const timedOutToastData = { + id: toastId, + icon: 'times', + title: TransactionsDefaultTitles.timedOut, + hasCloseButton: true, + iconClassName: 'warning' + }; + + switch (status) { + case TransactionBatchStatusesEnum.signed: + case TransactionBatchStatusesEnum.sent: + return pendingToastData; + case TransactionBatchStatusesEnum.success: + return sender !== address ? receivedToastData : successToastData; + case TransactionBatchStatusesEnum.cancelled: + case TransactionBatchStatusesEnum.fail: + return failToastData; + case TransactionBatchStatusesEnum.timedOut: + return timedOutToastData; + case TransactionBatchStatusesEnum.invalid: + return invalidToastData; + default: + return pendingToastData; + } + }; + + private getToastProceededStatus = (transactions: SignedTransactionType[]) => { + const processedTransactions = transactions.filter( + (tx) => + !isServerTransactionPending(tx.status as TransactionServerStatusesEnum) + ).length; + + const totalTransactions = transactions.length; + + if (totalTransactions === 1 && processedTransactions === 1) { + return isServerTransactionPending( + transactions[0].status as TransactionServerStatusesEnum + ) + ? 'Processing transaction' + : 'Transaction processed'; + } + + return `${processedTransactions} / ${totalTransactions} transactions processed`; + }; + + public destroy() { + this.unsubscribe(); + } +} diff --git a/src/core/managers/ToastManager/types/index.ts b/src/core/managers/ToastManager/types/index.ts new file mode 100644 index 0000000..4ffb46a --- /dev/null +++ b/src/core/managers/ToastManager/types/index.ts @@ -0,0 +1 @@ +export * from './toast.types'; diff --git a/src/core/managers/ToastManager/types/toast.types.ts b/src/core/managers/ToastManager/types/toast.types.ts new file mode 100644 index 0000000..90f668e --- /dev/null +++ b/src/core/managers/ToastManager/types/toast.types.ts @@ -0,0 +1,49 @@ +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; + +export enum TransactionsDefaultTitles { + success = 'Transaction successful', + received = 'Transaction received', + failed = 'Transaction failed', + pending = 'Processing transaction', + timedOut = 'Transaction timed out', + invalid = 'Transaction invalid' +} + +export interface GetToastsOptionsDataPropsType { + address: string; + sender: string; + status?: TransactionBatchStatusesEnum | TransactionServerStatusesEnum; + toastId: string; +} + +export interface IToastDataState { + id: string; + icon: string; + hasCloseButton: boolean; + title: string; + iconClassName: string; +} +export interface ITransactionProgressState { + progressClass?: string; + currentRemaining: number; +} +export interface ITransaction { + hash: string; + status: string; +} +export interface ITransactionToast { + toastId: string; + wrapperClass?: string; // TODO: remove ? + processedTransactionsStatus: string; + transactions: ITransaction[]; + toastDataState: IToastDataState; + transactionProgressState?: ITransactionProgressState; +} + +export enum TransactionToastEventsEnum { + 'CLOSE_TOAST' = 'CLOSE_TOAST', + 'TRANSACTION_TOAST_DATA_UPDATE' = 'TRANSACTION_TOAST_DATA_UPDATE' +} diff --git a/src/core/managers/TransactionManager/TransactionManager.ts b/src/core/managers/TransactionManager/TransactionManager.ts new file mode 100644 index 0000000..243990d --- /dev/null +++ b/src/core/managers/TransactionManager/TransactionManager.ts @@ -0,0 +1,163 @@ +import { Transaction } from '@multiversx/sdk-core/out'; +import axios, { AxiosError } from 'axios'; +import { BATCH_TRANSACTIONS_ID_SEPARATOR } from 'constants/transactions.constants'; +import { getAccount } from 'core/methods/account/getAccount'; +import { addTransactionToast } from 'store/actions/toasts/toastsActions'; +import { createTrackedTransactionsSession } from 'store/actions/trackedTransactions/trackedTransactionsActions'; +import { networkSelector } from 'store/selectors'; +import { getState } from 'store/store'; +import { TransactionServerStatusesEnum } from 'types/enums.types'; +import { BatchTransactionsResponseType } from 'types/serverTransactions.types'; +import { SignedTransactionType } from 'types/transactions.types'; +import { isGuardianTx } from 'utils/transactions/isGuardianTx'; + +export class TransactionManager { + private static instance: TransactionManager | null = null; + + private constructor() {} + + public static getInstance(): TransactionManager { + if (!TransactionManager.instance) { + TransactionManager.instance = new TransactionManager(); + } + return TransactionManager.instance; + } + + public send = async ( + signedTransactions: Transaction[] | Transaction[][] + ): Promise => { + if (signedTransactions.length === 0) { + throw new Error('No transactions to send'); + } + + try { + if (!this.isBatchTransaction(signedTransactions)) { + const hashes = await this.sendSignedTransactions(signedTransactions); + return hashes; + } + + const sentTransactions = + await this.sendSignedBatchTransactions(signedTransactions); + + if (!sentTransactions.data || sentTransactions.data.error) { + throw new Error( + sentTransactions.data?.error || 'Failed to send transactions' + ); + } + + const flatSentTransactions = this.sequentialToFlatArray( + sentTransactions.data.transactions + ); + + return flatSentTransactions.map((transaction) => transaction.hash); + } catch (error) { + const responseData = <{ message: string }>( + (error as AxiosError).response?.data + ); + throw responseData?.message ?? (error as any).message; + } + }; + + public track = async ( + signedTransactions: Transaction[], + options: { disableToasts?: boolean } = { disableToasts: false } + ) => { + const parsedTransactions = signedTransactions.map((transaction) => + this.parseSignedTransaction(transaction) + ); + const sessionId = createTrackedTransactionsSession(parsedTransactions); + if (!options.disableToasts) { + addTransactionToast(sessionId); + } + }; + + private sendSignedTransactions = async ( + signedTransactions: Transaction[] + ): Promise => { + const { apiAddress, apiTimeout } = networkSelector(getState()); + + const promises = signedTransactions.map((transaction) => + axios.post(`${apiAddress}/transactions`, transaction.toPlainObject(), { + timeout: Number(apiTimeout) + }) + ); + + const response = await Promise.all(promises); + + return response.map(({ data }) => data.txHash); + }; + + private sendSignedBatchTransactions = async ( + signedTransactions: Transaction[][] + ) => { + const { address } = getAccount(); + const { apiAddress, apiTimeout } = networkSelector(getState()); + + if (!address) { + return { + error: + 'Invalid address provided. You need to be logged in to send transactions' + }; + } + + const batchId = this.buildBatchId(address); + const parsedTransactions = signedTransactions.map((transactions) => + transactions.map((transaction) => + this.parseSignedTransaction(transaction) + ) + ); + + const payload = { + transactions: parsedTransactions, + id: batchId + }; + + const { data } = await axios.post( + `${apiAddress}/batch`, + payload, + { + timeout: Number(apiTimeout) + } + ); + + return { data }; + }; + + private buildBatchId = (address: string) => { + const sessionId = Date.now().toString(); + return `${sessionId}${BATCH_TRANSACTIONS_ID_SEPARATOR}${address}`; + }; + + private sequentialToFlatArray = ( + transactions: SignedTransactionType[] | SignedTransactionType[][] = [] + ) => + this.getIsSequential(transactions) + ? transactions.flat() + : (transactions as SignedTransactionType[]); + + private getIsSequential = ( + transactions?: SignedTransactionType[] | SignedTransactionType[][] + ) => transactions?.every((transaction) => Array.isArray(transaction)); + + private isBatchTransaction = ( + transactions: Transaction[] | Transaction[][] + ): transactions is Transaction[][] => { + return Array.isArray(transactions[0]); + }; + + private parseSignedTransaction = (signedTransaction: Transaction) => { + const parsedTransaction = { + ...signedTransaction.toPlainObject(), + hash: signedTransaction.getHash().hex(), + status: TransactionServerStatusesEnum.pending + }; + + // TODO: Remove when the protocol supports usernames for guardian transactions + if (isGuardianTx({ data: parsedTransaction.data })) { + delete parsedTransaction.senderUsername; + delete parsedTransaction.receiverUsername; + } + + return parsedTransaction; + }; +} diff --git a/src/core/managers/TransactionManager/index.ts b/src/core/managers/TransactionManager/index.ts new file mode 100644 index 0000000..e6dcdcf --- /dev/null +++ b/src/core/managers/TransactionManager/index.ts @@ -0,0 +1 @@ +export * from './TransactionManager'; diff --git a/src/core/managers/WalletConnectStateManager/WalletConnectStateManager.ts b/src/core/managers/WalletConnectStateManager/WalletConnectStateManager.ts new file mode 100644 index 0000000..a33d9cf --- /dev/null +++ b/src/core/managers/WalletConnectStateManager/WalletConnectStateManager.ts @@ -0,0 +1,56 @@ +import { + IWalletConnectModalData, + WalletConnectEventsEnum +} from 'core/providers/strategies/WalletConnectProviderStrategy/types'; +import { IEventBus } from 'types/manager.types'; + +export class WalletConnectStateManager< + T extends + IEventBus = IEventBus +> { + private static instance: WalletConnectStateManager< + IEventBus + > | null = null; + private eventBus: T; + + private initialData: IWalletConnectModalData = { + wcURI: '', + shouldClose: false + }; + + private data: IWalletConnectModalData = { ...this.initialData }; + + private constructor(eventBus: T) { + this.eventBus = eventBus; + } + + public static getInstance>( + eventBus: U + ): WalletConnectStateManager { + if (!WalletConnectStateManager.instance) { + WalletConnectStateManager.instance = new WalletConnectStateManager( + eventBus + ); + } + return WalletConnectStateManager.instance as WalletConnectStateManager; + } + + public closeAndReset(): void { + this.data.shouldClose = true; + this.notifyDataUpdate(); + this.resetData(); + } + + private resetData(): void { + this.data = { ...this.initialData }; + } + + public updateWcURI(wcURI: string): void { + this.data.wcURI = wcURI; + this.notifyDataUpdate(); + } + + private notifyDataUpdate(): void { + this.eventBus.publish(WalletConnectEventsEnum.DATA_UPDATE, this.data); + } +} diff --git a/src/core/managers/WalletConnectStateManager/index.ts b/src/core/managers/WalletConnectStateManager/index.ts new file mode 100644 index 0000000..efc4043 --- /dev/null +++ b/src/core/managers/WalletConnectStateManager/index.ts @@ -0,0 +1 @@ +export * from './WalletConnectStateManager'; diff --git a/src/core/managers/index.ts b/src/core/managers/index.ts new file mode 100644 index 0000000..952f086 --- /dev/null +++ b/src/core/managers/index.ts @@ -0,0 +1,5 @@ +export * from './LedgerConnectStateManager'; +export * from './SignTransactionsStateManager'; +export * from './TransactionManager'; +export * from './WalletConnectStateManager'; +export * from './PendingTransactionsStateManager'; diff --git a/src/core/methods/account/getAccount.ts b/src/core/methods/account/getAccount.ts index 341e426..7fcc837 100644 --- a/src/core/methods/account/getAccount.ts +++ b/src/core/methods/account/getAccount.ts @@ -1,6 +1,6 @@ import { accountSelector } from 'store/selectors'; import { getState } from 'store/store'; -export function getAccount() { - return accountSelector(getState()); +export function getAccount(state = getState()) { + return accountSelector(state); } diff --git a/src/core/methods/account/getIsLoggedIn.ts b/src/core/methods/account/getIsLoggedIn.ts index 9316522..8e04a1f 100644 --- a/src/core/methods/account/getIsLoggedIn.ts +++ b/src/core/methods/account/getIsLoggedIn.ts @@ -1,5 +1,4 @@ import { isLoggedInSelector } from 'store/selectors/accountSelectors'; -import { getAddress } from './getAddress'; import { getState } from 'store/store'; export function getIsLoggedIn() { diff --git a/src/core/methods/account/getLatestNonce.ts b/src/core/methods/account/getLatestNonce.ts index e5ebbe5..fb94cb6 100644 --- a/src/core/methods/account/getLatestNonce.ts +++ b/src/core/methods/account/getLatestNonce.ts @@ -2,7 +2,7 @@ import { accountNonceSelector } from 'store/selectors/accountSelectors'; import { getState } from 'store/store'; import { AccountType } from 'types/account.types'; -export const getLatestNonce = (account: AccountType | null) => { +export function getLatestNonce(account: AccountType | null) { const currentAccountNonce = accountNonceSelector(getState()); if (!account) { return currentAccountNonce; @@ -10,4 +10,4 @@ export const getLatestNonce = (account: AccountType | null) => { return currentAccountNonce && !isNaN(currentAccountNonce) ? Math.max(currentAccountNonce, account.nonce) : account.nonce; -}; +} diff --git a/src/core/methods/account/getWebviewToken.ts b/src/core/methods/account/getWebviewToken.ts index fcaa009..1b7e32b 100644 --- a/src/core/methods/account/getWebviewToken.ts +++ b/src/core/methods/account/getWebviewToken.ts @@ -1,9 +1,11 @@ import { getWindowLocation } from 'utils/window/getWindowLocation'; -export const getWebviewToken = () => { +// TODO: also get from store +// TODO: is this still needed? Maybe drop support and use postMessage +export function getWebviewToken() { const { search } = getWindowLocation(); const urlSearchParams = new URLSearchParams(search) as any; const searchParams = Object.fromEntries(urlSearchParams); return searchParams?.accessToken; -}; +} diff --git a/src/core/methods/init/init.ts b/src/core/methods/init/init.ts deleted file mode 100644 index 07d78d0..0000000 --- a/src/core/methods/init/init.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { initStore } from 'store/store'; -import { defaultStorageCallback, StorageCallback } from 'store/storage'; -import { setNativeAuthConfig } from 'store/actions/config/configActions'; -import { initializeNetwork } from 'store/actions'; -import { CustomNetworkType } from 'types/network.types'; -import { EnvironmentsEnum } from 'types/enums.types'; -import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; -import { getDefaultNativeAuthConfig } from 'services/nativeAuth/methods/getDefaultNativeAuthConfig'; - -type InitAppType = { - storage?: { - getStorageCallback: StorageCallback; - }; - dAppConfig?: { - nativeAuth?: boolean | NativeAuthConfigType; - network?: CustomNetworkType; - environment?: EnvironmentsEnum; - }; -}; -const defaultInitAppProps = { - storage: { - getStorageCallback: defaultStorageCallback - } -}; - -/** - * Initializes the dApp with the given configuration. - * @param props - The configuration for the dApp initialization. - * @param props.storage - The storage configuration for the dApp. - * @param props.storage.getStorageCallback - The callback to get the storage (custom storage). - * @param props.nativeAuth - The native auth configuration for the dApp. - * @param props.nativeAuth - If set to `true`, will fallback on default configuration. - * @param props.nativeAuth - If set to `false`, will disable native auth. - * @param props.nativeAuth - If set to `NativeAuthConfigType`, will set the native auth configuration. - * - * !!! Avoid changing the configuration during the dApp lifecycle. - * - * @example - * ```ts - * initializeDApp({ - * nativeAuth: true - * }); - * ``` - * */ -export const initializeDApp = async (props?: InitAppType) => { - const { storage, dAppConfig } = { ...defaultInitAppProps, ...props }; - initStore(storage.getStorageCallback); - - if (dAppConfig?.nativeAuth) { - const nativeAuthConfig: NativeAuthConfigType = - typeof dAppConfig.nativeAuth === 'boolean' - ? getDefaultNativeAuthConfig() - : dAppConfig.nativeAuth; - - setNativeAuthConfig(nativeAuthConfig); - } - - if (dAppConfig?.network) { - await initializeNetwork({ - customNetworkConfig: dAppConfig.network, - environment: dAppConfig.environment ?? EnvironmentsEnum.devnet - }); - } -}; diff --git a/src/core/methods/initApp/initApp.ts b/src/core/methods/initApp/initApp.ts new file mode 100644 index 0000000..a746c7e --- /dev/null +++ b/src/core/methods/initApp/initApp.ts @@ -0,0 +1,84 @@ +import { safeWindow } from 'constants/index'; +import { ToastManager } from 'core/managers/ToastManager/ToastManager'; +import { restoreProvider } from 'core/providers/helpers/restoreProvider'; +import { ProviderFactory } from 'core/providers/ProviderFactory'; +import { getDefaultNativeAuthConfig } from 'services/nativeAuth/methods/getDefaultNativeAuthConfig'; +import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; +import { initializeNetwork } from 'store/actions'; +import { + setCrossWindowConfig, + setNativeAuthConfig, + setWalletConnectConfig +} from 'store/actions/config/configActions'; +import { defaultStorageCallback } from 'store/storage'; +import { initStore } from 'store/store'; +import { InitAppType } from './initApp.types'; +import { getIsLoggedIn } from '../account/getIsLoggedIn'; +import { registerWebsocketListener } from './websocket/registerWebsocket'; +import { trackTransactions } from '../trackTransactions/trackTransactions'; + +const defaultInitAppProps = { + storage: { + getStorageCallback: defaultStorageCallback + } +}; + +/** + * Initializes the dApp with the given configuration. + * @param props - The configuration for the dApp initialization. + * + * @example + * ```ts + initApp({ + nativeAuth: true, + environment: EnvironmentsEnum.devnet + }); + * ``` + * */ +export async function initApp({ + storage = defaultInitAppProps.storage, + dAppConfig, + customProviders +}: InitAppType) { + initStore(storage.getStorageCallback); + + const { apiAddress } = await initializeNetwork({ + customNetworkConfig: dAppConfig.network, + environment: dAppConfig.environment + }); + + if (dAppConfig?.nativeAuth) { + const nativeAuthConfig: NativeAuthConfigType = + typeof dAppConfig.nativeAuth === 'boolean' + ? getDefaultNativeAuthConfig(apiAddress) + : dAppConfig.nativeAuth; + + setNativeAuthConfig(nativeAuthConfig); + } + + if (dAppConfig?.providers?.walletConnect) { + setWalletConnectConfig(dAppConfig.providers.walletConnect); + } + + if (dAppConfig?.providers?.crossWindow) { + setCrossWindowConfig(dAppConfig.providers.crossWindow); + } + + trackTransactions(); + const toastManager = new ToastManager(); + toastManager.init(); + + const isLoggedIn = getIsLoggedIn(); + + const usedProviders = [ + ...((safeWindow as any)?.multiversx?.providers || []), + ...(customProviders || []) + ]; + + ProviderFactory.customProviders(usedProviders || []); + + if (isLoggedIn) { + await restoreProvider(); + await registerWebsocketListener(); + } +} diff --git a/src/core/methods/initApp/initApp.types.ts b/src/core/methods/initApp/initApp.types.ts new file mode 100644 index 0000000..1ecdfa0 --- /dev/null +++ b/src/core/methods/initApp/initApp.types.ts @@ -0,0 +1,59 @@ +import { CrossWindowConfig } from 'core/providers/strategies/CrossWindowProviderStrategy/types'; +import { WalletConnectConfig } from 'core/providers/strategies/WalletConnectProviderStrategy/types'; +import { ICustomProvider } from 'core/providers/types/providerFactory.types'; +import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; +import { StorageCallback } from 'store/storage'; +import { EnvironmentsEnum } from 'types/enums.types'; +import { CustomNetworkType } from 'types/network.types'; + +type BaseDappConfigType = { + /** + * The native auth configuration for the dApp. + * If set to `true`, will fallback on default configuration. + * If set to `false`, will disable native auth. + * If set to `NativeAuthConfigType`, will set the native auth configuration. + */ + nativeAuth?: boolean | NativeAuthConfigType; + /** + * Customize exising providers + */ + providers?: { + crossWindow?: CrossWindowConfig; + walletConnect?: WalletConnectConfig; + }; +}; + +export type EnvironmentDappConfigType = BaseDappConfigType & { + /** + * If passed in, will automatically initialize the network with the given environment. + */ + environment: EnvironmentsEnum; + network?: CustomNetworkType; +}; + +export type CustomNetworkDappConfigType = BaseDappConfigType & { + /** + * Can override the network configuration, e.g. for sovereign shards. + * Must include `apiAddress` if provided. + */ + network: CustomNetworkType & { apiAddress: string }; + environment?: never; +}; + +export type DappConfigType = + | EnvironmentDappConfigType + | CustomNetworkDappConfigType; + +export type InitAppType = { + /** + * The storage configuration for the dApp. + */ + storage?: { + /** + * The callback to get the storage (custom storage). + */ + getStorageCallback: StorageCallback; + }; + dAppConfig: DappConfigType; + customProviders?: ICustomProvider[]; +}; diff --git a/src/core/methods/initApp/websocket/initializeWebsocketConnection.ts b/src/core/methods/initApp/websocket/initializeWebsocketConnection.ts new file mode 100644 index 0000000..9b8a39a --- /dev/null +++ b/src/core/methods/initApp/websocket/initializeWebsocketConnection.ts @@ -0,0 +1,119 @@ +import { io } from 'socket.io-client'; +import { getWebsocketUrl } from 'apiCalls/websocket'; +import { getAccount } from 'core/methods/account/getAccount'; +import { + setWebsocketBatchEvent, + setWebsocketEvent +} from 'store/actions/account/accountActions'; +import { networkSelector } from 'store/selectors'; +import { getStore } from 'store/store'; +import { retryMultipleTimes } from 'utils/retryMultipleTimes'; +import { + BatchTransactionsWSResponseType, + websocketConnection, + WebsocketConnectionStatusEnum +} from './websocket.constants'; + +const TIMEOUT = 3000; +const RECONNECTION_ATTEMPTS = 3; +const RETRY_INTERVAL = 500; +const MESSAGE_DELAY = 1000; +const BATCH_UPDATED_EVENT = 'batchUpdated'; +const CONNECT = 'connect'; +const DISCONNECT = 'disconnect'; + +// eslint-disable-next-line no-undef +type TimeoutType = NodeJS.Timeout | null; + +export async function initializeWebsocketConnection() { + const { address } = getAccount(); + const { apiAddress, websocketUrl: customWebsocketUrl } = networkSelector( + getStore().getState() + ); + + let messageTimeout: TimeoutType = null; + let batchTimeout: TimeoutType = null; + + const handleMessageReceived = (message: string) => { + if (messageTimeout) { + clearTimeout(messageTimeout); + } + messageTimeout = setTimeout(() => { + setWebsocketEvent(message); + }, MESSAGE_DELAY); + }; + + const handleBatchUpdate = (data: BatchTransactionsWSResponseType) => { + if (batchTimeout) { + clearTimeout(batchTimeout); + } + batchTimeout = setTimeout(() => { + setWebsocketBatchEvent(data); + }, MESSAGE_DELAY); + }; + + const initializeConnection = retryMultipleTimes( + async () => { + // To avoid multiple connections to the same endpoint + websocketConnection.status = WebsocketConnectionStatusEnum.PENDING; + + const websocketUrl = + customWebsocketUrl ?? (await getWebsocketUrl(apiAddress)); + + if (!websocketUrl) { + console.warn('Cannot get websocket URL'); + return; + } + + websocketConnection.instance = io(websocketUrl, { + forceNew: true, + reconnectionAttempts: RECONNECTION_ATTEMPTS, + timeout: TIMEOUT, + query: { address } + }); + + websocketConnection.status = WebsocketConnectionStatusEnum.COMPLETED; + + websocketConnection.instance.onAny(handleMessageReceived); + + websocketConnection.instance.on(BATCH_UPDATED_EVENT, handleBatchUpdate); + + websocketConnection.instance.on(CONNECT, () => { + console.log('Websocket connected.'); + }); + + websocketConnection.instance.on(DISCONNECT, () => { + console.warn('Websocket disconnected. Trying to reconnect...'); + setTimeout(() => { + console.log('Websocket reconnecting...'); + websocketConnection.instance?.connect(); + }, RETRY_INTERVAL); + }); + }, + { retries: 2, delay: RETRY_INTERVAL } + ); + + const closeConnection = () => { + websocketConnection.instance?.close(); + websocketConnection.status = WebsocketConnectionStatusEnum.NOT_INITIALIZED; + if (messageTimeout) { + clearTimeout(messageTimeout); + } + if (batchTimeout) { + clearTimeout(batchTimeout); + } + }; + + if ( + address && + websocketConnection.status === + WebsocketConnectionStatusEnum.NOT_INITIALIZED && + !websocketConnection.instance?.active + ) { + await initializeConnection(); + } + + return { + closeConnection + }; +} diff --git a/src/core/methods/initApp/websocket/registerWebsocket.ts b/src/core/methods/initApp/websocket/registerWebsocket.ts new file mode 100644 index 0000000..13a65cd --- /dev/null +++ b/src/core/methods/initApp/websocket/registerWebsocket.ts @@ -0,0 +1,25 @@ +import { getAccount } from 'core/methods/account/getAccount'; +import { getStore } from 'store/store'; +import { initializeWebsocketConnection } from './initializeWebsocketConnection'; + +let localAddress = ''; +let closeConnectionRef: () => void; + +export async function registerWebsocketListener() { + const store = getStore(); + const account = getAccount(); + localAddress = account.address; + + // Initialize the websocket connection + const data = await initializeWebsocketConnection(); + closeConnectionRef = data.closeConnection; + + store.subscribe(async ({ account: { address } }) => { + if (localAddress && address !== localAddress) { + closeConnectionRef(); + localAddress = address; + const { closeConnection } = await initializeWebsocketConnection(); + closeConnectionRef = closeConnection; + } + }); +} diff --git a/src/core/methods/initApp/websocket/websocket.constants.ts b/src/core/methods/initApp/websocket/websocket.constants.ts new file mode 100644 index 0000000..c79cbac --- /dev/null +++ b/src/core/methods/initApp/websocket/websocket.constants.ts @@ -0,0 +1,21 @@ +import { Socket } from 'socket.io-client'; + +export type BatchTransactionsWSResponseType = { + batchId: string; + txHashes: string[]; +}; + +export enum WebsocketConnectionStatusEnum { + NOT_INITIALIZED = 'not_initialized', + PENDING = 'pending', + COMPLETED = 'completed' +} + +export const websocketConnection: { + instance: Socket | null; + // Use the connection status to avoid multiple websocket connections + status: WebsocketConnectionStatusEnum; +} = { + instance: null, + status: WebsocketConnectionStatusEnum.NOT_INITIALIZED +}; diff --git a/src/core/methods/login/helpers/getCallbackUrl.ts b/src/core/methods/login/helpers/getCallbackUrl.ts deleted file mode 100644 index fb84905..0000000 --- a/src/core/methods/login/helpers/getCallbackUrl.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { getWindowLocation } from 'utils/window/getWindowLocation'; - -export function getCallbackUrl() { - const { origin, pathname } = getWindowLocation(); - return encodeURIComponent(`${origin}${pathname}`); -} diff --git a/src/core/methods/login/helpers/getLoginService.ts b/src/core/methods/login/helpers/getLoginService.ts deleted file mode 100644 index 6cf47f3..0000000 --- a/src/core/methods/login/helpers/getLoginService.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Address, SignableMessage } from '@multiversx/sdk-core'; -import { nativeAuth } from 'services/nativeAuth'; -import { buildNativeAuthConfig } from 'services/nativeAuth/methods'; -import { networkSelector, tokenLoginSelector } from 'store/selectors'; -import { getState } from 'store/store'; -import { OnProviderLoginType } from 'types/login.types'; -import { getAccount } from '../../account/getAccount'; -import { setTokenLogin } from 'store/actions/loginInfo/loginInfoActions'; -import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; - -const getApiAddress = ( - apiAddress: string, - config?: OnProviderLoginType['nativeAuth'] -) => { - if (!config) { - return null; - } - if (config === true) { - return apiAddress; - } - return config.apiAddress ?? apiAddress; -}; - -export const getLoginService = (config?: OnProviderLoginType['nativeAuth']) => { - const network = networkSelector(getState()); - - const tokenLogin = tokenLoginSelector(getState()); - let tokenRef = tokenLogin?.loginToken; - - const apiAddress = getApiAddress(network.apiAddress, config); - - const configuration = buildNativeAuthConfig({ - ...(config === true ? {} : config), - ...(apiAddress ? { apiAddress } : {}) - }); - - const hasNativeAuth = Boolean(config); - - const client = nativeAuth(configuration); - - const setLoginToken = (loginToken: string) => { - tokenRef = loginToken; - - setTokenLogin({ - ...tokenLogin, - loginToken, - ...(apiAddress ? { nativeAuthConfig: configuration } : {}) - }); - }; - - const getNativeAuthLoginToken = () => { - try { - return client.initialize(); - } catch (error) { - console.error('Unable to get block. Login failed.', error); - return; - } - }; - - const setTokenLoginInfo = ({ - address, - signature - }: { - address: string; - signature: string; - }) => { - const loginToken = tokenRef; - - if (!loginToken) { - throw 'Token not found. Call `setLoginToken` first.'; - } - - if (!hasNativeAuth) { - setTokenLogin({ - loginToken, - signature - }); - - return; - } - - const nativeAuthToken = client.getToken({ - address, - token: loginToken, - signature - }); - - setTokenLogin({ - loginToken, - signature, - nativeAuthToken, - ...(apiAddress ? { nativeAuthConfig: configuration } : {}) - }); - return nativeAuthToken; - }; - - const refreshNativeAuthTokenLogin = async ({ - signMessageCallback, - nativeAuthClientConfig - }: { - signMessageCallback: ( - messageToSign: SignableMessage, - options: Record - ) => Promise; - nativeAuthClientConfig?: NativeAuthConfigType; - }) => { - const { address } = getAccount(); - - const nativeAuthClient = nativeAuth( - nativeAuthClientConfig || configuration - ); - - const loginToken = await nativeAuthClient.initialize({ - noCache: Boolean(nativeAuthClientConfig) - }); - - tokenRef = loginToken; - if (!loginToken) { - return; - } - const messageToSign = new SignableMessage({ - address: new Address(address), - message: Buffer.from(`${address}${loginToken}`) - }); - const signedMessage = await signMessageCallback(messageToSign, {}); - const nativeAuthToken = setTokenLoginInfo({ - address, - signature: signedMessage.getSignature().toString('hex') - }); - - return nativeAuthToken; - }; - - return { - configuration, - setLoginToken, - getNativeAuthLoginToken, - setTokenLoginInfo, - refreshNativeAuthTokenLogin - }; -}; diff --git a/src/core/methods/login/login.ts b/src/core/methods/login/login.ts deleted file mode 100644 index fb064f0..0000000 --- a/src/core/methods/login/login.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { nativeAuth } from 'services/nativeAuth'; -import { setAccount, setAddress } from 'store/actions/account'; -import { - setProviderType, - setTokenLogin -} from 'store/actions/loginInfo/loginInfoActions'; -import { setAccountProvider } from 'core/providers/accountProvider'; -import { - IProvider, - IProviderFactory -} from 'core/providers/types/providerFactory.types'; -import { ProviderFactory } from 'core/providers/ProviderFactory'; -import { nativeAuthConfigSelector } from 'store/selectors'; -import { getState } from 'store/store'; -import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; -import { getIsLoggedIn } from 'core/methods/account/getIsLoggedIn'; -import { getAddress } from 'core/methods/account/getAddress'; -import { loginAction, logoutAction } from 'store/actions'; -import { impersonateAccount } from './helpers/impersonateAccount'; -import { SECOND_LOGIN_ATTEMPT_ERROR } from 'constants/errorMessages.constants'; -import { getCallbackUrl } from './helpers/getCallbackUrl'; - -async function loginWithoutNativeToken(provider: IProvider) { - await provider.login?.({ - callbackUrl: getCallbackUrl() - }); - - const address = await provider.getAddress?.(); - - if (!address) { - throw new Error('Address not found'); - } - - setAddress(address); - - return { - address - }; -} - -async function tryImpersonateAccount({ - loginToken, - extraInfoData, - address, - provider -}: { - loginToken: string; - extraInfoData: { - multisig?: string; - impersonate?: string; - }; - address: string; - provider: IProvider; -}) { - return await impersonateAccount({ - loginToken, - extraInfoData, - address, - provider - }); -} - -async function loginWithNativeToken( - provider: IProvider, - nativeAuthConfig: NativeAuthConfigType -) { - const nativeAuthClient = nativeAuth(nativeAuthConfig); - - const loginToken = await nativeAuthClient.initialize({ - noCache: true - }); - - const loginResult = await provider.login?.({ - callbackUrl: getCallbackUrl(), - token: loginToken - }); - - const address = provider.getAddress - ? // TODO check why on the second login the address is fetched asynchronously (looks like the crosswindow provider has getAddress as an async function) - await provider.getAddress() - : loginResult?.address; - const signature = provider.getTokenLoginSignature - ? provider.getTokenLoginSignature() - : loginResult?.signature; - - if (!address) { - console.warn('Login cancelled.'); - return null; - } - - if (!signature) { - console.error('Failed to sign login token'); - return null; - } - - const nativeAuthToken = nativeAuthClient.getToken({ - address, - token: loginToken, - signature - }); - - setTokenLogin({ - loginToken, - signature, - nativeAuthToken - }); - loginAction({ - address, - providerType: provider.getType() - }); - - const impersonationDetails = await tryImpersonateAccount({ - loginToken, - extraInfoData: { - multisig: loginResult?.multisig, - impersonate: loginResult?.impersonate - }, - address, - provider - }); - - if (impersonationDetails.account) { - setAccount(impersonationDetails.account); - } else { - logoutAction(); - console.error('Failed to fetch account'); - throw new Error('Failed to fetch account'); - } - - return { - address: impersonationDetails?.address || address, - signature, - nativeAuthToken, - loginToken: impersonationDetails?.modifiedLoginToken || loginToken, - nativeAuthConfig - }; -} - -export const login = async ({ - providerConfig -}: { - providerConfig: IProviderFactory; -}) => { - const loggedIn = getIsLoggedIn(); - - if (loggedIn) { - console.warn('Already logged in with:', getAddress()); - throw new Error(SECOND_LOGIN_ATTEMPT_ERROR); - } - - const factory = new ProviderFactory(); - const provider = await factory.create(providerConfig); - - if (!provider) { - throw new Error('Provider not found'); - } - - await provider.init?.(); - setAccountProvider(provider); - setProviderType(providerConfig.type); - - const nativeAuthConfig = nativeAuthConfigSelector(getState()); - - if (nativeAuthConfig) { - return await loginWithNativeToken(provider, nativeAuthConfig); - } - - return await loginWithoutNativeToken(provider); -}; diff --git a/src/core/methods/network/getEgldLabel.ts b/src/core/methods/network/getEgldLabel.ts new file mode 100644 index 0000000..4cf0398 --- /dev/null +++ b/src/core/methods/network/getEgldLabel.ts @@ -0,0 +1,6 @@ +import { networkSelector } from 'store/selectors'; +import { getState } from 'store/store'; + +export function getEgldLabel(state = getState()) { + return networkSelector(state).egldLabel; +} diff --git a/src/core/methods/trackTransactions/helpers/checkTransactionStatus/checkBatch.ts b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/checkBatch.ts new file mode 100644 index 0000000..1fbbb61 --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/checkBatch.ts @@ -0,0 +1,184 @@ +import { getTransactionsByHashes } from 'apiCalls/transactions/getTransactionsByHashes'; +import { + updateTrackedTransactionStatus, + updateTrackedTransactionsSession +} from 'store/actions/trackedTransactions/trackedTransactionsActions'; +import { getIsTransactionFailed } from 'store/actions/transactions/transactionStateByStatus'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; +import { ServerTransactionType } from 'types/serverTransactions.types'; +import { + GetTransactionsByHashesReturnType, + SignedTransactionType +} from 'types/transactions.types'; +import { refreshAccount } from 'utils/account'; + +import { getPendingTransactions } from './getPendingTransactions'; +import { manageFailedTransactions } from './manageFailedTransactions'; +import { TransactionsTrackerType } from '../../trackTransactions.types'; + +export interface TransactionStatusTrackerPropsType + extends TransactionsTrackerType { + sessionId: string; + transactionBatch: SignedTransactionType[]; + shouldRefreshBalance?: boolean; + isSequential?: boolean; +} + +interface RetriesType { + [hash: string]: number; +} + +const retries: RetriesType = {}; +const timeouts: string[] = []; + +interface ManageTransactionType { + serverTransaction: GetTransactionsByHashesReturnType[0]; + sessionId: string; + shouldRefreshBalance?: boolean; + isSequential?: boolean; +} + +function manageTransaction({ + serverTransaction, + sessionId, + shouldRefreshBalance, + isSequential +}: ManageTransactionType) { + const { + hash, + status, + inTransit, + results, + invalidTransaction, + hasStatusChanged + } = serverTransaction; + try { + if (timeouts.includes(hash)) { + return; + } + + const retriesForThisHash = retries[hash]; + if (retriesForThisHash > 30) { + // consider transaction as stuck after 1 minute + updateTrackedTransactionsSession({ + sessionId, + status: TransactionBatchStatusesEnum.timedOut + }); + return; + } + + if ( + (invalidTransaction && !isSequential) || + status === TransactionBatchStatusesEnum.sent + ) { + retries[hash] = retries[hash] ? retries[hash] + 1 : 1; + return; + } + + // The tx is from a sequential batch. + // If the transactions before this are not successful then it means that no other tx will be processed + if (isSequential && !status) { + updateTrackedTransactionStatus({ + sessionId, + status, + transactionHash: hash, + inTransit, + serverTransaction: serverTransaction as unknown as ServerTransactionType + }); + return; + } + + if (hasStatusChanged) { + updateTrackedTransactionStatus({ + sessionId, + status, + transactionHash: hash, + inTransit, + serverTransaction: serverTransaction as unknown as ServerTransactionType + }); + } + + // if set to true will trigger a balance refresh after each iteration + if (!shouldRefreshBalance) { + refreshAccount(); + } + + if (getIsTransactionFailed(status)) { + manageFailedTransactions({ sessionId, hash, results }); + } + } catch (error) { + console.error(error); + updateTrackedTransactionsSession({ + sessionId, + status: TransactionBatchStatusesEnum.timedOut + }); + } +} + +export async function checkBatch({ + sessionId, + transactionBatch: transactions, + getTransactionsByHash = getTransactionsByHashes, + shouldRefreshBalance, + isSequential, + onSuccess, + onFail +}: TransactionStatusTrackerPropsType) { + try { + if (transactions == null) { + return; + } + + const pendingTransactions = getPendingTransactions(transactions, timeouts); + + const serverTransactions = await getTransactionsByHash(pendingTransactions); + + for (const serverTransaction of serverTransactions) { + manageTransaction({ + serverTransaction, + sessionId, + shouldRefreshBalance, + isSequential + }); + } + + const hasCompleted = serverTransactions.every( + (tx) => tx.status !== TransactionServerStatusesEnum.pending + ); + + // Call the onSuccess or onFail callback only if the transactions are sent normally (not using batch transactions mechanism). + // The batch transactions mechanism will call the callbacks separately. + + // TODO: check grouping and sequential transactions + if (hasCompleted /* && !customTransactionInformation?.grouping */) { + const isSuccessful = serverTransactions.every( + (tx) => tx.status === TransactionServerStatusesEnum.success + ); + + if (isSuccessful) { + updateTrackedTransactionsSession({ + sessionId, + status: TransactionBatchStatusesEnum.success + }); + return onSuccess?.(sessionId); + } + + const isFailed = serverTransactions.some( + (tx) => tx.status === TransactionServerStatusesEnum.fail + ); + + if (isFailed) { + updateTrackedTransactionsSession({ + sessionId, + status: TransactionBatchStatusesEnum.fail + }); + return onFail?.(sessionId); + } + } + } catch (error) { + console.error(error); + } +} diff --git a/src/core/methods/trackTransactions/helpers/checkTransactionStatus/checkTransactionStatus.ts b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/checkTransactionStatus.ts new file mode 100644 index 0000000..86eb92f --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/checkTransactionStatus.ts @@ -0,0 +1,28 @@ +import { refreshAccount } from 'utils/account'; +import { checkBatch } from './checkBatch'; +import { TransactionsTrackerType } from '../../trackTransactions.types'; +import { getPendingStoreTrackedTransactions } from '../getPendingStoreTrackedTransactions'; + +export async function checkTransactionStatus( + props: TransactionsTrackerType & { + shouldRefreshBalance?: boolean; + } +) { + const { pendingTrackedSessions: pendingSessions } = + getPendingStoreTrackedTransactions(); + if (Object.keys(pendingSessions).length > 0) { + for (const [sessionId, { transactions }] of Object.entries( + pendingSessions + )) { + await checkBatch({ + sessionId, + transactionBatch: transactions, + ...props + }); + } + } + + if (props.shouldRefreshBalance) { + await refreshAccount(); + } +} diff --git a/src/core/methods/trackTransactions/helpers/checkTransactionStatus/getPendingTransactions.ts b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/getPendingTransactions.ts new file mode 100644 index 0000000..a7f1747 --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/getPendingTransactions.ts @@ -0,0 +1,30 @@ +import { getIsTransactionPending } from 'store/actions/transactions/transactionStateByStatus'; +import { SignedTransactionType } from 'types/transactions.types'; + +export interface PendingTransactionType { + hash: string; + previousStatus: string; +} + +export function getPendingTransactions( + transactions: SignedTransactionType[], + timedOutHashes: string[] +): PendingTransactionType[] { + const pendingTransactions = transactions.reduce( + (acc: PendingTransactionType[], { status, hash }) => { + if ( + hash != null && + !timedOutHashes.includes(hash) && + getIsTransactionPending(status) + ) { + acc.push({ + hash, + previousStatus: status + }); + } + return acc; + }, + [] + ); + return pendingTransactions; +} diff --git a/src/core/methods/trackTransactions/helpers/checkTransactionStatus/index.ts b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/index.ts new file mode 100644 index 0000000..11b692e --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/index.ts @@ -0,0 +1 @@ +export * from './checkTransactionStatus'; diff --git a/src/core/methods/trackTransactions/helpers/checkTransactionStatus/manageFailedTransactions.ts b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/manageFailedTransactions.ts new file mode 100644 index 0000000..4654e42 --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/checkTransactionStatus/manageFailedTransactions.ts @@ -0,0 +1,41 @@ +import { + updateTrackedTransactionStatus, + updateTrackedTransactionsSession +} from 'store/actions/trackedTransactions/trackedTransactionsActions'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; +import { + ResultType, + ServerTransactionType +} from 'types/serverTransactions.types'; + +export function manageFailedTransactions({ + results, + hash, + sessionId +}: { + results: ResultType[]; + hash: string; + sessionId: string; +}) { + const resultWithError = results?.find( + (scResult) => scResult?.returnMessage !== '' + ); + + updateTrackedTransactionStatus({ + transactionHash: hash, + sessionId, + status: TransactionServerStatusesEnum.fail, + errorMessage: resultWithError?.returnMessage, + inTransit: false, + serverTransaction: resultWithError as unknown as ServerTransactionType + }); + + updateTrackedTransactionsSession({ + sessionId, + status: TransactionBatchStatusesEnum.fail, + errorMessage: resultWithError?.returnMessage + }); +} diff --git a/src/core/methods/trackTransactions/helpers/getPendingStoreTrackedTransactions.ts b/src/core/methods/trackTransactions/helpers/getPendingStoreTrackedTransactions.ts new file mode 100644 index 0000000..f0fc62e --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/getPendingStoreTrackedTransactions.ts @@ -0,0 +1,26 @@ +import { + pendingTrackedSessionsSelector, + pendingTrackedTransactionsSelector +} from 'store/selectors/trackedTransactionsSelector'; +import { TrackedTransactionsSliceType } from 'store/slices/trackedTransactions/trackedTransactionsSlice.types'; +import { getState } from 'store/store'; +import { SignedTransactionType } from 'types/transactions.types'; + +export interface UseGetPendingTrackedTransactionsReturnType { + pendingTrackedTransactions: SignedTransactionType[]; + pendingTrackedSessions: TrackedTransactionsSliceType; + hasPendingTrackedTransactions: boolean; +} + +export function getPendingStoreTrackedTransactions(): UseGetPendingTrackedTransactionsReturnType { + const pendingTrackedTransactions = + pendingTrackedTransactionsSelector(getState()); + const pendingTrackedSessions = pendingTrackedSessionsSelector(getState()); + const hasPendingTrackedTransactions = pendingTrackedTransactions.length > 0; + + return { + pendingTrackedTransactions, + pendingTrackedSessions, + hasPendingTrackedTransactions + }; +} diff --git a/src/core/methods/trackTransactions/helpers/getPollingInterval.ts b/src/core/methods/trackTransactions/helpers/getPollingInterval.ts new file mode 100644 index 0000000..a575322 --- /dev/null +++ b/src/core/methods/trackTransactions/helpers/getPollingInterval.ts @@ -0,0 +1,14 @@ +import { TRANSACTIONS_STATUS_POLLING_INTERVAL_MS } from 'constants/transactions.constants'; +import { roundDurationSelectorSelector } from 'store/selectors'; +import { getState } from 'store/store'; + +export function getPollingInterval() { + const roundDuration = roundDurationSelectorSelector(getState()); + + if (!roundDuration) { + return TRANSACTIONS_STATUS_POLLING_INTERVAL_MS; + } + + // Polling interval should not be less than 1s + return Math.max(1000, roundDuration / 2); +} diff --git a/src/core/methods/trackTransactions/trackTransactions.ts b/src/core/methods/trackTransactions/trackTransactions.ts new file mode 100644 index 0000000..ee3383b --- /dev/null +++ b/src/core/methods/trackTransactions/trackTransactions.ts @@ -0,0 +1,61 @@ +import { websocketEventSelector } from 'store/selectors/accountSelectors'; +import { getStore } from 'store/store'; +import { checkTransactionStatus } from './helpers/checkTransactionStatus'; +import { getPollingInterval } from './helpers/getPollingInterval'; +import { + websocketConnection, + WebsocketConnectionStatusEnum +} from '../initApp/websocket/websocket.constants'; + +/** + * Tracks transactions using websocket or polling + * @returns cleanup function + */ +export async function trackTransactions() { + const store = getStore(); + const pollingInterval = getPollingInterval(); + // eslint-disable-next-line no-undef + let pollingIntervalTimer: NodeJS.Timeout | null = null; + let timestamp = websocketEventSelector(store.getState())?.timestamp; + + const isWebsocketCompleted = + websocketConnection.status === WebsocketConnectionStatusEnum.COMPLETED; + + const recheckStatus = () => { + checkTransactionStatus({ + shouldRefreshBalance: isWebsocketCompleted + }); + }; + + recheckStatus(); + + if (isWebsocketCompleted) { + // Do not set polling interval if websocket is complete + if (pollingIntervalTimer) { + clearInterval(pollingIntervalTimer); + pollingIntervalTimer = null; + } + store.subscribe(async ({ account: { websocketEvent } }) => { + if (websocketEvent?.message && timestamp !== websocketEvent.timestamp) { + timestamp = websocketEvent.timestamp; + recheckStatus(); + } + }); + } else { + // Set polling interval if websocket is not complete and no existing interval is set + if (!pollingIntervalTimer) { + pollingIntervalTimer = setInterval(recheckStatus, pollingInterval); + } + } + + function cleanup() { + if (pollingIntervalTimer) { + clearInterval(pollingIntervalTimer); + pollingIntervalTimer = null; + } + } + + return { + cleanup + }; +} diff --git a/src/core/methods/trackTransactions/trackTransactions.types.ts b/src/core/methods/trackTransactions/trackTransactions.types.ts new file mode 100644 index 0000000..fb6eba6 --- /dev/null +++ b/src/core/methods/trackTransactions/trackTransactions.types.ts @@ -0,0 +1,7 @@ +import { GetTransactionsByHashesType } from 'types/transactions.types'; + +export interface TransactionsTrackerType { + getTransactionsByHash?: GetTransactionsByHashesType; + onSuccess?: (sessionId: string | null) => void; + onFail?: (sessionId: string | null, errorMessage?: string) => void; +} diff --git a/src/core/providers/DappProvider/DappProvider.ts b/src/core/providers/DappProvider/DappProvider.ts new file mode 100644 index 0000000..803851b --- /dev/null +++ b/src/core/providers/DappProvider/DappProvider.ts @@ -0,0 +1,81 @@ +import { Message } from '@multiversx/sdk-core/out/message'; +import { Transaction } from '@multiversx/sdk-core/out/transaction'; +import { IProvider } from '../types/providerFactory.types'; +import { login } from './helpers/login/login'; +import { logout } from './helpers/logout/logout'; +import { signMessage } from './helpers/signMessage/signMessage'; +import { + verifyMessage, + VerifyMessageReturnType +} from './helpers/signMessage/verifyMessage'; +import { + signTransactionsWithProvider, + SignTransactionsOptionsType +} from './helpers/signTransactions/signTransactionsWithProvider'; + +export class DappProvider { + private provider: IProvider; + + constructor(provider: IProvider) { + this.provider = provider; + } + + init() { + return this.provider.init(); + } + + async login() { + return await login(this.provider); + } + + async logout( + options = { + shouldBroadcastLogoutAcrossTabs: true, + hasConsentPopup: false + } + ) { + return await logout({ provider: this.provider, options }); + } + + setShouldShowConsentPopup(shouldShow: boolean) { + this.provider.setShouldShowConsentPopup?.(shouldShow); + } + + getType() { + return this.provider.getType(); + } + + getProvider() { + return this.provider; + } + + async signTransactions( + transactions: Transaction[], + options?: SignTransactionsOptionsType + ): Promise { + const signedTransactions = await signTransactionsWithProvider({ + provider: this.provider, + transactions, + options + }); + return signedTransactions; + } + + async signMessage( + message: Message, + options?: { + hasConsentPopup?: boolean; + } + ): Promise { + const signedMessage = await signMessage({ + provider: this.provider, + message, + options + }); + return signedMessage; + } + + verifyMessage(signedMessage: string): VerifyMessageReturnType { + return verifyMessage(signedMessage); + } +} diff --git a/src/core/methods/login/helpers/impersonateAccount.ts b/src/core/providers/DappProvider/helpers/login/helpers/extractAccountFromToken.ts similarity index 57% rename from src/core/methods/login/helpers/impersonateAccount.ts rename to src/core/providers/DappProvider/helpers/login/helpers/extractAccountFromToken.ts index 0a3be16..e9802fa 100644 --- a/src/core/methods/login/helpers/impersonateAccount.ts +++ b/src/core/providers/DappProvider/helpers/login/helpers/extractAccountFromToken.ts @@ -1,17 +1,12 @@ -import { setAccount } from 'store/actions/account'; -import { setLoginToken } from 'store/actions/loginInfo/loginInfoActions'; +import { getLatestNonce } from 'core/methods/account/getLatestNonce'; import { IProvider } from 'core/providers/types/providerFactory.types'; import { loginAction } from 'store/actions'; +import { setAccount } from 'store/actions/account'; +import { setLoginToken } from 'store/actions/loginInfo/loginInfoActions'; import { AccountType } from 'types/account.types'; -import { getImpersonatedAccountDetails } from './getImpersonatedAccountDetails'; -import { getLatestNonce } from 'core/methods/account/getLatestNonce'; +import { getAccountFromToken } from './getAccountFromToken'; -export async function impersonateAccount({ - loginToken, - extraInfoData, - address, - provider -}: { +interface IExtractAccountFromTokenProps { loginToken: string; extraInfoData: { multisig?: string; @@ -19,34 +14,42 @@ export async function impersonateAccount({ }; address: string; provider: IProvider; -}) { - const impersonationDetails = await getImpersonatedAccountDetails({ +} + +export async function extractAccountFromToken({ + loginToken, + extraInfoData, + address, + provider +}: IExtractAccountFromTokenProps) { + const accountDetails = await getAccountFromToken({ originalLoginToken: loginToken, extraInfoData, address }); - if (impersonationDetails.modifiedLoginToken) { - setLoginToken(impersonationDetails.modifiedLoginToken); + if (accountDetails.modifiedLoginToken) { + setLoginToken(accountDetails.modifiedLoginToken); } - if (impersonationDetails.account) { + if (accountDetails.account) { + // TODO remove this as is already done before this function is called loginAction({ - address: impersonationDetails.address, + address: accountDetails.address, providerType: provider.getType() }); const newAccount: AccountType = { - ...impersonationDetails.account, - nonce: getLatestNonce(impersonationDetails.account) + ...accountDetails.account, + nonce: getLatestNonce(accountDetails.account) }; setAccount(newAccount); return { - ...impersonationDetails, + ...accountDetails, account: newAccount }; } - return impersonationDetails; + return accountDetails; } diff --git a/src/core/methods/login/helpers/getImpersonatedAccountDetails.ts b/src/core/providers/DappProvider/helpers/login/helpers/getAccountFromToken.ts similarity index 70% rename from src/core/methods/login/helpers/getImpersonatedAccountDetails.ts rename to src/core/providers/DappProvider/helpers/login/helpers/getAccountFromToken.ts index 3381c26..d9ef9d7 100644 --- a/src/core/methods/login/helpers/getImpersonatedAccountDetails.ts +++ b/src/core/providers/DappProvider/helpers/login/helpers/getAccountFromToken.ts @@ -1,7 +1,7 @@ -import { getAccount } from 'utils/account/getAccount'; +import { fetchAccount } from 'utils/account/fetchAccount'; import { getModifiedLoginToken } from './getModifiedLoginToken'; -interface GetImpersonatedAccountDetailsType { +interface GetAccountFromTokenType { address: string; originalLoginToken?: string; extraInfoData: { @@ -10,11 +10,11 @@ interface GetImpersonatedAccountDetailsType { }; } -export const getImpersonatedAccountDetails = async ({ +export async function getAccountFromToken({ originalLoginToken, extraInfoData, address -}: GetImpersonatedAccountDetailsType) => { +}: GetAccountFromTokenType) { const modifiedLoginToken = await getModifiedLoginToken({ loginToken: originalLoginToken, extraInfoData @@ -25,11 +25,11 @@ export const getImpersonatedAccountDetails = async ({ const accountAddress = modifiedLoginToken != null ? tokenAddress : address; - const account = await getAccount(accountAddress); + const account = await fetchAccount(accountAddress); return { account, address: accountAddress, modifiedLoginToken }; -}; +} diff --git a/src/core/methods/login/helpers/getModifiedLoginToken.ts b/src/core/providers/DappProvider/helpers/login/helpers/getModifiedLoginToken.ts similarity index 92% rename from src/core/methods/login/helpers/getModifiedLoginToken.ts rename to src/core/providers/DappProvider/helpers/login/helpers/getModifiedLoginToken.ts index 3c92e32..ede4957 100644 --- a/src/core/methods/login/helpers/getModifiedLoginToken.ts +++ b/src/core/providers/DappProvider/helpers/login/helpers/getModifiedLoginToken.ts @@ -10,10 +10,10 @@ export interface GetMultiSigLoginTokenType { }; } -export const getModifiedLoginToken = async ({ +export async function getModifiedLoginToken({ loginToken, extraInfoData -}: GetMultiSigLoginTokenType) => { +}: GetMultiSigLoginTokenType) { if (loginToken == null || Object.keys(extraInfoData).length === 0) { return null; } @@ -40,4 +40,4 @@ export const getModifiedLoginToken = async ({ }); return tokenLogin; -}; +} diff --git a/src/core/methods/login/helpers/tests/getModifiedLoginToken.test.ts b/src/core/providers/DappProvider/helpers/login/helpers/tests/getModifiedLoginToken.test.ts similarity index 100% rename from src/core/methods/login/helpers/tests/getModifiedLoginToken.test.ts rename to src/core/providers/DappProvider/helpers/login/helpers/tests/getModifiedLoginToken.test.ts diff --git a/src/core/providers/DappProvider/helpers/login/login.ts b/src/core/providers/DappProvider/helpers/login/login.ts new file mode 100644 index 0000000..d03b0f5 --- /dev/null +++ b/src/core/providers/DappProvider/helpers/login/login.ts @@ -0,0 +1,104 @@ +import { registerWebsocketListener } from 'core/methods/initApp/websocket/registerWebsocket'; +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { nativeAuth } from 'services/nativeAuth'; +import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; +import { logoutAction } from 'store/actions'; +import { setAddress } from 'store/actions/account'; +import { setTokenLogin } from 'store/actions/loginInfo/loginInfoActions'; +import { nativeAuthConfigSelector } from 'store/selectors'; +import { getState } from 'store/store'; +import { extractAccountFromToken } from './helpers/extractAccountFromToken'; + +async function loginWithoutNativeToken(provider: IProvider) { + await provider.login(); + + // TODO update this when the provider will be standardized + const address = await provider.getAddress?.(); + + if (!address) { + throw new Error('Address not found'); + } + + setAddress(address); + + return { + address + }; +} + +async function loginWithNativeToken( + provider: IProvider, + nativeAuthConfig: NativeAuthConfigType +) { + const nativeAuthClient = nativeAuth(nativeAuthConfig); + + const loginToken = await nativeAuthClient.initialize({ + noCache: true + }); + + const { address, signature, ...loginResult } = await provider.login({ + token: loginToken + }); + + if (!address) { + console.warn('Login cancelled.'); + return null; + } + + if (!signature) { + console.error('Failed to sign login token'); + return null; + } + + const nativeAuthToken = nativeAuthClient.getToken({ + address, + token: loginToken, + signature + }); + + setTokenLogin({ + loginToken, + signature, + nativeAuthToken + }); + + const accountDetails = await extractAccountFromToken({ + loginToken, + extraInfoData: { + multisig: loginResult?.multisig, + impersonate: loginResult?.impersonate + }, + address, + provider + }); + + if (!accountDetails.account) { + logoutAction(); + console.error('Failed to fetch account'); + throw new Error('Failed to fetch account'); + } + + await registerWebsocketListener(); + + return { + address: accountDetails?.address || address, + signature, + nativeAuthToken, + loginToken: accountDetails?.modifiedLoginToken || loginToken, + nativeAuthConfig + }; +} + +export async function login(provider: IProvider) { + const nativeAuthConfig = nativeAuthConfigSelector(getState()); + + if (nativeAuthConfig) { + return await loginWithNativeToken(provider, nativeAuthConfig); + } + + const data = await loginWithoutNativeToken(provider); + + await registerWebsocketListener(); + + return data; +} diff --git a/src/core/methods/logout/logout.ts b/src/core/providers/DappProvider/helpers/logout/logout.ts similarity index 75% rename from src/core/methods/logout/logout.ts rename to src/core/providers/DappProvider/helpers/logout/logout.ts index b29a2bc..73f3cc9 100644 --- a/src/core/methods/logout/logout.ts +++ b/src/core/providers/DappProvider/helpers/logout/logout.ts @@ -1,11 +1,12 @@ +import { getAddress } from 'core/methods/account/getAddress'; +import { + IProvider, + ProviderTypeEnum +} from 'core/providers/types/providerFactory.types'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; import { storage } from 'storage'; import { localStorageKeys } from 'storage/local'; -import { getAddress } from '../account/getAddress'; -import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; import { logoutAction } from 'store/actions/sharedActions/sharedActions'; -import { getAccountProvider } from 'core/providers/accountProvider'; -import { getProviderType } from 'core/providers/helpers/utils'; -import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; const broadcastLogoutAcrossTabs = (address: string) => { const storedData = storage.local?.getItem(localStorageKeys.logoutEvent); @@ -33,15 +34,19 @@ export type LogoutPropsType = { hasConsentPopup?: boolean; }; -export async function logout( +interface IProviderLogout { + provider: IProvider; + options?: LogoutPropsType; +} + +export async function logout({ + provider, options = { shouldBroadcastLogoutAcrossTabs: true, hasConsentPopup: false } -) { +}: IProviderLogout) { let address = getAddress(); - const provider = getAccountProvider(); - const providerType = getProviderType(provider); if (options.shouldBroadcastLogoutAcrossTabs) { broadcastLogoutAcrossTabs(address); @@ -52,7 +57,7 @@ export async function logout( if ( options.hasConsentPopup && - providerType === ProviderTypeEnum.crossWindow + provider.getType() === ProviderTypeEnum.crossWindow ) { (provider as unknown as CrossWindowProvider).setShouldShowConsentPopup( true diff --git a/src/core/providers/DappProvider/helpers/signMessage/getVerifier.ts b/src/core/providers/DappProvider/helpers/signMessage/getVerifier.ts new file mode 100644 index 0000000..7e17920 --- /dev/null +++ b/src/core/providers/DappProvider/helpers/signMessage/getVerifier.ts @@ -0,0 +1,8 @@ +import { Address } from '@multiversx/sdk-core/out'; +import { UserPublicKey, UserVerifier } from '@multiversx/sdk-wallet'; + +export function getVerifier(address: string) { + const publicKey = new UserPublicKey(Address.fromString(address).pubkey()); + + return new UserVerifier(publicKey); +} diff --git a/src/core/providers/DappProvider/helpers/signMessage/signMessage.ts b/src/core/providers/DappProvider/helpers/signMessage/signMessage.ts new file mode 100644 index 0000000..ed21f05 --- /dev/null +++ b/src/core/providers/DappProvider/helpers/signMessage/signMessage.ts @@ -0,0 +1,42 @@ +import { Message, Address } from '@multiversx/sdk-core'; +import { getAddress } from 'core/methods/account/getAddress'; +import { + IProvider, + ProviderTypeEnum +} from 'core/providers/types/providerFactory.types'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; +import { Nullable } from 'types'; + +export type SignMessageType = { + provider: IProvider; + message: Message; + options?: { + hasConsentPopup?: boolean; + }; +}; + +export async function signMessage({ + message, + provider, + options +}: SignMessageType): Promise> { + const address = getAddress(); + + const messageToSign = new Message({ + address: new Address(address), + data: message.data + }); + + if ( + options?.hasConsentPopup && + provider.getType() === ProviderTypeEnum.crossWindow + ) { + (provider as unknown as CrossWindowProvider).setShouldShowConsentPopup( + true + ); + } + + const signedMessage = await provider.signMessage(messageToSign, options); + + return signedMessage; +} diff --git a/src/core/providers/DappProvider/helpers/signMessage/tests/verifyMessage.test.ts b/src/core/providers/DappProvider/helpers/signMessage/tests/verifyMessage.test.ts new file mode 100644 index 0000000..1dc2800 --- /dev/null +++ b/src/core/providers/DappProvider/helpers/signMessage/tests/verifyMessage.test.ts @@ -0,0 +1,23 @@ +import { verifyMessage } from '../verifyMessage'; + +jest.mock('../getVerifier', () => ({ + getVerifier: jest.fn().mockImplementation(() => ({ + verify: jest.fn().mockImplementation(() => true) + })) +})); + +describe('Verify Message test', () => { + const signature = + '{"address":"erd1wh9c0sjr2xn8hzf02lwwcr4jk2s84tat9ud2kaq6zr7xzpvl9l5q8awmex","message":"0x54455354","signature":"0xfd7578037cdaed106e04c437821828a78ac0eb93d42118b6c8a11510520400cfa4a06dfa446cd6437c0f91264675bd554cbcb2e0b08622e9f210772890f12d01","version":1,"signer":"ErdJS"}'; + + it('should verify message successfully', () => { + const { address, isVerified, message } = verifyMessage(signature); + + expect(address).toStrictEqual( + 'erd1wh9c0sjr2xn8hzf02lwwcr4jk2s84tat9ud2kaq6zr7xzpvl9l5q8awmex' + ); + + expect(isVerified).toStrictEqual(true); + expect(message).toStrictEqual('TEST'); + }); +}); diff --git a/src/core/providers/DappProvider/helpers/signMessage/verifyMessage.ts b/src/core/providers/DappProvider/helpers/signMessage/verifyMessage.ts new file mode 100644 index 0000000..ae8b263 --- /dev/null +++ b/src/core/providers/DappProvider/helpers/signMessage/verifyMessage.ts @@ -0,0 +1,44 @@ +import { Address, Message, MessageComputer } from '@multiversx/sdk-core/out'; +import { getVerifier } from './getVerifier'; + +export type VerifyMessageReturnType = { + isVerified: boolean; + message: string; + address: any; +}; + +export function verifyMessage(signedMessage: string): VerifyMessageReturnType { + try { + const { message, address, signature } = JSON.parse(signedMessage); + + const decodedMessage = Buffer.from(message.replace('0x', ''), 'hex'); + const decodedSignature = Buffer.from(signature.replace('0x', ''), 'hex'); + const bech32Address = new Address(address); + + const verifier = getVerifier(address); + + const messageComputer = new MessageComputer(); + + const msg = new Message({ + address: bech32Address, + data: decodedMessage, + signature: decodedSignature + }); + + const serializedMessage = messageComputer.computeBytesForVerifying(msg); + + const isVerified = verifier.verify(serializedMessage, decodedSignature); + + return { + isVerified, + message: decodedMessage.toString(), + address + }; + } catch { + return { + isVerified: false, + message: '', + address: '' + }; + } +} diff --git a/src/core/providers/DappProvider/helpers/signTransactions/signTransactionsWithProvider.ts b/src/core/providers/DappProvider/helpers/signTransactions/signTransactionsWithProvider.ts new file mode 100644 index 0000000..a6f573f --- /dev/null +++ b/src/core/providers/DappProvider/helpers/signTransactions/signTransactionsWithProvider.ts @@ -0,0 +1,50 @@ +import { + Address, + Transaction, + TransactionOptions, + TransactionVersion +} from '@multiversx/sdk-core/out'; +import { getAccount } from 'core/methods/account/getAccount'; +import { + IProvider, + ProviderTypeEnum +} from 'core/providers/types/providerFactory.types'; + +export type SignTransactionsOptionsType = { + skipGuardian?: boolean; +}; + +type SignTransactionsType = { + provider: IProvider; + transactions: Transaction[]; + options?: SignTransactionsOptionsType; +}; + +export async function signTransactionsWithProvider({ + provider, + transactions, + options = {} +}: SignTransactionsType): Promise { + const { isGuarded, activeGuardianAddress } = getAccount(); + const isLedger = provider.getType() === ProviderTypeEnum.ledger; + + const transactionsToSign = + activeGuardianAddress && isGuarded && !options.skipGuardian + ? transactions?.map((transaction) => { + transaction.setVersion(TransactionVersion.withTxOptions()); + const options = { + guarded: true, + ...(isLedger ? { hashSign: true } : {}) + }; + transaction.setOptions(TransactionOptions.withOptions(options)); + transaction.setGuardian(Address.fromBech32(activeGuardianAddress)); + + return transaction; + }) + : transactions; + + const signedTransactions: Transaction[] = + (await provider.signTransactions(transactionsToSign)) ?? []; + + return signedTransactions; +} diff --git a/src/core/providers/DappProvider/index.ts b/src/core/providers/DappProvider/index.ts new file mode 100644 index 0000000..233e0f2 --- /dev/null +++ b/src/core/providers/DappProvider/index.ts @@ -0,0 +1 @@ +export * from './DappProvider'; diff --git a/src/core/providers/ProviderFactory.ts b/src/core/providers/ProviderFactory.ts index 620b6ae..fc518bd 100644 --- a/src/core/providers/ProviderFactory.ts +++ b/src/core/providers/ProviderFactory.ts @@ -1,94 +1,103 @@ -import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; -import { ExtensionProvider } from '@multiversx/sdk-extension-provider'; +import { IframeLoginTypes } from '@multiversx/sdk-web-wallet-iframe-provider/out/constants'; +import { getAddress } from 'core/methods/account/getAddress'; import { + CrossWindowProviderStrategy, + ExtensionProviderStrategy, + IFrameProviderStrategy, + LedgerProviderStrategy, + WalletConnectProviderStrategy +} from 'core/providers/strategies'; +import { setProviderType } from 'store/actions/loginInfo/loginInfoActions'; +import { DappProvider } from './DappProvider/DappProvider'; +import { setAccountProvider } from './helpers/accountProvider'; +import { + ICustomProvider, IProvider, - IProviderConfig, IProviderFactory, ProviderTypeEnum } from './types/providerFactory.types'; -import { isBrowserWithPopupConfirmation } from '../../constants'; export class ProviderFactory { - public async create({ - type, - config, - customProvider - }: IProviderFactory): Promise { - let createdProvider: IProvider | undefined; + private static _customProviders: ICustomProvider[] = []; - switch (type) { - // case ProviderTypeEnum.iframe: { - // const provider = await ProviderFactory.getIframeProvider({ - // walletAddress, - // }); - // createdProvider = provider as unknown as IProvider; - // break; - // } + public static customProviders(providers: ICustomProvider[]) { + this._customProviders = providers; + } - case ProviderTypeEnum.extension: { - const provider = await this.getExtensionProvider(); - createdProvider = provider as unknown as IProvider; + public static async create({ + type + }: IProviderFactory): Promise { + let createdProvider: IProvider | null = null; - createdProvider.getAddress = () => { - return Promise.resolve(provider.account.address); - }; + switch (type) { + case ProviderTypeEnum.extension: { + const providerInstance = new ExtensionProviderStrategy(); + createdProvider = await providerInstance.createProvider(); - createdProvider.getTokenLoginSignature = () => { - return provider.account.signature; - }; + break; + } - createdProvider.getType = () => { - return ProviderTypeEnum.extension; - }; + case ProviderTypeEnum.crossWindow: { + const providerInstance = new CrossWindowProviderStrategy(); + createdProvider = await providerInstance.createProvider(); break; } - case ProviderTypeEnum.crossWindow: { - const { walletAddress } = config.network; + case ProviderTypeEnum.ledger: { + const providerInstance = new LedgerProviderStrategy(); + createdProvider = await providerInstance.createProvider(); - const provider = await this.getCrossWindowProvider({ - walletAddress + break; + } + + case ProviderTypeEnum.metamask: { + const providerInstance = new IFrameProviderStrategy({ + type: IframeLoginTypes.metamask }); - createdProvider = provider as unknown as IProvider; - createdProvider.getType = () => { - return ProviderTypeEnum.crossWindow; - }; + createdProvider = await providerInstance.createProvider(); break; } - case ProviderTypeEnum.custom: { - createdProvider = customProvider; + case ProviderTypeEnum.passkey: { + const providerInstance = new IFrameProviderStrategy({ + type: IframeLoginTypes.passkey + }); + createdProvider = await providerInstance.createProvider(); + break; } + case ProviderTypeEnum.walletConnect: { + const providerInstance = new WalletConnectProviderStrategy(); + createdProvider = await providerInstance.createProvider(); - default: break; - } + } - return createdProvider; - } + default: { + const address = getAddress(); - private async getCrossWindowProvider({ - walletAddress - }: Partial) { - // CrossWindowProvider.getInstance().clearInstance(); - const provider = CrossWindowProvider.getInstance(); - await provider.init(); - provider.setWalletUrl(String(walletAddress)); + for (const customProvider of this._customProviders) { + if (customProvider.type === type) { + createdProvider = await customProvider.constructor(address); + } + } + break; + } + } - if (isBrowserWithPopupConfirmation) { - provider.setShouldShowConsentPopup(true); + if (!createdProvider) { + throw new Error('Unable to create provider'); } - return provider; - } + createdProvider.getType = () => type; + const dappProvider = new DappProvider(createdProvider); + + setAccountProvider(dappProvider); + setProviderType(type as ProviderTypeEnum); - private async getExtensionProvider() { - const provider = ExtensionProvider.getInstance(); - await provider.init(); - return provider; + return dappProvider; } } diff --git a/src/core/providers/accountProvider.ts b/src/core/providers/accountProvider.ts deleted file mode 100644 index f1282f3..0000000 --- a/src/core/providers/accountProvider.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { emptyProvider } from './helpers/emptyProvider'; -import { IProvider } from 'core/providers/types/providerFactory.types'; - -export type ProvidersType = IProvider; - -let accountProvider: ProvidersType = emptyProvider; - -export function setAccountProvider( - provider: TProvider -) { - accountProvider = provider; -} - -export function getAccountProvider(): IProvider { - return (accountProvider as IProvider) || emptyProvider; -} diff --git a/src/core/providers/helpers/accountProvider.ts b/src/core/providers/helpers/accountProvider.ts new file mode 100644 index 0000000..d1c4a1d --- /dev/null +++ b/src/core/providers/helpers/accountProvider.ts @@ -0,0 +1,17 @@ +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { DappProvider } from '../DappProvider'; +import { emptyProvider } from './emptyProvider'; + +export type ProvidersType = IProvider; + +let accountProvider: DappProvider = new DappProvider(emptyProvider); + +export function setAccountProvider( + provider: TProvider +) { + accountProvider = provider; +} + +export function getAccountProvider(): DappProvider { + return (accountProvider as DappProvider) || emptyProvider; +} diff --git a/src/core/providers/helpers/emptyProvider.ts b/src/core/providers/helpers/emptyProvider.ts index b73c157..9e60996 100644 --- a/src/core/providers/helpers/emptyProvider.ts +++ b/src/core/providers/helpers/emptyProvider.ts @@ -1,11 +1,13 @@ -import { SignableMessage, Transaction } from '@multiversx/sdk-core'; -import { EngineTypes } from 'utils/walletconnect/__sdkWalletconnectProvider'; +import { Message, Transaction } from '@multiversx/sdk-core'; +import { + IDAppProviderAccount, + IDAppProviderOptions +} from '@multiversx/sdk-dapp-utils/out'; import { IProvider, ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; - -export const DAPP_INIT_ROUTE = '/dapp/init'; +import { EngineTypes } from 'utils/walletconnect/__sdkWalletconnectProvider'; const notInitializedError = (caller: string) => { return `Unable to perform ${caller}, Provider not initialized`; @@ -28,12 +30,21 @@ export class EmptyProvider implements IProvider { throw new Error(notInitializedError(`logout with options: ${options}`)); } + getAccount(): IDAppProviderAccount | null { + throw new Error(notInitializedError('unable to get account')); + } + setAccount(account: IDAppProviderAccount): void { + throw new Error( + notInitializedError(`unable to set account with: ${account}`) + ); + } + isInitialized(): boolean { return false; } - isConnected(): Promise { - return Promise.resolve(false); + isConnected(): boolean { + return false; } sendTransaction?< @@ -53,25 +64,25 @@ export class EmptyProvider implements IProvider { ): Promise { throw new Error( notInitializedError( - `signTransaction with transactions: ${transaction} options: ${options}` + `signTransaction with transactions: ${JSON.stringify(transaction)} options: ${options}` ) ); } signTransactions(transactions: T[]): Promise { throw new Error( - notInitializedError(`signTransactions with transactions: ${transactions}`) + notInitializedError( + `signTransactions with transactions: ${JSON.stringify(transactions)}` + ) ); } - signMessage( - message: T, - options: TOptions - ): Promise { + signMessage( + message: Message, + options?: IDAppProviderOptions + ): Promise { throw new Error( - notInitializedError( - `signTransactions with ${message} and options ${options}` - ) + notInitializedError(`signMessage with ${message} and options ${options}`) ); } @@ -102,7 +113,7 @@ export class EmptyProvider implements IProvider { } getTokenLoginSignature(): string | undefined { - throw new Error(notInitializedError(`getSignature`)); + throw new Error(notInitializedError('getSignature')); } getType(): ProviderTypeEnum { diff --git a/src/core/providers/helpers/restoreProvider.ts b/src/core/providers/helpers/restoreProvider.ts new file mode 100644 index 0000000..b7d7609 --- /dev/null +++ b/src/core/providers/helpers/restoreProvider.ts @@ -0,0 +1,22 @@ +import { providerTypeSelector } from 'store/selectors'; +import { getState } from 'store/store'; +import { setAccountProvider } from './accountProvider'; +import { ProviderFactory } from '../ProviderFactory'; + +export async function restoreProvider() { + const type = providerTypeSelector(getState()); + + if (!type) { + return; + } + + const provider = await ProviderFactory.create({ + type + }); + + if (!provider) { + throw new Error('Provider not found'); + } + + setAccountProvider(provider); +} diff --git a/src/core/providers/helpers/utils.ts b/src/core/providers/helpers/utils.ts deleted file mode 100644 index 4b0341a..0000000 --- a/src/core/providers/helpers/utils.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ExtensionProvider } from '@multiversx/sdk-extension-provider'; -import { HWProvider } from '@multiversx/sdk-hw-provider'; -import { MetamaskProvider } from '@multiversx/sdk-metamask-provider/out/metamaskProvider'; -import { OperaProvider } from '@multiversx/sdk-opera-provider'; -import { WalletProvider } from '@multiversx/sdk-web-wallet-provider'; -import { WalletConnectV2Provider } from 'utils/walletconnect/__sdkWalletconnectProvider'; -import { EmptyProvider } from './emptyProvider'; -import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; -import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; - -export const getProviderType = ( - provider?: TProvider | null -): ProviderTypeEnum => { - switch (provider?.constructor) { - case WalletProvider: - return ProviderTypeEnum.webhook; - case WalletConnectV2Provider: - return ProviderTypeEnum.walletConnect; - case HWProvider: - return ProviderTypeEnum.hardware; - case ExtensionProvider: - return ProviderTypeEnum.extension; - case MetamaskProvider: - return ProviderTypeEnum.metamask; - case OperaProvider: - return ProviderTypeEnum.opera; - case CrossWindowProvider: - return ProviderTypeEnum.crossWindow; - case EmptyProvider: - default: - return ProviderTypeEnum.none; - } -}; diff --git a/src/core/providers/index.ts b/src/core/providers/index.ts index 5cd1e7c..ceb373e 100644 --- a/src/core/providers/index.ts +++ b/src/core/providers/index.ts @@ -1,2 +1,16 @@ -export { getAccountProvider } from './accountProvider'; -export * from './helpers/getLedgerConfiguration'; +export { getAccountProvider } from './helpers/accountProvider'; +export * from './strategies'; + +/* +// TODO: create detectProvider function +(window as any).multiversx = {}; +(window as any).multiversx.providers = [ + { + name: "PEM", + icon: "", + class: (config) => { + return new PEMProvider(config); + }, + }, +]; +*/ diff --git a/src/core/providers/strategies/CrossWindowProviderStrategy/CrossWindowProviderStrategy.ts b/src/core/providers/strategies/CrossWindowProviderStrategy/CrossWindowProviderStrategy.ts new file mode 100644 index 0000000..6e537cb --- /dev/null +++ b/src/core/providers/strategies/CrossWindowProviderStrategy/CrossWindowProviderStrategy.ts @@ -0,0 +1,238 @@ +import { Message, Transaction } from '@multiversx/sdk-core/out'; +import { isBrowserWithPopupConfirmation } from 'constants/browser.constants'; +import { + PendingTransactionsStateManager, + PendingTransactionsEventsEnum +} from 'core/managers'; +import { getAccount } from 'core/methods/account/getAccount'; +import { getAddress } from 'core/methods/account/getAddress'; +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { PendingTransactionsModal } from 'lib/sdkDappCoreUi'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; +import { crossWindowConfigSelector } from 'store/selectors'; +import { networkSelector } from 'store/selectors/networkSelectors'; +import { getState } from 'store/store'; +import { ProviderErrorsEnum } from 'types/provider.types'; +import { createModalElement } from 'utils/createModalElement'; + +type CrossWindowProviderProps = { + address?: string; + walletAddress?: string; +}; + +export class CrossWindowProviderStrategy { + private provider: CrossWindowProvider | null = null; + private address: string; + private walletAddress?: string; + private _signTransactions: + | ((transactions: Transaction[]) => Promise) + | null = null; + private _signMessage: ((messageToSign: Message) => Promise) | null = + null; + + constructor(config?: CrossWindowProviderProps) { + this.address = config?.address || ''; + this.walletAddress = config?.walletAddress; + } + + public createProvider = async (): Promise => { + this.initialize(); + const network = networkSelector(getState()); + + if (!this.provider) { + this.provider = CrossWindowProvider.getInstance(); + this.provider.init(); + } + + // Bind in order to break reference + this._signTransactions = this.provider.signTransactions.bind(this.provider); + this._signMessage = this.provider.signMessage.bind(this.provider); + + this.provider.setWalletUrl(this.walletAddress || network.walletAddress); + this.provider.setAddress(this.address); + + this.setPopupConsent(); + + return this.buildProvider(); + }; + + private buildProvider = () => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const provider = this.provider as unknown as IProvider; + + provider.setAccount({ address: this.address }); + provider.signTransactions = this.signTransactions; + provider.signMessage = this.signMessage; + + return provider; + }; + + private initialize = () => { + if (this.address) { + return; + } + + const address = getAddress(); + + if (!address) { + return; + } + + this.address = address; + }; + + private signTransactions = async (transactions: Transaction[]) => { + if (!this.provider || !this._signTransactions) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + const { eventBus, onClose, manager } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: 'Confirm on MultiversX Web Wallet', + subtitle: 'Check your MultiversX Web Wallet to sign the transaction' + }); + + this.setPopupConsent(); + + try { + const signedTransactions: Transaction[] = + (await this._signTransactions(transactions)) ?? []; + + // Guarded Transactions or Signed Transactions + return this.getTransactions(signedTransactions); + } catch (error) { + this.provider.cancelAction(); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private signMessage = async (message: Message) => { + if (!this.provider || !this._signMessage) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + const { eventBus, onClose, manager } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: 'Message Signing', + subtitle: 'Check your MultiversX Web Wallet to sign the message' + }); + + this.setPopupConsent(); + + try { + const signedMessage = await this._signMessage(message); + + return signedMessage; + } catch (error) { + this.provider.cancelAction(); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private setPopupConsent = () => { + const crossWindowDappConfig = crossWindowConfigSelector(getState()); + + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + if ( + crossWindowDappConfig?.isBrowserWithPopupConfirmation || + isBrowserWithPopupConfirmation + ) { + this.provider.setShouldShowConsentPopup(true); + } + }; + + private getTransactions = async (transactions: Transaction[]) => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const { isGuarded } = getAccount(); + + const allSignedByGuardian = this.getAreAllTransactionsSignedByGuardian({ + isGuarded, + transactions + }); + + const needs2FAsigning = isGuarded && !allSignedByGuardian; + + if (needs2FAsigning) { + const guardedTransactions = + await this.provider.guardTransactions(transactions); + + return guardedTransactions; + } + + return transactions; + }; + + private getAreAllTransactionsSignedByGuardian = ({ + transactions, + isGuarded + }: { + transactions: Transaction[]; + isGuarded?: boolean; + }) => { + if (!isGuarded) { + return true; + } + + if (transactions.length === 0) { + return false; + } + + return transactions.every((tx) => + Boolean(tx.getGuardianSignature().toString('hex')) + ); + }; + + private getModalHandlers = async (modalElement: PendingTransactionsModal) => { + const eventBus = await modalElement.getEventBus(); + + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + const manager = PendingTransactionsStateManager.getInstance(eventBus); + + const onClose = (cancelAction = true) => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + if (cancelAction) { + this.provider.cancelAction(); + } + + manager.closeAndReset(); + }; + return { eventBus, manager, onClose }; + }; +} diff --git a/src/core/providers/strategies/CrossWindowProviderStrategy/index.ts b/src/core/providers/strategies/CrossWindowProviderStrategy/index.ts new file mode 100644 index 0000000..bdf237e --- /dev/null +++ b/src/core/providers/strategies/CrossWindowProviderStrategy/index.ts @@ -0,0 +1,2 @@ +export * from './CrossWindowProviderStrategy'; +export * from './types'; diff --git a/src/core/providers/strategies/CrossWindowProviderStrategy/types/crossWindow.types.ts b/src/core/providers/strategies/CrossWindowProviderStrategy/types/crossWindow.types.ts new file mode 100644 index 0000000..76a3782 --- /dev/null +++ b/src/core/providers/strategies/CrossWindowProviderStrategy/types/crossWindow.types.ts @@ -0,0 +1,6 @@ +export interface CrossWindowConfig { + /** + * default: `false` + */ + isBrowserWithPopupConfirmation?: boolean; +} diff --git a/src/core/providers/strategies/CrossWindowProviderStrategy/types/index.ts b/src/core/providers/strategies/CrossWindowProviderStrategy/types/index.ts new file mode 100644 index 0000000..a49e6ba --- /dev/null +++ b/src/core/providers/strategies/CrossWindowProviderStrategy/types/index.ts @@ -0,0 +1 @@ +export * from './crossWindow.types'; diff --git a/src/core/providers/strategies/ExtensionProviderStrategy/ExtensionProviderStrategy.ts b/src/core/providers/strategies/ExtensionProviderStrategy/ExtensionProviderStrategy.ts new file mode 100644 index 0000000..131101e --- /dev/null +++ b/src/core/providers/strategies/ExtensionProviderStrategy/ExtensionProviderStrategy.ts @@ -0,0 +1,121 @@ +import { Transaction, Message } from '@multiversx/sdk-core/out'; +import { IDAppProviderOptions } from '@multiversx/sdk-dapp-utils/out'; +import { ExtensionProvider } from '@multiversx/sdk-extension-provider/out/extensionProvider'; +import { + PendingTransactionsStateManager, + PendingTransactionsEventsEnum +} from 'core/managers'; +import { getAccount } from 'core/methods/account/getAccount'; +import { getAddress } from 'core/methods/account/getAddress'; +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { PendingTransactionsModal } from 'lib/sdkDappCoreUi'; +import { Nullable, ProviderErrorsEnum } from 'types'; +import { createModalElement } from 'utils/createModalElement'; + +export class ExtensionProviderStrategy { + private address: string = ''; + private provider: ExtensionProvider | null = null; + private _signMessage: ((message: Message) => Promise) | null = null; + + constructor(address?: string) { + this.address = address || ''; + } + + public createProvider = async (): Promise => { + this.initialize(); + + if (!this.provider) { + this.provider = ExtensionProvider.getInstance(); + await this.provider.init(); + } + + this._signMessage = this.provider.signMessage.bind(this.provider); + + return this.buildProvider(); + }; + + private buildProvider = () => { + const { address } = getAccount(); + + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const provider = this.provider as unknown as IProvider; + provider.signMessage = this.signMessage; + + provider.setAccount({ address: this.address || address }); + return provider; + }; + + private initialize = () => { + if (this.address) { + return; + } + + const address = getAddress(); + + if (!address) { + return; + } + + this.address = address; + }; + + private signMessage = async (message: Message) => { + if (!this.provider || !this._signMessage) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + + const { eventBus, manager, onClose } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: 'Message Signing', + subtitle: 'Check your MultiversX Wallet Extension to sign the message' + }); + + try { + const signedMessage = await this._signMessage(message); + + return signedMessage; + } catch (error) { + this.provider.cancelAction(); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private getModalHandlers = async (modalElement: PendingTransactionsModal) => { + const eventBus = await modalElement.getEventBus(); + + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + const manager = PendingTransactionsStateManager.getInstance(eventBus); + + const onClose = (cancelAction = true) => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + if (cancelAction) { + this.provider.cancelAction(); + } + + manager.closeAndReset(); + }; + + return { eventBus, manager, onClose }; + }; +} diff --git a/src/core/providers/strategies/ExtensionProviderStrategy/index.ts b/src/core/providers/strategies/ExtensionProviderStrategy/index.ts new file mode 100644 index 0000000..cd40205 --- /dev/null +++ b/src/core/providers/strategies/ExtensionProviderStrategy/index.ts @@ -0,0 +1 @@ +export * from './ExtensionProviderStrategy'; diff --git a/src/core/providers/strategies/IFrameProviderStrategy/IFrameProviderStrategy.ts b/src/core/providers/strategies/IFrameProviderStrategy/IFrameProviderStrategy.ts new file mode 100644 index 0000000..92b7e94 --- /dev/null +++ b/src/core/providers/strategies/IFrameProviderStrategy/IFrameProviderStrategy.ts @@ -0,0 +1,169 @@ +import { Message, Transaction } from '@multiversx/sdk-core/out'; +import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; +import { IframeLoginTypes } from '@multiversx/sdk-web-wallet-iframe-provider/out/constants'; +import { + PendingTransactionsStateManager, + PendingTransactionsEventsEnum +} from 'core/managers'; +import { getAccount } from 'core/methods/account/getAccount'; +import { getAddress } from 'core/methods/account/getAddress'; +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { PendingTransactionsModal } from 'lib/sdkDappCoreUi'; +import { networkSelector } from 'store/selectors/networkSelectors'; +import { getState } from 'store/store'; +import { ProviderErrorsEnum } from 'types/provider.types'; +import { createModalElement } from 'utils/createModalElement'; +import { IFrameProviderType } from './types'; + +export class IFrameProviderStrategy { + private provider: IframeProvider | null = null; + private address?: string; + private type: IframeLoginTypes | null = null; + private _signTransactions: + | ((transactions: Transaction[]) => Promise) + | null = null; + private _signMessage: ((message: Message) => Promise) | null = null; + + constructor({ type, address }: IFrameProviderType) { + this.type = type; + this.address = address; + } + + public createProvider = async (): Promise => { + this.initialize(); + const network = networkSelector(getState()); + + if (!this.type) { + throw new Error(ProviderErrorsEnum.invalidType); + } + + if (!this.provider) { + this.provider = IframeProvider.getInstance(); + await this.provider.init(); + } + + this.provider.setLoginType(this.type); + this.provider.setWalletUrl(String(network.iframeWalletAddress)); + this._signTransactions = this.provider.signTransactions.bind(this.provider); + this._signMessage = this.provider.signMessage.bind(this.provider); + + return this.buildProvider(); + }; + + private buildProvider = () => { + const { address } = getAccount(); + + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const provider = this.provider as unknown as IProvider; + + provider.setAccount({ address: this.address || address }); + provider.signTransactions = this.signTransactions; + provider.signMessage = this.signMessage; + return provider; + }; + + private initialize = () => { + if (this.address) { + return; + } + + const address = getAddress(); + + if (!address) { + return; + } + + this.address = address; + }; + + private signTransactions = async (transactions: Transaction[]) => { + if (!this.provider || !this._signTransactions) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + const { eventBus, manager, onClose } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: `Confirm on MultiversX ${this.type}`, + subtitle: `Check your MultiversX ${this.type} to sign the transaction` + }); + try { + const signedTransactions: Transaction[] = + await this._signTransactions(transactions); + + return signedTransactions; + } catch (error) { + this.provider.cancelAction(); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private signMessage = async (message: Message) => { + if (!this.provider || !this._signMessage || !this.type) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + const { eventBus, manager, onClose } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: 'Message Signing', + subtitle: `Check your MultiversX ${this.type} to sign the message` + }); + + try { + const signedMessage = await this._signMessage(message); + + return signedMessage; + } catch (error) { + this.provider.cancelAction(); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private getModalHandlers = async (modalElement: PendingTransactionsModal) => { + const eventBus = await modalElement.getEventBus(); + + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + const manager = PendingTransactionsStateManager.getInstance(eventBus); + + const onClose = (cancelAction = true) => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + if (cancelAction) { + this.provider.cancelAction(); + } + + manager.closeAndReset(); + }; + + return { eventBus, manager, onClose }; + }; +} diff --git a/src/core/providers/strategies/IFrameProviderStrategy/index.ts b/src/core/providers/strategies/IFrameProviderStrategy/index.ts new file mode 100644 index 0000000..e805579 --- /dev/null +++ b/src/core/providers/strategies/IFrameProviderStrategy/index.ts @@ -0,0 +1,2 @@ +export * from './IFrameProviderStrategy'; +export * from './types'; diff --git a/src/core/providers/strategies/IFrameProviderStrategy/types/iframe.types.ts b/src/core/providers/strategies/IFrameProviderStrategy/types/iframe.types.ts new file mode 100644 index 0000000..d07fee0 --- /dev/null +++ b/src/core/providers/strategies/IFrameProviderStrategy/types/iframe.types.ts @@ -0,0 +1,6 @@ +import { IframeLoginTypes } from '@multiversx/sdk-web-wallet-iframe-provider/out/constants'; + +export type IFrameProviderType = { + type: IframeLoginTypes; + address?: string; +}; diff --git a/src/core/providers/strategies/IFrameProviderStrategy/types/index.ts b/src/core/providers/strategies/IFrameProviderStrategy/types/index.ts new file mode 100644 index 0000000..48c2b23 --- /dev/null +++ b/src/core/providers/strategies/IFrameProviderStrategy/types/index.ts @@ -0,0 +1 @@ +export * from './iframe.types'; diff --git a/src/core/providers/strategies/LedgerProviderStrategy/LedgerProviderStrategy.ts b/src/core/providers/strategies/LedgerProviderStrategy/LedgerProviderStrategy.ts new file mode 100644 index 0000000..676998e --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/LedgerProviderStrategy.ts @@ -0,0 +1,445 @@ +import { Transaction } from '@multiversx/sdk-core/out'; +import { IDAppProviderOptions } from '@multiversx/sdk-dapp-utils/out'; +import { HWProvider, IProviderAccount } from '@multiversx/sdk-hw-provider'; +import BigNumber from 'bignumber.js'; +import { safeWindow } from 'constants/index'; +import { LedgerConnectStateManager } from 'core/managers'; +import { getAddress } from 'core/methods/account/getAddress'; +import { getIsLoggedIn } from 'core/methods/account/getIsLoggedIn'; +import { + IProvider, + ProviderTypeEnum +} from 'core/providers/types/providerFactory.types'; +import { defineCustomElements, LedgerConnectModal } from 'lib/sdkDappCoreUi'; +import { setLedgerAccount } from 'store/actions'; +import { setLedgerLogin } from 'store/actions/loginInfo/loginInfoActions'; +import { IEventBus } from 'types/manager.types'; +import { ProviderErrorsEnum } from 'types/provider.types'; +import { fetchAccount } from 'utils/account/fetchAccount'; +import { createModalElement } from 'utils/createModalElement'; +import { + getLedgerProvider, + getLedgerErrorCodes, + getAuthTokenText +} from './helpers'; +import { + ILedgerAccount, + ILedgerConnectModalData, + LedgerConnectEventsEnum +} from './types'; +import { signTransactions } from '../helpers/signTransactions/signTransactions'; + +const failInitializeErrorText = 'Check if the MultiversX App is open on Ledger'; + +export class LedgerProviderStrategy { + private address: string = ''; + private provider: HWProvider | null = null; + private manager: LedgerConnectStateManager< + IEventBus + > | null = null; + private config: { + version: string; + dataEnabled: boolean; + } | null = null; + private eventBus: IEventBus | null = null; + private _login: + | ((options?: { addressIndex: number }) => Promise) + | null = null; + private _signTransactions: + | (( + transactions: Transaction[], + options?: IDAppProviderOptions + ) => Promise) + | null = null; + + constructor(address?: string) { + this.address = address || ''; + } + + public createProvider = async (): Promise => { + this.initialize(); + await defineCustomElements(safeWindow); + + const eventBus = await this.createEventBus(); + + const manager = LedgerConnectStateManager.getInstance(eventBus); + this.manager = manager; + + if (!this.provider) { + const shouldInitiateLogin = !getIsLoggedIn(); + + const { ledgerProvider, ledgerConfig } = await new Promise< + Awaited> + >(async function buildLedgerProvider(resolve, reject) { + const onRetry = () => buildLedgerProvider(resolve, reject); + const onCancel = () => reject('Device unavailable'); + + try { + manager?.updateAccountScreen({ + isLoading: true + }); + + const data = await getLedgerProvider(); + + eventBus?.unsubscribe( + LedgerConnectEventsEnum.CONNECT_DEVICE, + onRetry + ); + eventBus?.unsubscribe(LedgerConnectEventsEnum.CLOSE, onCancel); + + resolve(data); + } catch (err) { + if (!shouldInitiateLogin) { + throw err; + } + + const { errorMessage, defaultErrorMessage } = + getLedgerErrorCodes(err); + manager?.updateConnectScreen({ + error: + errorMessage ?? defaultErrorMessage ?? failInitializeErrorText + }); + + eventBus?.subscribe(LedgerConnectEventsEnum.CONNECT_DEVICE, onRetry); + eventBus?.subscribe(LedgerConnectEventsEnum.CLOSE, onCancel); + } + }); + + this.config = ledgerConfig; + this.provider = ledgerProvider; + this._login = ledgerProvider.login.bind(ledgerProvider); + this._signTransactions = + ledgerProvider.signTransactions.bind(ledgerProvider); + } + + return this.buildProvider(); + }; + + private buildProvider = async () => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const provider = this.provider as unknown as IProvider; + provider.setAccount({ address: this.address }); + provider.signTransactions = this.signTransactions; + provider.login = this.login; + + await provider.init(); + return provider; + }; + + private initialize = () => { + if (this.address) { + return; + } + + const address = getAddress(); + + if (!address) { + return; + } + + this.address = address; + }; + + private createEventBus = async () => { + const shouldInitiateLogin = !getIsLoggedIn(); + + if (!shouldInitiateLogin) { + return; + } + + const modalElement = await createModalElement( + 'ledger-connect-modal' + ); + const eventBus = await modalElement.getEventBus(); + + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + this.eventBus = eventBus; + return eventBus; + }; + + private signTransactions = async (transactions: Transaction[]) => { + if (!this._signTransactions) { + throw new Error('Sign transactions method is not initialized'); + } + + const signedTransactions = await signTransactions({ + transactions, + handleSign: this._signTransactions + }); + return signedTransactions; + }; + + private login = async (options?: { + callbackUrl?: string; + token?: string; + }) => { + if (!this.provider || !this.config) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const isConnected = this.provider.isConnected(); + + if (!isConnected) { + throw new Error('Ledger device is not connected'); + } + + const authData = getAuthTokenText({ + loginToken: options?.token, + version: this.config.version + }); + + const updateAccounts = async () => { + if (!this.manager || !this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const startIndex = this.manager.getAccountScreenData()?.startIndex || 0; + const allAccounts = this.manager.getAllAccounts(); + + const hasData = allAccounts.some( + ({ index, balance }) => + index === startIndex && new BigNumber(balance).isFinite() + ); + + const slicedAccounts = allAccounts.slice( + startIndex, + startIndex + this.manager.addressesPerPage + ); + + if (hasData) { + return this.manager.updateAccountScreen({ + accounts: slicedAccounts, + isLoading: false + }); + } + + if (slicedAccounts.length === 0) { + this.manager.updateAccountScreen({ + isLoading: true + }); + } + + try { + const accountsArray = await this.provider.getAccounts( + startIndex, + this.manager.addressesPerPage + ); + + const accountsWithBalance: ILedgerAccount[] = accountsArray.map( + (address, index) => { + return { + address, + balance: '...', + index: index + startIndex + }; + } + ); + + const newAllAccounts = [...allAccounts, ...accountsWithBalance]; + + this.manager.updateAllAccounts(newAllAccounts); + + this.manager.updateAccountScreen({ + accounts: newAllAccounts.slice( + startIndex, + startIndex + this.manager.addressesPerPage + ), + isLoading: false + }); + + const balancePromises = accountsArray.map((address) => + fetchAccount(address) + ); + + const balances = await Promise.all(balancePromises); + + balances.forEach((account, index) => { + const bNbalance = new BigNumber(String(account?.balance)); + if (!account || bNbalance.isNaN()) { + return; + } + const balance = bNbalance + .dividedBy(BigNumber(10).pow(18)) + .toFormat(4) + .toString(); + const accountArrayIndex = index + startIndex; + newAllAccounts[accountArrayIndex].balance = balance; + }); + + this.manager.updateAllAccounts(newAllAccounts); + + this.manager.updateAccountScreen({ + accounts: newAllAccounts.slice( + startIndex, + startIndex + this.manager.addressesPerPage + ) + }); + } catch (error) { + this.manager.updateAccountScreen({ + accounts: allAccounts.slice( + startIndex, + startIndex + this.manager.addressesPerPage + ), + isLoading: false + }); + console.error('Failed to fetch accounts:', error); + } + }; + + await updateAccounts(); + + const selectedAccount = await new Promise<{ + address: string; + signature: string; + addressIndex: number; + }>(async (resolve, reject) => { + const unsubscribeFromEvents = () => { + if (!this.eventBus) { + throw new Error('Event bus not provided for Ledger provider'); + } + // eslint-disable-next-line @typescript-eslint/no-use-before-define + this.eventBus.unsubscribe(LedgerConnectEventsEnum.CLOSE, onCancel); + this.eventBus.unsubscribe( + LedgerConnectEventsEnum.NEXT_PAGE, + // eslint-disable-next-line @typescript-eslint/no-use-before-define + onNextPageChanged + ); + this.eventBus.unsubscribe( + LedgerConnectEventsEnum.PREV_PAGE, + // eslint-disable-next-line @typescript-eslint/no-use-before-define + onPrevPageChanged + ); + this.eventBus.unsubscribe( + LedgerConnectEventsEnum.ACCESS_WALLET, + // eslint-disable-next-line @typescript-eslint/no-use-before-define + onAccessWallet + ); + }; + + const closeComponent = () => { + this.manager?.closeAndReset(); + }; + + const onCancel = async () => { + await updateAccounts(); + unsubscribeFromEvents(); + reject('User cancelled login'); + }; + + const onNextPageChanged = async () => { + const startIndex = + this.manager?.getAccountScreenData()?.startIndex || 0; + this.manager?.updateStartIndex( + startIndex + this.manager.addressesPerPage + ); + await updateAccounts(); + }; + + const onPrevPageChanged = async () => { + const startIndex = + this.manager?.getAccountScreenData()?.startIndex || 0; + + if (startIndex > 0) { + this.manager?.updateStartIndex( + Math.max(0, startIndex - this.manager.addressesPerPage) + ); + + await updateAccounts(); + } + }; + + // Initialize here in order to have access inside function + const manager = this.manager; + const provider = this.provider; + const login = this._login; + + const onAccessWallet = async function tryAccessWallet(payload: { + addressIndex: number; + selectedAddress: string; + }) { + if (!provider || !login) { + return; + } + + manager?.updateConfirmScreen({ + ...authData, + selectedAddress: payload.selectedAddress + }); + + try { + const loginInfo = options?.token + ? await provider.tokenLogin({ + token: Buffer.from(`${options?.token}{}`), + addressIndex: payload.addressIndex + }) + : await login({ + addressIndex: payload.addressIndex + }); + + closeComponent(); + + resolve({ + address: loginInfo.address, + signature: loginInfo.signature + ? loginInfo.signature.toString('hex') + : '', + addressIndex: payload.addressIndex + }); + } catch (err) { + console.error('User rejected login:', err); + const shouldClose = Boolean(manager?.getAccountScreenData()); + if (shouldClose) { + return closeComponent(); + } + const shouldGoBack = Boolean(manager?.getConfirmScreenData()); + if (shouldGoBack) { + await updateAccounts(); + } + } + }; + + if (!this.eventBus) { + throw new Error('Event bus not provided for Ledger provider'); + } + + this.eventBus.subscribe(LedgerConnectEventsEnum.CLOSE, onCancel); + this.eventBus.subscribe( + LedgerConnectEventsEnum.NEXT_PAGE, + onNextPageChanged + ); + this.eventBus.subscribe( + LedgerConnectEventsEnum.PREV_PAGE, + onPrevPageChanged + ); + this.eventBus.subscribe( + LedgerConnectEventsEnum.ACCESS_WALLET, + onAccessWallet + ); + }); + + const { version, dataEnabled } = this.config; + + setLedgerLogin({ + index: selectedAccount.addressIndex, + loginType: ProviderTypeEnum.ledger + }); + + setLedgerAccount({ + address: selectedAccount.address, + index: selectedAccount.addressIndex, + version, + hasContractDataEnabled: dataEnabled + }); + + return { + address: selectedAccount.address, + signature: selectedAccount.signature + }; + }; +} diff --git a/src/core/providers/strategies/LedgerProviderStrategy/helpers/getAuthTokenText.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getAuthTokenText.ts new file mode 100644 index 0000000..1756d47 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getAuthTokenText.ts @@ -0,0 +1,47 @@ +import { decodeLoginToken } from 'services/nativeAuth/helpers/decodeLoginToken'; +import getLedgerVersionOptions from './getLedgerVersionOptions'; +import { secondsToTimeString } from './secondsToTimeString'; + +// TODO: rename to something more specific? +export const getAuthTokenText = ({ + loginToken, + version +}: { + loginToken?: string; + version?: string; +}) => { + if (!loginToken || !version) { + return null; + } + + const { ledgerWithUsernames } = getLedgerVersionOptions(version); + const nativeAuthInfo = decodeLoginToken(loginToken); + if (nativeAuthInfo == null) { + return null; + } + + const confirmAddressText = 'For security, please confirm that your address:'; + const authText = 'and Auth Token:'; + const areShownText = 'are the one shown on your Ledger device screen now.'; + + if (ledgerWithUsernames) { + const time = secondsToTimeString(nativeAuthInfo.ttl); + + const confirmAddressText = 'For security, please confirm your address:'; + const authText = 'and authorize:'; + + return { + data: `${nativeAuthInfo.origin} for ${time}.`, + confirmAddressText, + authText, + areShownText: '' + }; + } + + return { + data: loginToken, + confirmAddressText, + authText, + areShownText + }; +}; diff --git a/src/core/providers/helpers/getLedgerConfiguration.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerConfiguration.ts similarity index 80% rename from src/core/providers/helpers/getLedgerConfiguration.ts rename to src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerConfiguration.ts index 0658cb3..445e8ee 100644 --- a/src/core/providers/helpers/getLedgerConfiguration.ts +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerConfiguration.ts @@ -3,11 +3,7 @@ import { IHWWalletApp } from '@multiversx/sdk-hw-provider/out/interface'; import { LEDGER_CONTRACT_DATA_ENABLED_VALUE } from 'constants/index'; -export const DAPP_INIT_ROUTE = '/dapp/init'; - -export const getLedgerConfiguration = async ( - initializedHwWalletP: HWProvider -) => { +export async function getLedgerConfiguration(initializedHwWalletP: HWProvider) { if (!initializedHwWalletP.isInitialized()) { throw new Error('Unable to get version. Provider not initialized'); } @@ -15,4 +11,4 @@ export const getLedgerConfiguration = async ( const { contractData, version } = await hwApp.getAppConfiguration(); const dataEnabled = contractData === LEDGER_CONTRACT_DATA_ENABLED_VALUE; return { version, dataEnabled }; -}; +} diff --git a/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerErrorCodes.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerErrorCodes.ts new file mode 100644 index 0000000..423dd1a --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerErrorCodes.ts @@ -0,0 +1,21 @@ +import { ledgerErrorCodes } from 'constants/ledger.constants'; + +const ledgerAppErrorText = 'Check if the MultiversX app is open on Ledger'; +const notConnectedCode = 0x6e01; +const wrongClaCode = 0x6e00; +const inactiveAppCodes = [notConnectedCode, wrongClaCode]; + +export function getLedgerErrorCodes(err?: any) { + let errorMessage: string | null = null; + if (err?.statusCode in ledgerErrorCodes) { + const statusCode: keyof typeof ledgerErrorCodes = err?.statusCode; + const { message } = ledgerErrorCodes[statusCode]; + errorMessage = inactiveAppCodes.includes(statusCode) + ? ledgerAppErrorText + : message; + } + return { + errorMessage, + defaultErrorMessage: ledgerAppErrorText + }; +} diff --git a/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerProvider.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerProvider.ts new file mode 100644 index 0000000..6b50e4f --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerProvider.ts @@ -0,0 +1,51 @@ +import { HWProvider } from '@multiversx/sdk-hw-provider'; +import { getIsLoggedIn } from 'core/methods/account/getIsLoggedIn'; +import { getAccountProvider } from 'core/providers/helpers/accountProvider'; +import { ledgerLoginSelector } from 'store/selectors/loginInfoSelectors'; +import { getState } from 'store/store'; +import { getLedgerConfiguration } from './getLedgerConfiguration'; + +export async function getLedgerProvider() { + const isLoggedIn = getIsLoggedIn(); + const ledgerLogin = ledgerLoginSelector(getState()); + const provider = getAccountProvider(); + + const initHWProvider = async () => { + const hasAddressIndex = ledgerLogin?.index != null; + + if (provider instanceof HWProvider && provider.isInitialized()) { + if (hasAddressIndex) { + await provider.setAddressIndex(ledgerLogin.index); + } + + return provider; + } + + const ledgerProvider = new HWProvider(); + const isInitialized = await ledgerProvider.init(); + + if (!isInitialized) { + throw new Error('Failed to initialize Ledger Provider'); + } + + if (hasAddressIndex) { + await ledgerProvider.setAddressIndex(ledgerLogin.index); + } + + return ledgerProvider; + }; + + try { + const ledgerProvider = await initHWProvider(); + const ledgerConfig = await getLedgerConfiguration(ledgerProvider); + return { ledgerProvider, ledgerConfig }; + } catch (err) { + console.error('Could not initialize ledger app', err); + + if (isLoggedIn) { + await provider.logout(); + } + + throw err; + } +} diff --git a/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerVersionOptions.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerVersionOptions.ts new file mode 100644 index 0000000..3594057 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/getLedgerVersionOptions.ts @@ -0,0 +1,67 @@ +import { + LEDGER_HASH_SIGN_MINIMUM_VERSION, + LEDGER_MULTI_ACCOUNT_MINIMUM_VERSION, + LEDGER_SIGN_AUTH_TOKEN_MINIMUM_VERSION, + LEDGER_WITH_WHITELISTED_TOKENS_MINIMUM_VERSION, + LEDGER_WITH_GUARDIANS_MINIMUM_VERSION, + LEDGER_WITH_USERNAMES_MINIMUM_VERSION +} from 'constants/index'; + +function compareVersions(a: string, b: string) { + let i, diff; + const regExStrip0 = /(\.0+)+$/; + const segmentsA = a.replace(regExStrip0, '').split('.'); + const segmentsB = b.replace(regExStrip0, '').split('.'); + const l = Math.min(segmentsA.length, segmentsB.length); + + for (i = 0; i < l; i++) { + diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); + if (diff) { + return diff; + } + } + return segmentsA.length - segmentsB.length; +} + +export function getLedgerVersionOptions(version: string) { + const sortedVersions = [ + LEDGER_MULTI_ACCOUNT_MINIMUM_VERSION, + LEDGER_HASH_SIGN_MINIMUM_VERSION, + LEDGER_SIGN_AUTH_TOKEN_MINIMUM_VERSION, + LEDGER_WITH_WHITELISTED_TOKENS_MINIMUM_VERSION, + LEDGER_WITH_GUARDIANS_MINIMUM_VERSION, + LEDGER_WITH_USERNAMES_MINIMUM_VERSION, + version + ].sort((a, b) => compareVersions(a, b)); + + const indexOfMultiAccount = sortedVersions.indexOf( + LEDGER_MULTI_ACCOUNT_MINIMUM_VERSION + ); + const indexOfHashSign = sortedVersions.indexOf( + LEDGER_HASH_SIGN_MINIMUM_VERSION + ); + const indexOfSignAuthToken = sortedVersions.indexOf( + LEDGER_SIGN_AUTH_TOKEN_MINIMUM_VERSION + ); + const indexOfWhitelistedTokens = sortedVersions.indexOf( + LEDGER_WITH_WHITELISTED_TOKENS_MINIMUM_VERSION + ); + const indexOfGuardians = sortedVersions.indexOf( + LEDGER_WITH_GUARDIANS_MINIMUM_VERSION + ); + const indexOfUsernames = sortedVersions.indexOf( + LEDGER_WITH_USERNAMES_MINIMUM_VERSION + ); + const indexOfVersion = sortedVersions.indexOf(version); + + return { + ledgerWithMultiAccount: indexOfVersion >= indexOfMultiAccount, + ledgerWithHashSign: indexOfVersion >= indexOfHashSign, + ledgerWithSignAuthToken: indexOfVersion >= indexOfSignAuthToken, + ledgerWithWhitelistedTokens: indexOfVersion >= indexOfWhitelistedTokens, + ledgerWithGuardians: indexOfVersion >= indexOfGuardians, + ledgerWithUsernames: indexOfVersion >= indexOfUsernames + }; +} + +export default getLedgerVersionOptions; diff --git a/src/core/providers/strategies/LedgerProviderStrategy/helpers/index.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/index.ts new file mode 100644 index 0000000..68fd2a1 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/index.ts @@ -0,0 +1,6 @@ +export * from './getAuthTokenText'; +export * from './getLedgerConfiguration'; +export * from './getLedgerErrorCodes'; +export * from './getLedgerProvider'; +export * from './getLedgerVersionOptions'; +export * from './secondsToTimeString'; diff --git a/src/core/providers/strategies/LedgerProviderStrategy/helpers/secondsToTimeString.ts b/src/core/providers/strategies/LedgerProviderStrategy/helpers/secondsToTimeString.ts new file mode 100644 index 0000000..7af6a51 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/helpers/secondsToTimeString.ts @@ -0,0 +1,29 @@ +import isString from 'lodash/isString'; + +export const secondsToTimeString = (seconds: number) => { + if (seconds <= 0 || isNaN(seconds) || !seconds || isString(seconds)) { + return 'N/A time'; + } + + if (seconds >= 86400) { + return 'more than one day'; + } + + const hours = Math.floor(seconds / 3600); + const remainingSeconds = seconds % 3600; + const minutes = Math.floor(remainingSeconds / 60); + const remainingSecondsAfterMinutes = remainingSeconds % 60; + + const parts = []; + if (hours > 0) { + parts.push(`${hours}h`); + } + if (minutes > 0) { + parts.push(`${minutes}min`); + } + if (remainingSecondsAfterMinutes > 0) { + parts.push(`${remainingSecondsAfterMinutes}sec`); + } + + return parts.join(' '); +}; diff --git a/src/core/providers/strategies/LedgerProviderStrategy/index.ts b/src/core/providers/strategies/LedgerProviderStrategy/index.ts new file mode 100644 index 0000000..5840241 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/index.ts @@ -0,0 +1,2 @@ +export * from './LedgerProviderStrategy'; +export * from './types'; diff --git a/src/core/providers/strategies/LedgerProviderStrategy/tests/getLedgerVersionOptions.test.ts b/src/core/providers/strategies/LedgerProviderStrategy/tests/getLedgerVersionOptions.test.ts new file mode 100644 index 0000000..e242514 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/tests/getLedgerVersionOptions.test.ts @@ -0,0 +1,84 @@ +import ledgerVersionOptions from '../helpers/getLedgerVersionOptions'; + +describe('ledgerOptions tests', () => { + test('detects ledger without multiAccount', () => { + expect(ledgerVersionOptions('1.0.6')).toStrictEqual({ + ledgerWithHashSign: false, + ledgerWithMultiAccount: false, + ledgerWithSignAuthToken: false, + ledgerWithWhitelistedTokens: false, + ledgerWithGuardians: false, + ledgerWithUsernames: false + }); + }); + test('ledger with multiAccount', () => { + expect(ledgerVersionOptions('1.0.8')).toStrictEqual({ + ledgerWithHashSign: false, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: false, + ledgerWithWhitelistedTokens: false, + ledgerWithGuardians: false, + ledgerWithUsernames: false + }); + }); + test('ledger with hashSign', () => { + expect(ledgerVersionOptions('1.0.11')).toStrictEqual({ + ledgerWithHashSign: true, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: false, + ledgerWithWhitelistedTokens: false, + ledgerWithGuardians: false, + ledgerWithUsernames: false + }); + }); + test('ledger with tokenSign', () => { + expect(ledgerVersionOptions('1.0.15')).toStrictEqual({ + ledgerWithHashSign: true, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: true, + ledgerWithWhitelistedTokens: false, + ledgerWithGuardians: false, + ledgerWithUsernames: false + }); + }); + test('ledger with tokens', () => { + expect(ledgerVersionOptions('1.0.17')).toStrictEqual({ + ledgerWithHashSign: true, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: true, + ledgerWithWhitelistedTokens: true, + ledgerWithGuardians: false, + ledgerWithUsernames: false + }); + }); + test('ledger with latest tokens', () => { + expect(ledgerVersionOptions('1.0.22')).toStrictEqual({ + ledgerWithHashSign: true, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: true, + ledgerWithWhitelistedTokens: true, + ledgerWithGuardians: true, + ledgerWithUsernames: false + }); + }); + test('ledger with usernames', () => { + expect(ledgerVersionOptions('1.0.23')).toStrictEqual({ + ledgerWithHashSign: true, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: true, + ledgerWithWhitelistedTokens: true, + ledgerWithGuardians: true, + ledgerWithUsernames: true + }); + }); + test('latest ledger version', () => { + expect(ledgerVersionOptions('1.1.1')).toStrictEqual({ + ledgerWithHashSign: true, + ledgerWithMultiAccount: true, + ledgerWithSignAuthToken: true, + ledgerWithWhitelistedTokens: true, + ledgerWithGuardians: true, + ledgerWithUsernames: true + }); + }); +}); diff --git a/src/core/providers/strategies/LedgerProviderStrategy/tests/secondsToTimeString.test.ts b/src/core/providers/strategies/LedgerProviderStrategy/tests/secondsToTimeString.test.ts new file mode 100644 index 0000000..a1bd883 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/tests/secondsToTimeString.test.ts @@ -0,0 +1,51 @@ +import { secondsToTimeString } from '../helpers/secondsToTimeString'; + +describe('secondsToTimeString tests', () => { + it('converts 0 seconds to "N/A time"', () => { + expect(secondsToTimeString(0)).toBe('N/A time'); + }); + + it('converts NaN to "N/A time"', () => { + expect(secondsToTimeString(NaN)).toBe('N/A time'); + }); + + it('converts undefined to "N/A time"', () => { + expect(secondsToTimeString(undefined as any)).toBe('N/A time'); + }); + + it('converts -1 to "N/A time"', () => { + expect(secondsToTimeString(-1)).toBe('N/A time'); + }); + + it('converts null to "N/A time"', () => { + expect(secondsToTimeString(null as any)).toBe('N/A time'); + }); + + it('converts string values to "N/A time"', () => { + expect(secondsToTimeString('abc' as any)).toBe('N/A time'); + expect(secondsToTimeString('123' as any)).toBe('N/A time'); + }); + + it('converts seconds less than a minute correctly', () => { + expect(secondsToTimeString(45)).toBe('45sec'); + expect(secondsToTimeString(59)).toBe('59sec'); + }); + + it('converts seconds to minutes and seconds correctly', () => { + expect(secondsToTimeString(60)).toBe('1min'); + expect(secondsToTimeString(123)).toBe('2min 3sec'); + expect(secondsToTimeString(599)).toBe('9min 59sec'); + }); + + it('converts seconds to hours, minutes, and seconds correctly', () => { + expect(secondsToTimeString(3600)).toBe('1h'); + expect(secondsToTimeString(3666)).toBe('1h 1min 6sec'); + expect(secondsToTimeString(7200)).toBe('2h'); + expect(secondsToTimeString(7323)).toBe('2h 2min 3sec'); + }); + + it('handles more than 24 hours', () => { + expect(secondsToTimeString(86400)).toBe('more than one day'); + expect(secondsToTimeString(100000)).toBe('more than one day'); + }); +}); diff --git a/src/core/providers/strategies/LedgerProviderStrategy/types/index.ts b/src/core/providers/strategies/LedgerProviderStrategy/types/index.ts new file mode 100644 index 0000000..b997314 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/types/index.ts @@ -0,0 +1 @@ +export * from './ledger.types'; diff --git a/src/core/providers/strategies/LedgerProviderStrategy/types/ledger.types.ts b/src/core/providers/strategies/LedgerProviderStrategy/types/ledger.types.ts new file mode 100644 index 0000000..5e69850 --- /dev/null +++ b/src/core/providers/strategies/LedgerProviderStrategy/types/ledger.types.ts @@ -0,0 +1,44 @@ +// types here need to be synced with the types in sdk-dapp-core-ui + +export interface IConnectScreenData { + customContentMarkup?: string; + disabled?: boolean; + error?: string; +} + +export interface IAccountScreenData { + accounts: ILedgerAccount[]; + startIndex: number; + addressesPerPage: number; + isLoading: boolean; +} + +export interface IConfirmScreenData { + data?: string; + selectedAddress: string; + confirmAddressText?: string; + authText?: string; + areShownText?: string | null; +} + +export interface ILedgerConnectModalData { + connectScreenData: IConnectScreenData | null; + accountScreenData: IAccountScreenData | null; + shouldClose?: true; + confirmScreenData: IConfirmScreenData | null; +} + +export interface ILedgerAccount { + address: string; + balance: string; + index: number; +} + +export enum LedgerConnectEventsEnum { + 'CONNECT_DEVICE' = 'CONNECT_DEVICE', + 'ACCESS_WALLET' = 'ACCESS_WALLET', + 'NEXT_PAGE' = 'NEXT_PAGE', + 'PREV_PAGE' = 'PREV_PAGE', + 'CLOSE' = 'CLOSE', + 'DATA_UPDATE' = 'DATA_UPDATE' +} diff --git a/src/core/providers/strategies/WalletConnectProviderStrategy/WalletConnectProviderStrategy.ts b/src/core/providers/strategies/WalletConnectProviderStrategy/WalletConnectProviderStrategy.ts new file mode 100644 index 0000000..ff6399c --- /dev/null +++ b/src/core/providers/strategies/WalletConnectProviderStrategy/WalletConnectProviderStrategy.ts @@ -0,0 +1,423 @@ +import { Message, Transaction } from '@multiversx/sdk-core/out'; +import { + IProviderAccount, + SessionEventTypes, + SessionTypes, + OptionalOperation +} from '@multiversx/sdk-wallet-connect-provider/out'; +import { safeWindow } from 'constants/window.constants'; +import { + PendingTransactionsStateManager, + PendingTransactionsEventsEnum +} from 'core/managers'; +import { WalletConnectStateManager } from 'core/managers/WalletConnectStateManager/WalletConnectStateManager'; +import { getIsLoggedIn } from 'core/methods/account/getIsLoggedIn'; +import { getAccountProvider } from 'core/providers/helpers/accountProvider'; +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { + defineCustomElements, + PendingTransactionsModal, + WalletConnectModal +} from 'lib/sdkDappCoreUi'; +import { logoutAction } from 'store/actions'; +import { + chainIdSelector, + nativeAuthConfigSelector, + walletConnectConfigSelector +} from 'store/selectors'; +import { getState } from 'store/store'; +import { IEventBus } from 'types/manager.types'; +import { ProviderErrorsEnum } from 'types/provider.types'; +import { createModalElement } from 'utils/createModalElement'; +import { + WalletConnectOptionalMethodsEnum, + WalletConnectV2Provider +} from 'utils/walletconnect/__sdkWalletconnectProvider'; +import { + WalletConnectEventsEnum, + WalletConnectV2Error, + WalletConnectConfig, + IWalletConnectModalData +} from './types'; + +const dappMethods: string[] = [ + WalletConnectOptionalMethodsEnum.CANCEL_ACTION, + WalletConnectOptionalMethodsEnum.SIGN_LOGIN_TOKEN +]; + +export class WalletConnectProviderStrategy { + private provider: WalletConnectV2Provider | null = null; + private config: WalletConnectConfig | undefined; + private methods: string[] = []; + private manager: WalletConnectStateManager< + IEventBus + > | null = null; + private approval: (() => Promise) | null = null; + private unsubscribeEvents: (() => void) | null = null; + private _login: + | ((options?: { + approval?: () => Promise; + token?: string; + }) => Promise) + | null = null; + private _signTransactions: + | ((transactions: Transaction[]) => Promise) + | null = null; + private _signMessage: ((message: Message) => Promise) | null = null; + + constructor(config?: WalletConnectConfig) { + this.config = config; + } + + public createProvider = async (): Promise => { + this.initialize(); + await defineCustomElements(safeWindow); + + const eventBus = await this.createEventBus(); + + if (eventBus) { + const manager = WalletConnectStateManager.getInstance(eventBus); + this.manager = manager; + } + + if (!this.provider && this.config) { + const { walletConnectProvider, dappMethods } = + await this.createWalletConnectProvider(this.config); + + // Bind in order to break reference + this._login = walletConnectProvider.login.bind(walletConnectProvider); + this._signTransactions = walletConnectProvider.signTransactions.bind( + walletConnectProvider + ); + this._signMessage = walletConnectProvider.signMessage.bind( + walletConnectProvider + ); + + this.provider = walletConnectProvider; + this.methods = dappMethods; + } + + const onClose = () => { + if (!this.manager) { + throw new Error('State manager is not initialized'); + } + + this.manager.closeAndReset(); + }; + + this.unsubscribeEvents = () => { + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + eventBus.unsubscribe(WalletConnectEventsEnum.CLOSE, onClose); + }; + + if (eventBus && this.manager && this.provider) { + const { uri = '', approval } = await this.provider.connect({ + methods: this.methods + }); + + this.approval = approval; + this.manager.updateWcURI(uri); + + eventBus.subscribe(WalletConnectEventsEnum.CLOSE, onClose); + } + + return this.buildProvider(); + }; + + private buildProvider = () => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const provider = this.provider as unknown as IProvider; + provider.login = this.login; + provider.signTransactions = this.signTransactions; + provider.signMessage = this.signMessage; + + return provider; + }; + + private initialize = () => { + if (this.config?.walletConnectV2ProjectId) { + return; + } + + const walletConnectConfig = walletConnectConfigSelector(getState()); + + if (!walletConnectConfig) { + throw new Error(WalletConnectV2Error.invalidConfig); + } + + this.config = walletConnectConfig; + }; + + private createEventBus = async () => { + const shouldInitiateLogin = !getIsLoggedIn(); + + if (!shouldInitiateLogin) { + return; + } + + const modalElement = await createModalElement( + 'wallet-connect-modal' + ); + + const eventBus = await modalElement.getEventBus(); + return eventBus; + }; + + private createWalletConnectProvider = async (config: WalletConnectConfig) => { + const isLoggedIn = getIsLoggedIn(); + const chainId = chainIdSelector(getState()); + const provider = getAccountProvider(); + const nativeAuthConfig = nativeAuthConfigSelector(getState()); + + if (nativeAuthConfig) { + dappMethods.push(WalletConnectOptionalMethodsEnum.SIGN_NATIVE_AUTH_TOKEN); + } + + if (!config?.walletConnectV2ProjectId) { + throw new Error(WalletConnectV2Error.invalidConfig); + } + + const handleOnLogin = () => {}; + + const handleOnLogout = async () => { + await config.onLogout?.(); + logoutAction(); + }; + + const handleOnEvent = (_event: SessionEventTypes['event']) => {}; + + const providerHandlers = { + onClientLogin: handleOnLogin, + onClientLogout: handleOnLogout, + onClientEvent: handleOnEvent + }; + + try { + const { + walletConnectV2ProjectId, + walletConnectV2Options = {}, + walletConnectV2RelayAddress = '' + } = config; + const walletConnectProvider = new WalletConnectV2Provider( + providerHandlers, + chainId, + walletConnectV2RelayAddress, + walletConnectV2ProjectId, + walletConnectV2Options + ); + + await walletConnectProvider.init(); + + return { walletConnectProvider, dappMethods }; + } catch (err) { + console.error(WalletConnectV2Error.connectError, err); + + if (isLoggedIn) { + await provider.logout(); + } + + throw err; + } + }; + + private login = async (options?: { + token?: string; + }): Promise<{ + address: string; + signature: string; + }> => { + if (!this.provider || !this.manager) { + throw new Error( + 'Provider or manager is not initialized. Call createProvider first.' + ); + } + + const isConnected = this.provider.isConnected(); + + if (isConnected) { + throw new Error(WalletConnectV2Error.connectError); + } + + const reconnect = async (): Promise<{ + address: string; + signature: string; + }> => { + if (!this.provider || !this.manager) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + if (!this._login) { + throw new Error('Login method is not initialized.'); + } + + try { + await this.provider.init(); + + const { uri = '', approval: wcApproval } = await this.provider.connect({ + methods: this.methods + }); + + this.manager.updateWcURI(uri); + + const providerInfo = await this._login({ + approval: wcApproval, + token: options?.token + }); + + const { address = '', signature = '' } = providerInfo ?? {}; + + this.manager.closeAndReset(); + this.unsubscribeEvents?.(); + return { address, signature }; + } catch { + return await reconnect(); + } + }; + + if (!this.approval || !this._login) { + throw new Error('Approval or login is not initialized'); + } + + try { + const providerData = await this._login({ + approval: this.approval, + token: options?.token + }); + + const { address = '', signature = '' } = providerData ?? {}; + + this.manager.closeAndReset(); + this.unsubscribeEvents?.(); + return { address, signature }; + } catch (error) { + console.error(WalletConnectV2Error.userRejected, error); + return await reconnect(); + } + }; + + private signTransactions = async (transactions: Transaction[]) => { + if (!this.provider || !this._signTransactions) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + const { eventBus, manager, onClose } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: 'Confirm on the xPortal App', + subtitle: 'Check your phone to sign the transaction' + }); + try { + const signedTransactions: Transaction[] = + await this._signTransactions(transactions); + + return signedTransactions; + } catch (error) { + await this.sendCustomRequest({ + method: WalletConnectOptionalMethodsEnum.CANCEL_ACTION, + action: OptionalOperation.CANCEL_ACTION + }); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private signMessage = async (message: Message) => { + if (!this.provider || !this._signMessage) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + const modalElement = await createModalElement( + 'pending-transactions-modal' + ); + const { eventBus, manager, onClose } = + await this.getModalHandlers(modalElement); + + eventBus.subscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + + manager.updateData({ + isPending: true, + title: 'Message Signing', + subtitle: 'Check your MultiversX xPortal App to sign the message' + }); + + try { + const signedMessage = await this._signMessage(message); + + return signedMessage; + } catch (error) { + await this.sendCustomRequest({ + method: WalletConnectOptionalMethodsEnum.CANCEL_ACTION, + action: OptionalOperation.CANCEL_ACTION + }); + throw error; + } finally { + onClose(false); + eventBus.unsubscribe(PendingTransactionsEventsEnum.CLOSE, onClose); + } + }; + + private sendCustomRequest = async ({ + action, + method + }: { + action: OptionalOperation; + method: WalletConnectOptionalMethodsEnum; + }) => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + try { + await this.provider.sendCustomRequest?.({ + request: { + method, + params: { action } + } + }); + } catch (error) { + console.error(WalletConnectV2Error.actionError, error); + } + }; + + private getModalHandlers = async (modalElement: PendingTransactionsModal) => { + const eventBus = await modalElement.getEventBus(); + + if (!eventBus) { + throw new Error(ProviderErrorsEnum.eventBusError); + } + + const manager = PendingTransactionsStateManager.getInstance(eventBus); + + const onClose = async (cancelAction = true) => { + if (!this.provider) { + throw new Error(ProviderErrorsEnum.notInitialized); + } + + if (cancelAction) { + await this.sendCustomRequest({ + method: WalletConnectOptionalMethodsEnum.CANCEL_ACTION, + action: OptionalOperation.CANCEL_ACTION + }); + } + + manager.closeAndReset(); + }; + + return { eventBus, manager, onClose }; + }; +} diff --git a/src/core/providers/strategies/WalletConnectProviderStrategy/index.ts b/src/core/providers/strategies/WalletConnectProviderStrategy/index.ts new file mode 100644 index 0000000..ea53f38 --- /dev/null +++ b/src/core/providers/strategies/WalletConnectProviderStrategy/index.ts @@ -0,0 +1,2 @@ +export * from './WalletConnectProviderStrategy'; +export * from './types'; diff --git a/src/core/providers/strategies/WalletConnectProviderStrategy/types/index.ts b/src/core/providers/strategies/WalletConnectProviderStrategy/types/index.ts new file mode 100644 index 0000000..de7f71d --- /dev/null +++ b/src/core/providers/strategies/WalletConnectProviderStrategy/types/index.ts @@ -0,0 +1 @@ +export * from './walletConnect.types'; diff --git a/src/core/providers/strategies/WalletConnectProviderStrategy/types/walletConnect.types.ts b/src/core/providers/strategies/WalletConnectProviderStrategy/types/walletConnect.types.ts new file mode 100644 index 0000000..b2222fe --- /dev/null +++ b/src/core/providers/strategies/WalletConnectProviderStrategy/types/walletConnect.types.ts @@ -0,0 +1,37 @@ +import { WalletConnectV2ProviderOptionsType } from '@multiversx/sdk-wallet-connect-provider/out'; + +export enum WalletConnectV2Error { + invalidAddress = 'Invalid address', + invalidConfig = 'Invalid WalletConnect setup', + invalidTopic = 'Expired connection', + sessionExpired = 'Unable to connect to existing session', + connectError = 'Unable to connect', + userRejected = 'User rejected connection proposal', + userRejectedExisting = 'User rejected existing connection proposal', + errorLogout = 'Unable to remove existing pairing', + invalidChainID = 'Invalid chainID', + actionError = 'Unable to send event' +} + +// types here need to be synced with the types in sdk-dapp-core-ui +export enum WalletConnectEventsEnum { + 'CLOSE' = 'CLOSE', + 'DATA_UPDATE' = 'DATA_UPDATE' +} + +export interface IWalletConnectModalData { + wcURI: string; + shouldClose?: boolean; +} + +export interface WalletConnectConfig { + walletConnectV2ProjectId: string; + /** + * Function to be called when disconnecting the dApp from xPortal. + * Handles user redirection or cleanup after logout. + */ + onLogout: () => Promise; + walletConnectV2RelayAddress?: string; + walletConnectV2Options?: WalletConnectV2ProviderOptionsType; + customRequestMethods?: Array; +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/calculateFeeInFiat.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/calculateFeeInFiat.ts new file mode 100644 index 0000000..86606bb --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/calculateFeeInFiat.ts @@ -0,0 +1,34 @@ +import { DIGITS, DECIMALS } from 'constants/index'; +import { formatAmount } from 'lib/sdkDappUtils'; +import { getUsdValue } from './getUsdValue'; + +export interface CalculateFeeInFiatType { + feeLimit: string; + egldPriceInUsd: number; + hideEqualSign?: boolean; +} + +export const calculateFeeInFiat = ({ + feeLimit, + egldPriceInUsd, + hideEqualSign +}: CalculateFeeInFiatType) => { + const amount = formatAmount({ + input: feeLimit, + decimals: DECIMALS, + digits: DIGITS, + showLastNonZeroDecimal: true + }); + + const feeAsUsdValue = getUsdValue({ + amount, + usd: egldPriceInUsd, + decimals: DIGITS + }); + + if (hideEqualSign) { + return feeAsUsdValue; + } + + return `≈ ${feeAsUsdValue}`; +}; diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/calculateFeeLimit.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/calculateFeeLimit.ts new file mode 100755 index 0000000..ad1ee86 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/calculateFeeLimit.ts @@ -0,0 +1,76 @@ +import { + Transaction, + TransactionPayload, + TransactionVersion, + Address, + TokenPayment +} from '@multiversx/sdk-core'; +import BigNumber from 'bignumber.js'; +import { + EXTRA_GAS_LIMIT_GUARDED_TX, + GAS_LIMIT, + GAS_PRICE, + ZERO +} from 'constants/index'; +import { isGuardianTx } from 'utils/transactions/isGuardianTx'; +import { stringIsFloat, stringIsInteger } from 'utils/validation'; + +export interface CalculateFeeLimitType { + gasLimit: string; + gasPrice: string; + data: string; + gasPerDataByte: string; + gasPriceModifier: string; + chainId: string; + minGasLimit?: string; + defaultGasPrice?: string; +} +const placeholderData = { + from: 'erd12dnfhej64s6c56ka369gkyj3hwv5ms0y5rxgsk2k7hkd2vuk7rvqxkalsa', + to: 'erd12dnfhej64s6c56ka369gkyj3hwv5ms0y5rxgsk2k7hkd2vuk7rvqxkalsa' +}; +export function calculateFeeLimit({ + minGasLimit = String(GAS_LIMIT), + gasLimit, + gasPrice, + data: inputData, + gasPerDataByte, + gasPriceModifier, + defaultGasPrice = String(GAS_PRICE), + chainId +}: CalculateFeeLimitType) { + const data = inputData || ''; + const validGasLimit = stringIsInteger(gasLimit) ? gasLimit : minGasLimit; + + // We need to add extra gas fee for guardian transactions + const extraGasLimit = isGuardianTx({ data }) ? EXTRA_GAS_LIMIT_GUARDED_TX : 0; + const usedGasLimit = new BigNumber(validGasLimit) + .plus(extraGasLimit) + .toNumber(); + + const validGasPrice = stringIsFloat(gasPrice) ? gasPrice : defaultGasPrice; + const transaction = new Transaction({ + nonce: 0, + value: TokenPayment.egldFromAmount('0'), + receiver: new Address(placeholderData.to), + sender: new Address(placeholderData.to), + gasPrice: parseInt(validGasPrice), + gasLimit: usedGasLimit, + data: new TransactionPayload(data.trim()), + chainID: chainId, + version: new TransactionVersion(1) + }); + + try { + const bNfee = transaction.computeFee({ + GasPerDataByte: parseInt(gasPerDataByte), + MinGasLimit: parseInt(minGasLimit), + GasPriceModifier: parseFloat(gasPriceModifier), + ChainID: chainId + }); + return bNfee.toString(10); + } catch (err) { + console.error(err); + return ZERO; + } +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/checkIsValidSender.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/checkIsValidSender.ts new file mode 100644 index 0000000..ed420ee --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/checkIsValidSender.ts @@ -0,0 +1,25 @@ +import { AccountType } from 'types/account.types'; + +// Don't allow signing if the logged in account's address +// is neither the sender or the sender account's active guardian +export const checkIsValidSender = ( + senderAccount: Partial | null, + address: string | string[] +) => { + if (!senderAccount) { + return true; + } + + if (Array.isArray(address)) { + return address.some( + (addr) => + senderAccount.address === addr || + senderAccount.activeGuardianAddress === addr + ); + } + + return ( + senderAccount.address === address || + senderAccount.activeGuardianAddress === address + ); +}; diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getExtractTransactionsInfo.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getExtractTransactionsInfo.ts new file mode 100644 index 0000000..d719f74 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getExtractTransactionsInfo.ts @@ -0,0 +1,84 @@ +import { getAccountFromApi } from 'apiCalls/account'; +import { getScamAddressData } from 'apiCalls/utils/getScamAddressData'; +import { SENDER_DIFFERENT_THAN_LOGGED_IN_ADDRESS } from 'constants/errorMessages.constants'; + +import { MultiSignTransactionType } from 'types/transactions.types'; +import { checkIsValidSender } from './checkIsValidSender'; +import { getMultiEsdtTransferData } from './getMultiEsdtTransferData/getMultiEsdtTransferData'; +import { isTokenTransfer } from './isTokenTransfer'; + +interface VerifiedAddressesType { + [address: string]: { type: string; info: string }; +} +let verifiedAddresses: VerifiedAddressesType = {}; + +type ExtractTransactionsInfoType = { + getTxInfoByDataField: ReturnType< + typeof getMultiEsdtTransferData + >['getTxInfoByDataField']; + sender: string; + address: string; + egldLabel: string; +}; + +export function getExtractTransactionsInfo({ + getTxInfoByDataField, + egldLabel, + sender, + address +}: ExtractTransactionsInfoType) { + const extractTransactionsInfo = async ( + currentTx: MultiSignTransactionType + ) => { + if (currentTx == null) { + return; + } + + const senderAccount = + !sender || sender === address ? null : await getAccountFromApi(sender); + + const { transaction, multiTxData, transactionIndex } = currentTx; + const dataField = transaction.getData().toString(); + const transactionTokenInfo = getTxInfoByDataField( + transaction.getData().toString(), + multiTxData + ); + + const { tokenId } = transactionTokenInfo; + const receiver = transaction.getReceiver().toString(); + + if (sender && sender !== address) { + const isValidSender = checkIsValidSender(senderAccount, address); + + if (!isValidSender) { + console.error(SENDER_DIFFERENT_THAN_LOGGED_IN_ADDRESS); + throw SENDER_DIFFERENT_THAN_LOGGED_IN_ADDRESS; + } + } + + const notSender = address !== receiver; + const verified = receiver in verifiedAddresses; + + if (receiver && notSender && !verified) { + const data = await getScamAddressData(receiver); + verifiedAddresses = { + ...verifiedAddresses, + ...(data?.scamInfo ? { [receiver]: data.scamInfo } : {}) + }; + } + + const isTokenTransaction = Boolean( + tokenId && isTokenTransfer({ tokenId, egldLabel }) + ); + + return { + transaction, + receiverScamInfo: verifiedAddresses[receiver]?.info || null, + transactionTokenInfo, + isTokenTransaction, + dataField, + transactionIndex + }; + }; + return extractTransactionsInfo; +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/getMultiEsdtTransferData.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/getMultiEsdtTransferData.ts new file mode 100644 index 0000000..9b9cfd3 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/getMultiEsdtTransferData.ts @@ -0,0 +1,59 @@ +import { Transaction } from '@multiversx/sdk-core'; +import { + MultiSignTransactionType, + TransactionDataTokenType, + TransactionsDataTokensType +} from 'types/transactions.types'; +import { parseMultiEsdtTransferDataForMultipleTransactions } from './helpers/parseMultiEsdtTransferDataForMultipleTransactions'; + +const defaultTransactionInfo: TransactionDataTokenType = { + tokenId: '', + amount: '', + type: '', + multiTxData: '', + receiver: '' +}; + +export type MultiEsdtTransferDataReturnType = ReturnType< + typeof getMultiEsdtTransferData +>; + +export function getMultiEsdtTransferData(transactions?: Transaction[]): { + parsedTransactionsByDataField: TransactionsDataTokensType; + getTxInfoByDataField: ( + data: string, + multiTransactionData?: string + ) => TransactionDataTokenType; + allTransactions: MultiSignTransactionType[]; +} { + const { allTransactions, parsedTransactionsByDataField } = + parseMultiEsdtTransferDataForMultipleTransactions({ transactions }); + + function getTxInfoByDataField( + data: string, + multiTransactionData?: string + ): TransactionDataTokenType { + if (parsedTransactionsByDataField == null) { + return defaultTransactionInfo; + } + + if (data in parsedTransactionsByDataField) { + return parsedTransactionsByDataField[data]; + } + + if ( + multiTransactionData != null && + String(multiTransactionData) in parsedTransactionsByDataField + ) { + return parsedTransactionsByDataField[multiTransactionData]; + } + + return defaultTransactionInfo; + } + + return { + parsedTransactionsByDataField, + getTxInfoByDataField, + allTransactions + }; +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/getAllStringOccurrences.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/getAllStringOccurrences.ts new file mode 100644 index 0000000..df64bb0 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/getAllStringOccurrences.ts @@ -0,0 +1,15 @@ +export const getAllStringOccurrences = ( + sourceStr: string, + searchStr: string +) => { + const startingIndices = []; + + let indexOccurence = sourceStr.indexOf(searchStr, 0); + + while (indexOccurence >= 0) { + startingIndices.push(indexOccurence); + indexOccurence = sourceStr.indexOf(searchStr, indexOccurence + 1); + } + + return startingIndices; +}; diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/getTokenFromData.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/getTokenFromData.ts new file mode 100644 index 0000000..a8e3467 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/getTokenFromData.ts @@ -0,0 +1,99 @@ +import { Address } from '@multiversx/sdk-core'; +import BigNumber from 'bignumber.js'; +import { TransactionTypesEnum } from 'types/enums.types'; +import { decodePart } from 'utils/decoders/decodePart'; +import { addressIsValid } from 'utils/validation/addressIsValid'; + +const noData = { + tokenId: '', + amount: '' +}; + +export const decodeData = (data: string) => { + const nonceIndex = 2; + const amountIndex = 3; + const parts = data.split('@'); + const decodedParts = parts.map((part, i) => + [nonceIndex, amountIndex].includes(i) ? part : decodePart(part) + ); + return decodedParts; +}; + +export function getTokenFromData(data?: string): { + tokenId: string; + amount: string; + collection?: string; + nonce?: string; + receiver?: string; +} { + if (!data) { + return noData; + } + + const isTokenTransfer = data.startsWith(TransactionTypesEnum.ESDTTransfer); + const isNftTransfer = + data.startsWith(TransactionTypesEnum.ESDTNFTTransfer) && data.includes('@'); + const isNftBurn = + data.startsWith(TransactionTypesEnum.ESDTNFTBurn) && data.includes('@'); + + if (isTokenTransfer) { + const [, encodedToken, encodedAmount] = data.split('@'); + try { + const tokenId = Buffer.from(encodedToken, 'hex').toString('ascii'); + + if (!tokenId) { + return noData; + } + + const amount = new BigNumber( + '0x' + encodedAmount.replace('0x', '') + ).toString(10); + + return { + tokenId, + amount + }; + } catch (e) { + console.error('Error getting token from transaction data', e); + } + } + + if (isNftTransfer) { + try { + const [, /*ESDTNFTTransfer*/ collection, nonce, quantity, receiver] = + decodeData(data); + if ( + [collection, nonce, quantity, receiver].every((el) => Boolean(el)) && + addressIsValid(new Address(receiver).bech32()) + ) { + return { + tokenId: `${collection}-${nonce}`, + amount: new BigNumber(quantity, 16).toString(10), + collection, + nonce, + receiver: new Address(receiver).bech32() + }; + } + } catch (_err) { + /* empty */ + } + } + + if (isNftBurn) { + try { + const [, /*ESDTNFTBurn*/ collection, nonce, quantity] = decodeData(data); + if ([collection, nonce, quantity].every((el) => Boolean(el))) { + return { + tokenId: `${collection}-${nonce}`, + amount: new BigNumber(quantity, 16).toString(10), + collection, + nonce + }; + } + } catch (_err) { + /* empty */ + } + } + + return noData; +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/parseMultiEsdtTransferData.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/parseMultiEsdtTransferData.ts new file mode 100644 index 0000000..ec7c0b3 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/parseMultiEsdtTransferData.ts @@ -0,0 +1,98 @@ +import BigNumber from 'bignumber.js'; +import { TransactionTypesEnum } from 'types/enums.types'; +import { MultiEsdtTransactionType } from 'types/transactions.types'; +import { decodePart } from 'utils/decoders/decodePart'; +import { getAllStringOccurrences } from './getAllStringOccurrences'; + +// TODO: add tests +export function parseMultiEsdtTransferData(data?: string) { + const transactions: MultiEsdtTransactionType[] = []; + let contractCallDataIndex = 0; + try { + if ( + data?.startsWith(TransactionTypesEnum.MultiESDTNFTTransfer) && + data?.includes('@') + ) { + const [, receiver, encodedTxCount, ...rest] = data.split('@'); + + if (receiver) { + const txCount = new BigNumber(encodedTxCount, 16).toNumber(); + + if (txCount >= Number.MAX_SAFE_INTEGER) { + return []; + } + + let itemIndex = 0; + + for (let txIndex = 0; txIndex < txCount; txIndex++) { + const transaction: MultiEsdtTransactionType = { + type: TransactionTypesEnum.nftTransaction, + data: '', + receiver + }; + + for (let index = 0; index < 3; index++) { + switch (index) { + case 0: + transaction.token = decodePart(rest[itemIndex]); + transaction.data = rest[itemIndex]; + break; + case 1: { + const encodedNonce = + rest[itemIndex] && rest[itemIndex].length + ? rest[itemIndex] + : ''; + if (encodedNonce && encodedNonce !== '00') { + transaction.nonce = encodedNonce; + } else { + transaction.type = TransactionTypesEnum.esdtTransaction; + } + transaction.data = `${transaction.data}@${rest[itemIndex]}`; + break; + } + case 2: + transaction.amount = new BigNumber( + rest[itemIndex], + 16 + ).toString(10); + transaction.data = `${transaction.data}@${rest[itemIndex]}`; + break; + default: + break; + } + contractCallDataIndex = itemIndex + 1; + itemIndex++; + } + transactions[txIndex] = transaction; + } + + const isDifferentFromTxCount = transactions.length !== txCount; + const hasInvalidNoOfAdSigns = transactions.some((tx) => { + const adSignOccurences = getAllStringOccurrences(tx.data, '@').length; + return adSignOccurences !== 2; + }); + + const hasAdStart = transactions.some((tx) => tx.data.startsWith('@')); + if (isDifferentFromTxCount || hasInvalidNoOfAdSigns || hasAdStart) { + return []; + } + + if (rest[contractCallDataIndex]) { + let scCallData = rest[contractCallDataIndex]; + for (let i = contractCallDataIndex + 1; i < rest.length; i++) { + scCallData += '@' + rest[i]; + } + transactions[txCount] = { + type: TransactionTypesEnum.scCall, + data: scCallData, + receiver + }; + } + } + } + } catch (err) { + console.error('failed parsing tx', err); + return transactions; + } + return transactions; +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/parseMultiEsdtTransferDataForMultipleTransactions.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/parseMultiEsdtTransferDataForMultipleTransactions.ts new file mode 100644 index 0000000..7265ffb --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/helpers/parseMultiEsdtTransferDataForMultipleTransactions.ts @@ -0,0 +1,72 @@ +import type { Transaction } from '@multiversx/sdk-core'; + +import { + MultiSignTransactionType, + TransactionsDataTokensType +} from 'types/transactions.types'; +import { getTokenFromData } from './getTokenFromData'; +import { parseMultiEsdtTransferData } from './parseMultiEsdtTransferData'; + +export function parseMultiEsdtTransferDataForMultipleTransactions({ + transactions +}: { + transactions?: Transaction[]; +}) { + const allTransactions: MultiSignTransactionType[] = []; + const parsedTransactionsByDataField: TransactionsDataTokensType = {}; + + if (!transactions || transactions.length === 0) { + return { + allTransactions, + parsedTransactionsByDataField + }; + } + + transactions.forEach((transaction, transactionIndex) => { + const txData = transaction.getData().toString(); + const multiTxs = parseMultiEsdtTransferData(txData); + + if (multiTxs.length > 0) { + multiTxs.forEach((trx, idx) => { + const newTx: MultiSignTransactionType = { + transaction, + multiTxData: trx.data, + transactionIndex: idx + }; + + parsedTransactionsByDataField[trx.data] = { + tokenId: trx.token ? trx.token : '', + amount: trx.amount ? trx.amount : '', + type: trx.type, + nonce: trx.nonce ? trx.nonce : '', + multiTxData: trx.data, + receiver: trx.receiver + }; + + allTransactions.push(newTx); + }); + } else { + const transactionData = transaction.getData().toString(); + + const { tokenId, amount } = getTokenFromData(transactionData); + + if (tokenId) { + parsedTransactionsByDataField[transactionData] = { + tokenId, + amount, + receiver: transaction.getReceiver().bech32() + }; + } + allTransactions.push({ + transaction, + transactionIndex, + multiTxData: transactionData + }); + } + }); + + return { + allTransactions, + parsedTransactionsByDataField + }; +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/tests/getMultiEsdtTransferData.test.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/tests/getMultiEsdtTransferData.test.ts new file mode 100644 index 0000000..bf0ec43 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getMultiEsdtTransferData/tests/getMultiEsdtTransferData.test.ts @@ -0,0 +1,9 @@ +import { getMultiEsdtTransferData } from '../getMultiEsdtTransferData'; + +describe('getMultiEsdtTransferData', () => { + it('should extract transaction information', async () => { + const data = getMultiEsdtTransferData([]); + // Assert the result is correct based on your mock data + expect(data).toBeTruthy(); + }); +}); diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/getUsdValue.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/getUsdValue.ts new file mode 100644 index 0000000..8558ad8 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/getUsdValue.ts @@ -0,0 +1,24 @@ +export const getUsdValue = ({ + amount, + usd, + decimals = 2, + addEqualSign +}: { + amount: string; + usd: number; + decimals?: number; + addEqualSign?: boolean; +}) => { + let sum = (parseFloat(amount) * usd).toFixed(decimals); + if (isNaN(Number(sum))) { + sum = '0'; + } + + const formattedValue = parseFloat(sum).toLocaleString('en', { + maximumFractionDigits: decimals, + minimumFractionDigits: decimals + }); + const equalSign = parseFloat(amount) > 0 ? '≈' : '='; + const equalSignPrefix = addEqualSign ? `${equalSign} ` : ''; + return `${equalSignPrefix}$${formattedValue}`; +}; diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/isTokenTransfer.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/isTokenTransfer.ts new file mode 100644 index 0000000..c68d6c9 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/isTokenTransfer.ts @@ -0,0 +1,9 @@ +export function isTokenTransfer({ + tokenId, + egldLabel +}: { + tokenId: string | undefined; + egldLabel: string; +}) { + return Boolean(tokenId && tokenId !== egldLabel); +} diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/tests/calculateFeeInFiat.test.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/tests/calculateFeeInFiat.test.ts new file mode 100644 index 0000000..1d8257a --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/tests/calculateFeeInFiat.test.ts @@ -0,0 +1,11 @@ +import { calculateFeeInFiat } from '../calculateFeeInFiat'; + +describe('calculateFeeInFiat tests', () => { + it('computes correct fee in fiat', () => { + const fee = calculateFeeInFiat({ + feeLimit: '50000000000000', + egldPriceInUsd: 135.78 + }); + expect(fee).toBe('≈ $0.0068'); + }); +}); diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/tests/calculateFeeLimit.test.tsx b/src/core/providers/strategies/helpers/signTransactions/helpers/tests/calculateFeeLimit.test.tsx new file mode 100644 index 0000000..009caad --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/tests/calculateFeeLimit.test.tsx @@ -0,0 +1,96 @@ +import { GAS_PER_DATA_BYTE, GAS_PRICE_MODIFIER } from 'constants/index'; +import { calculateFeeLimit } from '../calculateFeeLimit'; + +describe('calculateFeeLimit tests', () => { + it('computes correct fee', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: '62000', + gasPrice: '1000000000', + data: 'testdata', + chainId: 'T', + gasPerDataByte: String(GAS_PER_DATA_BYTE), + gasPriceModifier: String(GAS_PRICE_MODIFIER) + }); + expect(feeLimit).toBe('62000000000000'); + }); + + it('computes correct fee for larger data', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: '11100000', + gasPrice: '1000000000', + data: 'bid@0d59@43525a502d333663366162@25', + gasPerDataByte: String(GAS_PER_DATA_BYTE), + gasPriceModifier: String(GAS_PRICE_MODIFIER), + defaultGasPrice: '1000000000', + chainId: 'T' + }); + + expect(feeLimit).toBe('210990000000000'); + }); + + it('computes correct fee for SetGuardian tx', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: '', + gasPrice: (1_000_000).toString(), + data: 'SetGuardian@qwerty@12345', + chainId: 'T', + gasPerDataByte: '1', + gasPriceModifier: '1' + }); + + expect(feeLimit).toBe((100_000_000_000).toString()); // (minGasLimit + extra guardian gas) * gasPrice + }); + + it('computes correct fee for GuardAccount tx', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: '', + gasPrice: (1_000_000).toString(), + data: 'GuardAccount@qwerty@12345', + chainId: 'T', + gasPerDataByte: '1', + gasPriceModifier: '1' + }); + + expect(feeLimit).toBe((100_000_000_000).toString()); // (minGasLimit + extra guardian gas) * gasPrice + }); + + it('computes correct fee for UnGuardAccount tx', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: '', + gasPrice: (1_000_000).toString(), + data: 'UnGuardAccount@qwerty@12345', + chainId: 'T', + gasPerDataByte: '1', + gasPriceModifier: '1' + }); + + expect(feeLimit).toBe((100_000_000_000).toString()); // (minGasLimit + extra guardian gas) * gasPrice + }); + + it('computes correct fee for UnGuardAccount tx and gas limit specified', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: (1_000_000).toString(), + gasPrice: (1_000_000).toString(), + data: 'UnGuardAccount@qwerty@12345', + chainId: 'T', + gasPerDataByte: '1', + gasPriceModifier: '1' + }); + + expect(feeLimit).toBe((1_050_000_000_000).toString()); // (gasLimit + extra guardian gas) * gasPrice + }); + + it('computes correct fee for UnGuardAccount tx and min gas limit specified', () => { + const feeLimit = calculateFeeLimit({ + gasLimit: '', + minGasLimit: (1_000_000).toString(), + gasPrice: (1_000_000).toString(), + data: 'UnGuardAccount@qwerty@12345', + chainId: 'T', + gasPerDataByte: '1', + gasPriceModifier: '1' + }); + + expect(feeLimit).toBe((1_050_000_000_000).toString()); // (minGasLimit + extra guardian gas) * gasPrice + }); +}); diff --git a/src/core/providers/strategies/helpers/signTransactions/helpers/tests/getUsdValue.test.ts b/src/core/providers/strategies/helpers/signTransactions/helpers/tests/getUsdValue.test.ts new file mode 100644 index 0000000..927d6f4 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/helpers/tests/getUsdValue.test.ts @@ -0,0 +1,23 @@ +import { getUsdValue } from '../getUsdValue'; + +describe('getUsdValue tests', () => { + it('formats amount', () => { + expect( + getUsdValue({ + amount: '2', + usd: 40, + decimals: 4, + addEqualSign: true + }) + ).toBe('≈ $80.0000'); + }); + it('shows = for 0', () => { + expect( + getUsdValue({ + amount: '0', + usd: 40, + addEqualSign: true + }) + ).toBe('= $0.00'); + }); +}); diff --git a/src/core/providers/strategies/helpers/signTransactions/signTransactions.ts b/src/core/providers/strategies/helpers/signTransactions/signTransactions.ts new file mode 100644 index 0000000..c8720d8 --- /dev/null +++ b/src/core/providers/strategies/helpers/signTransactions/signTransactions.ts @@ -0,0 +1,222 @@ +import { Transaction } from '@multiversx/sdk-core/out'; +import { getEconomics } from 'apiCalls/economics/getEconomics'; +import { getPersistedTokenDetails } from 'apiCalls/tokens/getPersistedTokenDetails'; +import { GAS_PER_DATA_BYTE, GAS_PRICE_MODIFIER } from 'constants/mvx.constants'; +import { SignTransactionsStateManager } from 'core/managers/SignTransactionsStateManager/SignTransactionsStateManager'; +import { + TokenType, + SignEventsEnum +} from 'core/managers/SignTransactionsStateManager/types'; +import { getAddress } from 'core/methods/account/getAddress'; +import { getEgldLabel } from 'core/methods/network/getEgldLabel'; +import { IProvider } from 'core/providers/types/providerFactory.types'; +import { SignTransactionsModal } from 'lib/sdkDappCoreUi'; +import { formatAmount } from 'lib/sdkDappUtils'; +import { networkSelector } from 'store/selectors/networkSelectors'; +import { getState } from 'store/store'; +import { EsdtEnumType, NftEnumType } from 'types/tokens.types'; +import { createModalElement } from 'utils/createModalElement'; +import { calculateFeeInFiat } from './helpers/calculateFeeInFiat'; +import { calculateFeeLimit } from './helpers/calculateFeeLimit'; +import { getExtractTransactionsInfo } from './helpers/getExtractTransactionsInfo'; +import { getMultiEsdtTransferData } from './helpers/getMultiEsdtTransferData/getMultiEsdtTransferData'; +import { getUsdValue } from './helpers/getUsdValue'; + +export async function signTransactions({ + transactions = [], + handleSign +}: { + transactions?: Transaction[]; + handleSign: IProvider['signTransactions']; +}) { + const address = getAddress(); + const network = networkSelector(getState()); + + const egldLabel = getEgldLabel(); + const signModalElement = await createModalElement( + 'sign-transactions-modal' + ); + + const { allTransactions, getTxInfoByDataField } = + getMultiEsdtTransferData(transactions); + + const eventBus = await signModalElement.getEventBus(); + + if (!eventBus) { + throw new Error('Event bus not provided for Ledger provider'); + } + + const manager = SignTransactionsStateManager.getInstance(eventBus); + if (!manager) { + throw new Error('Unable to establish connection with sign screens'); + } + + return new Promise(async (resolve, reject) => { + const signedTransactions: Transaction[] = []; + let currentTransactionIndex = 0; + const economics = await getEconomics(); + + const signNextTransaction = async () => { + const currentTransaction = allTransactions[currentTransactionIndex]; + const sender = currentTransaction?.transaction?.getSender().toString(); + const transaction = currentTransaction?.transaction; + const price = economics?.price; + + const feeLimit = calculateFeeLimit({ + gasPerDataByte: String(GAS_PER_DATA_BYTE), + gasPriceModifier: String(GAS_PRICE_MODIFIER), + gasLimit: transaction.getGasLimit().valueOf().toString(), + gasPrice: transaction.getGasPrice().valueOf().toString(), + data: transaction.getData().toString(), + chainId: transaction.getChainID().valueOf() + }); + + const feeLimitFormatted = formatAmount({ + input: feeLimit, + showLastNonZeroDecimal: true + }); + + const feeInFiatLimit = price + ? calculateFeeInFiat({ + feeLimit, + egldPriceInUsd: price, + hideEqualSign: true + }) + : null; + + const extractTransactionsInfo = getExtractTransactionsInfo({ + getTxInfoByDataField, + egldLabel, + sender, + address + }); + + const plainTransaction = currentTransaction.transaction.toPlainObject(); + + const txInfo = await extractTransactionsInfo(currentTransaction); + + let tokenIdForTokenDetails = txInfo?.transactionTokenInfo?.tokenId; + const isEgld = !tokenIdForTokenDetails; + let tokenAmount = ''; + + let tokenType: TokenType = null; + + if (txInfo?.transactionTokenInfo) { + const { tokenId, nonce, amount } = txInfo.transactionTokenInfo; + const isNftOrSft = nonce && nonce.length > 0; + tokenIdForTokenDetails = isNftOrSft ? `${tokenId}-${nonce}` : tokenId; + tokenType = isNftOrSft ? null : EsdtEnumType.FungibleESDT; + tokenAmount = amount; + } + + const tokenDetails = await getPersistedTokenDetails({ + tokenId: tokenIdForTokenDetails + }); + + const { esdtPrice, tokenDecimals, type, identifier, tokenImageUrl } = + tokenDetails; + + const isNft = + type === NftEnumType.SemiFungibleESDT || + type === NftEnumType.NonFungibleESDT; + + if (isNft) { + manager.updateFungibleTransaction(type, { + identifier, + amount: tokenAmount, + imageURL: tokenImageUrl + }); + } else { + const getFormattedAmount = ({ addCommas }: { addCommas: boolean }) => + formatAmount({ + input: isEgld + ? currentTransaction.transaction.getValue().toString() + : tokenAmount, + decimals: isEgld ? Number(network.decimals) : tokenDecimals, + digits: Number(network.digits), + showLastNonZeroDecimal: false, + addCommas + }); + + const formattedAmount = getFormattedAmount({ addCommas: true }); + const rawAmount = getFormattedAmount({ addCommas: false }); + const tokenPrice = Number(isEgld ? price : esdtPrice); + const usdValue = getUsdValue({ + amount: rawAmount, + usd: tokenPrice, + addEqualSign: true + }); + manager.updateTokenTransaction({ + identifier: identifier ?? egldLabel, + amount: formattedAmount, + usdValue + }); + } + + manager.updateCommonData({ + receiver: plainTransaction.receiver.toString(), + data: currentTransaction.transaction.getData().toString(), + egldLabel, + tokenType, + feeLimit: feeLimitFormatted, + feeInFiatLimit, + transactionsCount: allTransactions.length, + currentIndex: currentTransactionIndex + }); + + const onCancel = () => { + reject(new Error('Transaction signing cancelled by user')); + signModalElement.remove(); + }; + + const onSign = async () => { + const shouldContinueWithoutSigning = Boolean( + txInfo?.transactionTokenInfo?.type && + txInfo?.transactionTokenInfo?.multiTxData && + !txInfo?.dataField.endsWith( + txInfo?.transactionTokenInfo?.multiTxData + ) + ); + + const removeEvents = () => { + eventBus.unsubscribe(SignEventsEnum.SIGN_TRANSACTION, onSign); + eventBus.unsubscribe(SignEventsEnum.CLOSE, onCancel); + }; + + if (shouldContinueWithoutSigning) { + currentTransactionIndex++; + removeEvents(); + return signNextTransaction(); + } + + try { + const signedTransaction = await handleSign([ + currentTransaction.transaction + ]); + + if (signedTransaction) { + signedTransactions.push(signedTransaction[0]); + } + + removeEvents(); + + if (signedTransactions.length == transactions.length) { + signModalElement.remove(); + resolve(signedTransactions); + } else { + currentTransactionIndex++; + signNextTransaction(); + } + } catch (error) { + reject('Error signing transactions: ' + error); + signModalElement.remove(); + } + }; + + eventBus.subscribe(SignEventsEnum.SIGN_TRANSACTION, onSign); + eventBus.subscribe(SignEventsEnum.CLOSE, onCancel); + }; + + signNextTransaction(); + }); +} diff --git a/src/core/providers/strategies/index.ts b/src/core/providers/strategies/index.ts new file mode 100644 index 0000000..bc64baf --- /dev/null +++ b/src/core/providers/strategies/index.ts @@ -0,0 +1,5 @@ +export * from './CrossWindowProviderStrategy'; +export * from './ExtensionProviderStrategy'; +export * from './IFrameProviderStrategy'; +export * from './LedgerProviderStrategy'; +export * from './WalletConnectProviderStrategy'; diff --git a/src/core/providers/types/providerFactory.types.ts b/src/core/providers/types/providerFactory.types.ts index ee6a022..02e3b43 100644 --- a/src/core/providers/types/providerFactory.types.ts +++ b/src/core/providers/types/providerFactory.types.ts @@ -1,7 +1,8 @@ import type { IDAppProviderBase } from '@multiversx/sdk-dapp-utils'; // @ts-ignore -export interface IProvider extends IDAppProviderBase { +export interface IProvider + extends IDAppProviderBase { init: () => Promise; login: (options?: { callbackUrl?: string; token?: string }) => Promise<{ address: string; @@ -12,7 +13,7 @@ export interface IProvider extends IDAppProviderBase { }>; logout: () => Promise; setShouldShowConsentPopup?: (shouldShow: boolean) => void; - getType: () => ProviderTypeEnum; + getType: () => T[keyof T] | string; getAddress(): Promise; // TODO will be removed as soon as the new login method is implemented in the same way for all providers getTokenLoginSignature(): string | undefined; @@ -20,9 +21,8 @@ export interface IProvider extends IDAppProviderBase { } export interface IProviderConfig { - // TODO check if we have to pass the network object as argument here or it should be read from the state - network: { - walletAddress: string; + account?: { + address: string; }; } @@ -31,16 +31,24 @@ export enum ProviderTypeEnum { crossWindow = 'crossWindow', extension = 'extension', walletConnect = 'walletConnect', - hardware = 'hardware', + ledger = 'ledger', opera = 'opera', metamask = 'metamask', - webhook = 'webhook', - custom = 'custom', + passkey = 'passkey', none = '' } -export interface IProviderFactory { - type: ProviderTypeEnum; - config: IProviderConfig; - customProvider?: IProvider; +export interface IProviderFactory< + T extends ProviderTypeEnum = ProviderTypeEnum +> { + type: T[keyof T]; +} + +export interface ICustomProvider< + T extends ProviderTypeEnum = ProviderTypeEnum +> { + name: string; + type: T[keyof T]; + icon: string; + constructor: (address?: string) => Promise; } diff --git a/src/lib/sdkDappCoreUi.ts b/src/lib/sdkDappCoreUi.ts new file mode 100644 index 0000000..c389f0a --- /dev/null +++ b/src/lib/sdkDappCoreUi.ts @@ -0,0 +1,18 @@ +import type { CustomElementsDefineOptions } from '@multiversx/sdk-dapp-core-ui/loader'; +export type { LedgerConnectModal } from '@multiversx/sdk-dapp-core-ui/dist/components/ledger-connect-modal'; +export type { SignTransactionsModal } from '@multiversx/sdk-dapp-core-ui/dist/components/sign-transactions-modal'; +export type { WalletConnectModal } from '@multiversx/sdk-dapp-core-ui/dist/components/wallet-connect-modal'; +export type { PendingTransactionsModal } from '@multiversx/sdk-dapp-core-ui/dist/components/pending-transactions-modal'; +export type { TransactionToastList } from '@multiversx/sdk-dapp-core-ui/dist/components/transaction-toast-list'; + +export async function defineCustomElements( + win?: Window, + opts?: CustomElementsDefineOptions +): Promise { + try { + const loader = await import('@multiversx/sdk-dapp-core-ui/loader'); + loader.defineCustomElements(win, opts); + } catch (err) { + throw new Error('@multiversx/sdk-dapp-core-ui not found' + err); + } +} diff --git a/src/lib/sdkDappUtils.ts b/src/lib/sdkDappUtils.ts new file mode 100644 index 0000000..756625a --- /dev/null +++ b/src/lib/sdkDappUtils.ts @@ -0,0 +1 @@ +export { formatAmount } from '@multiversx/sdk-dapp-utils/out/helpers'; diff --git a/src/services/nativeAuth/helpers/decodeNativeAuthToken.ts b/src/services/nativeAuth/helpers/decodeNativeAuthToken.ts index 35c1881..8ae1819 100644 --- a/src/services/nativeAuth/helpers/decodeNativeAuthToken.ts +++ b/src/services/nativeAuth/helpers/decodeNativeAuthToken.ts @@ -57,7 +57,7 @@ export const decodeNativeAuthToken = ( } return result; - } catch (err) { + } catch (_err) { return null; } }; diff --git a/src/services/nativeAuth/helpers/getLatestBlockHash.ts b/src/services/nativeAuth/helpers/getLatestBlockHash.ts index 72e3375..2f748f2 100644 --- a/src/services/nativeAuth/helpers/getLatestBlockHash.ts +++ b/src/services/nativeAuth/helpers/getLatestBlockHash.ts @@ -92,7 +92,7 @@ export async function getLatestBlockHash( requestPromise.current = null; return response; - } catch (err) { + } catch (_error) { requestPromise.current = null; return null as any; } diff --git a/src/services/nativeAuth/methods/getDefaultNativeAuthConfig.ts b/src/services/nativeAuth/methods/getDefaultNativeAuthConfig.ts index 0ae7fe4..beb8848 100644 --- a/src/services/nativeAuth/methods/getDefaultNativeAuthConfig.ts +++ b/src/services/nativeAuth/methods/getDefaultNativeAuthConfig.ts @@ -1,9 +1,11 @@ import { getWindowLocation } from 'utils/window/getWindowLocation'; -export const getDefaultNativeAuthConfig = () => { +export const getDefaultNativeAuthConfig = ( + apiAddress = 'https://api.multiversx.com' +) => { return { origin: getWindowLocation().origin, - apiAddress: 'https://api.multiversx.com', + apiAddress, expirySeconds: 60 * 60 * 24, // one day tokenExpirationToastWarningSeconds: 5 * 60 // five minutes }; diff --git a/src/storage/local.ts b/src/storage/local.ts index ac027e5..a0d906d 100644 --- a/src/storage/local.ts +++ b/src/storage/local.ts @@ -6,7 +6,7 @@ export const localStorageKeys = { } as const; type LocalValueType = keyof typeof localStorageKeys; -type LocalKeyType = typeof localStorageKeys[LocalValueType]; +type LocalKeyType = (typeof localStorageKeys)[LocalValueType]; type ExpiresType = number | false; diff --git a/src/store/actions/account/accountActions.ts b/src/store/actions/account/accountActions.ts index 29f0fc2..858ea4d 100644 --- a/src/store/actions/account/accountActions.ts +++ b/src/store/actions/account/accountActions.ts @@ -1,23 +1,24 @@ -import { getStore } from 'store/store'; -import { AccountType } from 'types/account.types'; -import { emptyAccount } from 'store/slices/account/emptyAccount'; import { BatchTransactionsWSResponseType, LedgerAccountType } from 'store/slices/account/account.types'; +import { emptyAccount } from 'store/slices/account/emptyAccount'; +import { getStore } from 'store/store'; +import { AccountType } from 'types/account.types'; export const setAddress = (address: string) => getStore().setState(({ account: state }) => { state.address = address; }); -export const setAccount = (account: AccountType) => +export const setAccount = (account: AccountType) => { getStore().setState(({ account: state }) => { const isSameAddress = state.address === account.address; state.accounts = { [state.address]: isSameAddress ? account : emptyAccount }; }); +}; // TODO: check if needed export const setLedgerAccount = (ledgerAccount: LedgerAccountType | null) => diff --git a/src/store/actions/config/configActions.ts b/src/store/actions/config/configActions.ts index ef3c122..bfcc425 100644 --- a/src/store/actions/config/configActions.ts +++ b/src/store/actions/config/configActions.ts @@ -1,7 +1,19 @@ -import { getStore } from 'store/store'; +import { CrossWindowConfig } from 'core/providers/strategies/CrossWindowProviderStrategy/types'; +import { WalletConnectConfig } from 'core/providers/strategies/WalletConnectProviderStrategy/types'; import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; +import { getStore } from 'store/store'; export const setNativeAuthConfig = (config: NativeAuthConfigType) => getStore().setState(({ config: state }) => { state.nativeAuthConfig = config; }); + +export const setWalletConnectConfig = (config: WalletConnectConfig) => + getStore().setState(({ config: state }) => { + state.walletConnectConfig = config; + }); + +export const setCrossWindowConfig = (config: CrossWindowConfig) => + getStore().setState(({ config: state }) => { + state.crossWindowConfig = config; + }); diff --git a/src/store/actions/loginInfo/loginInfoActions.ts b/src/store/actions/loginInfo/loginInfoActions.ts index 68d6d6b..c8a610f 100644 --- a/src/store/actions/loginInfo/loginInfoActions.ts +++ b/src/store/actions/loginInfo/loginInfoActions.ts @@ -1,13 +1,15 @@ -import { TokenLoginType } from 'types/login.types'; +import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; import { LedgerLoginType, LoginInfoType, WalletConnectLoginType } from 'store/slices/loginInfo/loginInfo.types'; import { getStore } from 'store/store'; -import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; +import { TokenLoginType } from 'types/login.types'; -export const setProviderType = (providerType: ProviderTypeEnum) => +export const setProviderType = ( + providerType: T +) => getStore().setState(({ loginInfo: state }) => { state.providerType = providerType; }); diff --git a/src/store/actions/network/initializeNetwork.ts b/src/store/actions/network/initializeNetwork.ts index c03b1e3..f6d6130 100644 --- a/src/store/actions/network/initializeNetwork.ts +++ b/src/store/actions/network/initializeNetwork.ts @@ -1,36 +1,54 @@ import { getServerConfiguration } from 'apiCalls/configuration/getServerConfiguration'; +import { fallbackNetworkConfigurations } from 'constants/network.constants'; +import { emptyNetwork } from 'store/slices/network/emptyNetwork'; import { EnvironmentsEnum } from 'types/enums.types'; import { CustomNetworkType, NetworkType } from 'types/network.types'; import { initializeNetworkConfig } from './networkActions'; -import { fallbackNetworkConfigurations } from 'constants/network.constants'; export type InitializeNetworkPropsType = { customNetworkConfig?: CustomNetworkType; - environment: EnvironmentsEnum; + environment?: EnvironmentsEnum; }; export const initializeNetwork = async ({ customNetworkConfig = {}, environment -}: InitializeNetworkPropsType): Promise => { +}: InitializeNetworkPropsType) => { const fetchConfigFromServer = !customNetworkConfig?.skipFetchFromServer; const customNetworkApiAddress = customNetworkConfig?.apiAddress; - const fallbackConfig = fallbackNetworkConfigurations[environment] || {}; - const localConfig = { + const isFoundEnv = + environment && environment in fallbackNetworkConfigurations; + + const fallbackConfig: NetworkType | Record = isFoundEnv + ? fallbackNetworkConfigurations[environment as EnvironmentsEnum] + : {}; + + const baseConfig = { + ...emptyNetwork, ...fallbackConfig, ...customNetworkConfig }; - if (fetchConfigFromServer) { - const fallbackApiAddress = fallbackConfig?.apiAddress; + const localConfig: NetworkType = { + ...baseConfig, + apiTimeout: String(baseConfig.apiTimeout), + walletConnectBridgeAddresses: baseConfig.walletConnectBridgeAddresses || [], + walletConnectV2RelayAddresses: + 'walletConnectV2RelayAddresses' in baseConfig + ? baseConfig.walletConnectV2RelayAddresses + : ['wss://relay.walletconnect.com'] + }; + const fallbackApiAddress = fallbackConfig?.apiAddress; + + if (fetchConfigFromServer) { const serverConfig = await getServerConfiguration( customNetworkApiAddress || fallbackApiAddress ); if (serverConfig != null) { - const apiConfig = { + const apiConfig: NetworkType = { ...fallbackConfig, ...serverConfig, ...customNetworkConfig diff --git a/src/store/actions/network/networkActions.ts b/src/store/actions/network/networkActions.ts index 10a5f90..1413578 100644 --- a/src/store/actions/network/networkActions.ts +++ b/src/store/actions/network/networkActions.ts @@ -9,11 +9,10 @@ export const initializeNetworkConfig = (newNetwork: NetworkType) => Math.random() * newNetwork.walletConnectV2RelayAddresses.length ) ]; - const { walletConnectV2RelayAddresses, ...rest } = newNetwork; state.network = { ...state.network, - ...rest, + ...newNetwork, walletConnectV2RelayAddress }; }); diff --git a/src/store/actions/sharedActions/sharedActions.ts b/src/store/actions/sharedActions/sharedActions.ts index 91b89b1..fcda2aa 100644 --- a/src/store/actions/sharedActions/sharedActions.ts +++ b/src/store/actions/sharedActions/sharedActions.ts @@ -1,21 +1,21 @@ import { Address } from '@multiversx/sdk-core/out'; -import { getStore } from '../../store'; -import { resetStore } from 'store/middleware/logoutMiddleware'; import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; +import { resetStore } from 'store/middleware/logoutMiddleware'; +import { getStore } from '../../store'; export const logoutAction = () => getStore().setState(resetStore); -export interface LoginActionPayloadType { +export interface LoginActionPayloadType< + T extends ProviderTypeEnum = ProviderTypeEnum +> { address: string; - providerType: ProviderTypeEnum; + providerType: T[keyof T]; } export const loginAction = ({ address, providerType -}: LoginActionPayloadType) => +}: LoginActionPayloadType) => { getStore().setState(({ account, loginInfo }) => { - console.log('settings address with:', address); - account.address = address; account.publicKey = new Address(address).hex(); @@ -23,3 +23,4 @@ export const loginAction = ({ loginInfo.providerType = providerType; } }); +}; diff --git a/src/store/actions/toasts/toastsActions.ts b/src/store/actions/toasts/toastsActions.ts new file mode 100644 index 0000000..c3be971 --- /dev/null +++ b/src/store/actions/toasts/toastsActions.ts @@ -0,0 +1,83 @@ +import { + CustomToastType, + ToastsEnum +} from 'store/slices/toast/toastSlice.types'; +import { getStore } from 'store/store'; +import { getUnixTimestamp } from 'utils'; + +export const addCustomToast = ( + customToasts: CustomToastType, + currentToastId?: string +) => { + getStore().setState(({ toasts: state }) => { + const lastToastIndex = + state.customToasts.length > 0 + ? Math.max( + ...state.customToasts.map((toast) => + parseInt(toast.toastId.split('-').pop() || '0') + ) + ) + : 0; + const toastId = currentToastId || `custom-toast-${lastToastIndex + 1}`; + + const existingToastIndex = state.customToasts.findIndex( + (toast) => toast.toastId === toastId + ); + + const isToastFound = existingToastIndex !== -1; + + if (isToastFound) { + const updatedToast: CustomToastType = { + ...state.customToasts[existingToastIndex], + ...customToasts, + type: ToastsEnum.custom, + toastId + }; + + state.customToasts[existingToastIndex] = updatedToast; + return; + } + + state.customToasts.push({ + ...customToasts, + type: ToastsEnum.custom, + toastId + }); + }); +}; + +export const removeCustomToast = (toastId: string) => { + getStore().setState(({ toasts: state }) => { + state.customToasts = state.customToasts.filter( + (toast) => toast.toastId !== toastId + ); + }); +}; + +export const addTransactionToast = (toastId: string) => { + getStore().setState(({ toasts: state }) => { + const lastToastIndex = + state.transactionToasts.length > 0 + ? Math.max( + ...state.transactionToasts.map((toast) => + parseInt(toast.toastId.split('-').pop() || '0') + ) + ) + : 0; + const newToastId = toastId || `transaction-toast-${lastToastIndex + 1}`; + + state.transactionToasts.push({ + type: ToastsEnum.transaction, + startTimestamp: getUnixTimestamp(), + toastId: newToastId + }); + }); +}; + +export const removeTransactionToast = (toastId: string) => { + getStore().setState(({ toasts: state }) => { + state.transactionToasts = state.transactionToasts.filter((toast) => { + return toast.toastId !== toastId; + }); + }); +}; diff --git a/src/store/actions/trackedTransactions/trackedTransactionsActions.ts b/src/store/actions/trackedTransactions/trackedTransactionsActions.ts new file mode 100644 index 0000000..60a49bc --- /dev/null +++ b/src/store/actions/trackedTransactions/trackedTransactionsActions.ts @@ -0,0 +1,102 @@ +import { getStore } from 'store/store'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; +import { ServerTransactionType } from 'types/serverTransactions.types'; +import { SignedTransactionType } from 'types/transactions.types'; +import { + getIsTransactionFailed, + getIsTransactionNotExecuted, + getIsTransactionSuccessful +} from './transactionStateByStatus'; + +export interface UpdateTrackedTransactionStatusPayloadType { + sessionId: string; + transactionHash: string; + status: TransactionServerStatusesEnum | TransactionBatchStatusesEnum; + serverTransaction?: ServerTransactionType; + errorMessage?: string; + inTransit?: boolean; +} + +export const createTrackedTransactionsSession = ( + transactions: SignedTransactionType[] +) => { + const sessionId = Date.now().toString(); + getStore().setState(({ trackedTransactions: state }) => { + state[sessionId] = { + transactions, + status: TransactionBatchStatusesEnum.sent + }; + }); + return sessionId; +}; + +export const updateTrackedTransactionsSession = ({ + sessionId, + status, + errorMessage +}: { + sessionId: string; + status: TransactionBatchStatusesEnum; + errorMessage?: string; +}) => { + getStore().setState(({ trackedTransactions: state }) => { + state[sessionId].status = status; + state[sessionId].errorMessage = errorMessage; + }); +}; + +export const updateTrackedTransactionStatus = ( + payload: UpdateTrackedTransactionStatusPayloadType +) => { + const { + sessionId, + status, + errorMessage, + transactionHash, + serverTransaction, + inTransit + } = payload; + getStore().setState(({ trackedTransactions: state }) => { + const transactions = state[sessionId]?.transactions; + if (transactions != null) { + state[sessionId].transactions = transactions.map((transaction) => { + if (transaction.hash === transactionHash) { + return { + ...(serverTransaction ?? {}), + ...transaction, + status: status as TransactionServerStatusesEnum, + errorMessage, + inTransit + }; + } + return transaction; + }); + const areTransactionsSuccessful = state[sessionId]?.transactions?.every( + (transaction) => { + return getIsTransactionSuccessful(transaction.status); + } + ); + + const areTransactionsFailed = state[sessionId]?.transactions?.some( + (transaction) => getIsTransactionFailed(transaction.status) + ); + + const areTransactionsNotExecuted = state[sessionId]?.transactions?.every( + (transaction) => getIsTransactionNotExecuted(transaction.status) + ); + + if (areTransactionsSuccessful) { + state[sessionId].status = TransactionBatchStatusesEnum.success; + } + if (areTransactionsFailed) { + state[sessionId].status = TransactionBatchStatusesEnum.fail; + } + if (areTransactionsNotExecuted) { + state[sessionId].status = TransactionBatchStatusesEnum.invalid; + } + } + }); +}; diff --git a/src/store/actions/trackedTransactions/transactionStateByStatus.ts b/src/store/actions/trackedTransactions/transactionStateByStatus.ts new file mode 100644 index 0000000..4397715 --- /dev/null +++ b/src/store/actions/trackedTransactions/transactionStateByStatus.ts @@ -0,0 +1,143 @@ +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; + +export const pendingBatchTransactionsStates = [ + TransactionBatchStatusesEnum.sent +]; + +export const successBatchTransactionsStates = [ + TransactionBatchStatusesEnum.success +]; + +export const failBatchTransactionsStates = [ + TransactionBatchStatusesEnum.fail, + TransactionBatchStatusesEnum.cancelled, + TransactionBatchStatusesEnum.timedOut +]; + +export const invalidBatchTransactionsStates = [ + TransactionBatchStatusesEnum.invalid +]; + +export const timedOutBatchTransactionsStates = [ + TransactionBatchStatusesEnum.timedOut +]; + +export const pendingServerTransactionsStatuses = [ + TransactionServerStatusesEnum.pending +]; + +export const successServerTransactionsStates = [ + TransactionServerStatusesEnum.success +]; + +export const failServerTransactionsStates = [ + TransactionServerStatusesEnum.fail, + TransactionServerStatusesEnum.invalid +]; + +export const notExecutedServerTransactionsStates = [ + TransactionServerStatusesEnum.notExecuted +]; + +export function getIsTransactionPending( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionPending(status as TransactionBatchStatusesEnum) || + isServerTransactionPending(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionSuccessful( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionSuccessful(status as TransactionBatchStatusesEnum) || + isServerTransactionSuccessful(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionFailed( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionFailed(status as TransactionBatchStatusesEnum) || + isServerTransactionFailed(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionNotExecuted( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionInvalid(status as TransactionBatchStatusesEnum) || + isServerTransactionNotExecuted(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionTimedOut( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + isBatchTransactionTimedOut(status as TransactionBatchStatusesEnum) + ); +} + +export function isBatchTransactionPending( + status?: TransactionBatchStatusesEnum +) { + return status != null && pendingBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionSuccessful( + status: TransactionBatchStatusesEnum +) { + return status != null && successBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionFailed(status: TransactionBatchStatusesEnum) { + return status != null && failBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionInvalid( + status: TransactionBatchStatusesEnum +) { + return status != null && invalidBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionTimedOut( + status?: TransactionBatchStatusesEnum +) { + return status != null && timedOutBatchTransactionsStates.includes(status); +} + +export function isServerTransactionPending( + status?: TransactionServerStatusesEnum +) { + return status != null && pendingServerTransactionsStatuses.includes(status); +} +export function isServerTransactionSuccessful( + status: TransactionServerStatusesEnum +) { + return status != null && successServerTransactionsStates.includes(status); +} + +export function isServerTransactionFailed( + status: TransactionServerStatusesEnum +) { + return status != null && failServerTransactionsStates.includes(status); +} + +export function isServerTransactionNotExecuted( + status: TransactionServerStatusesEnum +) { + return status != null && notExecutedServerTransactionsStates.includes(status); +} diff --git a/src/store/actions/transactions/transactionStateByStatus.ts b/src/store/actions/transactions/transactionStateByStatus.ts new file mode 100644 index 0000000..4397715 --- /dev/null +++ b/src/store/actions/transactions/transactionStateByStatus.ts @@ -0,0 +1,143 @@ +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; + +export const pendingBatchTransactionsStates = [ + TransactionBatchStatusesEnum.sent +]; + +export const successBatchTransactionsStates = [ + TransactionBatchStatusesEnum.success +]; + +export const failBatchTransactionsStates = [ + TransactionBatchStatusesEnum.fail, + TransactionBatchStatusesEnum.cancelled, + TransactionBatchStatusesEnum.timedOut +]; + +export const invalidBatchTransactionsStates = [ + TransactionBatchStatusesEnum.invalid +]; + +export const timedOutBatchTransactionsStates = [ + TransactionBatchStatusesEnum.timedOut +]; + +export const pendingServerTransactionsStatuses = [ + TransactionServerStatusesEnum.pending +]; + +export const successServerTransactionsStates = [ + TransactionServerStatusesEnum.success +]; + +export const failServerTransactionsStates = [ + TransactionServerStatusesEnum.fail, + TransactionServerStatusesEnum.invalid +]; + +export const notExecutedServerTransactionsStates = [ + TransactionServerStatusesEnum.notExecuted +]; + +export function getIsTransactionPending( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionPending(status as TransactionBatchStatusesEnum) || + isServerTransactionPending(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionSuccessful( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionSuccessful(status as TransactionBatchStatusesEnum) || + isServerTransactionSuccessful(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionFailed( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionFailed(status as TransactionBatchStatusesEnum) || + isServerTransactionFailed(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionNotExecuted( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + (isBatchTransactionInvalid(status as TransactionBatchStatusesEnum) || + isServerTransactionNotExecuted(status as TransactionServerStatusesEnum)) + ); +} + +export function getIsTransactionTimedOut( + status?: TransactionServerStatusesEnum | TransactionBatchStatusesEnum +) { + return ( + status != null && + isBatchTransactionTimedOut(status as TransactionBatchStatusesEnum) + ); +} + +export function isBatchTransactionPending( + status?: TransactionBatchStatusesEnum +) { + return status != null && pendingBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionSuccessful( + status: TransactionBatchStatusesEnum +) { + return status != null && successBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionFailed(status: TransactionBatchStatusesEnum) { + return status != null && failBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionInvalid( + status: TransactionBatchStatusesEnum +) { + return status != null && invalidBatchTransactionsStates.includes(status); +} + +export function isBatchTransactionTimedOut( + status?: TransactionBatchStatusesEnum +) { + return status != null && timedOutBatchTransactionsStates.includes(status); +} + +export function isServerTransactionPending( + status?: TransactionServerStatusesEnum +) { + return status != null && pendingServerTransactionsStatuses.includes(status); +} +export function isServerTransactionSuccessful( + status: TransactionServerStatusesEnum +) { + return status != null && successServerTransactionsStates.includes(status); +} + +export function isServerTransactionFailed( + status: TransactionServerStatusesEnum +) { + return status != null && failServerTransactionsStates.includes(status); +} + +export function isServerTransactionNotExecuted( + status: TransactionServerStatusesEnum +) { + return status != null && notExecutedServerTransactionsStates.includes(status); +} diff --git a/src/store/actions/transactions/transactionsActions.ts b/src/store/actions/transactions/transactionsActions.ts new file mode 100644 index 0000000..44fe876 --- /dev/null +++ b/src/store/actions/transactions/transactionsActions.ts @@ -0,0 +1,104 @@ +import { getStore } from 'store/store'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; +import { ServerTransactionType } from 'types/serverTransactions.types'; +import { SignedTransactionType } from 'types/transactions.types'; +import { + getIsTransactionFailed, + getIsTransactionNotExecuted, + getIsTransactionSuccessful +} from './transactionStateByStatus'; + +export type UpdateSignedTransactionStatusPayloadType = { + sessionId: string; + transactionHash: string; + status: TransactionServerStatusesEnum | TransactionBatchStatusesEnum; + serverTransaction?: ServerTransactionType; + errorMessage?: string; + inTransit?: boolean; +}; + +export const createTransactionsSession = ({ + transactions +}: { + transactions: SignedTransactionType[]; +}) => { + const sessionId = Date.now().toString(); + getStore().setState(({ transactions: state }) => { + state[sessionId] = { + transactions, + status: TransactionBatchStatusesEnum.sent + }; + }); + return sessionId; +}; + +export const updateTransactionsSession = ({ + sessionId, + status, + errorMessage +}: { + sessionId: string; + status: TransactionBatchStatusesEnum; + errorMessage?: string; +}) => { + getStore().setState(({ transactions: state }) => { + state[sessionId].status = status; + state[sessionId].errorMessage = errorMessage; + }); +}; + +export const updateSignedTransactionStatus = ( + payload: UpdateSignedTransactionStatusPayloadType +) => { + const { + sessionId, + status, + errorMessage, + transactionHash, + serverTransaction, + inTransit + } = payload; + getStore().setState(({ transactions: state }) => { + const transactions = state[sessionId]?.transactions; + if (transactions != null) { + state[sessionId].transactions = transactions.map((transaction) => { + if (transaction.hash === transactionHash) { + return { + ...(serverTransaction ?? {}), + ...transaction, + status: status as TransactionServerStatusesEnum, + errorMessage, + inTransit + }; + } + return transaction; + }); + const areTransactionsSuccessful = state[sessionId]?.transactions?.every( + (transaction) => { + return getIsTransactionSuccessful(transaction.status); + } + ); + + const areTransactionsFailed = state[sessionId]?.transactions?.some( + (transaction) => getIsTransactionFailed(transaction.status) + ); + + const areTransactionsNotExecuted = state[sessionId]?.transactions?.every( + (transaction) => getIsTransactionNotExecuted(transaction.status) + ); + + if (areTransactionsSuccessful) { + state[sessionId].status = TransactionBatchStatusesEnum.success; + } + if (areTransactionsFailed) { + state[sessionId].status = TransactionBatchStatusesEnum.fail; + } + if (areTransactionsNotExecuted) { + state[sessionId].status = TransactionBatchStatusesEnum.invalid; + } + } + }); +}; diff --git a/src/store/middleware/logoutMiddleware.ts b/src/store/middleware/logoutMiddleware.ts index b4fe50a..eed1ef8 100644 --- a/src/store/middleware/logoutMiddleware.ts +++ b/src/store/middleware/logoutMiddleware.ts @@ -1,9 +1,9 @@ -import { storage } from 'storage'; import { WritableDraft } from 'immer'; -import { initialState as initialAccountState } from 'store/slices/account/accountSlice'; -import { initialState as initialLoginInfoState } from 'store/slices/loginInfo/loginInfoSlice'; +import { storage } from 'storage'; import { localStorageKeys } from 'storage/local'; import { isLoggedInSelector } from 'store/selectors'; +import { initialState as initialAccountState } from 'store/slices/account/accountSlice'; +import { initialState as initialLoginInfoState } from 'store/slices/loginInfo/loginInfoSlice'; import { StoreType } from '../store.types'; export const resetStore = (store: WritableDraft) => { diff --git a/src/store/reactStore.ts b/src/store/reactStore.ts new file mode 100644 index 0000000..94b19db --- /dev/null +++ b/src/store/reactStore.ts @@ -0,0 +1,4 @@ +import { createBoundedUseStore } from './createBoundedStore'; +import { getStore } from './store'; + +export const getReactStore = () => createBoundedUseStore(getStore()); diff --git a/src/store/selectors/accountSelectors.ts b/src/store/selectors/accountSelectors.ts index a592554..bfddcc7 100644 --- a/src/store/selectors/accountSelectors.ts +++ b/src/store/selectors/accountSelectors.ts @@ -6,6 +6,10 @@ export const accountSelector = ({ export const addressSelector = ({ account: { address } }: StoreType) => address; +export const websocketEventSelector = ({ + account: { websocketEvent } +}: StoreType) => websocketEvent; + export const accountNonceSelector = (store: StoreType) => accountSelector(store)?.nonce || 0; diff --git a/src/store/selectors/configSelectors.ts b/src/store/selectors/configSelectors.ts index d4e507d..03483c9 100644 --- a/src/store/selectors/configSelectors.ts +++ b/src/store/selectors/configSelectors.ts @@ -4,3 +4,11 @@ export const configSelector = ({ config }: StoreType) => config; export const nativeAuthConfigSelector = ({ config }: StoreType) => config.nativeAuthConfig; + +export const walletConnectConfigSelector = ({ config }: StoreType) => { + return config.walletConnectConfig; +}; + +export const crossWindowConfigSelector = ({ config }: StoreType) => { + return config.crossWindowConfig; +}; diff --git a/src/store/selectors/hooks/useSelector.ts b/src/store/selectors/hooks/useSelector.ts index 94ac5f3..0b4c1ab 100644 --- a/src/store/selectors/hooks/useSelector.ts +++ b/src/store/selectors/hooks/useSelector.ts @@ -1,11 +1,11 @@ +import { getReactStore } from 'store/reactStore'; import { StoreType } from 'store/store.types'; -import { getStoreHook } from '../../store'; type ExtractState = S extends { getState: () => infer T } ? T : StoreType; export function useSelector( selector: (state: ExtractState) => T ) { - const useStore = getStoreHook(); + const useStore = getReactStore(); return useStore(selector); } diff --git a/src/store/selectors/loginInfoSelectors.ts b/src/store/selectors/loginInfoSelectors.ts index f8251c9..bec96fa 100644 --- a/src/store/selectors/loginInfoSelectors.ts +++ b/src/store/selectors/loginInfoSelectors.ts @@ -4,3 +4,12 @@ export const loginInfoSelector = ({ loginInfo }: StoreType) => loginInfo; export const tokenLoginSelector = ({ loginInfo }: StoreType) => loginInfo.tokenLogin; + +export const walletConnectLoginSelector = ({ loginInfo }: StoreType) => + loginInfo.walletConnectLogin; + +export const providerTypeSelector = ({ loginInfo }: StoreType) => + loginInfo.providerType; + +export const ledgerLoginSelector = ({ loginInfo }: StoreType) => + loginInfo.ledgerLogin; diff --git a/src/store/selectors/networkSelectors.ts b/src/store/selectors/networkSelectors.ts index fe6f319..39a9527 100644 --- a/src/store/selectors/networkSelectors.ts +++ b/src/store/selectors/networkSelectors.ts @@ -6,3 +6,10 @@ export const networkSelector = ({ network }: StoreType) => network.network; export const chainIdSelector = ({ network: { network } }: StoreType) => network.chainId; + +export const walletAddressSelector = ({ network: { network } }: StoreType) => + network.walletAddress; + +export const roundDurationSelectorSelector = ({ + network: { network } +}: StoreType) => network.roundDuration; diff --git a/src/store/selectors/toastsSelectors.ts b/src/store/selectors/toastsSelectors.ts new file mode 100644 index 0000000..901709c --- /dev/null +++ b/src/store/selectors/toastsSelectors.ts @@ -0,0 +1,9 @@ +import { StoreType } from 'store/store.types'; + +export const toastsSliceSelector = ({ toasts }: StoreType) => toasts; + +export const customToastsSelector = ({ toasts }: StoreType) => + toasts.customToasts; + +export const transactionToastsSelector = ({ toasts }: StoreType) => + toasts.transactionToasts; diff --git a/src/store/selectors/trackedTransactionsSelector.ts b/src/store/selectors/trackedTransactionsSelector.ts new file mode 100644 index 0000000..f7f1af5 --- /dev/null +++ b/src/store/selectors/trackedTransactionsSelector.ts @@ -0,0 +1,41 @@ +import { TrackedTransactionsSliceType } from 'store/slices/trackedTransactions/trackedTransactionsSlice.types'; +import { StoreType } from 'store/store.types'; +import { TransactionServerStatusesEnum } from 'types/enums.types'; +import { SignedTransactionType } from 'types/transactions.types'; + +export const trackedTransactionsSliceSelector = ({ + trackedTransactions +}: StoreType) => trackedTransactions; + +export const pendingTrackedSessionsSelector = ({ + trackedTransactions: state +}: StoreType): TrackedTransactionsSliceType => { + const pendingSessions: TrackedTransactionsSliceType = {}; + + Object.entries(state).forEach(([sessionId, data]) => { + const hasPendingTransactions = data.transactions.some( + ({ status }) => status === TransactionServerStatusesEnum.pending + ); + if (hasPendingTransactions && data.status === 'sent') { + pendingSessions[sessionId] = data; + } + }); + + return pendingSessions; +}; + +export const pendingTrackedTransactionsSelector = ({ + trackedTransactions: state +}: StoreType) => { + const pendingTransactions: SignedTransactionType[] = []; + + Object.values(state).forEach(({ transactions }) => { + transactions.forEach((transaction) => { + if (transaction.status === TransactionServerStatusesEnum.pending) { + pendingTransactions.push(transaction); + } + }); + }); + + return pendingTransactions; +}; diff --git a/src/store/selectors/transactionsSelector.ts b/src/store/selectors/transactionsSelector.ts new file mode 100644 index 0000000..b073fc0 --- /dev/null +++ b/src/store/selectors/transactionsSelector.ts @@ -0,0 +1,103 @@ +import { TransactionsSliceType } from 'store/slices/transactions/transacitionsSlice.types'; +import { StoreType } from 'store/store.types'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types/enums.types'; +import { SignedTransactionType } from 'types/transactions.types'; + +export const transactionsSliceSelector = ({ transactions }: StoreType) => + transactions; + +export const pendingSessionsSelector = ({ + transactions: state +}: StoreType): TransactionsSliceType => { + const pendingSessions: TransactionsSliceType = {}; + + Object.entries(state).forEach(([sessionId, data]) => { + const hasPendingTransactions = data.transactions.some( + ({ status }) => status === TransactionServerStatusesEnum.pending + ); + if (hasPendingTransactions && data.status === 'sent') { + pendingSessions[sessionId] = data; + } + }); + + return pendingSessions; +}; + +export const pendingTransactionsSelector = ({ + transactions: state +}: StoreType) => { + const pendingTransactions: SignedTransactionType[] = []; + + Object.values(state).forEach(({ transactions }) => { + transactions.forEach((transaction) => { + if ( + [ + TransactionServerStatusesEnum.pending, + TransactionBatchStatusesEnum.sent + ].includes(transaction.status) + ) { + pendingTransactions.push(transaction); + } + }); + }); + + return pendingTransactions; +}; + +export const successfulTransactionsSelector = ({ + transactions: state +}: StoreType) => { + const successfulTransactions: SignedTransactionType[] = []; + + Object.values(state).forEach(({ transactions }) => { + transactions.forEach((transaction) => { + if (transaction.status === TransactionServerStatusesEnum.success) { + successfulTransactions.push(transaction); + } + }); + }); + + return successfulTransactions; +}; + +export const failedTransactionsSelector = ({ + transactions: state +}: StoreType) => { + const successfulTransactions: SignedTransactionType[] = []; + + Object.values(state).forEach(({ transactions }) => { + transactions.forEach((transaction) => { + if ( + [ + TransactionServerStatusesEnum.fail, + TransactionServerStatusesEnum.invalid, + TransactionBatchStatusesEnum.cancelled, + TransactionBatchStatusesEnum.timedOut + ].includes(transaction.status) + ) { + successfulTransactions.push(transaction); + } + }); + }); + + return successfulTransactions; +}; + +export const timedOutTransactionsSelector = ({ + transactions: state +}: StoreType) => { + const successfulTransactions: SignedTransactionType[] = []; + + Object.values(state).forEach(({ transactions }) => { + transactions.forEach((transaction) => { + if (transaction.status === TransactionBatchStatusesEnum.timedOut) { + successfulTransactions.push(transaction); + } + }); + }); + + return successfulTransactions; +}; diff --git a/src/store/slices/account/emptyAccount.ts b/src/store/slices/account/emptyAccount.ts index 08b9bcd..a7a0550 100644 --- a/src/store/slices/account/emptyAccount.ts +++ b/src/store/slices/account/emptyAccount.ts @@ -1,4 +1,4 @@ -import { ELLIPSIS, ZERO } from 'constants/placeholders'; +import { ELLIPSIS, ZERO } from 'constants/placeholders.constants'; import { AccountType } from 'types/account.types'; export const emptyAccount: AccountType = { diff --git a/src/store/slices/config/config.types.ts b/src/store/slices/config/config.types.ts index 52b3270..cc765bc 100644 --- a/src/store/slices/config/config.types.ts +++ b/src/store/slices/config/config.types.ts @@ -1,5 +1,9 @@ +import { CrossWindowConfig } from 'core/providers/strategies/CrossWindowProviderStrategy/types'; +import { WalletConnectConfig } from 'core/providers/strategies/WalletConnectProviderStrategy/types'; import { NativeAuthConfigType } from 'services/nativeAuth/nativeAuth.types'; export interface ConfigSliceType { nativeAuthConfig: NativeAuthConfigType | null; + walletConnectConfig: WalletConnectConfig | null; + crossWindowConfig: CrossWindowConfig | null; } diff --git a/src/store/slices/config/configSlice.ts b/src/store/slices/config/configSlice.ts index 3c4500d..cf12ec9 100644 --- a/src/store/slices/config/configSlice.ts +++ b/src/store/slices/config/configSlice.ts @@ -7,7 +7,9 @@ import { ConfigSliceType } from './config.types'; // The config should be changed by using the `setNativeAuthConfig` action in some specific cases. // Preferably, the config should be set at the dApp initialization and not changed during the dApp lifecycle. (e.g. when the user logs in/log out) const initialState: ConfigSliceType = { - nativeAuthConfig: null + nativeAuthConfig: null, + walletConnectConfig: null, + crossWindowConfig: null }; function getConfigSlice(): StateCreator< diff --git a/src/store/slices/index.ts b/src/store/slices/index.ts index 80d5a64..c967642 100644 --- a/src/store/slices/index.ts +++ b/src/store/slices/index.ts @@ -2,3 +2,5 @@ export * from './account'; export * from './network'; export * from './loginInfo'; export * from './config'; +export * from './transactions'; +export * from './toast'; diff --git a/src/store/slices/loginInfo/loginInfo.types.ts b/src/store/slices/loginInfo/loginInfo.types.ts index 2ff1f3c..4560b12 100644 --- a/src/store/slices/loginInfo/loginInfo.types.ts +++ b/src/store/slices/loginInfo/loginInfo.types.ts @@ -1,5 +1,5 @@ -import { TokenLoginType } from 'types/login.types'; import { ProviderTypeEnum } from 'core/providers/types/providerFactory.types'; +import { TokenLoginType } from 'types/login.types'; export interface WalletConnectLoginType { loginType: string; @@ -17,8 +17,10 @@ export interface LoginInfoType { expires: number; } -export interface LoginInfoSliceType { - providerType: ProviderTypeEnum | null; +export interface LoginInfoSliceType< + T extends ProviderTypeEnum = ProviderTypeEnum +> { + providerType: T[keyof T] | null; walletConnectLogin: WalletConnectLoginType | null; ledgerLogin: LedgerLoginType | null; tokenLogin: TokenLoginType | null; diff --git a/src/store/slices/network/emptyNetwork.ts b/src/store/slices/network/emptyNetwork.ts index 2250fdf..b1d664b 100644 --- a/src/store/slices/network/emptyNetwork.ts +++ b/src/store/slices/network/emptyNetwork.ts @@ -16,5 +16,6 @@ export const emptyNetwork: CurrentNetworkType = { walletAddress: '', apiAddress: '', explorerAddress: '', - apiTimeout: '4000' + apiTimeout: '4000', + roundDuration: 60000 }; diff --git a/src/store/slices/network/networkSlice.ts b/src/store/slices/network/networkSlice.ts index f0163c8..fc0f215 100644 --- a/src/store/slices/network/networkSlice.ts +++ b/src/store/slices/network/networkSlice.ts @@ -1,7 +1,7 @@ import { StateCreator } from 'zustand/vanilla'; -import { NetworkSliceType } from './networkSlice.types'; import { StoreType, MutatorsIn } from 'store/store.types'; import { emptyNetwork } from './emptyNetwork'; +import { NetworkSliceType } from './networkSlice.types'; const initialState: NetworkSliceType = { network: emptyNetwork diff --git a/src/store/slices/toast/index.ts b/src/store/slices/toast/index.ts new file mode 100644 index 0000000..0f54e79 --- /dev/null +++ b/src/store/slices/toast/index.ts @@ -0,0 +1 @@ +export { toastSlice } from './toastSlice'; diff --git a/src/store/slices/toast/toastSlice.ts b/src/store/slices/toast/toastSlice.ts new file mode 100644 index 0000000..42973b2 --- /dev/null +++ b/src/store/slices/toast/toastSlice.ts @@ -0,0 +1,19 @@ +import { StateCreator } from 'zustand/vanilla'; +import { StoreType, MutatorsIn } from 'store/store.types'; +import { ToastsSliceState } from './toastSlice.types'; + +const initialState: ToastsSliceState = { + customToasts: [], + transactionToasts: [] +}; + +function getToastSlice(): StateCreator< + StoreType, + MutatorsIn, + [], + ToastsSliceState +> { + return () => initialState; +} + +export const toastSlice = getToastSlice(); diff --git a/src/store/slices/toast/toastSlice.types.ts b/src/store/slices/toast/toastSlice.types.ts new file mode 100644 index 0000000..53a0811 --- /dev/null +++ b/src/store/slices/toast/toastSlice.types.ts @@ -0,0 +1,35 @@ +import { SignedTransactionType } from 'types/transactions.types'; + +export interface ToastsSliceState { + customToasts: CustomToastType[]; + transactionToasts: TransactionToastType[]; +} + +export interface SharedCustomToast { + toastId: string; + /** + * Duration in miliseconds + */ + duration?: number; + type?: string; + onClose?: () => void; +} + +//TODO: Implement custom toast support +export type CustomToastType = SharedCustomToast; + +export interface TransactionToastType { + duration?: number; + icon?: string; + iconClassName?: string; + startTimestamp: number; + title?: string; + toastId: string; + transaction?: SignedTransactionType; + type: string; +} + +export enum ToastsEnum { + custom = 'custom', + transaction = 'transaction' +} diff --git a/src/store/slices/trackedTransactions/index.ts b/src/store/slices/trackedTransactions/index.ts new file mode 100644 index 0000000..1a48a65 --- /dev/null +++ b/src/store/slices/trackedTransactions/index.ts @@ -0,0 +1 @@ +export { trackedTransactionsSlice } from './trackedTransactionsSlice'; diff --git a/src/store/slices/trackedTransactions/trackedTransactionsSlice.ts b/src/store/slices/trackedTransactions/trackedTransactionsSlice.ts new file mode 100644 index 0000000..dc84674 --- /dev/null +++ b/src/store/slices/trackedTransactions/trackedTransactionsSlice.ts @@ -0,0 +1,16 @@ +import { StateCreator } from 'zustand/vanilla'; +import { StoreType, MutatorsIn } from 'store/store.types'; +import { TrackedTransactionsSliceType } from './trackedTransactionsSlice.types'; + +const initialState: TrackedTransactionsSliceType = {}; + +function getTrackedTransactionsSlice(): StateCreator< + StoreType, + MutatorsIn, + [], + TrackedTransactionsSliceType +> { + return () => initialState; +} + +export const trackedTransactionsSlice = getTrackedTransactionsSlice(); diff --git a/src/store/slices/trackedTransactions/trackedTransactionsSlice.types.ts b/src/store/slices/trackedTransactions/trackedTransactionsSlice.types.ts new file mode 100644 index 0000000..40802b2 --- /dev/null +++ b/src/store/slices/trackedTransactions/trackedTransactionsSlice.types.ts @@ -0,0 +1,13 @@ +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum +} from 'types'; +import { SignedTransactionType } from 'types/transactions.types'; + +export interface TrackedTransactionsSliceType { + [sessionId: string]: { + transactions: SignedTransactionType[]; + status?: TransactionBatchStatusesEnum | TransactionServerStatusesEnum; + errorMessage?: string; + }; +} diff --git a/src/store/slices/transactions/index.ts b/src/store/slices/transactions/index.ts new file mode 100644 index 0000000..e9e07c2 --- /dev/null +++ b/src/store/slices/transactions/index.ts @@ -0,0 +1 @@ +export { transactionsSlice } from './transacitionsSlice'; diff --git a/src/store/slices/transactions/transacitionsSlice.ts b/src/store/slices/transactions/transacitionsSlice.ts new file mode 100644 index 0000000..81f4c51 --- /dev/null +++ b/src/store/slices/transactions/transacitionsSlice.ts @@ -0,0 +1,16 @@ +import { StateCreator } from 'zustand/vanilla'; +import { StoreType, MutatorsIn } from 'store/store.types'; +import { TransactionsSliceType } from './transacitionsSlice.types'; + +const initialState: TransactionsSliceType = {}; + +function getTransactionsSlice(): StateCreator< + StoreType, + MutatorsIn, + [], + TransactionsSliceType +> { + return () => initialState; +} + +export const transactionsSlice = getTransactionsSlice(); diff --git a/src/store/slices/transactions/transacitionsSlice.types.ts b/src/store/slices/transactions/transacitionsSlice.types.ts new file mode 100644 index 0000000..282c7fa --- /dev/null +++ b/src/store/slices/transactions/transacitionsSlice.types.ts @@ -0,0 +1,10 @@ +import { TransactionBatchStatusesEnum } from 'types/enums.types'; +import { SignedTransactionType } from 'types/transactions.types'; + +export interface TransactionsSliceType { + [sessionId: string]: { + transactions: SignedTransactionType[]; + status?: TransactionBatchStatusesEnum; + errorMessage?: string; + }; +} diff --git a/src/store/storage/inMemoryStorage.ts b/src/store/storage/inMemoryStorage.ts index 00ebdd1..b8d228b 100644 --- a/src/store/storage/inMemoryStorage.ts +++ b/src/store/storage/inMemoryStorage.ts @@ -1,32 +1,32 @@ interface InMemoryStorageType { - [key: string]: string; + [key: string]: string; } export class InMemoryStorage { - private storage: InMemoryStorageType = {}; + private storage: InMemoryStorageType = {}; - setItem(key: string, value: string) { - this.storage[key] = value; - } + setItem(key: string, value: string) { + this.storage[key] = value; + } - getItem(key: string): string | null { - return this.storage.hasOwnProperty(key) ? this.storage[key] : null; - } + getItem(key: string): string | null { + return this.storage.hasOwnProperty(key) ? this.storage[key] : null; + } - removeItem(key: string) { - delete this.storage[key]; - } + removeItem(key: string) { + delete this.storage[key]; + } - clear() { - this.storage = {} as Storage; - } + clear() { + this.storage = {} as Storage; + } - get length() { - return Object.keys(this.storage).length; - } + get length() { + return Object.keys(this.storage).length; + } - key(index: number): string | null { - const keys = Object.keys(this.storage); - return keys[index] || null; - } -} \ No newline at end of file + key(index: number): string | null { + const keys = Object.keys(this.storage); + return keys[index] || null; + } +} diff --git a/src/store/storage/index.ts b/src/store/storage/index.ts index 763326c..2bcf8e8 100644 --- a/src/store/storage/index.ts +++ b/src/store/storage/index.ts @@ -1,2 +1,2 @@ -export * from "./storageCallback"; -export * from "./inMemoryStorage"; \ No newline at end of file +export * from './storageCallback'; +export * from './inMemoryStorage'; diff --git a/src/store/storage/storageCallback.ts b/src/store/storage/storageCallback.ts index e06fa77..bae107f 100644 --- a/src/store/storage/storageCallback.ts +++ b/src/store/storage/storageCallback.ts @@ -2,4 +2,4 @@ import { StateStorage } from 'zustand/middleware'; export type StorageCallback = () => StateStorage; -export const defaultStorageCallback: StorageCallback = () => localStorage; \ No newline at end of file +export const defaultStorageCallback: StorageCallback = () => localStorage; diff --git a/src/store/store.ts b/src/store/store.ts index 32d2e3a..2b3a616 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -1,16 +1,22 @@ -import { createStore } from 'zustand/vanilla'; import { createJSONStorage, devtools, persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; +import { createStore } from 'zustand/vanilla'; +import { applyMiddlewares } from './middleware'; +import { + networkSlice, + accountSlice, + loginInfoSlice, + transactionsSlice, + configSlice, + toastSlice +} from './slices'; +import { trackedTransactionsSlice } from './slices/trackedTransactions'; import { InMemoryStorage, defaultStorageCallback, StorageCallback } from './storage'; -import { networkSlice, accountSlice, loginInfoSlice } from './slices'; -import { createBoundedUseStore } from './createBoundedStore'; import { StoreType } from './store.types'; -import { applyMiddlewares } from './middleware'; -import { configSlice } from './slices'; export type MutatorsIn = [ ['zustand/devtools', never], @@ -30,9 +36,12 @@ export const createDAppStore = (getStorageCallback: StorageCallback) => { persist( immer((...args) => ({ network: networkSlice(...args), + transactions: transactionsSlice(...args), account: accountSlice(...args), loginInfo: loginInfoSlice(...args), - config: configSlice(...args) + config: configSlice(...args), + trackedTransactions: trackedTransactionsSlice(...args), + toasts: toastSlice(...args) })), { name: 'sdk-dapp-store', @@ -49,6 +58,10 @@ export type StoreApi = ReturnType; let store: StoreApi; +export const setDAppStore = (_store: StoreApi) => { + store = _store; +}; + export const getStore = () => { if (!store) { setDAppStore(createDAppStore(() => new InMemoryStorage())); @@ -56,10 +69,6 @@ export const getStore = () => { return store; }; -export const setDAppStore = (_store: StoreApi) => { - store = _store; -}; - /** * Initialize store with the preferred storage by passing a callback. * Default storage is localStorage. @@ -78,5 +87,3 @@ export const initStore = (getStorageCallback = defaultStorageCallback) => { }; export const getState = () => getStore().getState(); - -export const getStoreHook = () => createBoundedUseStore(getStore()); diff --git a/src/store/store.types.ts b/src/store/store.types.ts index 8145523..277f634 100644 --- a/src/store/store.types.ts +++ b/src/store/store.types.ts @@ -1,13 +1,19 @@ import { AccountSliceType } from './slices/account/account.types'; +import { ConfigSliceType } from './slices/config/config.types'; import { LoginInfoSliceType } from './slices/loginInfo/loginInfo.types'; import { NetworkSliceType } from './slices/network/networkSlice.types'; -import { ConfigSliceType } from './slices/config/config.types'; +import { ToastsSliceState } from './slices/toast/toastSlice.types'; +import { TrackedTransactionsSliceType } from './slices/trackedTransactions/trackedTransactionsSlice.types'; +import { TransactionsSliceType } from './slices/transactions/transacitionsSlice.types'; export type StoreType = { network: NetworkSliceType; account: AccountSliceType; loginInfo: LoginInfoSliceType; config: ConfigSliceType; + transactions: TransactionsSliceType; + toasts: ToastsSliceState; + trackedTransactions: TrackedTransactionsSliceType; }; export type MutatorsIn = [ diff --git a/src/types/enums.types.ts b/src/types/enums.types.ts index 4af22bd..d1a2487 100644 --- a/src/types/enums.types.ts +++ b/src/types/enums.types.ts @@ -4,6 +4,36 @@ export enum EnvironmentsEnum { mainnet = 'mainnet' } +export enum TransactionServerStatusesEnum { + pending = 'pending', + fail = 'fail', + invalid = 'invalid', + success = 'success', + executed = 'executed', + notExecuted = 'not executed', + rewardReverted = 'reward-reverted' +} + +export enum TransactionTypesEnum { + MultiESDTNFTTransfer = 'MultiESDTNFTTransfer', + ESDTTransfer = 'ESDTTransfer', + ESDTNFTBurn = 'ESDTNFTBurn', + ESDTNFTTransfer = 'ESDTNFTTransfer', + esdtTransaction = 'esdtTransaction', + nftTransaction = 'nftTransaction', + scCall = 'scCall' +} + +export enum TransactionBatchStatusesEnum { + signed = 'signed', + cancelled = 'cancelled', + success = 'success', + sent = 'sent', + fail = 'fail', + timedOut = 'timedOut', + invalid = 'invalid' +} + export enum TypesOfSmartContractCallsEnum { MultiESDTNFTTransfer = 'MultiESDTNFTTransfer', ESDTNFTTransfer = 'ESDTNFTTransfer' @@ -22,3 +52,9 @@ export enum ESDTTransferTypesEnum { ESDTWipe = 'ESDTWipe', ESDTFreeze = 'ESDTFreeze' } + +export enum GuardianActionsEnum { + SetGuardian = 'SetGuardian', + GuardAccount = 'GuardAccount', + UnGuardAccount = 'UnGuardAccount' +} diff --git a/src/types/index.ts b/src/types/index.ts index 9d0a1f8..002b283 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,3 +1,4 @@ export * from './enums.types'; export * from './network.types'; -export * from './misc.types'; \ No newline at end of file +export * from './misc.types'; +export * from './provider.types'; diff --git a/src/types/manager.types.ts b/src/types/manager.types.ts new file mode 100644 index 0000000..c357fdc --- /dev/null +++ b/src/types/manager.types.ts @@ -0,0 +1,5 @@ +export interface IEventBus { + subscribe(event: string, callback: Function): void; + publish(event: string, data: T): void; + unsubscribe(event: string, callback: Function): void; +} diff --git a/src/types/network.types.ts b/src/types/network.types.ts index ee8a732..f0f00d1 100644 --- a/src/types/network.types.ts +++ b/src/types/network.types.ts @@ -14,6 +14,9 @@ export interface BaseNetworkType { walletConnectV2ProjectId?: string; walletConnectV2Options?: Record; xAliasAddress?: string; + roundDuration: number; + iframeWalletAddress?: string; + websocketUrl?: string; } export interface CurrentNetworkType extends BaseNetworkType { @@ -44,6 +47,8 @@ export interface CustomNetworkType { apiTimeout?: string; walletConnectV2ProjectId?: string; walletConnectV2Options?: any; + iframeWalletAddress?: string; + websocketUrl?: string; } export interface ApiNetworkConfigType { diff --git a/src/types/provider.types.ts b/src/types/provider.types.ts new file mode 100644 index 0000000..5e69921 --- /dev/null +++ b/src/types/provider.types.ts @@ -0,0 +1,5 @@ +export enum ProviderErrorsEnum { + notInitialized = 'Provider is not initialized.', + invalidType = 'Invalid type.', + eventBusError = 'eventBus is not initialized' +} diff --git a/src/types/serverTransactions.types.ts b/src/types/serverTransactions.types.ts new file mode 100644 index 0000000..ae6b3c7 --- /dev/null +++ b/src/types/serverTransactions.types.ts @@ -0,0 +1,347 @@ +import { AssetType, ScamInfoType } from './account.types'; +import { EsdtEnumType, NftEnumType } from './tokens.types'; +import { SignedTransactionType } from './transactions.types'; + +//#region server trasactions + +export interface ScResultType { + callType: string; + gasLimit: number; + gasPrice: number; + nonce: number; + prevTxHash: string; + hash: string; + originalTxHash: string; + receiver: string; + sender: string; + timestamp: number; + value: string; + data?: string; + returnMessage?: string; +} + +export interface TransactionTokensType { + esdts: string[]; + nfts: string[]; +} + +export enum TransactionActionsEnum { + // esdtNft category + transfer = 'transfer', + // legacy delegation + unBond = 'unBond', + unStake = 'unStake', + // stake category + delegate = 'delegate', + stake = 'stake', + unDelegate = 'unDelegate', + stakeClaimRewards = 'claimRewards', + reDelegateRewards = 'reDelegateRewards', + withdraw = 'withdraw', + // mex category + claimLockedAssets = 'claimLockedAssets', + swapTokensFixedInput = 'swapTokensFixedInput', + swapTokensFixedOutput = 'swapTokensFixedOutput', + swap = 'swap', + addLiquidity = 'addLiquidity', + addLiquidityProxy = 'addLiquidityProxy', + removeLiquidity = 'removeLiquidity', + removeLiquidityProxy = 'removeLiquidityProxy', + enterFarm = 'enterFarm', + enterFarmProxy = 'enterFarmProxy', + enterFarmAndLockRewards = 'enterFarmAndLockRewards', + enterFarmAndLockRewardsProxy = 'enterFarmAndLockRewardsProxy', + exitFarm = 'exitFarm', + exitFarmProxy = 'exitFarmProxy', + claimRewards = 'claimRewards', + claimRewardsProxy = 'claimRewardsProxy', + compoundRewards = 'compoundRewards', + compoundRewardsProxy = 'compoundRewardsProxy', + wrapEgld = 'wrapEgld', + unwrapEgld = 'unwrapEgld', + unlockAssets = 'unlockAssets', + mergeLockedAssetTokens = 'mergeLockedAssetTokens', + stakeFarm = 'stakeFarm', + stakeFarmProxy = 'stakeFarmProxy', + stakeFarmTokens = 'stakeFarmTokens', + stakeFarmTokensProxy = 'stakeFarmTokensProxy', + unstakeFarm = 'unstakeFarm', + unstakeFarmProxy = 'unstakeFarmProxy', + unstakeFarmTokens = 'unstakeFarmTokens', + unstakeFarmTokensProxy = 'unstakeFarmTokensProxy', + claimDualYield = 'claimDualYield', + claimDualYieldProxy = 'claimDualYieldProxy', + unbondFarm = 'unbondFarm', + ping = 'ping', + lockTokens = 'lockTokens', + migrateOldTokens = 'migrateOldTokens' +} + +export enum TransactionActionCategoryEnum { + esdtNft = 'esdtNft', + mex = 'mex', + stake = 'stake', + scCall = 'scCall' +} + +export interface TokenArgumentType { + type: NftEnumType | EsdtEnumType; + name: string; + ticker: string; + collection?: string; + identifier?: string; + token?: string; + decimals: number; + value: string; + providerName?: string; + providerAvatar?: string; + svgUrl?: string; + valueUSD?: string; +} + +export interface TransactionActionType { + category: string; + name: TransactionActionsEnum; + description?: string; + arguments?: { [key: string]: any }; +} + +export interface UnwrapperType { + token?: TokenArgumentType[]; + tokenNoValue?: TokenArgumentType[]; + tokenNoLink?: TokenArgumentType[]; + address?: string; + egldValue?: string; + value?: string; + providerName?: string; + providerAvatar?: string; +} + +export enum TransactionOperationActionTypeEnum { + none = 'none', + transfer = 'transfer', + burn = 'burn', + addQuantity = 'addQuantity', + create = 'create', + multiTransfer = 'multiTransfer', + localMint = 'localMint', + localBurn = 'localBurn', + wipe = 'wipe', + freeze = 'freeze', + writeLog = 'writeLog', + signalError = 'signalError', + + // to be deprecated ? + ESDTLocalMint = 'ESDTLocalMint', + ESDTLocalBurn = 'ESDTLocalBurn' +} + +export enum VisibleTransactionOperationType { + nft = 'nft', + esdt = 'esdt', + egld = 'egld' +} +export enum HiddenTransactionOperationType { + none = 'none', + error = 'error', + log = 'log' +} + +export interface OperationType { + id?: string; + action: TransactionOperationActionTypeEnum; + type: VisibleTransactionOperationType | HiddenTransactionOperationType; + esdtType?: NftEnumType | EsdtEnumType; + collection?: string; + name?: string; + identifier?: string; + sender: string; + ticker?: string; + receiver: string; + value: string; + decimals?: number; + data?: string; + message?: string; + svgUrl?: string; + senderAssets?: AssetType; + receiverAssets?: AssetType; + valueUSD?: string; +} + +export interface LogType { + hash: string; + callType: string; + gasLimit: number; + gasPrice: number; + nonce: number; + prevTxHash: string; + receiver?: string; + sender: string; + value: string; + data?: string; + originalTxHash: string; + returnMessage?: string; + logs?: any; +} + +export interface EventType { + address: string; + identifier: string; + topics: string[]; + order: number; + data?: string; + additionalData?: string[]; +} + +export interface ResultLogType { + id: string; + address: string; + events: EventType[]; +} + +export interface ResultType { + hash: string; + callType: string; + gasLimit: number; + gasPrice: number; + nonce: number; + prevTxHash: string; + receiver?: string; + sender: string; + value: string; + data?: string; + originalTxHash: string; + returnMessage?: string; + logs?: ResultLogType; + senderAssets?: AssetType; + receiverAssets?: AssetType; + miniBlockHash?: string; + function?: string; + timestamp?: number; +} + +export interface ReceiptType { + value: string; + sender: string; + data: string; +} + +export interface ServerTransactionType { + fee?: string; + data: string; + gasLimit: number; + gasPrice: number; + gasUsed: number; + txHash: string; + miniBlockHash: string; + nonce: number; + receiver: string; + receiverShard: number; + round: number; + sender: string; + senderShard: number; + signature: string; + status: string; + inTransit?: boolean; + timestamp: number; + value: string; + price: number; + results?: ResultType[]; + operations?: OperationType[]; + action?: TransactionActionType; + logs?: { + id: string; + address: string; + events: EventType[]; + }; + scamInfo?: ScamInfoType; + pendingResults?: boolean; + receipt?: ReceiptType; + senderAssets?: AssetType; + receiverAssets?: AssetType; + type?: TransferTypeEnum; + originalTxHash?: string; + isNew?: boolean; // UI flag + tokenValue?: string; + tokenIdentifier?: string; + function?: string; +} + +export enum TransferTypeEnum { + Transaction = 'Transaction', + SmartContractResult = 'SmartContractResult' +} + +//#endregion + +//#region interpreted trasactions + +export enum TransactionDirectionEnum { + SELF = 'Self', + INTERNAL = 'Internal', + IN = 'In', + OUT = 'Out' +} + +export interface InterpretedTransactionType extends ServerTransactionType { + transactionDetails: { + direction?: TransactionDirectionEnum; + method: string; + transactionTokens: TokenArgumentType[]; + isContract?: boolean; + }; + links: { + senderLink?: string; + receiverLink?: string; + senderShardLink?: string; + receiverShardLink?: string; + transactionLink?: string; + }; +} + +export interface DecodeForDisplayPropsType { + input: string; + decodeMethod: DecodeMethodEnum; + identifier?: string; +} + +export interface DecodedDisplayType { + displayValue: string; + validationWarnings: string[]; +} + +export enum DecodeMethodEnum { + raw = 'raw', + text = 'text', + decimal = 'decimal', + smart = 'smart' +} + +//#endregion + +export enum BatchTransactionStatus { + pending = 'pending', + success = 'success', + invalid = 'invalid', + dropped = 'dropped', + fail = 'fail' +} + +export interface BatchTransactionsRequestType { + id: string; + transactions: SignedTransactionType[][]; +} + +export interface BatchTransactionsResponseType { + id: string; + status: BatchTransactionStatus; + transactions: SignedTransactionType[][]; + error?: string; + message?: string; + statusCode?: string; +} + +export type BatchTransactionsWSResponseType = { + batchId: string; + txHashes: string[]; +}; diff --git a/src/types/tokens.types.ts b/src/types/tokens.types.ts new file mode 100644 index 0000000..bd59af1 --- /dev/null +++ b/src/types/tokens.types.ts @@ -0,0 +1,180 @@ +import { ScamInfoType } from './account.types'; + +export interface TokenRolesType { + address: string; + roles: string[]; +} + +export interface TokenLockedAccountType { + address: string; + name: string; + balance: string; +} +export interface TokenSupplyType { + supply: number; + circulatingSupply: number; + minted: number; + burnt: number; + initialMinted: number; + lockedAccounts?: TokenLockedAccountType[]; +} + +export interface TokenType { + identifier: string; + ticker?: string; + name: string; + balance?: string; + decimals?: number; + owner: string; + minted: string; + burnt: string; + supply: string | number; + circulatingSupply: string | number; + canBurn: boolean; + canChangeOwner: boolean; + canFreeze: boolean; + canMint: boolean; + canPause: boolean; + canUpgrade: boolean; + canWipe: boolean; + isPaused: boolean; + transactions: number; + accounts: number; + price?: number; + marketCap?: number; + valueUsd?: number; + assets?: { + website?: string; + description?: string; + status?: string; + pngUrl?: string; + svgUrl?: string; + social?: any; + extraTokens?: string[]; + lockedAccounts?: { [key: string]: string }; + ledgerSignature?: string; + }; +} + +export interface CollectionType { + collection: string; + type: NftEnumType; + name: string; + ticker: string; + timestamp: number; + canFreeze: boolean; + canWipe: boolean; + canPause: boolean; + canTransferRole: boolean; + owner: string; + decimals?: number; + assets?: { + website?: string; + description?: string; + status?: string; + pngUrl?: string; + svgUrl?: string; + }; + scamInfo?: ScamInfoType; +} + +export enum EsdtEnumType { + FungibleESDT = 'FungibleESDT' +} + +export enum NftEnumType { + NonFungibleESDT = 'NonFungibleESDT', + SemiFungibleESDT = 'SemiFungibleESDT', + MetaESDT = 'MetaESDT' +} + +export interface NftType { + identifier: string; + collection: string; + ticker?: string; + timestamp: number; + attributes: string; + nonce: number; + type: NftEnumType; + name: string; + creator: string; + royalties: number; + balance: string; + uris?: string[]; + url?: string; + thumbnailUrl?: string; + tags?: string[]; + decimals?: number; + owner?: string; + supply?: string; + isWhitelistedStorage?: boolean; + owners?: { + address: string; + balance: string; + }[]; + assets?: { + website?: string; + description?: string; + status?: string; + pngUrl?: string; + svgUrl?: string; + }; + metadata?: { + description?: string; + fileType?: string; + fileUri?: string; + fileName?: string; + }; + media?: { + url: string; + originalUrl: string; + thumbnailUrl: string; + fileType: string; + fileSize: number; + }[]; + scamInfo?: ScamInfoType; +} + +export interface TokenAssets { + description: string; + status: string; + svgUrl: string; + website?: string; + pngUrl?: string; + social?: any; + extraTokens?: string[]; + lockedAccounts?: { [key: string]: string }; +} + +export interface TokenMediaType { + url?: string; + originalUrl?: string; + thumbnailUrl?: string; + fileType?: string; + fileSize?: number; +} + +export interface TokenOptionType { + tokenLabel: string; + tokenDecimals: number; + tokenAvatar: string; + assets?: TokenAssets; + type?: NftEnumType; + error?: string; + esdtPrice?: number; + ticker?: string; + identifier?: string; + name?: string; + isLoading?: boolean; +} + +export interface TokenInfoResponse { + identifier: string; + name: string; + ticker: string; + decimals: number; + type?: NftEnumType; + assets: TokenAssets; + media?: TokenMediaType[]; + price: number; +} diff --git a/src/types/transactions.types.ts b/src/types/transactions.types.ts new file mode 100644 index 0000000..29fb7b6 --- /dev/null +++ b/src/types/transactions.types.ts @@ -0,0 +1,83 @@ +import { IPlainTransactionObject, Transaction } from '@multiversx/sdk-core/out'; +import { + TransactionBatchStatusesEnum, + TransactionServerStatusesEnum, + TransactionTypesEnum +} from 'types/enums.types'; +import { ResultType } from './serverTransactions.types'; + +export interface SignedTransactionType extends IPlainTransactionObject { + hash: string; + status: TransactionServerStatusesEnum | TransactionBatchStatusesEnum; + inTransit?: boolean; +} + +export interface MultiSignTransactionType { + multiTxData?: string; + transactionIndex: number; + transaction: Transaction; +} + +interface MultiEsdtType { + type: + | TransactionTypesEnum.esdtTransaction + | TransactionTypesEnum.nftTransaction; + receiver: string; + token?: string; + nonce?: string; + amount?: string; + data: string; +} + +interface MultiEsdtScCallType { + type: TransactionTypesEnum.scCall; + receiver: string; + token?: string; + nonce?: string; + amount?: string; + data: string; +} + +export type MultiEsdtTransactionType = MultiEsdtType | MultiEsdtScCallType; + +export interface TransactionDataTokenType { + tokenId: string; + amount: string; + receiver: string; + type?: MultiEsdtTransactionType['type'] | ''; + nonce?: string; + multiTxData?: string; +} + +export type TransactionsDataTokensType = + | Record + | undefined; + +export type PendingTransactionsType = { + hash: string; + previousStatus: string; +}[]; + +export type GetTransactionsByHashesReturnType = { + hash: string; + invalidTransaction: boolean; + status: TransactionServerStatusesEnum | TransactionBatchStatusesEnum; + inTransit?: boolean; + results: ResultType[]; + sender: string; + receiver: string; + data: string; + previousStatus: string; + hasStatusChanged: boolean; +}[]; + +export type GetTransactionsByHashesType = ( + pendingTransactions: PendingTransactionsType +) => Promise; + +export enum TransactionDirectionEnum { + SELF = 'Self', + INTERNAL = 'Internal', + IN = 'In', + OUT = 'Out' +} diff --git a/src/utils/account/fetchAccount.ts b/src/utils/account/fetchAccount.ts new file mode 100644 index 0000000..76e8587 --- /dev/null +++ b/src/utils/account/fetchAccount.ts @@ -0,0 +1,3 @@ +import { getAccountFromApi } from 'apiCalls/account/getAccountFromApi'; + +export const fetchAccount = (address?: string) => getAccountFromApi(address); diff --git a/src/utils/account/getAccount.ts b/src/utils/account/getAccount.ts deleted file mode 100644 index b4da6d5..0000000 --- a/src/utils/account/getAccount.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { getAccountFromApi } from 'apiCalls/accounts/getAccountFromApi'; - -export const getAccount = (address?: string) => getAccountFromApi(address); diff --git a/src/utils/account/index.ts b/src/utils/account/index.ts index 7603022..fdd5e34 100644 --- a/src/utils/account/index.ts +++ b/src/utils/account/index.ts @@ -1 +1,3 @@ -export * from './getAccount'; +export * from './fetchAccount'; +export * from './refreshAccount'; +export * from './trimUsernameDomain'; diff --git a/src/utils/account/refreshAccount.ts b/src/utils/account/refreshAccount.ts new file mode 100644 index 0000000..85d0c16 --- /dev/null +++ b/src/utils/account/refreshAccount.ts @@ -0,0 +1,58 @@ +import { getAddress } from 'core/methods/account/getAddress'; +import { getLatestNonce } from 'core/methods/account/getLatestNonce'; +import { getAccountProvider } from 'core/providers/helpers/accountProvider'; +import { setAccount } from 'store/actions'; +import { fetchAccount } from './fetchAccount'; + +const setNewAccount = async () => { + try { + const address = getAddress(); + + try { + const account = await fetchAccount(address); + + if (account != null) { + const accountData = { + ...account, + nonce: getLatestNonce(account) + }; + + setAccount(accountData); + + return accountData; + } + } catch (e) { + console.error('Failed getting account ', e); + } + } catch (e) { + console.error('Failed getting address ', e); + } + + return null; +}; + +export async function refreshAccount() { + const provider = getAccountProvider(); + + if (provider == null) { + throw 'Provider not initialized'; + } + + try { + if (!provider.init) { + throw 'Current provider does not have init() function'; + } + + const initialized = await provider.init(); + + if (!initialized) { + return; + } + + return setNewAccount(); + } catch (e) { + console.error('Failed initializing provider ', e); + } + + return undefined; +} diff --git a/src/utils/account/trimUsernameDomain.ts b/src/utils/account/trimUsernameDomain.ts new file mode 100644 index 0000000..129745f --- /dev/null +++ b/src/utils/account/trimUsernameDomain.ts @@ -0,0 +1,12 @@ +export const trimUsernameDomain = (username?: string) => { + if (!username) { + return; + } + + const elrondSuffixExists = username.lastIndexOf('.elrond') > 0; + const trimmedPartBeforeLastDot = elrondSuffixExists + ? username.substring(0, username.lastIndexOf('.')) + : username; + + return trimmedPartBeforeLastDot; +}; diff --git a/src/utils/createModalElement.ts b/src/utils/createModalElement.ts new file mode 100644 index 0000000..cfc3423 --- /dev/null +++ b/src/utils/createModalElement.ts @@ -0,0 +1,24 @@ +import { IEventBus } from '@multiversx/sdk-dapp-core-ui/loader'; +import { safeWindow } from 'constants/index'; +import { defineCustomElements } from 'lib/sdkDappCoreUi'; + +//TODO: allow override createModalElement similar to accountProvider and add typed name for all webcomponents +export const createModalElement = async < + T extends HTMLElement & { + getEventBus: () => Promise; + } +>( + name: string +) => { + await defineCustomElements(safeWindow); + + if (!safeWindow.document) { + return {} as T; + } + + const modalElement = safeWindow.document.createElement(name) as T; + safeWindow.document.body.appendChild(modalElement); + await customElements.whenDefined(name); + + return modalElement; +}; diff --git a/src/utils/decoders/base64Utils.ts b/src/utils/decoders/base64Utils.ts index d2ec165..af97e3d 100644 --- a/src/utils/decoders/base64Utils.ts +++ b/src/utils/decoders/base64Utils.ts @@ -35,7 +35,7 @@ export function isStringBase64(str: string) { // it is a regular base64 string return true; } - } catch (e) { + } catch (_e) { return false; } diff --git a/src/utils/decoders/decodePart.ts b/src/utils/decoders/decodePart.ts index cb77935..bf9c589 100644 --- a/src/utils/decoders/decodePart.ts +++ b/src/utils/decoders/decodePart.ts @@ -9,7 +9,9 @@ export function decodePart(part: string) { if (isUtf8(hexPart) && hexPart.length > 1) { decodedPart = hexPart; } - } catch (error) {} + } catch (_error) { + /* empty */ + } return decodedPart; } diff --git a/src/utils/decoders/isAscii.ts b/src/utils/decoders/isAscii.ts index bc00a95..cc4c183 100644 --- a/src/utils/decoders/isAscii.ts +++ b/src/utils/decoders/isAscii.ts @@ -1 +1,2 @@ +// eslint-disable-next-line no-control-regex export const isAscii = (str: string) => !/[^\x00-\x7F]/gm.test(str); diff --git a/src/utils/decoders/isUtf8.ts b/src/utils/decoders/isUtf8.ts index 3c34598..9d08a13 100644 --- a/src/utils/decoders/isUtf8.ts +++ b/src/utils/decoders/isUtf8.ts @@ -1,6 +1,8 @@ export function isUtf8(str: string) { for (let i = 0; i < str.length; i++) { - if (str.charCodeAt(i) > 127) return false; + if (str.charCodeAt(i) > 127) { + return false; + } } return true; } diff --git a/src/utils/decoders/tests/decodePart.test.tsx b/src/utils/decoders/tests/decodePart.test.ts similarity index 100% rename from src/utils/decoders/tests/decodePart.test.tsx rename to src/utils/decoders/tests/decodePart.test.ts diff --git a/src/utils/decoders/tests/isUtf8.test.ts b/src/utils/decoders/tests/isUtf8.test.ts index 1035d60..1cafc1e 100644 --- a/src/utils/decoders/tests/isUtf8.test.ts +++ b/src/utils/decoders/tests/isUtf8.test.ts @@ -6,7 +6,7 @@ describe('isUtf8', () => { expect(result).toStrictEqual(true); }); - it('should return valid UTF-8', async () => { + it('should also return valid UTF-8', async () => { const result = isUtf8('ZEdWemRDQjBjbUZ1YzJGamRHbHZiaUR3bjVtQQ=='); expect(result).toStrictEqual(true); }); @@ -16,7 +16,7 @@ describe('isUtf8', () => { expect(result).toStrictEqual(false); }); - it('should return invalid UTF-8', async () => { + it('should return also invalid UTF-8', async () => { const result = isUtf8('��-'); expect(result).toStrictEqual(false); }); diff --git a/src/utils/index.ts b/src/utils/index.ts index c14cfcf..965aba3 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,7 +1,8 @@ -export * from './dateTime'; -export * from './window'; +export * from './account'; export * from './asyncActions'; +export * from './dateTime'; export * from './decoders'; -export * from './validation'; -export * from './account'; export * from './retryMultipleTimes'; +export * from './transactions'; +export * from './validation'; +export * from './window'; diff --git a/src/utils/operations/tests/timeRemaining.test.ts b/src/utils/operations/tests/timeRemaining.test.ts new file mode 100644 index 0000000..77c0454 --- /dev/null +++ b/src/utils/operations/tests/timeRemaining.test.ts @@ -0,0 +1,33 @@ +import { timeRemaining } from '../timeRemaining'; + +describe('timeRemaining tests - short time format', () => { + const entries: [number, string][] = [ + [1076, '17 min'], + [3976, '1 hr'], + [5286, '1 hr'] + ]; + + for (let i = 0; i < entries.length; i++) { + const [input, output] = entries[i]; + test(`parse ${input} -> ${output}`, () => { + const result = timeRemaining(input); + expect(result).toStrictEqual(output); + }); + } +}); + +describe('timeRemaining tests - long time format', () => { + const entries: [number, string][] = [ + [1076, '17 min 56 sec'], + [3976, '1 hr 6 min'], + [5286, '1 hr 28 min'] + ]; + + for (let i = 0; i < entries.length; i++) { + const [input, output] = entries[i]; + test(`parse ${input} -> ${output}`, () => { + const result = timeRemaining(input, false); + expect(result).toStrictEqual(output); + }); + } +}); diff --git a/src/utils/operations/timeRemaining.ts b/src/utils/operations/timeRemaining.ts new file mode 100644 index 0000000..975148f --- /dev/null +++ b/src/utils/operations/timeRemaining.ts @@ -0,0 +1,88 @@ +export function getRemainingTime(ms: number) { + const days = Math.floor(ms / (24 * 60 * 60 * 1000)); + const daysms = ms % (24 * 60 * 60 * 1000); + const hrs = Math.floor(daysms / (60 * 60 * 1000)); + const hrsms = daysms % (60 * 60 * 1000); + const mins = Math.floor(hrsms / (60 * 1000)); + const minsms = hrsms % (60 * 1000); + const secs = Math.floor(minsms / 1000); + + let secsString = secs + ' sec'; + let minsString = mins + ' min'; + let hrsString = hrs + ' hr'; + let daysString = days + ' day'; + + if (secs > 1) { + secsString = secs + ' sec'; + } + if (mins > 1) { + minsString = mins + ' min'; + } + if (hrs > 1) { + hrsString = hrs + ' hrs'; + } + if (days > 1) { + daysString = days + ' days'; + } + + if (days >= 1) { + return daysString + ' ' + hrsString; + } + if (hrs >= 1) { + const minutesString = mins === 0 ? '' : ' ' + minsString; + return hrsString + minutesString; + } + if (mins >= 1) { + const secString = secs === 0 ? '' : ' ' + secsString; + return minsString + secString; + } + + return secsString; +} + +function getShortDateTimeFormat(datetime: string) { + const parts = datetime.split(' '); + if (parts.length > 1) { + return `${parts[0]} ${parts[1]}`; + } + return datetime; +} + +const getUTCDateNow = (date = new Date(), extendedSeconds = 0) => + Date.UTC( + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate(), + date.getUTCHours(), + date.getUTCMinutes(), + date.getUTCSeconds() + extendedSeconds, + date.getUTCMilliseconds() + ); + +function getUTCdiffInMs(duration: number) { + const date = new Date(); + const startDate = getUTCDateNow(date); + const endDate = getUTCDateNow(date, duration); + const diffInMs = Math.max(endDate - startDate, 0); + return diffInMs; +} + +export function timeRemaining(duration: number, short = true) { + const diffInMs = getUTCdiffInMs(duration); + const remaining = getRemainingTime(diffInMs); + return short ? getShortDateTimeFormat(remaining) : remaining; +} + +function getDifferenceInMs(timestamp: number) { + const dateNow = new Date().getTime(); + const difference = dateNow - timestamp; + const diffInMs = Math.max(difference, 0); + return diffInMs; +} + +export function timeAgo(timestamp: number, short = true) { + const diffInMs = getDifferenceInMs(timestamp); + const remaining = getRemainingTime(diffInMs); + + return short ? getShortDateTimeFormat(remaining) : remaining; +} diff --git a/src/utils/retryMultipleTimes.ts b/src/utils/retryMultipleTimes.ts index 8d1578d..943cd5c 100644 --- a/src/utils/retryMultipleTimes.ts +++ b/src/utils/retryMultipleTimes.ts @@ -6,13 +6,14 @@ interface Options { } const executeAsyncCall = async ( - cb: (...args: any[]) => any, + cb: (..._args: any[]) => any, options: Options, args: any[], retries = 0 ): Promise => { try { return await cb(...args); + // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (error) { if (retries < options.retries) { if (options?.delay != null) { @@ -28,7 +29,7 @@ const executeAsyncCall = async ( export const retryMultipleTimes = ( - cb: (...args: any[]) => any, + cb: (..._args: any[]) => any, options: Options = { retries: 5, delay: 500 } ) => async (...args: any[]) => { diff --git a/src/utils/transactions/explorerUrlBuilder.ts b/src/utils/transactions/explorerUrlBuilder.ts new file mode 100644 index 0000000..2b4c5ab --- /dev/null +++ b/src/utils/transactions/explorerUrlBuilder.ts @@ -0,0 +1,59 @@ +import { + ACCOUNTS_ENDPOINT, + BLOCKS_ENDPOINT, + CODE_ENDPOINT, + COLLECTIONS_ENDPOINT, + CONTRACTS_ENDPOINT, + IDENTITIES_ENDPOINT, + LOCKED_ACCOUNTS_ENDPOINT, + LOGS_ENDPOINT, + MINIBLOCKS_ENDPOINT, + NFTS_ENDPOINT, + NODES_ENDPOINT, + PROVIDERS_ENDPOINT, + ROLES_ENDPOINT, + SC_RESULTS_ENDPOINT, + TOKENS_ENDPOINT, + TRANSACTIONS_ENDPOINT +} from 'apiCalls/endpoints'; + +export const explorerUrlBuilder = { + shard: (shard: number | string) => `/${BLOCKS_ENDPOINT}?shard=${shard}`, + receiverShard: (shard: number | string) => + `/${TRANSACTIONS_ENDPOINT}?receivershard=${shard}`, + senderShard: (shard: number | string) => + `/${TRANSACTIONS_ENDPOINT}?sendershard=${shard}`, + transactionDetails: (hash: number | string) => + `/${TRANSACTIONS_ENDPOINT}/${hash}`, + transactionDetailsScResults: (hash: string) => + `/${TRANSACTIONS_ENDPOINT}/${hash}/${SC_RESULTS_ENDPOINT}`, + transactionDetailsLogs: (hash: string) => + `/${TRANSACTIONS_ENDPOINT}/${hash}/${LOGS_ENDPOINT}`, + nodeDetails: (publicKey: string) => `/${NODES_ENDPOINT}/${publicKey}`, + accountDetails: (address: string) => `/${ACCOUNTS_ENDPOINT}/${address}`, + accountDetailsContractCode: (address: string) => + `/${ACCOUNTS_ENDPOINT}/${address}/${CODE_ENDPOINT}`, + accountDetailsTokens: (address: string) => + `/${ACCOUNTS_ENDPOINT}/${address}/${TOKENS_ENDPOINT}`, + accountDetailsNfts: (address: string) => + `/${ACCOUNTS_ENDPOINT}/${address}/${NFTS_ENDPOINT}`, + accountDetailsScResults: (address: string) => + `/${ACCOUNTS_ENDPOINT}/${address}/${SC_RESULTS_ENDPOINT}`, + accountDetailsContracts: (address: string) => + `/${ACCOUNTS_ENDPOINT}/${address}/${CONTRACTS_ENDPOINT}`, + identityDetails: (id: string) => `/${IDENTITIES_ENDPOINT}/${id}`, + tokenDetails: (tokenId: string) => `/${TOKENS_ENDPOINT}/${tokenId}`, + tokenDetailsAccounts: (tokenId: string) => + `/${TOKENS_ENDPOINT}/${tokenId}/${ACCOUNTS_ENDPOINT}`, + tokenDetailsLockedAccounts: (tokenId: string) => + `/${TOKENS_ENDPOINT}/${tokenId}/${LOCKED_ACCOUNTS_ENDPOINT}`, + tokenDetailsRoles: (tokenId: string) => + `/${TOKENS_ENDPOINT}/${tokenId}/${ROLES_ENDPOINT}`, + collectionDetails: (identifier: string) => + `/${COLLECTIONS_ENDPOINT}/${identifier}`, + nftDetails: (identifier: string) => `/${NFTS_ENDPOINT}/${identifier}`, + providerDetails: (address: string) => `/${PROVIDERS_ENDPOINT}/${address}`, + providerDetailsTransactions: (address: string) => + `/${PROVIDERS_ENDPOINT}/${address}/${TRANSACTIONS_ENDPOINT}`, + miniblockDetails: (hash: string) => `/${MINIBLOCKS_ENDPOINT}/${hash}` +}; diff --git a/src/utils/transactions/getActiveTransactionsStatus.ts b/src/utils/transactions/getActiveTransactionsStatus.ts new file mode 100644 index 0000000..6211bd2 --- /dev/null +++ b/src/utils/transactions/getActiveTransactionsStatus.ts @@ -0,0 +1,40 @@ +import { + failedTransactionsSelector, + pendingTransactionsSelector, + successfulTransactionsSelector, + timedOutTransactionsSelector +} from 'store/selectors/transactionsSelector'; +import { getState } from 'store/store'; + +export interface GetActiveTransactionsStatusReturnType { + timedOut: boolean; + fail: boolean; + success: boolean; + pending: boolean; +} + +export function getActiveTransactionsStatus(): GetActiveTransactionsStatusReturnType { + const state = getState(); + const timedOutTransactions = timedOutTransactionsSelector(state); + const failedTransactions = failedTransactionsSelector(state); + const successfulTransactions = successfulTransactionsSelector(state); + const pendingTransactions = pendingTransactionsSelector(state); + const pending = Object.keys(pendingTransactions)?.length > 0; + const timedOut = !pending && Object.keys(timedOutTransactions)?.length > 0; + + const fail = + !pending && !timedOut && Object.keys(failedTransactions)?.length > 0; + + const success = + !pending && + !timedOut && + !fail && + Object.keys(successfulTransactions).length > 0; + + return { + pending, + timedOut, + fail, + success + }; +} diff --git a/src/utils/transactions/getExplorerLink.ts b/src/utils/transactions/getExplorerLink.ts new file mode 100644 index 0000000..9da5078 --- /dev/null +++ b/src/utils/transactions/getExplorerLink.ts @@ -0,0 +1,28 @@ +let errorMessageDisplayed = false; + +function logError(error: string) { + if (!errorMessageDisplayed) { + console.error(error); + errorMessageDisplayed = true; + } +} + +export function getExplorerLink({ + explorerAddress, + to +}: { + explorerAddress: string; + to: string; +}) { + try { + // if a valid url is sent, return the original url + const url = new URL(to); + return url.href; + } catch { + if (!to.startsWith('/')) { + logError(`Link not prepended by / : ${to}`); + to = `/${to}`; + } + return explorerAddress ? `${explorerAddress}${to}` : to; + } +} diff --git a/src/utils/transactions/getHumanReadableTimeFormat.ts b/src/utils/transactions/getHumanReadableTimeFormat.ts new file mode 100644 index 0000000..da9e2ac --- /dev/null +++ b/src/utils/transactions/getHumanReadableTimeFormat.ts @@ -0,0 +1,32 @@ +export interface GetHumanReadableTimeFormatType { + value: number; + noSeconds?: boolean; + utc?: boolean; + meridiem?: boolean; +} + +/** + * @param value - UNIX timestamp + * */ +export function getHumanReadableTimeFormat({ + value, + noSeconds, + utc, + meridiem = true +}: GetHumanReadableTimeFormatType) { + const utcDate = new Date(value * 1000); + const [, AmPm] = utcDate + .toLocaleString('en-US', { hour: 'numeric', hour12: meridiem }) + .split(' '); + const formatted = utcDate.toUTCString(); + const [, date] = formatted.split(','); + const [day, month, year, time] = date.trim().split(' '); + const [hours, minutes, sec] = time.split(':'); + const seconds = `:${sec}`; + const timeFormatted = `${hours}:${minutes}${noSeconds ? '' : seconds}`; + const utcSuffix = utc ? 'UTC' : ''; + const meridiemSuffix = meridiem ? AmPm : ''; + const suffix = `${meridiemSuffix} ${utcSuffix}`.trim(); + + return `${month} ${day}, ${year} ${timeFormatted} ${suffix}`.trim(); +} diff --git a/src/utils/transactions/getInterpretedTransaction.ts b/src/utils/transactions/getInterpretedTransaction.ts new file mode 100644 index 0000000..8c3f463 --- /dev/null +++ b/src/utils/transactions/getInterpretedTransaction.ts @@ -0,0 +1,83 @@ +import { + InterpretedTransactionType, + ServerTransactionType +} from 'types/serverTransactions.types'; +import { TokenArgumentType } from 'types/serverTransactions.types'; +import { explorerUrlBuilder } from './explorerUrlBuilder'; +import { getExplorerLink } from './getExplorerLink'; +import { getTokenFromData } from './getTokenFromData'; +import { getTransactionMethod } from './getTransactionMethod'; +import { getTransactionReceiver } from './getTransactionReceiver'; +import { getTransactionReceiverAssets } from './getTransactionReceiverAssets'; +import { getTransactionTokens } from './getTransactionTokens'; +import { getTransactionTransferType } from './getTransactionTransferType'; +import { isContract } from '../validation'; + +export interface GetInterpretedTransactionType { + address: string; + explorerAddress: string; + transaction: ServerTransactionType; +} + +export function getInterpretedTransaction({ + transaction, + address, + explorerAddress +}: GetInterpretedTransactionType): InterpretedTransactionType { + const tokenIdentifier = + transaction.tokenIdentifier ?? getTokenFromData(transaction.data).tokenId; + + const receiver = getTransactionReceiver(transaction); + const receiverAssets = getTransactionReceiverAssets(transaction); + + const direction = getTransactionTransferType(address, transaction, receiver); + const method = getTransactionMethod(transaction); + const transactionTokens: TokenArgumentType[] = + getTransactionTokens(transaction); + + const senderLink = getExplorerLink({ + explorerAddress, + to: explorerUrlBuilder.accountDetails(transaction.sender) + }); + const receiverLink = getExplorerLink({ + explorerAddress, + to: explorerUrlBuilder.accountDetails(receiver) + }); + const senderShardLink = getExplorerLink({ + explorerAddress, + to: explorerUrlBuilder.senderShard(transaction.senderShard) + }); + const receiverShardLink = getExplorerLink({ + explorerAddress, + to: explorerUrlBuilder.receiverShard(transaction.receiverShard) + }); + + const transactionHash = transaction.originalTxHash + ? `${transaction.originalTxHash}#${transaction.txHash}` + : transaction.txHash; + + const transactionLink = getExplorerLink({ + explorerAddress, + to: explorerUrlBuilder.transactionDetails(transactionHash) + }); + + return { + ...transaction, + tokenIdentifier, + receiver, + receiverAssets, + transactionDetails: { + direction, + method, + transactionTokens, + isContract: isContract(transaction.sender) + }, + links: { + senderLink, + receiverLink, + senderShardLink, + receiverShardLink, + transactionLink + } + }; +} diff --git a/src/utils/transactions/getOperationsMessages.ts b/src/utils/transactions/getOperationsMessages.ts new file mode 100644 index 0000000..577bb17 --- /dev/null +++ b/src/utils/transactions/getOperationsMessages.ts @@ -0,0 +1,9 @@ +import { ServerTransactionType } from 'types/serverTransactions.types'; + +export function getOperationsMessages(transaction: ServerTransactionType) { + return ( + transaction?.operations + ?.map((operation) => operation.message) + .filter((messages): messages is string => Boolean(messages)) ?? [] + ); +} diff --git a/src/utils/transactions/getReceiptMessage.ts b/src/utils/transactions/getReceiptMessage.ts new file mode 100644 index 0000000..04b1787 --- /dev/null +++ b/src/utils/transactions/getReceiptMessage.ts @@ -0,0 +1,40 @@ +import BigNumber from 'bignumber.js'; +import { DECIMALS, DIGITS, REFUNDED_GAS } from 'constants/index'; +import { formatAmount } from 'lib/sdkDappUtils'; +import { ServerTransactionType } from 'types/serverTransactions.types'; + +const getReceiptValue = (transaction: ServerTransactionType) => { + if (!transaction.receipt?.value) { + return ''; + } + + if (transaction.receipt?.data === REFUNDED_GAS) { + const formattedGas = formatAmount({ + input: transaction.receipt.value, + decimals: DECIMALS, + digits: DIGITS, + showLastNonZeroDecimal: true + }); + + const gasRefunded = new BigNumber(formattedGas) + .times(transaction.gasPrice) + .times(100); + + return gasRefunded.toFixed(); + } + + return transaction.receipt.value; +}; + +export function getReceiptMessage(transaction: ServerTransactionType) { + const message = transaction.receipt?.data; + + if (!message) { + return ''; + } + + const receiptValue = getReceiptValue(transaction); + const value = receiptValue ? `: ${receiptValue}` : ''; + + return `${message}${value}`; +} diff --git a/src/utils/transactions/getScResultsMessages.ts b/src/utils/transactions/getScResultsMessages.ts new file mode 100644 index 0000000..12b65b3 --- /dev/null +++ b/src/utils/transactions/getScResultsMessages.ts @@ -0,0 +1,9 @@ +import { ServerTransactionType } from 'types/serverTransactions.types'; + +export function getScResultsMessages(transaction: ServerTransactionType) { + return ( + transaction?.results + ?.map((result) => result.returnMessage) + .filter((messages): messages is string => Boolean(messages)) ?? [] + ); +} diff --git a/src/utils/transactions/getShardText.ts b/src/utils/transactions/getShardText.ts new file mode 100644 index 0000000..3d89499 --- /dev/null +++ b/src/utils/transactions/getShardText.ts @@ -0,0 +1,24 @@ +import { ALL_SHARDS_SHARD_ID, METACHAIN_SHARD_ID } from 'constants/index'; + +export const getShardText = (shard: number | string) => { + let shardText = shard; + + if (typeof shardText === 'string' && shardText.includes('Shard')) { + shardText = shardText.replace('Shard', '').replace(' ', ''); + } + + const isMetachain = + METACHAIN_SHARD_ID.toString() === String(shardText).toString() || + String(shardText) === 'metachain'; + + const isAllShards = + ALL_SHARDS_SHARD_ID.toString() === String(shardText).toString(); + + if (isMetachain) { + return 'Metachain'; + } + if (isAllShards) { + return 'All Shards'; + } + return `Shard ${shardText}`; +}; diff --git a/src/utils/transactions/getTokenFromData.ts b/src/utils/transactions/getTokenFromData.ts new file mode 100644 index 0000000..a976053 --- /dev/null +++ b/src/utils/transactions/getTokenFromData.ts @@ -0,0 +1,95 @@ +import { Address } from '@multiversx/sdk-core'; +import BigNumber from 'bignumber.js'; +import { decodePart } from 'utils/decoders/decodePart'; +import { TransactionTypesEnum } from 'types/enums.types'; +import { addressIsValid } from '../validation'; + +const noData = { + tokenId: '', + amount: '' +}; + +export const decodeData = (data: string) => { + const nonceIndex = 2; + const amountIndex = 3; + const parts = data.split('@'); + const decodedParts = parts.map((part, i) => + [nonceIndex, amountIndex].includes(i) ? part : decodePart(part) + ); + return decodedParts; +}; + +export function getTokenFromData(data?: string): { + tokenId: string; + amount: string; + collection?: string; + nonce?: string; + receiver?: string; +} { + if (!data) { + return noData; + } + + const isTokenTransfer = data.startsWith(TransactionTypesEnum.ESDTTransfer); + const isNftTransfer = + data.startsWith(TransactionTypesEnum.ESDTNFTTransfer) && data.includes('@'); + const isNftBurn = + data.startsWith(TransactionTypesEnum.ESDTNFTBurn) && data.includes('@'); + + if (isTokenTransfer) { + const [, encodedToken, encodedAmount] = data.split('@'); + try { + const tokenId = Buffer.from(encodedToken, 'hex').toString('ascii'); + + if (!tokenId) { + return noData; + } + + const amount = new BigNumber( + '0x' + encodedAmount.replace('0x', '') + ).toString(10); + + return { + tokenId, + amount + }; + } catch (e) { + console.error('Error getting token from transaction data', e); + } + } + + if (isNftTransfer) { + try { + const [, /*ESDTNFTTransfer*/ collection, nonce, quantity, receiver] = + decodeData(data); + if ( + [collection, nonce, quantity, receiver].every((el) => Boolean(el)) && + addressIsValid(new Address(receiver).bech32()) + ) { + return { + tokenId: `${collection}-${nonce}`, + amount: new BigNumber(quantity, 16).toString(10), + collection, + nonce, + receiver: new Address(receiver).bech32() + }; + } + } catch (err) {} + } + + if (isNftBurn) { + try { + const [, /*ESDTNFTBurn*/ collection, nonce, quantity] = decodeData(data); + if ([collection, nonce, quantity].every((el) => Boolean(el))) { + return { + tokenId: `${collection}-${nonce}`, + amount: new BigNumber(quantity, 16).toString(10), + collection, + nonce + }; + } + } catch (err) {} + } + + return noData; +} diff --git a/src/utils/transactions/getTransactionActionNftText.ts b/src/utils/transactions/getTransactionActionNftText.ts new file mode 100644 index 0000000..d56da89 --- /dev/null +++ b/src/utils/transactions/getTransactionActionNftText.ts @@ -0,0 +1,71 @@ +import { formatAmount } from 'lib/sdkDappUtils'; +import { TokenArgumentType } from 'types/serverTransactions.types'; +import { NftEnumType } from 'types/tokens.types'; +import { explorerUrlBuilder } from './explorerUrlBuilder'; + +export interface TransactionActionNftType { + token: TokenArgumentType; + noValue?: boolean; + showLastNonZeroDecimal?: boolean; +} +export interface TransactionActionNftReturnType { + badgeText: string | null; + tokenFormattedAmount: string | null; + tokenExplorerLink: string; + tokenLinkText: string; + token: TokenArgumentType; + showLastNonZeroDecimal?: boolean; + noValue?: boolean; +} + +export function getTransactionActionNftText({ + token, + noValue, + showLastNonZeroDecimal +}: TransactionActionNftType): TransactionActionNftReturnType { + const isTokenAmountVisible = + !noValue && token.value && token.type !== NftEnumType.NonFungibleESDT; + const canShowFormattedAmount = token.decimals != null; + + let badgeText = ''; + if (token.type === NftEnumType.NonFungibleESDT) { + badgeText = 'NFT'; + } + if (token.type === NftEnumType.SemiFungibleESDT) { + badgeText = 'SFT'; + } + if (token.type === NftEnumType.MetaESDT) { + badgeText = 'Meta-ESDT'; + } + + let tokenFormattedAmount = ''; + if (isTokenAmountVisible && canShowFormattedAmount) { + tokenFormattedAmount = canShowFormattedAmount + ? formatAmount({ + input: token.value, + decimals: token.decimals, + digits: 2, + showLastNonZeroDecimal + }) + : Number(token.value).toLocaleString('en'); + } + + const tokenExplorerLink = explorerUrlBuilder.nftDetails( + String(token.identifier) + ); + + const tokenLinkText = + token.ticker === token.collection + ? token.identifier ?? token.ticker + : token.ticker; + + return { + badgeText, + tokenFormattedAmount: isTokenAmountVisible ? tokenFormattedAmount : null, + tokenExplorerLink, + tokenLinkText, + token, + noValue, + showLastNonZeroDecimal + }; +} diff --git a/src/utils/transactions/getTransactionMessages.ts b/src/utils/transactions/getTransactionMessages.ts new file mode 100644 index 0000000..48c5c6b --- /dev/null +++ b/src/utils/transactions/getTransactionMessages.ts @@ -0,0 +1,16 @@ +import { InterpretedTransactionType } from 'types/serverTransactions.types'; +import { getOperationsMessages } from './getOperationsMessages'; +import { getReceiptMessage } from './getReceiptMessage'; +import { getScResultsMessages } from './getScResultsMessages'; + +export function getTransactionMessages( + transaction: InterpretedTransactionType +) { + return Array.from( + new Set([ + ...getScResultsMessages(transaction), + ...getOperationsMessages(transaction), + getReceiptMessage(transaction) + ]) + ).filter((el) => Boolean(el)); +} diff --git a/src/utils/transactions/getTransactionMethod.ts b/src/utils/transactions/getTransactionMethod.ts new file mode 100644 index 0000000..f84b4cc --- /dev/null +++ b/src/utils/transactions/getTransactionMethod.ts @@ -0,0 +1,28 @@ +import { + TransactionActionCategoryEnum, + TransactionActionsEnum, + ServerTransactionType +} from 'types/serverTransactions.types'; + +export const getTransactionMethod = (transaction: ServerTransactionType) => { + let transactionAction = 'Transaction'; + const transactionHasAction = + transaction.action?.name && transaction.action?.category; + + if (transactionHasAction) { + if ( + transaction.action?.category === TransactionActionCategoryEnum.esdtNft && + transaction.action?.name === TransactionActionsEnum.transfer + ) { + transactionAction = 'Transaction'; + } else if (transaction.action) { + transactionAction = transaction.action.name; + } + + if (transaction.action?.arguments?.functionName) { + transactionAction = transaction.action.arguments.functionName; + } + } + + return transactionAction; +}; diff --git a/src/utils/transactions/getTransactionReceiver.ts b/src/utils/transactions/getTransactionReceiver.ts new file mode 100644 index 0000000..0ffa550 --- /dev/null +++ b/src/utils/transactions/getTransactionReceiver.ts @@ -0,0 +1,10 @@ +import { ServerTransactionType } from 'types/serverTransactions.types'; + +export function getTransactionReceiver(transaction: ServerTransactionType) { + let receiver = transaction.receiver; + if (transaction.action?.arguments?.receiver) { + receiver = transaction.action.arguments.receiver; + } + + return receiver; +} diff --git a/src/utils/transactions/getTransactionReceiverAssets.ts b/src/utils/transactions/getTransactionReceiverAssets.ts new file mode 100644 index 0000000..0c2e484 --- /dev/null +++ b/src/utils/transactions/getTransactionReceiverAssets.ts @@ -0,0 +1,15 @@ +import { ServerTransactionType } from 'types/serverTransactions.types'; +import { getTransactionReceiver } from './getTransactionReceiver'; + +/** + * The information about an account like name, icon, etc... + * */ +export function getTransactionReceiverAssets( + transaction: ServerTransactionType +) { + const receiver = getTransactionReceiver(transaction); + + return transaction.receiver === receiver + ? transaction.receiverAssets + : undefined; +} diff --git a/src/utils/transactions/getTransactionStatus.ts b/src/utils/transactions/getTransactionStatus.ts new file mode 100644 index 0000000..73be8a4 --- /dev/null +++ b/src/utils/transactions/getTransactionStatus.ts @@ -0,0 +1,24 @@ +import { TransactionServerStatusesEnum } from 'types/enums.types'; +import { InterpretedTransactionType } from 'types/serverTransactions.types'; + +export function getTransactionStatus(transaction: InterpretedTransactionType) { + const statusIs = (compareTo: string) => + transaction.status.toLowerCase() === compareTo.toLowerCase(); + + const failed = + statusIs(TransactionServerStatusesEnum.fail) || + statusIs(TransactionServerStatusesEnum.rewardReverted); + const success = statusIs(TransactionServerStatusesEnum.success); + const invalid = + statusIs(TransactionServerStatusesEnum.notExecuted) || + statusIs(TransactionServerStatusesEnum.invalid); + const pending = + statusIs(TransactionServerStatusesEnum.pending) || + transaction.pendingResults; + return { + failed, + success, + invalid, + pending + }; +} diff --git a/src/utils/transactions/getTransactionTokens.ts b/src/utils/transactions/getTransactionTokens.ts new file mode 100644 index 0000000..ba217fa --- /dev/null +++ b/src/utils/transactions/getTransactionTokens.ts @@ -0,0 +1,21 @@ +import { + ServerTransactionType, + TokenArgumentType +} from 'types/serverTransactions.types'; + +export const getTransactionTokens = ( + transaction: ServerTransactionType +): TokenArgumentType[] => { + if (transaction.action) { + const merged = [ + transaction.action.arguments?.token, + transaction.action.arguments?.token1, + transaction.action.arguments?.token2, + transaction.action.arguments?.transfers // array of tokens + ].filter((x) => x != null); + + return [].concat(...merged); + } + + return []; +}; diff --git a/src/utils/transactions/getTransactionTransferType.ts b/src/utils/transactions/getTransactionTransferType.ts new file mode 100644 index 0000000..775bdf9 --- /dev/null +++ b/src/utils/transactions/getTransactionTransferType.ts @@ -0,0 +1,28 @@ +import { + ServerTransactionType, + TransferTypeEnum, + TransactionDirectionEnum +} from 'types/serverTransactions.types'; + +export function getTransactionTransferType( + address: string, + transaction: ServerTransactionType, + receiver: string +): TransactionDirectionEnum { + const directionOut = address === transaction.sender; + const directionIn = address === receiver; + const directionSelf = directionOut && directionIn; + const isScResult = transaction?.type === TransferTypeEnum.SmartContractResult; + + switch (true) { + case isScResult: + return TransactionDirectionEnum.INTERNAL; + case directionSelf: + return TransactionDirectionEnum.SELF; + case directionIn: + return TransactionDirectionEnum.IN; + case directionOut: + default: + return TransactionDirectionEnum.OUT; + } +} diff --git a/src/utils/transactions/getTransactionValue/constants.ts b/src/utils/transactions/getTransactionValue/constants.ts new file mode 100644 index 0000000..20dd6f6 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/constants.ts @@ -0,0 +1,32 @@ +import { TransactionActionsEnum } from 'types/serverTransactions.types'; + +/** + * If `action.name` or `function` is in `ACTIONS_WITH_MANDATORY_OPERATIONS[]`, transaction value will be computed based `operations` field + */ +export const ACTIONS_WITH_MANDATORY_OPERATIONS = [ + TransactionActionsEnum.reDelegateRewards, + TransactionActionsEnum.claimRewards, + TransactionActionsEnum.unBond +]; + +/** + * If `action.name` is in `ACTIONS_WITH_EGLD_VALUE[]`, transaction value will be returned directly + */ +export const ACTIONS_WITH_EGLD_VALUE = [ + TransactionActionsEnum.wrapEgld, + TransactionActionsEnum.unwrapEgld +]; + +/** + * If `action.name` is in `ACTIONS_WITH_VALUE_IN_DATA_FIELD[]`, transaction value will be computed based `data` field + */ +export const ACTIONS_WITH_VALUE_IN_DATA_FIELD = [ + TransactionActionsEnum.unStake +]; + +/** + * If `action.name` is in `ACTIONS_WITH_VALUE_IN_ACTION_FIELD[]`, transaction value will be computed based `action` field + */ +export const ACTIONS_WITH_VALUE_IN_ACTION_FIELD = [ + TransactionActionsEnum.unDelegate +]; diff --git a/src/utils/transactions/getTransactionValue/getTransactionValue.ts b/src/utils/transactions/getTransactionValue/getTransactionValue.ts new file mode 100644 index 0000000..d07ec03 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/getTransactionValue.ts @@ -0,0 +1,125 @@ +import { DECIMALS } from 'constants/index'; +import { formatAmount } from 'lib/sdkDappUtils'; +import { InterpretedTransactionType } from 'types/serverTransactions.types'; +import { NftEnumType } from 'types/tokens.types'; + +import { + ACTIONS_WITH_EGLD_VALUE, + ACTIONS_WITH_MANDATORY_OPERATIONS, + ACTIONS_WITH_VALUE_IN_ACTION_FIELD, + ACTIONS_WITH_VALUE_IN_DATA_FIELD +} from './constants'; + +import { + getEgldValueData, + getTitleText, + getValueFromActions, + getValueFromDataField, + getValueFromOperations +} from './helpers'; +import { + EgldValueDataType, + NFTValueDataType, + TokenValueDataType +} from './types'; +import { explorerUrlBuilder } from '../explorerUrlBuilder'; +import { getTransactionActionNftText } from '../getTransactionActionNftText'; +import { getTransactionTokens } from '../getTransactionTokens'; + +export interface GetTransactionValueReturnType { + egldValueData?: EgldValueDataType; + tokenValueData?: TokenValueDataType; + nftValueData?: NFTValueDataType; +} + +export interface GetTransactionValueType { + hideMultipleBadge?: boolean; + transaction: InterpretedTransactionType; +} + +export const getTransactionValue = ({ + transaction, + hideMultipleBadge +}: GetTransactionValueType): GetTransactionValueReturnType => { + if (transaction.action) { + if (ACTIONS_WITH_EGLD_VALUE.includes(transaction.action.name)) { + return getEgldValueData(transaction.value); + } + + if (ACTIONS_WITH_VALUE_IN_DATA_FIELD.includes(transaction.action.name)) { + return getValueFromDataField(transaction); + } + + if (ACTIONS_WITH_MANDATORY_OPERATIONS.includes(transaction.action.name)) { + return getValueFromOperations(transaction); + } + + if (ACTIONS_WITH_VALUE_IN_ACTION_FIELD.includes(transaction.action.name)) { + return getValueFromActions(transaction); + } + + const transactionTokens = getTransactionTokens(transaction); + + if (transactionTokens.length) { + const txToken = transactionTokens[0]; + const isNft = Object.values(NftEnumType).includes( + txToken.type as NftEnumType + ); + + const hasTitleText = !hideMultipleBadge && transactionTokens.length > 1; + const titleText = hasTitleText ? getTitleText(transactionTokens) : ''; + + if (isNft) { + const { + badgeText, + tokenFormattedAmount, + tokenExplorerLink, + tokenLinkText + } = getTransactionActionNftText({ token: txToken }); + + return { + nftValueData: { + badgeText, + tokenFormattedAmount, + tokenExplorerLink, + tokenLinkText, + transactionTokens, + token: txToken, + value: tokenFormattedAmount != null ? txToken.value : null, + decimals: tokenFormattedAmount != null ? txToken.decimals : null, + titleText + } + }; + } + + const tokenFormattedAmount = txToken.value + ? formatAmount({ + input: txToken.value, + decimals: txToken.decimals ?? DECIMALS, + digits: 2, + addCommas: true + }) + : null; + + const tokenExplorerLink = explorerUrlBuilder.tokenDetails( + String(txToken.token) + ); + + return { + tokenValueData: { + tokenExplorerLink, + showFormattedAmount: false, + tokenFormattedAmount, + tokenLinkText: txToken.ticker, + transactionTokens, + token: txToken, + value: txToken.value, + decimals: txToken.decimals ?? DECIMALS, + titleText + } + }; + } + } + + return getEgldValueData(transaction.value); +}; diff --git a/src/utils/transactions/getTransactionValue/helpers/getEgldValueData.ts b/src/utils/transactions/getTransactionValue/helpers/getEgldValueData.ts new file mode 100644 index 0000000..3fc812f --- /dev/null +++ b/src/utils/transactions/getTransactionValue/helpers/getEgldValueData.ts @@ -0,0 +1,10 @@ +import { DECIMALS } from 'constants/mvx.constants'; +import { formatAmount } from 'lib/sdkDappUtils'; + +export const getEgldValueData = (value: string) => ({ + egldValueData: { + value, + formattedValue: formatAmount({ input: value }), + decimals: DECIMALS + } +}); diff --git a/src/utils/transactions/getTransactionValue/helpers/getTitleText.ts b/src/utils/transactions/getTransactionValue/helpers/getTitleText.ts new file mode 100644 index 0000000..4a8f6c7 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/helpers/getTitleText.ts @@ -0,0 +1,55 @@ +import { DECIMALS } from 'constants/mvx.constants'; +import { formatAmount } from 'lib/sdkDappUtils'; +import { TokenArgumentType } from 'types/serverTransactions.types'; + +import { getIdentifierType } from 'utils/validation/getIdentifierType'; +import { getTransactionActionNftText } from '../../getTransactionActionNftText'; +import { + EgldValueDataType, + NFTValueDataType, + TokenValueDataType +} from '../types'; + +export interface GetTransactionValueReturnType { + egldValueData?: EgldValueDataType; + tokenValueData?: TokenValueDataType; + nftValueData?: NFTValueDataType; +} + +export const getTitleText = ( + transactionTokens: TokenArgumentType[] +): string => { + const tokensArray = transactionTokens.map((transactionToken) => { + const { isNft } = getIdentifierType(transactionToken.type); + if (isNft) { + const { badgeText, tokenFormattedAmount, tokenLinkText } = + getTransactionActionNftText({ + token: transactionToken + }); + + const badge = badgeText != null ? `(${badgeText}) ` : ''; + + const value = `${badge}${tokenFormattedAmount} ${tokenLinkText}`; + return value; + } + + const tokenFormattedAmount = transactionToken.value + ? formatAmount({ + input: transactionToken.value, + decimals: transactionToken.decimals ?? DECIMALS, + digits: 2, + addCommas: true + }) + : null; + + const identifier = transactionToken.collection + ? transactionToken.identifier + : transactionToken.token; + + const value = `${tokenFormattedAmount} ${transactionToken.ticker} (${identifier})`; + return value; + }); + + const joinedTokensWithLineBreak = decodeURI(tokensArray.join('%0A')); + return joinedTokensWithLineBreak; +}; diff --git a/src/utils/transactions/getTransactionValue/helpers/getValueFromActions.ts b/src/utils/transactions/getTransactionValue/helpers/getValueFromActions.ts new file mode 100644 index 0000000..16cc542 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/helpers/getValueFromActions.ts @@ -0,0 +1,23 @@ +import BigNumber from 'bignumber.js'; +import { InterpretedTransactionType } from 'types/serverTransactions.types'; +import { getEgldValueData } from './getEgldValueData'; + +let warningLogged = false; + +export function getValueFromActions(transaction: InterpretedTransactionType) { + const value = new BigNumber(transaction.action?.arguments?.value); + + if (!value.isNaN()) { + return getEgldValueData(transaction.action?.arguments?.value); + } + + if (!warningLogged) { + console.error( + `Unable to interpret ${transaction.action?.name} data for txHash: ${transaction.txHash}` + ); + warningLogged = true; + } + + // fallback on transaction value + return getEgldValueData(transaction.value); +} diff --git a/src/utils/transactions/getTransactionValue/helpers/getValueFromDataField.ts b/src/utils/transactions/getTransactionValue/helpers/getValueFromDataField.ts new file mode 100644 index 0000000..4205e8e --- /dev/null +++ b/src/utils/transactions/getTransactionValue/helpers/getValueFromDataField.ts @@ -0,0 +1,27 @@ +import BigNumber from 'bignumber.js'; +import { InterpretedTransactionType } from 'types/serverTransactions.types'; +import { decodeBase64 } from 'utils/decoders'; +import { getEgldValueData } from './getEgldValueData'; + +let warningLogged = false; + +export function getValueFromDataField(transaction: InterpretedTransactionType) { + try { + const data = decodeBase64(transaction.data); + const encodedValue = data.replace(`${transaction.action?.name}@`, ''); + const value = new BigNumber(encodedValue, 16); + if (!value.isNaN()) { + return getEgldValueData(value.toString(10)); + } + } catch (err) { + if (!warningLogged) { + console.error( + `Unable to extract value for txHash: ${transaction.txHash}` + ); + warningLogged = true; + } + } + + // fallback on transaction value + return getEgldValueData(transaction.value); +} diff --git a/src/utils/transactions/getTransactionValue/helpers/getValueFromOperations.ts b/src/utils/transactions/getTransactionValue/helpers/getValueFromOperations.ts new file mode 100644 index 0000000..b061503 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/helpers/getValueFromOperations.ts @@ -0,0 +1,31 @@ +import { InterpretedTransactionType } from 'types/serverTransactions.types'; +import { getEgldValueData } from './getEgldValueData'; +import { getVisibleOperations } from '../../getVisibleOperations'; + +let warningLogged = false; + +const logError = (hash: string) => { + if (!warningLogged) { + console.error( + `Operations field missing for txHash: ${hash}. + Unable to compute value field.` + ); + warningLogged = true; + } +}; + +export function getValueFromOperations( + transaction: InterpretedTransactionType +) { + try { + if (transaction.operations) { + const [operation] = getVisibleOperations(transaction); + return getEgldValueData(operation?.value); + } else { + logError(transaction.txHash); + } + } catch (err) { + logError(transaction.txHash); + } + return getEgldValueData(transaction.value); +} diff --git a/src/utils/transactions/getTransactionValue/helpers/index.ts b/src/utils/transactions/getTransactionValue/helpers/index.ts new file mode 100644 index 0000000..80d2309 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/helpers/index.ts @@ -0,0 +1,5 @@ +export * from './getTitleText'; +export * from './getEgldValueData'; +export * from './getValueFromDataField'; +export * from './getValueFromOperations'; +export * from './getValueFromActions'; diff --git a/src/utils/transactions/getTransactionValue/index.ts b/src/utils/transactions/getTransactionValue/index.ts new file mode 100644 index 0000000..da93a6d --- /dev/null +++ b/src/utils/transactions/getTransactionValue/index.ts @@ -0,0 +1 @@ +export * from './getTransactionValue'; diff --git a/src/utils/transactions/getTransactionValue/types.ts b/src/utils/transactions/getTransactionValue/types.ts new file mode 100644 index 0000000..08566c1 --- /dev/null +++ b/src/utils/transactions/getTransactionValue/types.ts @@ -0,0 +1,26 @@ +import { TokenArgumentType } from 'types/serverTransactions.types'; + +export interface ESDTValueDataType { + tokenFormattedAmount: string | null; + tokenExplorerLink: string; + tokenLinkText: string; + transactionTokens: TokenArgumentType[]; + token: TokenArgumentType; + value: string | null; + decimals: number | null; + titleText: string; +} + +export interface NFTValueDataType extends ESDTValueDataType { + badgeText: string | null; +} + +export interface TokenValueDataType extends ESDTValueDataType { + showFormattedAmount: boolean; +} + +export interface EgldValueDataType { + value: string; + formattedValue: string; + decimals: number; +} diff --git a/src/utils/transactions/getVisibleOperations.ts b/src/utils/transactions/getVisibleOperations.ts new file mode 100644 index 0000000..dfbaea4 --- /dev/null +++ b/src/utils/transactions/getVisibleOperations.ts @@ -0,0 +1,17 @@ +import { + InterpretedTransactionType, + VisibleTransactionOperationType +} from 'types/serverTransactions.types'; + +export const getVisibleOperations = ( + transaction: InterpretedTransactionType +) => { + const operations = + transaction?.operations?.filter((operation) => + Object.values(VisibleTransactionOperationType).includes( + operation.type + ) + ) ?? []; + + return operations; +}; diff --git a/src/utils/transactions/index.ts b/src/utils/transactions/index.ts new file mode 100644 index 0000000..d9cc05e --- /dev/null +++ b/src/utils/transactions/index.ts @@ -0,0 +1,17 @@ +export { explorerUrlBuilder } from './explorerUrlBuilder'; +export { getActiveTransactionsStatus } from './getActiveTransactionsStatus'; +export { getExplorerLink } from './getExplorerLink'; +export { getHumanReadableTimeFormat } from './getHumanReadableTimeFormat'; +export { getInterpretedTransaction } from './getInterpretedTransaction'; +export { getOperationsMessages } from './getOperationsMessages'; +export { getReceiptMessage } from './getReceiptMessage'; +export { getScResultsMessages } from './getScResultsMessages'; +export { getShardText } from './getShardText'; +export { getTokenFromData } from './getTokenFromData'; +export { getTransactionMessages } from './getTransactionMessages'; +export { getTransactionMethod } from './getTransactionMethod'; +export { getTransactionReceiver } from './getTransactionReceiver'; +export { getTransactionReceiverAssets } from './getTransactionReceiverAssets'; +export { getTransactionStatus } from './getTransactionStatus'; +export { getTransactionTokens } from './getTransactionTokens'; +export { getTransactionTransferType } from './getTransactionTransferType'; diff --git a/src/utils/transactions/isGuardianTx.ts b/src/utils/transactions/isGuardianTx.ts new file mode 100644 index 0000000..bdeef01 --- /dev/null +++ b/src/utils/transactions/isGuardianTx.ts @@ -0,0 +1,21 @@ +import { GuardianActionsEnum } from 'types/enums.types'; + +export const isGuardianTx = ({ + data, + onlySetGuardian +}: { + data?: string; + onlySetGuardian?: boolean; +}) => { + if (!data) { + return false; + } + + if (onlySetGuardian) { + return data.startsWith(GuardianActionsEnum.SetGuardian); + } + + return Object.values(GuardianActionsEnum).some((action) => + data.startsWith(action) + ); +}; diff --git a/src/utils/transactions/tests/base-transaction-mock.ts b/src/utils/transactions/tests/base-transaction-mock.ts new file mode 100644 index 0000000..23c9285 --- /dev/null +++ b/src/utils/transactions/tests/base-transaction-mock.ts @@ -0,0 +1,28 @@ +import { TransactionActionsEnum } from 'types/serverTransactions.types'; + +export const baseTransactionMock = { + blockHash: '', + price: 60, + txHash: 'c747f6ea467fb68e2f152a5baa57edbc7e04d297954878084363cbdb961eed7e', + gasLimit: 60000000, + gasPrice: 1000000000, + gasUsed: 60000000, + miniBlockHash: + 'd7ad7c1f8f57e3a370b12092604c42157cb5228ab598e9bbca641ee2e4ee7bd2', + nonce: 965, + receiver: 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + receiverShard: 0, + round: 2044988, + sender: 'erd1axhx4kenjlae6sknq7zjg2g4fvzavv979r2fg425p62wkl84avtqsf7vvv', + senderShard: 0, + signature: 'transaction-signature-hash', + status: 'fail', + value: '1234', + fee: '655440000000000', + timestamp: 1660821528, + data: 'cGluZw==', + action: { + category: 'scCall', + name: TransactionActionsEnum.ping + } +}; diff --git a/src/utils/transactions/tests/extended-transaction-mock.ts b/src/utils/transactions/tests/extended-transaction-mock.ts new file mode 100644 index 0000000..d703734 --- /dev/null +++ b/src/utils/transactions/tests/extended-transaction-mock.ts @@ -0,0 +1,91 @@ +import { + ServerTransactionType, + TransactionOperationActionTypeEnum, + TransactionActionCategoryEnum, + TransactionActionsEnum, + VisibleTransactionOperationType +} from 'types/serverTransactions.types'; +import { EsdtEnumType } from 'types/tokens.types'; +import { baseTransactionMock } from './base-transaction-mock'; + +export const transactionMock: ServerTransactionType = { + ...baseTransactionMock, + action: { + name: TransactionActionsEnum.transfer, + category: TransactionActionCategoryEnum.scCall, + arguments: { + token: 'token', + token1: 'token1', + token2: 'token2', + transfers: 'transfers', + null: null, + undefined: undefined + } + }, + receiverAssets: { + name: 'john doe', + description: 'description', + iconPng: 'icon.png', + iconSvg: 'icon.svg', + tags: ['@tag1', '@tag2'] + }, + operations: [ + { + name: 'send', + type: VisibleTransactionOperationType.egld, + action: TransactionOperationActionTypeEnum.transfer, + esdtType: EsdtEnumType.FungibleESDT, + receiver: + 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + sender: 'erd1axhx4kenjlae6sknq7zjg2g4fvzavv979r2fg425p62wkl84avtqsf7vvv', + value: '1', + decimals: 4, + identifier: 'EGLD', + message: 'message 0' + }, + { + name: 'send', + type: VisibleTransactionOperationType.egld, + action: TransactionOperationActionTypeEnum.transfer, + esdtType: EsdtEnumType.FungibleESDT, + receiver: + 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + sender: 'erd1axhx4kenjlae6sknq7zjg2g4fvzavv979r2fg425p62wkl84avtqsf7vvv', + value: '1', + decimals: 4, + identifier: 'EGLD', + message: 'message 1' + } + ], + results: [ + { + callType: '', + value: '1', + gasLimit: 100, + gasPrice: 0.001, + hash: 'tx-hash', + nonce: 0, + sender: 'sender-hash', + originalTxHash: 'original-tx-hash', + prevTxHash: 'prev-tx-hash', + returnMessage: 'message 0' + }, + { + callType: '', + value: '1', + gasLimit: 100, + gasPrice: 0.001, + hash: 'tx-hash', + nonce: 0, + sender: 'sender-hash', + originalTxHash: 'original-tx-hash', + prevTxHash: 'prev-tx-hash', + returnMessage: 'message 1' + } + ], + receipt: { + data: '@some-data', + value: '1000', + sender: 'sender-hash' + } +}; diff --git a/src/utils/transactions/tests/getExplorerkLink.test.ts b/src/utils/transactions/tests/getExplorerkLink.test.ts new file mode 100644 index 0000000..55c1d99 --- /dev/null +++ b/src/utils/transactions/tests/getExplorerkLink.test.ts @@ -0,0 +1,27 @@ +import { getExplorerLink } from '../getExplorerLink'; + +describe('getNetworkLink', () => { + it('return "/${to}" parameter when the explorerAddress is empty and log an error in console', () => { + // prevent showing errors in Jest console + jest.mock('console', () => ({ + error: () => null + })); + + const input = 'address'; + const consoleErrorSpy = jest.spyOn(console, 'error'); + + const result = getExplorerLink({ explorerAddress: '', to: input }); + + expect(consoleErrorSpy).toHaveBeenCalled(); + expect(result).toEqual(`/${input}`); + }); + + it('compose link using explorer address and "to" parameter', () => { + const explorerAddress = 'http://devnet-explorer.multiversx.com'; + const to = '/address'; + + const result = getExplorerLink({ explorerAddress, to }); + + expect(result).toEqual(`${explorerAddress}${to}`); + }); +}); diff --git a/src/utils/transactions/tests/getHumanReadableTimeFormat.test.ts b/src/utils/transactions/tests/getHumanReadableTimeFormat.test.ts new file mode 100644 index 0000000..ee41c4d --- /dev/null +++ b/src/utils/transactions/tests/getHumanReadableTimeFormat.test.ts @@ -0,0 +1,139 @@ +import { getHumanReadableTimeFormat } from '../getHumanReadableTimeFormat'; + +describe('getHumanReadableTimeFormat', () => { + it('returns full readable date, non-UTC', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const hours = date.getUTCHours(); + const noSeconds = false; + const utc = false; + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33:12 AM`); + }); + + it('returns readable date without seconds, non-UTC', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const hours = date.getUTCHours(); + const noSeconds = true; + const utc = false; + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33 AM`); + }); + + it('returns full readable date in UTC', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const noSeconds = false; + const utc = true; + const hours = date.getUTCHours(); + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33:12 AM UTC`); + }); + + it('returns full readable date without seconds in UTC', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const noSeconds = true; + const utc = true; + const hours = date.getUTCHours(); + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33 AM UTC`); + }); + + it('returns full readable date, non-UTC, without meridiem', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const hours = date.getUTCHours(); + const noSeconds = false; + const utc = false; + const meridiem = false; + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc, + meridiem + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33:12`); + }); + + it('returns readable date without seconds, non-UTC, without meridiem', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const hours = date.getUTCHours(); + const noSeconds = true; + const utc = false; + const meridiem = false; + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc, + meridiem + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33`); + }); + + it('returns full readable date in UTC, without meridiem', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const noSeconds = false; + const utc = true; + const hours = date.getUTCHours(); + const meridiem = false; + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc, + meridiem + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33:12 UTC`); + }); + + it('returns full readable date without seconds in UTC, without meridiem', () => { + const date = new Date(1993, 3, 23, 8, 33, 12); + const value = date.getTime() / 1000; // UNIX timestamp + const noSeconds = true; + const utc = true; + const hours = date.getUTCHours(); + const meridiem = false; + + const result = getHumanReadableTimeFormat({ + value, + noSeconds, + utc, + meridiem + }); + + expect(result).toEqual(`Apr 23, 1993 0${hours}:33 UTC`); + }); +}); diff --git a/src/utils/transactions/tests/getInterpretedTransaction.test.ts b/src/utils/transactions/tests/getInterpretedTransaction.test.ts new file mode 100644 index 0000000..c0d0a03 --- /dev/null +++ b/src/utils/transactions/tests/getInterpretedTransaction.test.ts @@ -0,0 +1,162 @@ +import { + InterpretedTransactionType, + TransactionDirectionEnum +} from 'types/serverTransactions.types'; +import { + ServerTransactionType, + TransactionActionsEnum +} from 'types/serverTransactions.types'; +import { getInterpretedTransaction } from '../getInterpretedTransaction'; +import { transactionMock } from './extended-transaction-mock'; +import { explorerUrlBuilder } from '../explorerUrlBuilder'; + +const explorerAddress = 'https://testing.devnet.com'; + +describe('transaction interpreter', () => { + describe('interpretServerTransaction', () => { + it('creates an extended model of the existing transaction, containing all the needed information necessary to build the UI without processing inside the components', () => { + const transaction: ServerTransactionType = { + ...transactionMock, + tokenIdentifier: 'token-id' + }; + const output: InterpretedTransactionType = { + ...transaction, + links: { + senderLink: `${explorerAddress}${explorerUrlBuilder.accountDetails( + transaction.sender + )}`, + receiverLink: `${explorerAddress}${explorerUrlBuilder.accountDetails( + transaction.receiver + )}`, + receiverShardLink: `${explorerAddress}${explorerUrlBuilder.receiverShard( + transaction.receiverShard + )}`, + senderShardLink: `${explorerAddress}${explorerUrlBuilder.senderShard( + transaction.senderShard + )}`, + transactionLink: `${explorerAddress}${explorerUrlBuilder.transactionDetails( + transaction.txHash + )}` + }, + transactionDetails: { + transactionTokens: [ + transaction?.action?.arguments?.token, + transaction?.action?.arguments?.token1, + transaction?.action?.arguments?.token2, + transaction?.action?.arguments?.transfers + ].filter((x) => x != null), + direction: TransactionDirectionEnum.OUT, + isContract: false, + method: TransactionActionsEnum.transfer + } + }; + + const result = getInterpretedTransaction({ + transaction, + address: 'erd1-my-address-hash', + explorerAddress + }); + + expect(result).toEqual(output); + }); + }); + + describe('interpretServerTransactions', () => { + it('parse all the transactions and creates transactions extended models, containing all the needed information necessary to build the UI without processing inside the components', () => { + const networkAddress = 'https://testing.devnet.com'; + const transactions: ServerTransactionType[] = [ + { + ...transactionMock, + tokenIdentifier: 'token-id' + }, + { + ...transactionMock, + tokenIdentifier: 'token-id-2', + // SC address. Use to set the isContract field + sender: + 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + // Use the same with the account address to have SELF transfer + receiver: + 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + senderShard: 2, + receiverShard: 3 + } + ]; + const output: InterpretedTransactionType[] = [ + { + ...transactions[0], + links: { + senderLink: `${networkAddress}${explorerUrlBuilder.accountDetails( + transactions[0].sender + )}`, + receiverLink: `${networkAddress}${explorerUrlBuilder.accountDetails( + transactions[0].receiver + )}`, + receiverShardLink: `${networkAddress}${explorerUrlBuilder.receiverShard( + transactions[0].receiverShard + )}`, + senderShardLink: `${networkAddress}${explorerUrlBuilder.senderShard( + transactions[0].senderShard + )}`, + transactionLink: `${networkAddress}${explorerUrlBuilder.transactionDetails( + transactions[0].txHash + )}` + }, + transactionDetails: { + transactionTokens: [ + transactions[0]?.action?.arguments?.token, + transactions[0]?.action?.arguments?.token1, + transactions[0]?.action?.arguments?.token2, + transactions[0]?.action?.arguments?.transfers + ].filter((x) => x != null), + direction: TransactionDirectionEnum.IN, + isContract: false, + method: TransactionActionsEnum.transfer + } + }, + { + ...transactions[1], + links: { + senderLink: `${networkAddress}${explorerUrlBuilder.accountDetails( + transactions[1].sender + )}`, + receiverLink: `${networkAddress}${explorerUrlBuilder.accountDetails( + transactions[1].receiver + )}`, + receiverShardLink: `${networkAddress}${explorerUrlBuilder.receiverShard( + transactions[1].receiverShard + )}`, + senderShardLink: `${networkAddress}${explorerUrlBuilder.senderShard( + transactions[1].senderShard + )}`, + transactionLink: `${networkAddress}${explorerUrlBuilder.transactionDetails( + transactions[1].txHash + )}` + }, + transactionDetails: { + transactionTokens: [ + transactions[1]?.action?.arguments?.token, + transactions[1]?.action?.arguments?.token1, + transactions[1]?.action?.arguments?.token2, + transactions[1]?.action?.arguments?.transfers + ].filter((x) => x != null), + direction: TransactionDirectionEnum.SELF, + isContract: true, + method: TransactionActionsEnum.transfer + } + } + ]; + + const result = transactions.map((transaction) => + getInterpretedTransaction({ + transaction, + address: + 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + explorerAddress + }) + ); + + expect(result).toEqual(output); + }); + }); +}); diff --git a/src/utils/transactions/tests/getOperationsMessages.test.ts b/src/utils/transactions/tests/getOperationsMessages.test.ts new file mode 100644 index 0000000..bda15cf --- /dev/null +++ b/src/utils/transactions/tests/getOperationsMessages.test.ts @@ -0,0 +1,48 @@ +import { + OperationType, + TransactionOperationActionTypeEnum, + VisibleTransactionOperationType +} from 'types/serverTransactions.types'; +import { getOperationsMessages } from '../getOperationsMessages'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getOperationsMessages', () => { + it('receive empty array if no operations messages exists on the transaction', () => { + const result = getOperationsMessages(baseTransactionMock); + + expect(result).toEqual([]); + }); + + it('receive an array with all operations messages', () => { + const baseTransactionOperation = { + name: 'send', + type: VisibleTransactionOperationType.egld, + action: TransactionOperationActionTypeEnum.transfer, + esdtType: 'FungibleESDT', + receiver: + 'erd1qqqqqqqqqqqqqpgq4gdcg0k83u7lpv4s4532w3au9y9h0vm70eqq6m8qk2', + sender: 'erd1axhx4kenjlae6sknq7zjg2g4fvzavv979r2fg425p62wkl84avtqsf7vvv', + value: '1', + decimals: 4, + identifier: 'EGLD' + }; + + const transaction = { + ...baseTransactionMock, + operations: [ + { + ...baseTransactionOperation, + message: 'message 0' + }, + { + ...baseTransactionOperation, + message: 'message 1' + } + ] as OperationType[] + }; + + const result = getOperationsMessages(transaction); + + expect(result).toEqual(['message 0', 'message 1']); + }); +}); diff --git a/src/utils/transactions/tests/getReceiptMessage.test.ts b/src/utils/transactions/tests/getReceiptMessage.test.ts new file mode 100644 index 0000000..24a96b5 --- /dev/null +++ b/src/utils/transactions/tests/getReceiptMessage.test.ts @@ -0,0 +1,57 @@ +import BigNumber from 'bignumber.js'; +import { DECIMALS, DIGITS, REFUNDED_GAS } from 'constants/index'; + +import { formatAmount } from 'lib/sdkDappUtils'; +import { getReceiptMessage } from '../getReceiptMessage'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getReceiptMessage', () => { + it('returns empty string if no data exists on the transaction receipt field', () => { + const transaction = { + ...baseTransactionMock, + receipt: undefined + }; + const result = getReceiptMessage(transaction); + + expect(result).toEqual(''); + }); + + it(`returns a message that contains the refunded gas value if the receipt data field contains ${REFUNDED_GAS}`, () => { + const transaction = { + ...baseTransactionMock, + receipt: { + data: REFUNDED_GAS, + value: '1000', + sender: '' + } + }; + const result = getReceiptMessage(transaction); + const formattedGas = formatAmount({ + input: transaction.receipt.value, + decimals: DECIMALS, + digits: DIGITS, + showLastNonZeroDecimal: true + }); + const gasRefunded = new BigNumber(formattedGas) + .times(transaction.gasPrice) + .times(100); + + expect(result).toEqual(`${transaction.receipt.data}: ${gasRefunded}`); + }); + + it(`returns a message that contains the receipt data field value and the receipt value if the receipt data field does not contains ${REFUNDED_GAS}`, () => { + const transaction = { + ...baseTransactionMock, + receipt: { + data: '@some-data', + value: '1000', + sender: 'sender-hash' + } + }; + const result = getReceiptMessage(transaction); + + expect(result).toEqual( + `${transaction.receipt.data}: ${transaction.receipt.value}` + ); + }); +}); diff --git a/src/utils/transactions/tests/getScResultsMessages.test.ts b/src/utils/transactions/tests/getScResultsMessages.test.ts new file mode 100644 index 0000000..5f3eaf5 --- /dev/null +++ b/src/utils/transactions/tests/getScResultsMessages.test.ts @@ -0,0 +1,46 @@ +import { + ResultType, + ServerTransactionType +} from 'types/serverTransactions.types'; +import { getScResultsMessages } from '../getScResultsMessages'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getScResultsMessages', () => { + it('receive empty array if no results exists on the transaction', () => { + const result = getScResultsMessages(baseTransactionMock); + + expect(result).toEqual([]); + }); + + it('receive an array with all results messages', () => { + const baseTransactionResult = { + callType: '', + value: '1', + gasLimit: 100, + gasPrice: 0.001, + hash: 'tx-hash', + nonce: 0, + sender: 'sender-hash', + originalTxHash: 'original-tx-hash', + prevTxHash: 'prev-tx-hash' + } as ResultType; + + const transaction: ServerTransactionType = { + ...baseTransactionMock, + results: [ + { + ...baseTransactionResult, + returnMessage: 'message 0' + }, + { + ...baseTransactionResult, + returnMessage: 'message 1' + } + ] as ResultType[] + }; + + const result = getScResultsMessages(transaction); + + expect(result).toEqual(['message 0', 'message 1']); + }); +}); diff --git a/src/utils/transactions/tests/getShardText.test.ts b/src/utils/transactions/tests/getShardText.test.ts new file mode 100644 index 0000000..0e041c4 --- /dev/null +++ b/src/utils/transactions/tests/getShardText.test.ts @@ -0,0 +1,13 @@ +import { getShardText } from '../getShardText'; + +describe('getShardText tests', () => { + it('formats metachain', () => { + expect(getShardText(4294967295)).toBe('Metachain'); + }); + it('formats Shard 1', () => { + expect(getShardText(1)).toBe('Shard 1'); + }); + it('formats Shard 2', () => { + expect(getShardText('Shard 2')).toBe('Shard 2'); + }); +}); diff --git a/src/utils/transactions/tests/getTokenFromData.test.ts b/src/utils/transactions/tests/getTokenFromData.test.ts new file mode 100644 index 0000000..ca8cce9 --- /dev/null +++ b/src/utils/transactions/tests/getTokenFromData.test.ts @@ -0,0 +1,49 @@ +import { getTokenFromData } from '../getTokenFromData'; + +describe('getTokenFromData tests', () => { + test('get nft test', () => { + const result = getTokenFromData( + 'ESDTNFTTransfer@4d455441524944452d346264313933@4022@a688906bd8b00000@ebfd923cd251f857ed7639e87143ac83f12f423827abc4a0cdde0119c3e37915' + ); + + expect(result).toStrictEqual({ + collection: 'METARIDE-4bd193', + tokenId: 'METARIDE-4bd193-4022', + nonce: '4022', + amount: '12000000000000000000', + receiver: 'erd1a07ey0xj28u90mtk8858zsavs0cj7s3cy74ufgxdmcq3nslr0y2st2aaax' + }); + }); + test('get token test', () => { + const result = getTokenFromData( + 'ESDTTransfer@5745474c442d383836303061@8ac7230489e80000@73776170546f6b656e734669786564496e707574@555344432d613332393036@480e48f5' + ); + + expect(result).toStrictEqual({ + tokenId: 'WEGLD-88600a', + amount: '10000000000000000000' + }); + }); + test('get multiesdt test', () => { + const result = getTokenFromData( + 'MultiESDTNFTTransfer@00000000000000000500bfa6f00d36d61f232c3c7532fae6b08e3909aac27ceb@02@5745474c442d383836303061@@4657679aa5be59@4d45582d623662623764@@e5eb0b83150fb8ec2b@6164644c6971756964697479@45a354a5e6a567@e39e745b5f173ec0d8' + ); + + expect(result).toStrictEqual({ + tokenId: '', + amount: '' + }); + }); + test('get nft from burn transaction', () => { + const result = getTokenFromData( + 'ESDTNFTBurn@4554484f532d643735383863@015a@01' + ); + + expect(result).toStrictEqual({ + collection: 'ETHOS-d7588c', + tokenId: 'ETHOS-d7588c-015a', + nonce: '015a', + amount: '1' + }); + }); +}); diff --git a/src/utils/transactions/tests/getTransactionMethod.test.ts b/src/utils/transactions/tests/getTransactionMethod.test.ts new file mode 100644 index 0000000..541e5ce --- /dev/null +++ b/src/utils/transactions/tests/getTransactionMethod.test.ts @@ -0,0 +1,65 @@ +import { + ServerTransactionType, + TransactionActionCategoryEnum, + TransactionActionsEnum +} from 'types/serverTransactions.types'; +import { getTransactionMethod } from '../getTransactionMethod'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getTransactionMethod', () => { + it('returns default value "Transaction" in case of missing "action" field', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: undefined + }; + + const result = getTransactionMethod(transaction); + + expect(result).toEqual('Transaction'); + }); + + it(`returns default value "Transaction" when the transaction is a "${TransactionActionsEnum.transfer}" and the action's category is "${TransactionActionCategoryEnum.esdtNft}"`, () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: { + category: TransactionActionCategoryEnum.esdtNft, + name: TransactionActionsEnum.transfer + } + }; + + const result = getTransactionMethod(transaction); + + expect(result).toEqual('Transaction'); + }); + + it(`returns the transaction method read from the action field when the transaction is not a "${TransactionActionsEnum.transfer}" or the action's category is not "${TransactionActionCategoryEnum.esdtNft}"`, () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: { + category: TransactionActionCategoryEnum.scCall, + name: TransactionActionsEnum.claimRewards + } + }; + + const result = getTransactionMethod(transaction); + + expect(result).toEqual(transaction.action?.name); + }); + + it('overrides the transaction method when there is a transaction method defined on the action arguments', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: { + category: TransactionActionCategoryEnum.scCall, + name: TransactionActionsEnum.claimRewards, + arguments: { + functionName: 'customFunction' + } + } + }; + + const result = getTransactionMethod(transaction); + + expect(result).toEqual(transaction.action?.arguments?.functionName); + }); +}); diff --git a/src/utils/transactions/tests/getTransactionReceiver.test.ts b/src/utils/transactions/tests/getTransactionReceiver.test.ts new file mode 100644 index 0000000..60de128 --- /dev/null +++ b/src/utils/transactions/tests/getTransactionReceiver.test.ts @@ -0,0 +1,37 @@ +import { + ServerTransactionType, + TransactionActionCategoryEnum, + TransactionActionsEnum +} from 'types/serverTransactions.types'; +import { getTransactionReceiver } from '../getTransactionReceiver'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getTransactionReceiver', () => { + it('returns receiver address from transaction body', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + receiver: 'receiver-hash' + }; + + const result = getTransactionReceiver(transaction); + + expect(result).toEqual(transaction.receiver); + }); + + it('returns receiver address from the transaction action arguments if exists', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: { + category: TransactionActionCategoryEnum.esdtNft, + name: TransactionActionsEnum.transfer, + arguments: { + receiver: 'receiver-hash' + } + } + }; + + const result = getTransactionReceiver(transaction); + + expect(result).toEqual(transaction.action?.arguments?.receiver); + }); +}); diff --git a/src/utils/transactions/tests/getTransactionReceiverAssets.test.ts b/src/utils/transactions/tests/getTransactionReceiverAssets.test.ts new file mode 100644 index 0000000..148027d --- /dev/null +++ b/src/utils/transactions/tests/getTransactionReceiverAssets.test.ts @@ -0,0 +1,52 @@ +import { + ServerTransactionType, + TransactionActionCategoryEnum, + TransactionActionsEnum +} from 'types/serverTransactions.types'; +import { getTransactionReceiverAssets } from '../getTransactionReceiverAssets'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getTransactionReceiverAssets', () => { + it('returns receiver assets', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + receiver: 'receiver-hash', + receiverAssets: { + name: 'john doe', + description: 'description', + iconPng: 'icon.png', + iconSvg: 'icon.svg', + tags: ['@tag1', '@tag2'] + } + }; + + const result = getTransactionReceiverAssets(transaction); + + expect(result).toBe(transaction.receiverAssets); + }); + + it('returns "undefined" when the transaction receiver does not match the receiver address from the transaction action arguments', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + receiver: 'receiver-hash', + receiverAssets: { + name: 'john doe', + description: 'description', + iconPng: 'icon.png', + iconSvg: 'icon.svg', + tags: ['@tag1', '@tag2'] + }, + action: { + name: TransactionActionsEnum.transfer, + category: TransactionActionCategoryEnum.scCall, + arguments: { + receiver: 'receiver-hash-from-action-arguments' + } + } + }; + + const result = getTransactionReceiverAssets(transaction); + + expect(result).toBeUndefined(); + }); +}); diff --git a/src/utils/transactions/tests/getTransactionTokens.test.ts b/src/utils/transactions/tests/getTransactionTokens.test.ts new file mode 100644 index 0000000..cdbce40 --- /dev/null +++ b/src/utils/transactions/tests/getTransactionTokens.test.ts @@ -0,0 +1,59 @@ +import { + ServerTransactionType, + TransactionActionCategoryEnum, + TransactionActionsEnum +} from 'types/serverTransactions.types'; +import { getTransactionTokens } from '../getTransactionTokens'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getTransactionTokens', () => { + it('returns empty array when the transaction action details are missing', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: undefined + }; + + const result = getTransactionTokens(transaction); + + expect(result).toEqual([]); + }); + + it('returns an array with all existing tokens in the action arguments', () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + action: { + name: TransactionActionsEnum.swap, + category: TransactionActionCategoryEnum.mex, + description: 'Swap 1 WEGLD for a minimum of 45.117988 USDC', + arguments: { + transfers: [ + { + type: 'FungibleESDT', + name: 'WrappedEGLD', + ticker: 'WEGLD', + svgUrl: + 'https://devnet-media.multiversx.com/tokens/asset/WEGLD-d7c6bb/logo.svg', + token: 'WEGLD-d7c6bb', + decimals: 18, + value: '1000000000000000000' + }, + { + type: 'FungibleESDT', + name: 'WrappedUSDC', + ticker: 'USDC', + svgUrl: + 'https://devnet-media.multiversx.com/tokens/asset/USDC-8d4068/logo.svg', + token: 'USDC-8d4068', + decimals: 6, + value: '45117988' + } + ] + } + } + }; + + const result = getTransactionTokens(transaction); + + expect(result).toEqual(transaction.action?.arguments?.transfers); + }); +}); diff --git a/src/utils/transactions/tests/getTransactionTransferType.test.ts b/src/utils/transactions/tests/getTransactionTransferType.test.ts new file mode 100644 index 0000000..e4ccc26 --- /dev/null +++ b/src/utils/transactions/tests/getTransactionTransferType.test.ts @@ -0,0 +1,67 @@ +import { TransactionDirectionEnum } from 'types/serverTransactions.types'; +import { + ServerTransactionType, + TransferTypeEnum +} from 'types/serverTransactions.types'; +import { getTransactionTransferType } from '../getTransactionTransferType'; +import { baseTransactionMock } from './base-transaction-mock'; + +describe('getTransactionTransferType', () => { + it(`returns "${TransactionDirectionEnum.INTERNAL}" when the transaction type is "${TransferTypeEnum.SmartContractResult}" `, () => { + const transaction: ServerTransactionType = { + ...baseTransactionMock, + type: TransferTypeEnum.SmartContractResult + }; + + const result = getTransactionTransferType( + 'address-hash', + transaction, + 'receiver-hash' + ); + + expect(result).toEqual(TransactionDirectionEnum.INTERNAL); + }); + + it(`returns "${TransactionDirectionEnum.SELF}" for self transfers`, () => { + const sender = 'my-address-hash'; + + const transaction: ServerTransactionType = { + ...baseTransactionMock, + sender + }; + + const result = getTransactionTransferType(sender, transaction, sender); + + expect(result).toEqual(TransactionDirectionEnum.SELF); + }); + + it(`returns "${TransactionDirectionEnum.IN}" when receive something from an address`, () => { + const receiver = 'my-address-hash'; + + const transaction: ServerTransactionType = { + ...baseTransactionMock, + receiver + }; + + const result = getTransactionTransferType(receiver, transaction, receiver); + + expect(result).toEqual(TransactionDirectionEnum.IN); + }); + + it(`returns "${TransactionDirectionEnum.OUT}" for when transfer something to an address`, () => { + const sender = 'my-address-hash'; + + const transaction: ServerTransactionType = { + ...baseTransactionMock, + sender + }; + + const result = getTransactionTransferType( + sender, + transaction, + 'receiver-hash' + ); + + expect(result).toEqual(TransactionDirectionEnum.OUT); + }); +}); diff --git a/src/utils/validation/isContract.ts b/src/utils/validation/isContract.ts index a3a5b06..087acbf 100644 --- a/src/utils/validation/isContract.ts +++ b/src/utils/validation/isContract.ts @@ -1,7 +1,7 @@ import { Address, TransactionPayload } from '@multiversx/sdk-core'; import { ESDTTransferTypesEnum, TypesOfSmartContractCallsEnum } from 'types'; -import { addressIsValid } from './addressIsValid'; import { isStringBase64 } from 'utils/decoders/base64Utils'; +import { addressIsValid } from './addressIsValid'; export function isContract( receiver: string, diff --git a/src/utils/validation/stringIsFloat.ts b/src/utils/validation/stringIsFloat.ts index f95e875..c752883 100755 --- a/src/utils/validation/stringIsFloat.ts +++ b/src/utils/validation/stringIsFloat.ts @@ -12,7 +12,6 @@ export const stringIsFloat = (amount: string) => { return false; } - // eslint-disable-next-line let [wholes, decimals] = amount.split('.'); if (decimals) { while (decimals.charAt(decimals.length - 1) === ZERO) { diff --git a/src/utils/validation/tests/stringIsFloat.test.ts b/src/utils/validation/tests/stringIsFloat.test.ts index 7b6f511..415a326 100644 --- a/src/utils/validation/tests/stringIsFloat.test.ts +++ b/src/utils/validation/tests/stringIsFloat.test.ts @@ -51,7 +51,7 @@ describe('stringIsFloat tests', () => { it('denies NaN', () => { expect(stringIsFloat(NaN as any)).toBe(false); }); - it('denies caret separation', () => { + it('also denies caret separation', () => { expect(stringIsFloat(Infinity as any)).toBe(false); }); }); diff --git a/src/utils/window/getDefaultCallbackUrl.ts b/src/utils/window/getDefaultCallbackUrl.ts deleted file mode 100644 index d5e149b..0000000 --- a/src/utils/window/getDefaultCallbackUrl.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getWindowLocation } from './index'; - -export const getDefaultCallbackUrl = () => { - const { pathname, search, hash } = getWindowLocation(); - - return `${pathname ?? ''}${search ?? ''}${hash ?? ''}`; -}; diff --git a/src/utils/window/index.ts b/src/utils/window/index.ts index 698dd2e..2fcc985 100644 --- a/src/utils/window/index.ts +++ b/src/utils/window/index.ts @@ -1,4 +1,3 @@ -export * from './getDefaultCallbackUrl'; export * from './getWindowLocation'; export * from './isWindowAvailable'; export * from './sanitizeCallbackUrl'; diff --git a/src/utils/window/matchPath.ts b/src/utils/window/matchPath.ts index 33641c0..65cae02 100644 --- a/src/utils/window/matchPath.ts +++ b/src/utils/window/matchPath.ts @@ -3,8 +3,9 @@ function warning(cond: any, message: string): void { if (!cond) { - // eslint-disable-next-line no-console - if (typeof console !== 'undefined') console.warn(message); + if (typeof console !== 'undefined') { + console.warn(message); + } try { // Welcome to debugging React Router! @@ -13,8 +14,8 @@ function warning(cond: any, message: string): void { // find the source for a warning that appears in the console by // enabling "pause on exceptions" in your JavaScript debugger. throw new Error(message); - // eslint-disable-next-line no-empty - } catch (e) {} + // eslint-disable-next-line no-empty, @typescript-eslint/no-unused-vars + } catch (error) {} } } @@ -22,7 +23,7 @@ type ParamParseFailed = { failed: true }; type ParamParseSegment = // Check here if there exists a forward slash in the string. - // eslint-disable-next-line prettier/prettier + Segment extends `${infer LeftSegment}/${infer RightSegment}` ? // If there is a forward slash, then attempt to parse each side of the // forward slash. @@ -37,25 +38,25 @@ type ParamParseSegment = ? LeftResult | RightResult : LeftResult : // If the left side is not successfully parsed as a param, then check - // if only the right side can be successfully parse as a param. If it - // can, then the result is just right, else it's a failure. - RightResult extends string - ? RightResult - : ParamParseFailed + // if only the right side can be successfully parse as a param. If it + // can, then the result is just right, else it's a failure. + RightResult extends string + ? RightResult + : ParamParseFailed : ParamParseFailed : // If the left side didn't parse into a param, then just check the right - // side. - ParamParseSegment extends infer RightResult - ? RightResult extends string - ? RightResult + // side. + ParamParseSegment extends infer RightResult + ? RightResult extends string + ? RightResult + : ParamParseFailed : ParamParseFailed - : ParamParseFailed : // If there's no forward slash, then check if this segment starts with a - // colon. If it does, then this is a dynamic segment, so the result is - // just the remainder of the string. Otherwise, it's a failure. - Segment extends `:${infer Remaining}` - ? Remaining - : ParamParseFailed; + // colon. If it does, then this is a dynamic segment, so the result is + // just the remainder of the string. Otherwise, it's a failure. + Segment extends `:${infer Remaining}` + ? Remaining + : ParamParseFailed; // Attempt to parse the given string segment. If it fails, then just return the // plain string type as a default fallback. Otherwise return the union of the @@ -69,7 +70,7 @@ type ParamParseKey = * The parameters that were parsed from the URL path. */ type Params = { - readonly [key in Key]: string | undefined; + readonly [_key in Key]: string | undefined; }; /** @@ -143,7 +144,9 @@ export function matchPath< ); const match = pathname.match(matcher); - if (!match) return null; + if (!match) { + return null; + } const matchedPathname = match[0]; let pathnameBase = matchedPathname.replace(/(.)\/+$/, '$1'); diff --git a/src/utils/window/tests/getDefaultCallbackUrl.test.ts b/src/utils/window/tests/getDefaultCallbackUrl.test.ts deleted file mode 100644 index d6f78ed..0000000 --- a/src/utils/window/tests/getDefaultCallbackUrl.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { getDefaultCallbackUrl } from '../getDefaultCallbackUrl'; - -const searchMock = '?search=mock'; -const pathnameMock = '/unlock'; -const originMock = 'https://multiversx.com'; -const hashMock = '#main'; -const hrefMock = 'https://multiversx.com/technology'; -const urlMock = '/unlock?search=mock#main'; - -let windowSpy: jest.SpyInstance; - -beforeEach(() => { - windowSpy = jest.spyOn(window, 'window', 'get'); -}); -afterEach(() => { - windowSpy.mockRestore(); -}); - -describe('Get window location', () => { - it('getDefaultCallbackUrl should be undefined', () => { - windowSpy.mockImplementation(() => undefined); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(''); - }); - - it('window should return search', () => { - windowSpy.mockImplementation(() => ({ - location: { - search: searchMock - } - })); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(searchMock); - }); - - it('getDefaultCallbackUrl should return pathname', () => { - windowSpy.mockImplementation(() => ({ - location: { - pathname: pathnameMock - } - })); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(pathnameMock); - }); - - it('getDefaultCallbackUrl should return empty string when only origin is specified', () => { - windowSpy.mockImplementation(() => ({ - location: { - origin: originMock - } - })); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(''); - }); - - it('getDefaultCallbackUrl should return hash', () => { - windowSpy.mockImplementation(() => ({ - location: { - hash: hashMock - } - })); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(hashMock); - }); - - it('getDefaultCallbackUrl should return empty', () => { - windowSpy.mockImplementation(() => ({ - location: { - href: hrefMock - } - })); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(''); - }); - - it('getDefaultCallbackUrl should return complete URL without origin', () => { - windowSpy.mockImplementation(() => ({ - location: { - pathname: pathnameMock, - origin: originMock, - hash: hashMock, - href: hrefMock, - search: searchMock - } - })); - - const callbackUrl = getDefaultCallbackUrl(); - expect(callbackUrl).toStrictEqual(urlMock); - }); -}); diff --git a/yarn.lock b/yarn.lock index 2b70c98..cf20e83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,159 +10,114 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== dependencies: - "@babel/highlight" "^7.24.7" + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/compat-data@^7.24.8": - version "7.24.9" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.9.tgz#53eee4e68f1c1d0282aa0eb05ddb02d033fc43a0" - integrity sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng== +"@babel/compat-data@^7.25.9": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" + integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.9.tgz#dc07c9d307162c97fa9484ea997ade65841c7c82" - integrity sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg== + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.9" - "@babel/helper-compilation-targets" "^7.24.8" - "@babel/helper-module-transforms" "^7.24.9" - "@babel/helpers" "^7.24.8" - "@babel/parser" "^7.24.8" - "@babel/template" "^7.24.7" - "@babel/traverse" "^7.24.8" - "@babel/types" "^7.24.9" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.8", "@babel/generator@^7.24.9", "@babel/generator@^7.7.2": - version "7.24.10" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.10.tgz#a4ab681ec2a78bbb9ba22a3941195e28a81d8e76" - integrity sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg== +"@babel/generator@^7.26.0", "@babel/generator@^7.26.3", "@babel/generator@^7.7.2": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019" + integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ== dependencies: - "@babel/types" "^7.24.9" + "@babel/parser" "^7.26.3" + "@babel/types" "^7.26.3" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" + jsesc "^3.0.2" -"@babel/helper-compilation-targets@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz#b607c3161cd9d1744977d4f97139572fe778c271" - integrity sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw== +"@babel/helper-compilation-targets@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" + integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== dependencies: - "@babel/compat-data" "^7.24.8" - "@babel/helper-validator-option" "^7.24.8" - browserslist "^4.23.1" + "@babel/compat-data" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" - integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-function-name@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" - integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== - dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-hoist-variables@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" - integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-module-imports@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-module-transforms@^7.24.9": - version "7.24.9" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz#e13d26306b89eea569180868e652e7f514de9d29" - integrity sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw== - dependencies: - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-simple-access" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" - -"@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.24.7", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" - integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== - -"@babel/helper-simple-access@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" - integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/helper-split-export-declaration@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" - integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== - dependencies: - "@babel/types" "^7.24.7" - -"@babel/helper-string-parser@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" - integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== - -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== - -"@babel/helper-validator-option@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" - integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== - -"@babel/helpers@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.8.tgz#2820d64d5d6686cca8789dd15b074cd862795873" - integrity sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ== - dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.8" - -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== - dependencies: - "@babel/helper-validator-identifier" "^7.24.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@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.25.9", "@babel/helper-plugin-utils@^7.8.0": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46" + integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw== + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.7", "@babel/parser@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.8.tgz#58a4dbbcad7eb1d48930524a3fd93d93e9084c6f" - integrity sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" + integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA== + dependencies: + "@babel/types" "^7.26.3" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -178,14 +133,28 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7" + integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -200,13 +169,13 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" - integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" + integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -220,7 +189,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -248,7 +217,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== @@ -256,182 +232,194 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c" - integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA== - dependencies: - "@babel/helper-plugin-utils" "^7.24.7" - -"@babel/template@^7.24.7", "@babel/template@^7.3.3": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" - integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.8.tgz#6c14ed5232b7549df3371d820fbd9abfcd7dfab7" - integrity sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.8" - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-function-name" "^7.24.7" - "@babel/helper-hoist-variables" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/parser" "^7.24.8" - "@babel/types" "^7.24.8" + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/template@^7.25.9", "@babel/template@^7.3.3": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/traverse@^7.25.9": + version "7.26.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd" + integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.3" + "@babel/parser" "^7.26.3" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.3" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.24.9", "@babel/types@^7.3.3": - version "7.24.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.9.tgz#228ce953d7b0d16646e755acf204f4cf3d08cc73" - integrity sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3", "@babel/types@^7.3.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0" + integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA== dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@esbuild/aix-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" - integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== - -"@esbuild/android-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" - integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== - -"@esbuild/android-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" - integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== - -"@esbuild/android-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" - integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== - -"@esbuild/darwin-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== - -"@esbuild/darwin-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" - integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== - -"@esbuild/freebsd-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" - integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== - -"@esbuild/freebsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" - integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== - -"@esbuild/linux-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" - integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== - -"@esbuild/linux-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" - integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== - -"@esbuild/linux-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" - integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== - -"@esbuild/linux-loong64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" - integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== - -"@esbuild/linux-mips64el@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" - integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== - -"@esbuild/linux-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" - integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== - -"@esbuild/linux-riscv64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" - integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== - -"@esbuild/linux-s390x@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" - integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== - -"@esbuild/linux-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" - integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== - -"@esbuild/netbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" - integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== - -"@esbuild/openbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" - integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== - -"@esbuild/sunos-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" - integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== - -"@esbuild/win32-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" - integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== - -"@esbuild/win32-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" - integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== - -"@esbuild/win32-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" - integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== +"@esbuild/aix-ppc64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.1.tgz#044268dc9ca4dc67f8d4aad8f51cfb894bfd7114" + integrity sha512-O7yppwipkXvnEPjzkSXJRk2g4bS8sUx9p9oXHq9MU/U7lxUzZVsnFZMDTmeeX9bfQxrFcvOacl/ENgOh0WP9pA== + +"@esbuild/android-arm64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.1.tgz#76aacd934449e541f05b66d5ec8cbff96ec2ae81" + integrity sha512-jXhccq6es+onw7x8MxoFnm820mz7sGa9J14kLADclmiEUH4fyj+FjR6t0M93RgtlI/awHWhtF0Wgfhqgf9gDZA== + +"@esbuild/android-arm@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.1.tgz#8247c5aef933a212bca261290f6e43a9dca07cc5" + integrity sha512-hh3jKWikdnTtHCglDAeVO3Oyh8MaH8xZUaWMiCCvJ9/c3NtPqZq+CACOlGTxhddypXhl+8B45SeceYBfB/e8Ow== + +"@esbuild/android-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.1.tgz#80cbfa35412299edefbc4ab78064f0b66e448008" + integrity sha512-NPObtlBh4jQHE01gJeucqEhdoD/4ya2owSIS8lZYS58aR0x7oZo9lB2lVFxgTANSa5MGCBeoQtr+yA9oKCGPvA== + +"@esbuild/darwin-arm64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.1.tgz#154167fb9e54017dac4b343f8e5e25c9d9324036" + integrity sha512-BLT7TDzqsVlQRmJfO/FirzKlzmDpBWwmCUlyggfzUwg1cAxVxeA4O6b1XkMInlxISdfPAOunV9zXjvh5x99Heg== + +"@esbuild/darwin-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.1.tgz#db971502c9fa204906b89e489810c902bf6d9afb" + integrity sha512-D3h3wBQmeS/vp93O4B+SWsXB8HvRDwMyhTNhBd8yMbh5wN/2pPWRW5o/hM3EKgk9bdKd9594lMGoTCTiglQGRQ== + +"@esbuild/freebsd-arm64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.1.tgz#f0f3bc20c23af999bd696099a324dceb66d77761" + integrity sha512-/uVdqqpNKXIxT6TyS/oSK4XE4xWOqp6fh4B5tgAwozkyWdylcX+W4YF2v6SKsL4wCQ5h1bnaSNjWPXG/2hp8AQ== + +"@esbuild/freebsd-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.1.tgz#d36af9085edb34244b41e5a57640e6b4452cbec2" + integrity sha512-paAkKN1n1jJitw+dAoR27TdCzxRl1FOEITx3h201R6NoXUojpMzgMLdkXVgCvaCSCqwYkeGLoe9UVNRDKSvQgw== + +"@esbuild/linux-arm64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.1.tgz#9d2ad42eea33b2a9571f13e7ecc39ee9d3ff0c6d" + integrity sha512-G65d08YoH00TL7Xg4LaL3gLV21bpoAhQ+r31NUu013YB7KK0fyXIt05VbsJtpqh/6wWxoLJZOvQHYnodRrnbUQ== + +"@esbuild/linux-arm@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.1.tgz#d6f7c5873479dd97148bef3e3a7f09d486642883" + integrity sha512-tRHnxWJnvNnDpNVnsyDhr1DIQZUfCXlHSCDohbXFqmg9W4kKR7g8LmA3kzcwbuxbRMKeit8ladnCabU5f2traA== + +"@esbuild/linux-ia32@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.1.tgz#8f2aef34a31c8d16dbce0b8679021f4881f38efe" + integrity sha512-tt/54LqNNAqCz++QhxoqB9+XqdsaZOtFD/srEhHYwBd3ZUOepmR1Eeot8bS+Q7BiEvy9vvKbtpHf+r6q8hF5UA== + +"@esbuild/linux-loong64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.1.tgz#44461ea2388efbafa6cf12b2bc1407a5388da066" + integrity sha512-MhNalK6r0nZD0q8VzUBPwheHzXPr9wronqmZrewLfP7ui9Fv1tdPmg6e7A8lmg0ziQCziSDHxh3cyRt4YMhGnQ== + +"@esbuild/linux-mips64el@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.1.tgz#754d533a4fef4b0790d82bfe1e82d6876f18370e" + integrity sha512-YCKVY7Zen5rwZV+nZczOhFmHaeIxR4Zn3jcmNH53LbgF6IKRwmrMywqDrg4SiSNApEefkAbPSIzN39FC8VsxPg== + +"@esbuild/linux-ppc64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.1.tgz#2aafcfe2826c7d5d2e3c41eb8934e6368a7cada5" + integrity sha512-bw7bcQ+270IOzDV4mcsKAnDtAFqKO0jVv3IgRSd8iM0ac3L8amvCrujRVt1ajBTJcpDaFhIX+lCNRKteoDSLig== + +"@esbuild/linux-riscv64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.1.tgz#481ceaf5939d14fb25da62a385b5e6c2096a3370" + integrity sha512-ARmDRNkcOGOm1AqUBSwRVDfDeD9hGYRfkudP2QdoonBz1ucWVnfBPfy7H4JPI14eYtZruRSczJxyu7SRYDVOcg== + +"@esbuild/linux-s390x@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.1.tgz#e25b97005e4c82540d1bc7af88e333fb55142570" + integrity sha512-o73TcUNMuoTZlhwFdsgr8SfQtmMV58sbgq6gQq9G1xUiYnHMTmJbwq65RzMx89l0iya69lR4bxBgtWiiOyDQZA== + +"@esbuild/linux-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.1.tgz#a05a61d0a0cbb03baa6db12cd8164c1e5265ffb2" + integrity sha512-da4/1mBJwwgJkbj4fMH7SOXq2zapgTo0LKXX1VUZ0Dxr+e8N0WbS80nSZ5+zf3lvpf8qxrkZdqkOqFfm57gXwA== + +"@esbuild/netbsd-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.1.tgz#e298f854e8999563f2e4668bd542678c46be4b53" + integrity sha512-CPWs0HTFe5woTJN5eKPvgraUoRHrCtzlYIAv9wBC+FAyagBSaf+UdZrjwYyTGnwPGkThV4OCI7XibZOnPvONVw== + +"@esbuild/openbsd-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.1.tgz#640d34de1e3c6bc3ff64e0379aae00ede3608f14" + integrity sha512-xxhTm5QtzNLc24R0hEkcH+zCx/o49AsdFZ0Cy5zSd/5tOj4X2g3/2AJB625NoadUuc4A8B3TenLJoYdWYOYCew== + +"@esbuild/sunos-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.1.tgz#f53cb1cdcbf05b3320e147ddb85ec2b1cf2b6cfc" + integrity sha512-CWibXszpWys1pYmbr9UiKAkX6x+Sxw8HWtw1dRESK1dLW5fFJ6rMDVw0o8MbadusvVQx1a8xuOxnHXT941Hp1A== + +"@esbuild/win32-arm64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.1.tgz#df4f44f9b4fec9598c0ec2c34fec9c568c8ab85d" + integrity sha512-jb5B4k+xkytGbGUS4T+Z89cQJ9DJ4lozGRSV+hhfmCPpfJ3880O31Q1srPCimm+V6UCbnigqD10EgDNgjvjerQ== + +"@esbuild/win32-ia32@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.1.tgz#a57edbd9905db9f957327ae0facfbf406a80a4e4" + integrity sha512-PgyFvjJhXqHn1uxPhyN1wZ6dIomKjiLUQh1LjFvjiV1JmnkZ/oMPrfeEAZg5R/1ftz4LZWZr02kefNIQ5SKREQ== + +"@esbuild/win32-x64@0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.1.tgz#eb86553d90e86a8c174b96650fdb4c60f2de16a7" + integrity sha512-W9NttRZQR5ehAiqHGDnvfDaGmQOm6Fi4vSlce8mjM75x//XKuVAByohlEX6N17yZnVXxQFuh4fDRunP8ca6bfA== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== dependencies: - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" - integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@eslint/eslintrc@^3.0.2": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" - integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== +"@eslint/config-array@^0.19.0": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.1.tgz#734aaea2c40be22bbb1f2a9dac687c57a6a4c984" + integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA== + dependencies: + "@eslint/object-schema" "^2.1.5" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.9.0": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.1.tgz#31763847308ef6b7084a4505573ac9402c51f9d1" + integrity sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -443,10 +431,22 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.1.1.tgz#eb0f82461d12779bbafc1b5045cde3143d350a8a" - integrity sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ== +"@eslint/js@9.15.0": + version "9.15.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.15.0.tgz#df0e24fe869143b59731942128c19938fdbadfb5" + integrity sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg== + +"@eslint/object-schema@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.5.tgz#8670a8f6258a2be5b2c620ff314a1d984c23eb2e" + integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ== + +"@eslint/plugin-kit@^0.2.3": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz#2b78e7bb3755784bb13faa8932a1d994d6537792" + integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg== + dependencies: + levn "^0.4.1" "@ethereumjs/common@^3.2.0": version "3.2.0" @@ -480,29 +480,52 @@ ethereum-cryptography "^2.0.0" micro-ftch "^0.3.1" -"@humanwhocodes/config-array@^0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" - integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== +"@fortawesome/fontawesome-common-types@6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz#7123d74b0c1e726794aed1184795dbce12186470" + integrity sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg== + +"@fortawesome/fontawesome-svg-core@>= 6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz#0ac6013724d5cc327c1eb81335b91300a4fce2f2" + integrity sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA== dependencies: - "@humanwhocodes/object-schema" "^2.0.3" - debug "^4.3.1" - minimatch "^3.0.5" + "@fortawesome/fontawesome-common-types" "6.7.2" + +"@fortawesome/free-solid-svg-icons@>= 6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz#fe25883b5eb8464a82918599950d283c465b57f6" + integrity sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA== + dependencies: + "@fortawesome/fontawesome-common-types" "6.7.2" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== -"@humanwhocodes/retry@^0.2.3": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.2.4.tgz#4f3059423823bd8176132ceea9447dee101dfac1" - integrity sha512-Ttl/jHpxfS3st5sxwICYfk4pOH0WrLI1SpW283GgQL7sCWU7EHIOhX4b4fkIxr3tkfzwg8+FNojtzsIEE7Ecgg== +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -732,9 +755,9 @@ chalk "^4.0.0" "@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== dependencies: "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" @@ -773,12 +796,12 @@ rxjs "6" semver "^7.3.5" -"@ledgerhq/devices@^8.0.3", "@ledgerhq/devices@^8.0.5", "@ledgerhq/devices@^8.4.1": - version "8.4.1" - resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.4.1.tgz#ab47c188ef9156f6b81c37c4ef2f2aeec97c19bf" - integrity sha512-Mbjzqlcj4Q2StxEmaYEb5wv6sK5Sk26L4xs0BC9io/AyvpXNTDAp67tryB/klNcvd+WwZPcPdYYvlNzfQ0WTUA== +"@ledgerhq/devices@^8.0.7", "@ledgerhq/devices@^8.3.0", "@ledgerhq/devices@^8.4.4": + version "8.4.4" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.4.4.tgz#0d195c1650fe57da2fad7f0d9074a0190947cd6f" + integrity sha512-sz/ryhe/R687RHtevIE9RlKaV8kkKykUV4k29e7GAVwzHX1gqG+O75cu1NCJUHLbp3eABV5FdvZejqRUlLis9A== dependencies: - "@ledgerhq/errors" "^6.18.0" + "@ledgerhq/errors" "^6.19.1" "@ledgerhq/logs" "^6.12.0" rxjs "^7.8.1" semver "^7.3.5" @@ -788,58 +811,58 @@ 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.13.0", "@ledgerhq/errors@^6.18.0": - version "6.18.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.18.0.tgz#d55d6a57430d7a86532a9033ce0b45103264c620" - integrity sha512-L3jQWAGyooxRDk/MRlW2v4Ji9+kloBtdmz9wBkHaj2j0n+05rweJSV3GHw9oye1BYMbVFqFffmT4H3hlXlCasw== +"@ledgerhq/errors@^6.12.6", "@ledgerhq/errors@^6.14.0", "@ledgerhq/errors@^6.16.4", "@ledgerhq/errors@^6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.19.1.tgz#d9ac45ad4ff839e468b8f63766e665537aaede58" + integrity sha512-75yK7Nnit/Gp7gdrJAz0ipp31CCgncRp+evWt6QawQEtQKYEDfGo10QywgrrBBixeRxwnMy1DP6g2oCWRf1bjw== -"@ledgerhq/hw-transport-web-ble@6.27.17": - version "6.27.17" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-web-ble/-/hw-transport-web-ble-6.27.17.tgz#40bdf67dd277863c307399ea42f62e607c88b278" - integrity sha512-OoKbImhgyi43F6PM2KAJfViW+oEmZ3M8Tq9XZ0X57oL6QCQUYv6FakEFFkZzNuNWFdtFKGPgNt6xygqIdNElEQ== +"@ledgerhq/hw-transport-web-ble@6.28.6": + version "6.28.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-web-ble/-/hw-transport-web-ble-6.28.6.tgz#f1f5361983b2f4ead0f716f326b5881809b97066" + integrity sha512-SsseU5T4ePhdvFdwUOsF207gyMgiHyymvRAV66/hpHCd0+m/81kV8nZneeD3Z1pG0XPG+tPlF90r7nLwtUoiXw== dependencies: - "@ledgerhq/devices" "^8.0.5" - "@ledgerhq/errors" "^6.13.0" - "@ledgerhq/hw-transport" "^6.28.6" - "@ledgerhq/logs" "^6.10.1" - rxjs "6" + "@ledgerhq/devices" "^8.3.0" + "@ledgerhq/errors" "^6.16.4" + "@ledgerhq/hw-transport" "^6.30.6" + "@ledgerhq/logs" "^6.12.0" + rxjs "^7.8.1" -"@ledgerhq/hw-transport-webhid@6.27.15": - version "6.27.15" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webhid/-/hw-transport-webhid-6.27.15.tgz#36cbf1fd710dee19f51519668229a5df95b05046" - integrity sha512-xhtFy/SNttvBna8t1ZiP74K6Lj8uDhp0W+Zjvwz4IS6tS9gWZbKUB7scbrNrJep6Q77Of1bzDXrswyaoxFZrUg== +"@ledgerhq/hw-transport-webhid@6.28.6": + version "6.28.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webhid/-/hw-transport-webhid-6.28.6.tgz#94562750136d869774cb56304573a1875ca6375f" + integrity sha512-npU1mgL97KovpTUgcdORoOZ7eVFgwCA7zt0MpgUGUMRNJWDgCFsJslx7KrVXlCGOg87gLfDojreIre502I5pYg== dependencies: - "@ledgerhq/devices" "^8.0.3" - "@ledgerhq/errors" "^6.12.6" - "@ledgerhq/hw-transport" "^6.28.4" - "@ledgerhq/logs" "^6.10.1" + "@ledgerhq/devices" "^8.3.0" + "@ledgerhq/errors" "^6.16.4" + "@ledgerhq/hw-transport" "^6.30.6" + "@ledgerhq/logs" "^6.12.0" -"@ledgerhq/hw-transport-webusb@6.27.15": - version "6.27.15" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-6.27.15.tgz#b661000ca68f21ed1cd4f931f0c9690b217529fc" - integrity sha512-XRteQmJMFbMETOwwwJrXhEvBEdu1DpuDQNI04bzMQE9p81rLjwd6pIhfP/W1O94av7Iq4kaatNsNpxkitmp59w== +"@ledgerhq/hw-transport-webusb@6.28.6": + version "6.28.6" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-6.28.6.tgz#c17c193578da112ef76769e4ce72129d40d87faa" + integrity sha512-rzICsvhcFcL4wSAvRPe+b9EEWB8cxj6yWy3FZdfs7ufi/0muNpFXWckWv1TC34em55sGXu2cMcwMKXg/O/Lc0Q== dependencies: - "@ledgerhq/devices" "^8.0.3" - "@ledgerhq/errors" "^6.12.6" - "@ledgerhq/hw-transport" "^6.28.4" - "@ledgerhq/logs" "^6.10.1" + "@ledgerhq/devices" "^8.3.0" + "@ledgerhq/errors" "^6.16.4" + "@ledgerhq/hw-transport" "^6.30.6" + "@ledgerhq/logs" "^6.12.0" -"@ledgerhq/hw-transport@6.28.4": - version "6.28.4" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.28.4.tgz#c2fc5bff4fca71ac44f069b775d33d0b1b5d9000" - integrity sha512-fB2H92YQjidmae2GFCmOGPwkZWk0lvTu0tlLlzfiY0wRheAG+DEgjnqhdU8wmydkPLIj0WUjRgldtnJtg/a2iQ== +"@ledgerhq/hw-transport@6.28.8": + version "6.28.8" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.28.8.tgz#f99a5c71c5c09591e9bfb1b970c42aafbe81351f" + integrity sha512-XxQVl4htd018u/M66r0iu5nlHi+J6QfdPsORzDF6N39jaz+tMqItb7tUlXM/isggcuS5lc7GJo7NOuJ8rvHZaQ== dependencies: - "@ledgerhq/devices" "^8.0.3" - "@ledgerhq/errors" "^6.12.6" + "@ledgerhq/devices" "^8.0.7" + "@ledgerhq/errors" "^6.14.0" events "^3.3.0" -"@ledgerhq/hw-transport@^6.28.4", "@ledgerhq/hw-transport@^6.28.6": - version "6.31.1" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.1.tgz#fb462c5455fc6c1e8300c216cc52df6f3fb88565" - integrity sha512-0hVcrqUOM7AYV/JEq8yoeBiXLjpWrentgYt8MC3n+iNFfpORU/SUprcbu0s884IHzj+a8mx0JCZp9y7uPSLlzg== +"@ledgerhq/hw-transport@^6.30.6": + version "6.31.4" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.4.tgz#9b23a6de4a4caaa5c24b149c2dea8adde46f0eb1" + integrity sha512-6c1ir/cXWJm5dCWdq55NPgCJ3UuKuuxRvf//Xs36Bq9BwkV2YaRQhZITAkads83l07NAdR16hkTWqqpwFMaI6A== dependencies: - "@ledgerhq/devices" "^8.4.1" - "@ledgerhq/errors" "^6.18.0" + "@ledgerhq/devices" "^8.4.4" + "@ledgerhq/errors" "^6.19.1" "@ledgerhq/logs" "^6.12.0" events "^3.3.0" @@ -875,9 +898,9 @@ readable-stream "^3.6.2" "@metamask/object-multiplex@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-2.0.0.tgz#aa6e4aa7b4e2f457ea4bb51cd7281d931e0aa35d" - integrity sha512-+ItrieVZie3j2LfYE0QkdW3dsEMfMEp419IGx1zyeLqjRZ14iQUPRO0H6CGgfAAoC0x6k2PfCAGRwJUA9BMrqA== + version "2.1.0" + resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz#5e2e908fc46aee581cbba809870eeee0e571cbb6" + integrity sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA== dependencies: once "^1.4.0" readable-stream "^3.6.2" @@ -901,17 +924,17 @@ webextension-polyfill "^0.10.0" "@metamask/rpc-errors@^6.2.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@metamask/rpc-errors/-/rpc-errors-6.3.1.tgz#d5bb4740e070c3d87e91717ff4c3c6061a081cab" - integrity sha512-ugDY7cKjF4/yH5LtBaOIKHw/AiGGSAmzptAUEiAEGr/78LwuzcXAxmzEQfSfMIfI+f9Djr8cttq1pRJJKfTuCg== + version "6.4.0" + resolved "https://registry.yarnpkg.com/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz#a7ce01c06c9a347ab853e55818ac5654a73bd006" + integrity sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg== dependencies: "@metamask/utils" "^9.0.0" fast-safe-stringify "^2.0.6" "@metamask/safe-event-emitter@^3.0.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.1.tgz#e89b840a7af8097a8ed4953d8dc8470d1302d3ef" - integrity sha512-ihb3B0T/wJm1eUuArYP4lCTSEoZsClHhuWyfo/kMX3m/odpqNcPfsz5O2A3NT7dXCAgWPGDQGPqygCpgeniKMw== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz#bfac8c7a1a149b5bbfe98f59fbfea512dfa3bad4" + integrity sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA== "@metamask/superstruct@^3.0.0", "@metamask/superstruct@^3.1.0": version "3.1.0" @@ -934,9 +957,9 @@ uuid "^9.0.1" "@metamask/utils@^9.0.0": - version "9.1.0" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.1.0.tgz#54e5afcec07e6032d4dd4171e862b36daa52d77e" - integrity sha512-g2REf+xSt0OZfMoNNdC4+/Yy8eP3KUqvIArel54XRFKPoXbHI6+YjFfrLtfykWBjffOp7DTfIc3Kvk5TLfuiyg== + version "9.3.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.3.0.tgz#4726bd7f5d6a43ea8425b6d663ab9207f617c2d1" + integrity sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g== dependencies: "@ethereumjs/tx" "^4.2.0" "@metamask/superstruct" "^3.1.0" @@ -970,70 +993,84 @@ strict-event-emitter "^0.2.4" web-encoding "^1.1.5" -"@multiversx/sdk-core@12.18.0": - version "12.18.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-core/-/sdk-core-12.18.0.tgz#ae99665f9afb2bd4f1e325cb7daabb1dbcc55ca6" - integrity sha512-F+xGslPMkkZ0S/Q8UJZsMYl0mgHIuK/GdVsNFPiMKxQsKkxA2LTjNdPxVxjwgvRmN7WfdsTtQvmlsA5O1NYhBg== - dependencies: - "@multiversx/sdk-transaction-decoder" "1.0.2" - bech32 "1.1.4" - bignumber.js "9.0.1" - blake2b "2.1.3" - buffer "6.0.3" - json-duplicate-key-handle "1.0.0" - keccak "3.0.2" - protobufjs "7.2.4" +"@multiversx/sdk-bls-wasm@0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-bls-wasm/-/sdk-bls-wasm-0.3.5.tgz#2e83308fdc7a0928c6d5a7f910d796fd8eb2d90b" + integrity sha512-c0tIdQUnbBLSt6NYU+OpeGPYdL0+GV547HeHT8Xc0BKQ7Cj0v82QUoA2QRtWrR1G4MNZmLsIacZSsf6DrIS2Bw== -"@multiversx/sdk-core@>= 13.0.0": - version "13.2.2" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-core/-/sdk-core-13.2.2.tgz#e98f8ede0c1898e1571ad9a63a92385d8ceb276f" - integrity sha512-ABQuy7PcFBnl5f9yFczgaq7tX72X0M836Ky9h4HRCQd5Mao3OJ3TrgHEvxZe9SVYXtwOm337iPsbkZzVslxu9A== +"@multiversx/sdk-core@>= 13.5.0": + version "13.16.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-core/-/sdk-core-13.16.0.tgz#e996ff30cbc983436dafc06e22050bbe2c61136e" + integrity sha512-+MXIhlgCFRGWiDTegSlLvyClQVJFXgzgNHJL04LALom4ec8eezkPuf8wNzDcBvpR/8Drt2cGGnbPiOo3r4j54A== dependencies: "@multiversx/sdk-transaction-decoder" "1.0.2" + "@noble/ed25519" "1.7.3" + "@noble/hashes" "1.3.0" bech32 "1.1.4" blake2b "2.1.3" buffer "6.0.3" + ed25519-hd-key "1.1.2" + ed2curve "0.3.0" json-bigint "1.0.0" keccak "3.0.2" + scryptsy "2.1.0" + tweetnacl "1.0.3" + uuid "8.3.2" + optionalDependencies: + "@multiversx/sdk-bls-wasm" "0.3.5" + axios "^1.7.4" + bip39 "3.1.0" + +"@multiversx/sdk-dapp-core-ui@0.0.0-alpha.0": + version "0.0.0-alpha.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-core-ui/-/sdk-dapp-core-ui-0.0.0-alpha.0.tgz#b3176c43b8a2b5fd04059e8ce4386e5cc9ce4df1" + integrity sha512-zgz2iYFk92f8P3MKXWU1RAszshdVtQLkPJB1S90y5G35wPS6sYCx8+kZAJWyzgGZWwjP8Ufaho6KNlTKii++lw== + dependencies: + "@fortawesome/fontawesome-svg-core" ">= 6.7.2" + "@fortawesome/free-solid-svg-icons" ">= 6.7.2" + "@multiversx/sdk-dapp-utils" ">= 1.0.2" + bignumber.js ">= 9.1.2" + classnames ">= 2.5.1" + qrcode ">= 1.5.4" + +"@multiversx/sdk-dapp-utils@>= 1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-utils/-/sdk-dapp-utils-1.0.2.tgz#f21e6c9566b4dc5ef535b0549f3f8c1403c4c469" + integrity sha512-TX7rshlcSptT70mmh7lgkw3uyljQgjyDHhah11JKs7Yw9FmYFGCefXhfAcN+VI/n7xZRti/HW0oTU82OqzU3bQ== -"@multiversx/sdk-dapp-utils@>= 0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-utils/-/sdk-dapp-utils-0.1.0.tgz#3103c2ffc648703e75f96acd229af299cb0840ab" - integrity sha512-EFvktZ/S1WQ1ie02nnKZHARC4r23JZWwoTFd5py1qi/Z/UoLHIzJ394HLjXFb6gBTsp4wnvNwIXBA/DNrd2Yeg== - -"@multiversx/sdk-extension-provider@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-extension-provider/-/sdk-extension-provider-3.0.0.tgz#e0e178ee5555f9440457547759621f5c3152c5fa" - integrity sha512-xNHLShzimYbMXqEJoiNyB4fNOXQUwSJCzt9FiOA4GdxucJnCgIM25mXtSj2I93cz+KD39QgRjEYep+li/lykOw== +"@multiversx/sdk-extension-provider@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-extension-provider/-/sdk-extension-provider-4.0.0.tgz#77a7d45bf09ae22e569267270f17ac01c5f97d17" + integrity sha512-zFt4jUS7tu+MlDPou9wmzoW1dcvQuz0nBEYY75ynt82wC7aYjSDhsYh3U4DKtj5TgmyoOSZ31CLJN0wcoNYVaw== -"@multiversx/sdk-hw-provider@6.4.0": - version "6.4.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-hw-provider/-/sdk-hw-provider-6.4.0.tgz#a9afda37a23b2950c8b9a4c1f1ddbf1e513b0fda" - integrity sha512-o+iO64U7gi3oqQHIaCNWoOCarrOQyjXEq7kEsWg/HXJOANpc+lq4GiXPtBkN5mOwPoj/UlEk1HfxA+54mTCFNQ== +"@multiversx/sdk-hw-provider@7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-hw-provider/-/sdk-hw-provider-7.0.0.tgz#dafb239179949e23a75805c7cd386d618b1855cd" + integrity sha512-ZRGp5q985v5wvjnSZw+uvEXKGwe5YORuULhYMVoh63cPtGhyHIxl7H9D190KtSV0/LJfTcVUDDrtKoepOoKuVA== dependencies: "@ledgerhq/devices" "8.0.3" "@ledgerhq/errors" "6.12.6" - "@ledgerhq/hw-transport" "6.28.4" - "@ledgerhq/hw-transport-web-ble" "6.27.17" - "@ledgerhq/hw-transport-webhid" "6.27.15" - "@ledgerhq/hw-transport-webusb" "6.27.15" + "@ledgerhq/hw-transport" "6.28.8" + "@ledgerhq/hw-transport-web-ble" "6.28.6" + "@ledgerhq/hw-transport-webhid" "6.28.6" + "@ledgerhq/hw-transport-webusb" "6.28.6" buffer "6.0.3" platform "1.3.6" -"@multiversx/sdk-metamask-provider@0.0.5": - version "0.0.5" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-metamask-provider/-/sdk-metamask-provider-0.0.5.tgz#9f07ec8b9d1d2b2d88e8a9bccc149f01f144be37" - integrity sha512-IicSD/0G6/ZyU5j1Q6YXcXqILZu54ZjvoN1iunffYCDYeBSt1RZrUUdvBAfzjx47ubvX8Ic0iVbfgykjBCLfCQ== +"@multiversx/sdk-metamask-provider@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-metamask-provider/-/sdk-metamask-provider-1.0.0.tgz#ba3f373d498688209c4dff81732e3c5cc2d219fa" + integrity sha512-5AsaeAQlhgH/nH0fxGlUOzKcjxAlsqZ8JTwKev3mZWKrbugOOukp8rM3a3oUCRO4yTDI8z3VAYb8ELvnNfYM3Q== dependencies: "@metamask/providers" "16.0.0" - "@multiversx/sdk-core" "12.18.0" + protobufjs "7.4.0" "@multiversx/sdk-native-auth-client@^1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-native-auth-client/-/sdk-native-auth-client-1.0.8.tgz#160b34b9ce80595008b1d7fdab75cea6347eb907" - integrity sha512-anXcQplVp3/m2rBH4oGQZNIhk0m/J45SomubNMCgSzepJ2PU5E5eQLYletvSDObhTGfRnNCF8edAldkDP9a4Kw== + version "1.0.9" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-native-auth-client/-/sdk-native-auth-client-1.0.9.tgz#24807976a150602e5c691df138056a88d3910e43" + integrity sha512-q1/cDRKz7QQsr8lQskUsfGkqJbIut772/MBX52Td4OTGg/G1HAm2xsELe+06y7L537A2rqz5/W9KkJ5yWt968g== dependencies: - axios "^1.6.8" + axios "^1.7.4" "@multiversx/sdk-opera-provider@1.0.0-alpha.1": version "1.0.0-alpha.1" @@ -1047,19 +1084,44 @@ dependencies: bech32 "^2.0.0" -"@multiversx/sdk-wallet-connect-provider@4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet-connect-provider/-/sdk-wallet-connect-provider-4.1.2.tgz#db8472c334507fcf4191227a170177d1404be1ce" - integrity sha512-zdJna8ZNhEtNQYL4xjoPDbsKlAaruvLdAKVn6sxyyd90ME1+5T5Owp5ITMZdihOLPaGjmvjRKNgy777iADyqTQ== +"@multiversx/sdk-wallet-connect-provider@5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet-connect-provider/-/sdk-wallet-connect-provider-5.0.1.tgz#105ff6dd58697e72bd56ccc1d5ff9259ec5075a0" + integrity sha512-mid+3vT/b7JludK3HQSD/leeQv0n6Vd4oApRMbzzgsY2kE2a+5Y1YUGlT1EtoRYJnscT8Ss7TSp7Wgs/K5PJCA== dependencies: - "@walletconnect/sign-client" "2.12.2" - "@walletconnect/utils" "2.12.2" + "@walletconnect/sign-client" "2.17.0" + "@walletconnect/utils" "2.17.0" bech32 "1.1.4" -"@multiversx/sdk-web-wallet-cross-window-provider@>= 1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-1.0.0.tgz#14ea0eb110de78a7e5dfbb1cb237cc8f86006b40" - integrity sha512-xqdKCFpBCxNcp4aSwC2FLbks2Ii2uy5YpHnqR8qnqCnjH6TqdGZ1xKzQauZsiYqseVueVTmynK28w9pTOZ0Oqg== +"@multiversx/sdk-wallet@4.5.1": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet/-/sdk-wallet-4.5.1.tgz#e4ffd218645c870c466bc0a7ef9bf68a4737ceb5" + integrity sha512-rvaMUV6OxNj9gchOn7wSCPZcWc6hjs1nQuY6QwnaEcBfPsHtFemNNt+t3uxPZOrDhAwXqUgyy9WdltvOs8somg== + dependencies: + "@multiversx/sdk-bls-wasm" "0.3.5" + "@noble/ed25519" "1.7.3" + "@noble/hashes" "1.3.0" + bech32 "1.1.4" + bip39 "3.0.2" + blake2b "2.1.3" + ed25519-hd-key "1.1.2" + ed2curve "0.3.0" + keccak "3.0.1" + scryptsy "2.1.0" + tweetnacl "1.0.3" + uuid "8.3.2" + +"@multiversx/sdk-web-wallet-cross-window-provider@>= 2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-2.0.4.tgz#bb605e42bd68f1806c16a9152cc2f2be4e2b304b" + integrity sha512-Oh5OvNsfGUYFc6fCl7pxaX+yqnRvn0d5rVhwEHVHhNMZVv0Q3cLaZak/wLftJNaQfAPVOw0gbD573fHCUa5bUw== + dependencies: + qs "6.11.2" + +"@multiversx/sdk-web-wallet-iframe-provider@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-2.0.1.tgz#0c31b59269eab92c4b7373dbb526751171394836" + integrity sha512-eQg6ZrlwhCTd4IwU7yf/jSjO3Q6eO97ENYLaZw6VDhcBTdNeKpIgVuW80B7quJf7jZWuYeRejEA3KrR5gZfeLA== dependencies: "@types/jest" "^29.5.11" "@types/qs" "6.9.10" @@ -1079,11 +1141,26 @@ dependencies: "@noble/hashes" "1.4.0" -"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@~1.4.0": +"@noble/ed25519@1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" + integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ== + +"@noble/hashes@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" + integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== + +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== +"@noble/hashes@^1.2.0", "@noble/hashes@^1.3.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.6.1.tgz#df6e5943edcea504bac61395926d6fd67869a0d5" + integrity sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1097,7 +1174,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -1105,102 +1182,113 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + "@open-draft/until@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca" integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q== -"@parcel/watcher-android-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" - integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg== - -"@parcel/watcher-darwin-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34" - integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA== - -"@parcel/watcher-darwin-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020" - integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg== - -"@parcel/watcher-freebsd-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8" - integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w== - -"@parcel/watcher-linux-arm-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d" - integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA== - -"@parcel/watcher-linux-arm64-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7" - integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA== - -"@parcel/watcher-linux-arm64-musl@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635" - integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA== - -"@parcel/watcher-linux-x64-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39" - integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg== - -"@parcel/watcher-linux-x64-musl@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16" - integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ== +"@parcel/watcher-android-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz#e32d3dda6647791ee930556aee206fcd5ea0fb7a" + integrity sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ== + +"@parcel/watcher-darwin-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz#0d9e680b7e9ec1c8f54944f1b945aa8755afb12f" + integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw== + +"@parcel/watcher-darwin-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz#f9f1d5ce9d5878d344f14ef1856b7a830c59d1bb" + integrity sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA== + +"@parcel/watcher-freebsd-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz#2b77f0c82d19e84ff4c21de6da7f7d096b1a7e82" + integrity sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw== + +"@parcel/watcher-linux-arm-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz#92ed322c56dbafa3d2545dcf2803334aee131e42" + integrity sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA== + +"@parcel/watcher-linux-arm-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz#cd48e9bfde0cdbbd2ecd9accfc52967e22f849a4" + integrity sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA== + +"@parcel/watcher-linux-arm64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz#7b81f6d5a442bb89fbabaf6c13573e94a46feb03" + integrity sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA== + +"@parcel/watcher-linux-arm64-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz#dcb8ff01077cdf59a18d9e0a4dff7a0cfe5fd732" + integrity sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q== + +"@parcel/watcher-linux-x64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz#2e254600fda4e32d83942384d1106e1eed84494d" + integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw== + +"@parcel/watcher-linux-x64-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz#01fcea60fedbb3225af808d3f0a7b11229792eef" + integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA== "@parcel/watcher-wasm@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.4.1.tgz#c4353e4fdb96ee14389856f7f6f6d21b7dcef9e1" - integrity sha512-/ZR0RxqxU/xxDGzbzosMjh4W6NdYFMqq2nvo2b8SLi7rsl/4jkL8S5stIikorNkdR50oVDvqb/3JT05WM+CRRA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.5.0.tgz#81fad1e10957f08a532eb4fc0d4c353cd8901a50" + integrity sha512-Z4ouuR8Pfggk1EYYbTaIoxc+Yv4o7cGQnH0Xy8+pQ+HbiW+ZnwhcD2LPf/prfq1nIWpAxjOkQ8uSMFWMtBLiVQ== dependencies: is-glob "^4.0.3" micromatch "^4.0.5" napi-wasm "^1.1.0" -"@parcel/watcher-win32-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc" - integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg== +"@parcel/watcher-win32-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz#87cdb16e0783e770197e52fb1dc027bb0c847154" + integrity sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig== -"@parcel/watcher-win32-ia32@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7" - integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw== +"@parcel/watcher-win32-ia32@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz#778c39b56da33e045ba21c678c31a9f9d7c6b220" + integrity sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA== -"@parcel/watcher-win32-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf" - integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A== +"@parcel/watcher-win32-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz#33873876d0bbc588aacce38e90d1d7480ce81cb7" + integrity sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw== "@parcel/watcher@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8" - integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.0.tgz#5c88818b12b8de4307a9d3e6dc3e28eba0dfbd10" + integrity sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ== dependencies: detect-libc "^1.0.3" is-glob "^4.0.3" micromatch "^4.0.5" node-addon-api "^7.0.0" optionalDependencies: - "@parcel/watcher-android-arm64" "2.4.1" - "@parcel/watcher-darwin-arm64" "2.4.1" - "@parcel/watcher-darwin-x64" "2.4.1" - "@parcel/watcher-freebsd-x64" "2.4.1" - "@parcel/watcher-linux-arm-glibc" "2.4.1" - "@parcel/watcher-linux-arm64-glibc" "2.4.1" - "@parcel/watcher-linux-arm64-musl" "2.4.1" - "@parcel/watcher-linux-x64-glibc" "2.4.1" - "@parcel/watcher-linux-x64-musl" "2.4.1" - "@parcel/watcher-win32-arm64" "2.4.1" - "@parcel/watcher-win32-ia32" "2.4.1" - "@parcel/watcher-win32-x64" "2.4.1" + "@parcel/watcher-android-arm64" "2.5.0" + "@parcel/watcher-darwin-arm64" "2.5.0" + "@parcel/watcher-darwin-x64" "2.5.0" + "@parcel/watcher-freebsd-x64" "2.5.0" + "@parcel/watcher-linux-arm-glibc" "2.5.0" + "@parcel/watcher-linux-arm-musl" "2.5.0" + "@parcel/watcher-linux-arm64-glibc" "2.5.0" + "@parcel/watcher-linux-arm64-musl" "2.5.0" + "@parcel/watcher-linux-x64-glibc" "2.5.0" + "@parcel/watcher-linux-x64-musl" "2.5.0" + "@parcel/watcher-win32-arm64" "2.5.0" + "@parcel/watcher-win32-ia32" "2.5.0" + "@parcel/watcher-win32-x64" "2.5.0" "@pkgjs/parseargs@^0.11.0": version "0.11.0" @@ -1265,10 +1353,20 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@scure/base@^1.1.3", "@scure/base@~1.1.6": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.7.tgz#fe973311a5c6267846aa131bc72e96c5d40d2b30" - integrity sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g== +"@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== + +"@scure/base@^1.1.3": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.1.tgz#dd0b2a533063ca612c17aa9ad26424a2ff5aa865" + integrity sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ== + +"@scure/base@~1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== "@scure/bip32@1.4.0": version "1.4.0" @@ -1306,6 +1404,11 @@ dependencies: "@sinonjs/commons" "^3.0.0" +"@socket.io/component-emitter@~3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" + integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== + "@stablelib/aead@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3" @@ -1400,7 +1503,7 @@ "@stablelib/constant-time" "^1.0.1" "@stablelib/wipe" "^1.0.1" -"@stablelib/random@^1.0.1", "@stablelib/random@^1.0.2": +"@stablelib/random@1.0.2", "@stablelib/random@^1.0.1", "@stablelib/random@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@stablelib/random/-/random-1.0.2.tgz#2dece393636489bf7e19c51229dd7900eddf742c" integrity sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w== @@ -1431,7 +1534,7 @@ resolved "https://registry.yarnpkg.com/@stablelib/wipe/-/wipe-1.0.1.tgz#d21401f1d59ade56a62e139462a97f104ed19a36" integrity sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg== -"@stablelib/x25519@^1.0.3": +"@stablelib/x25519@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@stablelib/x25519/-/x25519-1.0.3.tgz#13c8174f774ea9f3e5e42213cbf9fc68a3c7b7fd" integrity sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw== @@ -1440,74 +1543,74 @@ "@stablelib/random" "^1.0.2" "@stablelib/wipe" "^1.0.1" -"@swc/core-darwin-arm64@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.0.tgz#fdc694dd6e8543f3efea0619a6fba9ce82939205" - integrity sha512-2ylhM7f0HwUwLrFYZAe/dse8PCbPsYcJS3Dt7Q8NT3PUn7vy6QOMxNcOPPuDrnmaXqQQO3oxdmRapguTxaat9g== - -"@swc/core-darwin-x64@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.0.tgz#a9a78ace5c7e43c8cb68d11c53d33a0bf966ca8e" - integrity sha512-SgVnN4gT1Rb9YfTkp4FCUITqSs7Yj0uB2SUciu5CV3HuGvS5YXCUzh+KrwpLFtx8NIgivISKcNnb41mJi98X8Q== - -"@swc/core-linux-arm-gnueabihf@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.0.tgz#6861ac82fda01b68b44970d3b9aaa955d7311d98" - integrity sha512-+Z9Dayart1iKJQEJJ9N/KS4z5EdXJE3WPFikY0jonKTo4Dd8RuyVz5yLvqcIMeVdz/SwximATaL6iJXw7hZS9A== - -"@swc/core-linux-arm64-gnu@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.0.tgz#aa0e3dac17807c73d501f52526115666d60ea7a6" - integrity sha512-UnLrCiZ1EI4shznJn0xP6DLgsXUSwtfsdgHhGYCrvbgVBBve3S9iFgVFEB3SPl7Q/TdowNbrN4zHU0oChfiNfw== - -"@swc/core-linux-arm64-musl@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.0.tgz#4bb226a4e9eabac4e1a3b3ffd7ea5955629c84ed" - integrity sha512-H724UANA+ptsfwKRr9mnaDa9cb5fw0oFysiGKTgb3DMYcgk3Od0jMTnXVPFSVpo7FlmyxeC9K8ueUPBOoOK6XA== - -"@swc/core-linux-x64-gnu@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.0.tgz#ee65d1362214e91de89414f41b3310ba5302c2c5" - integrity sha512-SY3HA0K0Dpqt1HIfMLGpwL4hd4UaL2xHP5oZXPlRQPhUDZrbb4PbI3ZJnh66c63eL4ZR8EJ+HRFI0Alx5p69Zw== - -"@swc/core-linux-x64-musl@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.0.tgz#0868518771004753acb07d9871cf5b143b51dc30" - integrity sha512-cEJ2ebtV1v/5Ilb55E05J6F5SrHKQWzUttIhR5Mkayyo+yvPslcpByuFC3D+J7X1ebziTOBpWuMpUdjLfh3SMQ== - -"@swc/core-win32-arm64-msvc@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.0.tgz#43048d67f871e798566c3883c991bed521ef3b9e" - integrity sha512-ecQOOmzEssz+m0pR4xDYCGuvn3E/l0nQ3tk5jp1NA1lsAy4bMV0YbYCHjptYvWL/UjhIerIp3IlCJ8x5DodSog== - -"@swc/core-win32-ia32-msvc@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.0.tgz#6e98f413e6469cfd00dcc7c106cb69f2c709e581" - integrity sha512-gz81seZkRn3zMnVOc7L5k6F4vQC82gIxmHiL+GedK+A37XI/X26AASU3zxvORnqQbwQYXQ+AEVckxBmFlz3v2g== - -"@swc/core-win32-x64-msvc@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.0.tgz#79dfce878552f0a066a40c9cef524f4a8f872674" - integrity sha512-b5Fd1xEOw9uqBpj2lqsaR4Iq9UhiL84hNDcEsi6DQA7Y1l85waQAslTbS0E4/pJ1PISAs0jW0zIGLco1eaWBOg== +"@swc/core-darwin-arm64@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.1.tgz#faaaab19b4a039ae67ef661c0144a6f20fe8a78e" + integrity sha512-NyELPp8EsVZtxH/mEqvzSyWpfPJ1lugpTQcSlMduZLj1EASLO4sC8wt8hmL1aizRlsbjCX+r0PyL+l0xQ64/6Q== + +"@swc/core-darwin-x64@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.10.1.tgz#754600f453abd24471c202d48836f1161d798f49" + integrity sha512-L4BNt1fdQ5ZZhAk5qoDfUnXRabDOXKnXBxMDJ+PWLSxOGBbWE6aJTnu4zbGjJvtot0KM46m2LPAPY8ttknqaZA== + +"@swc/core-linux-arm-gnueabihf@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.1.tgz#b0f43c482d0d1819b382a4eb4a0733ce2e386257" + integrity sha512-Y1u9OqCHgvVp2tYQAJ7hcU9qO5brDMIrA5R31rwWQIAKDkJKtv3IlTHF0hrbWk1wPR0ZdngkQSJZple7G+Grvw== + +"@swc/core-linux-arm64-gnu@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.1.tgz#e02a9e22c25ba85ef00335742e549e06284cf33a" + integrity sha512-tNQHO/UKdtnqjc7o04iRXng1wTUXPgVd8Y6LI4qIbHVoVPwksZydISjMcilKNLKIwOoUQAkxyJ16SlOAeADzhQ== + +"@swc/core-linux-arm64-musl@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.1.tgz#3a0530af8f8bd3717f2f1bd8a2f5183fc58d4cf1" + integrity sha512-x0L2Pd9weQ6n8dI1z1Isq00VHFvpBClwQJvrt3NHzmR+1wCT/gcYl1tp9P5xHh3ldM8Cn4UjWCw+7PaUgg8FcQ== + +"@swc/core-linux-x64-gnu@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.1.tgz#5eb4d282b047a22896ab1d4627403be4c3e4fa6a" + integrity sha512-yyYEwQcObV3AUsC79rSzN9z6kiWxKAVJ6Ntwq2N9YoZqSPYph+4/Am5fM1xEQYf/kb99csj0FgOelomJSobxQA== + +"@swc/core-linux-x64-musl@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.1.tgz#890f2eda3e67ccc6817cdd04eff91e6ad9e761c4" + integrity sha512-tcaS43Ydd7Fk7sW5ROpaf2Kq1zR+sI5K0RM+0qYLYYurvsJruj3GhBCaiN3gkzd8m/8wkqNqtVklWaQYSDsyqA== + +"@swc/core-win32-arm64-msvc@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.1.tgz#4ea7b2a2fab47f801d31ea8b001a141efaa5e6bf" + integrity sha512-D3Qo1voA7AkbOzQ2UGuKNHfYGKL6eejN8VWOoQYtGHHQi1p5KK/Q7V1ku55oxXBsj79Ny5FRMqiRJpVGad7bjQ== + +"@swc/core-win32-ia32-msvc@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.1.tgz#729102669ccdb72e69884cce58e3686ac63d6f36" + integrity sha512-WalYdFoU3454Og+sDKHM1MrjvxUGwA2oralknXkXL8S0I/8RkWZOB++p3pLaGbTvOO++T+6znFbQdR8KRaa7DA== + +"@swc/core-win32-x64-msvc@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.1.tgz#7d665a7c69642861aed850ecb0cdf5d87197edda" + integrity sha512-JWobfQDbTnoqaIwPKQ3DVSywihVXlQMbDuwik/dDWlj33A8oEHcjPOGs4OqcA3RHv24i+lfCQpM3Mn4FAMfacA== "@swc/core@^1.4.17": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.0.tgz#81f4e7dadf03e1d7f9a5e48a87f5d857e8fc1468" - integrity sha512-d4vMzH6ICllDwlPuhset2h8gu/USHdbyfJim+2hQEdxC0UONtfpmu38XBgNqRjStrji1Q5M10jfeUZL3cu1i8g== + version "1.10.1" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.10.1.tgz#16b3b8284bafb0ecabb253925796883971e5a761" + integrity sha512-rQ4dS6GAdmtzKiCRt3LFVxl37FaY1cgL9kSUTnhQ2xc3fmHOd7jdJK/V4pSZMG1ruGTd0bsi34O2R0Olg9Zo/w== dependencies: "@swc/counter" "^0.1.3" - "@swc/types" "^0.1.9" + "@swc/types" "^0.1.17" optionalDependencies: - "@swc/core-darwin-arm64" "1.7.0" - "@swc/core-darwin-x64" "1.7.0" - "@swc/core-linux-arm-gnueabihf" "1.7.0" - "@swc/core-linux-arm64-gnu" "1.7.0" - "@swc/core-linux-arm64-musl" "1.7.0" - "@swc/core-linux-x64-gnu" "1.7.0" - "@swc/core-linux-x64-musl" "1.7.0" - "@swc/core-win32-arm64-msvc" "1.7.0" - "@swc/core-win32-ia32-msvc" "1.7.0" - "@swc/core-win32-x64-msvc" "1.7.0" + "@swc/core-darwin-arm64" "1.10.1" + "@swc/core-darwin-x64" "1.10.1" + "@swc/core-linux-arm-gnueabihf" "1.10.1" + "@swc/core-linux-arm64-gnu" "1.10.1" + "@swc/core-linux-arm64-musl" "1.10.1" + "@swc/core-linux-x64-gnu" "1.10.1" + "@swc/core-linux-x64-musl" "1.10.1" + "@swc/core-win32-arm64-msvc" "1.10.1" + "@swc/core-win32-ia32-msvc" "1.10.1" + "@swc/core-win32-x64-msvc" "1.10.1" "@swc/counter@^0.1.3": version "0.1.3" @@ -1515,18 +1618,18 @@ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== "@swc/jest@^0.2.36": - version "0.2.36" - resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.36.tgz#2797450a30d28b471997a17e901ccad946fe693e" - integrity sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw== + version "0.2.37" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.37.tgz#9c2aaf22c87682aa968016e3e4843d1a25cae6bd" + integrity sha512-CR2BHhmXKGxTiFr21DYPRHQunLkX3mNIFGFkxBGji6r9uyIR5zftTOVYj1e0sFNMV2H7mf/+vpaglqaryBtqfQ== dependencies: "@jest/create-cache-key-function" "^29.7.0" "@swc/counter" "^0.1.3" jsonc-parser "^3.2.0" -"@swc/types@^0.1.9": - version "0.1.9" - resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.9.tgz#e67cdcc2e4dd74a3cef4474b465eb398e7ae83e2" - integrity sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg== +"@swc/types@^0.1.17": + version "0.1.17" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.17.tgz#bd1d94e73497f27341bf141abdf4c85230d41e7c" + integrity sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ== dependencies: "@swc/counter" "^0.1.3" @@ -1580,6 +1683,11 @@ dependencies: "@types/ms" "*" +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@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" @@ -1606,10 +1714,18 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@29.5.13": + version "29.5.13" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.13.tgz#8bc571659f401e6a719a7bf0dbcb8b78c71a8adc" + integrity sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/jest@^29.5.11": - version "29.5.12" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" - integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -1638,10 +1754,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash@^4.17.4": - version "4.17.7" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.7.tgz#2f776bcb53adc9e13b2c0dfd493dfcbd7de43612" - integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== +"@types/lodash@4.17.4": + version "4.17.4" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.4.tgz#0303b64958ee070059e3a7184048a55159fe20b7" + integrity sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ== "@types/ms@*": version "0.7.34" @@ -1649,19 +1765,24 @@ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/node-fetch@^2.5.10": - version "2.6.11" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" - integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + version "2.6.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" + integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== dependencies: "@types/node" "*" form-data "^4.0.0" "@types/node@*", "@types/node@>=13.7.0": - version "20.14.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.11.tgz#09b300423343460455043ddd4d0ded6ac579b74b" - integrity sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA== + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== dependencies: - undici-types "~5.26.4" + undici-types "~6.20.0" + +"@types/node@11.11.6": + version "11.11.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" + integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== "@types/node@20.12.8": version "20.12.8" @@ -1675,11 +1796,6 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.10.tgz#0af26845b5067e1c9a622658a51f60a3934d51e8" integrity sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw== -"@types/semver@^7.5.8": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - "@types/set-cookie-parser@^2.4.0": version "2.4.10" resolved "https://registry.yarnpkg.com/@types/set-cookie-parser/-/set-cookie-parser-2.4.10.tgz#ad3a807d6d921db9720621ea3374c5d92020bcbc" @@ -1703,120 +1819,159 @@ integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.32" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" - integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz#c78e309fe967cb4de05b85cdc876fb95f8e01b6f" - integrity sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg== +"@typescript-eslint/eslint-plugin@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz#c95c6521e70c8b095a684d884d96c0c1c63747d2" + integrity sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.8.0" - "@typescript-eslint/type-utils" "7.8.0" - "@typescript-eslint/utils" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" - debug "^4.3.4" + "@typescript-eslint/scope-manager" "8.15.0" + "@typescript-eslint/type-utils" "8.15.0" + "@typescript-eslint/utils" "8.15.0" + "@typescript-eslint/visitor-keys" "8.15.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" - semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.8.0.tgz#1e1db30c8ab832caffee5f37e677dbcb9357ddc8" - integrity sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ== +"@typescript-eslint/parser@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.15.0.tgz#92610da2b3af702cfbc02a46e2a2daa6260a9045" + integrity sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A== dependencies: - "@typescript-eslint/scope-manager" "7.8.0" - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/typescript-estree" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" + "@typescript-eslint/scope-manager" "8.15.0" + "@typescript-eslint/types" "8.15.0" + "@typescript-eslint/typescript-estree" "8.15.0" + "@typescript-eslint/visitor-keys" "8.15.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz#bb19096d11ec6b87fb6640d921df19b813e02047" - integrity sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g== +"@typescript-eslint/scope-manager@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz#28a1a0f13038f382424f45a988961acaca38f7c6" + integrity sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA== + dependencies: + "@typescript-eslint/types" "8.15.0" + "@typescript-eslint/visitor-keys" "8.15.0" + +"@typescript-eslint/scope-manager@8.18.2": + version "8.18.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz#d193c200d61eb0ddec5987c8e48c9d4e1c0510bd" + integrity sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g== dependencies: - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" + "@typescript-eslint/types" "8.18.2" + "@typescript-eslint/visitor-keys" "8.18.2" -"@typescript-eslint/type-utils@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz#9de166f182a6e4d1c5da76e94880e91831e3e26f" - integrity sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A== +"@typescript-eslint/type-utils@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz#a6da0f93aef879a68cc66c73fe42256cb7426c72" + integrity sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw== dependencies: - "@typescript-eslint/typescript-estree" "7.8.0" - "@typescript-eslint/utils" "7.8.0" + "@typescript-eslint/typescript-estree" "8.15.0" + "@typescript-eslint/utils" "8.15.0" debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/types@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.8.0.tgz#1fd2577b3ad883b769546e2d1ef379f929a7091d" - integrity sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw== +"@typescript-eslint/types@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.15.0.tgz#4958edf3d83e97f77005f794452e595aaf6430fc" + integrity sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ== -"@typescript-eslint/typescript-estree@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz#b028a9226860b66e623c1ee55cc2464b95d2987c" - integrity sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg== +"@typescript-eslint/types@8.18.2": + version "8.18.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.2.tgz#5ebad5b384c8aa1c0f86cee1c61bcdbe7511f547" + integrity sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ== + +"@typescript-eslint/typescript-estree@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz#915c94e387892b114a2a2cc0df2d7f19412c8ba7" + integrity sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg== dependencies: - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/visitor-keys" "7.8.0" + "@typescript-eslint/types" "8.15.0" + "@typescript-eslint/visitor-keys" "8.15.0" debug "^4.3.4" - globby "^11.1.0" + fast-glob "^3.3.2" is-glob "^4.0.3" minimatch "^9.0.4" semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.8.0.tgz#57a79f9c0c0740ead2f622e444cfaeeb9fd047cd" - integrity sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ== +"@typescript-eslint/typescript-estree@8.18.2": + version "8.18.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz#fffb85527f8304e29bfbbdc712f4515da9f8b47c" + integrity sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg== dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.15" - "@types/semver" "^7.5.8" - "@typescript-eslint/scope-manager" "7.8.0" - "@typescript-eslint/types" "7.8.0" - "@typescript-eslint/typescript-estree" "7.8.0" + "@typescript-eslint/types" "8.18.2" + "@typescript-eslint/visitor-keys" "8.18.2" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" semver "^7.6.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/visitor-keys@7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz#7285aab991da8bee411a42edbd5db760d22fdd91" - integrity sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA== +"@typescript-eslint/utils@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.15.0.tgz#ac04679ad19252776b38b81954b8e5a65567cef6" + integrity sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ== dependencies: - "@typescript-eslint/types" "7.8.0" - eslint-visitor-keys "^3.4.3" + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.15.0" + "@typescript-eslint/types" "8.15.0" + "@typescript-eslint/typescript-estree" "8.15.0" -"@walletconnect/core@2.12.2": - version "2.12.2" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.12.2.tgz#12bd568b90daed876e58ebcc098c12843a3321e6" - integrity sha512-7Adv/b3pp9F42BkvReaaM4KS8NEvlkS7AMtwO3uF/o6aRMKtcfTJq9/jgWdKJh4RP8pPRTRFjCw6XQ/RZtT4aQ== +"@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.18.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.2.tgz#a2635f71904a84f9e47fe1b6f65a6d944ff1adf9" + integrity sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q== dependencies: - "@walletconnect/heartbeat" "1.2.1" - "@walletconnect/jsonrpc-provider" "1.0.13" - "@walletconnect/jsonrpc-types" "1.0.3" + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.18.2" + "@typescript-eslint/types" "8.18.2" + "@typescript-eslint/typescript-estree" "8.18.2" + +"@typescript-eslint/visitor-keys@8.15.0": + version "8.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz#9ea5a85eb25401d2aa74ec8a478af4e97899ea12" + integrity sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q== + dependencies: + "@typescript-eslint/types" "8.15.0" + eslint-visitor-keys "^4.2.0" + +"@typescript-eslint/visitor-keys@8.18.2": + version "8.18.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz#b3e434b701f086b10a7c82416ebc56899d27ef2f" + integrity sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw== + dependencies: + "@typescript-eslint/types" "8.18.2" + eslint-visitor-keys "^4.2.0" + +"@walletconnect/core@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.17.0.tgz#bf490e85a4702eff0f7cf81ba0d3c1016dffff33" + integrity sha512-On+uSaCfWdsMIQsECwWHZBmUXfrnqmv6B8SXRRuTJgd8tUpEvBkLQH4X7XkSm3zW6ozEkQTCagZ2ox2YPn3kbw== + dependencies: + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/jsonrpc-ws-connection" "1.0.14" - "@walletconnect/keyvaluestorage" "^1.1.1" - "@walletconnect/logger" "^2.1.2" - "@walletconnect/relay-api" "^1.0.9" - "@walletconnect/relay-auth" "^1.0.4" - "@walletconnect/safe-json" "^1.0.2" - "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.12.2" - "@walletconnect/utils" "2.12.2" - events "^3.3.0" - isomorphic-unfetch "3.1.0" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.0.4" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.17.0" + "@walletconnect/utils" "2.17.0" + events "3.3.0" lodash.isequal "4.5.0" - uint8arrays "^3.1.0" + uint8arrays "3.1.0" "@walletconnect/environment@^1.0.1": version "1.0.1" @@ -1825,7 +1980,7 @@ dependencies: tslib "1.14.1" -"@walletconnect/events@^1.0.1": +"@walletconnect/events@1.0.1", "@walletconnect/events@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/events/-/events-1.0.1.tgz#2b5f9c7202019e229d7ccae1369a9e86bda7816c" integrity sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ== @@ -1833,33 +1988,25 @@ keyvaluestorage-interface "^1.0.0" tslib "1.14.1" -"@walletconnect/heartbeat@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.1.tgz#afaa3a53232ae182d7c9cff41c1084472d8f32e9" - integrity sha512-yVzws616xsDLJxuG/28FqtZ5rzrTA4gUjdEMTbWB5Y8V1XHRmqq4efAxCw5ie7WjbXFSUyBHaWlMR+2/CpQC5Q== +"@walletconnect/heartbeat@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz#e8dc5179db7769950c6f9cf59b23516d9b95227d" + integrity sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/time" "^1.0.2" - tslib "1.14.1" + events "^3.3.0" -"@walletconnect/jsonrpc-provider@1.0.13": - version "1.0.13" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.13.tgz#9a74da648d015e1fffc745f0c7d629457f53648b" - integrity sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g== +"@walletconnect/jsonrpc-provider@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz#696f3e3b6d728b361f2e8b853cfc6afbdf2e4e3e" + integrity sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow== dependencies: "@walletconnect/jsonrpc-utils" "^1.0.8" "@walletconnect/safe-json" "^1.0.2" - tslib "1.14.1" - -"@walletconnect/jsonrpc-types@1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz#65e3b77046f1a7fa8347ae02bc1b841abe6f290c" - integrity sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw== - dependencies: - keyvaluestorage-interface "^1.0.0" - tslib "1.14.1" + events "^3.3.0" -"@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": +"@walletconnect/jsonrpc-types@1.0.4", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz#ce1a667d79eadf2a2d9d002c152ceb68739c230c" integrity sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ== @@ -1886,7 +2033,7 @@ events "^3.3.0" ws "^7.5.1" -"@walletconnect/keyvaluestorage@^1.1.1": +"@walletconnect/keyvaluestorage@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== @@ -1895,7 +2042,7 @@ idb-keyval "^6.2.1" unstorage "^1.9.0" -"@walletconnect/logger@^2.0.1", "@walletconnect/logger@^2.1.2": +"@walletconnect/logger@2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.1.2.tgz#813c9af61b96323a99f16c10089bfeb525e2a272" integrity sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw== @@ -1903,14 +2050,14 @@ "@walletconnect/safe-json" "^1.0.2" pino "7.11.0" -"@walletconnect/relay-api@^1.0.9": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.10.tgz#5aef3cd07c21582b968136179aa75849dcc65499" - integrity sha512-tqrdd4zU9VBNqUaXXQASaexklv6A54yEyQQEXYOCr+Jz8Ket0dmPBDyg19LVSNUN2cipAghQc45/KVmfFJ0cYw== +"@walletconnect/relay-api@1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.11.tgz#80ab7ef2e83c6c173be1a59756f95e515fb63224" + integrity sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q== dependencies: "@walletconnect/jsonrpc-types" "^1.0.2" -"@walletconnect/relay-auth@^1.0.4": +"@walletconnect/relay-auth@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@walletconnect/relay-auth/-/relay-auth-1.0.4.tgz#0b5c55c9aa3b0ef61f526ce679f3ff8a5c4c2c7c" integrity sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ== @@ -1922,75 +2069,77 @@ tslib "1.14.1" uint8arrays "^3.0.0" -"@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": +"@walletconnect/safe-json@1.0.2", "@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.2.tgz#7237e5ca48046e4476154e503c6d3c914126fa77" integrity sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA== dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.12.2": - version "2.12.2" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.12.2.tgz#10cddcba3740f726149c33ef1a9040a808d65e08" - integrity sha512-cM0ualXj6nVvLqS4BDNRk+ZWR+lubcsz/IHreH+3wYrQ2sV+C0fN6ctrd7MMGZss0C0qacWCx0pm62ZBuoKvqA== +"@walletconnect/sign-client@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.17.0.tgz#efe811b1bb10082d964e2f0378aaa1b40f424503" + integrity sha512-sErYwvSSHQolNXni47L3Bm10ptJc1s1YoJvJd34s5E9h9+d3rj7PrhbiW9X82deN+Dm5oA8X9tC4xty1yIBrVg== dependencies: - "@walletconnect/core" "2.12.2" - "@walletconnect/events" "^1.0.1" - "@walletconnect/heartbeat" "1.2.1" + "@walletconnect/core" "2.17.0" + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/logger" "^2.1.2" - "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.12.2" - "@walletconnect/utils" "2.12.2" - events "^3.3.0" + "@walletconnect/logger" "2.1.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.17.0" + "@walletconnect/utils" "2.17.0" + events "3.3.0" -"@walletconnect/time@^1.0.2": +"@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" integrity sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g== dependencies: tslib "1.14.1" -"@walletconnect/types@2.12.2": - version "2.12.2" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.12.2.tgz#8b64a2015a0a96972d28acb2ff317a9a994abfdb" - integrity sha512-9CmwTlPbrFTzayTL9q7xM7s3KTJkS6kYFtH2m1/fHFgALs6pIUjf1qAx1TF2E4tv7SEzLAIzU4NqgYUt2vWXTg== +"@walletconnect/types@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.17.0.tgz#20eda5791e3172f8ab9146caa3f317701d4b3232" + integrity sha512-i1pn9URpvt9bcjRDkabuAmpA9K7mzyKoLJlbsAujRVX7pfaG7wur7u9Jz0bk1HxvuABL5LHNncTnVKSXKQ5jZA== dependencies: - "@walletconnect/events" "^1.0.1" - "@walletconnect/heartbeat" "1.2.1" - "@walletconnect/jsonrpc-types" "1.0.3" - "@walletconnect/keyvaluestorage" "^1.1.1" - "@walletconnect/logger" "^2.0.1" - events "^3.3.0" + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "2.1.2" + events "3.3.0" -"@walletconnect/utils@2.12.2": - version "2.12.2" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.12.2.tgz#a2c349d4effef7c1c5e72e74a5483d8dfbb10918" - integrity sha512-zf50HeS3SfoLv1N9GPl2IXTZ9TsXfet4usVAsZmX9P6/Xzq7d/7QakjVQCHH/Wk1O9XkcsfeoZoUhRxoMJ5uJw== +"@walletconnect/utils@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.17.0.tgz#02b3af0b80d0c1a994d692d829d066271b04d071" + integrity sha512-1aeQvjwsXy4Yh9G6g2eGmXrEl+BzkNjHRdCrGdMYqFTFa8ROEJfTGsSH3pLsNDlOY94CoBUvJvM55q/PMoN/FQ== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" - "@stablelib/random" "^1.0.2" + "@stablelib/random" "1.0.2" "@stablelib/sha256" "1.0.1" - "@stablelib/x25519" "^1.0.3" - "@walletconnect/relay-api" "^1.0.9" - "@walletconnect/safe-json" "^1.0.2" - "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.12.2" - "@walletconnect/window-getters" "^1.0.1" - "@walletconnect/window-metadata" "^1.0.1" + "@stablelib/x25519" "1.0.3" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.0.4" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.17.0" + "@walletconnect/window-getters" "1.0.1" + "@walletconnect/window-metadata" "1.0.1" detect-browser "5.3.0" + elliptic "^6.5.7" query-string "7.1.3" - uint8arrays "^3.1.0" + uint8arrays "3.1.0" -"@walletconnect/window-getters@^1.0.1": +"@walletconnect/window-getters@1.0.1", "@walletconnect/window-getters@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.1.tgz#f36d1c72558a7f6b87ecc4451fc8bd44f63cbbdc" integrity sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q== dependencies: tslib "1.14.1" -"@walletconnect/window-metadata@^1.0.1": +"@walletconnect/window-metadata@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz#2124f75447b7e989e4e4e1581d55d25bc75f7be5" integrity sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA== @@ -2034,16 +2183,16 @@ acorn-jsx@^5.3.2: integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.0.2: - version "8.3.3" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== dependencies: acorn "^8.11.0" -acorn@^8.1.0, acorn@^8.11.0, acorn@^8.11.3, acorn@^8.12.0, acorn@^8.8.1: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +acorn@^8.1.0, acorn@^8.11.0, acorn@^8.14.0, acorn@^8.8.1: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== agent-base@6: version "6.0.2" @@ -2080,16 +2229,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" @@ -2128,15 +2270,15 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" + call-bound "^1.0.3" + is-array-buffer "^3.0.5" -array-includes@^3.1.7: +array-includes@^3.1.8: version "3.1.8" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== @@ -2153,7 +2295,7 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.3: +array.prototype.findlastindex@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== @@ -2166,38 +2308,37 @@ array.prototype.findlastindex@^1.2.3: es-shim-unscopables "^1.0.2" array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== dependencies: array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" + call-bind "^1.0.8" define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" asn1.js@^4.10.1: version "4.10.1" @@ -2236,7 +2377,7 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" -axios-mock-adapter@^1.22.0: +axios-mock-adapter@1.22.0: version "1.22.0" resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz#0f3e6be0fc9b55baab06f2d49c0b71157e7c053d" integrity sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw== @@ -2244,10 +2385,10 @@ axios-mock-adapter@^1.22.0: fast-deep-equal "^3.1.3" is-buffer "^2.0.5" -axios@>=1.6.5, axios@^1.6.8: - version "1.7.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" - integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== +axios@>=1.6.5, axios@^1.7.4: + version "1.7.9" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" + integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -2288,22 +2429,25 @@ babel-plugin-jest-hoist@^29.6.3: "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" babel-preset-jest@^29.6.3: version "29.6.3" @@ -2313,11 +2457,6 @@ babel-preset-jest@^29.6.3: babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" -backslash@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/backslash/-/backslash-0.2.0.tgz#6c3c1fce7e7e714ccfc10fd74f0f73410677375f" - integrity sha512-Avs+8FUZ1HF/VFP4YWwHQZSGzRPm37ukU1JQYQWijuHhtXdOuAzcZ8PcAzfIw898a8PyBzdn+RtnKA6MzW0X2A== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -2338,12 +2477,7 @@ bech32@^2.0.0: resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355" integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== -bignumber.js@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" - integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== - -bignumber.js@9.x, bignumber.js@^9.0.0: +bignumber.js@9.x, "bignumber.js@>= 9.1.2", bignumber.js@^9.0.0: version "9.1.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== @@ -2353,6 +2487,23 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +bip39@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.2.tgz#2baf42ff3071fc9ddd5103de92e8f80d9257ee32" + integrity sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ== + dependencies: + "@types/node" "11.11.6" + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + +bip39@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.1.0.tgz#c55a418deaf48826a6ceb34ac55b3ee1577e18a3" + integrity sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A== + dependencies: + "@noble/hashes" "^1.2.0" + bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -2378,11 +2529,11 @@ blake2b@2.1.3: nanoassert "^1.0.0" bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + version "4.12.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.1.tgz#215741fe3c9dba2d7e12c001d0cfdbae43975ba7" + integrity sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg== -bn.js@^5.0.0, bn.js@^5.2.1: +bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -2433,7 +2584,7 @@ browserify-aes@^1.0.4, browserify-aes@^1.2.0: inherits "^2.0.1" safe-buffer "^5.0.1" -browserify-cipher@^1.0.0: +browserify-cipher@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== @@ -2453,14 +2604,15 @@ browserify-des@^1.0.0: safe-buffer "^5.1.2" browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + version "4.1.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.1.tgz#06e530907fe2949dc21fc3c2e2302e10b1437238" + integrity sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ== dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" + bn.js "^5.2.1" + randombytes "^2.1.0" + safe-buffer "^5.2.1" -browserify-sign@^4.0.0: +browserify-sign@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208" integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw== @@ -2483,15 +2635,15 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.23.1: - version "4.23.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" - integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== +browserslist@^4.24.0: + version "4.24.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" + integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== dependencies: - caniuse-lite "^1.0.30001640" - electron-to-chromium "^1.4.820" - node-releases "^2.0.14" - update-browserslist-db "^1.1.0" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" bs-logger@0.x: version "0.2.6" @@ -2538,23 +2690,38 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" + integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== dependencies: - es-define-property "^1.0.0" es-errors "^1.3.0" function-bind "^1.1.2" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" get-intrinsic "^1.2.4" - set-function-length "^1.2.1" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.3.1: +camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== @@ -2564,19 +2731,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001640: - version "1.0.30001642" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz#6aa6610eb24067c246d30c57f055a9d0a7f8d05f" - integrity sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" +caniuse-lite@^1.0.30001688: + version "1.0.30001690" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" + integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" @@ -2617,12 +2775,12 @@ ci-info@^3.2.0: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + version "1.0.6" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7" + integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + inherits "^2.0.4" + safe-buffer "^5.2.1" citty@^0.1.5, citty@^0.1.6: version "0.1.6" @@ -2632,9 +2790,14 @@ citty@^0.1.5, citty@^0.1.6: consola "^3.2.3" cjs-module-lexer@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" - integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== + +"classnames@>= 2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== cli-cursor@^3.1.0: version "3.1.0" @@ -2662,6 +2825,15 @@ clipboardy@^4.0.0: is-wsl "^3.1.0" is64bit "^2.0.0" +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -2686,13 +2858,6 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -2700,11 +2865,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -2727,15 +2887,15 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -confbox@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" - integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== consola@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" - integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== + version "3.3.1" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.3.1.tgz#e60b4bfcd9e36cd766cc9afe2c93c14fe64c9356" + integrity sha512-GyKnPG3/I+a4RtJxgHquJXWr70g9I3c4NT3dvqh0LPHQP2nZFQBOBszb7a5u/pGzqr40AKplQA6UxM1BSynSXg== console-browserify@^1.1.0: version "1.2.0" @@ -2752,10 +2912,10 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-es@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.2.1.tgz#7e417c2a708ec0f5e0b0cc026b8f04ff0e532917" - integrity sha512-ilTPDuxhZX44BSzzRB58gvSY2UevZKQM9fjisn7Z+NJ92CtSU6kO1+22ZN/agbEJANFjK85EiJJbi/gQv18OXA== +cookie-es@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.2.2.tgz#18ceef9eb513cac1cb6c14bcbf8bdb2679b34821" + integrity sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg== cookie@^0.4.2: version "0.4.2" @@ -2772,7 +2932,7 @@ crc-32@^1.2.0: resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== -create-ecdh@^4.0.0: +create-ecdh@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== @@ -2791,7 +2951,7 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: ripemd160 "^2.0.1" sha.js "^2.4.0" -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: +create-hmac@1.1.7, create-hmac@^1.1.4, create-hmac@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== @@ -2821,36 +2981,39 @@ create-require@^1.1.1: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.0, cross-spawn@^7.0.3, cross-spawn@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -crossws@^0.2.0, crossws@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.2.4.tgz#82a8b518bff1018ab1d21ced9e35ffbe1681ad03" - integrity sha512-DAxroI2uSOgUKLz00NX6A8U/8EE3SZHmIND+10jkVSaypvyt57J5JEOxAQOL6lQxyzi/wZbTIwssU1uy69h5Vg== +"crossws@>=0.2.0 <0.4.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.3.1.tgz#7980e0b6688fe23286661c3ab8deeccbaa05ca86" + integrity sha512-HsZgeVYaG+b5zA+9PbIPGq4+J/CJynJuearykPsXx4V/eMhyQ5EDVg3Ak2FBZtVXCiOLu/U7IiwDHTr9MA+IKw== + dependencies: + uncrypto "^0.1.3" crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + version "3.12.1" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.1.tgz#bb8921bec9acc81633379aa8f52d69b0b69e0dac" + integrity sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ== dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" + browserify-cipher "^1.0.1" + browserify-sign "^4.2.3" + create-ecdh "^4.0.4" + create-hash "^1.2.0" + create-hmac "^1.1.7" + diffie-hellman "^5.0.3" + hash-base "~3.0.4" + inherits "^2.0.4" + pbkdf2 "^3.1.2" + public-encrypt "^4.0.3" + randombytes "^2.1.0" + randomfill "^1.0.4" cssom@^0.5.0: version "0.5.0" @@ -2878,39 +3041,39 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== dependencies: - call-bind "^1.0.6" + call-bound "^1.0.3" es-errors "^1.3.0" - is-data-view "^1.0.1" + is-data-view "^1.0.2" -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== dependencies: - call-bind "^1.0.7" + call-bound "^1.0.3" es-errors "^1.3.0" - is-data-view "^1.0.1" + is-data-view "^1.0.2" -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== dependencies: - call-bind "^1.0.6" + call-bound "^1.0.2" es-errors "^1.3.0" is-data-view "^1.0.1" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@^3.2.7: version "3.2.7" @@ -2919,6 +3082,18 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@~4.3.1, debug@~4.3.2: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + decimal.js@^10.4.2: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" @@ -2960,7 +3135,7 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" -define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: +define-properties@^1.1.3, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -3012,7 +3187,7 @@ diff-sequences@^29.6.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== -diffie-hellman@^5.0.0: +diffie-hellman@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== @@ -3021,6 +3196,11 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dijkstrajs@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23" + integrity sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -3047,6 +3227,15 @@ domexception@^4.0.0: dependencies: webidl-conversions "^7.0.0" +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + duplexify@^4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" @@ -3057,15 +3246,31 @@ duplexify@^4.1.2: readable-stream "^3.1.1" stream-shift "^1.0.2" -electron-to-chromium@^1.4.820: - version "1.4.830" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.830.tgz#a11899bc3343bc28f57a87fcf83060e0d28038d4" - integrity sha512-TrPKKH20HeN0J1LHzsYLs2qwXrp8TF4nHdu4sq61ozGbzMpWhI7iIOPYPPkxeq1azMT9PZ8enPFcftbs/Npcjg== +ed25519-hd-key@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/ed25519-hd-key/-/ed25519-hd-key-1.1.2.tgz#168dcf08419694be7bba3319e7d64e4a5cfe5d44" + integrity sha512-/0y9y6N7vM6Kj5ASr9J9wcMVDTtygxSOvYX+PJiMD7VcxCx2G03V5bLRl8Dug9EgkLFsLhGqBtQWQRcElEeWTA== + dependencies: + bip39 "3.0.2" + create-hmac "1.1.7" + tweetnacl "1.0.3" + +ed2curve@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ed2curve/-/ed2curve-0.3.0.tgz#322b575152a45305429d546b071823a93129a05d" + integrity sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ== + dependencies: + tweetnacl "1.x.x" + +electron-to-chromium@^1.5.73: + version "1.5.76" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz#db20295c5061b68f07c8ea4dfcbd701485d94a3d" + integrity sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ== -elliptic@^6.5.3, elliptic@^6.5.5: - version "6.5.6" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.6.tgz#ee5f7c3a00b98a2144ac84d67d01f04d438fa53e" - integrity sha512-mpzdtpeCLuS3BmE3pO3Cpp5bbjlOPY2Q0PgoF+Od1XZrHLYI28Xe3ossCmYCQt11FQKEYd9+PF8jymTvtWJSHQ== +elliptic@^6.5.3, elliptic@^6.5.5, elliptic@^6.5.7: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== dependencies: bn.js "^4.11.9" brorand "^1.1.0" @@ -3092,15 +3297,31 @@ end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.12.0: - version "5.17.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5" - integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA== +engine.io-client@~6.5.2: + version "6.5.4" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.4.tgz#b8bc71ed3f25d0d51d587729262486b4b33bd0d0" + integrity sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.17.1" + xmlhttprequest-ssl "~2.0.0" + +engine.io-parser@~5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== + +enhanced-resolve@^5.15.0: + version "5.18.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz#91eb1db193896b9801251eeff1c6980278b1e404" + integrity sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" -entities@^4.4.0: +entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -3112,66 +3333,65 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== +es-abstract@^1.23.2, es-abstract@^1.23.5, es-abstract@^1.23.6: + version "1.23.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.7.tgz#36e3da46fdb0d2ae3b9df4235e3a3167c1605b36" + integrity sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ== dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" + call-bind "^1.0.8" + call-bound "^1.0.3" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" es-errors "^1.3.0" es-object-atoms "^1.0.0" es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.2.6" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" + has-proto "^1.2.0" + has-symbols "^1.1.0" hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" + is-data-view "^1.0.2" + is-regex "^1.2.1" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.0" + math-intrinsics "^1.1.0" + object-inspect "^1.13.3" object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" + object.assign "^4.1.7" + regexp.prototype.flags "^1.5.3" + safe-array-concat "^1.1.3" + safe-regex-test "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.18" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== -es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== @@ -3192,21 +3412,21 @@ es-set-tostringtag@^2.0.3: has-tostringtag "^1.0.2" hasown "^2.0.1" -es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: +es-shim-unscopables@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: hasown "^2.0.0" -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" esbuild-node-externals@1.14.0: version "1.14.0" @@ -3216,39 +3436,39 @@ esbuild-node-externals@1.14.0: find-up "^5.0.0" tslib "^2.4.1" -esbuild@^0.21.1: - version "0.21.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" - integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== +esbuild@0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.1.tgz#3d6f199f6ec849158278c6632f438463bab88c38" + integrity sha512-GPqx+FX7mdqulCeQ4TsGZQ3djBJkx5k7zBGtqt9ycVlWNg8llJ4RO9n2vciu8BN2zAEs6lPbPl0asZsAh7oWzg== optionalDependencies: - "@esbuild/aix-ppc64" "0.21.5" - "@esbuild/android-arm" "0.21.5" - "@esbuild/android-arm64" "0.21.5" - "@esbuild/android-x64" "0.21.5" - "@esbuild/darwin-arm64" "0.21.5" - "@esbuild/darwin-x64" "0.21.5" - "@esbuild/freebsd-arm64" "0.21.5" - "@esbuild/freebsd-x64" "0.21.5" - "@esbuild/linux-arm" "0.21.5" - "@esbuild/linux-arm64" "0.21.5" - "@esbuild/linux-ia32" "0.21.5" - "@esbuild/linux-loong64" "0.21.5" - "@esbuild/linux-mips64el" "0.21.5" - "@esbuild/linux-ppc64" "0.21.5" - "@esbuild/linux-riscv64" "0.21.5" - "@esbuild/linux-s390x" "0.21.5" - "@esbuild/linux-x64" "0.21.5" - "@esbuild/netbsd-x64" "0.21.5" - "@esbuild/openbsd-x64" "0.21.5" - "@esbuild/sunos-x64" "0.21.5" - "@esbuild/win32-arm64" "0.21.5" - "@esbuild/win32-ia32" "0.21.5" - "@esbuild/win32-x64" "0.21.5" - -escalade@^3.1.1, escalade@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + "@esbuild/aix-ppc64" "0.21.1" + "@esbuild/android-arm" "0.21.1" + "@esbuild/android-arm64" "0.21.1" + "@esbuild/android-x64" "0.21.1" + "@esbuild/darwin-arm64" "0.21.1" + "@esbuild/darwin-x64" "0.21.1" + "@esbuild/freebsd-arm64" "0.21.1" + "@esbuild/freebsd-x64" "0.21.1" + "@esbuild/linux-arm" "0.21.1" + "@esbuild/linux-arm64" "0.21.1" + "@esbuild/linux-ia32" "0.21.1" + "@esbuild/linux-loong64" "0.21.1" + "@esbuild/linux-mips64el" "0.21.1" + "@esbuild/linux-ppc64" "0.21.1" + "@esbuild/linux-riscv64" "0.21.1" + "@esbuild/linux-s390x" "0.21.1" + "@esbuild/linux-x64" "0.21.1" + "@esbuild/netbsd-x64" "0.21.1" + "@esbuild/openbsd-x64" "0.21.1" + "@esbuild/sunos-x64" "0.21.1" + "@esbuild/win32-arm64" "0.21.1" + "@esbuild/win32-ia32" "0.21.1" + "@esbuild/win32-x64" "0.21.1" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^1.0.5: version "1.0.5" @@ -3295,23 +3515,24 @@ eslint-import-resolver-node@^0.3.9: is-core-module "^2.13.0" resolve "^1.22.4" -eslint-import-resolver-typescript@3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" - integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== - dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - fast-glob "^3.3.1" - get-tsconfig "^4.5.0" - is-core-module "^2.11.0" +eslint-import-resolver-typescript@3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" + integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.5" + enhanced-resolve "^5.15.0" + eslint-module-utils "^2.8.1" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" is-glob "^4.0.3" -eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" - integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== +eslint-module-utils@^2.12.0, eslint-module-utils@^2.8.1: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" @@ -3323,29 +3544,38 @@ eslint-plugin-es@^3.0.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" - integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== +eslint-plugin-import@2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" array.prototype.flat "^1.3.2" array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" + eslint-module-utils "^2.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" semver "^6.3.1" + string.prototype.trimend "^1.0.8" tsconfig-paths "^3.15.0" +eslint-plugin-jest@28.9.0: + version "28.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.9.0.tgz#19168dfaed124339cd2252c4c4d1ac3688aeb243" + integrity sha512-rLu1s1Wf96TgUUxSw6loVIkNtUjq1Re7A9QdCCHSohnvXEBAjuL420h0T/fMmkQlNsQP2GhQzEUpYHPfxBkvYQ== + dependencies: + "@typescript-eslint/utils" "^6.0.0 || ^7.0.0 || ^8.0.0" + eslint-plugin-node@11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" @@ -3358,23 +3588,23 @@ eslint-plugin-node@11.1.0: resolve "^1.10.1" semver "^6.1.0" -eslint-plugin-prettier@5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz#17cfade9e732cef32b5f5be53bd4e07afd8e67e1" - integrity sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw== +eslint-plugin-prettier@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95" + integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw== dependencies: prettier-linter-helpers "^1.0.0" - synckit "^0.8.6" + synckit "^0.9.1" -eslint-plugin-promise@6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" - integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== +eslint-plugin-promise@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-7.1.0.tgz#06b3ad6d36b3c3ef3ec201c8a8d97049cf5dbb20" + integrity sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ== -eslint-scope@^8.0.1: - version "8.0.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94" - integrity sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA== +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -3391,38 +3621,42 @@ eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint-visitor-keys@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" - integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== -eslint@9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.1.1.tgz#39ec657ccd12813cb4a1dab2f9229dcc6e468271" - integrity sha512-b4cRQ0BeZcSEzPpY2PjFY70VbO32K7BStTGtBsnIGdTSEEQzBi8hPBcGQmTG2zUvFr9uLe0TK42bw8YszuHEqg== +eslint@9.15.0: + version "9.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.15.0.tgz#77c684a4e980e82135ebff8ee8f0a9106ce6b8a6" + integrity sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^3.0.2" - "@eslint/js" "9.1.1" - "@humanwhocodes/config-array" "^0.13.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.9.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.15.0" + "@eslint/plugin-kit" "^0.2.3" + "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.2.3" - "@nodelib/fs.walk" "^1.2.8" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" - cross-spawn "^7.0.2" + cross-spawn "^7.0.5" debug "^4.3.2" escape-string-regexp "^4.0.0" - eslint-scope "^8.0.1" - eslint-visitor-keys "^4.0.0" - espree "^10.0.1" - esquery "^1.4.2" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^8.0.0" @@ -3431,31 +3665,27 @@ eslint@9.1.1: ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - is-path-inside "^3.0.3" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" -espree@^10.0.1: - version "10.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56" - integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA== +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== dependencies: - acorn "^8.12.0" + acorn "^8.14.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^4.0.0" + eslint-visitor-keys "^4.2.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: +esquery@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== @@ -3494,7 +3724,7 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -events@^3.0.0, events@^3.3.0: +events@3.3.0, events@^3.0.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -3580,7 +3810,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.9, fast-glob@^3.3.1: +fast-glob@^3.2.9, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -3612,9 +3842,9 @@ fast-safe-stringify@^2.0.6: integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + version "1.18.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.18.0.tgz#d631d7e25faffea81887fe5ea8c9010e1b36fee0" + integrity sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw== dependencies: reusify "^1.0.4" @@ -3676,14 +3906,14 @@ flat-cache@^4.0.0: keyv "^4.5.4" flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== for-each@^0.3.3: version "0.3.3" @@ -3693,17 +3923,17 @@ for-each@^0.3.3: is-callable "^1.1.3" foreground-child@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" - integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -3724,15 +3954,17 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" functions-have-names@^1.2.3: version "1.2.3" @@ -3744,21 +3976,26 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -get-caller-file@^2.0.5: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.6.tgz#43dd3dd0e7b49b82b2dfcad10dc824bf7fc265d5" + integrity sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA== dependencies: + call-bind-apply-helpers "^1.0.1" + dunder-proto "^1.0.0" + es-define-property "^1.0.1" es-errors "^1.3.0" + es-object-atoms "^1.0.0" function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.0.0" get-package-type@^0.1.0: version "0.1.0" @@ -3780,19 +4017,19 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== dependencies: - call-bind "^1.0.5" + call-bound "^1.0.3" es-errors "^1.3.0" - get-intrinsic "^1.2.4" + get-intrinsic "^1.2.6" -get-tsconfig@^4.5.0: - version "4.7.6" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.6.tgz#118fd5b7b9bae234cc7705a00cd771d7eb65d62a" - integrity sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA== +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== dependencies: resolve-pkg-maps "^1.0.0" @@ -3810,7 +4047,18 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.3.14, glob@^10.3.7: +glob@10.3.14: + version "10.3.14" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.14.tgz#36501f871d373fe197fc5794588d0aa71e69ff68" + integrity sha512-4fkAqu93xe9Mk7le9v0y3VrPDqLKHarNi2s4Pv7f2yOvfhWfhc7hRPHC/JyqMqb8B/Dt/eGS4n7ykwf3fOsl8g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.11.0" + +glob@^10.3.7: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== @@ -3844,7 +4092,7 @@ globals@^14.0.0: resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== -globalthis@^1.0.3: +globalthis@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== @@ -3852,7 +4100,7 @@ globalthis@^1.0.3: define-properties "^1.2.1" gopd "^1.0.1" -globby@^11.0.4, globby@^11.1.0: +globby@^11.0.4: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -3864,12 +4112,10 @@ globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" @@ -3882,35 +4128,30 @@ graphemer@^1.4.0: integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== "graphql@^15.0.0 || ^16.0.0": - version "16.9.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" - integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== + version "16.10.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.10.0.tgz#24c01ae0af6b11ea87bf55694429198aaa8e220c" + integrity sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ== -h3@^1.10.2, h3@^1.11.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/h3/-/h3-1.12.0.tgz#9d7f05f08a997d263e484b02436cb027df3026d8" - integrity sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA== +h3@^1.12.0, h3@^1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.13.0.tgz#b5347a8936529794b6754b440e26c0ab8a60dceb" + integrity sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg== dependencies: - cookie-es "^1.1.0" - crossws "^0.2.4" + cookie-es "^1.2.2" + crossws ">=0.2.0 <0.4.0" defu "^6.1.4" destr "^2.0.3" - iron-webcrypto "^1.1.1" - ohash "^1.1.3" + iron-webcrypto "^1.2.1" + ohash "^1.1.4" radix3 "^1.1.2" - ufo "^1.5.3" + ufo "^1.5.4" uncrypto "^0.1.3" - unenv "^1.9.0" + unenv "^1.10.0" -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== has-flag@^4.0.0: version "4.0.0" @@ -3924,15 +4165,17 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1, has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" @@ -3950,13 +4193,13 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -hash-base@~3.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow== +hash-base@~3.0, hash-base@~3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.5.tgz#52480e285395cf7fba17dc4c9e47acdc7f248a8a" + integrity sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + inherits "^2.0.4" + safe-buffer "^5.2.1" hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" @@ -4061,9 +4304,9 @@ ieee754@^1.1.13, ieee754@^1.2.1: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^5.1.1, ignore@^5.2.0, ignore@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== immer@^10.1.1: version "10.1.1" @@ -4079,9 +4322,9 @@ import-fresh@^3.2.1: resolve-from "^4.0.0" import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -4125,47 +4368,55 @@ inquirer@^8.2.0: through "^2.3.6" wrap-ansi "^6.0.1" -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== dependencies: es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" + hasown "^2.0.2" + side-channel "^1.1.0" -iron-webcrypto@^1.1.1: +iron-webcrypto@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz#aa60ff2aa10550630f4c0b11fd2442becdb35a6f" integrity sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg== is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b" + integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + has-tostringtag "^1.0.2" -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== dependencies: - has-bigints "^1.0.1" + has-bigints "^1.0.2" is-binary-path@~2.1.0: version "2.1.0" @@ -4174,44 +4425,54 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== +is-boolean-object@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89" + integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: +is-bun-module@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.3.0.tgz#ea4d24fdebfcecc98e81bcbcb506827fee288760" + integrity sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA== + dependencies: + semver "^7.6.3" + +is-callable@^1.1.3, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" - integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== +is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: hasown "^2.0.2" -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" is-typed-array "^1.1.13" -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-docker@^3.0.0: version "3.0.0" @@ -4223,6 +4484,13 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -4233,7 +4501,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.7: +is-generator-function@^1.0.10, is-generator-function@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -4259,6 +4527,11 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + is-nan@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" @@ -4267,52 +4540,50 @@ is-nan@^1.3.2: call-bind "^1.0.0" define-properties "^1.1.3" -is-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - is-node-process@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + has-tostringtag "^1.0.2" is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== dependencies: - call-bind "^1.0.7" + call-bound "^1.0.3" is-stream@^2.0.0: version "2.0.1" @@ -4324,38 +4595,54 @@ is-stream@^3.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== +is-string@^1.0.7, is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + has-tostringtag "^1.0.2" -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== dependencies: - has-symbols "^1.0.2" + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" -is-typed-array@^1.1.13, is-typed-array@^1.1.3: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15, is-typed-array@^1.1.3: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== dependencies: - which-typed-array "^1.1.14" + which-typed-array "^1.1.16" is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef" + integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q== dependencies: - call-bind "^1.0.2" + call-bound "^1.0.2" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" is-wsl@^3.1.0: version "3.1.0" @@ -4386,7 +4673,7 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isomorphic-fetch@^3.0.0: +isomorphic-fetch@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== @@ -4399,14 +4686,6 @@ isomorphic-timers-promises@^1.0.1: resolved "https://registry.yarnpkg.com/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz#e4137c24dbc54892de8abae3a4b5c1ffff381598" integrity sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ== -isomorphic-unfetch@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" - integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== - dependencies: - node-fetch "^2.6.1" - unfetch "^4.2.0" - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" @@ -4460,6 +4739,15 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jackspeak@^3.1.2: version "3.4.3" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" @@ -4841,10 +5129,10 @@ jest@29.7.0: import-local "^3.0.2" jest-cli "^29.7.0" -jiti@^1.21.0: - version "1.21.6" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" - integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== +jiti@^2.1.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== js-levenshtein@^1.1.6: version "1.1.6" @@ -4903,10 +5191,10 @@ jsdom@^20.0.0: ws "^8.11.0" xml-name-validator "^4.0.0" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== json-bigint@1.0.0: version "1.0.0" @@ -4920,13 +5208,6 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-duplicate-key-handle@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-duplicate-key-handle/-/json-duplicate-key-handle-1.0.0.tgz#0678bd17822d23d8c0d0958b43011875fa37f363" - integrity sha512-OLIxL+UpfwUsqcLX3i6Z51ChTou/Vje+6bSeGUSubj96dF/SfjObDprLy++ZXYH07KITuEzsXS7PX7e/BGf4jw== - dependencies: - backslash "^0.2.0" - json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -4959,6 +5240,14 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4" integrity sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ== +keccak@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.1.tgz#ae30a0e94dbe43414f741375cff6d64c8bea0bff" + integrity sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + keccak@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" @@ -5003,27 +5292,27 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -listhen@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.7.2.tgz#66b81740692269d5d8cafdc475020f2fc51afbae" - integrity sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g== +listhen@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.9.0.tgz#59355f7e4fc1eefda6bc494ae7e9ed13aa7658ef" + integrity sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg== dependencies: "@parcel/watcher" "^2.4.1" "@parcel/watcher-wasm" "^2.4.1" citty "^0.1.6" clipboardy "^4.0.0" consola "^3.2.3" - crossws "^0.2.0" + crossws ">=0.2.0 <0.4.0" defu "^6.1.4" get-port-please "^3.1.2" - h3 "^1.10.2" + h3 "^1.12.0" http-shutdown "^1.2.2" - jiti "^1.21.0" - mlly "^1.6.1" + jiti "^2.1.2" + mlly "^1.7.1" node-forge "^1.3.1" pathe "^1.1.2" std-env "^3.7.0" - ufo "^1.4.0" + ufo "^1.5.4" untun "^0.1.3" uqr "^0.1.2" @@ -5056,7 +5345,7 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5081,7 +5370,7 @@ loose-envify@^1.1.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lru-cache@^10.2.0: +lru-cache@^10.2.0, 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== @@ -5112,6 +5401,11 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +math-intrinsics@^1.0.0, math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -5137,9 +5431,9 @@ micro-ftch@^0.3.1: integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.7" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" - integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" picomatch "^2.3.1" @@ -5189,14 +5483,14 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.4: +minimatch@^9.0.1, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -5208,32 +5502,22 @@ minimist@^1.2.0, minimist@^1.2.6: 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: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -mlly@^1.6.1, mlly@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.1.tgz#e0336429bb0731b6a8e887b438cbdae522c8f32f" - integrity sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA== +mlly@^1.7.1, mlly@^1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.3.tgz#d86c0fcd8ad8e16395eb764a5f4b831590cee48c" + integrity sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A== dependencies: - acorn "^8.11.3" + acorn "^8.14.0" pathe "^1.1.2" - pkg-types "^1.1.1" - ufo "^1.5.3" - -mri@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + pkg-types "^1.2.1" + ufo "^1.5.4" -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5284,9 +5568,9 @@ nanoassert@^1.0.0: integrity sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ== napi-wasm@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" - integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.3.tgz#7bb95c88e6561f84880bb67195437b1cfbe99224" + integrity sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg== natural-compare@^1.4.0: version "1.4.0" @@ -5303,7 +5587,7 @@ node-addon-api@^7.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== -node-fetch-native@^1.6.2, node-fetch-native@^1.6.3, node-fetch-native@^1.6.4: +node-fetch-native@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== @@ -5321,19 +5605,19 @@ node-forge@^1.3.1: integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.0: - version "4.8.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5" - integrity sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw== + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.14: - version "2.0.17" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.17.tgz#d74bc4fec38d839eec5db2a3c9c963d4f33cb366" - integrity sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== node-stdlib-browser@1.2.0: version "1.2.0" @@ -5388,14 +5672,14 @@ npm-run-path@^5.1.0: path-key "^4.0.0" nwsapi@^2.2.2: - version "2.2.12" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" - integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== + version "2.2.16" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43" + integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ== -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== +object-inspect@^1.13.3: + version "1.13.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== object-is@^1.1.5: version "1.1.6" @@ -5410,17 +5694,19 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4, object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== +object.assign@^4.1.4, object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== dependencies: - call-bind "^1.0.5" + call-bind "^1.0.8" + call-bound "^1.0.3" define-properties "^1.2.1" - has-symbols "^1.0.3" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" object-keys "^1.1.1" -object.fromentries@^2.0.7: +object.fromentries@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== @@ -5430,7 +5716,7 @@ object.fromentries@^2.0.7: es-abstract "^1.23.2" es-object-atoms "^1.0.0" -object.groupby@^1.0.1: +object.groupby@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== @@ -5439,28 +5725,29 @@ object.groupby@^1.0.1: define-properties "^1.2.1" es-abstract "^1.23.2" -object.values@^1.1.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" - integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== +object.values@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== dependencies: - call-bind "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" define-properties "^1.2.1" es-object-atoms "^1.0.0" -ofetch@^1.3.3: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635" - integrity sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw== +ofetch@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.4.1.tgz#b6bf6b0d75ba616cef6519dd8b6385a8bae480ec" + integrity sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw== dependencies: destr "^2.0.3" - node-fetch-native "^1.6.3" - ufo "^1.5.3" + node-fetch-native "^1.6.4" + ufo "^1.5.4" -ohash@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.3.tgz#f12c3c50bfe7271ce3fd1097d42568122ccdcf07" - integrity sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw== +ohash@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.4.tgz#ae8d83014ab81157d2c285abf7792e2995fadd72" + integrity sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g== on-exit-leak-free@^0.2.0: version "0.2.0" @@ -5564,9 +5851,9 @@ p-try@^2.0.0: integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== package-json-from-dist@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" - integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + 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== pako@~1.0.5: version "1.0.11" @@ -5603,11 +5890,11 @@ parse-json@^5.2.0: lines-and-columns "^1.1.6" parse5@^7.0.0, parse5@^7.1.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + version "7.2.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" + integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== dependencies: - entities "^4.4.0" + entities "^4.5.0" path-browserify@^1.0.1: version "1.0.1" @@ -5639,7 +5926,7 @@ 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: +path-scurry@^1.11.0, 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== @@ -5648,9 +5935,9 @@ path-scurry@^1.11.1: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@^6.2.0: - version "6.2.2" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36" - integrity sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw== + version "6.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" + integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ== path-type@^4.0.0: version "4.0.0" @@ -5662,7 +5949,7 @@ pathe@^1.1.1, pathe@^1.1.2: resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== -pbkdf2@^3.0.3, pbkdf2@^3.1.2: +pbkdf2@^3.0.9, pbkdf2@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== @@ -5673,10 +5960,10 @@ pbkdf2@^3.0.3, pbkdf2@^3.1.2: safe-buffer "^5.0.1" sha.js "^2.4.8" -picocolors@^1.0.0, picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -5732,13 +6019,13 @@ pkg-dir@^5.0.0: dependencies: find-up "^5.0.0" -pkg-types@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.3.tgz#161bb1242b21daf7795036803f28e30222e476e3" - integrity sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA== +pkg-types@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.2.1.tgz#6ac4e455a5bb4b9a6185c1c79abd544c901db2e5" + integrity sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw== dependencies: - confbox "^0.1.7" - mlly "^1.7.1" + confbox "^0.1.8" + mlly "^1.7.2" pathe "^1.1.2" platform@1.3.6: @@ -5753,6 +6040,11 @@ plimit-lit@^1.2.6: dependencies: queue-lit "^1.5.1" +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + pony-cause@^2.1.10: version "2.1.11" resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.11.tgz#d69a20aaccdb3bdb8f74dd59e5c68d8e6772e4bd" @@ -5812,10 +6104,10 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -protobufjs@7.2.4: - version "7.2.4" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae" - integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== +protobufjs@7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.0.tgz#a32ec0422c039798c41a0700306a6e305b9cb32c" + integrity sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -5830,10 +6122,10 @@ protobufjs@7.2.4: "@types/node" ">=13.7.0" long "^5.0.0" -protobufjs@^7.3.0: - version "7.3.2" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.2.tgz#60f3b7624968868f6f739430cfbc8c9370e26df4" - integrity sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg== +protobufjs@7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -5854,11 +6146,13 @@ proxy-from-env@^1.1.0: integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" -public-encrypt@^4.0.0: +public-encrypt@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== @@ -5875,7 +6169,7 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== -punycode@^2.1.0, punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -5885,6 +6179,15 @@ pure-rand@^6.0.0: resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== +"qrcode@>= 1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.4.tgz#5cb81d86eb57c675febb08cf007fff963405da88" + integrity sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg== + dependencies: + dijkstrajs "^1.0.1" + 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" @@ -5899,10 +6202,10 @@ qs@6.11.2: dependencies: side-channel "^1.0.4" -qs@^6.11.2: - version "6.12.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.3.tgz#e43ce03c8521b9c7fd7f1f13e514e5ca37727754" - integrity sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ== +qs@^6.12.3: + version "6.13.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.1.tgz#3ce5fc72bd3a8171b85c99b93c65dd20b7d1b16e" + integrity sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg== dependencies: side-channel "^1.0.6" @@ -5946,14 +6249,14 @@ radix3@^1.1.2: resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" -randomfill@^1.0.3: +randomfill@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== @@ -5996,9 +6299,9 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable util-deprecate "^1.0.1" "readable-stream@^3.6.2 || ^4.4.2": - version "4.5.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" - integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== + version "4.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.6.0.tgz#ce412dfb19c04efde1c5936d99c27f37a1ff94c9" + integrity sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw== dependencies: abort-controller "^3.0.0" buffer "^6.0.3" @@ -6018,15 +6321,29 @@ real-require@^0.1.0: resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.1.0.tgz#736ac214caa20632847b7ca8c1056a0767df9381" integrity sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg== -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz#c905f3386008de95a62315f3ea8630404be19e2f" + integrity sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + dunder-proto "^1.0.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" + integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" define-properties "^1.2.1" es-errors "^1.3.0" - set-function-name "^2.0.1" + set-function-name "^2.0.2" regexpp@^3.0.0: version "3.2.0" @@ -6038,6 +6355,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -6066,16 +6388,16 @@ resolve-pkg-maps@^1.0.0: integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== resolve.exports@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" - integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== resolve@^1.10.1, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== dependencies: - is-core-module "^2.13.0" + is-core-module "^2.16.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -6093,9 +6415,9 @@ reusify@^1.0.4: integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^5.0.6: - version "5.0.9" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.9.tgz#c3baa1b886eadc2ec7981a06a593c3d01134ffe9" - integrity sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA== + version "5.0.10" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" + integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== dependencies: glob "^10.3.7" @@ -6133,14 +6455,15 @@ rxjs@^7.5.5, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" isarray "^2.0.5" safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: @@ -6153,19 +6476,19 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== dependencies: - call-bind "^1.0.6" + call-bound "^1.0.2" es-errors "^1.3.0" - is-regex "^1.1.4" + is-regex "^1.2.1" safe-stable-stringify@^2.1.0: - version "2.4.3" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" - integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" @@ -6179,22 +6502,32 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" +scryptsy@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" + integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w== + semver@^6.1.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: +semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + set-cookie-parser@^2.4.6: - version "2.6.0" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" - integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== + version "2.7.1" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" + integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== -set-function-length@^1.2.1: +set-function-length@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== @@ -6206,7 +6539,7 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.1: +set-function-name@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== @@ -6241,15 +6574,45 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4, side-channel@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== dependencies: - call-bind "^1.0.7" es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.0.4, side-channel@^1.0.6, side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" @@ -6271,6 +6634,24 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +socket.io-client@4.7.5: + version "4.7.5" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7" + integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.5.2" + 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== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + sonic-boom@^2.2.1: version "2.8.0" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" @@ -6314,9 +6695,9 @@ stack-utils@^2.0.3: escape-string-regexp "^2.0.0" std-env@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" - integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + version "3.8.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" + integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== stream-browserify@^3.0.0: version "3.0.0" @@ -6384,22 +6765,26 @@ string-width@4.1.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2. is-fullwidth-code-point "^3.0.0" strip-ansi "^5.2.0" -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== dependencies: - call-bind "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" define-properties "^1.2.1" - es-abstract "^1.23.0" + es-abstract "^1.23.5" es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== +string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== dependencies: - call-bind "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.2" define-properties "^1.2.1" es-object-atoms "^1.0.0" @@ -6479,13 +6864,6 @@ 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== -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -6510,10 +6888,10 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -synckit@^0.8.6: - version "0.8.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" - integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== +synckit@^0.9.1: + version "0.9.2" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" + integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== dependencies: "@pkgr/core" "^0.1.0" tslib "^2.6.2" @@ -6537,11 +6915,6 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - thread-stream@^0.15.1: version "0.15.2" resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4" @@ -6573,11 +6946,6 @@ tmpl@1.0.5: resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6608,9 +6976,9 @@ tr46@~0.0.3: integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-api-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" - integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== ts-jest@29.1.2: version "29.1.2" @@ -6654,15 +7022,20 @@ tslib@1.14.1, tslib@^1.9.0: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.1.0, tslib@^2.4.1, tslib@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" - integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== tty-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== +tweetnacl@1.0.3, tweetnacl@1.x.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -6685,76 +7058,93 @@ type-fest@^2.19.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== dependencies: - call-bind "^1.0.7" + call-bound "^1.0.3" es-errors "^1.3.0" - is-typed-array "^1.1.13" + is-typed-array "^1.1.14" -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== dependencies: - call-bind "^1.0.7" + call-bind "^1.0.8" for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== dependencies: available-typed-arrays "^1.0.7" - call-bind "^1.0.7" + call-bind "^1.0.8" for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== dependencies: call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-proto "^1.0.3" is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" -typescript@^5.4.5: - version "5.5.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" - integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== +typescript-eslint@8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.15.0.tgz#c8a2a0d183c3eb48ae176aa078c1b9daa584cf9d" + integrity sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w== + dependencies: + "@typescript-eslint/eslint-plugin" "8.15.0" + "@typescript-eslint/parser" "8.15.0" + "@typescript-eslint/utils" "8.15.0" + +typescript@5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== -ufo@^1.4.0, ufo@^1.5.3: +ufo@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== -uint8arrays@^3.0.0, uint8arrays@^3.1.0: +uint8arrays@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.0.tgz#8186b8eafce68f28bd29bd29d683a311778901e2" + integrity sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog== + dependencies: + multiformats "^9.4.2" + +uint8arrays@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg== dependencies: multiformats "^9.4.2" -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== dependencies: - call-bind "^1.0.2" + call-bound "^1.0.3" has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" uncrypto@^0.1.3: version "0.1.3" @@ -6766,7 +7156,12 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -unenv@^1.9.0: +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + +unenv@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.10.0.tgz#c3394a6c6e4cfe68d699f87af456fe3f0db39571" integrity sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ== @@ -6777,31 +7172,26 @@ unenv@^1.9.0: node-fetch-native "^1.6.4" pathe "^1.1.2" -unfetch@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== - universalify@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== unstorage@^1.9.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.10.2.tgz#fb7590ada8b30e83be9318f85100158b02a76dae" - integrity sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ== + version "1.14.1" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.14.1.tgz#49d8cb9b219114e29e56d6c1df83be13713083e5" + integrity sha512-0MBKpoVhNLL/Ixvue9lIsrHkwwWW9/f3TRftsYu1R7nZJJyHSdgPMBDjny2op07nirnS3OX6H3u+YDFGld+1Bg== dependencies: anymatch "^3.1.3" chokidar "^3.6.0" + citty "^0.1.6" destr "^2.0.3" - h3 "^1.11.1" - listhen "^1.7.2" - lru-cache "^10.2.0" - mri "^1.2.0" - node-fetch-native "^1.6.2" - ofetch "^1.3.3" - ufo "^1.4.0" + h3 "^1.13.0" + listhen "^1.9.0" + lru-cache "^10.4.3" + node-fetch-native "^1.6.4" + ofetch "^1.4.1" + ufo "^1.5.4" untun@^0.1.3: version "0.1.3" @@ -6812,13 +7202,13 @@ untun@^0.1.3: consola "^3.2.3" pathe "^1.1.1" -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" + escalade "^3.2.0" + picocolors "^1.1.0" uqr@^0.1.2: version "0.1.2" @@ -6841,12 +7231,12 @@ url-parse@^1.5.3: requires-port "^1.0.0" url@^0.11.0: - version "0.11.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" - integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== + version "0.11.4" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.4.tgz#adca77b3562d56b72746e76b330b7f27b6721f3c" + integrity sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg== dependencies: punycode "^1.4.1" - qs "^6.11.2" + qs "^6.12.3" use-sync-external-store@1.2.0: version "1.2.0" @@ -6869,6 +7259,11 @@ util@^0.12.3, util@^0.12.4, util@^0.12.5: is-typed-array "^1.1.3" which-typed-array "^1.1.2" +uuid@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" @@ -6971,26 +7366,61 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-boxed-primitive@^1.0.2: +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" -which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which-typed-array@^1.1.16, which-typed-array@^1.1.18, which-typed-array@^1.1.2: + version "1.1.18" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" + integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== dependencies: available-typed-arrays "^1.0.7" - call-bind "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" for-each "^0.3.3" - gopd "^1.0.1" + gopd "^1.2.0" has-tostringtag "^1.0.2" which@^2.0.1: @@ -7014,7 +7444,7 @@ word-wrap@^1.2.5: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^6.0.1: +wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== @@ -7064,6 +7494,11 @@ ws@^8.11.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +ws@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + xml-name-validator@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" @@ -7074,11 +7509,21 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + xtend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -7089,11 +7534,36 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + yargs@^17.3.1: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" @@ -7112,9 +7582,9 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zustand@^4.4.7: - version "4.5.4" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.4.tgz#63abdd81edfb190bc61e0bbae045cc4d52158a05" - integrity sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg== +zustand@4.4.7: + version "4.4.7" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.7.tgz#355406be6b11ab335f59a66d2cf9815e8f24038c" + integrity sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw== dependencies: use-sync-external-store "1.2.0"