diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15a06140a..354397f2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: run: yarn lint - name: Run unit tests, generate test coverage report env: - AVAILABLE_CHAINS: 'Preprod,Preview,Mainnet' + AVAILABLE_CHAINS: 'Preprod,Preview,Mainnet,Sanchonet' DEFAULT_CHAIN: 'Preprod' run: yarn test:coverage --maxWorkers=2 - name: Upload build diff --git a/apps/browser-extension-wallet/.env.defaults b/apps/browser-extension-wallet/.env.defaults index 217603e1f..006147c92 100644 --- a/apps/browser-extension-wallet/.env.defaults +++ b/apps/browser-extension-wallet/.env.defaults @@ -58,22 +58,27 @@ PRODUCTION_MODE_TRACKING=false POSTHOG_DEV_TOKEN_MAINNET=phc_gH96Lx5lEVXTTWEyytSdTFPDk3Xsxwi4BqG88mKObd1 POSTHOG_DEV_TOKEN_PREPROD=phc_Xlmldm6EYSfQVgB9Uxm3b2xC1noDlgFFXpF9AJ6SMfJ POSTHOG_DEV_TOKEN_PREVIEW=phc_e8SaOOWpXpNE59TnpLumeUjWm4iv024AWjhQqU406jr +POSTHOG_DEV_TOKEN_SANCHONET=phc_OUu6sPucDu5S6skRmYbWN5Jn8TpggWTQu1Y1ETkm3xt # Cardano Services CARDANO_SERVICES_URL_MAINNET=https://backend.live-mainnet.eks.lw.iog.io CARDANO_SERVICES_URL_PREPROD=https://backend.live-preprod.eks.lw.iog.io CARDANO_SERVICES_URL_PREVIEW=https://backend.live-preview.eks.lw.iog.io +# TODO: update this with a valid sanchonet url +CARDANO_SERVICES_URL_SANCHONET=https://backend.dev-sanchonet.eks.lw.iog.io # Explorer URLs CEXPLORER_URL_MAINNET=https://cexplorer.io CEXPLORER_URL_PREVIEW=https://preview.cexplorer.io CEXPLORER_URL_PREPROD=https://preprod.cexplorer.io -CEXPLORER_URL_SANCHONET=https://sanchonet.cexplorer.io +CEXPLORER_URL_SANCHONET= # ADA Handle URLs ADA_HANDLE_URL_MAINNET=https://api.handle.me ADA_HANDLE_URL_PREVIEW=https://preview.api.handle.me ADA_HANDLE_URL_PREPROD=https://preprod.api.handle.me +# TODO: update this with a valid sanchonet url +ADA_HANDLE_URL_SANCHONET= # Manifest.json LACE_EXTENSION_KEY=gafhhkghbfjjkeiendhlofajokpaflmk diff --git a/apps/browser-extension-wallet/.env.example b/apps/browser-extension-wallet/.env.example index 50c5ebf43..ae66e0ab8 100644 --- a/apps/browser-extension-wallet/.env.example +++ b/apps/browser-extension-wallet/.env.example @@ -4,7 +4,7 @@ DEFAULT_CHAIN=Mainnet WALLET_SYNC_TIMEOUT_IN_SEC=60 WALLET_INTERVAL_IN_SEC=30 DROP_CONSOLE_IN_PRODUCTION=false -AVAILABLE_CHAINS=Preprod,Preview,Mainnet +AVAILABLE_CHAINS=Preprod,Preview,Mainnet,Sanchonet ADA_PRICE_POLLING_IN_SEC=60 TOKEN_PRICE_POLLING_IN_SEC=300 SAVED_PRICE_DURATION_IN_MINUTES=720 @@ -64,17 +64,22 @@ POSTHOG_DEV_TOKEN_PREVIEW=dev-preview-token CARDANO_SERVICES_URL_MAINNET=https://backend.live-mainnet.eks.lw.iog.io CARDANO_SERVICES_URL_PREPROD=https://backend.live-preprod.eks.lw.iog.io CARDANO_SERVICES_URL_PREVIEW=https://backend.live-preview.eks.lw.iog.io +# TODO: update this with a valid sanchonet url +CARDANO_SERVICES_URL_SANCHONET=https://backend.dev-sanchonet.eks.lw.iog.io # Explorer URLs CEXPLORER_URL_MAINNET=https://cexplorer.io CEXPLORER_URL_PREVIEW=https://preview.cexplorer.io CEXPLORER_URL_PREPROD=https://preprod.cexplorer.io -CEXPLORER_URL_TESTNET=https://testnet.cexplorer.io +# TODO: update this with a valid sanchonet cexplorer +CEXPLORER_URL_SANCHONET=https://preprod.cexplorer.io # ADA Handle URLs ADA_HANDLE_URL_MAINNET=https://api.handle.me ADA_HANDLE_URL_PREVIEW=https://preview.api.handle.me ADA_HANDLE_URL_PREPROD=https://preprod.api.handle.me +# TODO: update this with a valid sanchonet url +ADA_HANDLE_URL_SANCHONET=https://preprod.api.handle.me # Manifest.json LACE_EXTENSION_KEY=gafhhkghbfjjkeiendhlofajokpaflmk diff --git a/apps/browser-extension-wallet/src/config.ts b/apps/browser-extension-wallet/src/config.ts index 99906fed8..bdb23b42b 100644 --- a/apps/browser-extension-wallet/src/config.ts +++ b/apps/browser-extension-wallet/src/config.ts @@ -22,7 +22,7 @@ export type Config = { ADA_PRICE_CHECK_INTERVAL: number; TOKEN_PRICE_CHECK_INTERVAL: number; AVAILABLE_CHAINS: Wallet.ChainName[]; - CEXPLORER_BASE_URL: Record; + CEXPLORER_BASE_URL: Record, string>; CEXPLORER_URL_PATHS: CExplorerUrlPaths; SAVED_PRICE_DURATION: number; }; @@ -32,11 +32,13 @@ const envChecks = (chosenChain: Wallet.ChainName): void => { if ( !process.env.CARDANO_SERVICES_URL_MAINNET || !process.env.CARDANO_SERVICES_URL_PREPROD || - !process.env.CARDANO_SERVICES_URL_PREVIEW + !process.env.CARDANO_SERVICES_URL_PREVIEW || + !process.env.CARDANO_SERVICES_URL_SANCHONET ) { throw new Error('env vars not complete'); } + // TODO Update if sanchonet explorer becomes available if (!process.env.CEXPLORER_URL_MAINNET || !process.env.CEXPLORER_URL_PREVIEW || !process.env.CEXPLORER_URL_PREPROD) { throw new Error('explorer vars not complete'); } @@ -78,7 +80,8 @@ export const config = (): Config => { CARDANO_SERVICES_URLS: { Mainnet: process.env.CARDANO_SERVICES_URL_MAINNET, Preprod: process.env.CARDANO_SERVICES_URL_PREPROD, - Preview: process.env.CARDANO_SERVICES_URL_PREVIEW + Preview: process.env.CARDANO_SERVICES_URL_PREVIEW, + Sanchonet: process.env.CARDANO_SERVICES_URL_SANCHONET }, CEXPLORER_BASE_URL: { Mainnet: `${process.env.CEXPLORER_URL_MAINNET}`, diff --git a/apps/browser-extension-wallet/src/dapp-connector.tsx b/apps/browser-extension-wallet/src/dapp-connector.tsx index a8bbd35db..e9d96606d 100644 --- a/apps/browser-extension-wallet/src/dapp-connector.tsx +++ b/apps/browser-extension-wallet/src/dapp-connector.tsx @@ -14,6 +14,7 @@ import { } from '@providers'; import { HashRouter } from 'react-router-dom'; import { ThemeProvider } from '@providers/ThemeProvider'; +import { UIThemeProvider } from '@providers/UIThemeProvider'; import { BackgroundServiceAPIProvider } from '@providers/BackgroundServiceAPI'; import { APP_MODE_POPUP } from './utils/constants'; import { PostHogClientProvider } from '@providers/PostHogClientProvider'; @@ -34,7 +35,9 @@ const App = (): React.ReactElement => ( - + + + diff --git a/apps/browser-extension-wallet/src/features/address-book/context/AddressBookProvider.tsx b/apps/browser-extension-wallet/src/features/address-book/context/AddressBookProvider.tsx index 65fea4797..c1604d2c9 100644 --- a/apps/browser-extension-wallet/src/features/address-book/context/AddressBookProvider.tsx +++ b/apps/browser-extension-wallet/src/features/address-book/context/AddressBookProvider.tsx @@ -18,7 +18,8 @@ export type AddressRecordParams = Pick { diff --git a/apps/browser-extension-wallet/src/features/dapp/components/ConfirmTransaction.tsx b/apps/browser-extension-wallet/src/features/dapp/components/ConfirmTransaction.tsx deleted file mode 100644 index e711aa50e..000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/ConfirmTransaction.tsx +++ /dev/null @@ -1,347 +0,0 @@ -import React, { useState, useEffect, useMemo, useCallback } from 'react'; -import { Button, PostHogAction, useObservable } from '@lace/common'; -import { useTranslation } from 'react-i18next'; -import { DappTransaction } from '@lace/core'; -import { Layout } from './Layout'; -import { useViewsFlowContext } from '@providers/ViewFlowProvider'; -import { sectionTitle, DAPP_VIEWS } from '../config'; -import styles from './ConfirmTransaction.module.scss'; -import { Wallet } from '@lace/cardano'; -import { useAddressBookContext, withAddressBookContext } from '@src/features/address-book/context'; -import { useWalletStore } from '@stores'; -import { AddressListType } from '@views/browser/features/activity'; -import { consumeRemoteApi, exposeApi, RemoteApiPropertyType } from '@cardano-sdk/web-extension'; -import { DappDataService } from '@lib/scripts/types'; -import { DAPP_CHANNELS } from '@src/utils/constants'; -import { runtime } from 'webextension-polyfill'; -import { useFetchCoinPrice, useRedirection } from '@hooks'; -import { - assetsBurnedInspector, - assetsMintedInspector, - createTxInspector, - AssetsMintedInspection, - MintedAsset -} from '@cardano-sdk/core'; -import { Skeleton } from 'antd'; -import { dAppRoutePaths } from '@routes'; -import { UserPromptService } from '@lib/scripts/background/services'; -import { of } from 'rxjs'; -import { getAssetsInformation, TokenInfo } from '@src/utils/get-assets-information'; -import * as HardwareLedger from '../../../../../../node_modules/@cardano-sdk/hardware-ledger/dist/cjs'; -import { useCurrencyStore, useAnalyticsContext } from '@providers'; -import { TX_CREATION_TYPE_KEY, TxCreationType } from '@providers/AnalyticsProvider/analyticsTracker'; -import { txSubmitted$ } from '@providers/AnalyticsProvider/onChain'; - -const DAPP_TOAST_DURATION = 50; - -const dappDataApi = consumeRemoteApi>( - { - baseChannel: DAPP_CHANNELS.dappData, - properties: { - getSignTxData: RemoteApiPropertyType.MethodReturningPromise - } - }, - { logger: console, runtime } -); - -const convertMetadataArrayToObj = (arr: unknown[]): Record => { - const result: Record = {}; - for (const item of arr) { - if (typeof item === 'object' && !Array.isArray(item) && item !== null) { - Object.assign(result, item); - } - } - return result; -}; - -// eslint-disable-next-line complexity, sonarjs/cognitive-complexity -const getAssetNameFromMintMetadata = (asset: MintedAsset, metadata: Wallet.Cardano.TxMetadata): string | undefined => { - if (!asset || !metadata) return; - const decodedAssetName = Buffer.from(asset.assetName, 'hex').toString(); - - // Tries to find the asset name in the tx metadata under label 721 or 20 - for (const [key, value] of metadata.entries()) { - // eslint-disable-next-line no-magic-numbers - if (key !== BigInt(721) && key !== BigInt(20)) return; - const cip25Metadata = Wallet.cardanoMetadatumToObj(value); - if (!Array.isArray(cip25Metadata)) return; - - // cip25Metadata should be an array containing all policies for the minted assets in the tx - const policyLevelMetadata = convertMetadataArrayToObj(cip25Metadata)[asset.policyId]; - if (!Array.isArray(policyLevelMetadata)) return; - - // policyLevelMetadata should be an array of objects with the minted assets names as key - // e.g. "policyId" = [{ "AssetName1": { ...metadataAsset1 } }, { "AssetName2": { ...metadataAsset2 } }]; - const assetProperties = convertMetadataArrayToObj(policyLevelMetadata)?.[decodedAssetName]; - if (!Array.isArray(assetProperties)) return; - - // assetProperties[decodedAssetName] should be an array of objects with the properties as keys - // e.g. [{ "name": "Asset Name" }, { "description": "An asset" }, ...] - const assetMetadataName = convertMetadataArrayToObj(assetProperties)?.name; - // eslint-disable-next-line consistent-return - return typeof assetMetadataName === 'string' ? assetMetadataName : undefined; - } -}; - -// eslint-disable-next-line sonarjs/cognitive-complexity -export const ConfirmTransaction = withAddressBookContext((): React.ReactElement => { - const { - utils: { setNextView } - } = useViewsFlowContext(); - const { t } = useTranslation(); - const { - walletInfo, - inMemoryWallet, - getKeyAgentType, - blockchainProvider: { assetProvider }, - walletUI: { cardanoCoin } - } = useWalletStore(); - const { fiatCurrency } = useCurrencyStore(); - const { list: addressList } = useAddressBookContext(); - const { priceResult } = useFetchCoinPrice(); - const analytics = useAnalyticsContext(); - - const [tx, setTx] = useState(); - const assets = useObservable(inMemoryWallet.assetInfo$); - const [errorMessage, setErrorMessage] = useState(); - const redirectToSignFailure = useRedirection(dAppRoutePaths.dappTxSignFailure); - const [isConfirmingTx, setIsConfirmingTx] = useState(); - const keyAgentType = getKeyAgentType(); - const isUsingHardwareWallet = useMemo( - () => keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory, - [keyAgentType] - ); - const [assetsInfo, setAssetsInfo] = useState(); - const [dappInfo, setDappInfo] = useState(); - - // All assets' ids in the transaction body. Used to fetch their info from cardano services - const assetIds = useMemo(() => { - const uniqueAssetIds = new Set(); - // Merge all assets (TokenMaps) from the tx outputs and mint - const assetMaps = tx?.body?.outputs?.map((output) => output.value.assets) ?? []; - if (tx?.body?.mint?.size > 0) assetMaps.push(tx.body.mint); - - // Extract all unique asset ids from the array of TokenMaps - for (const asset of assetMaps) { - if (asset) { - for (const id of asset.keys()) { - !uniqueAssetIds.has(id) && uniqueAssetIds.add(id); - } - } - } - return [...uniqueAssetIds.values()]; - }, [tx]); - - useEffect(() => { - if (assetIds?.length > 0) { - getAssetsInformation(assetIds, assets, { - assetProvider, - extraData: { nftMetadata: true, tokenMetadata: true } - }) - .then((result) => setAssetsInfo(result)) - .catch((error) => { - console.error(error); - }); - } - }, [assetIds, assetProvider, assets]); - - const cancelTransaction = useCallback((close = false) => { - exposeApi>( - { - api$: of({ - async allowSignTx(): Promise { - return Promise.reject(); - } - }), - baseChannel: DAPP_CHANNELS.userPrompt, - properties: { allowSignTx: RemoteApiPropertyType.MethodReturningPromise } - }, - { logger: console, runtime } - ); - close && setTimeout(() => window.close(), DAPP_TOAST_DURATION); - }, []); - - window.addEventListener('beforeunload', cancelTransaction); - - const signWithHardwareWallet = async () => { - setIsConfirmingTx(true); - try { - HardwareLedger.LedgerKeyAgent.establishDeviceConnection(Wallet.KeyManagement.CommunicationType.Web) - .then(() => { - exposeApi>( - { - api$: of({ - async allowSignTx(): Promise { - return Promise.resolve(true); - } - }), - baseChannel: DAPP_CHANNELS.userPrompt, - properties: { allowSignTx: RemoteApiPropertyType.MethodReturningPromise } - }, - { logger: console, runtime } - ); - }) - .catch((error) => { - throw error; - }); - } catch (error) { - console.error('error', error); - cancelTransaction(false); - redirectToSignFailure(); - } - }; - - useEffect(() => { - dappDataApi - .getSignTxData() - .then(({ dappInfo: backgroundDappInfo, tx: backgroundTx }) => { - setDappInfo(backgroundDappInfo); - setTx(backgroundTx); - }) - .catch((error) => { - setErrorMessage(error); - console.error(error); - }); - }, []); - - const createMintedList = useCallback( - (mintedAssets: AssetsMintedInspection) => { - if (!assetsInfo) return []; - return mintedAssets.map((asset) => { - const assetId = Wallet.Cardano.AssetId.fromParts(asset.policyId, asset.assetName); - const assetInfo = assets.get(assetId) || assetsInfo?.get(assetId); - // If it's a new asset or the name is being updated we should be getting it from the tx metadata - const metadataName = getAssetNameFromMintMetadata(asset, tx?.auxiliaryData?.blob); - return { - name: assetInfo?.name.toString() || asset.fingerprint || assetId, - ticker: - metadataName ?? - assetInfo?.nftMetadata?.name ?? - assetInfo?.tokenMetadata?.ticker ?? - assetInfo?.tokenMetadata?.name ?? - asset.fingerprint.toString(), - amount: Wallet.util.calculateAssetBalance(asset.quantity, assetInfo) - }; - }); - }, - [assets, assetsInfo, tx] - ); - - const createAssetList = useCallback( - (txAssets: Wallet.Cardano.TokenMap) => { - if (!assetsInfo) return []; - const assetList: Wallet.Cip30SignTxAssetItem[] = []; - txAssets.forEach(async (value, key) => { - const walletAsset = assets.get(key) || assetsInfo?.get(key); - assetList.push({ - name: walletAsset?.name.toString() || key.toString(), - ticker: walletAsset?.tokenMetadata?.ticker || walletAsset?.nftMetadata?.name, - amount: Wallet.util.calculateAssetBalance(value, walletAsset) - }); - }); - return assetList; - }, - [assets, assetsInfo] - ); - - const addressToNameMap = useMemo( - () => new Map(addressList?.map((item: AddressListType) => [item.address, item.name])), - [addressList] - ); - - const txSummary: Wallet.Cip30SignTxSummary | undefined = useMemo(() => { - if (!tx) return; - const inspector = createTxInspector({ - minted: assetsMintedInspector, - burned: assetsBurnedInspector - }); - - const { minted, burned } = inspector(tx as Wallet.Cardano.HydratedTx); - const isMintTransaction = minted.length > 0 || burned.length > 0; - - const txType = isMintTransaction ? 'Mint' : 'Send'; - - const externalOutputs = tx.body.outputs.filter((output) => { - if (txType === 'Send') { - return walletInfo.addresses.every((addr) => output.address !== addr.address); - } - return true; - }); - - // eslint-disable-next-line unicorn/no-array-reduce - const txSummaryOutputs: Wallet.Cip30SignTxSummary['outputs'] = externalOutputs.reduce((acc, txOut) => { - // Don't show withdrawl tx's etc - if (txOut.address.toString() === walletInfo.addresses[0].address.toString()) return acc; - - return [ - ...acc, - { - coins: Wallet.util.lovelacesToAdaString(txOut.value.coins.toString()), - recipient: addressToNameMap?.get(txOut.address.toString()) || txOut.address.toString(), - ...(txOut.value.assets?.size > 0 && { assets: createAssetList(txOut.value.assets) }) - } - ]; - }, []); - - // eslint-disable-next-line consistent-return - return { - fee: Wallet.util.lovelacesToAdaString(tx.body.fee.toString()), - outputs: txSummaryOutputs, - type: txType, - mintedAssets: createMintedList(minted), - burnedAssets: createMintedList(burned) - }; - }, [tx, walletInfo.addresses, createAssetList, createMintedList, addressToNameMap]); - - const onConfirm = () => { - analytics.sendEventToPostHog(PostHogAction.SendTransactionSummaryConfirmClick, { - [TX_CREATION_TYPE_KEY]: TxCreationType.External - }); - - txSubmitted$.next({ - id: tx?.id.toString(), - date: new Date().toString(), - creationType: TxCreationType.External - }); - - isUsingHardwareWallet ? signWithHardwareWallet() : setNextView(); - }; - - return ( - - {tx && txSummary ? ( - - ) : ( - - )} -
- - -
-
- ); -}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/__tests__/ConfirmTransaction.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/__tests__/ConfirmTransaction.test.tsx deleted file mode 100644 index 7acabf64d..000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/__tests__/ConfirmTransaction.test.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable import/imports-first */ -import * as CurrencyProvider from '@providers/currency'; - -const mockGetKeyAgentType = jest.fn(); -const mockUseWalletStore = jest.fn(); -const error = 'error in getSignTxData'; -const mockConsumeRemoteApi = jest.fn().mockReturnValue({ - getSignTxData: async () => await Promise.reject(error) -}); -const mockCreateTxInspector = jest.fn().mockReturnValue(() => ({ minted: [] as any, burned: [] as any })); -const mockUseCurrencyStore = jest.fn().mockReturnValue({ fiatCurrency: { code: 'usd', symbol: '$' } }); -import * as React from 'react'; -import { cleanup, render, waitFor } from '@testing-library/react'; -import { ConfirmTransaction } from '../ConfirmTransaction'; -import '@testing-library/jest-dom'; -import { I18nextProvider } from 'react-i18next'; -import { StoreProvider } from '@src/stores'; -import { - AnalyticsProvider, - AppSettingsProvider, - BackgroundServiceAPIProvider, - BackgroundServiceAPIProviderProps, - DatabaseProvider, - ViewFlowProvider -} from '@src/providers'; -import { APP_MODE_BROWSER } from '@src/utils/constants'; -import i18n from '@lib/i18n'; -import { BehaviorSubject } from 'rxjs'; -import { act } from 'react-dom/test-utils'; -import { sendViewsFlowState } from '../../config'; -import { PostHogClientProvider } from '@providers/PostHogClientProvider'; -import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; - -const assetInfo$ = new BehaviorSubject(new Map()); -const available$ = new BehaviorSubject([]); -const tokenPrices$ = new BehaviorSubject({}); -const adaPrices$ = new BehaviorSubject({}); - -const assetProvider = { - getAsset: () => ({}), - getAssets: (): any[] => [] -}; -const inMemoryWallet = { - assetInfo$, - balance: { - utxo: { - available$ - } - } -}; - -jest.mock('@src/stores', () => ({ - ...jest.requireActual('@src/stores'), - useWalletStore: mockUseWalletStore -})); - -jest.mock('@providers/currency', (): typeof CurrencyProvider => ({ - ...jest.requireActual('@providers/currency'), - useCurrencyStore: mockUseCurrencyStore -})); - -jest.mock('@cardano-sdk/web-extension', () => { - const original = jest.requireActual('@cardano-sdk/web-extension'); - return { - __esModule: true, - ...original, - consumeRemoteApi: mockConsumeRemoteApi - }; -}); - -jest.mock('@cardano-sdk/core', () => { - const original = jest.requireActual('@cardano-sdk/core'); - return { - __esModule: true, - ...original, - createTxInspector: mockCreateTxInspector - }; -}); - -const testIds = { - dappTransactionConfirm: 'dapp-transaction-confirm' -}; - -const backgroundService = { - getBackgroundStorage: jest.fn(), - setBackgroundStorage: jest.fn(), - coinPrices: { tokenPrices$, adaPrices$ } -} as unknown as BackgroundServiceAPIProviderProps['value']; - -const getWrapper = - () => - ({ children }: { children: React.ReactNode }) => - ( - - - - - - - - {children} - - - - - - - - ); - -describe('Testing ConfirmTransaction component', () => { - window.ResizeObserver = ResizeObserver; - describe('Testing errors', () => { - beforeEach(() => { - mockUseWalletStore.mockImplementation(() => ({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - })); - }); - - afterEach(() => { - jest.resetModules(); - jest.resetAllMocks(); - cleanup(); - }); - - test('should disable confirm button and show proper error if getSignTxData throws', async () => { - let queryByTestId: any; - act(() => { - ({ queryByTestId } = render(, { - wrapper: getWrapper() - })); - }); - - await waitFor(async () => { - expect(queryByTestId(testIds.dappTransactionConfirm).closest('button')).toHaveAttribute('disabled'); - }); - }); - }); -}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx new file mode 100644 index 000000000..e9f317129 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ConfirmDRepRegistration } from '@lace/core'; +import { SignTxData } from './types'; +import { certificateInspectorFactory, drepIDasBech32FromHash } from './utils'; +import { Wallet } from '@lace/cardano'; +import { useWalletStore } from '@src/stores'; + +const { CertificateType } = Wallet.Cardano; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export const ConfirmDRepRegistrationContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { t } = useTranslation(); + const { + walletUI: { cardanoCoin } + } = useWalletStore(); + const certificate = certificateInspectorFactory( + CertificateType.RegisterDelegateRepresentative + )(signTxData.tx); + const depositPaidWithCardanoSymbol = `${Wallet.util.lovelacesToAdaString(certificate.deposit.toString())} ${ + cardanoCoin.symbol + }`; + + return ( + + ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx new file mode 100644 index 000000000..42650c2b8 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ConfirmDRepRetirement } from '@lace/core'; +import { SignTxData } from './types'; +import { certificateInspectorFactory, drepIDasBech32FromHash, getOwnRetirementMessageKey } from './utils'; +import { Wallet } from '@lace/cardano'; +import { useWalletStore } from '@src/stores'; +import { useIsOwnPubDRepKey } from './hooks'; + +const { CertificateType } = Wallet.Cardano; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export const ConfirmDRepRetirementContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { t } = useTranslation(); + const { + walletUI: { cardanoCoin }, + inMemoryWallet + } = useWalletStore(); + const certificate = certificateInspectorFactory( + CertificateType.UnregisterDelegateRepresentative + )(signTxData.tx); + const depositPaidWithCardanoSymbol = `${Wallet.util.lovelacesToAdaString(certificate.deposit.toString())} ${ + cardanoCoin.symbol + }`; + + const isOwnRetirement = useIsOwnPubDRepKey(inMemoryWallet.getPubDRepKey, certificate.dRepCredential.hash); + const ownRetirementMessageKey = getOwnRetirementMessageKey(isOwnRetirement); + + return ( + + ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepUpdateContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepUpdateContainer.tsx new file mode 100644 index 000000000..bc52b868d --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepUpdateContainer.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ConfirmDRepUpdate } from '@lace/core'; +import { SignTxData } from './types'; +import { certificateInspectorFactory, drepIDasBech32FromHash } from './utils'; +import { Wallet } from '@lace/cardano'; + +const { CertificateType } = Wallet.Cardano; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export const ConfirmDRepUpdateContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { t } = useTranslation(); + const certificate = certificateInspectorFactory( + CertificateType.UpdateDelegateRepresentative + )(signTxData.tx); + + return ( + + ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/ConfirmTransaction.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss similarity index 72% rename from apps/browser-extension-wallet/src/features/dapp/components/ConfirmTransaction.module.scss rename to apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss index cfac6eebe..9d25c19f3 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/ConfirmTransaction.module.scss +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss @@ -1,5 +1,5 @@ -@import '../../../../../../packages/common/src/ui/styles/theme.scss'; -@import '../../../../src/styles/rules/flex.scss'; +@import '../../../../../../../packages/common/src/ui/styles/theme.scss'; +@import '../../../../../src/styles/rules/flex.scss'; .actions { display: flex; @@ -20,10 +20,11 @@ gap: size_unit(1); padding: size_unit(2) size_unit(3) size_unit(2) size_unit(3); border-top: 2px solid var(--light-mode-light-grey-plus, var(--dark-mode-mid-grey)); - margin: 0 size_unit(-3) size_unit(-2) size_unit(-3); + margin: size_unit(4) size_unit(-3) size_unit(-2) size_unit(-3); position: sticky; bottom: 0; .actionBtn { width: 100%; } + z-index: 10; } diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx new file mode 100644 index 000000000..f90eea8d7 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx @@ -0,0 +1,90 @@ +/* eslint-disable no-console */ +import React, { useMemo } from 'react'; +import { Button, PostHogAction } from '@lace/common'; +import { useTranslation } from 'react-i18next'; +import { Layout } from '../Layout'; +import { useViewsFlowContext } from '@providers/ViewFlowProvider'; +import styles from './ConfirmTransaction.module.scss'; +import { Wallet } from '@lace/cardano'; +import { useWalletStore } from '@stores'; +import { useDisallowSignTx, useSignWithHardwareWallet, useSignTxData, useOnBeforeUnload } from './hooks'; +import { consumeRemoteApi, RemoteApiPropertyType } from '@cardano-sdk/web-extension'; +import { DappDataService } from '@lib/scripts/types'; +import { DAPP_CHANNELS } from '@src/utils/constants'; +import { runtime } from 'webextension-polyfill'; +import { getTitleKey, getTxType } from './utils'; +import { ConfirmTransactionContent } from './ConfirmTransactionContent'; +import { TX_CREATION_TYPE_KEY, TxCreationType } from '@providers/AnalyticsProvider/analyticsTracker'; +import { txSubmitted$ } from '@providers/AnalyticsProvider/onChain'; +import { useAnalyticsContext } from '@providers'; + +export const ConfirmTransaction = (): React.ReactElement => { + const { t } = useTranslation(); + const { + utils: { setNextView } + } = useViewsFlowContext(); + const dappDataApi = useMemo( + () => + consumeRemoteApi>( + { + baseChannel: DAPP_CHANNELS.dappData, + properties: { + getSignTxData: RemoteApiPropertyType.MethodReturningPromise + } + }, + { logger: console, runtime } + ), + [] + ); + const { getKeyAgentType } = useWalletStore(); + const analytics = useAnalyticsContext(); + const { signTxData, errorMessage } = useSignTxData(dappDataApi.getSignTxData); + const keyAgentType = getKeyAgentType(); + const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; + const disallowSignTx = useDisallowSignTx(); + const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); + const txType = signTxData ? getTxType(signTxData.tx) : undefined; + const title = txType ? t(getTitleKey(txType)) : ''; + const onConfirm = () => { + analytics.sendEventToPostHog(PostHogAction.SendTransactionSummaryConfirmClick, { + [TX_CREATION_TYPE_KEY]: TxCreationType.External + }); + + txSubmitted$.next({ + id: signTxData.tx?.id.toString(), + date: new Date().toString(), + creationType: TxCreationType.External + }); + + isUsingHardwareWallet ? signWithHardwareWallet() : setNextView(); + }; + + useOnBeforeUnload(disallowSignTx); + + return ( + + +
+ + +
+
+ ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx new file mode 100644 index 000000000..eb931efab --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Skeleton } from 'antd'; +import { ConfirmDRepRegistrationContainer } from './ConfirmDRepRegistrationContainer'; +import { DappTransactionContainer } from './DappTransactionContainer'; +import { SignTxData } from './types'; +import { ConfirmDRepRetirementContainer } from './ConfirmDRepRetirementContainer'; +import { ConfirmVoteDelegationContainer } from './ConfirmVoteDelegationContainer'; +import { VotingProceduresContainer } from './VotingProceduresContainer'; +import { ConfirmDRepUpdateContainer } from './ConfirmDRepUpdateContainer'; +import { Wallet } from '@lace/cardano'; + +interface Props { + txType?: Wallet.Cip30TxType; + signTxData?: SignTxData; + errorMessage?: string; +} + +export const ConfirmTransactionContent = ({ txType, signTxData, errorMessage }: Props): React.ReactElement => { + if (!signTxData) { + return ; + } + if (txType === Wallet.Cip30TxType.DRepRegistration) { + return ; + } + if (txType === Wallet.Cip30TxType.DRepRetirement) { + return ; + } + if (txType === Wallet.Cip30TxType.DRepUpdate) { + return ; + } + if (txType === Wallet.Cip30TxType.VoteDelegation) { + return ; + } + if (txType === Wallet.Cip30TxType.VotingProcedures) { + return ; + } + + return ; +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx new file mode 100644 index 000000000..436dfd0eb --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ConfirmVoteDelegation } from '@lace/core'; +import { SignTxData } from './types'; +import { certificateInspectorFactory, drepIDasBech32FromHash } from './utils'; +import { Wallet } from '@lace/cardano'; + +const { CertificateType } = Wallet.Cardano; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export const ConfirmVoteDelegationContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { t } = useTranslation(); + const { dRep } = certificateInspectorFactory( + CertificateType.VoteDelegation + )(signTxData.tx); + + return ( + + ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx new file mode 100644 index 000000000..63d35ea57 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DappTransactionContainer.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { useObservable } from '@lace/common'; +import { useWalletStore } from '@stores'; +import { useCreateAssetList, useCreateMintedAssetList, useTxSummary } from './hooks'; +import { Skeleton } from 'antd'; +import { DappTransaction } from '@lace/core'; +import { TokenInfo } from '@src/utils/get-assets-information'; +import { useAddressBookContext, withAddressBookContext } from '@src/features/address-book/context'; +import { AddressListType } from '@src/views/browser-view/features/activity'; +import { SignTxData } from './types'; +import { useCurrencyStore } from '@providers/currency'; +import { useFetchCoinPrice } from '@hooks'; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export const DappTransactionContainer = withAddressBookContext( + ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { + walletInfo, + inMemoryWallet, + blockchainProvider: { assetProvider }, + walletUI: { cardanoCoin } + } = useWalletStore(); + const currencyStore = useCurrencyStore(); + const coinPrice = useFetchCoinPrice(); + const { list: addressList } = useAddressBookContext() as { list: AddressListType[] }; + const assets = useObservable(inMemoryWallet.assetInfo$); + const createAssetList = useCreateAssetList({ + outputs: signTxData.tx.body.outputs, + assets, + assetProvider + }); + const createMintedAssetList = useCreateMintedAssetList({ + metadata: signTxData.tx.auxiliaryData?.blob, + outputs: signTxData.tx.body.outputs, + mint: signTxData.tx.body.mint, + assets, + assetProvider + }); + const txSummary = useTxSummary({ + addressList, + createAssetList, + createMintedAssetList, + tx: signTxData.tx, + walletInfo + }); + + if (!txSummary) { + return ; + } + + return ( + + ); + } +); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/VotingProceduresContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/VotingProceduresContainer.tsx new file mode 100644 index 000000000..7fb85f611 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/VotingProceduresContainer.tsx @@ -0,0 +1,113 @@ +import React, { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { VotingProcedures } from '@lace/core'; +import { SignTxData } from './types'; +import { drepIDasBech32FromHash, votingProceduresInspector } from './utils'; +import { Wallet } from '@lace/cardano'; +import { useWalletStore } from '@src/stores'; +import { config } from '@src/config'; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export enum VoterType { + CONSTITUTIONAL_COMMITTEE = 'constitutionalCommittee', + SPO = 'spo', + DREP = 'drep' +} + +export const getVoterType = (voterType: Wallet.Cardano.VoterType): VoterType => { + switch (voterType) { + case Wallet.Cardano.VoterType.ccHotKeyHash: + case Wallet.Cardano.VoterType.ccHotScriptHash: + return VoterType.CONSTITUTIONAL_COMMITTEE; + case Wallet.Cardano.VoterType.stakePoolKeyHash: + return VoterType.SPO; + case Wallet.Cardano.VoterType.dRepKeyHash: + case Wallet.Cardano.VoterType.dRepScriptHash: + default: + return VoterType.DREP; + } +}; + +export enum Votes { + YES = 'yes', + NO = 'no', + ABSTAIN = 'abstain' +} + +export const getVote = (vote: Wallet.Cardano.Vote): Votes => { + switch (vote) { + case Wallet.Cardano.Vote.yes: + return Votes.YES; + case Wallet.Cardano.Vote.no: + return Votes.NO; + case Wallet.Cardano.Vote.abstain: + default: + return Votes.ABSTAIN; + } +}; + +export const VotingProceduresContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { t } = useTranslation(); + const votingProcedures = votingProceduresInspector(signTxData.tx); + const { environmentName } = useWalletStore(); + const { CEXPLORER_BASE_URL, CEXPLORER_URL_PATHS } = config(); + + const explorerBaseUrl = useMemo( + () => (environmentName === 'Sanchonet' ? '' : `${CEXPLORER_BASE_URL[environmentName]}/${CEXPLORER_URL_PATHS.Tx}`), + [CEXPLORER_BASE_URL, CEXPLORER_URL_PATHS.Tx, environmentName] + ); + + return ( + { + const voterType = getVoterType(votingProcedure.voter.__typename); + + const drepId = + voterType === VoterType.DREP + ? drepIDasBech32FromHash(votingProcedure.voter.credential.hash) + : votingProcedure.voter.credential.hash.toString(); + return { + voter: { + type: t(`core.votingProcedures.voterType.${voterType}`), + dRepId: drepId + }, + votes: votingProcedure.votes.map((vote) => ({ + actionId: { + index: vote.actionId.actionIndex, + txHash: vote.actionId.id.toString(), + ...(explorerBaseUrl && { txHashUrl: `${explorerBaseUrl}/${vote.actionId.id}` }) + }, + votingProcedure: { + vote: t(`core.votingProcedures.votes.${getVote(vote.votingProcedure.vote)}`), + anchor: !!vote.votingProcedure.anchor?.url && { + url: vote.votingProcedure.anchor?.url, + hash: vote.votingProcedure.anchor?.dataHash.toString() + } + } + })) + }; + })} + translations={{ + voterType: t('core.VotingProcedures.voterType'), + procedureTitle: t('core.VotingProcedures.procedureTitle'), + actionIdTitle: t('core.VotingProcedures.actionIdTitle'), + vote: t('core.VotingProcedures.vote'), + actionId: { + index: t('core.VotingProcedures.actionId.index'), + txHash: t('core.VotingProcedures.actionId.txHash') + }, + anchor: { + hash: t('core.VotingProcedures.anchor.hash'), + url: t('core.VotingProcedures.anchor.url') + }, + dRepId: t('core.VotingProcedures.dRepId') + }} + errorMessage={errorMessage} + /> + ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRegistrationContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRegistrationContainer.test.tsx new file mode 100644 index 000000000..d63017f1e --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRegistrationContainer.test.tsx @@ -0,0 +1,177 @@ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +const mockUseWalletStore = jest.fn(); +const t = jest.fn().mockImplementation((res) => res); +const mockUseTranslation = jest.fn(() => ({ t })); +const mockConfirmDRepRegistration = jest.fn(); +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { ConfirmDRepRegistrationContainer } from '../ConfirmDRepRegistrationContainer'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { act } from 'react-dom/test-utils'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { buildMockTx } from '@src/utils/mocks/tx'; +import { Wallet } from '@lace/cardano'; +import BigNumber from 'bignumber.js'; + +const LOVELACE_VALUE = 1_000_000; +const DEFAULT_DECIMALS = 2; + +const { Cardano, Crypto, HexBlob } = Wallet; + +const assetInfo$ = new BehaviorSubject(new Map()); +const available$ = new BehaviorSubject([]); + +const inMemoryWallet = { + assetInfo$, + balance: { + utxo: { + available$ + } + } +}; + +const cardanoCoinMock = { + symbol: 'cardanoCoinMockSymbol' +}; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); + +jest.mock('@lace/core', () => { + const original = jest.requireActual('@lace/core'); + return { + __esModule: true, + ...original, + ConfirmDRepRegistration: mockConfirmDRepRegistration + }; +}); + +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); + return { + __esModule: true, + ...original, + useTranslation: mockUseTranslation + }; +}); + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + {children} + + + + + + + ); + +describe('Testing ConfirmDRepRegistrationContainer component', () => { + beforeEach(() => { + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + inMemoryWallet, + walletUI: { cardanoCoin: cardanoCoinMock }, + walletInfo: {} + })); + mockConfirmDRepRegistration.mockReset(); + mockConfirmDRepRegistration.mockReturnValue(); + mockUseTranslation.mockReset(); + mockUseTranslation.mockImplementation(() => ({ t })); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('should render ConfirmDRepRegistration component with proper props', async () => { + let queryByTestId: any; + + const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' + }; + const certificate: Wallet.Cardano.Certificate = { + __typename: Cardano.CertificateType.RegisterDelegateRepresentative, + dRepCredential: { + type: Cardano.CredentialType.KeyHash, + hash: Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + }, + deposit: BigInt('1000'), + anchor: { + url: 'anchorUrl', + dataHash: Crypto.Hash32ByteBase16(Buffer.from('anchorDataHashanchorDataHashanch').toString('hex')) + } + }; + const tx = buildMockTx({ + certificates: [certificate] + }); + const errorMessage = 'errorMessage'; + const props = { signTxData: { dappInfo, tx }, errorMessage }; + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('ConfirmDRepRegistration')).toBeInTheDocument(); + expect(mockConfirmDRepRegistration).toHaveBeenLastCalledWith( + { + dappInfo, + metadata: { + depositPaid: `${new BigNumber(certificate.deposit.toString()) + .dividedBy(LOVELACE_VALUE) + .toFixed(DEFAULT_DECIMALS)} ${cardanoCoinMock.symbol}`, + drepId: Cardano.DRepID(HexBlob.toTypedBech32('drep', Wallet.HexBlob(certificate.dRepCredential.hash))), + hash: certificate.anchor?.dataHash, + url: certificate.anchor?.url + }, + translations: { + metadata: t('core.DRepRegistration.metadata'), + labels: { + depositPaid: t('core.DRepRegistration.depositPaid'), + drepId: t('core.DRepRegistration.drepId'), + hash: t('core.DRepRegistration.hash'), + url: t('core.DRepRegistration.url') + } + }, + errorMessage + }, + {} + ); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx new file mode 100644 index 000000000..bb0fe2b21 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx @@ -0,0 +1,220 @@ +/* eslint-disable sonarjs/no-identical-functions */ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +const mockUseWalletStore = jest.fn(); +const t = jest.fn().mockImplementation((res) => res); +const mockUseTranslation = jest.fn(() => ({ t })); +const mockConfirmDRepRetirement = jest.fn(); +const mockPubDRepKeyToHash = jest.fn(); +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { ConfirmDRepRetirementContainer } from '../ConfirmDRepRetirementContainer'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { act } from 'react-dom/test-utils'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { buildMockTx } from '@src/utils/mocks/tx'; +import { Wallet } from '@lace/cardano'; +import BigNumber from 'bignumber.js'; + +const LOVELACE_VALUE = 1_000_000; +const DEFAULT_DECIMALS = 2; + +const { Cardano, Crypto, HexBlob } = Wallet; + +const assetInfo$ = new BehaviorSubject(new Map()); +const available$ = new BehaviorSubject([]); + +const hash = Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')); +const getPubDRepKey = async () => await hash; + +const inMemoryWallet = { + getPubDRepKey, + assetInfo$, + balance: { + utxo: { + available$ + } + } +}; + +const cardanoCoinMock = { + symbol: 'cardanoCoinMockSymbol' +}; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); + +jest.mock('@lace/core', () => { + const original = jest.requireActual('@lace/core'); + return { + __esModule: true, + ...original, + ConfirmDRepRetirement: mockConfirmDRepRetirement + }; +}); + +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); + return { + __esModule: true, + ...original, + useTranslation: mockUseTranslation + }; +}); + +jest.mock('../utils.ts', () => { + const original = jest.requireActual('../utils.ts'); + return { + __esModule: true, + ...original, + pubDRepKeyToHash: mockPubDRepKeyToHash + }; +}); + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + {children} + + + + + + + ); + +describe('Testing ConfirmDRepRetirementContainer component', () => { + beforeEach(() => { + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + inMemoryWallet, + walletUI: { cardanoCoin: cardanoCoinMock }, + walletInfo: {} + })); + mockConfirmDRepRetirement.mockReset(); + mockConfirmDRepRetirement.mockReturnValue(); + mockPubDRepKeyToHash.mockReset(); + mockPubDRepKeyToHash.mockImplementation(async () => await '123'); + mockUseTranslation.mockReset(); + mockUseTranslation.mockImplementation(() => ({ t })); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' + }; + const certificate: Wallet.Cardano.Certificate = { + __typename: Cardano.CertificateType.UnregisterDelegateRepresentative, + dRepCredential: { + type: Cardano.CredentialType.KeyHash, + hash + }, + deposit: BigInt('1000') + }; + const tx = buildMockTx({ + certificates: [certificate] + }); + const errorMessage = 'errorMessage'; + + test('should render ConfirmDRepRetirementContainer component with proper props', async () => { + let queryByTestId: any; + await act(async () => { + ({ queryByTestId } = render( + , + { + wrapper: getWrapper() + } + )); + }); + + expect(queryByTestId('ConfirmDRepRetirementContainer')).toBeInTheDocument(); + expect(mockConfirmDRepRetirement).toHaveBeenLastCalledWith( + { + dappInfo, + metadata: { + depositReturned: `${new BigNumber(certificate.deposit.toString()) + .dividedBy(LOVELACE_VALUE) + .toFixed(DEFAULT_DECIMALS)} ${cardanoCoinMock.symbol}`, + drepId: Cardano.DRepID(HexBlob.toTypedBech32('drep', Wallet.HexBlob(certificate.dRepCredential.hash))) + }, + translations: { + metadata: t('core.DRepRetirement.metadata'), + labels: { + depositReturned: t('core.DRepRetirement.depositReturned'), + drepId: t('core.DRepRetirement.drepId') + } + }, + errorMessage + }, + {} + ); + }); + + test('should render ConfirmDRepRetirementContainer component with proper error for own retirement', async () => { + mockPubDRepKeyToHash.mockReset(); + mockPubDRepKeyToHash.mockImplementation(async (_hash) => await _hash); + let queryByTestId: any; + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('ConfirmDRepRetirementContainer')).toBeInTheDocument(); + expect( + mockConfirmDRepRetirement.mock.calls[mockConfirmDRepRetirement.mock.calls.length - 1][0].errorMessage + ).toEqual(t('core.DRepRetirement.isOwnRetirement')); + }); + + test('should render ConfirmDRepRetirementContainer component with proper error for not own retirement', async () => { + mockPubDRepKeyToHash.mockReset(); + mockPubDRepKeyToHash.mockImplementation(async () => await ''); + let queryByTestId: any; + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('ConfirmDRepRetirementContainer')).toBeInTheDocument(); + + expect( + mockConfirmDRepRetirement.mock.calls[mockConfirmDRepRetirement.mock.calls.length - 1][0].errorMessage + ).toEqual(t('core.DRepRetirement.isNotOwnRetirement')); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepUpdateContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepUpdateContainer.test.tsx new file mode 100644 index 000000000..eba21c333 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepUpdateContainer.test.tsx @@ -0,0 +1,168 @@ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +const mockUseWalletStore = jest.fn(); +const t = jest.fn().mockImplementation((res) => res); +const mockUseTranslation = jest.fn(() => ({ t })); +const mockConfirmDRepUpdate = jest.fn(); +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { ConfirmDRepUpdateContainer } from '../ConfirmDRepUpdateContainer'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { act } from 'react-dom/test-utils'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { buildMockTx } from '@src/utils/mocks/tx'; +import { Wallet } from '@lace/cardano'; + +const { Cardano, Crypto, HexBlob } = Wallet; + +const assetInfo$ = new BehaviorSubject(new Map()); +const available$ = new BehaviorSubject([]); + +const inMemoryWallet = { + assetInfo$, + balance: { + utxo: { + available$ + } + } +}; + +const cardanoCoinMock = { + symbol: 'cardanoCoinMockSymbol' +}; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); + +jest.mock('@lace/core', () => { + const original = jest.requireActual('@lace/core'); + return { + __esModule: true, + ...original, + ConfirmDRepUpdate: mockConfirmDRepUpdate + }; +}); + +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); + return { + __esModule: true, + ...original, + useTranslation: mockUseTranslation + }; +}); + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + {children} + + + + + + + ); + +describe('Testing ConfirmDRepUpdateContainer component', () => { + beforeEach(() => { + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + inMemoryWallet, + walletUI: { cardanoCoin: cardanoCoinMock }, + walletInfo: {} + })); + mockConfirmDRepUpdate.mockReset(); + mockConfirmDRepUpdate.mockReturnValue(); + mockUseTranslation.mockReset(); + mockUseTranslation.mockImplementation(() => ({ t })); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('should render ConfirmDRepUpdate component with proper props', async () => { + let queryByTestId: any; + + const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' + }; + const certificate: Wallet.Cardano.Certificate = { + __typename: Cardano.CertificateType.UpdateDelegateRepresentative, + dRepCredential: { + type: Cardano.CredentialType.KeyHash, + hash: Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + }, + anchor: { + url: 'anchorUrl', + dataHash: Crypto.Hash32ByteBase16(Buffer.from('anchorDataHashanchorDataHashanch').toString('hex')) + } + }; + const tx = buildMockTx({ + certificates: [certificate] + }); + const errorMessage = 'errorMessage'; + const props = { signTxData: { dappInfo, tx }, errorMessage }; + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('ConfirmDRepUpdate')).toBeInTheDocument(); + expect(mockConfirmDRepUpdate).toHaveBeenLastCalledWith( + { + dappInfo, + metadata: { + drepId: Cardano.DRepID(HexBlob.toTypedBech32('drep', Wallet.HexBlob(certificate.dRepCredential.hash))), + hash: certificate.anchor?.dataHash, + url: certificate.anchor?.url + }, + translations: { + metadata: t('core.DRepUpdate.metadata'), + labels: { + drepId: t('core.DRepUpdate.drepId'), + hash: t('core.DRepUpdate.hash'), + url: t('core.DRepUpdate.url') + } + }, + errorMessage + }, + {} + ); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx new file mode 100644 index 000000000..351276597 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx @@ -0,0 +1,306 @@ +/* eslint-disable max-statements */ +/* eslint-disable sonarjs/no-identical-functions */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +const mockGetKeyAgentType = jest.fn(); +const mockUseWalletStore = jest.fn(); +const error = 'error in getSignTxData'; +const mockConsumeRemoteApi = jest.fn(); +const mockConfirmTransactionContent = jest.fn(() => ); +const mockGetTitleKey = jest.fn(); +const mockGetTxType = jest.fn(); +const mockUseDisallowSignTx = jest.fn(); +const mockUseViewsFlowContext = jest.fn(); +const mockUseSignWithHardwareWallet = jest.fn(); +const mockUseOnBeforeUnload = jest.fn(); +const mockCreateTxInspector = jest.fn().mockReturnValue(() => ({ minted: [] as any, burned: [] as any })); +import * as React from 'react'; +import { cleanup, render, act, fireEvent } from '@testing-library/react'; +import { ConfirmTransaction } from '../ConfirmTransaction'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider, + ViewFlowProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { sendViewsFlowState } from '../../../config'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { Wallet } from '@lace/cardano'; + +const assetInfo$ = new BehaviorSubject(new Map()); +const available$ = new BehaviorSubject([]); + +const assetProvider = { + getAsset: () => ({}), + getAssets: (): any[] => [] +}; +const inMemoryWallet = { + assetInfo$, + balance: { + utxo: { + available$ + } + } +}; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); + +jest.mock('@cardano-sdk/web-extension', () => { + const original = jest.requireActual('@cardano-sdk/web-extension'); + return { + __esModule: true, + ...original, + consumeRemoteApi: mockConsumeRemoteApi + }; +}); + +jest.mock('@cardano-sdk/core', () => { + const original = jest.requireActual('@cardano-sdk/core'); + return { + __esModule: true, + ...original, + createTxInspector: mockCreateTxInspector + }; +}); + +jest.mock('@lace/common', () => { + const original = jest.requireActual('@lace/common'); + return { + __esModule: true, + ...original, + useSearchParams: () => ({}) + }; +}); + +jest.mock('../ConfirmTransactionContent', () => { + const original = jest.requireActual('../ConfirmTransactionContent'); + return { + __esModule: true, + ...original, + ConfirmTransactionContent: mockConfirmTransactionContent + }; +}); + +jest.mock('../utils.ts', () => { + const original = jest.requireActual('../utils.ts'); + return { + __esModule: true, + ...original, + getTitleKey: mockGetTitleKey, + getTxType: mockGetTxType + }; +}); + +jest.mock('../hooks.ts', () => { + const original = jest.requireActual('../hooks.ts'); + return { + __esModule: true, + ...original, + useDisallowSignTx: mockUseDisallowSignTx, + useSignWithHardwareWallet: mockUseSignWithHardwareWallet, + useOnBeforeUnload: mockUseOnBeforeUnload + }; +}); + +jest.mock('@providers/ViewFlowProvider', () => { + const original = jest.requireActual('@providers/ViewFlowProvider'); + return { + __esModule: true, + ...original, + useViewsFlowContext: mockUseViewsFlowContext + }; +}); + +const testIds = { + dappTransactionConfirm: 'dapp-transaction-confirm', + layoutTitle: 'layout-title', + dappTransactionCancel: 'dapp-transaction-cancel' +}; + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + + {children} + + + + + + + + ); + +describe('Testing ConfirmTransaction component', () => { + window.ResizeObserver = ResizeObserver; + + beforeEach(() => { + mockUseSignWithHardwareWallet.mockReset(); + mockUseSignWithHardwareWallet.mockReturnValue({}); + mockUseViewsFlowContext.mockReset(); + mockUseViewsFlowContext.mockReturnValue({ utils: {} }); + mockConfirmTransactionContent.mockReset(); + mockConfirmTransactionContent.mockImplementation(() => ); + mockConfirmTransactionContent.mockReset(); + mockConfirmTransactionContent.mockImplementation(() => ); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('Should render proper state for inMemory wallet', async () => { + let queryByTestId: any; + + const txType = 'txType'; + mockGetKeyAgentType.mockReset(); + mockGetKeyAgentType.mockReturnValue(Wallet.KeyManagement.KeyAgentType.InMemory); + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + })); + mockGetTxType.mockReset(); + mockGetTxType.mockReturnValue(txType); + mockGetTitleKey.mockReset(); + mockGetTitleKey.mockImplementation((val) => val); + + const signTxData = { tx: { id: 'test-tx-id' } }; + mockConsumeRemoteApi.mockReset(); + mockConsumeRemoteApi.mockReturnValue({ + getSignTxData: async () => await Promise.resolve(signTxData) + }); + const disallowSignTx = jest.fn(); + mockUseDisallowSignTx.mockReset(); + mockUseDisallowSignTx.mockReturnValue(disallowSignTx); + const setNextViewMock = jest.fn(); + mockUseViewsFlowContext.mockReset(); + mockUseViewsFlowContext.mockReturnValue({ utils: { setNextView: setNextViewMock } }); + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId(testIds.layoutTitle)).toHaveTextContent(txType); + expect(queryByTestId('ConfirmTransactionContent')).toBeInTheDocument(); + expect(mockConfirmTransactionContent).toHaveBeenLastCalledWith( + { + txType, + signTxData + }, + {} + ); + expect(mockUseOnBeforeUnload).toHaveBeenCalledWith(disallowSignTx); + expect(queryByTestId(testIds.dappTransactionConfirm)).toHaveTextContent('Confirm'); + expect(queryByTestId(testIds.dappTransactionConfirm)).not.toBeDisabled(); + expect(queryByTestId(testIds.dappTransactionCancel)).toHaveTextContent('Cancel'); + + await act(async () => { + fireEvent.click(queryByTestId(testIds.dappTransactionCancel)); + }); + + expect(disallowSignTx).toHaveBeenCalledWith(true); + + await act(async () => { + fireEvent.click(queryByTestId(testIds.dappTransactionConfirm)); + }); + + expect(setNextViewMock).toHaveBeenCalled(); + }); + + test('Should render proper state for hardware wallet', async () => { + let queryByTestId: any; + + mockGetKeyAgentType.mockReset(); + mockGetKeyAgentType.mockReturnValue(Wallet.KeyManagement.KeyAgentType.Ledger); + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + })); + + const signTxData = { tx: { id: 'test-tx-id' } }; + mockConsumeRemoteApi.mockReset(); + mockConsumeRemoteApi.mockReturnValue({ + getSignTxData: async () => await Promise.resolve(signTxData) + }); + const signWithHardwareWalletMock = jest.fn(); + mockUseSignWithHardwareWallet.mockReset(); + mockUseSignWithHardwareWallet.mockReturnValue({ signWithHardwareWallet: signWithHardwareWalletMock }); + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId(testIds.dappTransactionConfirm)).toHaveTextContent('Confirm with Ledger'); + + await act(async () => { + fireEvent.click(queryByTestId(testIds.dappTransactionConfirm)); + }); + + expect(signWithHardwareWalletMock).toHaveBeenCalled(); + }); + + test('should disable confirm button and show proper error if getSignTxData throws', async () => { + let queryByTestId: any; + const txType = 'txType'; + mockUseWalletStore.mockImplementation(() => ({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + })); + mockConsumeRemoteApi.mockReset(); + mockConsumeRemoteApi.mockReturnValue({ + getSignTxData: async () => await Promise.reject(error) + }); + mockGetTxType.mockReset(); + mockGetTxType.mockReturnValue(txType); + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('ConfirmTransactionContent')).toBeInTheDocument(); + expect(mockConfirmTransactionContent).toHaveBeenLastCalledWith({ errorMessage: error }, {}); + expect(queryByTestId(testIds.dappTransactionConfirm).closest('button')).toHaveAttribute('disabled'); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransactionContent.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransactionContent.test.tsx new file mode 100644 index 000000000..c2ad9259a --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransactionContent.test.tsx @@ -0,0 +1,226 @@ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +import { Wallet } from '@lace/cardano'; + +const mockSkeleton = jest.fn(() => ); +const mockConfirmDRepRegistrationContainer = jest.fn(() => ); +const mockConfirmDRepRetirementContainer = jest.fn(() => ); +const mockConfirmDRepUpdateContainer = jest.fn(() => ); +const mockConfirmVoteDelegationContainer = jest.fn(() => ); +const mockVotingProceduresContainer = jest.fn(() => ); +const mockDappTransactionContainer = jest.fn(() => ); +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { ConfirmTransactionContent } from '../ConfirmTransactionContent'; +import '@testing-library/jest-dom'; +import { act } from 'react-dom/test-utils'; +import { buildMockTx } from '@src/utils/mocks/tx'; + +jest.mock('antd', () => { + const original = jest.requireActual('antd'); + return { + __esModule: true, + ...original, + Skeleton: mockSkeleton + }; +}); + +jest.mock('../ConfirmDRepRegistrationContainer', () => { + const original = jest.requireActual('../ConfirmDRepRegistrationContainer'); + return { + __esModule: true, + ...original, + ConfirmDRepRegistrationContainer: mockConfirmDRepRegistrationContainer + }; +}); + +jest.mock('../ConfirmDRepRetirementContainer', () => { + const original = jest.requireActual('../ConfirmDRepRetirementContainer'); + return { + __esModule: true, + ...original, + ConfirmDRepRetirementContainer: mockConfirmDRepRetirementContainer + }; +}); + +jest.mock('../ConfirmDRepUpdateContainer', () => { + const original = jest.requireActual('../ConfirmDRepUpdateContainer'); + return { + __esModule: true, + ...original, + ConfirmDRepUpdateContainer: mockConfirmDRepUpdateContainer + }; +}); + +jest.mock('../ConfirmVoteDelegationContainer', () => { + const original = jest.requireActual('../ConfirmVoteDelegationContainer'); + return { + __esModule: true, + ...original, + ConfirmVoteDelegationContainer: mockConfirmVoteDelegationContainer + }; +}); + +jest.mock('../VotingProceduresContainer', () => { + const original = jest.requireActual('../VotingProceduresContainer'); + return { + __esModule: true, + ...original, + VotingProceduresContainer: mockVotingProceduresContainer + }; +}); + +jest.mock('../DappTransactionContainer', () => { + const original = jest.requireActual('../DappTransactionContainer'); + return { + __esModule: true, + ...original, + DappTransactionContainer: mockDappTransactionContainer + }; +}); + +const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' +}; +const errorMessage = 'errorMessage'; +const props = { signTxData: { dappInfo, tx: buildMockTx() }, errorMessage }; + +describe('Testing ConfirmTransactionContent component', () => { + afterEach(() => { + cleanup(); + }); + + test('should render loader placeholder if there is no signTxData', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render()); + }); + + expect(queryByTestId('skeleton')).toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).not.toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).not.toBeInTheDocument(); + expect(mockSkeleton).toHaveBeenLastCalledWith({ loading: true }, {}); + }); + + test('should render ConfirmDRepRegistrationContainer with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render( + + )); + }); + + expect(queryByTestId('skeleton')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).not.toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).not.toBeInTheDocument(); + expect(mockConfirmDRepRegistrationContainer).toHaveBeenLastCalledWith(props, {}); + }); + + test('should render ConfirmDRepRetirementContainer with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render( + + )); + }); + + expect(queryByTestId('skeleton')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).not.toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).not.toBeInTheDocument(); + expect(mockConfirmDRepRetirementContainer).toHaveBeenLastCalledWith(props, {}); + }); + + test('should render ConfirmDRepUpdateContainer with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render( + + )); + }); + + expect(queryByTestId('skeleton')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).not.toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).not.toBeInTheDocument(); + expect(mockConfirmDRepUpdateContainer).toHaveBeenLastCalledWith(props, {}); + }); + + test('should render ConfirmVoteDelegationContainer with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render( + + )); + }); + + expect(queryByTestId('skeleton')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).not.toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).not.toBeInTheDocument(); + expect(mockConfirmVoteDelegationContainer).toHaveBeenLastCalledWith(props, {}); + }); + + test('should render VotingProceduresContainer with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render( + + )); + }); + + expect(queryByTestId('skeleton')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).not.toBeInTheDocument(); + expect(mockVotingProceduresContainer).toHaveBeenLastCalledWith(props, {}); + }); + + test('should render DappTransactionContainer with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render( + + )); + }); + + expect(queryByTestId('skeleton')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRegistrationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepRetirementContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmDRepUpdateContainer')).not.toBeInTheDocument(); + expect(queryByTestId('ConfirmVoteDelegationContainer')).not.toBeInTheDocument(); + expect(queryByTestId('VotingProceduresContainer')).not.toBeInTheDocument(); + expect(queryByTestId('DappTransactionContainer')).toBeInTheDocument(); + expect(mockDappTransactionContainer).toHaveBeenLastCalledWith(props, {}); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmVoteDelegationContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmVoteDelegationContainer.test.tsx new file mode 100644 index 000000000..dadcfafa2 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmVoteDelegationContainer.test.tsx @@ -0,0 +1,216 @@ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +const mockUseWalletStore = jest.fn(); +const t = jest.fn().mockImplementation((res) => res); +const mockUseTranslation = jest.fn(() => ({ t })); +const mockConfirmVoteDelegation = jest.fn(); +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { ConfirmVoteDelegationContainer } from '../ConfirmVoteDelegationContainer'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { act } from 'react-dom/test-utils'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { buildMockTx } from '@src/utils/mocks/tx'; +import { Wallet } from '@lace/cardano'; + +const REWARD_ACCOUNT = Wallet.Cardano.RewardAccount('stake_test1uqrw9tjymlm8wrwq7jk68n6v7fs9qz8z0tkdkve26dylmfc2ux2hj'); +const STAKE_KEY_HASH = Wallet.Cardano.RewardAccount.toHash(REWARD_ACCOUNT); + +const assetInfo$ = new BehaviorSubject(new Map()); +const available$ = new BehaviorSubject([]); + +const inMemoryWallet = { + assetInfo$, + balance: { + utxo: { + available$ + } + } +}; + +const cardanoCoinMock = { + symbol: 'cardanoCoinMockSymbol' +}; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); + +jest.mock('@lace/core', () => { + const original = jest.requireActual('@lace/core'); + return { + __esModule: true, + ...original, + ConfirmVoteDelegation: mockConfirmVoteDelegation + }; +}); + +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); + return { + __esModule: true, + ...original, + useTranslation: mockUseTranslation + }; +}); + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + {children} + + + + + + + ); + +describe('Testing ConfirmVoteDelegationContainer component', () => { + beforeEach(() => { + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + inMemoryWallet, + walletUI: { cardanoCoin: cardanoCoinMock }, + walletInfo: {} + })); + mockConfirmVoteDelegation.mockReset(); + mockConfirmVoteDelegation.mockReturnValue(); + mockUseTranslation.mockReset(); + mockUseTranslation.mockImplementation(() => ({ t })); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('should render ConfirmVoteDelegation component with proper props', async () => { + let queryByTestId: any; + let rerender: any; + + const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' + }; + const certificate: Wallet.Cardano.Certificate = { + __typename: Wallet.Cardano.CertificateType.VoteDelegation, + dRep: { + type: Wallet.Cardano.CredentialType.KeyHash, + hash: Wallet.Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + }, + stakeKeyHash: STAKE_KEY_HASH + }; + const tx = buildMockTx({ + certificates: [certificate] + }); + const errorMessage = 'errorMessage'; + const props = { signTxData: { dappInfo, tx }, errorMessage }; + const dRep = certificate.dRep; + + await act(async () => { + ({ rerender, queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('ConfirmVoteDelegation')).toBeInTheDocument(); + expect(mockConfirmVoteDelegation).toHaveBeenLastCalledWith( + { + dappInfo, + metadata: { + alwaysAbstain: false, + alwaysNoConfidence: false, + drepId: Wallet.Cardano.DRepID( + Wallet.HexBlob.toTypedBech32('drep', Wallet.HexBlob((dRep as unknown as Wallet.Cardano.Credential).hash)) + ) + }, + translations: { + metadata: t('core.VoteDelegation.metadata'), + option: t('core.VoteDelegation.option'), + labels: { + drepId: t('core.VoteDelegation.drepId'), + alwaysAbstain: t('core.VoteDelegation.alwaysAbstain'), + alwaysNoConfidence: t('core.VoteDelegation.alwaysNoConfidence') + } + }, + errorMessage + }, + {} + ); + + await act(async () => { + rerender( + , + { + wrapper: getWrapper() + } + ); + }); + expect(mockConfirmVoteDelegation.mock.calls[mockConfirmVoteDelegation.mock.calls.length - 1][0].metadata).toEqual({ + alwaysAbstain: true, + alwaysNoConfidence: false + }); + await act(async () => { + rerender( + , + { + wrapper: getWrapper() + } + ); + }); + expect(mockConfirmVoteDelegation.mock.calls[mockConfirmVoteDelegation.mock.calls.length - 1][0].metadata).toEqual({ + alwaysAbstain: false, + alwaysNoConfidence: true + }); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx new file mode 100644 index 000000000..4f58f3f93 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/DappTransactionContainer.test.tsx @@ -0,0 +1,258 @@ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +import * as CurrencyProvider from '@providers/currency'; +import * as UseFetchCoinPrice from '@hooks/useFetchCoinPrice'; + +const mockSkeleton = jest.fn(() => ); +const mockUseWalletStore = jest.fn(); +const t = jest.fn().mockImplementation((res) => res); +const mockUseTranslation = jest.fn(() => ({ t })); +const mockDappTransaction = jest.fn(); +const mockUseTxSummary = jest.fn(); +const mockUseCreateAssetList = jest.fn(); +const mockUseCreateMintedAssetList = jest.fn(); +const mockWithAddressBookContext = jest.fn((children) => children); +const mockUseCurrencyStore = jest.fn().mockReturnValue({ fiatCurrency: { code: 'usd', symbol: '$' } }); +const mockUseFetchCoinPrice = jest.fn().mockReturnValue({ priceResult: { cardano: { price: 2 }, tokens: new Map() } }); +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { DappTransactionContainer } from '../DappTransactionContainer'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { act } from 'react-dom/test-utils'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { buildMockTx } from '@src/utils/mocks/tx'; +import { Wallet } from '@lace/cardano'; +import { SignTxData } from '../types'; + +const { Cardano, Crypto } = Wallet; + +const assetProvider = 'assetProvider'; +const walletInfo = 'walletInfo'; +const mockedAssetsInfo = new Map([['id', 'data']]); +const assetInfo$ = new BehaviorSubject(mockedAssetsInfo); +const available$ = new BehaviorSubject([]); + +const inMemoryWallet = { + assetInfo$, + balance: { + utxo: { + available$ + } + } +}; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); +jest.mock('@hooks/useFetchCoinPrice', (): typeof UseFetchCoinPrice => ({ + ...jest.requireActual('@hooks/useFetchCoinPrice'), + useFetchCoinPrice: mockUseFetchCoinPrice +})); +jest.mock('@providers/currency', (): typeof CurrencyProvider => ({ + ...jest.requireActual('@providers/currency'), + useCurrencyStore: mockUseCurrencyStore +})); + +jest.mock('@lace/core', () => { + const original = jest.requireActual('@lace/core'); + return { + __esModule: true, + ...original, + DappTransaction: mockDappTransaction + }; +}); + +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); + return { + __esModule: true, + ...original, + useTranslation: mockUseTranslation + }; +}); + +jest.mock('../hooks.ts', () => { + const original = jest.requireActual('../hooks.ts'); + return { + __esModule: true, + ...original, + useTxSummary: mockUseTxSummary, + useCreateAssetList: mockUseCreateAssetList, + useCreateMintedAssetList: mockUseCreateMintedAssetList + }; +}); + +const addressList = 'addressList'; +jest.mock('@src/features/address-book/context', () => ({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...jest.requireActual('@src/features/address-book/context'), + withAddressBookContext: mockWithAddressBookContext, + useAddressBookContext: () => ({ list: addressList }) +})); + +jest.mock('antd', () => { + const original = jest.requireActual('antd'); + return { + __esModule: true, + ...original, + Skeleton: mockSkeleton + }; +}); + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + {children} + + + + + + + ); + +describe('Testing DappTransactionContainer component', () => { + beforeEach(() => { + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + inMemoryWallet, + blockchainProvider: { assetProvider }, + walletInfo, + walletUI: { cardanoCoin: {} } + })); + mockDappTransaction.mockReset(); + mockDappTransaction.mockReturnValue(); + mockUseTranslation.mockReset(); + mockUseTranslation.mockImplementation(() => ({ t })); + mockWithAddressBookContext.mockReset(); + mockWithAddressBookContext.mockImplementation((children) => children); + mockSkeleton.mockReset(); + mockSkeleton.mockImplementation(() => ); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('should render DappTransaction component with proper props', async () => { + let queryByTestId: any; + + const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' + }; + const certificate: Wallet.Cardano.Certificate = { + __typename: Cardano.CertificateType.RegisterDelegateRepresentative, + dRepCredential: { + type: Cardano.CredentialType.KeyHash, + hash: Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + }, + deposit: BigInt('1000'), + anchor: { + url: 'anchorUrl', + dataHash: Crypto.Hash32ByteBase16(Buffer.from('anchorDataHashanchorDataHashanch').toString('hex')) + } + }; + const tx = buildMockTx({ + certificates: [certificate] + }); + const errorMessage = 'errorMessage'; + const props = { signTxData: { dappInfo, tx }, errorMessage }; + + const txSummary = 'txSummary'; + mockUseTxSummary.mockReset(); + mockUseTxSummary.mockReturnValue(txSummary); + const createAssetList = 'createAssetList'; + mockUseCreateAssetList.mockReset(); + mockUseCreateAssetList.mockReturnValue(createAssetList); + const createMintedAssetList = 'createMintedAssetList'; + mockUseCreateMintedAssetList.mockReset(); + mockUseCreateMintedAssetList.mockReturnValue(createMintedAssetList); + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('DappTransaction')).toBeInTheDocument(); + expect(mockUseCreateAssetList).toHaveBeenLastCalledWith({ + outputs: props.signTxData.tx.body.outputs, + assets: mockedAssetsInfo, + assetProvider + }); + expect(mockUseCreateMintedAssetList).toHaveBeenLastCalledWith({ + outputs: props.signTxData.tx.body.outputs, + assets: mockedAssetsInfo, + assetProvider, + metadata: props.signTxData.tx.auxiliaryData.blob, + mint: props.signTxData.tx.body.mint + }); + expect(mockUseTxSummary).toHaveBeenLastCalledWith({ + addressList, + createAssetList, + createMintedAssetList, + tx: props.signTxData.tx, + walletInfo + }); + expect(mockDappTransaction).toHaveBeenLastCalledWith( + { + dappInfo, + transaction: txSummary, + fiatCurrencyCode: 'usd', + fiatCurrencyPrice: 2, + errorMessage + }, + {} + ); + }); + + test('should render loader in case there is no txSummary', async () => { + let queryByTestId: any; + + mockUseTxSummary.mockReset(); + mockUseTxSummary.mockReturnValue(null); + mockUseCurrencyStore.mockRestore(); + + const signTxData = { tx: { body: {} } } as unknown as SignTxData; + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('DappTransaction')).not.toBeInTheDocument(); + expect(queryByTestId('skeleton')).toBeInTheDocument(); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/VotingProceduresContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/VotingProceduresContainer.test.tsx new file mode 100644 index 000000000..00a65675c --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/VotingProceduresContainer.test.tsx @@ -0,0 +1,294 @@ +/* eslint-disable sonarjs/no-identical-functions */ +/* eslint-disable unicorn/consistent-destructuring */ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +const mockUseWalletStore = jest.fn(); +const t = jest.fn().mockImplementation((res) => res); +const mockUseTranslation = jest.fn(() => ({ t })); +const mockVotingProcedures = jest.fn(); +const mockPreprodCexplorerBaseUrl = 'PREPROD_CEXPLORER_BASE_URL'; +const mockCexplorerUrlPathsTx = 'CEXPLORER_URL_PATHS.TX'; +import * as React from 'react'; +import { cleanup, render } from '@testing-library/react'; +import { VoterType, Votes, VotingProceduresContainer, getVote, getVoterType } from '../VotingProceduresContainer'; +import '@testing-library/jest-dom'; +import { I18nextProvider } from 'react-i18next'; +import { StoreProvider } from '@src/stores'; +import { + AnalyticsProvider, + AppSettingsProvider, + BackgroundServiceAPIProvider, + BackgroundServiceAPIProviderProps, + DatabaseProvider +} from '@src/providers'; +import { APP_MODE_BROWSER } from '@src/utils/constants'; +import i18n from '@lib/i18n'; +import { act } from 'react-dom/test-utils'; +import { PostHogClientProvider } from '@providers/PostHogClientProvider'; +import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; +import { buildMockTx } from '@src/utils/mocks/tx'; +import { Wallet } from '@lace/cardano'; + +jest.mock('@src/stores', () => ({ + ...jest.requireActual('@src/stores'), + useWalletStore: mockUseWalletStore +})); + +jest.mock('@src/config', () => { + const original = jest.requireActual('@src/config'); + return { + ...original, + config: () => ({ + ...original.config(), + CEXPLORER_BASE_URL: { Preprod: mockPreprodCexplorerBaseUrl }, + CEXPLORER_URL_PATHS: { Tx: mockCexplorerUrlPathsTx } + }) + }; +}); + +jest.mock('@lace/core', () => { + const original = jest.requireActual('@lace/core'); + return { + __esModule: true, + ...original, + VotingProcedures: mockVotingProcedures + }; +}); + +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); + return { + __esModule: true, + ...original, + useTranslation: mockUseTranslation + }; +}); + +const backgroundService = { + getBackgroundStorage: jest.fn(), + setBackgroundStorage: jest.fn() +} as unknown as BackgroundServiceAPIProviderProps['value']; + +const getWrapper = + () => + ({ children }: { children: React.ReactNode }) => + ( + + + + + + + {children} + + + + + + + ); + +describe('Testing VotingProceduresContainer component', () => { + beforeEach(() => { + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + environmentName: 'Preprod' + })); + mockVotingProcedures.mockReset(); + mockVotingProcedures.mockReturnValue(); + mockUseTranslation.mockReset(); + mockUseTranslation.mockImplementation(() => ({ t })); + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + const dappInfo = { + name: 'dappName', + logo: 'dappLogo', + url: 'dappUrl' + }; + const tx = buildMockTx(); + const errorMessage = 'errorMessage'; + const constitutionalCommitteeKeyHashVoter: Wallet.Cardano.ConstitutionalCommitteeKeyHashVoter = { + __typename: Wallet.Cardano.VoterType.ccHotKeyHash, + credential: { + type: Wallet.Cardano.CredentialType.KeyHash, + hash: Wallet.Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + } + }; + const constitutionalCommitteeScriptHashVoter: Wallet.Cardano.ConstitutionalCommitteeScriptHashVoter = { + __typename: Wallet.Cardano.VoterType.ccHotScriptHash, + credential: { + type: Wallet.Cardano.CredentialType.ScriptHash, + hash: Wallet.Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + } + }; + const drepKeyHashVoter: Wallet.Cardano.DrepKeyHashVoter = { + __typename: Wallet.Cardano.VoterType.dRepKeyHash, + credential: { + type: Wallet.Cardano.CredentialType.KeyHash, + hash: Wallet.Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + } + }; + const drepScriptHashVoter: Wallet.Cardano.DrepScriptHashVoter = { + __typename: Wallet.Cardano.VoterType.dRepScriptHash, + credential: { + type: Wallet.Cardano.CredentialType.ScriptHash, + hash: Wallet.Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + } + }; + const stakePoolKeyHashVoter: Wallet.Cardano.StakePoolKeyHashVoter = { + __typename: Wallet.Cardano.VoterType.stakePoolKeyHash, + credential: { + type: Wallet.Cardano.CredentialType.KeyHash, + hash: Wallet.Crypto.Hash28ByteBase16(Buffer.from('dRepCredentialHashdRepCreden').toString('hex')) + } + }; + + const voters = [ + constitutionalCommitteeKeyHashVoter, + constitutionalCommitteeScriptHashVoter, + drepKeyHashVoter, + drepScriptHashVoter, + stakePoolKeyHashVoter + ]; + + const votes = [ + Wallet.Cardano.Vote.yes, + Wallet.Cardano.Vote.no, + Wallet.Cardano.Vote.abstain, + Wallet.Cardano.Vote.yes, + Wallet.Cardano.Vote.no + ]; + + const votingProcedures = voters.map((voter, index) => ({ + voter, + votes: [ + { + actionId: { + id: Wallet.Cardano.TransactionId(`724a0a88b9470a714fc5bf84daf5851fa259a9b89e1a5453f6f5cd6595ad982${index}`), + actionIndex: 0 + }, + votingProcedure: { + vote: votes[index], + ...(index && { + anchor: { + url: `anchorUrl${index}`, + dataHash: Wallet.Crypto.Hash32ByteBase16( + Buffer.from(`anchorDataHashanchorDataHashanc${index}`).toString('hex') + ) + } + }) + } + } + ] + })); + + const props = { signTxData: { dappInfo, tx: { ...tx, body: { ...tx.body, votingProcedures } } }, errorMessage }; + + test('should render VotingProcedures component with proper props', async () => { + let queryByTestId: any; + + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('VotingProcedures')).toBeInTheDocument(); + // eslint-disable-next-line unicorn/consistent-function-scoping + const getExpectedDrepId = (type: string) => (hash: Wallet.Crypto.Hash28ByteBase16) => + type === VoterType.DREP + ? Wallet.Cardano.DRepID(Wallet.HexBlob.toTypedBech32('drep', Wallet.HexBlob(hash))) + : hash.toString(); + expect(mockVotingProcedures).toHaveBeenLastCalledWith( + { + dappInfo, + data: voters.map(({ __typename }, index) => ({ + voter: { + type: t(`core.votingProcedures.voterType.${getVoterType(__typename)}`), + dRepId: getExpectedDrepId(getVoterType(__typename))(voters[index].credential.hash) + }, + votes: votingProcedures[index].votes.map((vote) => ({ + actionId: { + index: vote.actionId.actionIndex, + txHash: vote.actionId.id.toString(), + txHashUrl: `${mockPreprodCexplorerBaseUrl}/${mockCexplorerUrlPathsTx}/${vote.actionId.id}` + }, + votingProcedure: { + vote: t(`core.votingProcedures.votes.${getVote(vote.votingProcedure.vote)}`), + anchor: !!vote.votingProcedure.anchor?.url && { + url: vote.votingProcedure.anchor?.url, + hash: vote.votingProcedure.anchor?.dataHash.toString() + } + } + })) + })), + translations: { + voterType: t('core.VotingProcedures.voterType'), + procedureTitle: t('core.VotingProcedures.procedureTitle'), + actionIdTitle: t('core.VotingProcedures.actionIdTitle'), + vote: t('core.VotingProcedures.vote'), + actionId: { + index: t('core.VotingProcedures.actionId.index'), + txHash: t('core.VotingProcedures.actionId.txHash') + }, + anchor: { + hash: t('core.VotingProcedures.anchor.hash'), + url: t('core.VotingProcedures.anchor.url') + }, + dRepId: t('core.VotingProcedures.dRepId') + }, + errorMessage + }, + {} + ); + }); + + test('should render VotingProcedures with no txHashUrl for Sanchonet network', async () => { + let queryByTestId: any; + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockImplementation(() => ({ + environmentName: 'Sanchonet' + })); + await act(async () => { + ({ queryByTestId } = render(, { + wrapper: getWrapper() + })); + }); + + expect(queryByTestId('VotingProcedures')).toBeInTheDocument(); + const lastCockVotingProceduresCallParams = + mockVotingProcedures.mock.calls[mockVotingProcedures.mock.calls.length - 1][0]; + + let txHashUrls: Array = []; + + for (const data of lastCockVotingProceduresCallParams.data) { + txHashUrls = [ + ...txHashUrls, + ...data.votes.map(({ actionId: { txHashUrl } }: { actionId: { txHashUrl?: string } }) => txHashUrl) + ]; + } + + expect(txHashUrls.filter((e) => !!e).length).toEqual(0); + }); + + test('testing getVoterType', () => { + expect(getVoterType(constitutionalCommitteeKeyHashVoter.__typename)).toEqual(VoterType.CONSTITUTIONAL_COMMITTEE); + expect(getVoterType(constitutionalCommitteeScriptHashVoter.__typename)).toEqual(VoterType.CONSTITUTIONAL_COMMITTEE); + expect(getVoterType(drepKeyHashVoter.__typename)).toEqual(VoterType.DREP); + expect(getVoterType(drepScriptHashVoter.__typename)).toEqual(VoterType.DREP); + expect(getVoterType(stakePoolKeyHashVoter.__typename)).toEqual(VoterType.SPO); + }); + + test('testing getVote', () => { + expect(getVote(Wallet.Cardano.Vote.yes)).toEqual(Votes.YES); + expect(getVote(Wallet.Cardano.Vote.no)).toEqual(Votes.NO); + expect(getVote(Wallet.Cardano.Vote.abstain)).toEqual(Votes.ABSTAIN); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx new file mode 100644 index 000000000..609255a03 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx @@ -0,0 +1,424 @@ +/* eslint-disable no-magic-numbers */ +/* eslint-disable unicorn/no-null */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable import/imports-first */ +import { AssetsMintedInspection } from '@cardano-sdk/core'; + +const mockPubDRepKeyToHash = jest.fn(); +const mockDisallowSignTx = jest.fn(); +const mockAllowSignTx = jest.fn(); +const mockEstablishDeviceConnection = jest.fn(); +const mockGetTransactionAssetsId = jest.fn(); +const mockGetAssetsInformation = jest.fn(); +const mockCalculateAssetBalance = jest.fn(); +const mockLovelacesToAdaString = jest.fn(); +import { act, cleanup } from '@testing-library/react'; +import { + useCreateAssetList, + useIsOwnPubDRepKey, + useOnBeforeUnload, + useSignTxData, + useSignWithHardwareWallet, + useTxSummary +} from '../hooks'; +import { renderHook } from '@testing-library/react-hooks'; +import { Wallet } from '@lace/cardano'; +import * as hooks from '@hooks'; +import { dAppRoutePaths } from '@routes/wallet-paths'; +import { TokenInfo } from '@src/utils/get-assets-information'; +import { AddressListType } from '@src/views/browser-view/features/activity'; +import { WalletInfo } from '@src/types'; +import * as Core from '@cardano-sdk/core'; + +jest.mock('@cardano-sdk/core', () => ({ + ...jest.requireActual('@cardano-sdk/core'), + createTxInspector: jest.fn() +})); + +jest.mock('@hooks', () => { + const original = jest.requireActual('@hooks'); + return { + __esModule: true, + ...original + }; +}); + +jest.mock('@cardano-sdk/hardware-ledger', () => { + const original = jest.requireActual('@cardano-sdk/hardware-ledger'); + return { + __esModule: true, + ...original, + LedgerKeyAgent: { + ...original.LedgerKeyAgent, + establishDeviceConnection: mockEstablishDeviceConnection + } + }; +}); + +jest.mock('../utils.ts', () => { + const original = jest.requireActual('../utils.ts'); + return { + __esModule: true, + ...original, + pubDRepKeyToHash: mockPubDRepKeyToHash, + disallowSignTx: mockDisallowSignTx, + allowSignTx: mockAllowSignTx + }; +}); + +jest.mock('@src/stores/slices', () => { + const original = jest.requireActual('@src/stores/slices'); + return { + __esModule: true, + ...original, + getTransactionAssetsId: mockGetTransactionAssetsId + }; +}); + +jest.mock('@src/utils/get-assets-information', () => { + const original = jest.requireActual('@src/utils/get-assets-information'); + return { + __esModule: true, + ...original, + getAssetsInformation: mockGetAssetsInformation + }; +}); + +jest.mock('@lace/cardano', () => { + const actual = jest.requireActual('@lace/cardano'); + return { + __esModule: true, + ...actual, + Wallet: { + ...actual.Wallet, + util: { + ...actual.Wallet.util, + calculateAssetBalance: mockCalculateAssetBalance, + lovelacesToAdaString: mockLovelacesToAdaString + } + } + }; +}); + +const _listeners: { type: string; listener: EventListenerOrEventListenerObject }[] = []; + +const addEventListenerOriginal = window.addEventListener; + +const patchAddEventListener = () => { + window.addEventListener = (type: any, listener: any) => { + _listeners.push({ type, listener }); + addEventListenerOriginal.call(window, type, listener); + }; +}; + +const removeEventListeners = () => { + for (const { type, listener } of _listeners) { + window.removeEventListener(type, listener); + } +}; + +describe('Testing hooks', () => { + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('useCreateAssetList', async () => { + const assetsIds = ['id1', 'id2', 'id3', 'id4', 'id5'] as Wallet.Cardano.AssetId[]; + mockGetTransactionAssetsId.mockReset(); + mockGetTransactionAssetsId.mockReturnValue(assetsIds); + const tokenInfo = new Map([ + [assetsIds[0], null], + [ + assetsIds[1], + { + name: '', + tokenMetadata: { ticker: `${assetsIds[1]}_tokenMetadata_ticker` }, + nftMetadata: { name: `${assetsIds[1]}_nftMetadata_name` } + } + ], + [ + assetsIds[2], + { + name: `${assetsIds[2]}_name`, + tokenMetadata: { ticker: `${assetsIds[2]}_tokenMetadata_ticker` }, + nftMetadata: { name: `${assetsIds[2]}_nftMetadata_name` } + } + ], + [ + assetsIds[3], + { + name: `${assetsIds[3]}_name`, + tokenMetadata: null, + nftMetadata: { name: `${assetsIds[3]}_nftMetadata_name` } + } + ], + [ + assetsIds[4], + { + name: '' + } + ] + ]) as TokenInfo; + mockGetAssetsInformation.mockReset(); + mockGetAssetsInformation.mockImplementation(async () => await tokenInfo); + mockCalculateAssetBalance.mockReset(); + mockCalculateAssetBalance.mockImplementation((value, walletAsset) => `${value}_${walletAsset?.name || 'default'}`); + + const outputs = 'outputs' as unknown as Wallet.Cardano.TxOut[]; + const assetProvider = 'assetProvider' as unknown as Core.AssetProvider; + const assets = new Map([ + [ + assetsIds[0], + { + name: `${assetsIds[0]}_name_from_assets`, + tokenMetadata: { ticker: `${assetsIds[0]}_tokenMetadata_ticker_from_assets` } + } + ], + [ + assetsIds[1], + { + name: `${assetsIds[1]}_name_from_assets`, + tokenMetadata: null, + nftMetadata: { name: `${assetsIds[2]}_nftMetadata_name_from_assets` } + } + ], + [assetsIds[2], null], + [assetsIds[3], null], + [ + assetsIds[4], + { + ...tokenInfo.get(assetsIds[4]) + } + ] + ]) as unknown as TokenInfo; + + const tokenMap = new Map(assetsIds.map((id) => [id, `${id}_balance`])) as unknown as Wallet.Cardano.TokenMap; + tokenMap.set('id5' as Wallet.Cardano.AssetId, 'id5_balance' as unknown as bigint); + + let hook: any; + await act(async () => { + hook = renderHook(() => useCreateAssetList({ outputs, assets, assetProvider })); + }); + expect(hook.result.current(tokenMap)).toEqual([ + // should use assets info + { + name: assets.get(assetsIds[0]).name, + ticker: assets.get(assetsIds[0]).tokenMetadata.ticker, + amount: `${tokenMap.get(assetsIds[0])}_${assets.get(assetsIds[0]).name}` + }, + { + name: assets.get(assetsIds[1]).name, + ticker: assets.get(assetsIds[1]).nftMetadata.name, + amount: `${tokenMap.get(assetsIds[1])}_${assets.get(assetsIds[1]).name}` + }, + // should use assetProvider info + { + name: tokenInfo.get(assetsIds[2]).name, + ticker: tokenInfo.get(assetsIds[2]).tokenMetadata.ticker, + amount: `${tokenMap.get(assetsIds[2])}_${tokenInfo.get(assetsIds[2]).name}` + }, + { + name: tokenInfo.get(assetsIds[3]).name, + ticker: tokenInfo.get(assetsIds[3]).nftMetadata.name, + amount: `${tokenMap.get(assetsIds[3])}_${tokenInfo.get(assetsIds[3]).name}` + }, + { + name: 'id5', + amount: `${tokenMap.get('id5' as Wallet.Cardano.AssetId)}_${'default'}`, + ticker: undefined + } + ]); + }); + + test('useSignTxData', async () => { + const signTxData = { dappInfo: 'dappInfo', tx: 'tx' }; + const getSignTxDataMock = jest.fn(); + getSignTxDataMock.mockImplementation(async () => await signTxData); + const hook = renderHook(() => useSignTxData(getSignTxDataMock)); + + await hook.waitFor(() => { + expect(hook.result.current.signTxData).toEqual(signTxData); + expect(hook.result.current.errorMessage).toEqual(undefined); + }); + + const errorMessage = 'error'; + getSignTxDataMock.mockImplementation(async () => { + throw new Error(errorMessage); + }); + try { + await hook.rerender(); + } catch { + expect(hook.result.current.signTxData).toEqual(undefined); + expect(hook.result.current.errorMessage).toEqual(errorMessage); + } + }); + + test('useSignWithHardwareWallet', async () => { + const redirectToSignFailure = jest.fn(); + const useRedirectionSpy = jest.spyOn(hooks, 'useRedirection').mockImplementation(() => redirectToSignFailure); + mockEstablishDeviceConnection.mockReset(); + mockEstablishDeviceConnection.mockImplementation(async () => await true); + const hook = renderHook(() => useSignWithHardwareWallet()); + + await hook.waitFor(() => { + expect(hook.result.current.isConfirmingTx).toBeFalsy; + expect(useRedirectionSpy).toHaveBeenLastCalledWith(dAppRoutePaths.dappTxSignFailure); + }); + + await act(async () => { + await hook.result.current.signWithHardwareWallet(); + }); + + await hook.waitFor(() => { + expect(hook.result.current.isConfirmingTx).toBe(true); + expect(mockAllowSignTx).toHaveBeenCalledTimes(1); + expect(mockEstablishDeviceConnection).toHaveBeenCalledTimes(1); + expect(mockEstablishDeviceConnection).toHaveBeenLastCalledWith(Wallet.KeyManagement.CommunicationType.Web); + expect(mockDisallowSignTx).not.toHaveBeenCalled(); + }); + + mockEstablishDeviceConnection.mockReset(); + mockEstablishDeviceConnection.mockImplementation(async () => { + throw new Error('error'); + }); + + await hook.rerender(); + + await act(async () => { + try { + await hook.result.current.signWithHardwareWallet(); + } catch { + expect(hook.result.current.isConfirmingTx).toBe(true); + expect(mockAllowSignTx).toHaveBeenCalledTimes(1); + expect(mockDisallowSignTx).toHaveBeenCalledTimes(1); + expect(mockDisallowSignTx).toHaveBeenLastCalledWith(false); + expect(redirectToSignFailure).toHaveBeenCalledTimes(1); + } + }); + }); + + test('useTxSummary', async () => { + mockLovelacesToAdaString.mockReset(); + mockLovelacesToAdaString.mockImplementation((val) => val); + + const createTxInspectorSpy = jest + .spyOn(Core, 'createTxInspector') + .mockReturnValue(() => ({ minted: [], burned: [], votingProcedures: true })); + + const tx = { + body: { + fee: 'txFee', + outputs: [ + { + value: { coins: 'output_1_coins', assets: { size: 1 } }, + address: 'address1' + }, + { + value: { coins: 'output_2_coins', assets: { size: 1 } }, + address: 'address2' + }, + { + value: { coins: 'output_3_coins', assets: { size: 0 } }, + address: 'address3' + } + ] + } + } as unknown as Wallet.Cardano.Tx; + const addressList = [{ address: 'address1', name: 'address1_name' }] as AddressListType[]; + const walletInfo = { + name: 'walletName', + addresses: [{ address: 'address2' }, { address: 'address1' }] + } as WalletInfo; + const createAssetList = (txAssets: Wallet.Cardano.TokenMap) => txAssets as unknown as Wallet.Cip30SignTxAssetItem[]; + const createMintedAssetList = (txAssets: AssetsMintedInspection) => + txAssets as unknown as Wallet.Cip30SignTxAssetItem[]; + + let hook: any; + await act(async () => { + hook = renderHook(() => useTxSummary({ tx, addressList, walletInfo, createAssetList, createMintedAssetList })); + }); + + expect(hook.result.current).toEqual({ + fee: tx.body.fee.toString(), + burnedAssets: [], + mintedAssets: [], + outputs: [ + { + coins: tx.body.outputs[0].value.coins, + recipient: addressList[0].name, + assets: tx.body.outputs[0].value.assets + }, + { + coins: tx.body.outputs[2].value.coins, + recipient: tx.body.outputs[2].address + } + ], + type: Wallet.Cip30TxType.VotingProcedures + }); + + hook.unmount(); + + await act(async () => { + createTxInspectorSpy.mockReturnValue(() => ({ minted: [], burned: [] })); + + hook = renderHook(() => useTxSummary({ tx, addressList, walletInfo, createAssetList, createMintedAssetList })); + }); + + expect(hook.result.current).toEqual({ + fee: tx.body.fee.toString(), + burnedAssets: [], + mintedAssets: [], + outputs: [ + { + coins: tx.body.outputs[2].value.coins, + recipient: tx.body.outputs[2].address + } + ], + type: Wallet.Cip30TxType.Send + }); + }); + + test('useOnBeforeUnload', async () => { + patchAddEventListener(); + const cb = jest.fn(); + const hook = renderHook(() => useOnBeforeUnload(cb)); + + await hook.waitFor(() => { + window.dispatchEvent(new Event('beforeunload')); + expect(cb).toHaveBeenCalledTimes(1); + }); + + hook.unmount(); + + window.dispatchEvent(new Event('beforeunload')); + expect(cb).toHaveBeenCalledTimes(1); + + removeEventListeners(); + }); + + test('useIsOwnPubDRepKey', async () => { + const ed25519PublicKeyHexMock = 'ed25519PublicKeyHexMock'; + mockPubDRepKeyToHash.mockReset(); + mockPubDRepKeyToHash.mockImplementation(async (val: Wallet.Crypto.Ed25519PublicKeyHex) => await val); + + const hook = renderHook(() => + useIsOwnPubDRepKey( + async () => (await ed25519PublicKeyHexMock) as Wallet.Crypto.Ed25519PublicKeyHex, + ed25519PublicKeyHexMock as Wallet.Crypto.Hash28ByteBase16 + ) + ); + await hook.waitFor(() => { + expect(hook.result.current).toBe(true); + }); + + mockPubDRepKeyToHash.mockReset(); + mockPubDRepKeyToHash.mockImplementation(async () => await 1); + hook.rerender(); + + await hook.waitFor(() => { + expect(hook.result.current).toBe(false); + }); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx new file mode 100644 index 000000000..e420b4bdc --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx @@ -0,0 +1,157 @@ +/* eslint-disable unicorn/consistent-function-scoping */ +/* eslint-disable import/imports-first */ +const mockDRepID = jest.fn(); +const mockHexBlob = (val: string) => val; +mockHexBlob.toTypedBech32 = (prefix: string, value: string) => `${prefix}${value}`; +/* eslint-disable unicorn/no-useless-undefined */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable no-magic-numbers */ +/* eslint-disable max-statements */ +import { cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { Wallet } from '@lace/cardano'; +import * as Core from '@cardano-sdk/core'; +import { + getTitleKey, + certificateInspectorFactory, + votingProceduresInspector, + getTxType, + getOwnRetirementMessageKey, + drepIDasBech32FromHash, + pubDRepKeyToHash +} from '../utils'; +import { DAPP_VIEWS, sectionTitle } from '@src/features/dapp/config'; + +jest.mock('@cardano-sdk/core', () => ({ + ...jest.requireActual('@cardano-sdk/core'), + createTxInspector: jest.fn() +})); + +jest.mock('@lace/cardano', () => { + const actual = jest.requireActual('@lace/cardano'); + return { + __esModule: true, + ...actual, + Wallet: { + ...actual.Wallet, + Cardano: { + ...actual.Wallet.Cardano, + DRepID: mockDRepID + }, + HexBlob: mockHexBlob, + Crypto: { + ...actual.Wallet.Crypto, + Hash28ByteBase16: { + ...actual.Wallet.Crypto.Hash28ByteBase16, + fromEd25519KeyHashHex: (drepKeyHex: string) => drepKeyHex + }, + Ed25519PublicKey: { + ...actual.Wallet.Crypto.Ed25519PublicKey, + fromHex: async (val: string) => await { hash: async () => await { hex: () => val } } + } + } + } + }; +}); + +describe('Testing utils', () => { + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + cleanup(); + }); + + test('testing getVoterType', () => { + let txType = Wallet.Cip30TxType.DRepRegistration; + expect(getTitleKey(txType)).toEqual(`core.${txType}.title`); + txType = Wallet.Cip30TxType.DRepRetirement; + expect(getTitleKey(txType)).toEqual(`core.${txType}.title`); + txType = Wallet.Cip30TxType.DRepUpdate; + expect(getTitleKey(txType)).toEqual(`core.${txType}.title`); + txType = Wallet.Cip30TxType.VoteDelegation; + expect(getTitleKey(txType)).toEqual(`core.${txType}.title`); + txType = Wallet.Cip30TxType.VotingProcedures; + expect(getTitleKey(txType)).toEqual(`core.${txType}.title`); + txType = 'other' as Wallet.Cip30TxType; + expect(getTitleKey(txType)).toEqual(sectionTitle[DAPP_VIEWS.CONFIRM_TX]); + }); + + test('testing certificateInspectorFactory', () => { + const VoteDelegationCertificate = { __typename: Wallet.Cardano.CertificateType.VoteDelegation }; + expect( + certificateInspectorFactory(Wallet.Cardano.CertificateType.VoteDelegation)({ + body: { certificates: [VoteDelegationCertificate] } + } as Wallet.Cardano.Tx) + ).toEqual(VoteDelegationCertificate); + expect( + certificateInspectorFactory(Wallet.Cardano.CertificateType.VoteRegistrationDelegation)({ + body: { certificates: [VoteDelegationCertificate] } + } as Wallet.Cardano.Tx) + ).toEqual(undefined); + }); + + test('testing votingProceduresInspector', () => { + const votingProcedures = 'votingProcedures'; + expect(votingProceduresInspector({ body: { votingProcedures } } as unknown as Wallet.Cardano.Tx)).toEqual( + votingProcedures + ); + expect(votingProceduresInspector({ body: {} } as Wallet.Cardano.Tx)).toEqual(undefined); + }); + + test('testing getTxType', () => { + const tx = { body: {} } as Wallet.Cardano.Tx; + const txInspectorCurriedFnPayload = { minted: [], burned: [] } as unknown as any; + const createTxInspectorSpy = jest + .spyOn(Core, 'createTxInspector') + .mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, votingProcedures: true })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.VotingProcedures); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(1); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, minted: { length: 1 } })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.Mint); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(2); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, burned: { length: 1 } })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.Burn); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(3); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, dRepRegistration: true })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.DRepRegistration); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(4); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, dRepRetirement: true })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.DRepRetirement); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(5); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, voteDelegation: true })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.VoteDelegation); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(6); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload, dRepUpdate: true })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.DRepUpdate); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(7); + + createTxInspectorSpy.mockReturnValueOnce(() => ({ ...txInspectorCurriedFnPayload })); + expect(getTxType(tx)).toEqual(Wallet.Cip30TxType.Send); + expect(createTxInspectorSpy).toHaveBeenCalledTimes(8); + }); + + test('testing drepIDasBech32FromHash', () => { + mockDRepID.mockReset(); + mockDRepID.mockImplementation((val) => val); + + const drepID = '_drepID'; + expect(drepIDasBech32FromHash(drepID as Wallet.Crypto.Hash28ByteBase16)).toEqual(`drep${drepID}`); + }); + + test('testing pubDRepKeyToHash', async () => { + const pubDRepKeyHex = '_pubDRepKeyHex'; + expect(await pubDRepKeyToHash(pubDRepKeyHex as Wallet.Crypto.Ed25519PublicKeyHex)).toEqual(pubDRepKeyHex); + }); + + test('testing getOwnRetirementMessageKey', () => { + expect(getOwnRetirementMessageKey(undefined)).toEqual(''); + expect(getOwnRetirementMessageKey(true)).toEqual('core.DRepRetirement.isOwnRetirement'); + expect(getOwnRetirementMessageKey(false)).toEqual('core.DRepRetirement.isNotOwnRetirement'); + }); +}); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts new file mode 100644 index 000000000..4b3fc82e4 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts @@ -0,0 +1,283 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { + AssetProvider, + assetsBurnedInspector, + AssetsMintedInspection, + assetsMintedInspector, + createTxInspector, + MintedAsset +} from '@cardano-sdk/core'; +import * as HardwareLedger from '@cardano-sdk/hardware-ledger'; +import { dAppRoutePaths } from '@routes'; +import { Wallet } from '@lace/cardano'; +import { useRedirection } from '@hooks'; +import { CardanoTxOut, WalletInfo } from '@src/types'; +import { TokenInfo, getAssetsInformation } from '@src/utils/get-assets-information'; +import { getTransactionAssetsId } from '@src/stores/slices'; +import { AddressListType } from '@src/views/browser-view/features/activity'; +import { allowSignTx, pubDRepKeyToHash, disallowSignTx, getTxType } from './utils'; +import { GetSignTxData, SignTxData } from './types'; + +export const useCreateAssetList = ({ + assets, + outputs, + assetProvider +}: { + assets?: TokenInfo; + outputs?: CardanoTxOut[]; + assetProvider: AssetProvider; +}): ((txAssets: Wallet.Cardano.TokenMap) => Wallet.Cip30SignTxAssetItem[]) => { + const [assetsInfo, setAssetsInfo] = useState(); + const assetIds = useMemo(() => outputs && getTransactionAssetsId(outputs), [outputs]); + + useEffect(() => { + if (assetIds?.length > 0) { + getAssetsInformation(assetIds, assets, { + assetProvider, + extraData: { nftMetadata: true, tokenMetadata: true } + }) + .then((result) => setAssetsInfo(result)) + .catch((error) => { + console.error(error); + }); + } + }, [assetIds, assetProvider, assets]); + + return useCallback( + (txAssets: Wallet.Cardano.TokenMap) => { + if (!assetsInfo) return []; + const assetList: Wallet.Cip30SignTxAssetItem[] = []; + // eslint-disable-next-line unicorn/no-array-for-each + txAssets.forEach(async (value, key) => { + const walletAsset = assets.get(key) || assetsInfo?.get(key); + assetList.push({ + name: walletAsset?.name.toString() || key.toString(), + ticker: walletAsset?.tokenMetadata?.ticker || walletAsset.nftMetadata?.name, + amount: Wallet.util.calculateAssetBalance(value, walletAsset) + }); + }); + return assetList; + }, + [assets, assetsInfo] + ); +}; +const convertMetadataArrayToObj = (arr: unknown[]): Record => { + const result: Record = {}; + for (const item of arr) { + if (typeof item === 'object' && !Array.isArray(item) && item !== null) { + Object.assign(result, item); + } + } + return result; +}; + +// eslint-disable-next-line complexity, sonarjs/cognitive-complexity +const getAssetNameFromMintMetadata = (asset: MintedAsset, metadata: Wallet.Cardano.TxMetadata): string | undefined => { + if (!asset || !metadata) return; + const decodedAssetName = Buffer.from(asset.assetName, 'hex').toString(); + + // Tries to find the asset name in the tx metadata under label 721 or 20 + for (const [key, value] of metadata.entries()) { + // eslint-disable-next-line no-magic-numbers + if (key !== BigInt(721) && key !== BigInt(20)) return; + const cip25Metadata = Wallet.cardanoMetadatumToObj(value); + if (!Array.isArray(cip25Metadata)) return; + + // cip25Metadata should be an array containing all policies for the minted assets in the tx + const policyLevelMetadata = convertMetadataArrayToObj(cip25Metadata)[asset.policyId]; + if (!Array.isArray(policyLevelMetadata)) return; + + // policyLevelMetadata should be an array of objects with the minted assets names as key + // e.g. "policyId" = [{ "AssetName1": { ...metadataAsset1 } }, { "AssetName2": { ...metadataAsset2 } }]; + const assetProperties = convertMetadataArrayToObj(policyLevelMetadata)?.[decodedAssetName]; + if (!Array.isArray(assetProperties)) return; + + // assetProperties[decodedAssetName] should be an array of objects with the properties as keys + // e.g. [{ "name": "Asset Name" }, { "description": "An asset" }, ...] + const assetMetadataName = convertMetadataArrayToObj(assetProperties)?.name; + // eslint-disable-next-line consistent-return + return typeof assetMetadataName === 'string' ? assetMetadataName : undefined; + } +}; +export const useCreateMintedAssetList = ({ + assets, + outputs, + assetProvider, + metadata, + mint +}: { + assets?: TokenInfo; + outputs?: CardanoTxOut[]; + assetProvider: AssetProvider; + mint?: Wallet.Cardano.TokenMap; + metadata?: Wallet.Cardano.TxMetadata; +}): ((txAssets: AssetsMintedInspection) => Wallet.Cip30SignTxAssetItem[]) => { + const [assetsInfo, setAssetsInfo] = useState(); + const assetIds = useMemo(() => outputs && getTransactionAssetsId(outputs, mint), [outputs, mint]); + + // eslint-disable-next-line sonarjs/no-identical-functions + useEffect(() => { + if (assetIds?.length > 0) { + getAssetsInformation(assetIds, assets, { + assetProvider, + extraData: { nftMetadata: true, tokenMetadata: true } + }) + .then((result) => setAssetsInfo(result)) + .catch((error) => { + console.error(error); + }); + } + }, [assetIds, assetProvider, assets]); + + return useCallback( + (mintedAssets: AssetsMintedInspection) => { + if (!assetsInfo) return []; + return mintedAssets.map((asset) => { + const assetId = Wallet.Cardano.AssetId.fromParts(asset.policyId, asset.assetName); + const assetInfo = assets.get(assetId) || assetsInfo?.get(assetId); + // If it's a new asset or the name is being updated we should be getting it from the tx metadata + const metadataName = getAssetNameFromMintMetadata(asset, metadata); + return { + name: assetInfo?.name.toString() || asset.fingerprint || assetId, + ticker: + metadataName ?? + assetInfo?.nftMetadata?.name ?? + assetInfo?.tokenMetadata?.ticker ?? + assetInfo?.tokenMetadata?.name ?? + asset.fingerprint.toString(), + amount: Wallet.util.calculateAssetBalance(asset.quantity, assetInfo) + }; + }); + }, + [assets, assetsInfo, metadata] + ); +}; +export const useSignTxData = (getSignTxData: GetSignTxData): { signTxData?: SignTxData; errorMessage?: string } => { + const [signTxData, setSignTxData] = useState<{ dappInfo: Wallet.DappInfo; tx: Wallet.Cardano.Tx }>(); + const [errorMessage, setErrorMessage] = useState(); + + useEffect(() => { + getSignTxData() + .then((result) => { + setSignTxData(result); + }) + .catch((error) => { + setErrorMessage(error); + console.error(error); + }); + }, [getSignTxData, setSignTxData, setErrorMessage]); + + return { signTxData, errorMessage }; +}; + +export const useDisallowSignTx = (): ((close?: boolean) => void) => useCallback(disallowSignTx, []); + +export const useAllowSignTx = (): (() => void) => useCallback(allowSignTx, []); + +export const useSignWithHardwareWallet = (): { + signWithHardwareWallet: () => Promise; + isConfirmingTx: boolean; +} => { + const allow = useAllowSignTx(); + const disallow = useDisallowSignTx(); + const redirectToSignFailure = useRedirection>(dAppRoutePaths.dappTxSignFailure); + const [isConfirmingTx, setIsConfirmingTx] = useState(); + const signWithHardwareWallet = useCallback(async () => { + setIsConfirmingTx(true); + try { + await HardwareLedger.LedgerKeyAgent.establishDeviceConnection(Wallet.KeyManagement.CommunicationType.Web); + allow(); + } catch (error) { + console.error('error', error); + disallow(false); + redirectToSignFailure({}); + } + }, [allow, disallow, redirectToSignFailure]); + + return { isConfirmingTx, signWithHardwareWallet }; +}; + +export const useTxSummary = ({ + tx, + addressList, + walletInfo, + createAssetList, + createMintedAssetList +}: { + addressList: AddressListType[]; + walletInfo: WalletInfo; + tx: Wallet.Cardano.Tx; + createAssetList: (txAssets: Wallet.Cardano.TokenMap) => Wallet.Cip30SignTxAssetItem[]; + createMintedAssetList: (txAssets: AssetsMintedInspection) => Wallet.Cip30SignTxAssetItem[]; +}): Wallet.Cip30SignTxSummary | undefined => + useMemo((): Wallet.Cip30SignTxSummary | undefined => { + const txType = getTxType(tx); + const inspector = createTxInspector({ + minted: assetsMintedInspector, + burned: assetsBurnedInspector + }); + + const { minted, burned } = inspector(tx as Wallet.Cardano.HydratedTx); + + const addressToNameMap = new Map( + addressList?.map((item: AddressListType) => [item.address, item.name]) + ); + + const externalOutputs = tx.body.outputs.filter((output) => { + if (txType === Wallet.Cip30TxType.Send) { + return walletInfo.addresses.every((addr) => output.address !== addr.address); + } + // Don't show withdrawal tx's etc + return output.address.toString() !== walletInfo.addresses[0].address.toString(); + }); + + // eslint-disable-next-line unicorn/no-array-reduce + const txSummaryOutputs: Wallet.Cip30SignTxSummary['outputs'] = externalOutputs.reduce( + (acc, txOut) => [ + ...acc, + { + coins: Wallet.util.lovelacesToAdaString(txOut.value.coins.toString()), + recipient: addressToNameMap?.get(txOut.address.toString()) || txOut.address.toString(), + ...(txOut.value.assets?.size > 0 && { assets: createAssetList(txOut.value.assets) }) + } + ], + [] + ); + + return { + fee: Wallet.util.lovelacesToAdaString(tx.body.fee.toString()), + outputs: txSummaryOutputs, + type: txType, + mintedAssets: createMintedAssetList(minted), + burnedAssets: createMintedAssetList(burned) + }; + }, [tx, addressList, createMintedAssetList, walletInfo.addresses, createAssetList]); + +export const useOnBeforeUnload = (callBack: () => void): void => { + useEffect(() => { + window.addEventListener('beforeunload', callBack); + return () => { + window.removeEventListener('beforeunload', callBack); + }; + }, [callBack]); +}; + +export const useIsOwnPubDRepKey = ( + getOwnPubDRepKey: () => Promise, + drepHash: Wallet.Crypto.Hash28ByteBase16 +): boolean => { + const [isOwnDRepKey, setIsOwnDRepKey] = useState(); + + useEffect(() => { + const get = async () => { + const ownPubDRepKey = await getOwnPubDRepKey(); + const ownDRepKeyHash = await pubDRepKeyToHash(ownPubDRepKey); + + setIsOwnDRepKey(drepHash === ownDRepKeyHash); + }; + + get(); + }, [getOwnPubDRepKey, drepHash]); + + return isOwnDRepKey; +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/types.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/types.ts new file mode 100644 index 000000000..b6c1da399 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/types.ts @@ -0,0 +1,5 @@ +import { Wallet } from '@lace/cardano'; +import { DappDataService } from '@lib/scripts/types'; + +export type GetSignTxData = DappDataService['getSignTxData']; +export type SignTxData = { dappInfo: Wallet.DappInfo; tx: Wallet.Cardano.Tx }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts new file mode 100644 index 000000000..e17be6029 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -0,0 +1,129 @@ +/* eslint-disable no-console */ +import { Wallet } from '@lace/cardano'; +import { assetsBurnedInspector, assetsMintedInspector, createTxInspector } from '@cardano-sdk/core'; +import { RemoteApiPropertyType, exposeApi } from '@cardano-sdk/web-extension'; +import { UserPromptService } from '@lib/scripts/background/services'; +import { DAPP_CHANNELS } from '@src/utils/constants'; +import { runtime } from 'webextension-polyfill'; +import { of } from 'rxjs'; +import { sectionTitle, DAPP_VIEWS } from '../../config'; + +const { CertificateType } = Wallet.Cardano; + +const DAPP_TOAST_DURATION = 50; + +export const getTitleKey = (txType: Wallet.Cip30TxType): string => + [ + Wallet.Cip30TxType.DRepRegistration, + Wallet.Cip30TxType.DRepRetirement, + Wallet.Cip30TxType.DRepUpdate, + Wallet.Cip30TxType.VoteDelegation, + Wallet.Cip30TxType.VotingProcedures + ].includes(txType) + ? `core.${txType}.title` + : sectionTitle[DAPP_VIEWS.CONFIRM_TX]; + +export const disallowSignTx = (close = false): void => { + exposeApi>( + { + api$: of({ + async allowSignTx(): Promise { + return Promise.reject(); + } + }), + baseChannel: DAPP_CHANNELS.userPrompt, + properties: { allowSignTx: RemoteApiPropertyType.MethodReturningPromise } + }, + { logger: console, runtime } + ); + close && setTimeout(() => window.close(), DAPP_TOAST_DURATION); +}; + +export const allowSignTx = (): void => { + exposeApi>( + { + api$: of({ + async allowSignTx(): Promise { + return Promise.resolve(true); + } + }), + baseChannel: DAPP_CHANNELS.userPrompt, + properties: { allowSignTx: RemoteApiPropertyType.MethodReturningPromise } + }, + { logger: console, runtime } + ); +}; + +export const certificateInspectorFactory = + (type: Wallet.Cardano.CertificateType) => + (tx: Wallet.Cardano.Tx): T | undefined => + tx?.body?.certificates?.find((certificate) => certificate.__typename === type) as T | undefined; + +export const votingProceduresInspector = (tx: Wallet.Cardano.Tx): Wallet.Cardano.VotingProcedures | undefined => + tx?.body?.votingProcedures; + +export const getTxType = (tx: Wallet.Cardano.Tx): Wallet.Cip30TxType => { + const inspector = createTxInspector({ + minted: assetsMintedInspector, + burned: assetsBurnedInspector, + votingProcedures: votingProceduresInspector, + dRepRegistration: certificateInspectorFactory(CertificateType.RegisterDelegateRepresentative), + dRepRetirement: certificateInspectorFactory(CertificateType.UnregisterDelegateRepresentative), + dRepUpdate: certificateInspectorFactory(CertificateType.UpdateDelegateRepresentative), + voteDelegation: certificateInspectorFactory(CertificateType.VoteDelegation) + }); + + const { minted, burned, dRepRegistration, dRepRetirement, dRepUpdate, voteDelegation, votingProcedures } = inspector( + tx as Wallet.Cardano.HydratedTx + ); + const isMintTransaction = minted.length > 0; + const isBurnTransaction = burned.length > 0; + + if (votingProcedures) { + return Wallet.Cip30TxType.VotingProcedures; + } + + if (isMintTransaction) { + return Wallet.Cip30TxType.Mint; + } + + if (isBurnTransaction) { + return Wallet.Cip30TxType.Burn; + } + + if (dRepRegistration) { + return Wallet.Cip30TxType.DRepRegistration; + } + + if (dRepRetirement) { + return Wallet.Cip30TxType.DRepRetirement; + } + + if (voteDelegation) { + return Wallet.Cip30TxType.VoteDelegation; + } + + if (dRepUpdate) { + return Wallet.Cip30TxType.DRepUpdate; + } + + return Wallet.Cip30TxType.Send; +}; + +export const drepIDasBech32FromHash = (value: Wallet.Crypto.Hash28ByteBase16): Wallet.Cardano.DRepID => + Wallet.Cardano.DRepID(Wallet.HexBlob.toTypedBech32('drep', Wallet.HexBlob(value))); + +export const pubDRepKeyToHash = async ( + pubDRepKeyHex: Wallet.Crypto.Ed25519PublicKeyHex +): Promise => { + const pubDRepKey = await Wallet.Crypto.Ed25519PublicKey.fromHex(pubDRepKeyHex); + const drepKeyHex = (await pubDRepKey.hash()).hex(); + return Wallet.Crypto.Hash28ByteBase16.fromEd25519KeyHashHex(drepKeyHex); +}; + +export const getOwnRetirementMessageKey = (isOwnRetirement: boolean | undefined): string => { + if (isOwnRetirement === undefined) { + return ''; + } + return isOwnRetirement ? 'core.DRepRetirement.isOwnRetirement' : 'core.DRepRetirement.isNotOwnRetirement'; +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/config/ViewsConfig.tsx b/apps/browser-extension-wallet/src/features/dapp/config/ViewsConfig.tsx index 34624df13..dbb0144ef 100644 --- a/apps/browser-extension-wallet/src/features/dapp/config/ViewsConfig.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/config/ViewsConfig.tsx @@ -1,5 +1,5 @@ import { IViewsList } from '../../../types'; -import { ConfirmTransaction } from '../components/ConfirmTransaction'; +import { ConfirmTransaction } from '../components/confirm-transaction/ConfirmTransaction'; import { SignTransaction } from '../components/SignTransaction'; import { DappTransactionFail } from '../components/DappTransactionFail'; import { IViewAction, IViewState } from '../../../providers'; diff --git a/apps/browser-extension-wallet/src/hooks/__tests__/useActionExecution.test.ts b/apps/browser-extension-wallet/src/hooks/__tests__/useActionExecution.test.ts index 45b16018f..9a4f74627 100644 --- a/apps/browser-extension-wallet/src/hooks/__tests__/useActionExecution.test.ts +++ b/apps/browser-extension-wallet/src/hooks/__tests__/useActionExecution.test.ts @@ -9,7 +9,7 @@ import { ActionExecutionArgs, useActionExecution } from '@hooks/useActionExecuti import { ToastProps } from '@lace/common'; jest.mock('react-i18next', () => { - const original = jest.requireActual('@lace/common'); + const original = jest.requireActual('react-i18next'); return { __esModule: true, ...original, diff --git a/apps/browser-extension-wallet/src/hooks/__tests__/useDelegationDetails.test.ts b/apps/browser-extension-wallet/src/hooks/__tests__/useDelegationDetails.test.ts index 2a20ab0bd..d6e507db6 100644 --- a/apps/browser-extension-wallet/src/hooks/__tests__/useDelegationDetails.test.ts +++ b/apps/browser-extension-wallet/src/hooks/__tests__/useDelegationDetails.test.ts @@ -29,7 +29,7 @@ jest.mock('../../stores', () => ({ })); describe('Testing useBuildDelegation hook', () => { - process.env.AVAILABLE_CHAINS = process.env.AVAILABLE_CHAINS || 'Mainnet,Preprod,Preview'; + process.env.AVAILABLE_CHAINS = process.env.AVAILABLE_CHAINS || 'Mainnet,Preprod,Preview,Sanchonet'; process.env.DEFAULT_CHAIN = process.env.DEFAULT_CHAIN || 'Preprod'; test('should return use delegation details function', () => { diff --git a/apps/browser-extension-wallet/src/lib/scripts/migrations/versions/v0_6_0.ts b/apps/browser-extension-wallet/src/lib/scripts/migrations/versions/v0_6_0.ts index bef5ea99e..cbcfe7444 100644 --- a/apps/browser-extension-wallet/src/lib/scripts/migrations/versions/v0_6_0.ts +++ b/apps/browser-extension-wallet/src/lib/scripts/migrations/versions/v0_6_0.ts @@ -94,6 +94,12 @@ export const v0_6_0: Migration = { ? { keyAgentData: newKeyAgentData } : { keyAgentData: { ...newKeyAgentData, chainId: Wallet.Cardano.ChainIds.Mainnet, knownAddresses: [] } + }, + Sanchonet: + keyAgentStoredChainName === 'Sanchonet' + ? { keyAgentData: newKeyAgentData } + : { + keyAgentData: { ...newKeyAgentData, chainId: Wallet.Cardano.ChainIds.Sanchonet, knownAddresses: [] } } }; diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index 79ecd3e26..8bfd3ccbe 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -133,7 +133,7 @@ "mainnet": "Mainnet", "preprod": "Preprod", "preview": "Preview", - "legacyTestnet": "Legacy Testnet", + "sanchonet": "Sanchonet", "custom": "Custom", "offline": "Offline", "error": "Your internet connection is not working. You can still navigate the wallet based on the latest connection you had.", @@ -1129,6 +1129,63 @@ "tryingToUseAssetNotInWallet": "This DApp is trying to use token not held in your wallet.", "noCollateral": "Wallet should not be able to sign dapp txs without collateral." }, + "VotingProcedures": { + "title": "Confirm Vote", + "voterType": "Voter type", + "procedureTitle": "Procedure", + "actionIdTitle": "Action ID", + "vote": "Vote", + "actionId": { + "index": "Index", + "txHash": "TX Hash" + }, + "anchor": { + "hash": "Anchor Hash", + "url": "Anchor URL" + }, + "dRepId": "DRep ID", + "voterTypes": { + "constitutionalCommittee": "Constitutional Committee", + "spo": "SPO", + "drep": "DRep" + }, + "votes": { + "yes": "Yes", + "no": "No", + "abstain": "Abstain" + } + }, + "DRepRegistration": { + "title": "Confirm DRep Registration", + "metadata": "Metadata", + "url": "URL", + "hash": "Hash", + "drepId": "DRep ID", + "depositPaid": "Deposit paid" + }, + "DRepRetirement": { + "title": "Confirm DRep Retirement", + "metadata": "Metadata", + "drepId": "DRep ID", + "depositReturned": "Deposit returned", + "isOwnRetirement": "This is your DRep retirement.", + "isNotOwnRetirement": "The presented DRepID does not match your wallet's DRepID." + }, + "DRepUpdate": { + "title": "Confirm DRep Update", + "metadata": "Metadata", + "drepId": "DRep ID", + "url": "URL", + "hash": "Hash" + }, + "VoteDelegation": { + "title": "Confirm vote delegation", + "metadata": "Metadata", + "drepId": "DRep ID", + "alwaysAbstain": "Abstain", + "alwaysNoConfidence": "No Confidence", + "option": "Yes" + }, "destinationAddressInput": { "recipientAddress": "Recipient's address or $handle" }, diff --git a/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/config.ts b/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/config.ts index 29831d31d..8fb2af712 100644 --- a/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/config.ts +++ b/apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/config.ts @@ -9,23 +9,27 @@ export const POSTHOG_EXCLUDED_EVENTS = process.env.POSTHOG_EXCLUDED_EVENTS ?? '' export const DEV_NETWORK_ID_TO_POSTHOG_TOKEN_MAP: Record = { [Wallet.Cardano.NetworkMagics.Mainnet]: process.env.POSTHOG_DEV_TOKEN_MAINNET, [Wallet.Cardano.NetworkMagics.Preprod]: process.env.POSTHOG_DEV_TOKEN_PREPROD, - [Wallet.Cardano.NetworkMagics.Preview]: process.env.POSTHOG_DEV_TOKEN_PREVIEW + [Wallet.Cardano.NetworkMagics.Preview]: process.env.POSTHOG_DEV_TOKEN_PREVIEW, + [Wallet.Cardano.NetworkMagics.Sanchonet]: process.env.POSTHOG_DEV_TOKEN_SANCHONET }; export const PRODUCTION_NETWORK_ID_TO_POSTHOG_TOKEN_MAP: Record = { [Wallet.Cardano.NetworkMagics.Mainnet]: process.env.POSTHOG_PRODUCTION_TOKEN_MAINNET, [Wallet.Cardano.NetworkMagics.Preprod]: process.env.POSTHOG_PRODUCTION_TOKEN_PREPROD, - [Wallet.Cardano.NetworkMagics.Preview]: process.env.POSTHOG_PRODUCTION_TOKEN_PREVIEW + [Wallet.Cardano.NetworkMagics.Preview]: process.env.POSTHOG_PRODUCTION_TOKEN_PREVIEW, + [Wallet.Cardano.NetworkMagics.Sanchonet]: process.env.POSTHOG_PRODUCTION_TOKEN_SANCHONET }; export const DEV_NETWORK_ID_TO_POSTHOG_PROJECT_ID_MAP: Record = { [Wallet.Cardano.NetworkMagics.Mainnet]: 6315, [Wallet.Cardano.NetworkMagics.Preprod]: 6316, - [Wallet.Cardano.NetworkMagics.Preview]: 4874 + [Wallet.Cardano.NetworkMagics.Preview]: 4874, + [Wallet.Cardano.NetworkMagics.Sanchonet]: 11_178 }; export const PRODUCTION_NETWORK_ID_TO_POSTHOG_PROJECT_ID_MAP: Record = { [Wallet.Cardano.NetworkMagics.Mainnet]: 6621, [Wallet.Cardano.NetworkMagics.Preprod]: 6620, - [Wallet.Cardano.NetworkMagics.Preview]: 6619 + [Wallet.Cardano.NetworkMagics.Preview]: 6619, + [Wallet.Cardano.NetworkMagics.Sanchonet]: 11_179 }; diff --git a/apps/browser-extension-wallet/src/stores/slices/__tests__/activity-detail-slice.test.ts b/apps/browser-extension-wallet/src/stores/slices/__tests__/activity-detail-slice.test.ts new file mode 100644 index 000000000..f2c7fe2b7 --- /dev/null +++ b/apps/browser-extension-wallet/src/stores/slices/__tests__/activity-detail-slice.test.ts @@ -0,0 +1,31 @@ +import { CardanoTxOut } from '@src/types'; +import { getTransactionAssetsId } from '../activity-detail-slice'; + +describe('Testing activity detail slice', () => { + test('testing getTransactionAssetsId', () => { + const outputs = [ + { + value: { + assets: new Map([ + ['id1', 'val1'], + ['id2', 'val2'] + ]) + } + }, + { + value: { + assets: new Map([ + ['id1', 'val3'], + ['id3', 'val4'] + ]) + } + }, + { + value: { + assets: new Map([]) + } + } + ]; + expect(getTransactionAssetsId(outputs as unknown as CardanoTxOut[])).toEqual(['id1', 'id2', 'id3']); + }); +}); diff --git a/apps/browser-extension-wallet/src/stores/slices/__tests__/wallet-info-slice.test.ts b/apps/browser-extension-wallet/src/stores/slices/__tests__/wallet-info-slice.test.ts index 43223b673..8b4fe6e4d 100644 --- a/apps/browser-extension-wallet/src/stores/slices/__tests__/wallet-info-slice.test.ts +++ b/apps/browser-extension-wallet/src/stores/slices/__tests__/wallet-info-slice.test.ts @@ -68,7 +68,7 @@ describe('Testing wallet info slice', () => { describe('environment names set correctly', () => { let useWalletInfoHook: UseStore; - process.env.AVAILABLE_CHAINS = process.env.AVAILABLE_CHAINS || 'Mainnet,Preprod,Preview'; + process.env.AVAILABLE_CHAINS = process.env.AVAILABLE_CHAINS || 'Mainnet,Preprod,Preview,Sanchonet'; beforeEach(() => { useWalletInfoHook = create(mockWalletInfoStore); diff --git a/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts b/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts index 83d4dd693..5147a6d34 100644 --- a/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts +++ b/apps/browser-extension-wallet/src/stores/slices/activity-detail-slice.ts @@ -22,17 +22,24 @@ const isConfirmedTransaction = (props: Transaction): props is Wallet.Cardano.Hyd /** * returns a list of assets ids that belong to the transaction */ -const getTransactionAssetsId = (outputs: CardanoTxOut[]) => { - const assetIds: Wallet.Cardano.AssetId[] = []; - const assetMaps = outputs.map((output) => output.value.assets); +export const getTransactionAssetsId = ( + outputs: CardanoTxOut[], + mint?: Wallet.Cardano.TokenMap +): Wallet.Cardano.AssetId[] => { + const uniqueAssetIds = new Set(); + // Merge all assets (TokenMaps) from the tx outputs and mint + const assetMaps = outputs.map((output) => output.value.assets) ?? []; + if (mint?.size > 0) assetMaps.push(mint); + + // Extract all unique asset ids from the array of TokenMaps for (const asset of assetMaps) { if (asset) { for (const id of asset.keys()) { - !assetIds.includes(id) && assetIds.push(id); + !uniqueAssetIds.has(id) && uniqueAssetIds.add(id); } } } - return assetIds; + return [...uniqueAssetIds.values()]; }; const transactionMetadataTransformer = ( diff --git a/apps/browser-extension-wallet/src/utils/__tests__/chain.test.ts b/apps/browser-extension-wallet/src/utils/__tests__/chain.test.ts index fdbe1e951..a2fd7e754 100644 --- a/apps/browser-extension-wallet/src/utils/__tests__/chain.test.ts +++ b/apps/browser-extension-wallet/src/utils/__tests__/chain.test.ts @@ -9,7 +9,8 @@ describe('Testing getBaseUrlForChain function', () => { const CARDANO_SERVICES_URLS = { Mainnet: 'Mainnet', Preprod: 'Preprod', - Preview: 'Preview' + Preview: 'Preview', + Sanchonet: 'Sanchonet' }; beforeEach(() => { @@ -22,12 +23,13 @@ describe('Testing getBaseUrlForChain function', () => { }); test('should return proper url for chainName or throw', async () => { process.env.USE_DEV_ENDPOINTS = 'true'; - const AVAILABLE_CHAINS = ['Mainnet', 'Preprod', 'Preview'] as unknown as Wallet.ChainName[]; + const AVAILABLE_CHAINS = ['Mainnet', 'Preprod', 'Preview', 'Sanchonet'] as unknown as Wallet.ChainName[]; jest.spyOn(config, 'config').mockReturnValue({ CARDANO_SERVICES_URLS, AVAILABLE_CHAINS } as config.Config); expect(getBaseUrlForChain('Mainnet')).toBe(CARDANO_SERVICES_URLS.Mainnet); expect(getBaseUrlForChain('Preprod')).toBe(CARDANO_SERVICES_URLS.Preprod); expect(getBaseUrlForChain('Preview')).toBe(CARDANO_SERVICES_URLS.Preview); + expect(getBaseUrlForChain('Sanchonet')).toBe(CARDANO_SERVICES_URLS.Sanchonet); }); test('should throw in case chain is not suported', async () => { diff --git a/apps/browser-extension-wallet/src/utils/chain.ts b/apps/browser-extension-wallet/src/utils/chain.ts index 87d68ea4f..f8077af81 100644 --- a/apps/browser-extension-wallet/src/utils/chain.ts +++ b/apps/browser-extension-wallet/src/utils/chain.ts @@ -14,6 +14,9 @@ export const getBaseUrlForChain = (chainName: Wallet.ChainName): string => { case 'Preview': url = CARDANO_SERVICES_URLS.Preview; break; + case 'Sanchonet': + url = CARDANO_SERVICES_URLS.Sanchonet; + break; default: throw new Error('Incorrect chain supplied'); } diff --git a/apps/browser-extension-wallet/src/utils/mocks/test-helpers.tsx b/apps/browser-extension-wallet/src/utils/mocks/test-helpers.tsx index fa4511030..ab736b870 100644 --- a/apps/browser-extension-wallet/src/utils/mocks/test-helpers.tsx +++ b/apps/browser-extension-wallet/src/utils/mocks/test-helpers.tsx @@ -43,7 +43,8 @@ export const mockKeyAgentDataTestnet: Wallet.KeyManagement.SerializableKeyAgentD export const mockKeyAgentsByChain: Wallet.KeyAgentsByChain = { Mainnet: { keyAgentData: { ...mockKeyAgentDataTestnet, chainId: Wallet.Cardano.ChainIds.Mainnet } }, Preprod: { keyAgentData: { ...mockKeyAgentDataTestnet, chainId: Wallet.Cardano.ChainIds.Preprod } }, - Preview: { keyAgentData: { ...mockKeyAgentDataTestnet, chainId: Wallet.Cardano.ChainIds.Preview } } + Preview: { keyAgentData: { ...mockKeyAgentDataTestnet, chainId: Wallet.Cardano.ChainIds.Preview } }, + Sanchonet: { keyAgentData: { ...mockKeyAgentDataTestnet, chainId: Wallet.Cardano.ChainIds.Sanchonet } } }; export const mockInMemoryWallet = { diff --git a/apps/browser-extension-wallet/src/utils/mocks/tx.ts b/apps/browser-extension-wallet/src/utils/mocks/tx.ts index 96c2a6264..8ea60d13c 100644 --- a/apps/browser-extension-wallet/src/utils/mocks/tx.ts +++ b/apps/browser-extension-wallet/src/utils/mocks/tx.ts @@ -18,6 +18,9 @@ export const buildMockTx = ( } = {} ): Wallet.Cardano.HydratedTx => ({ + auxiliaryData: { + blob: new Map([[BigInt(1), 'metadataMock']]) + }, blockHeader: { blockNo: Wallet.Cardano.BlockNo(200), hash: Wallet.Cardano.BlockId('0dbe461fb5f981c0d01615332b8666340eb1a692b3034f46bcb5f5ea4172b2ed'), @@ -26,6 +29,9 @@ export const buildMockTx = ( body: { certificates: args.certificates, fee: BigInt(170_000), + mint: new Map([ + [Wallet.Cardano.AssetId('659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba8254534c41'), BigInt(3)] + ]), inputs: args.inputs ?? [ { address: sendingAddress, diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx index f96efee30..c80b7d22a 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/activity/components/TransactionDetailsProxy.tsx @@ -29,10 +29,12 @@ export const TransactionDetailsProxy = withAddressBookContext( const { list: addressList } = useAddressBookContext(); const { CEXPLORER_BASE_URL, CEXPLORER_URL_PATHS } = config(); - const explorerBaseUrl = useMemo( - () => `${CEXPLORER_BASE_URL[environmentName]}/${CEXPLORER_URL_PATHS.Tx}`, - [CEXPLORER_BASE_URL, CEXPLORER_URL_PATHS.Tx, environmentName] - ); + // TODO, remove if sanchonet gets an explorer + const explorerBaseUrl = useMemo(() => { + if (environmentName === 'Sanchonet') return; + // eslint-disable-next-line consistent-return + return `${CEXPLORER_BASE_URL[environmentName]}/${CEXPLORER_URL_PATHS.Tx}`; + }, [CEXPLORER_BASE_URL, CEXPLORER_URL_PATHS.Tx, environmentName]); const getHeaderDescription = () => { if (activityInfo.type === 'delegation') return '1 token'; return ` (${activityInfo?.assetAmount})`; @@ -72,6 +74,10 @@ export const TransactionDetailsProxy = withAddressBookContext( [addressList] ); + const environmentSpecificProps = { + ...(explorerBaseUrl && { openExternalLink: handleOpenExternalLink }) + }; + return ( // eslint-disable-next-line react/jsx-pascal-case analytics.sendEventToPostHog(PostHogAction.ActivityActivityDetailInputsClick)} sendAnalyticsOutputs={() => analytics.sendEventToPostHog(PostHogAction.ActivityActivityDetailOutputsClick)} + {...environmentSpecificProps} /> ); } diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetDetailsDrawer/AssetDetails.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetDetailsDrawer/AssetDetails.tsx index beac455ca..89c670e2d 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetDetailsDrawer/AssetDetails.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/assets/components/AssetDetailsDrawer/AssetDetails.tsx @@ -48,7 +48,12 @@ export const AssetDetails = ({ const { environmentName } = useWalletStore(); const openExternalLink = useExternalLinkOpener(); - const explorerBaseUrl = useMemo(() => CEXPLORER_BASE_URL[environmentName], [environmentName]); + // TODO remove if sanchonet gets an explorer + const explorerBaseUrl = useMemo(() => { + if (environmentName === 'Sanchonet') return; + // eslint-disable-next-line consistent-return + return CEXPLORER_BASE_URL[environmentName]; + }, [environmentName]); const isTxListLoading = activityListStatus === StateStatus.IDLE || activityListStatus === StateStatus.LOADING; return ( @@ -111,13 +116,19 @@ export const AssetDetails = ({ name: t('browserView.assetDetails.fingerprint'), value: fingerprint, showCopyIcon: true, - onClick: () => openExternalLink(`${explorerBaseUrl}/${CEXPLORER_URL_PATHS.Asset}/${fingerprint}`) + // TODO remove if sanchonet gets an explorer + ...(explorerBaseUrl && { + onClick: () => openExternalLink(`${explorerBaseUrl}/${CEXPLORER_URL_PATHS.Asset}/${fingerprint}`) + }) }, { name: t('browserView.assetDetails.policyId'), value: policyId, showCopyIcon: true, - onClick: () => openExternalLink(`${explorerBaseUrl}/${CEXPLORER_URL_PATHS.Policy}/${policyId}`) + // TODO remove if sanchonet gets an explorer + ...(explorerBaseUrl && { + onClick: () => openExternalLink(`${explorerBaseUrl}/${CEXPLORER_URL_PATHS.Policy}/${policyId}`) + }) } ]} /> diff --git a/apps/browser-extension-wallet/src/views/browser-view/features/settings/components/NetworkChoice.tsx b/apps/browser-extension-wallet/src/views/browser-view/features/settings/components/NetworkChoice.tsx index 288e5e6d4..6f73351f8 100644 --- a/apps/browser-extension-wallet/src/views/browser-view/features/settings/components/NetworkChoice.tsx +++ b/apps/browser-extension-wallet/src/views/browser-view/features/settings/components/NetworkChoice.tsx @@ -17,23 +17,27 @@ const { AVAILABLE_CHAINS } = config(); type networkEventSettings = | PostHogAction.SettingsNetworkPreviewClick | PostHogAction.SettingsNetworkPreprodClick - | PostHogAction.SettingsNetworkMainnetClick; + | PostHogAction.SettingsNetworkMainnetClick + | PostHogAction.SettingsNetworkSanchonetClick; type networkEventUserWalletProfile = | PostHogAction.UserWalletProfileNetworkPreviewClick | PostHogAction.UserWalletProfileNetworkPreprodClick - | PostHogAction.UserWalletProfileNetworkMainnetClick; + | PostHogAction.UserWalletProfileNetworkMainnetClick + | PostHogAction.UserWalletProfileNetworkSanchonetClick; -const settingsEventByNetworkName: Partial> = { +const settingsEventByNetworkName: Record = { Mainnet: PostHogAction.SettingsNetworkMainnetClick, Preprod: PostHogAction.SettingsNetworkPreprodClick, - Preview: PostHogAction.SettingsNetworkPreviewClick + Preview: PostHogAction.SettingsNetworkPreviewClick, + Sanchonet: PostHogAction.SettingsNetworkSanchonetClick }; -const walletProfileEventByNetworkName: Partial> = { +const walletProfileEventByNetworkName: Record = { Mainnet: PostHogAction.UserWalletProfileNetworkMainnetClick, Preprod: PostHogAction.UserWalletProfileNetworkPreprodClick, - Preview: PostHogAction.UserWalletProfileNetworkPreviewClick + Preview: PostHogAction.UserWalletProfileNetworkPreviewClick, + Sanchonet: PostHogAction.UserWalletProfileNetworkSanchonetClick }; export const NetworkChoice = ({ section }: { section?: 'settings' | 'wallet-profile' }): React.ReactElement => { @@ -51,6 +55,8 @@ export const NetworkChoice = ({ section }: { section?: 'settings' | 'wallet-prof return t('general.networks.preprod'); case 'Preview': return t('general.networks.preview'); + case 'Sanchonet': + return t('general.networks.sanchonet'); default: return ''; } diff --git a/apps/browser-extension-wallet/test/__mocks__/set-env-vars.js b/apps/browser-extension-wallet/test/__mocks__/set-env-vars.js index ca04f6597..a28abab98 100644 --- a/apps/browser-extension-wallet/test/__mocks__/set-env-vars.js +++ b/apps/browser-extension-wallet/test/__mocks__/set-env-vars.js @@ -1,11 +1,12 @@ process.env.CARDANO_SERVICES_URL_PREVIEW = 'https://preview-prod.com'; process.env.CARDANO_SERVICES_URL_PREPROD = 'https://preprod-prod.com'; process.env.CARDANO_SERVICES_URL_MAINNET = 'https://mainnet-url.com'; -process.env.AVAILABLE_CHAINS = 'Preprod,Preview,Mainnet'; +process.env.CARDANO_SERVICES_URL_SANCHONET = 'https://sanchonet-url.com'; +process.env.AVAILABLE_CHAINS = 'Preprod,Preview,Mainnet,Sanchonet'; process.env.CEXPLORER_URL_MAINNET = 'https://cexplorer.io'; process.env.CEXPLORER_URL_PREVIEW = 'https://preview.cexplorer.io'; process.env.CEXPLORER_URL_PREPROD = 'https://preprod.cexplorer.io'; -process.env.CEXPLORER_URL_TESTNET = 'https://testnet.cexplorer.io'; +process.env.CEXPLORER_URL_SANCHONET = 'https://sanchonet.cexplorer.io'; process.env.USE_HIDE_MY_BALANCE = 'true'; process.env.USE_POSTHOG_ANALYTICS = 'true'; process.env.USE_POSTHOG_ANALYTICS_FOR_OPTED_OUT = 'false'; diff --git a/apps/browser-extension-wallet/webpack-utils.js b/apps/browser-extension-wallet/webpack-utils.js index 6e1747731..a84c27cc2 100644 --- a/apps/browser-extension-wallet/webpack-utils.js +++ b/apps/browser-extension-wallet/webpack-utils.js @@ -9,11 +9,11 @@ const transformManifest = (content, mode) => { manifest.content_security_policy.extension_pages = manifest.content_security_policy.extension_pages .replace( '$CARDANO_SERVICES_URLS', - `${process.env.CARDANO_SERVICES_URL_MAINNET} ${process.env.CARDANO_SERVICES_URL_PREPROD} ${process.env.CARDANO_SERVICES_URL_PREVIEW}` + `${process.env.CARDANO_SERVICES_URL_MAINNET} ${process.env.CARDANO_SERVICES_URL_PREPROD} ${process.env.CARDANO_SERVICES_URL_PREVIEW} ${process.env.CARDANO_SERVICES_URL_SANCHONET}` ) .replace( '$ADA_HANDLE_URLS', - `${process.env.ADA_HANDLE_URL_MAINNET} ${process.env.ADA_HANDLE_URL_PREPROD} ${process.env.ADA_HANDLE_URL_PREVIEW}` + `${process.env.ADA_HANDLE_URL_MAINNET} ${process.env.ADA_HANDLE_URL_PREPROD} ${process.env.ADA_HANDLE_URL_PREVIEW} ${process.env.ADA_HANDLE_URL_SANCHONET}` ) .replace('$LOCALHOST_DEFAULT_SRC', mode === 'development' ? 'http://localhost:3000' : '') .replace('$LOCALHOST_SCRIPT_SRC', mode === 'development' ? 'http://localhost:3000' : '') diff --git a/packages/cardano/src/wallet/types.ts b/packages/cardano/src/wallet/types.ts index ab4164389..a193f1fbf 100644 --- a/packages/cardano/src/wallet/types.ts +++ b/packages/cardano/src/wallet/types.ts @@ -28,14 +28,27 @@ export enum TransactionStatus { SPENDABLE = 'spendable' } +export enum Cip30TxType { + Send = 'Send', + Mint = 'Mint', + Burn = 'Burn', + DRepRegistration = 'DRepRegistration', + DRepRetirement = 'DRepRetirement', + DRepUpdate = 'DRepUpdate', + VoteDelegation = 'VoteDelegation', + VotingProcedures = 'VotingProcedures' +} + +export type Cip30SignTxOutput = { + coins: string; + recipient: string; + assets?: Cip30SignTxAssetItem[]; +}; + export type Cip30SignTxSummary = { fee: string; - outputs: { - coins: string; - recipient: string; - assets?: Cip30SignTxAssetItem[]; - }[]; - type: 'Send' | 'Mint'; + outputs: Cip30SignTxOutput[]; + type: Cip30TxType; mintedAssets?: Cip30SignTxAssetItem[]; burnedAssets?: Cip30SignTxAssetItem[]; }; @@ -48,8 +61,8 @@ export type Cip30SignTxAssetItem = { export enum WalletManagerProviderTypes { CARDANO_SERVICES_PROVIDER = 'cardano-services-provider' } -// Exclude Sanchonet until in main branch -export type ChainName = keyof Omit; + +export type ChainName = keyof typeof Cardano.ChainIds; export interface CreateHardwareWalletArgs { deviceConnection: DeviceConnection; diff --git a/packages/common/src/analytics/types.ts b/packages/common/src/analytics/types.ts index 021949f17..a9c0cb63c 100644 --- a/packages/common/src/analytics/types.ts +++ b/packages/common/src/analytics/types.ts @@ -138,6 +138,7 @@ export enum PostHogAction { SettingsNetworkPreviewClick = 'settings | network | preview | click', SettingsNetworkPreprodClick = 'settings | network | preprod | click', SettingsNetworkMainnetClick = 'settings | network | mainnet | click', + SettingsNetworkSanchonetClick = 'settings | network | sanchonet | click', SettingsNetworkXClick = 'settings | network | x | click', SettingsAuthorizedDappsClick = 'settings | authorized dapps | click', SettingsAuthorizedDappsTrashBinIconClick = 'settings | authorized dapps | trash bin icon | click', @@ -187,6 +188,7 @@ export enum PostHogAction { UserWalletProfileNetworkPreviewClick = 'user/wallet profile | network | preview | click', UserWalletProfileNetworkPreprodClick = 'user/wallet profile | network | preprod | click', UserWalletProfileNetworkMainnetClick = 'user/wallet profile | network | mainnet | click', + UserWalletProfileNetworkSanchonetClick = 'user/wallet profile | network | sanchonet | click', UserWalletProfileLockWalletClick = 'user/wallet profile | lock wallet | click', // Lace Logo WalletLaceClick = 'wallet | lace | click', diff --git a/packages/core/.babelrc.json b/packages/core/.babelrc.json new file mode 100644 index 000000000..9164ce7ce --- /dev/null +++ b/packages/core/.babelrc.json @@ -0,0 +1,18 @@ +{ + "sourceType": "unambiguous", + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "chrome": 100, + "safari": 15, + "firefox": 91 + } + } + ], + "@babel/preset-typescript", + "@babel/preset-react" + ], + "plugins": [] +} diff --git a/packages/core/.storybook/main.js b/packages/core/.storybook/main.js new file mode 100644 index 000000000..0670843c0 --- /dev/null +++ b/packages/core/.storybook/main.js @@ -0,0 +1,51 @@ +module.exports = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + 'storybook-addon-pseudo-states', + { + name: '@storybook/addon-styling', + options: { + sass: { + // Require your Sass preprocessor here + implementation: require('sass') + } + } + } + ], + framework: '@storybook/react', + webpackFinal: (config) => { + const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test('.svg')); + fileLoaderRule.exclude = /\.svg$/; + + config.module.rules.push({ + test: /\.svg$/i, + issuer: /\.[jt]sx?$/, + use: [ + { + loader: '@svgr/webpack', + options: { + icon: true, + exportType: 'named' + } + } + ] + }); + + config.resolve.extensions.push('.svg'); + + return config; + }, + core: { + builder: 'webpack5', + options: { + lazyCompilation: true, + fsCache: true + } + }, + features: { + interactionsDebugger: true + } +}; diff --git a/packages/core/.storybook/preview-head.html b/packages/core/.storybook/preview-head.html new file mode 100644 index 000000000..7819a8476 --- /dev/null +++ b/packages/core/.storybook/preview-head.html @@ -0,0 +1,6 @@ + + + + + +Lace UI toolkit diff --git a/packages/core/.storybook/preview.js b/packages/core/.storybook/preview.js new file mode 100644 index 000000000..7ffa549ee --- /dev/null +++ b/packages/core/.storybook/preview.js @@ -0,0 +1,27 @@ +import React from 'react'; +import 'antd/dist/antd.css'; +import 'normalize.css'; +import './theme.scss'; +import { ThemeColorScheme, ThemeProvider } from '@lace/ui'; + +export const preview = { + parameters: { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/ + } + } + } +}; + +export const decorators = [ + (Story) => { + return ( + + + + ); + } +]; diff --git a/packages/core/.storybook/theme.scss b/packages/core/.storybook/theme.scss new file mode 100644 index 000000000..853cd9ddd --- /dev/null +++ b/packages/core/.storybook/theme.scss @@ -0,0 +1,36 @@ +@import '../../common/src/ui/styles/abstracts/mixins'; +@import '../../common/src/ui/styles/themes/dark'; +@import '../../common/src/ui/styles/themes/light'; + +@mixin dark-theme { + /* + in case the theme provider is not being used, this media query allows us to use the theme set on the user system + */ + @media (prefers-color-scheme: dark) { + :root { + @include theme-custom-properties($dark-theme); + } + } + + html[data-theme='dark'] { + @include theme-custom-properties($dark-theme); + } +} + +@mixin light-theme { + /* + in case the theme provider is not being used, this media query allows us to use the theme set on the user system + */ + @media (prefers-color-scheme: light) { + :root { + @include theme-custom-properties($light-theme); + } + } + + html[data-theme='light'] { + @include theme-custom-properties($light-theme); + } +} + +@include dark-theme; +@include light-theme; diff --git a/packages/core/package.json b/packages/core/package.json index 6001c1054..c1a167840 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,11 +27,13 @@ ], "scripts": { "build": "run -T rollup -c rollup.config.js", + "build-storybook": "storybook build", "cleanup": "yarn exec rm -rf dist node_modules coverage .rollup.cache src/dist", "lint": "cd ../.. && yarn core:lint", "prepack": "yarn build", "prestart": "yarn build", "start": "node dist/index.js", + "storybook": "NODE_OPTIONS=--openssl-legacy-provider; start-storybook -p 6006", "test": "NODE_ENV=test run -T jest -c ./test/jest.config.js", "test:coverage": "yarn test --coverage", "watch": "yarn build --watch" @@ -56,7 +58,26 @@ "zxcvbn": "^4.4.2" }, "devDependencies": { + "@babel/preset-env": "^7.22.20", + "@babel/preset-react": "^7.22.15", + "@babel/preset-typescript": "^7.22.15", + "@storybook/addon-actions": "^6.5.16", + "@storybook/addon-essentials": "^6.5.16", + "@storybook/addon-interactions": "^6.5.16", + "@storybook/addon-links": "^6.5.16", + "@storybook/addon-styling": "^1.3.7", + "@storybook/addon-styling-webpack": "^0.0.5", + "@storybook/builder-webpack5": "6.5.16", + "@storybook/core-events": "^6.5.16", + "@storybook/jest": "^0.0.10", + "@storybook/manager-webpack5": "6.5.16", + "@storybook/react": "^6.5.16", + "@storybook/test-runner": "^0.10.0", + "@storybook/testing-library": "^0.0.13", + "@types/babel__preset-env": "^7", "@types/debounce-promise": "^3.1.6", + "sass": "^1.68.0", + "storybook": "^7.4.3", "typescript": "^4.3.5" }, "peerDependencies": { diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 4aa7bab6a..cd74f3960 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -28,3 +28,8 @@ export * from '@ui/components/DappTransaction'; export * from '@ui/components/Send/SendTransactionCost'; export * from '@ui/components/MnemonicWordsAutoComplete'; export * from '@ui/components/AddressCard'; +export * from '@ui/components/ConfirmDRepRegistration'; +export * from '@ui/components/ConfirmDRepRetirement'; +export * from '@ui/components/ConfirmDRepUpdate'; +export * from '@ui/components/ConfirmVoteDelegation'; +export * from '@ui/components/VotingProcedures'; diff --git a/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx b/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx index bc40229b6..d8ae4967b 100644 --- a/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx +++ b/packages/core/src/ui/components/ActivityDetail/TransactionDetails.tsx @@ -140,8 +140,9 @@ export const TransactionDetails = ({
diff --git a/packages/core/src/ui/components/ConfirmDRepRegistration/ConfirmDRepRegistration.stories.tsx b/packages/core/src/ui/components/ConfirmDRepRegistration/ConfirmDRepRegistration.stories.tsx new file mode 100644 index 000000000..fd42d0903 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepRegistration/ConfirmDRepRegistration.stories.tsx @@ -0,0 +1,50 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { ConfirmDRepRegistration } from './ConfirmDRepRegistration'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'ConfirmDRepRegistration', + component: ConfirmDRepRegistration, + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + translations: { + labels: { + depositPaid: 'Deposit paid', + drepId: 'DRep ID', + hash: 'Hash', + url: 'URL' + }, + metadata: 'Metadata' + }, + metadata: { + depositPaid: '0.35 ADA', + drepId: '65ge6g54g5dd5', + hash: '9bba8233cdd086f0325daba465d568a88970d42536f9e71e92a80d5922ded885', + url: 'https://raw.githubusercontent.com/Ryun1/gov-metadata/main/governace-action/metadata.jsonldr1q99...uqvzlalu' + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; diff --git a/packages/core/src/ui/components/ConfirmDRepRegistration/ConfirmDRepRegistration.tsx b/packages/core/src/ui/components/ConfirmDRepRegistration/ConfirmDRepRegistration.tsx new file mode 100644 index 000000000..644b457fe --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepRegistration/ConfirmDRepRegistration.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { Box, Cell, Grid, TransactionSummary, Flex } from '@lace/ui'; +import { DappInfo, DappInfoProps } from '../DappInfo'; +import { ErrorPane } from '@lace/common'; +interface Props { + dappInfo: Omit; + errorMessage?: string; + translations: { + labels: { + url: string; + hash: string; + drepId: string; + depositPaid: string; + }; + metadata: string; + }; + metadata: { + url: string; + hash: string; + drepId: string; + depositPaid: string; + }; +} + +export const ConfirmDRepRegistration = ({ dappInfo, errorMessage, translations, metadata }: Props): JSX.Element => ( + + + + + {errorMessage && ( + + + + )} + + + + + {metadata.url && ( + + + + )} + {metadata.hash && ( + + + + )} + + + + + + + + +); diff --git a/packages/core/src/ui/components/ConfirmDRepRegistration/index.ts b/packages/core/src/ui/components/ConfirmDRepRegistration/index.ts new file mode 100644 index 000000000..cf5bded0e --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepRegistration/index.ts @@ -0,0 +1 @@ +export { ConfirmDRepRegistration } from './ConfirmDRepRegistration'; diff --git a/packages/core/src/ui/components/ConfirmDRepRetirement/ConfirmDRepRetirement.stories.tsx b/packages/core/src/ui/components/ConfirmDRepRetirement/ConfirmDRepRetirement.stories.tsx new file mode 100644 index 000000000..1bf53abd4 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepRetirement/ConfirmDRepRetirement.stories.tsx @@ -0,0 +1,46 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { ConfirmDRepRetirement } from './ConfirmDRepRetirement'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'ConfirmDRepRetirement', + component: ConfirmDRepRetirement, + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + translations: { + labels: { + depositReturned: 'Deposit paid', + drepId: 'DRep ID' + }, + metadata: 'Metadata' + }, + metadata: { + depositReturned: '0.35 ADA', + drepId: '65ge6g54g5dd5' + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; diff --git a/packages/core/src/ui/components/ConfirmDRepRetirement/ConfirmDRepRetirement.tsx b/packages/core/src/ui/components/ConfirmDRepRetirement/ConfirmDRepRetirement.tsx new file mode 100644 index 000000000..59219813a --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepRetirement/ConfirmDRepRetirement.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { Box, Cell, Grid, TransactionSummary, Flex } from '@lace/ui'; +import { DappInfo, DappInfoProps } from '../DappInfo'; +import { ErrorPane } from '@lace/common'; + +interface Props { + dappInfo: Omit; + errorMessage?: string; + translations: { + labels: { + drepId: string; + depositReturned: string; + }; + metadata: string; + }; + metadata: { + drepId: string; + depositReturned: string; + }; +} + +export const ConfirmDRepRetirement = ({ dappInfo, errorMessage, translations, metadata }: Props): JSX.Element => ( + + + + + {errorMessage && ( + + + + )} + + + + + + + + + + + + +); diff --git a/packages/core/src/ui/components/ConfirmDRepRetirement/index.ts b/packages/core/src/ui/components/ConfirmDRepRetirement/index.ts new file mode 100644 index 000000000..cb0e8d0d1 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepRetirement/index.ts @@ -0,0 +1 @@ +export { ConfirmDRepRetirement } from './ConfirmDRepRetirement'; diff --git a/packages/core/src/ui/components/ConfirmDRepUpdate/ConfirmDRepUpdate.stories.tsx b/packages/core/src/ui/components/ConfirmDRepUpdate/ConfirmDRepUpdate.stories.tsx new file mode 100644 index 000000000..c24658cde --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepUpdate/ConfirmDRepUpdate.stories.tsx @@ -0,0 +1,58 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { ConfirmDRepUpdate } from './ConfirmDRepUpdate'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'ConfirmDRepUpdate', + component: ConfirmDRepUpdate, + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + translations: { + labels: { + drepId: 'DRep ID', + hash: 'Hash', + url: 'URL' + }, + metadata: 'Metadata' + }, + metadata: { + drepId: '65ge6g54g5dd5', + hash: '9bba8233cdd086f0325daba465d568a88970d42536f9e71e92a80d5922ded885', + url: 'https://raw.githubusercontent.com/Ryun1/gov-metadata/main/governace-action/metadata.jsonldr1q99...uqvzlalu' + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; + +export const Empty: Story = { + args: { + ...data, + metadata: { + drepId: '65ge6g54g5dd5' + } + } +}; + +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; diff --git a/packages/core/src/ui/components/ConfirmDRepUpdate/ConfirmDRepUpdate.tsx b/packages/core/src/ui/components/ConfirmDRepUpdate/ConfirmDRepUpdate.tsx new file mode 100644 index 000000000..e86ee2b77 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepUpdate/ConfirmDRepUpdate.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { Box, Cell, Grid, TransactionSummary, Flex } from '@lace/ui'; +import { DappInfo, DappInfoProps } from '../DappInfo'; +import { ErrorPane } from '@lace/common'; + +interface Props { + dappInfo: Omit; + errorMessage?: string; + translations: { + labels: { + url: string; + hash: string; + drepId: string; + }; + metadata: string; + }; + metadata: { + url?: string; + hash?: string; + drepId: string; + }; +} + +export const ConfirmDRepUpdate = ({ dappInfo, errorMessage, translations, metadata }: Props): JSX.Element => ( + + + + + {errorMessage && ( + + + + )} + + + + + {metadata.url && ( + + + + )} + {metadata.hash && ( + + + + )} + + + + + +); diff --git a/packages/core/src/ui/components/ConfirmDRepUpdate/index.ts b/packages/core/src/ui/components/ConfirmDRepUpdate/index.ts new file mode 100644 index 000000000..1017f7880 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmDRepUpdate/index.ts @@ -0,0 +1 @@ +export { ConfirmDRepUpdate } from './ConfirmDRepUpdate'; diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.tsx b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.tsx new file mode 100644 index 000000000..370d32130 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.tsx @@ -0,0 +1,69 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { ConfirmVoteDelegation } from './ConfirmVoteDelegation'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'ConfirmVoteDelegation', + component: ConfirmVoteDelegation, + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + translations: { + labels: { + drepId: 'DRep ID', + alwaysAbstain: 'Abstain', + alwaysNoConfidence: 'No Confidence' + }, + option: 'Yes', + metadata: 'Metadata' + }, + metadata: { + drepId: 'drep1ruvgm0auzdplfn7g2jf3kcnpnw5mlhwxaxj8crag8h6t2ye9y9g', + alwaysAbstain: false, + alwaysNoConfidence: false + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; + +export const WithAbstain: Story = { + args: { + ...data, + metadata: { + alwaysAbstain: true, + alwaysNoConfidence: false + } + } +}; + +export const WithNoConfidence: Story = { + args: { + ...data, + metadata: { + alwaysAbstain: false, + alwaysNoConfidence: true + } + } +}; diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx new file mode 100644 index 000000000..c69240128 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { Box, Cell, Grid, TransactionSummary, Flex } from '@lace/ui'; +import { DappInfo, DappInfoProps } from '../DappInfo'; +import { ErrorPane } from '@lace/common'; + +interface Props { + dappInfo: Omit; + errorMessage?: string; + translations: { + labels: { + drepId: string; + alwaysAbstain: string; + alwaysNoConfidence: string; + }; + option: string; + metadata: string; + }; + metadata: { + drepId?: string; + alwaysAbstain: boolean; + alwaysNoConfidence: boolean; + }; +} + +export const ConfirmVoteDelegation = ({ dappInfo, errorMessage, translations, metadata }: Props): JSX.Element => ( + + + + + {errorMessage && ( + + + + )} + + + + + {metadata.drepId && ( + + + + )} + {metadata.alwaysAbstain && ( + + + + )} + {metadata.alwaysNoConfidence && ( + + + + )} + + +); diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/index.ts b/packages/core/src/ui/components/ConfirmVoteDelegation/index.ts new file mode 100644 index 000000000..33e8e6755 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/index.ts @@ -0,0 +1 @@ +export { ConfirmVoteDelegation } from './ConfirmVoteDelegation'; diff --git a/packages/core/src/ui/components/DappTransaction/DappTransaction.stories.tsx b/packages/core/src/ui/components/DappTransaction/DappTransaction.stories.tsx new file mode 100644 index 000000000..56f29d053 --- /dev/null +++ b/packages/core/src/ui/components/DappTransaction/DappTransaction.stories.tsx @@ -0,0 +1,60 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { DappTransaction } from './DappTransaction'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'DappTransaction', + component: DappTransaction, + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + translations: { + recipient: 'Recipient', + amount: 'Amount', + adaFollowingNumericValue: 'ADA', + fee: 'Fee', + transaction: 'Transaction' + }, + transaction: { + fee: '0.17', + outputs: [ + { + coins: '1', + recipient: + 'addr_test1qrl0s3nqfljv8dfckn7c4wkzu5rl6wn4hakkddcz2mczt3szlqss933x0aag07qcgspcaglmay6ufl4y4lalmlpe02mqhl0fx2' + } + ], + type: 'Mint' + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; + +export const WithInsufficientFunds: Story = { + args: { + ...data + } +}; + +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; diff --git a/packages/core/src/ui/components/DappTransaction/DappTransaction.tsx b/packages/core/src/ui/components/DappTransaction/DappTransaction.tsx index 9f5717baa..6b0d0bce8 100644 --- a/packages/core/src/ui/components/DappTransaction/DappTransaction.tsx +++ b/packages/core/src/ui/components/DappTransaction/DappTransaction.tsx @@ -4,23 +4,15 @@ import { ErrorPane } from '@lace/common'; import { Wallet } from '@lace/cardano'; import { DappInfo, DappInfoProps } from '../DappInfo'; import { DappTxHeader } from './DappTxHeader/DappTxHeader'; -import { DappTxAsset, DappTxAssetProps } from './DappTxAsset/DappTxAsset'; -import { DappTxOutput, DappTxOutputProps } from './DappTxOutput/DappTxOutput'; +import { DappTxAsset } from './DappTxAsset/DappTxAsset'; +import { DappTxOutput } from './DappTxOutput/DappTxOutput'; import styles from './DappTransaction.module.scss'; import { useTranslate } from '@src/ui/hooks'; import { TransactionFee } from '@ui/components/ActivityDetail'; -type TransactionDetails = { - fee: string; - outputs: DappTxOutputProps[]; - type: 'Send' | 'Mint'; - mintedAssets?: DappTxAssetProps[]; - burnedAssets?: DappTxAssetProps[]; -}; - export interface DappTransactionProps { /** Transaction details such as type, amount, fee and address */ - transaction: TransactionDetails; + transaction: Wallet.Cip30SignTxSummary; /** dApp information such as logo, name and url */ dappInfo: Omit; /** Optional error message */ @@ -44,7 +36,7 @@ export const DappTransaction = ({ {errorMessage && }
- {type === 'Mint' && mintedAssets?.length > 0 && ( + {type === Wallet.Cip30TxType.Mint && mintedAssets?.length > 0 && ( <> )} - {type === 'Mint' && burnedAssets?.length > 0 && ( + {type === Wallet.Cip30TxType.Burn && burnedAssets?.length > 0 && ( <> 0 ? undefined : t('package.core.dappTransaction.transaction')} @@ -66,7 +58,7 @@ export const DappTransaction = ({ ))} )} - {type === 'Send' && ( + {type === Wallet.Cip30TxType.Send && ( <> { +export const DappTxAsset = ({ amount, name, ticker }: Wallet.Cip30SignTxAssetItem): React.ReactElement => { const { t } = useTranslate(); return (
diff --git a/packages/core/src/ui/components/DappTransaction/DappTxAsset/index.ts b/packages/core/src/ui/components/DappTransaction/DappTxAsset/index.ts new file mode 100644 index 000000000..3418661f1 --- /dev/null +++ b/packages/core/src/ui/components/DappTransaction/DappTxAsset/index.ts @@ -0,0 +1 @@ +export { DappTxAsset } from './DappTxAsset'; diff --git a/packages/core/src/ui/components/DappTransaction/DappTxOutput/DappTxOutput.tsx b/packages/core/src/ui/components/DappTransaction/DappTxOutput/DappTxOutput.tsx index d60892916..9eccd4e0e 100644 --- a/packages/core/src/ui/components/DappTransaction/DappTxOutput/DappTxOutput.tsx +++ b/packages/core/src/ui/components/DappTransaction/DappTxOutput/DappTxOutput.tsx @@ -1,13 +1,13 @@ import React from 'react'; import { Ellipsis } from '@lace/common'; -import { DappTxAssetProps } from '../DappTxAsset/DappTxAsset'; import styles from './DappTxOutput.module.scss'; import { useTranslate } from '@src/ui/hooks'; +import { Wallet } from '@lace/cardano'; export interface DappTxOutputProps { coins: string; recipient: string; - assets?: DappTxAssetProps[]; + assets?: Wallet.Cip30SignTxAssetItem[]; } export const DappTxOutput = ({ recipient, coins, assets }: DappTxOutputProps): React.ReactElement => { diff --git a/packages/core/src/ui/components/InsufficientFundsWarning/InsufficientFundsWarning.module.scss b/packages/core/src/ui/components/InsufficientFundsWarning/InsufficientFundsWarning.module.scss new file mode 100644 index 000000000..303cbebf6 --- /dev/null +++ b/packages/core/src/ui/components/InsufficientFundsWarning/InsufficientFundsWarning.module.scss @@ -0,0 +1,23 @@ +@import '../../styles/theme.scss'; +@import '../../../../../common/src/ui/styles/abstracts/_typography.scss'; + +.warningAlert { + flex-direction: row; + background: var(--lace-cream); + display: flex; + align-items: center; + border-radius: size_unit(2); + padding: size_unit(2) size_unit(3); + gap: size_unit(3); + + svg { + height: size_unit(3); + width: size_unit(3); + color: var(--data-orange); + } + + p { + @include text-body-semi-bold; + margin: 0; + } +} diff --git a/packages/core/src/ui/components/InsufficientFundsWarning/InsufficientFundsWarning.tsx b/packages/core/src/ui/components/InsufficientFundsWarning/InsufficientFundsWarning.tsx new file mode 100644 index 000000000..7823ca8d4 --- /dev/null +++ b/packages/core/src/ui/components/InsufficientFundsWarning/InsufficientFundsWarning.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import styles from './InsufficientFundsWarning.module.scss'; +import { ReactComponent as WarningIcon } from '../../assets/icons/warning-icon.component.svg'; +import Icon from '@ant-design/icons'; + +export interface DappTransactionProps { + translations: string; +} + +export const InsufficientFundsWarning = ({ translations }: DappTransactionProps): React.ReactElement => ( +
+ +

{translations}

+
+); diff --git a/packages/core/src/ui/components/InsufficientFundsWarning/index.ts b/packages/core/src/ui/components/InsufficientFundsWarning/index.ts new file mode 100644 index 000000000..fdd126c9d --- /dev/null +++ b/packages/core/src/ui/components/InsufficientFundsWarning/index.ts @@ -0,0 +1 @@ +export * from './InsufficientFundsWarning'; diff --git a/packages/core/src/ui/components/VotingProcedures/VotingProcedures.stories.tsx b/packages/core/src/ui/components/VotingProcedures/VotingProcedures.stories.tsx new file mode 100644 index 000000000..72a297d79 --- /dev/null +++ b/packages/core/src/ui/components/VotingProcedures/VotingProcedures.stories.tsx @@ -0,0 +1,107 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { VotingProcedures } from './VotingProcedures'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'VotingProcedures', + component: VotingProcedures, + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + data: [ + { + voter: { + type: 'DRep', + dRepId: 'drep1cs234l5mtapethapx8cq97nkpa27xf84phruh5f6jqxa78ymlp4' + }, + votes: [ + { + actionId: { + index: 0, + txHash: '26bfdcc75a7f4d0cd8c71f0189bc5ca5ad2f4a3db6240c82b5a0edac7f9203e0', + txHashUrl: + 'https://cexplorer.io/address/addr1q9wlvfl74g9h8txw5v0lfew2gjsw9z56d5kj8mmv5d8tudcx9eh8zefr3cxuje02lu6tgy083xkl39rr5xkj483vvd6q8nlapq' + }, + votingProcedure: { + anchor: { + hash: '9067f223838d88b83f660c05eedf7f6f65c45de31e522c1bcb6a1eb287b17e89', + url: 'https://shorturl.at/eK145' + }, + vote: 'Yes' + } + } + ] + } + ], + translations: { + voterType: 'Voter type', + procedureTitle: 'Procedure', + actionIdTitle: 'Action ID', + vote: 'Vote', + actionId: { + index: 'Index', + txHash: 'TX Hash' + }, + anchor: { + hash: 'Anchor Hash', + url: 'Anchor URL' + }, + dRepId: 'DRep ID' + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; + +export const MultipleVotes: Story = { + args: { + ...data, + data: [ + ...data.data, + { + voter: { + type: 'DRep', + dRepId: 'drep1cs234l5mtapethapx8cq97nkpa27xf84phruh5f6jqxa78ymlp4' + }, + votes: [ + { + actionId: { + index: 0, + txHash: '26bfdcc75a7f4d0cd8c71f0189bc5ca5ad2f4a3db6240c82b5a0edac7f9203e0', + txHashUrl: + 'https://cexplorer.io/address/addr1q9wlvfl74g9h8txw5v0lfew2gjsw9z56d5kj8mmv5d8tudcx9eh8zefr3cxuje02lu6tgy083xkl39rr5xkj483vvd6q8nlapq' + }, + votingProcedure: { + anchor: { + hash: '9067f223838d88b83f660c05eedf7f6f65c45de31e522c1bcb6a1eb287b17e89', + url: 'https://shorturl.at/eK145' + }, + vote: 'Yes' + } + } + ] + } + ] + } +}; diff --git a/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx b/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx new file mode 100644 index 000000000..232b6aa43 --- /dev/null +++ b/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx @@ -0,0 +1,133 @@ +import React, { Fragment } from 'react'; +import { Box, Cell, Grid, Flex, Metadata, MetadataLink, Text, Divider, sx } from '@lace/ui'; +import { DappInfo, DappInfoProps } from '../DappInfo'; +import { ErrorPane } from '@lace/common'; + +type VotingProcedure = { + voter: { + type: string; + dRepId: string; + }; + votes: { + actionId: { + index: number; + txHash: string; + txHashUrl?: string; // Dependent on having an explorer to link + }; + votingProcedure: { + vote: string; + anchor: { + url: string; + hash: string; + } | null; + }; + }[]; +}; + +interface Props { + dappInfo: Omit; + errorMessage?: string; + data: VotingProcedure[]; + translations: { + actionIdTitle: string; + actionId: { + index: string; + txHash: string; + }; + anchor?: { + url: string; + hash: string; + }; + dRepId: string; + procedureTitle: string; + vote: string; + voterType: string; + }; +} + +const indexCounter = (text: string, idx: number, length: number): string => (length > 1 ? `${text} ${idx + 1}` : text); + +export const VotingProcedures = ({ dappInfo, errorMessage, data, translations }: Props): JSX.Element => { + const textCss = sx({ + color: '$text_primary' + }); + + return ( + + + + + {errorMessage && ( + + + + )} + {data.map(({ voter, votes }, idx) => ( + 0 ? '$40' : '$0'}> + + + + {indexCounter(translations.vote, idx, data.length)} + + + + + + + + + + + + {votes.map(({ actionId, votingProcedure }) => ( + + + + {indexCounter(translations.procedureTitle, idx, votes.length)} + + + + + + {votingProcedure.anchor && ( + <> + + + + + + + + )} + + + + + + {indexCounter(translations.actionIdTitle, idx, votes.length)} + + + {actionId.txHashUrl && ( + + + + )} + + + + + ))} + + + ))} + + ); +}; diff --git a/packages/core/src/ui/components/VotingProcedures/index.ts b/packages/core/src/ui/components/VotingProcedures/index.ts new file mode 100644 index 000000000..0bc283f6b --- /dev/null +++ b/packages/core/src/ui/components/VotingProcedures/index.ts @@ -0,0 +1 @@ +export { VotingProcedures } from './VotingProcedures'; diff --git a/packages/e2e-tests/src/assert/governance/CommonGovernancePageAssert.ts b/packages/e2e-tests/src/assert/governance/CommonGovernancePageAssert.ts new file mode 100644 index 000000000..e33914ede --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/CommonGovernancePageAssert.ts @@ -0,0 +1,55 @@ +import { expect } from 'chai'; +import { t } from '../../utils/translationService'; +import CommonGovernanceActionPageElements from '../../elements/governance/CommonGovernanceActionPageElements'; + +class CommonGovernancePageAssert { + commonGovernanceActionPageElements; + + constructor() { + this.commonGovernanceActionPageElements = new CommonGovernanceActionPageElements(); + } + + async assertSeeHeader(): Promise { + await this.commonGovernanceActionPageElements.headerLogo.waitForDisplayed(); + await this.commonGovernanceActionPageElements.betaPill.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.betaPill.getText()).to.equal(await t('core.dapp.beta')); + } + + async assertSeeTitle(expectedTitleKey: string): Promise { + await this.commonGovernanceActionPageElements.pageTitle.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.pageTitle.getText()).to.equal(await t(expectedTitleKey)); + } + + async assertSeeGovernanceDemoAppDetails( + expectedDAppName: string, + expectedDAppUrl: string, + expectedDAppLogoSrc: string + ): Promise { + await this.commonGovernanceActionPageElements.dAppLogo.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.headerLogo.$('img').getAttribute('src')).to.equal( + expectedDAppLogoSrc + ); + await this.commonGovernanceActionPageElements.dAppName.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.dAppName.getText()).to.equal(expectedDAppName); + await this.commonGovernanceActionPageElements.dAppUrl.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.dAppUrl.getText()).to.equal(expectedDAppUrl); + } + + async assertSeeMetadataHeader(expectedHeaderKey: string): Promise { + await this.commonGovernanceActionPageElements.metadataLabel.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.metadataLabel.getText()).to.equal(await t(expectedHeaderKey)); + } + + async assertSeeButtons(): Promise { + await this.commonGovernanceActionPageElements.confirmButton.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.confirmButton.getText()).to.equal( + await t('dapp.confirm.btn.confirm') + ); + await this.commonGovernanceActionPageElements.cancelButton.waitForDisplayed(); + expect(await this.commonGovernanceActionPageElements.cancelButton.getText()).to.equal( + await t('dapp.confirm.btn.cancel') + ); + } +} + +export default CommonGovernancePageAssert; diff --git a/packages/e2e-tests/src/assert/governance/ConfirmDRepRegistrationPageAssert.ts b/packages/e2e-tests/src/assert/governance/ConfirmDRepRegistrationPageAssert.ts new file mode 100644 index 000000000..a7db96b53 --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/ConfirmDRepRegistrationPageAssert.ts @@ -0,0 +1,51 @@ +import { expect } from 'chai'; +import { t } from '../../utils/translationService'; +import ConfirmDRepRegistrationPage from '../../elements/governance/ConfirmDRepRegistrationPage'; +import CommonGovernancePageAssert from './CommonGovernancePageAssert'; +import { GovernanceDemoAppDetails } from './GovernanceDemoAppDetails'; + +class ConfirmDRepRegistrationPageAssert extends CommonGovernancePageAssert { + async assertSeeConfirmDRepRegistrationPage( + expectedDRepID: string, + expectedMetadataUrl?: string, + expectedMetadataHash?: string + ) { + await this.assertSeeHeader(); + await this.assertSeeTitle('core.DRepRegistration.title'); + await this.assertSeeGovernanceDemoAppDetails( + GovernanceDemoAppDetails.dAppName, + GovernanceDemoAppDetails.dAppUrlShort, + GovernanceDemoAppDetails.dAppLogoSrc + ); + await this.assertSeeMetadataHeader('core.DRepRegistration.metadata'); + + await ConfirmDRepRegistrationPage.urlLabel.waitForDisplayed({ reverse: expectedMetadataUrl === '-' }); + await ConfirmDRepRegistrationPage.urlValue.waitForDisplayed({ reverse: expectedMetadataUrl === '-' }); + if (expectedMetadataUrl !== '-') { + expect(await ConfirmDRepRegistrationPage.urlLabel.getText()).to.equal(await t('core.DRepRegistration.url')); + expect(await ConfirmDRepRegistrationPage.urlValue.getText()).to.equal(expectedMetadataUrl); + } + + await ConfirmDRepRegistrationPage.hashLabel.waitForDisplayed({ reverse: expectedMetadataHash === '-' }); + await ConfirmDRepRegistrationPage.hashValue.waitForDisplayed({ reverse: expectedMetadataHash === '-' }); + if (expectedMetadataHash !== '-') { + expect(await ConfirmDRepRegistrationPage.hashLabel.getText()).to.equal(await t('core.DRepRegistration.hash')); + expect(await ConfirmDRepRegistrationPage.hashValue.getText()).to.equal(expectedMetadataHash); + } + + await ConfirmDRepRegistrationPage.dRepIdLabel.waitForDisplayed(); + expect(await ConfirmDRepRegistrationPage.dRepIdLabel.getText()).to.equal('core.DRepRegistration.drepId'); + await ConfirmDRepRegistrationPage.dRepIdValue.waitForDisplayed(); + expect(await ConfirmDRepRegistrationPage.dRepIdValue.getText()).to.equal(expectedDRepID); + await ConfirmDRepRegistrationPage.depositPaidLabel.waitForDisplayed(); + expect(await ConfirmDRepRegistrationPage.depositPaidLabel.getText()).to.equal( + await t('core.DRepRegistration.depositPaid') + ); + await ConfirmDRepRegistrationPage.depositPaidValue.waitForDisplayed(); + expect(await ConfirmDRepRegistrationPage.depositPaidValue.getText()).to.equal('2.00 tADA'); + + await this.assertSeeButtons(); + } +} + +export default new ConfirmDRepRegistrationPageAssert(); diff --git a/packages/e2e-tests/src/assert/governance/ConfirmDRepRetirementPageAssert.ts b/packages/e2e-tests/src/assert/governance/ConfirmDRepRetirementPageAssert.ts new file mode 100644 index 000000000..242ffec3b --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/ConfirmDRepRetirementPageAssert.ts @@ -0,0 +1,46 @@ +import CommonGovernancePageAssert from './CommonGovernancePageAssert'; +import { GovernanceDemoAppDetails } from './GovernanceDemoAppDetails'; +import { expect } from 'chai'; +import ConfirmDRepRetirementPage from '../../elements/governance/ConfirmDRepRetirementPage'; +import { t } from '../../utils/translationService'; + +class ConfirmDRepRetirementPageAssert extends CommonGovernancePageAssert { + async assertSeeConfirmDRepRetirementPage( + expectedDRepID: string, + expectedDepositReturned: string, + shouldDRepMatch = true + ) { + await this.assertSeeHeader(); + await this.assertSeeTitle('core.DRepRetirement.title'); + await this.assertSeeGovernanceDemoAppDetails( + GovernanceDemoAppDetails.dAppName, + GovernanceDemoAppDetails.dAppUrlShort, + GovernanceDemoAppDetails.dAppLogoSrc + ); + + await ConfirmDRepRetirementPage.errorPane.waitForDisplayed({ reverse: !shouldDRepMatch }); + if (shouldDRepMatch) { + expect(await ConfirmDRepRetirementPage.errorPane.getText()).to.equal( + await t('core.DRepRetirement.isNotOwnRetirement') + ); + } + + await this.assertSeeMetadataHeader('core.DRepRetirement.metadata'); + + await ConfirmDRepRetirementPage.dRepIdLabel.waitForDisplayed(); + expect(await ConfirmDRepRetirementPage.dRepIdLabel.getText()).to.equal('core.DRepRetirement.drepId'); + await ConfirmDRepRetirementPage.dRepIdValue.waitForDisplayed(); + expect(await ConfirmDRepRetirementPage.dRepIdValue.getText()).to.equal(expectedDRepID); + + await ConfirmDRepRetirementPage.depositReturnedLabel.waitForDisplayed(); + expect(await ConfirmDRepRetirementPage.depositReturnedLabel.getText()).to.equal( + await t('core.DRepRetirement.depositReturned') + ); + await ConfirmDRepRetirementPage.depositReturnedValue.waitForDisplayed(); + expect(await ConfirmDRepRetirementPage.depositReturnedValue.getText()).to.equal(expectedDepositReturned); + + await this.assertSeeButtons(); + } +} + +export default new ConfirmDRepRetirementPageAssert(); diff --git a/packages/e2e-tests/src/assert/governance/ConfirmDRepUpdatePageAssert.ts b/packages/e2e-tests/src/assert/governance/ConfirmDRepUpdatePageAssert.ts new file mode 100644 index 000000000..388ed0e2b --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/ConfirmDRepUpdatePageAssert.ts @@ -0,0 +1,45 @@ +import CommonGovernancePageAssert from './CommonGovernancePageAssert'; +import { GovernanceDemoAppDetails } from './GovernanceDemoAppDetails'; +import { expect } from 'chai'; +import { t } from '../../utils/translationService'; +import ConfirmDRepUpdatePage from '../../elements/governance/ConfirmDRepUpdatePage'; + +class ConfirmDRepUpdatePageAssert extends CommonGovernancePageAssert { + async assertSeeConfirmDRepUpdatePage( + expectedDRepID: string, + expectedMetadataUrl?: string, + expectedMetadataHash?: string + ) { + await this.assertSeeHeader(); + await this.assertSeeTitle('core.DRepUpdate.title'); + await this.assertSeeGovernanceDemoAppDetails( + GovernanceDemoAppDetails.dAppName, + GovernanceDemoAppDetails.dAppUrlShort, + GovernanceDemoAppDetails.dAppLogoSrc + ); + await this.assertSeeMetadataHeader('core.DRepUpdate.metadata'); + + await ConfirmDRepUpdatePage.urlLabel.waitForDisplayed({ reverse: expectedMetadataUrl === '-' }); + await ConfirmDRepUpdatePage.urlValue.waitForDisplayed({ reverse: expectedMetadataUrl === '-' }); + if (expectedMetadataUrl !== '-') { + expect(await ConfirmDRepUpdatePage.urlLabel.getText()).to.equal(await t('core.DRepUpdate.url')); + expect(await ConfirmDRepUpdatePage.urlValue.getText()).to.equal(expectedMetadataUrl); + } + + await ConfirmDRepUpdatePage.hashLabel.waitForDisplayed({ reverse: expectedMetadataHash === '-' }); + await ConfirmDRepUpdatePage.hashValue.waitForDisplayed({ reverse: expectedMetadataHash === '-' }); + if (expectedMetadataHash !== '-') { + expect(await ConfirmDRepUpdatePage.hashLabel.getText()).to.equal(await t('core.DRepUpdate.hash')); + expect(await ConfirmDRepUpdatePage.hashValue.getText()).to.equal(expectedMetadataHash); + } + + await ConfirmDRepUpdatePage.dRepIdLabel.waitForDisplayed(); + expect(await ConfirmDRepUpdatePage.dRepIdLabel.getText()).to.equal('core.DRepUpdate.drepId'); + await ConfirmDRepUpdatePage.dRepIdValue.waitForDisplayed(); + expect(await ConfirmDRepUpdatePage.dRepIdValue.getText()).to.equal(expectedDRepID); + + await this.assertSeeButtons(); + } +} + +export default new ConfirmDRepUpdatePageAssert(); diff --git a/packages/e2e-tests/src/assert/governance/ConfirmVoteDelegationPageAssert.ts b/packages/e2e-tests/src/assert/governance/ConfirmVoteDelegationPageAssert.ts new file mode 100644 index 000000000..bb3a405e5 --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/ConfirmVoteDelegationPageAssert.ts @@ -0,0 +1,48 @@ +import ConfirmVoteDelegationPage from '../../elements/governance/ConfirmVoteDelegationPage'; +import { expect } from 'chai'; +import { t } from '../../utils/translationService'; +import CommonGovernancePageAssert from './CommonGovernancePageAssert'; +import { GovernanceDemoAppDetails } from './GovernanceDemoAppDetails'; + +class ConfirmVoteDelegationPageAssert extends CommonGovernancePageAssert { + async assertSeeConfirmVoteDelegationPage(target: string) { + await this.assertSeeHeader(); + await this.assertSeeTitle('core.VoteDelegation.title'); + await this.assertSeeGovernanceDemoAppDetails( + GovernanceDemoAppDetails.dAppName, + GovernanceDemoAppDetails.dAppUrlShort, + GovernanceDemoAppDetails.dAppLogoSrc + ); + await this.assertSeeMetadataHeader('core.VoteDelegation.metadata'); + + switch (target) { + case 'abstain': + await ConfirmVoteDelegationPage.abstainLabel.waitForDisplayed(); + expect(await ConfirmVoteDelegationPage.abstainLabel.getText()).to.equal( + await t('core.VoteDelegation.alwaysAbstain') + ); + await ConfirmVoteDelegationPage.abstainValue.waitForDisplayed(); + expect(await ConfirmVoteDelegationPage.abstainValue.getText()).to.equal(await t('core.VoteDelegation.option')); + break; + case 'no confidence': + await ConfirmVoteDelegationPage.noConfidenceLabel.waitForDisplayed(); + expect(await ConfirmVoteDelegationPage.noConfidenceLabel.getText()).to.equal( + await t('core.VoteDelegation.alwaysNoConfidence') + ); + await ConfirmVoteDelegationPage.noConfidenceValue.waitForDisplayed(); + expect(await ConfirmVoteDelegationPage.noConfidenceValue.getText()).to.equal( + await t('core.VoteDelegation.option') + ); + break; + default: + await ConfirmVoteDelegationPage.dRepIdLabel.waitForDisplayed(); + expect(await ConfirmVoteDelegationPage.dRepIdLabel.getText()).to.equal(await t('core.VoteDelegation.drepId')); + await ConfirmVoteDelegationPage.dRepIdValue.waitForDisplayed(); + expect(await ConfirmVoteDelegationPage.dRepIdValue.getText()).to.equal(target); + } + + await this.assertSeeButtons(); + } +} + +export default new ConfirmVoteDelegationPageAssert(); diff --git a/packages/e2e-tests/src/assert/governance/GovernanceActionAllDonePageAssert.ts b/packages/e2e-tests/src/assert/governance/GovernanceActionAllDonePageAssert.ts new file mode 100644 index 000000000..e3c3d96ad --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/GovernanceActionAllDonePageAssert.ts @@ -0,0 +1,26 @@ +import { expect } from 'chai'; +import { t } from '../../utils/translationService'; +import GovernanceActionAllDonePage from '../../elements/governance/GovernanceActionAllDonePage'; +import CommonGovernancePageAssert from './CommonGovernancePageAssert'; + +class GovernanceActionAllDonePageAssert extends CommonGovernancePageAssert { + async assertSeeAllDonePage() { + await this.assertSeeHeader(); + await GovernanceActionAllDonePage.image.waitForDisplayed(); + + await GovernanceActionAllDonePage.heading.waitForDisplayed(); + expect(await GovernanceActionAllDonePage.heading.getText()).to.equal( + await t('browserView.transaction.success.youCanSafelyCloseThisPanel') + ); + + await GovernanceActionAllDonePage.description.waitForDisplayed(); + expect(await GovernanceActionAllDonePage.description.getText()).to.equal( + await t('core.dappTransaction.signedSuccessfully') + ); + + await GovernanceActionAllDonePage.closeButton.waitForDisplayed(); + expect(await GovernanceActionAllDonePage.closeButton.getText()).to.equal(await t('general.button.close')); + } +} + +export default new GovernanceActionAllDonePageAssert(); diff --git a/packages/e2e-tests/src/assert/governance/GovernanceDemoAppDetails.ts b/packages/e2e-tests/src/assert/governance/GovernanceDemoAppDetails.ts new file mode 100644 index 000000000..b629705b9 --- /dev/null +++ b/packages/e2e-tests/src/assert/governance/GovernanceDemoAppDetails.ts @@ -0,0 +1,6 @@ +export const GovernanceDemoAppDetails = { + dAppName: '✨Demos dApp✨', + dAppUrlLong: 'https://ryun1.github.io/cip95-cardano-wallet-connector', + dAppUrlShort: 'https://ryun1.github.io', + dAppLogoSrc: 'https://ryun1.github.io/cip95-cardano-wallet-connector/favicon.ico' +}; diff --git a/packages/e2e-tests/src/elements/governance/CommonGovernanceActionPageElements.ts b/packages/e2e-tests/src/elements/governance/CommonGovernanceActionPageElements.ts new file mode 100644 index 000000000..0d1d6b9f9 --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/CommonGovernanceActionPageElements.ts @@ -0,0 +1,32 @@ +/* eslint-disable no-undef */ +import CommonDappPageElements from '../dappConnector/commonDappPageElements'; + +class CommonGovernanceActionPageElements extends CommonDappPageElements { + private CANCEL_BUTTON = '[data-testid="dapp-transaction-cancel"]'; + private CONFIRM_BUTTON = '[data-testid="dapp-transaction-confirm"]'; + private METADATA_LABEL = '[data-testid="metadata-label"]'; + + get metadataLabel(): ChainablePromiseElement { + return $(this.METADATA_LABEL); + } + + get cancelButton(): ChainablePromiseElement { + return $(this.CANCEL_BUTTON); + } + + get confirmButton(): ChainablePromiseElement { + return $(this.CONFIRM_BUTTON); + } + + async clickButton(button: 'Cancel' | 'Confirm'): Promise { + if (button === 'Cancel') { + await this.cancelButton.waitForClickable(); + await this.cancelButton.click(); + } else { + await this.confirmButton.waitForClickable(); + await this.confirmButton.click(); + } + } +} + +export default CommonGovernanceActionPageElements; diff --git a/packages/e2e-tests/src/elements/governance/ConfirmDRepRegistrationPage.ts b/packages/e2e-tests/src/elements/governance/ConfirmDRepRegistrationPage.ts new file mode 100644 index 000000000..1ecad6dff --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/ConfirmDRepRegistrationPage.ts @@ -0,0 +1,46 @@ +import CommonGovernanceActionPageElements from './CommonGovernanceActionPageElements'; + +class ConfirmDRepRegistrationPage extends CommonGovernanceActionPageElements { + private URL_LABEL = '[data-testid="metadata-url-label"]'; + private URL_VALUE = '[data-testid="metadata-url-value"]'; + private HASH_LABEL = '[data-testid="metadata-hash-label"]'; + private HASH_VALUE = '[data-testid="metadata-hash-value"]'; + private DREP_ID_LABEL = '[data-testid="metadata-DRepID-label"]'; + private DREP_ID_VALUE = '[data-testid="metadata-DRepID-value"]'; + private DEPOSIT_PAID_LABEL = '[data-testid="metadata-depositPaid-label"]'; + private DEPOSIT_PAID_VALUE = '[data-testid="metadata-depositPaid-value"]'; + + get urlLabel() { + return $(this.URL_LABEL); + } + + get urlValue() { + return $(this.URL_VALUE); + } + + get hashLabel() { + return $(this.HASH_LABEL); + } + + get hashValue() { + return $(this.HASH_VALUE); + } + + get dRepIdLabel() { + return $(this.DREP_ID_LABEL); + } + + get dRepIdValue() { + return $(this.DREP_ID_VALUE); + } + + get depositPaidLabel() { + return $(this.DEPOSIT_PAID_LABEL); + } + + get depositPaidValue() { + return $(this.DEPOSIT_PAID_VALUE); + } +} + +export default new ConfirmDRepRegistrationPage(); diff --git a/packages/e2e-tests/src/elements/governance/ConfirmDRepRetirementPage.ts b/packages/e2e-tests/src/elements/governance/ConfirmDRepRetirementPage.ts new file mode 100644 index 000000000..9ffb16558 --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/ConfirmDRepRetirementPage.ts @@ -0,0 +1,31 @@ +import CommonGovernanceActionPageElements from './CommonGovernanceActionPageElements'; + +class ConfirmDRepRetirementPage extends CommonGovernanceActionPageElements { + private ERROR_PANE = '[data-testid="error-pane"]'; + private DREP_ID_LABEL = '[data-testid="metadata-DRepID-label"]'; + private DREP_ID_VALUE = '[data-testid="metadata-DRepID-value"]'; + private DEPOSIT_RETURNED_LABEL = '[data-testid="metadata-depositReturned-label"]'; + private DEPOSIT_RETURNED_VALUE = '[data-testid="metadata-depositReturned-value"]'; + + get errorPane() { + return $(this.ERROR_PANE); + } + + get dRepIdLabel() { + return $(this.DREP_ID_LABEL); + } + + get dRepIdValue() { + return $(this.DREP_ID_VALUE); + } + + get depositReturnedLabel() { + return $(this.DEPOSIT_RETURNED_LABEL); + } + + get depositReturnedValue() { + return $(this.DEPOSIT_RETURNED_VALUE); + } +} + +export default new ConfirmDRepRetirementPage(); diff --git a/packages/e2e-tests/src/elements/governance/ConfirmDRepUpdatePage.ts b/packages/e2e-tests/src/elements/governance/ConfirmDRepUpdatePage.ts new file mode 100644 index 000000000..8473723d4 --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/ConfirmDRepUpdatePage.ts @@ -0,0 +1,36 @@ +import CommonGovernanceActionPageElements from './CommonGovernanceActionPageElements'; + +class ConfirmDRepUpdatePage extends CommonGovernanceActionPageElements { + private URL_LABEL = '[data-testid="metadata-url-label"]'; + private URL_VALUE = '[data-testid="metadata-url-value"]'; + private HASH_LABEL = '[data-testid="metadata-hash-label"]'; + private HASH_VALUE = '[data-testid="metadata-hash-value"]'; + private DREP_ID_LABEL = '[data-testid="metadata-DRepID-label"]'; + private DREP_ID_VALUE = '[data-testid="metadata-DRepID-value"]'; + + get urlLabel() { + return $(this.URL_LABEL); + } + + get urlValue() { + return $(this.URL_VALUE); + } + + get hashLabel() { + return $(this.HASH_LABEL); + } + + get hashValue() { + return $(this.HASH_VALUE); + } + + get dRepIdLabel() { + return $(this.DREP_ID_LABEL); + } + + get dRepIdValue() { + return $(this.DREP_ID_VALUE); + } +} + +export default new ConfirmDRepUpdatePage(); diff --git a/packages/e2e-tests/src/elements/governance/ConfirmVoteDelegationPage.ts b/packages/e2e-tests/src/elements/governance/ConfirmVoteDelegationPage.ts new file mode 100644 index 000000000..c689189ca --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/ConfirmVoteDelegationPage.ts @@ -0,0 +1,36 @@ +import CommonGovernanceActionPageElements from './CommonGovernanceActionPageElements'; + +class ConfirmVoteDelegationPage extends CommonGovernanceActionPageElements { + private DREP_ID_LABEL = '[data-testid="metadata-DRepID-label"]'; + private DREP_ID_VALUE = '[data-testid="metadata-DRepID-value"]'; + private ABSTAIN_LABEL = '[data-testid="metadata-alwaysAbstain-label"]'; + private ABSTAIN_VALUE = '[data-testid="metadata-alwaysAbstain-value"]'; + private NO_CONFIDENCE_LABEL = '[data-testid="metadata-alwaysNoConfidence-label"]'; + private NO_CONFIDENCE_VALUE = '[data-testid="metadata-alwaysNoConfidence-value"]'; + + get dRepIdLabel() { + return $(this.DREP_ID_LABEL); + } + + get dRepIdValue() { + return $(this.DREP_ID_VALUE); + } + + get abstainLabel() { + return $(this.ABSTAIN_LABEL); + } + + get abstainValue() { + return $(this.ABSTAIN_VALUE); + } + + get noConfidenceLabel() { + return $(this.NO_CONFIDENCE_LABEL); + } + + get noConfidenceValue() { + return $(this.NO_CONFIDENCE_VALUE); + } +} + +export default new ConfirmVoteDelegationPage(); diff --git a/packages/e2e-tests/src/elements/governance/GovernanceActionAllDonePage.ts b/packages/e2e-tests/src/elements/governance/GovernanceActionAllDonePage.ts new file mode 100644 index 000000000..2631b7eca --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/GovernanceActionAllDonePage.ts @@ -0,0 +1,27 @@ +/* eslint-disable no-undef */ +import { ChainablePromiseElement } from 'webdriverio'; + +class GovernanceActionAllDonePage { + private IMAGE = '[data-testid="dapp-sign-tx-success-image"]'; + private HEADING = '[data-testid="dapp-sign-tx-success-heading"]'; + private DESCRIPTION = '[data-testid="dapp-sign-tx-success-description"]'; + private CLOSE_BUTTON = '[data-testid="dapp-sign-tx-success-close-button"]'; + + get image(): ChainablePromiseElement { + return $(this.IMAGE); + } + + get heading(): ChainablePromiseElement { + return $(this.HEADING); + } + + get description(): ChainablePromiseElement { + return $(this.DESCRIPTION); + } + + get closeButton(): ChainablePromiseElement { + return $(this.CLOSE_BUTTON); + } +} + +export default new GovernanceActionAllDonePage(); diff --git a/packages/e2e-tests/src/elements/governance/GovernanceDemoAppPage.ts b/packages/e2e-tests/src/elements/governance/GovernanceDemoAppPage.ts new file mode 100644 index 000000000..93c46f7a3 --- /dev/null +++ b/packages/e2e-tests/src/elements/governance/GovernanceDemoAppPage.ts @@ -0,0 +1,127 @@ +import DAppConnectorPageObject from '../../pageobject/dAppConnectorPageObject'; +import { GovernanceDemoAppDetails } from '../../assert/governance/GovernanceDemoAppDetails'; +import { browser } from '@wdio/globals'; + +// App is not adjusted for testing e.g. lack of custom testIDs +// https://ryun1.github.io/cip95-cardano-wallet-connector/ +class GovernanceDemoAppPage { + private VOTE_DELEGATION_TAB_BUTTON = '#bp3-tab-title_cip95-basic_1'; + private VOTE_DELEGATION_TAB_CONTENT = '//div[@id="bp3-tab-panel_cip95-basic_1"]'; + private VOTE_DELEGATION_TARGET_OF_VOTE_DELEGATION_INPUT = `(${this.VOTE_DELEGATION_TAB_CONTENT}//input[@class="bp3-input"])[1]`; + private VOTE_DELEGATION_STAKE_CREDENTIAL_INPUT = `(${this.VOTE_DELEGATION_TAB_CONTENT}//input[@class="bp3-input"])[2]`; + private BUILD_VOTE_DELEGATION_CERT_AND_ADD_TO_TX_BUTTON = `${this.VOTE_DELEGATION_TAB_CONTENT}//button[text()="Build cert, add to Tx"]`; + + private DREP_REGISTRATION_TAB_BUTTON = '#bp3-tab-title_cip95-basic_2'; + private DREP_REGISTRATION_TAB_CONTENT = '//div[@id="bp3-tab-panel_cip95-basic_2"]'; + private DREP_REGISTRATION_DREP_ID_INPUT = `(${this.DREP_REGISTRATION_TAB_CONTENT}//input[@class="bp3-input"])[1]`; + private DREP_REGISTRATION_DEPOSIT_AMOUNT_INPUT = `(${this.DREP_REGISTRATION_TAB_CONTENT}//input[@class="bp3-input"])[2]`; + private DREP_REGISTRATION_METADATA_URL_INPUT = `(${this.DREP_REGISTRATION_TAB_CONTENT}//input[@class="bp3-input"])[3]`; + private DREP_REGISTRATION_METADATA_HASH_INPUT = `(${this.DREP_REGISTRATION_TAB_CONTENT}//input[@class="bp3-input"])[4]`; + private BUILD_DREP_REGISTRATION_CERT_AND_ADD_TO_TX_BUTTON = `${this.DREP_REGISTRATION_TAB_CONTENT}//button[text()="Build cert, add to Tx"]`; + + private DREP_UPDATE_TAB_BUTTON = '#bp3-tab-title_cip95-basic_3'; + private DREP_UPDATE_TAB_CONTENT = '//div[@id="bp3-tab-panel_cip95-basic_2"]'; + private DREP_UPDATE_METADATA_URL_INPUT = `(${this.DREP_UPDATE_TAB_CONTENT}//input[@class="bp3-input"])[1]`; + private DREP_UPDATE_METADATA_HASH_INPUT = `(${this.DREP_UPDATE_TAB_CONTENT}//input[@class="bp3-input"])[2]`; + private BUILD_DREP_UPDATE_CERT_AND_ADD_TO_TX_BUTTON = `${this.DREP_UPDATE_TAB_CONTENT}//button[text()="Build cert, add to Tx"]`; + + private DREP_RETIREMENT_TAB_BUTTON = '#bp3-tab-title_cip95-basic_4'; + private DREP_RETIREMENT_TAB_CONTENT = '//div[@id="bp3-tab-panel_cip95-basic_4"]'; + private DREP_RETIREMENT_DEPOSIT_REFUND_AMOUNT_INPUT = `${this.DREP_RETIREMENT_TAB_CONTENT}//input`; + private BUILD_DREP_RETIREMENT_CERT_AND_ADD_TO_TX_BUTTON = `${this.DREP_RETIREMENT_TAB_CONTENT}//button[text()="Build cert, add to Tx"]`; + + private SIGN_AND_SUBMIT_TX_BUTTON = '//button[text()=".signTx() and .submitTx()"]'; + + get voteDelegationTabButton() { + return $(this.VOTE_DELEGATION_TAB_BUTTON); + } + + get dRepRegistrationTabButton() { + return $(this.DREP_REGISTRATION_TAB_BUTTON); + } + + get dRepUpdateTabButton() { + return $(this.DREP_UPDATE_TAB_BUTTON); + } + + get dRepRetirementTabButton() { + return $(this.DREP_RETIREMENT_TAB_BUTTON); + } + + get voteDelegationTargetOfVoteDelegationInput() { + return $(this.VOTE_DELEGATION_TARGET_OF_VOTE_DELEGATION_INPUT); + } + + get voteDelegationStakeCredentialInput() { + return $(this.VOTE_DELEGATION_STAKE_CREDENTIAL_INPUT); + } + + get voteDelegationBuildCertAndAddToTxButton() { + return $(this.BUILD_VOTE_DELEGATION_CERT_AND_ADD_TO_TX_BUTTON); + } + + get dRepRegistrationDRepIdInput() { + return $(this.DREP_REGISTRATION_DREP_ID_INPUT); + } + + get dRepRegistrationDepositAmountInput() { + return $(this.DREP_REGISTRATION_DEPOSIT_AMOUNT_INPUT); + } + + get dRepRegistrationMetadataUrlInput() { + return $(this.DREP_REGISTRATION_METADATA_URL_INPUT); + } + + get dRepRegistrationMetadataHashInput() { + return $(this.DREP_REGISTRATION_METADATA_HASH_INPUT); + } + + get dRepRegistrationBuildCertAndAddToTxButton() { + return $(this.BUILD_DREP_REGISTRATION_CERT_AND_ADD_TO_TX_BUTTON); + } + + get dRepUpdateMetadataUrlInput() { + return $(this.DREP_UPDATE_METADATA_URL_INPUT); + } + + get dRepUpdateMetadataHashInput() { + return $(this.DREP_UPDATE_METADATA_HASH_INPUT); + } + + get dRepUpdateBuildCertAndAddToTxButton() { + return $(this.BUILD_DREP_UPDATE_CERT_AND_ADD_TO_TX_BUTTON); + } + + get dRepRetirementDepositRefundAmountInput() { + return $(this.DREP_RETIREMENT_DEPOSIT_REFUND_AMOUNT_INPUT); + } + + get dRepRetirementBuildCertAndAddToTxButton() { + return $(this.BUILD_DREP_RETIREMENT_CERT_AND_ADD_TO_TX_BUTTON); + } + + get signAndSubmitButton() { + return $(this.SIGN_AND_SUBMIT_TX_BUTTON); + } + + async openAndAuthorize() { + await browser.newWindow(GovernanceDemoAppDetails.dAppUrlLong); + await DAppConnectorPageObject.waitAndSwitchToDAppConnectorWindow(3); + await DAppConnectorPageObject.clickButtonInDAppAuthorizationWindow('Authorize'); + await DAppConnectorPageObject.clickButtonInDAppAuthorizationModal('Always'); + await browser.pause(1000); + await browser.switchWindow(/Demos dApp/); + } + + async fillVoteDelegationTargetOfVoteDelegation(target: string) { + await this.voteDelegationTargetOfVoteDelegationInput.waitForEnabled(); + await this.voteDelegationTargetOfVoteDelegationInput.setValue(target); + } + + async fillVoteDelegationStakeCredential(stakeCredential: string) { + await this.voteDelegationStakeCredentialInput.waitForEnabled(); + await this.voteDelegationStakeCredentialInput.setValue(stakeCredential); + } +} + +export default new GovernanceDemoAppPage(); diff --git a/packages/e2e-tests/src/hooks/beforeTagHooks.ts b/packages/e2e-tests/src/hooks/beforeTagHooks.ts index 760d72fdd..d07f6890e 100644 --- a/packages/e2e-tests/src/hooks/beforeTagHooks.ts +++ b/packages/e2e-tests/src/hooks/beforeTagHooks.ts @@ -38,7 +38,7 @@ Before( Before( { - tags: '@Tokens-popup or @Transactions-Popup or @Staking-Popup or @LockWallet-popup or @Top-Navigation-Popup or @AddressBook-popup or @Common-Popup or @SendTx-Simple-Popup or @MainNavigation-Popup or @Settings-Popup or @NFTs-Popup or @NFT-Folders-Popup or @Send-Transaction-Metadata-Popup or @ForgotPassword or @DAppConnector-Popup' + tags: '@Tokens-popup or @Transactions-Popup or @Staking-Popup or @LockWallet-popup or @Top-Navigation-Popup or @AddressBook-popup or @Common-Popup or @SendTx-Simple-Popup or @MainNavigation-Popup or @Settings-Popup or @NFTs-Popup or @NFT-Folders-Popup or @Send-Transaction-Metadata-Popup or @ForgotPassword or @DAppConnector-Popup or @Governance' }, async () => { await popupViewWalletInitialization(); diff --git a/packages/e2e-tests/src/steps/GovernanceSteps.ts b/packages/e2e-tests/src/steps/GovernanceSteps.ts new file mode 100644 index 000000000..90b2397dc --- /dev/null +++ b/packages/e2e-tests/src/steps/GovernanceSteps.ts @@ -0,0 +1,117 @@ +import { Then, When } from '@cucumber/cucumber'; +import GovernanceDemoAppPage from '../elements/governance/GovernanceDemoAppPage'; +import ConfirmVoteDelegationPageAssert from '../assert/governance/ConfirmVoteDelegationPageAssert'; +import ConfirmDRepRegistrationPageAssert from '../assert/governance/ConfirmDRepRegistrationPageAssert'; +import ConfirmDRepUpdatePageAssert from '../assert/governance/ConfirmDRepUpdatePageAssert'; +import ConfirmDRepRetirementPageAssert from '../assert/governance/ConfirmDRepRetirementPageAssert'; +import ConfirmVoteDelegationPage from '../elements/governance/ConfirmVoteDelegationPage'; +import ConfirmDRepRegistrationPage from '../elements/governance/ConfirmDRepRegistrationPage'; +import ConfirmDRepRetirementPage from '../elements/governance/ConfirmDRepRetirementPage'; +import ConfirmDRepUpdatePage from '../elements/governance/ConfirmDRepUpdatePage'; +import GovernanceActionAllDonePageAssert from '../assert/governance/GovernanceActionAllDonePageAssert'; + +When(/^I open and authorize Governance Demo App$/, async () => { + await GovernanceDemoAppPage.openAndAuthorize(); +}); + +When(/^I open "Vote Delegation" form$/, async () => { + await GovernanceDemoAppPage.voteDelegationTabButton.waitForClickable(); + await GovernanceDemoAppPage.voteDelegationTabButton.click(); +}); + +When(/^I enter "([^"]*)" into "Target of Vote Delegation" field on "Vote Delegation" form$/, async (target: string) => { + await GovernanceDemoAppPage.fillVoteDelegationTargetOfVoteDelegation(target); +}); + +When(/^I enter "([^"]*)" into "Stake Credential" field on "Vote Delegation" form$/, async (target: string) => { + await GovernanceDemoAppPage.fillVoteDelegationStakeCredential(target); +}); + +When( + /^I build and submit "(Vote Delegation|DRep Registration|DRep Update|DRep Retirement|Vote)" transaction$/, + async (transactionType: 'Vote Delegation' | 'DRep Registration' | 'DRep Update' | 'DRep Retirement' | 'Vote') => { + switch (transactionType) { + case 'Vote Delegation': + await GovernanceDemoAppPage.voteDelegationBuildCertAndAddToTxButton.waitForClickable(); + await GovernanceDemoAppPage.voteDelegationBuildCertAndAddToTxButton.click(); + break; + case 'DRep Registration': + await GovernanceDemoAppPage.dRepRegistrationBuildCertAndAddToTxButton.waitForClickable(); + await GovernanceDemoAppPage.dRepRegistrationBuildCertAndAddToTxButton.click(); + break; + case 'DRep Update': + await GovernanceDemoAppPage.dRepUpdateBuildCertAndAddToTxButton.waitForClickable(); + await GovernanceDemoAppPage.dRepUpdateBuildCertAndAddToTxButton.click(); + break; + case 'DRep Retirement': + await GovernanceDemoAppPage.dRepRetirementBuildCertAndAddToTxButton.waitForClickable(); + await GovernanceDemoAppPage.dRepRetirementBuildCertAndAddToTxButton.click(); + break; + case 'Vote': + // TODO + break; + } + await GovernanceDemoAppPage.signAndSubmitButton.click(); + } +); + +Then(/^"Confirm vote delegation" window with "([^"]*)" target is displayed$/, async (target: string) => { + await ConfirmVoteDelegationPageAssert.assertSeeConfirmVoteDelegationPage(target); +}); + +Then( + /^"Confirm DRep Registration" window with DRep ID "([^"]*)", Metadata URL "([^"]*)" and Metadata Hash "([^"]*)" is displayed$/, + async (expectedDRepID: string, expectedUrl: string, expectedHash: string) => { + await ConfirmDRepRegistrationPageAssert.assertSeeConfirmDRepRegistrationPage( + expectedDRepID, + expectedUrl, + expectedHash + ); + } +); + +Then( + /^"Confirm DRep Update" window with DRep ID "([^"]*)", Metadata URL "([^"]*)" and Metadata Hash "([^"]*)" is displayed$/, + async (expectedDRepID: string, expectedUrl: string, expectedHash: string) => { + await ConfirmDRepUpdatePageAssert.assertSeeConfirmDRepUpdatePage(expectedDRepID, expectedUrl, expectedHash); + } +); + +Then( + /^"Confirm DRep Retirement" window with DRep ID "([^"]*)" and deposit returned "([^"]*)" is displayed$/, + async (expectedDRepID: string, expectedDepositReturned: string) => { + await ConfirmDRepRetirementPageAssert.assertSeeConfirmDRepRetirementPage(expectedDRepID, expectedDepositReturned); + } +); + +When( + /^I click "(Cancel|Confirm)" button on "(Vote Delegation|DRep Registration|DRep Update|DRep Retirement|Vote)" window$/, + async ( + button: 'Cancel' | 'Confirm', + window: 'Vote Delegation' | 'DRep Registration' | 'DRep Update' | 'DRep Retirement' | 'Vote' + ) => { + switch (window) { + case 'Vote Delegation': + await ConfirmVoteDelegationPage.clickButton(button); + break; + case 'DRep Registration': + await ConfirmDRepRegistrationPage.clickButton(button); + break; + case 'DRep Update': + await ConfirmDRepUpdatePage.clickButton(button); + break; + case 'DRep Retirement': + await ConfirmDRepRetirementPage.clickButton(button); + break; + case 'Vote': + // TODO + break; + default: + throw new Error(`Unsupported window: ${window}`); + } + } +); + +Then(/^"All done" screen is displayed for governance transaction$/, async () => { + await GovernanceActionAllDonePageAssert.assertSeeAllDonePage(); +}); diff --git a/packages/e2e-tests/src/utils/networkManager.ts b/packages/e2e-tests/src/utils/networkManager.ts index d882a5d31..0d3ebcee4 100644 --- a/packages/e2e-tests/src/utils/networkManager.ts +++ b/packages/e2e-tests/src/utils/networkManager.ts @@ -2,6 +2,7 @@ import { ChainablePromiseElement } from 'webdriverio'; import { Logger } from '../support/logger'; import allure from '@wdio/allure-reporter'; +// eslint-disable-next-line import/no-unresolved import { CDPSession } from 'puppeteer-core/lib/esm/puppeteer/common/Connection'; export class NetworkManager { diff --git a/packages/staking/src/features/overview/Overview.tsx b/packages/staking/src/features/overview/Overview.tsx index 45e57cce8..b87e4aac0 100644 --- a/packages/staking/src/features/overview/Overview.tsx +++ b/packages/staking/src/features/overview/Overview.tsx @@ -35,7 +35,7 @@ export const Overview = () => { if ( !totalCoinBalance || - !protocolParameters?.stakeKeyDeposit || + !protocolParameters?.hasOwnProperty('stakeKeyDeposit') || !balancesBalance?.available?.coinBalance || !rewardAccounts ) { diff --git a/packages/staking/src/features/overview/OverviewPopup.tsx b/packages/staking/src/features/overview/OverviewPopup.tsx index 5d0a4cac9..d0406baac 100644 --- a/packages/staking/src/features/overview/OverviewPopup.tsx +++ b/packages/staking/src/features/overview/OverviewPopup.tsx @@ -36,7 +36,7 @@ export const OverviewPopup = () => { if ( !totalCoinBalance || - !protocolParameters?.stakeKeyDeposit || + !protocolParameters?.hasOwnProperty('stakeKeyDeposit') || !balancesBalance?.available?.coinBalance || !rewardAccounts ) { diff --git a/packages/ui/package.json b/packages/ui/package.json index 96b82cd53..c5e31ae81 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -29,6 +29,18 @@ "typecheck": "tsc --noEmit", "watch": "yarn build --watch" }, + "resolutions": { + "@storybook/addon-actions": "^6.5.16", + "@storybook/addon-essentials": "^6.5.16", + "@storybook/addon-interactions": "^6.5.16", + "@storybook/addon-links": "^6.5.16", + "@storybook/builder-webpack5": "6.5.16", + "@storybook/jest": "^0.0.10", + "@storybook/manager-webpack5": "6.5.16", + "@storybook/react": "^6.5.16", + "@storybook/test-runner": "^0.10.0", + "@storybook/testing-library": "^0.0.13" + }, "dependencies": { "@radix-ui/react-alert-dialog": "^1.0.4", "@radix-ui/react-avatar": "^1.0.2", diff --git a/packages/ui/src/design-system/index.ts b/packages/ui/src/design-system/index.ts index e4c37ec07..3ecaa296e 100644 --- a/packages/ui/src/design-system/index.ts +++ b/packages/ui/src/design-system/index.ts @@ -24,7 +24,7 @@ export { ToastBar } from './toast-bar'; export * from './tooltip'; export { Message } from './message'; export { PasswordBox } from './password-box'; -export { Metadata } from './metadata'; +export { Metadata, MetadataLink } from './metadata'; export { TextLink } from './text-link'; export * as ProfileDropdown from './profile-dropdown'; export { TextBox } from './text-box'; diff --git a/packages/ui/src/design-system/metadata/index.ts b/packages/ui/src/design-system/metadata/index.ts index 6060859e4..d97b0957f 100644 --- a/packages/ui/src/design-system/metadata/index.ts +++ b/packages/ui/src/design-system/metadata/index.ts @@ -1 +1,2 @@ export { Metadata } from './metadata.component'; +export { MetadataLink } from './metadata-link.component'; diff --git a/packages/ui/src/design-system/metadata/metadata-link.component.tsx b/packages/ui/src/design-system/metadata/metadata-link.component.tsx new file mode 100644 index 000000000..5eb52078c --- /dev/null +++ b/packages/ui/src/design-system/metadata/metadata-link.component.tsx @@ -0,0 +1,45 @@ +import React from 'react'; + +import { Flex } from '../flex'; +import { Grid, Cell } from '../grid'; +import { TextLink } from '../text-link'; +import * as Typography from '../typography'; + +import * as cx from './metadata.css'; + +import type { OmitClassName } from '../../types'; + +type Props = OmitClassName<'div'> & { + label: string; + text: string; + url: string; +}; + +export const MetadataLink = ({ + label, + text, + url, + ...props +}: Readonly): JSX.Element => { + return ( + + + + {label} + + + + + + + + + + + ); +}; diff --git a/packages/ui/src/design-system/text-link/text-link.css.ts b/packages/ui/src/design-system/text-link/text-link.css.ts index 010a970b8..681ccc4f6 100644 --- a/packages/ui/src/design-system/text-link/text-link.css.ts +++ b/packages/ui/src/design-system/text-link/text-link.css.ts @@ -48,6 +48,7 @@ export const label = style([ color: vars.colors.$text_link_label_color_disabled, }, }, + wordBreak: 'break-all', }, ]); diff --git a/packages/ui/src/design-system/transaction-summary/transaction-summary-address.component.tsx b/packages/ui/src/design-system/transaction-summary/transaction-summary-address.component.tsx index 83234cfa0..087402100 100644 --- a/packages/ui/src/design-system/transaction-summary/transaction-summary-address.component.tsx +++ b/packages/ui/src/design-system/transaction-summary/transaction-summary-address.component.tsx @@ -11,23 +11,33 @@ import type { OmitClassName } from '../../types'; type Props = OmitClassName<'div'> & { label: string; address: string; + testID?: string; }; export const Address = ({ label, address, + testID, ...props }: Readonly): JSX.Element => { return ( - + {label} - {address} + + {address} + diff --git a/packages/ui/src/design-system/transaction-summary/transaction-summary-metadata.component.tsx b/packages/ui/src/design-system/transaction-summary/transaction-summary-metadata.component.tsx index 82d4d0c05..ccde339e4 100644 --- a/packages/ui/src/design-system/transaction-summary/transaction-summary-metadata.component.tsx +++ b/packages/ui/src/design-system/transaction-summary/transaction-summary-metadata.component.tsx @@ -11,23 +11,32 @@ import type { OmitClassName } from '../../types'; type Props = OmitClassName<'div'> & { label: string; text: string; + testID?: string; }; export const Metadata = ({ label, text, + testID, ...props }: Readonly): JSX.Element => { return ( - + {label} - + {text} diff --git a/rollup.config.js b/rollup.config.js index d2ef16661..aef7832d8 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -11,7 +11,7 @@ export default ({ tsPluginOptions = { tsconfig: 'src/tsconfig.json', composite: false, - exclude: ['**/*.stories.tsx'] + exclude: ['**/*.stories.tsx', '**/*.test.ts', '**/*.test.tsx'] } } = {}) => ({ input: 'src/index.ts', diff --git a/yarn.lock b/yarn.lock index c3954a3db..3816aa801 100644 --- a/yarn.lock +++ b/yarn.lock @@ -110,6 +110,17 @@ __metadata: languageName: node linkType: hard +"@aw-web-design/x-default-browser@npm:1.4.126": + version: 1.4.126 + resolution: "@aw-web-design/x-default-browser@npm:1.4.126" + dependencies: + default-browser-id: 3.0.0 + bin: + x-default-browser: bin/x-default-browser.js + checksum: f63b68a0ff41c8fe478b1b4822e169cac0d26c61b123c0400d5e16a8a5987732b85795aff16d6b21936f9c955f0d32bffbfc166890d3446f74a72a7a2c9633ea + languageName: node + linkType: hard + "@babel/code-frame@npm:7.12.11": version: 7.12.11 resolution: "@babel/code-frame@npm:7.12.11" @@ -164,6 +175,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.22.13": + version: 7.22.13 + resolution: "@babel/code-frame@npm:7.22.13" + dependencies: + "@babel/highlight": ^7.22.13 + chalk: ^2.4.2 + checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.22.5": version: 7.22.5 resolution: "@babel/code-frame@npm:7.22.5" @@ -215,6 +236,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.22.20, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/compat-data@npm:7.22.20" + checksum: efedd1d18878c10fde95e4d82b1236a9aba41395ef798cbb651f58dbf5632dbff475736c507b8d13d4c8f44809d41c0eb2ef0d694283af9ba5dd8339b6dab451 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.22.5": version: 7.22.5 resolution: "@babel/compat-data@npm:7.22.5" @@ -315,6 +343,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.13.16, @babel/core@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/core@npm:7.22.20" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.22.15 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-module-transforms": ^7.22.20 + "@babel/helpers": ^7.22.15 + "@babel/parser": ^7.22.16 + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.22.20 + "@babel/types": ^7.22.19 + convert-source-map: ^1.7.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: 73663a079194b5dc406b2e2e5e50db81977d443e4faf7ef2c27e5836cd9a359e81e551115193dc9b1a93471275351a972e54904f4d3aa6cb156f51e26abf6765 + languageName: node + linkType: hard + "@babel/core@npm:^7.15.5": version: 7.16.0 resolution: "@babel/core@npm:7.16.0" @@ -557,6 +608,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.22.15, @babel/generator@npm:^7.22.9": + version: 7.22.15 + resolution: "@babel/generator@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 5b2a3ccdc3634f6ea86e0a442722bcd430238369432d31f15b428a4ee8013c2f4f917b5b135bf4fc1d0a3e2f87f10fd4ce5d07955ecc2d3b9400a05c2a481374 + languageName: node + linkType: hard + "@babel/generator@npm:^7.22.5": version: 7.22.5 resolution: "@babel/generator@npm:7.22.5" @@ -608,6 +671,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 53da330f1835c46f26b7bf4da31f7a496dee9fd8696cca12366b94ba19d97421ce519a74a837f687749318f94d1a37f8d1abcbf35e8ed22c32d16373b2f6198d + languageName: node + linkType: hard + "@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.14.5" @@ -638,6 +710,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: 639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.14.5, @babel/helper-compilation-targets@npm:^7.15.0": version: 7.15.0 resolution: "@babel/helper-compilation-targets@npm:7.15.0" @@ -710,6 +791,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6": + version: 7.22.15 + resolution: "@babel/helper-compilation-targets@npm:7.22.15" + dependencies: + "@babel/compat-data": ^7.22.9 + "@babel/helper-validator-option": ^7.22.15 + browserslist: ^4.21.9 + lru-cache: ^5.1.1 + semver: ^6.3.1 + checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980 + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-compilation-targets@npm:7.22.5" @@ -809,6 +903,25 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.22.11, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-member-expression-to-functions": ^7.22.15 + "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 52c500d8d164abb3a360b1b7c4b8fff77bc4a5920d3a2b41ae6e1d30617b0dc0b972c1f5db35b1752007e04a748908b4a99bc872b73549ae837e87dcdde005a3 + languageName: node + linkType: hard + "@babel/helper-create-regexp-features-plugin@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.14.5" @@ -845,6 +958,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-regexp-features-plugin@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + regexpu-core: ^5.3.1 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 0243b8d4854f1dc8861b1029a46d3f6393ad72f366a5a08e36a4648aa682044f06da4c6e87a456260e1e1b33c999f898ba591a0760842c1387bcc93fbf2151a6 + languageName: node + linkType: hard + "@babel/helper-define-polyfill-provider@npm:^0.1.5": version: 0.1.5 resolution: "@babel/helper-define-polyfill-provider@npm:0.1.5" @@ -915,6 +1041,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-define-polyfill-provider@npm:^0.4.2": + version: 0.4.2 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.2" + dependencies: + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 1f6dec0c5d0876d278fe15b71238eccc5f74c4e2efa2c78aaafa8bc2cc96336b8e68d94cd1a78497356c96e8b91b8c1f4452179820624d1702aee2f9832e6569 + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-environment-visitor@npm:7.18.9" @@ -929,6 +1070,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-environment-visitor@npm:7.22.5" @@ -1124,6 +1272,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-member-expression-to-functions@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: c7c5d01c402dd8902c2ec3093f203ed0fc3bc5f669328a084d2e663c4c06dd0415480ee8220c6f96ba9b2dc49545c0078f221fc3900ab1e65de69a12fe7b361f + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-module-imports@npm:7.18.6" @@ -1160,6 +1317,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-module-imports@npm:7.22.5" @@ -1265,6 +1431,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.22.15, @babel/helper-module-transforms@npm:^7.22.20, @babel/helper-module-transforms@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/helper-module-transforms@npm:7.22.20" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-simple-access": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 8fce25362df8711bd4620f41c5c18769edfeafe7f8f1dae9691966ef368e57f9da68dfa1707cd63c834c89dc4eaa82c26f12ea33e88fd262ac62844b11dcc389 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-module-transforms@npm:7.22.5" @@ -1308,6 +1489,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-optimise-call-expression@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: c70ef6cc6b6ed32eeeec4482127e8be5451d0e5282d5495d5d569d39eb04d7f1d66ec99b327f45d1d5842a9ad8c22d48567e93fc502003a47de78d122e355f7c + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:7.10.4": version: 7.10.4 resolution: "@babel/helper-plugin-utils@npm:7.10.4" @@ -1336,6 +1526,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-plugin-utils@npm:7.22.5" + checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5 + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-remap-async-to-generator@npm:7.14.5" @@ -1372,6 +1569,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-remap-async-to-generator@npm:^7.22.5, @babel/helper-remap-async-to-generator@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-wrap-function": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7 + languageName: node + linkType: hard + "@babel/helper-replace-supers@npm:^7.14.5, @babel/helper-replace-supers@npm:^7.15.0": version: 7.15.0 resolution: "@babel/helper-replace-supers@npm:7.15.0" @@ -1423,6 +1633,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-replace-supers@npm:^7.22.5, @babel/helper-replace-supers@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/helper-replace-supers@npm:7.22.20" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-member-expression-to-functions": ^7.22.15 + "@babel/helper-optimise-call-expression": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a0008332e24daedea2e9498733e3c39b389d6d4512637e000f96f62b797e702ee24a407ccbcd7a236a551590a38f31282829a8ef35c50a3c0457d88218cae639 + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.14.8": version: 7.14.8 resolution: "@babel/helper-simple-access@npm:7.14.8" @@ -1495,6 +1718,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 1012ef2295eb12dc073f2b9edf3425661e9b8432a3387e62a8bc27c42963f1f216ab3124228015c748770b2257b4f1fda882ca8fa34c0bf485e929ae5bc45244 + languageName: node + linkType: hard + "@babel/helper-split-export-declaration@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-split-export-declaration@npm:7.14.5" @@ -1531,6 +1763,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" + dependencies: + "@babel/types": ^7.22.5 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.18.10": version: 7.18.10 resolution: "@babel/helper-string-parser@npm:7.18.10" @@ -1594,6 +1835,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.19, @babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-validator-identifier@npm:7.22.5" @@ -1622,6 +1870,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-validator-option@npm:7.22.15" + checksum: 68da52b1e10002a543161494c4bc0f4d0398c8fdf361d5f7f4272e95c45d5b32d974896d44f6a0ea7378c9204988879d73613ca683e13bd1304e46d25ff67a8d + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-validator-option@npm:7.22.5" @@ -1665,6 +1920,17 @@ __metadata: languageName: node linkType: hard +"@babel/helper-wrap-function@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-wrap-function@npm:7.22.20" + dependencies: + "@babel/helper-function-name": ^7.22.5 + "@babel/template": ^7.22.15 + "@babel/types": ^7.22.19 + checksum: 221ed9b5572612aeb571e4ce6a256f2dee85b3c9536f1dd5e611b0255e5f59a3d0ec392d8d46d4152149156a8109f92f20379b1d6d36abb613176e0e33f05fca + languageName: node + linkType: hard + "@babel/helpers@npm:^7.12.5": version: 7.15.3 resolution: "@babel/helpers@npm:7.15.3" @@ -1753,6 +2019,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helpers@npm:7.22.15" + dependencies: + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 49f61a93cbae4df3328bda67af5db743fead659ae4242571226c3596b7df78546189cdf991fed1eca33b559de8abf396a90a001f474a1bab351418f07b7ae6ef + languageName: node + linkType: hard + "@babel/helpers@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helpers@npm:7.22.5" @@ -1808,6 +2085,17 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.22.13": + version: 7.22.20 + resolution: "@babel/highlight@npm:7.22.20" + dependencies: + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.22.5": version: 7.22.5 resolution: "@babel/highlight@npm:7.22.5" @@ -1837,6 +2125,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.13.16, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.22.16, @babel/parser@npm:^7.22.7": + version: 7.22.16 + resolution: "@babel/parser@npm:7.22.16" + bin: + parser: ./bin/babel-parser.js + checksum: 944c756b5bdeb07b9fec16ecef6b3c61aff9d4c4b924abadcf01afa1840a740b8e2357ae00482b5b37daad6d2bfd848c947f27ad65138d687b6fdc924bc59edd + languageName: node + linkType: hard + "@babel/parser@npm:^7.14.7, @babel/parser@npm:^7.18.10, @babel/parser@npm:^7.20.1, @babel/parser@npm:^7.20.2": version: 7.20.3 resolution: "@babel/parser@npm:7.20.3" @@ -1958,6 +2255,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 8910ca21a7ec7c06f7b247d4b86c97c5aa15ef321518f44f6f490c5912fdf82c605aaa02b90892e375d82ccbedeadfdeadd922c1b836c9dd4c596871bf654753 + languageName: node + linkType: hard + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.14.5" @@ -1997,6 +2305,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/plugin-transform-optional-chaining": ^7.22.15 + peerDependencies: + "@babel/core": ^7.13.0 + checksum: fbefedc0da014c37f1a50a8094ce7dbbf2181ae93243f23d6ecba2499b5b20196c2124d6a4dfe3e9e0125798e80593103e456352a4beb4e5c6f7c75efb80fdac + languageName: node + linkType: hard + "@babel/plugin-proposal-async-generator-functions@npm:^7.14.9": version: 7.14.9 resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.14.9" @@ -2049,27 +2370,27 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-class-properties@npm:^7.16.0": - version: 7.16.0 - resolution: "@babel/plugin-proposal-class-properties@npm:7.16.0" +"@babel/plugin-proposal-class-properties@npm:^7.13.0, @babel/plugin-proposal-class-properties@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" dependencies: - "@babel/helper-create-class-features-plugin": ^7.16.0 - "@babel/helper-plugin-utils": ^7.14.5 + "@babel/helper-create-class-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b1665ced553e5cdb95eec2fda321cb226c5f255edd1a94b226b9d81e97e026472184b6898af26f2bb9ee64101fad1afe215b6fc469d3103dec78c55e732e49aa + checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 languageName: node linkType: hard -"@babel/plugin-proposal-class-properties@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" +"@babel/plugin-proposal-class-properties@npm:^7.16.0": + version: 7.16.0 + resolution: "@babel/plugin-proposal-class-properties@npm:7.16.0" dependencies: - "@babel/helper-create-class-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-create-class-features-plugin": ^7.16.0 + "@babel/helper-plugin-utils": ^7.14.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 + checksum: b1665ced553e5cdb95eec2fda321cb226c5f255edd1a94b226b9d81e97e026472184b6898af26f2bb9ee64101fad1afe215b6fc469d3103dec78c55e732e49aa languageName: node linkType: hard @@ -2306,27 +2627,27 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.16.0": - version: 7.16.0 - resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.16.0" +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.13.8, @babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" dependencies: - "@babel/helper-plugin-utils": ^7.14.5 + "@babel/helper-plugin-utils": ^7.18.6 "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e50f94929970cdc5c6ee22ec4c95c46ae25cdd8c391baf601f7f3d3a3cec417efc663a3fafa9ae5bca82a6815d49687b07cab9857f5a10e9ea862438ecb81e4a + checksum: 949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d languageName: node linkType: hard -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.16.0": + version: 7.16.0 + resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.16.0" dependencies: - "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-plugin-utils": ^7.14.5 "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d + checksum: e50f94929970cdc5c6ee22ec4c95c46ae25cdd8c391baf601f7f3d3a3cec417efc663a3fafa9ae5bca82a6815d49687b07cab9857f5a10e9ea862438ecb81e4a languageName: node linkType: hard @@ -2473,6 +2794,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-proposal-optional-chaining@npm:^7.13.12, @babel/plugin-proposal-optional-chaining@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" + dependencies: + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 + languageName: node + linkType: hard + "@babel/plugin-proposal-optional-chaining@npm:^7.16.0": version: 7.16.0 resolution: "@babel/plugin-proposal-optional-chaining@npm:7.16.0" @@ -2499,19 +2833,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-optional-chaining@npm:^7.21.0": - version: 7.21.0 - resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" - dependencies: - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 - languageName: node - linkType: hard - "@babel/plugin-proposal-private-methods@npm:^7.12.1, @babel/plugin-proposal-private-methods@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-proposal-private-methods@npm:7.14.5" @@ -2548,6 +2869,15 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": + version: 7.21.0-placeholder-for-preset-env.2 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91 + languageName: node + linkType: hard + "@babel/plugin-proposal-private-property-in-object@npm:^7.12.1": version: 7.18.6 resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.18.6" @@ -2753,6 +3083,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-flow@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-flow@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 84c8c40fcfe8e78cecdd6fb90e8f97f419e3f3b27a33de8324ae97d5ce1b87cdd98a636fa21a68d4d2c37c7d63f3a279bb84b6956b849921affed6b806b6ffe7 + languageName: node + linkType: hard + "@babel/plugin-syntax-import-assertions@npm:^7.20.0": version: 7.20.0 resolution: "@babel/plugin-syntax-import-assertions@npm:7.20.0" @@ -2764,7 +3105,29 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-meta@npm:^7.8.3": +"@babel/plugin-syntax-import-assertions@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2b8b5572db04a7bef1e6cd20debf447e4eef7cb012616f5eceb8fa3e23ce469b8f76ee74fd6d1e158ba17a8f58b0aec579d092fb67c5a30e83ccfbc5754916c1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 197b3c5ea2a9649347f033342cb222ab47f4645633695205c0250c6bf2af29e643753b8bb24a2db39948bef08e7c540babfd365591eb57fc110cb30b425ffc47 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-meta@npm:^7.10.4, @babel/plugin-syntax-import-meta@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" dependencies: @@ -2830,6 +3193,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-jsx@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-jsx@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8829d30c2617ab31393d99cec2978e41f014f4ac6f01a1cecf4c4dd8320c3ec12fdc3ce121126b2d8d32f6887e99ca1a0bad53dedb1e6ad165640b92b24980ce + languageName: node + linkType: hard + "@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" @@ -2951,6 +3325,29 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-typescript@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-syntax-typescript@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8ab7718fbb026d64da93681a57797d60326097fd7cb930380c8bffd9eb101689e90142c760a14b51e8e69c88a73ba3da956cb4520a3b0c65743aee5c71ef360a + languageName: node + linkType: hard + +"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c + languageName: node + linkType: hard + "@babel/plugin-transform-arrow-functions@npm:^7.12.1, @babel/plugin-transform-arrow-functions@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-arrow-functions@npm:7.14.5" @@ -2984,6 +3381,31 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-arrow-functions@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 35abb6c57062802c7ce8bd96b2ef2883e3124370c688bbd67609f7d2453802fb73944df8808f893b6c67de978eb2bcf87bbfe325e46d6f39b5fcb09ece11d01a + languageName: node + linkType: hard + +"@babel/plugin-transform-async-generator-functions@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.15" + dependencies: + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.9 + "@babel/plugin-syntax-async-generators": ^7.8.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fad98786b446ce63bde0d14a221e2617eef5a7bbca62b49d96f16ab5e1694521234cfba6145b830fbf9af16d60a8a3dbf148e8694830bd91796fe333b0599e73 + languageName: node + linkType: hard + "@babel/plugin-transform-async-to-generator@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-async-to-generator@npm:7.14.5" @@ -3023,6 +3445,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-async-to-generator@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.22.5" + dependencies: + "@babel/helper-module-imports": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b95f23f99dcb379a9f0a1c2a3bbea3f8dc0e1b16dc1ac8b484fe378370169290a7a63d520959a9ba1232837cf74a80e23f6facbe14fd42a3cda6d3c2d7168e62 + languageName: node + linkType: hard + "@babel/plugin-transform-block-scoped-functions@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.14.5" @@ -3056,6 +3491,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-block-scoped-functions@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 416b1341858e8ca4e524dee66044735956ced5f478b2c3b9bc11ec2285b0c25d7dbb96d79887169eb938084c95d0a89338c8b2fe70d473bd9dc92e5d9db1732c + languageName: node + linkType: hard + "@babel/plugin-transform-block-scoping@npm:^7.12.12, @babel/plugin-transform-block-scoping@npm:^7.14.5": version: 7.15.3 resolution: "@babel/plugin-transform-block-scoping@npm:7.15.3" @@ -3100,6 +3546,42 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-block-scoping@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-block-scoping@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c7091dc000b854ce0c471588ca0704ef1ce78cff954584a9f21c1668fd0669e7c8d5396fb72fe49a2216d9b96a400d435f424f27e41a097ef6c855f9c57df195 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-properties@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-class-properties@npm:7.22.5" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b830152dfc2ff2f647f0abe76e6251babdfbef54d18c4b2c73a6bf76b1a00050a5d998dac80dc901a48514e95604324943a9dd39317073fe0928b559e0e0c579 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-class-static-block@npm:7.22.11" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.11 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 69f040506fad66f1c6918d288d0e0edbc5c8a07c8b4462c1184ad2f9f08995d68b057126c213871c0853ae0c72afc60ec87492049dfacb20902e32346a448bcb + languageName: node + linkType: hard + "@babel/plugin-transform-classes@npm:^7.12.1, @babel/plugin-transform-classes@npm:^7.14.9": version: 7.14.9 resolution: "@babel/plugin-transform-classes@npm:7.14.9" @@ -3172,6 +3654,25 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-classes@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-classes@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-optimise-call-expression": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.9 + "@babel/helper-split-export-declaration": ^7.22.6 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d3f4d0c107dd8a3557ea3575cc777fab27efa92958b41e4a9822f7499725c1f554beae58855de16ddec0a7b694e45f59a26cea8fbde4275563f72f09c6e039a0 + languageName: node + linkType: hard + "@babel/plugin-transform-computed-properties@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-computed-properties@npm:7.14.5" @@ -3206,6 +3707,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-computed-properties@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-computed-properties@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/template": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c2a77a0f94ec71efbc569109ec14ea2aa925b333289272ced8b33c6108bdbb02caf01830ffc7e49486b62dec51911924d13f3a76f1149f40daace1898009e131 + languageName: node + linkType: hard + "@babel/plugin-transform-destructuring@npm:^7.12.1, @babel/plugin-transform-destructuring@npm:^7.14.7": version: 7.14.7 resolution: "@babel/plugin-transform-destructuring@npm:7.14.7" @@ -3250,6 +3763,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-destructuring@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-destructuring@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4bccb4765e5287f1d36119d930afb9941ea8f4f001bddb8febff716bac0e09dc58576624f3ec59470630513044dd342075fe11af16d8c1b234cb7406cffca9f0 + languageName: node + linkType: hard + "@babel/plugin-transform-dotall-regex@npm:^7.14.5, @babel/plugin-transform-dotall-regex@npm:^7.4.4": version: 7.14.5 resolution: "@babel/plugin-transform-dotall-regex@npm:7.14.5" @@ -3286,6 +3810,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-dotall-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 409b658d11e3082c8f69e9cdef2d96e4d6d11256f005772425fb230cc48fd05945edbfbcb709dab293a1a2f01f9c8a5bb7b4131e632b23264039d9f95864b453 + languageName: node + linkType: hard + "@babel/plugin-transform-duplicate-keys@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-duplicate-keys@npm:7.14.5" @@ -3319,6 +3855,29 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-duplicate-keys@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bb1280fbabaab6fab2ede585df34900712698210a3bd413f4df5bae6d8c24be36b496c92722ae676a7a67d060a4624f4d6c23b923485f906bfba8773c69f55b4 + languageName: node + linkType: hard + +"@babel/plugin-transform-dynamic-import@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 78fc9c532210bf9e8f231747f542318568ac360ee6c27e80853962c984283c73da3f8f8aebe83c2096090a435b356b092ed85de617a156cbe0729d847632be45 + languageName: node + linkType: hard + "@babel/plugin-transform-exponentiation-operator@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.14.5" @@ -3355,6 +3914,30 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-exponentiation-operator@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.22.5" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f2d660c1b1d51ad5fec1cd5ad426a52187204068c4158f8c4aa977b31535c61b66898d532603eef21c15756827be8277f724c869b888d560f26d7fe848bb5eae + languageName: node + linkType: hard + +"@babel/plugin-transform-export-namespace-from@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 73af5883a321ed56a4bfd43c8a7de0164faebe619287706896fc6ee2f7a4e69042adaa1338c0b8b4bdb9f7e5fdceb016fb1d40694cb43ca3b8827429e8aac4bf + languageName: node + linkType: hard + "@babel/plugin-transform-flow-strip-types@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-flow-strip-types@npm:7.14.5" @@ -3367,6 +3950,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-flow-strip-types@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-flow-strip-types@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-flow": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1ba48187d6f33814be01c6870489f0b1858256cf2b9dd7e62f02af8b30049bf375112f1d44692c5fed3cb9cd26ee2fb32e358cd79b6ad2360a51e8f993e861bf + languageName: node + linkType: hard + "@babel/plugin-transform-for-of@npm:^7.12.1, @babel/plugin-transform-for-of@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-for-of@npm:7.14.5" @@ -3411,6 +4006,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-for-of@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-for-of@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f395ae7bce31e14961460f56cf751b5d6e37dd27d7df5b1f4e49fec1c11b6f9cf71991c7ffbe6549878591e87df0d66af798cf26edfa4bfa6b4c3dba1fb2f73a + languageName: node + linkType: hard + "@babel/plugin-transform-function-name@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-function-name@npm:7.14.5" @@ -3448,6 +4054,31 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-function-name@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-function-name@npm:7.22.5" + dependencies: + "@babel/helper-compilation-targets": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: cff3b876357999cb8ae30e439c3ec6b0491a53b0aa6f722920a4675a6dd5b53af97a833051df4b34791fe5b3dd326ccf769d5c8e45b322aa50ee11a660b17845 + languageName: node + linkType: hard + +"@babel/plugin-transform-json-strings@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-json-strings@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-json-strings": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 50665e5979e66358c50e90a26db53c55917f78175127ac2fa05c7888d156d418ffb930ec0a109353db0a7c5f57c756ce01bfc9825d24cbfd2b3ec453f2ed8cba + languageName: node + linkType: hard + "@babel/plugin-transform-literals@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-literals@npm:7.14.5" @@ -3481,6 +4112,29 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ec37cc2ffb32667af935ab32fe28f00920ec8a1eb999aa6dc6602f2bebd8ba205a558aeedcdccdebf334381d5c57106c61f52332045730393e73410892a9735b + languageName: node + linkType: hard + +"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c664e9798e85afa7f92f07b867682dee7392046181d82f5d21bae6f2ca26dfe9c8375cdc52b7483c3fc09a983c1989f60eff9fbc4f373b0c0a74090553d05739 + languageName: node + linkType: hard + "@babel/plugin-transform-member-expression-literals@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-member-expression-literals@npm:7.14.5" @@ -3514,6 +4168,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-member-expression-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ec4b0e07915ddd4fda0142fd104ee61015c208608a84cfa13643a95d18760b1dc1ceb6c6e0548898b8c49e5959a994e46367260176dbabc4467f729b21868504 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-amd@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-modules-amd@npm:7.14.5" @@ -3552,6 +4217,31 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-amd@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-modules-amd@npm:7.22.5" + dependencies: + "@babel/helper-module-transforms": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7da4c4ebbbcf7d182abb59b2046b22d86eee340caf8a22a39ef6a727da2d8acfec1f714fcdcd5054110b280e4934f735e80a6848d192b6834c5d4459a014f04d + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.13.8, @babel/plugin-transform-modules-commonjs@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.15" + dependencies: + "@babel/helper-module-transforms": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-simple-access": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f8fc85fefa6be8626a378ca38fb84c7359043e7c692c854e9ee250a05121553b7f4a58e127099efe12662ec6bebbfd304ce638a0b4563d7cbd5982f3d877321c + languageName: node + linkType: hard + "@babel/plugin-transform-modules-commonjs@npm:^7.15.0": version: 7.15.0 resolution: "@babel/plugin-transform-modules-commonjs@npm:7.15.0" @@ -3650,6 +4340,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-systemjs@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.11" + dependencies: + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-module-transforms": ^7.22.9 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d0991e4bdc3352b6a9f4d12b6662e3645d892cd5c3c005ba5f14e65f1e218c6a8f7f4497e64a51d82a046e507aaa7db3143b800b0270dca1824cbd214ff3363d + languageName: node + linkType: hard + "@babel/plugin-transform-modules-umd@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-modules-umd@npm:7.14.5" @@ -3686,6 +4390,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-umd@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-modules-umd@npm:7.22.5" + dependencies: + "@babel/helper-module-transforms": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 46622834c54c551b231963b867adbc80854881b3e516ff29984a8da989bd81665bd70e8cba6710345248e97166689310f544aee1a5773e262845a8f1b3e5b8b4 + languageName: node + linkType: hard + "@babel/plugin-transform-named-capturing-groups-regex@npm:^7.14.9": version: 7.14.9 resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.14.9" @@ -3720,6 +4436,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 3ee564ddee620c035b928fdc942c5d17e9c4b98329b76f9cefac65c111135d925eb94ed324064cd7556d4f5123beec79abea1d4b97d1c8a2a5c748887a2eb623 + languageName: node + linkType: hard + "@babel/plugin-transform-new-target@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-new-target@npm:7.14.5" @@ -3753,6 +4481,56 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-new-target@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-new-target@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6b72112773487a881a1d6ffa680afde08bad699252020e86122180ee7a88854d5da3f15d9bca3331cf2e025df045604494a8208a2e63b486266b07c14e2ffbf3 + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 167babecc8b8fe70796a7b7d34af667ebbf43da166c21689502e5e8cc93180b7a85979c77c9f64b7cce431b36718bd0a6df9e5e0ffea4ae22afb22cfef886372 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: af064d06a4a041767ec396a5f258103f64785df290e038bba9f0ef454e6c914f2ac45d862bbdad8fac2c7ad47fa4e95356f29053c60c100a0160b02a995fe2a3 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.15" + dependencies: + "@babel/compat-data": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-transform-parameters": ^7.22.15 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 62197a6f12289c1c1bd57f3bed9f0f765ca32390bfe91e0b5561dd94dd9770f4480c4162dec98da094bc0ba99d2c2ebba68de47c019454041b0b7a68ba2ec66d + languageName: node + linkType: hard + "@babel/plugin-transform-object-super@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-object-super@npm:7.14.5" @@ -3789,6 +4567,43 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-object-super@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-object-super@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b71887877d74cb64dbccb5c0324fa67e31171e6a5311991f626650e44a4083e5436a1eaa89da78c0474fb095d4ec322d63ee778b202d33aa2e4194e1ed8e62d7 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-catch-binding@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.11" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f17abd90e1de67c84d63afea29c8021c74abb2794d3a6eeafb0bbe7372d3db32aefca386e392116ec63884537a4a2815d090d26264d259bacc08f6e3ed05294c + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6b97abe0e50ca2dd8684fcef2c8d12607637e707aa9d513b7035f5e812efbde9305736b438d422103a7844e04124cad5efa4ff0e6226a57afa1210a1c7485c8e + languageName: node + linkType: hard + "@babel/plugin-transform-parameters@npm:^7.12.1, @babel/plugin-transform-parameters@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-parameters@npm:7.14.5" @@ -3833,6 +4648,43 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-parameters@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-parameters@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 541188bb7d1876cad87687b5c7daf90f63d8208ae83df24acb1e2b05020ad1c78786b2723ca4054a83fcb74fb6509f30c4cacc5b538ee684224261ad5fb047c1 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-methods@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-private-methods@npm:7.22.5" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 321479b4fcb6d3b3ef622ab22fd24001e43d46e680e8e41324c033d5810c84646e470f81b44cbcbef5c22e99030784f7cac92f1829974da7a47a60a7139082c3 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.11" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.11 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4d029d84901e53c46dead7a46e2990a7bc62470f4e4ca58a0d063394f86652fd58fe4eea1eb941da3669cd536b559b9d058b342b59300026346b7a2a51badac8 + languageName: node + linkType: hard + "@babel/plugin-transform-property-literals@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-property-literals@npm:7.14.5" @@ -3866,6 +4718,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-property-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-property-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 796176a3176106f77fcb8cd04eb34a8475ce82d6d03a88db089531b8f0453a2fb8b0c6ec9a52c27948bc0ea478becec449893741fc546dfc3930ab927e3f9f2e + languageName: node + linkType: hard + "@babel/plugin-transform-react-constant-elements@npm:^7.14.5": version: 7.16.0 resolution: "@babel/plugin-transform-react-constant-elements@npm:7.16.0" @@ -3921,6 +4784,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-display-name@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-display-name@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a12bfd1e4e93055efca3ace3c34722571bda59d9740dca364d225d9c6e3ca874f134694d21715c42cc63d79efd46db9665bd4a022998767f9245f1e29d5d204d + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx-development@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-react-jsx-development@npm:7.14.5" @@ -3954,6 +4828,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.22.5" + dependencies: + "@babel/plugin-transform-react-jsx": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 36bc3ff0b96bb0ef4723070a50cfdf2e72cfd903a59eba448f9fe92fea47574d6f22efd99364413719e1f3fb3c51b6c9b2990b87af088f8486a84b2a5f9e4560 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx-self@npm:^7.18.6": version: 7.21.0 resolution: "@babel/plugin-transform-react-jsx-self@npm:7.21.0" @@ -4021,6 +4906,21 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx@npm:^7.22.15, @babel/plugin-transform-react-jsx@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/plugin-transform-react-jsx@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-jsx": ^7.22.5 + "@babel/types": ^7.22.15 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3899054e89550c3a0ef041af7c47ee266e2e934f498ee80fefeda778a6aa177b48aa8b4d2a8bf5848de977fec564571699ab952d9fa089c4c19b45ddb121df09 + languageName: node + linkType: hard + "@babel/plugin-transform-react-pure-annotations@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.14.5" @@ -4057,6 +4957,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-pure-annotations@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.22.5" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 092021c4f404e267002099ec20b3f12dd730cb90b0d83c5feed3dc00dbe43b9c42c795a18e7c6c7d7bddea20c7dd56221b146aec81b37f2e7eb5137331c61120 + languageName: node + linkType: hard + "@babel/plugin-transform-regenerator@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-regenerator@npm:7.14.5" @@ -4091,6 +5003,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-regenerator@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-regenerator@npm:7.22.10" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + regenerator-transform: ^0.15.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e13678d62d6fa96f11cb8b863f00e8693491e7adc88bfca3f2820f80cbac8336e7dec3a596eee6a1c4663b7ececc3564f2cd7fb44ed6d4ce84ac2bb7f39ecc6e + languageName: node + linkType: hard + "@babel/plugin-transform-reserved-words@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-reserved-words@npm:7.14.5" @@ -4124,6 +5048,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-reserved-words@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-reserved-words@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3ffd7dbc425fe8132bfec118b9817572799cab1473113a635d25ab606c1f5a2341a636c04cf6b22df3813320365ed5a965b5eeb3192320a10e4cc2c137bd8bfc + languageName: node + linkType: hard + "@babel/plugin-transform-runtime@npm:7.15.0": version: 7.15.0 resolution: "@babel/plugin-transform-runtime@npm:7.15.0" @@ -4173,6 +5108,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-shorthand-properties@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a5ac902c56ea8effa99f681340ee61bac21094588f7aef0bc01dff98246651702e677552fa6d10e548c4ac22a3ffad047dd2f8c8f0540b68316c2c203e56818b + languageName: node + linkType: hard + "@babel/plugin-transform-spread@npm:^7.12.1, @babel/plugin-transform-spread@npm:^7.14.6": version: 7.14.6 resolution: "@babel/plugin-transform-spread@npm:7.14.6" @@ -4209,6 +5155,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-spread@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-spread@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 5587f0deb60b3dfc9b274e269031cc45ec75facccf1933ea2ea71ced9fd3ce98ed91bb36d6cd26817c14474b90ed998c5078415f0eab531caf301496ce24c95c + languageName: node + linkType: hard + "@babel/plugin-transform-sticky-regex@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-sticky-regex@npm:7.14.5" @@ -4242,6 +5200,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-sticky-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 63b2c575e3e7f96c32d52ed45ee098fb7d354b35c2223b8c8e76840b32cc529ee0c0ceb5742fd082e56e91e3d82842a367ce177e82b05039af3d602c9627a729 + languageName: node + linkType: hard + "@babel/plugin-transform-template-literals@npm:^7.12.1, @babel/plugin-transform-template-literals@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-template-literals@npm:7.14.5" @@ -4275,6 +5244,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-template-literals@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-template-literals@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 27e9bb030654cb425381c69754be4abe6a7c75b45cd7f962cd8d604b841b2f0fb7b024f2efc1c25cc53f5b16d79d5e8cfc47cacbdaa983895b3aeefa3e7e24ff + languageName: node + linkType: hard + "@babel/plugin-transform-typeof-symbol@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-typeof-symbol@npm:7.14.5" @@ -4308,6 +5288,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-typeof-symbol@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.22.5" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 82a53a63ffc3010b689ca9a54e5f53b2718b9f4b4a9818f36f9b7dba234f38a01876680553d2716a645a61920b5e6e4aaf8d4a0064add379b27ca0b403049512 + languageName: node + linkType: hard + "@babel/plugin-transform-typescript@npm:^7.15.0": version: 7.15.0 resolution: "@babel/plugin-transform-typescript@npm:7.15.0" @@ -4347,6 +5338,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-typescript@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/plugin-transform-typescript@npm:7.22.15" + dependencies: + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-typescript": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c5d96cdbf0e1512707aa1c1e3ac6b370a25fd9c545d26008ce44eb13a47bd7fd67a1eb799c98b5ccc82e33a345fda55c0055e1fe3ed97646ed405dd13020b226 + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-escapes@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.14.5" @@ -4380,6 +5385,29 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-escapes@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.10" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 807f40ed1324c8cb107c45358f1903384ca3f0ef1d01c5a3c5c9b271c8d8eec66936a3dcc8d75ddfceea9421420368c2e77ae3adef0a50557e778dfe296bf382 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-property-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2495e5f663cb388e3d888b4ba3df419ac436a5012144ac170b622ddfc221f9ea9bdba839fa2bc0185cb776b578030666406452ec7791cbf0e7a3d4c88ae9574c + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-regex@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-transform-unicode-regex@npm:7.14.5" @@ -4416,6 +5444,30 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6b5d1404c8c623b0ec9bd436c00d885a17d6a34f3f2597996343ddb9d94f6379705b21582dfd4cec2c47fd34068872e74ab6b9580116c0566b3f9447e2a7fa06 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-sets-regex@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.22.5" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: c042070f980b139547f8b0179efbc049ac5930abec7fc26ed7a41d89a048d8ab17d362200e204b6f71c3c20d6991a0e74415e1a412a49adc8131c2a40c04822e + languageName: node + linkType: hard + "@babel/preset-env@npm:7.15.0, @babel/preset-env@npm:^7.12.11": version: 7.15.0 resolution: "@babel/preset-env@npm:7.15.0" @@ -4753,6 +5805,96 @@ __metadata: languageName: node linkType: hard +"@babel/preset-env@npm:^7.22.20, @babel/preset-env@npm:^7.22.9": + version: 7.22.20 + resolution: "@babel/preset-env@npm:7.22.20" + dependencies: + "@babel/compat-data": ^7.22.20 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.15 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.22.15 + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/plugin-syntax-class-properties": ^7.12.13 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/plugin-syntax-import-assertions": ^7.22.5 + "@babel/plugin-syntax-import-attributes": ^7.22.5 + "@babel/plugin-syntax-import-meta": ^7.10.4 + "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + "@babel/plugin-syntax-top-level-await": ^7.14.5 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 + "@babel/plugin-transform-arrow-functions": ^7.22.5 + "@babel/plugin-transform-async-generator-functions": ^7.22.15 + "@babel/plugin-transform-async-to-generator": ^7.22.5 + "@babel/plugin-transform-block-scoped-functions": ^7.22.5 + "@babel/plugin-transform-block-scoping": ^7.22.15 + "@babel/plugin-transform-class-properties": ^7.22.5 + "@babel/plugin-transform-class-static-block": ^7.22.11 + "@babel/plugin-transform-classes": ^7.22.15 + "@babel/plugin-transform-computed-properties": ^7.22.5 + "@babel/plugin-transform-destructuring": ^7.22.15 + "@babel/plugin-transform-dotall-regex": ^7.22.5 + "@babel/plugin-transform-duplicate-keys": ^7.22.5 + "@babel/plugin-transform-dynamic-import": ^7.22.11 + "@babel/plugin-transform-exponentiation-operator": ^7.22.5 + "@babel/plugin-transform-export-namespace-from": ^7.22.11 + "@babel/plugin-transform-for-of": ^7.22.15 + "@babel/plugin-transform-function-name": ^7.22.5 + "@babel/plugin-transform-json-strings": ^7.22.11 + "@babel/plugin-transform-literals": ^7.22.5 + "@babel/plugin-transform-logical-assignment-operators": ^7.22.11 + "@babel/plugin-transform-member-expression-literals": ^7.22.5 + "@babel/plugin-transform-modules-amd": ^7.22.5 + "@babel/plugin-transform-modules-commonjs": ^7.22.15 + "@babel/plugin-transform-modules-systemjs": ^7.22.11 + "@babel/plugin-transform-modules-umd": ^7.22.5 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 + "@babel/plugin-transform-new-target": ^7.22.5 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 + "@babel/plugin-transform-numeric-separator": ^7.22.11 + "@babel/plugin-transform-object-rest-spread": ^7.22.15 + "@babel/plugin-transform-object-super": ^7.22.5 + "@babel/plugin-transform-optional-catch-binding": ^7.22.11 + "@babel/plugin-transform-optional-chaining": ^7.22.15 + "@babel/plugin-transform-parameters": ^7.22.15 + "@babel/plugin-transform-private-methods": ^7.22.5 + "@babel/plugin-transform-private-property-in-object": ^7.22.11 + "@babel/plugin-transform-property-literals": ^7.22.5 + "@babel/plugin-transform-regenerator": ^7.22.10 + "@babel/plugin-transform-reserved-words": ^7.22.5 + "@babel/plugin-transform-shorthand-properties": ^7.22.5 + "@babel/plugin-transform-spread": ^7.22.5 + "@babel/plugin-transform-sticky-regex": ^7.22.5 + "@babel/plugin-transform-template-literals": ^7.22.5 + "@babel/plugin-transform-typeof-symbol": ^7.22.5 + "@babel/plugin-transform-unicode-escapes": ^7.22.10 + "@babel/plugin-transform-unicode-property-regex": ^7.22.5 + "@babel/plugin-transform-unicode-regex": ^7.22.5 + "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 + "@babel/preset-modules": 0.1.6-no-external-plugins + "@babel/types": ^7.22.19 + babel-plugin-polyfill-corejs2: ^0.4.5 + babel-plugin-polyfill-corejs3: ^0.8.3 + babel-plugin-polyfill-regenerator: ^0.5.2 + core-js-compat: ^3.31.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 99357a5cb30f53bacdc0d1cd6dff0f052ea6c2d1ba874d969bba69897ef716e87283e84a59dc52fb49aa31fd1b6f55ed756c64c04f5678380700239f6030b881 + languageName: node + linkType: hard + "@babel/preset-flow@npm:^7.12.1": version: 7.14.5 resolution: "@babel/preset-flow@npm:7.14.5" @@ -4766,6 +5908,32 @@ __metadata: languageName: node linkType: hard +"@babel/preset-flow@npm:^7.13.13": + version: 7.22.15 + resolution: "@babel/preset-flow@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-transform-flow-strip-types": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 17f8b80b1012802f983227b423c8823990db9748aec4f8bfd56ff774d8d954e9bdea67377788abac526754b3d307215c063c9beadf5f1b4331b30d4ba0593286 + languageName: node + linkType: hard + +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" + dependencies: + "@babel/helper-plugin-utils": ^7.0.0 + "@babel/types": ^7.4.4 + esutils: ^2.0.2 + peerDependencies: + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 + languageName: node + linkType: hard + "@babel/preset-modules@npm:^0.1.4": version: 0.1.4 resolution: "@babel/preset-modules@npm:0.1.4" @@ -4844,6 +6012,22 @@ __metadata: languageName: node linkType: hard +"@babel/preset-react@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/preset-react@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-transform-react-display-name": ^7.22.5 + "@babel/plugin-transform-react-jsx": ^7.22.15 + "@babel/plugin-transform-react-jsx-development": ^7.22.5 + "@babel/plugin-transform-react-pure-annotations": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c3ef99dfa2e9f57d2e08603e883aa20f47630a826c8e413888a93ae6e0084b5016871e463829be125329d40a1ba0a89f7c43d77b6dab52083c225cb43e63d10e + languageName: node + linkType: hard + "@babel/preset-typescript@npm:7.15.0, @babel/preset-typescript@npm:^7.12.7": version: 7.15.0 resolution: "@babel/preset-typescript@npm:7.15.0" @@ -4857,6 +6041,21 @@ __metadata: languageName: node linkType: hard +"@babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/preset-typescript@npm:7.22.15" + dependencies: + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-syntax-jsx": ^7.22.5 + "@babel/plugin-transform-modules-commonjs": ^7.22.15 + "@babel/plugin-transform-typescript": ^7.22.15 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 02ac4d5c812a52357c8f517f81584725f06f385d54ccfda89dd082e0ed89a94bd9f4d9b05fa1cbdcf426e3489c1921f04c93c5acc5deea83407a64c22ad2feb4 + languageName: node + linkType: hard + "@babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.0": version: 7.16.0 resolution: "@babel/preset-typescript@npm:7.16.0" @@ -4898,6 +6097,28 @@ __metadata: languageName: node linkType: hard +"@babel/register@npm:^7.13.16": + version: 7.22.15 + resolution: "@babel/register@npm:7.22.15" + dependencies: + clone-deep: ^4.0.1 + find-cache-dir: ^2.0.0 + make-dir: ^2.1.0 + pirates: ^4.0.5 + source-map-support: ^0.5.16 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 5497be6773608cd2d874210edd14499fce464ddbea170219da55955afe4c9173adb591164193458fd639e43b7d1314088a6186f4abf241476c59b3f0da6afd6f + languageName: node + linkType: hard + +"@babel/regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "@babel/regjsgen@npm:0.8.0" + checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 + languageName: node + linkType: hard + "@babel/runtime-corejs3@npm:^7.10.2": version: 7.15.3 resolution: "@babel/runtime-corejs3@npm:7.15.3" @@ -5026,6 +6247,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + languageName: node + linkType: hard + "@babel/template@npm:^7.22.5": version: 7.22.5 resolution: "@babel/template@npm:7.22.5" @@ -5197,6 +6429,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.22.15, @babel/traverse@npm:^7.22.20, @babel/traverse@npm:^7.22.8": + version: 7.22.20 + resolution: "@babel/traverse@npm:7.22.20" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.22.15 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.22.16 + "@babel/types": ^7.22.19 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 97da9afa7f8f505ce52c36ac2531129bc4a0e250880aaf9b467dc044f30a5bce2b756c1af4d961958bc225659546e811a7d536ab3d920fd60921087989b841b9 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.22.5": version: 7.22.5 resolution: "@babel/traverse@npm:7.22.5" @@ -5322,6 +6572,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19": + version: 7.22.19 + resolution: "@babel/types@npm:7.22.19" + dependencies: + "@babel/helper-string-parser": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.19 + to-fast-properties: ^2.0.0 + checksum: 2d69740e69b55ba36ece0c17d5afb7b7213b34297157df39ef9ba24965aff677c56f014413052ecc5b2fbbf26910c63e5bb24a969df84d7a17153750cf75915e + languageName: node + linkType: hard + "@babel/types@npm:^7.8.3": version: 7.22.10 resolution: "@babel/types@npm:7.22.10" @@ -6135,9 +7396,9 @@ __metadata: linkType: hard "@dcspark/cardano-multiplatform-lib-nodejs@npm:^3.1.1": - version: 3.1.1 - resolution: "@dcspark/cardano-multiplatform-lib-nodejs@npm:3.1.1" - checksum: e408d338fe199a29f0901364b77d284cc9455c0adc9041aadd8932b068a929040fda823a07eb80e5ca0df1396f148295cea3ea089de75339649141b23bdc00e3 + version: 3.1.2 + resolution: "@dcspark/cardano-multiplatform-lib-nodejs@npm:3.1.2" + checksum: b9afbe180758b8b564b2413b052d03f5225884d2425c23a33c8a65275c0a22de80f5a3e9ddda52a8e6a18072f7f898b5575aab70295e5216c3d3ae5e4c2daab0 languageName: node linkType: hard @@ -6352,6 +7613,15 @@ __metadata: languageName: node linkType: hard +"@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.0": + version: 1.0.1 + resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.1" + peerDependencies: + react: ">=16.8.0" + checksum: 700b6e5bbb37a9231f203bb3af11295eed01d73b2293abece0bc2a2237015e944d7b5114d4887ad9a79776504aa51ed2a8b0ddbc117c54495dd01a6b22f93786 + languageName: node + linkType: hard + "@emotion/utils@npm:0.11.3": version: 0.11.3 resolution: "@emotion/utils@npm:0.11.3" @@ -6425,6 +7695,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm64@npm:0.18.20" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/android-arm@npm:0.16.17" @@ -6453,6 +7730,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm@npm:0.18.20" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/android-x64@npm:0.16.17" @@ -6481,6 +7765,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-x64@npm:0.18.20" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/darwin-arm64@npm:0.16.17" @@ -6509,6 +7800,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-arm64@npm:0.18.20" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/darwin-x64@npm:0.16.17" @@ -6537,6 +7835,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-x64@npm:0.18.20" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/freebsd-arm64@npm:0.16.17" @@ -6565,6 +7870,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-arm64@npm:0.18.20" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/freebsd-x64@npm:0.16.17" @@ -6593,6 +7905,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-x64@npm:0.18.20" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-arm64@npm:0.16.17" @@ -6621,6 +7940,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm64@npm:0.18.20" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-arm@npm:0.16.17" @@ -6649,6 +7975,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm@npm:0.18.20" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-ia32@npm:0.16.17" @@ -6677,6 +8010,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ia32@npm:0.18.20" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-loong64@npm:0.16.17" @@ -6705,6 +8045,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-loong64@npm:0.18.20" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-mips64el@npm:0.16.17" @@ -6733,6 +8080,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-mips64el@npm:0.18.20" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-ppc64@npm:0.16.17" @@ -6761,6 +8115,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ppc64@npm:0.18.20" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-riscv64@npm:0.16.17" @@ -6789,6 +8150,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-riscv64@npm:0.18.20" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-s390x@npm:0.16.17" @@ -6817,6 +8185,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-s390x@npm:0.18.20" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/linux-x64@npm:0.16.17" @@ -6845,6 +8220,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-x64@npm:0.18.20" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/netbsd-x64@npm:0.16.17" @@ -6873,6 +8255,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/netbsd-x64@npm:0.18.20" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/openbsd-x64@npm:0.16.17" @@ -6901,6 +8290,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/openbsd-x64@npm:0.18.20" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/sunos-x64@npm:0.16.17" @@ -6929,6 +8325,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/sunos-x64@npm:0.18.20" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/win32-arm64@npm:0.16.17" @@ -6957,6 +8360,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-arm64@npm:0.18.20" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/win32-ia32@npm:0.16.17" @@ -6985,6 +8395,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-ia32@npm:0.18.20" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.16.17": version: 0.16.17 resolution: "@esbuild/win32-x64@npm:0.16.17" @@ -7013,6 +8430,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-x64@npm:0.18.20" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.1.2": version: 4.2.0 resolution: "@eslint-community/eslint-utils@npm:4.2.0" @@ -7107,6 +8531,13 @@ __metadata: languageName: node linkType: hard +"@fal-works/esbuild-plugin-global-externals@npm:^2.1.2": + version: 2.1.2 + resolution: "@fal-works/esbuild-plugin-global-externals@npm:2.1.2" + checksum: c59715902b9062aa7ff38973f298b509499fd146dbf564dc338b3f9e896da5bffb4ca676c27587fde79b3586003e24d65960acb62f009bca43dca34c76f8cbf7 + languageName: node + linkType: hard + "@figspec/components@npm:^1.0.0": version: 1.0.1 resolution: "@figspec/components@npm:1.0.1" @@ -7813,6 +9244,13 @@ __metadata: languageName: node linkType: hard +"@juggle/resize-observer@npm:^3.3.1": + version: 3.4.0 + resolution: "@juggle/resize-observer@npm:3.4.0" + checksum: 2505028c05cc2e17639fcad06218b1c4b60f932a4ebb4b41ab546ef8c157031ae377e3f560903801f6d01706dbefd4943b6c4704bf19ed86dfa1c62f1473a570 + languageName: node + linkType: hard + "@koralabs/handles-public-api-interfaces@npm:^1.6.6": version: 1.6.6 resolution: "@koralabs/handles-public-api-interfaces@npm:1.6.6" @@ -7962,8 +9400,25 @@ __metadata: resolution: "@lace/core@workspace:packages/core" dependencies: "@ant-design/icons": ^4.7.0 + "@babel/preset-env": ^7.22.20 + "@babel/preset-react": ^7.22.15 + "@babel/preset-typescript": ^7.22.15 "@lace/common": 0.1.0 "@lace/ui": ^0.1.0 + "@storybook/addon-actions": ^6.5.16 + "@storybook/addon-essentials": ^6.5.16 + "@storybook/addon-interactions": ^6.5.16 + "@storybook/addon-links": ^6.5.16 + "@storybook/addon-styling": ^1.3.7 + "@storybook/addon-styling-webpack": ^0.0.5 + "@storybook/builder-webpack5": 6.5.16 + "@storybook/core-events": ^6.5.16 + "@storybook/jest": ^0.0.10 + "@storybook/manager-webpack5": 6.5.16 + "@storybook/react": ^6.5.16 + "@storybook/test-runner": ^0.10.0 + "@storybook/testing-library": ^0.0.13 + "@types/babel__preset-env": ^7 "@types/debounce-promise": ^3.1.6 antd: ^4.24.10 axios: 0.21.4 @@ -7978,6 +9433,8 @@ __metadata: react-dom: 17.0.2 react-i18next: 11.11.4 react-infinite-scroll-component: ^6.1.0 + sass: ^1.68.0 + storybook: ^7.4.3 typescript: ^4.3.5 zxcvbn: ^4.4.2 peerDependencies: @@ -8399,6 +9856,17 @@ __metadata: languageName: node linkType: hard +"@ndelangen/get-tarball@npm:^3.0.7": + version: 3.0.9 + resolution: "@ndelangen/get-tarball@npm:3.0.9" + dependencies: + gunzip-maybe: ^1.4.2 + pump: ^3.0.0 + tar-fs: ^2.1.1 + checksum: 7fa8ac40b4e85738a4ee6bf891bc27fce2445b65b4477e0ec86aed0fa62ab18bdf5d193ce04553ad9bfa639e1eef33b8b30da4ef3e7218f12bf95f24c8786e5b + languageName: node + linkType: hard + "@noble/hashes@npm:^1.2.0": version: 1.3.1 resolution: "@noble/hashes@npm:1.3.1" @@ -9475,6 +10943,34 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-roving-focus@npm:1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-roving-focus@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-collection": 1.0.3 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 69b1c82c2d9db3ba71549a848f2704200dab1b2cd22d050c1e081a78b9a567dbfdc7fd0403ee010c19b79652de69924d8ca2076cd031d6552901e4213493ffc7 + languageName: node + linkType: hard + "@radix-ui/react-scroll-area@npm:^0.1.3": version: 0.1.4 resolution: "@radix-ui/react-scroll-area@npm:0.1.4" @@ -9495,6 +10991,66 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-select@npm:^1.2.2": + version: 1.2.2 + resolution: "@radix-ui/react-select@npm:1.2.2" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/number": 1.0.1 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-collection": 1.0.3 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-dismissable-layer": 1.0.4 + "@radix-ui/react-focus-guards": 1.0.1 + "@radix-ui/react-focus-scope": 1.0.3 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-popper": 1.1.2 + "@radix-ui/react-portal": 1.0.3 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-slot": 1.0.2 + "@radix-ui/react-use-callback-ref": 1.0.1 + "@radix-ui/react-use-controllable-state": 1.0.1 + "@radix-ui/react-use-layout-effect": 1.0.1 + "@radix-ui/react-use-previous": 1.0.1 + "@radix-ui/react-visually-hidden": 1.0.3 + aria-hidden: ^1.1.1 + react-remove-scroll: 2.5.5 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: af7b63cc9e2c6006ec08163392d244941e9e03534e7add1b7c5a86059d0eb8a0398d4f3e80d43ff22126874a02b985e44f1722d1de9218922f7aa653d09412e3 + languageName: node + linkType: hard + +"@radix-ui/react-separator@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-separator@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/react-primitive": 1.0.3 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 42f8c95e404de2ce9387040d78049808a48d423cd4c3bad8cca92c4b0bcbdcb3566b5b52a920d4e939a74b51188697f20a012221f0e630fc7f56de64096c15d2 + languageName: node + linkType: hard + "@radix-ui/react-slider@npm:^1.1.2": version: 1.1.2 resolution: "@radix-ui/react-slider@npm:1.1.2" @@ -9642,6 +11198,80 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-toggle-group@npm:1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-toggle-group@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-roving-focus": 1.0.4 + "@radix-ui/react-toggle": 1.0.3 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: b6c11fbbc3ca857ff68c0fa31f293c0d0111bcc8aa0cde2566214c090907530bfcb3b862f81585c2b02d8989b5c7971acff4d5c07c429870d80bd5602e30d376 + languageName: node + linkType: hard + +"@radix-ui/react-toggle@npm:1.0.3": + version: 1.0.3 + resolution: "@radix-ui/react-toggle@npm:1.0.3" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: ed5407f48254f20cda542017774f259d0b2c0007ea4bd7287d10d751016dbf269cb13d1142591432c269c3ab768cde2f1ba0344743027d36bbec10af909f19de + languageName: node + linkType: hard + +"@radix-ui/react-toolbar@npm:^1.0.4": + version: 1.0.4 + resolution: "@radix-ui/react-toolbar@npm:1.0.4" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-roving-focus": 1.0.4 + "@radix-ui/react-separator": 1.0.3 + "@radix-ui/react-toggle-group": 1.0.4 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 7ebee1f8add6510108979433c5b38627e2de9d48ef2172ca15274b9edbbc106ff43bcd47ff733b03ed2215b92e7af364ff82c79e5a1728374847e2b1e315552c + languageName: node + linkType: hard + "@radix-ui/react-tooltip@npm:^1.0.6": version: 1.0.6 resolution: "@radix-ui/react-tooltip@npm:1.0.6" @@ -10546,6 +12176,62 @@ __metadata: languageName: node linkType: hard +"@storybook/addon-styling-webpack@npm:^0.0.5": + version: 0.0.5 + resolution: "@storybook/addon-styling-webpack@npm:0.0.5" + dependencies: + "@storybook/node-logger": ^7.0.12 + peerDependencies: + webpack: ^5.0.0 + checksum: 43462f6b05b660f9e6a8d70640efeedfaad314ebe65d7a172d84213c9ff9f1f78d69ec5d242914ea704ec6ae9c4fc12cf0a7130d10d29367397e5e2babe2b2ed + languageName: node + linkType: hard + +"@storybook/addon-styling@npm:^1.3.7": + version: 1.3.7 + resolution: "@storybook/addon-styling@npm:1.3.7" + dependencies: + "@babel/template": ^7.20.7 + "@babel/types": ^7.21.5 + "@storybook/api": ^7.0.12 + "@storybook/components": ^7.0.12 + "@storybook/core-common": ^7.0.12 + "@storybook/core-events": ^7.0.12 + "@storybook/manager-api": ^7.0.12 + "@storybook/node-logger": ^7.0.12 + "@storybook/preview-api": ^7.0.12 + "@storybook/theming": ^7.0.12 + "@storybook/types": ^7.0.12 + css-loader: ^6.7.3 + less-loader: ^11.1.0 + postcss-loader: ^7.2.4 + prettier: ^2.8.0 + resolve-url-loader: ^5.0.0 + sass-loader: ^13.2.2 + style-loader: ^3.3.2 + peerDependencies: + less: ^3.5.0 || ^4.0.0 + postcss: ^7.0.0 || ^8.0.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + webpack: ^5.0.0 + peerDependenciesMeta: + less: + optional: true + postcss: + optional: true + react: + optional: true + react-dom: + optional: true + webpack: + optional: true + bin: + addon-styling-setup: postinstall.js + checksum: 5bac1a4109d15a6371260270518b2eada77ab153ddd0b75bb3c4ae31ee8ea61b6acacbf258add5166ae8b8450654fffc6be105c08c2b0ebdc2540abf6dba15a1 + languageName: node + linkType: hard + "@storybook/addon-toolbars@npm:6.5.16": version: 6.5.16 resolution: "@storybook/addon-toolbars@npm:6.5.16" @@ -10847,6 +12533,48 @@ __metadata: languageName: node linkType: hard +"@storybook/api@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/api@npm:7.5.0" + dependencies: + "@storybook/client-logger": 7.5.0 + "@storybook/manager-api": 7.5.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + checksum: 82fafa5963324d33f4860d2938dd8a4b6d70b810e5ec7678f676a0f288dfd9a5f1265a122d6341c9fff19be63cd2b0dcb0cc6549c840a1d6928290a3ffcda52f + languageName: node + linkType: hard + +"@storybook/builder-manager@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/builder-manager@npm:7.4.3" + dependencies: + "@fal-works/esbuild-plugin-global-externals": ^2.1.2 + "@storybook/core-common": 7.4.3 + "@storybook/manager": 7.4.3 + "@storybook/node-logger": 7.4.3 + "@types/ejs": ^3.1.1 + "@types/find-cache-dir": ^3.2.1 + "@yarnpkg/esbuild-plugin-pnp": ^3.0.0-rc.10 + browser-assert: ^1.2.1 + ejs: ^3.1.8 + esbuild: ^0.18.0 + esbuild-plugin-alias: ^0.2.1 + express: ^4.17.3 + find-cache-dir: ^3.0.0 + fs-extra: ^11.1.0 + process: ^0.11.10 + util: ^0.12.4 + checksum: bdbdf39f997e088aac54591e0705300f21bb01b52df46f125beadb45f2f90fb8afbd35ae1e514cc4c29c9fb2105fa3697482712157196d628583249c2a2b5fa2 + languageName: node + linkType: hard + "@storybook/builder-webpack4@npm:6.5.10": version: 6.5.10 resolution: "@storybook/builder-webpack4@npm:6.5.10" @@ -11153,6 +12881,86 @@ __metadata: languageName: node linkType: hard +"@storybook/channels@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/channels@npm:7.4.3" + dependencies: + "@storybook/client-logger": 7.4.3 + "@storybook/core-events": 7.4.3 + "@storybook/global": ^5.0.0 + qs: ^6.10.0 + telejson: ^7.2.0 + tiny-invariant: ^1.3.1 + checksum: 4028d8c96dd71b72fc3d27d346ce88ea73c5042648da3ea80c960b4bfee99de1e782aed03b775023616b753e3c6089f3c305c5635da1af0040270cfddd768fdd + languageName: node + linkType: hard + +"@storybook/channels@npm:7.5.0": + version: 7.5.0 + resolution: "@storybook/channels@npm:7.5.0" + dependencies: + "@storybook/client-logger": 7.5.0 + "@storybook/core-events": 7.5.0 + "@storybook/global": ^5.0.0 + qs: ^6.10.0 + telejson: ^7.2.0 + tiny-invariant: ^1.3.1 + checksum: dd318b3ab8c615b63b7f1d1c1b05ca31fb4985ba527a0ebb47d02498c18a826c78241985c644deaeaab32a4869e1cf67d40b2c7638905c01cf9942d30c0eb16d + languageName: node + linkType: hard + +"@storybook/cli@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/cli@npm:7.4.3" + dependencies: + "@babel/core": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/types": ^7.22.5 + "@ndelangen/get-tarball": ^3.0.7 + "@storybook/codemod": 7.4.3 + "@storybook/core-common": 7.4.3 + "@storybook/core-events": 7.4.3 + "@storybook/core-server": 7.4.3 + "@storybook/csf-tools": 7.4.3 + "@storybook/node-logger": 7.4.3 + "@storybook/telemetry": 7.4.3 + "@storybook/types": 7.4.3 + "@types/semver": ^7.3.4 + "@yarnpkg/fslib": 2.10.3 + "@yarnpkg/libzip": 2.3.0 + chalk: ^4.1.0 + commander: ^6.2.1 + cross-spawn: ^7.0.3 + detect-indent: ^6.1.0 + envinfo: ^7.7.3 + execa: ^5.0.0 + express: ^4.17.3 + find-up: ^5.0.0 + fs-extra: ^11.1.0 + get-npm-tarball-url: ^2.0.3 + get-port: ^5.1.1 + giget: ^1.0.0 + globby: ^11.0.2 + jscodeshift: ^0.14.0 + leven: ^3.1.0 + ora: ^5.4.1 + prettier: ^2.8.0 + prompts: ^2.4.0 + puppeteer-core: ^2.1.1 + read-pkg-up: ^7.0.1 + semver: ^7.3.7 + simple-update-notifier: ^2.0.0 + strip-json-comments: ^3.0.1 + tempy: ^1.0.1 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 + bin: + getstorybook: ./bin/index.js + sb: ./bin/index.js + checksum: cf762d80f422fa4bf448c080286b35b7081e274d7d432f7764cfbbe8f07af87fadd5eb81f7f6b73ff0c2a6d46e0d948514aee20ad0d51b1032ebc7e6de17ed97 + languageName: node + linkType: hard + "@storybook/client-api@npm:6.5.10": version: 6.5.10 resolution: "@storybook/client-api@npm:6.5.10" @@ -11274,6 +13082,46 @@ __metadata: languageName: node linkType: hard +"@storybook/client-logger@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/client-logger@npm:7.4.3" + dependencies: + "@storybook/global": ^5.0.0 + checksum: 442bd48c0b513c2bcce2d171e2ffc854f81a905597b1038fb384e2754a74bf1f59aa78d22480ad70fcb4efda0f5b70734021e8ee06cb77047a902eed37648ab1 + languageName: node + linkType: hard + +"@storybook/client-logger@npm:7.5.0": + version: 7.5.0 + resolution: "@storybook/client-logger@npm:7.5.0" + dependencies: + "@storybook/global": ^5.0.0 + checksum: 00f976e0d71107f9f07d98d3c1741ebb647cb50f3448377be481633198742a335a7178414cad5cb30f8327cfc5842f2726fbe5e5a7eafeed999a6f7cdab77e41 + languageName: node + linkType: hard + +"@storybook/codemod@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/codemod@npm:7.4.3" + dependencies: + "@babel/core": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/types": ^7.22.5 + "@storybook/csf": ^0.1.0 + "@storybook/csf-tools": 7.4.3 + "@storybook/node-logger": 7.4.3 + "@storybook/types": 7.4.3 + "@types/cross-spawn": ^6.0.2 + cross-spawn: ^7.0.3 + globby: ^11.0.2 + jscodeshift: ^0.14.0 + lodash: ^4.17.21 + prettier: ^2.8.0 + recast: ^0.23.1 + checksum: ba33c1497960c19c9873581412052c13c23565882fd57e17408fdb4094fa6d572a330ef624ef662954d7f46b8b4c9b4b0ebb0e6f24caa2927f4d03fa1f7c5b63 + languageName: node + linkType: hard + "@storybook/components@npm:6.5.10": version: 6.5.10 resolution: "@storybook/components@npm:6.5.10" @@ -11312,6 +13160,27 @@ __metadata: languageName: node linkType: hard +"@storybook/components@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/components@npm:7.5.0" + dependencies: + "@radix-ui/react-select": ^1.2.2 + "@radix-ui/react-toolbar": ^1.0.4 + "@storybook/client-logger": 7.5.0 + "@storybook/csf": ^0.1.0 + "@storybook/global": ^5.0.0 + "@storybook/theming": 7.5.0 + "@storybook/types": 7.5.0 + memoizerific: ^1.11.3 + use-resize-observer: ^9.1.0 + util-deprecate: ^1.0.2 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 5c8e194c2a827e9bf48f4237d00b4875022f1ad12855031a76f069cb4a679bc3a53ae6dfd15fe779578de8fdcaf3fbc28f2e0d681a2d8a2581ee39a5a29a020e + languageName: node + linkType: hard + "@storybook/components@npm:~6.3.0": version: 6.3.13 resolution: "@storybook/components@npm:6.3.13" @@ -11545,6 +13414,37 @@ __metadata: languageName: node linkType: hard +"@storybook/core-common@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/core-common@npm:7.4.3" + dependencies: + "@storybook/core-events": 7.4.3 + "@storybook/node-logger": 7.4.3 + "@storybook/types": 7.4.3 + "@types/find-cache-dir": ^3.2.1 + "@types/node": ^16.0.0 + "@types/node-fetch": ^2.6.4 + "@types/pretty-hrtime": ^1.0.0 + chalk: ^4.1.0 + esbuild: ^0.18.0 + esbuild-register: ^3.4.0 + file-system-cache: 2.3.0 + find-cache-dir: ^3.0.0 + find-up: ^5.0.0 + fs-extra: ^11.1.0 + glob: ^10.0.0 + handlebars: ^4.7.7 + lazy-universal-dotenv: ^4.0.0 + node-fetch: ^2.0.0 + picomatch: ^2.3.0 + pkg-dir: ^5.0.0 + pretty-hrtime: ^1.0.3 + resolve-from: ^5.0.0 + ts-dedent: ^2.0.0 + checksum: e81afc618648d9f41643eaeca68458bccdd350432023de43a4f3db1f5732e7d689e3527f077c2a2c48271918417684a303ee755b4a14e543edf0808c36295435 + languageName: node + linkType: hard + "@storybook/core-common@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": version: 7.0.2 resolution: "@storybook/core-common@npm:7.0.2" @@ -11572,6 +13472,37 @@ __metadata: languageName: node linkType: hard +"@storybook/core-common@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/core-common@npm:7.5.0" + dependencies: + "@storybook/core-events": 7.5.0 + "@storybook/node-logger": 7.5.0 + "@storybook/types": 7.5.0 + "@types/find-cache-dir": ^3.2.1 + "@types/node": ^18.0.0 + "@types/node-fetch": ^2.6.4 + "@types/pretty-hrtime": ^1.0.0 + chalk: ^4.1.0 + esbuild: ^0.18.0 + esbuild-register: ^3.5.0 + file-system-cache: 2.3.0 + find-cache-dir: ^3.0.0 + find-up: ^5.0.0 + fs-extra: ^11.1.0 + glob: ^10.0.0 + handlebars: ^4.7.7 + lazy-universal-dotenv: ^4.0.0 + node-fetch: ^2.0.0 + picomatch: ^2.3.0 + pkg-dir: ^5.0.0 + pretty-hrtime: ^1.0.3 + resolve-from: ^5.0.0 + ts-dedent: ^2.0.0 + checksum: 88300d4a8fc61c2dcc87a24ed54d61d5a9591655694e59b4bad67fd053b8db842500082bf5487ca477209e8dc1fe35a2127958342d4b41ce5c6c2584a59995f7 + languageName: node + linkType: hard + "@storybook/core-events@npm:6.3.13, @storybook/core-events@npm:~6.3.0": version: 6.3.13 resolution: "@storybook/core-events@npm:6.3.13" @@ -11608,7 +13539,7 @@ __metadata: languageName: node linkType: hard -"@storybook/core-events@npm:6.5.16": +"@storybook/core-events@npm:6.5.16, @storybook/core-events@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/core-events@npm:6.5.16" dependencies: @@ -11624,6 +13555,24 @@ __metadata: languageName: node linkType: hard +"@storybook/core-events@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/core-events@npm:7.4.3" + dependencies: + ts-dedent: ^2.0.0 + checksum: ffe6c5a0a7db32a42fcbe2fbe027977f071c458da621793468409ac29808a24573f94f083362200dde4b00bc14b00a66053ace4c9e3686b442ee2e4a126c9855 + languageName: node + linkType: hard + +"@storybook/core-events@npm:7.5.0, @storybook/core-events@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/core-events@npm:7.5.0" + dependencies: + ts-dedent: ^2.0.0 + checksum: 829321419c5e5e21c17e72c4006004e73b24648e065ed5b278074317f5d57ce896a1a28deff51184ae44fd8a9d463519ab261bbe5a17736ca50ff7c5bbcb44f9 + languageName: node + linkType: hard + "@storybook/core-server@npm:6.5.10": version: 6.5.10 resolution: "@storybook/core-server@npm:6.5.10" @@ -11750,6 +13699,56 @@ __metadata: languageName: node linkType: hard +"@storybook/core-server@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/core-server@npm:7.4.3" + dependencies: + "@aw-web-design/x-default-browser": 1.4.126 + "@discoveryjs/json-ext": ^0.5.3 + "@storybook/builder-manager": 7.4.3 + "@storybook/channels": 7.4.3 + "@storybook/core-common": 7.4.3 + "@storybook/core-events": 7.4.3 + "@storybook/csf": ^0.1.0 + "@storybook/csf-tools": 7.4.3 + "@storybook/docs-mdx": ^0.1.0 + "@storybook/global": ^5.0.0 + "@storybook/manager": 7.4.3 + "@storybook/node-logger": 7.4.3 + "@storybook/preview-api": 7.4.3 + "@storybook/telemetry": 7.4.3 + "@storybook/types": 7.4.3 + "@types/detect-port": ^1.3.0 + "@types/node": ^16.0.0 + "@types/pretty-hrtime": ^1.0.0 + "@types/semver": ^7.3.4 + better-opn: ^3.0.2 + chalk: ^4.1.0 + cli-table3: ^0.6.1 + compression: ^1.7.4 + detect-port: ^1.3.0 + express: ^4.17.3 + fs-extra: ^11.1.0 + globby: ^11.0.2 + ip: ^2.0.0 + lodash: ^4.17.21 + open: ^8.4.0 + pretty-hrtime: ^1.0.3 + prompts: ^2.4.0 + read-pkg-up: ^7.0.1 + semver: ^7.3.7 + serve-favicon: ^2.5.0 + telejson: ^7.2.0 + tiny-invariant: ^1.3.1 + ts-dedent: ^2.0.0 + util: ^0.12.4 + util-deprecate: ^1.0.2 + watchpack: ^2.2.0 + ws: ^8.2.3 + checksum: 4465b9285d2b6ff036e00f4c0e9100b84ced1c51a43d107c6cd618c366fe09cbb3f10aeb7d7b96aeb2afb255893ff077d2cad8f36cb61b81027fa7a8a908be0c + languageName: node + linkType: hard + "@storybook/core@npm:6.5.10": version: 6.5.10 resolution: "@storybook/core@npm:6.5.10" @@ -11846,6 +13845,23 @@ __metadata: languageName: node linkType: hard +"@storybook/csf-tools@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/csf-tools@npm:7.4.3" + dependencies: + "@babel/generator": ^7.22.9 + "@babel/parser": ^7.22.7 + "@babel/traverse": ^7.22.8 + "@babel/types": ^7.22.5 + "@storybook/csf": ^0.1.0 + "@storybook/types": 7.4.3 + fs-extra: ^11.1.0 + recast: ^0.23.1 + ts-dedent: ^2.0.0 + checksum: 6910d1613c8fa1b411bda1d23e4d03259152b03589b56e952165d3586bebfdd1d70b8dfba3ed8a2e67dbec4da6f48804ff448d58dab14e94c945decf1c264475 + languageName: node + linkType: hard + "@storybook/csf-tools@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": version: 7.0.2 resolution: "@storybook/csf-tools@npm:7.0.2" @@ -11890,6 +13906,13 @@ __metadata: languageName: node linkType: hard +"@storybook/docs-mdx@npm:^0.1.0": + version: 0.1.0 + resolution: "@storybook/docs-mdx@npm:0.1.0" + checksum: a7770842c3947a761bcbe776a9c4fd35163d30c3274fca034169f69ff614242eaa4cacaa2c95fd215827081ef9a43f4774d521a6f43a4d063ea5f4ea14b1d69a + languageName: node + linkType: hard + "@storybook/docs-tools@npm:6.5.10": version: 6.5.10 resolution: "@storybook/docs-tools@npm:6.5.10" @@ -11974,6 +13997,32 @@ __metadata: languageName: node linkType: hard +"@storybook/manager-api@npm:7.5.0, @storybook/manager-api@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/manager-api@npm:7.5.0" + dependencies: + "@storybook/channels": 7.5.0 + "@storybook/client-logger": 7.5.0 + "@storybook/core-events": 7.5.0 + "@storybook/csf": ^0.1.0 + "@storybook/global": ^5.0.0 + "@storybook/router": 7.5.0 + "@storybook/theming": 7.5.0 + "@storybook/types": 7.5.0 + dequal: ^2.0.2 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + semver: ^7.3.7 + store2: ^2.14.2 + telejson: ^7.2.0 + ts-dedent: ^2.0.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: c651ed1594f7bd704a846c2ba782785a0fdf83779d10b400b034711e65e40975e67d8cc484d5753523d2341112dd7e63b49dc71b04803b7a718b793b08adabf7 + languageName: node + linkType: hard + "@storybook/manager-webpack4@npm:6.5.10": version: 6.5.10 resolution: "@storybook/manager-webpack4@npm:6.5.10" @@ -12118,6 +14167,13 @@ __metadata: languageName: node linkType: hard +"@storybook/manager@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/manager@npm:7.4.3" + checksum: f7f78da50150dfc679242db97c8ebdf1da0592c6bf91e2c2daa70a263cd9e61a51e6d26cf331c3350b445bf5f3dd9f0a1e461c085fd2aaa52f35db4669be90d2 + languageName: node + linkType: hard + "@storybook/mdx1-csf@npm:^0.0.1": version: 0.0.1 resolution: "@storybook/mdx1-csf@npm:0.0.1" @@ -12175,6 +14231,20 @@ __metadata: languageName: node linkType: hard +"@storybook/node-logger@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/node-logger@npm:7.4.3" + checksum: 3d067b5e51f52622f4f950fb9bc3584dddc80e30cfd5348936c361ad6ea3006c99fcb23a29f57290b77c770c082f766ede177405d57a7fd68fad7881f6844bfc + languageName: node + linkType: hard + +"@storybook/node-logger@npm:7.5.0, @storybook/node-logger@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/node-logger@npm:7.5.0" + checksum: e6288f345f2a0a1db7fb3a6605910b37d844d4e4fedc2459ae2825a924e8c15453436d074fd1d87e89e82108eab6f32bd3870402ec25f381f572024f73b67319 + languageName: node + linkType: hard + "@storybook/postinstall@npm:6.5.16": version: 6.5.16 resolution: "@storybook/postinstall@npm:6.5.16" @@ -12184,6 +14254,28 @@ __metadata: languageName: node linkType: hard +"@storybook/preview-api@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/preview-api@npm:7.4.3" + dependencies: + "@storybook/channels": 7.4.3 + "@storybook/client-logger": 7.4.3 + "@storybook/core-events": 7.4.3 + "@storybook/csf": ^0.1.0 + "@storybook/global": ^5.0.0 + "@storybook/types": 7.4.3 + "@types/qs": ^6.9.5 + dequal: ^2.0.2 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + qs: ^6.10.0 + synchronous-promise: ^2.0.15 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 + checksum: 2347e122283847c4b02741e487f121a929288b0fcad589f2ef07b8b42352c0d652a33a31c44cbe492176a691929e3d27936232f53bed2834bb67146a2101f470 + languageName: node + linkType: hard + "@storybook/preview-api@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": version: 7.0.2 resolution: "@storybook/preview-api@npm:7.0.2" @@ -12207,6 +14299,28 @@ __metadata: languageName: node linkType: hard +"@storybook/preview-api@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/preview-api@npm:7.5.0" + dependencies: + "@storybook/channels": 7.5.0 + "@storybook/client-logger": 7.5.0 + "@storybook/core-events": 7.5.0 + "@storybook/csf": ^0.1.0 + "@storybook/global": ^5.0.0 + "@storybook/types": 7.5.0 + "@types/qs": ^6.9.5 + dequal: ^2.0.2 + lodash: ^4.17.21 + memoizerific: ^1.11.3 + qs: ^6.10.0 + synchronous-promise: ^2.0.15 + ts-dedent: ^2.0.0 + util-deprecate: ^1.0.2 + checksum: 43984ba7e3aafe3b32ac88adebb2dc898d5f96a991fe98a37524b02c2e8f887d4757d5b12ea5c5b812db173310076f2367e46f85ba21c4005591e87a100debc5 + languageName: node + linkType: hard + "@storybook/preview-web@npm:6.5.10": version: 6.5.10 resolution: "@storybook/preview-web@npm:6.5.10" @@ -12503,6 +14617,20 @@ __metadata: languageName: node linkType: hard +"@storybook/router@npm:7.5.0": + version: 7.5.0 + resolution: "@storybook/router@npm:7.5.0" + dependencies: + "@storybook/client-logger": 7.5.0 + memoizerific: ^1.11.3 + qs: ^6.10.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: be37e8e525c1c2d7ad6da883a1d588dbf3fe182143dc02222f10a43baaed3b7259e8c7c7bf32ac54e26bdc58cfb040bb418d898d8d97e8107a83a9d3c7ccd139 + languageName: node + linkType: hard + "@storybook/semver@npm:^7.3.2": version: 7.3.2 resolution: "@storybook/semver@npm:7.3.2" @@ -12628,6 +14756,22 @@ __metadata: languageName: node linkType: hard +"@storybook/telemetry@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/telemetry@npm:7.4.3" + dependencies: + "@storybook/client-logger": 7.4.3 + "@storybook/core-common": 7.4.3 + "@storybook/csf-tools": 7.4.3 + chalk: ^4.1.0 + detect-package-manager: ^2.0.1 + fetch-retry: ^5.0.2 + fs-extra: ^11.1.0 + read-pkg-up: ^7.0.1 + checksum: e2ecd2d6644cd0536554e270c552d45936c70d26230e24cc839a51c70340fdae3575017388a613ff549d5577238d748ca53ac8a1e9095ee76db291b3f0793b45 + languageName: node + linkType: hard + "@storybook/test-runner@npm:^0.10.0": version: 0.10.0 resolution: "@storybook/test-runner@npm:0.10.0" @@ -12764,6 +14908,21 @@ __metadata: languageName: node linkType: hard +"@storybook/theming@npm:7.5.0, @storybook/theming@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/theming@npm:7.5.0" + dependencies: + "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 + "@storybook/client-logger": 7.5.0 + "@storybook/global": ^5.0.0 + memoizerific: ^1.11.3 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: d7e94fb094daf3a064ab5ad65104f60d82ccf3cf7a9b194174725d9e96f888f1c3378e59a3c7dfc4a7e745354f504fd6f5e3145e69e315470ca6c004c3a7fdc5 + languageName: node + linkType: hard + "@storybook/types@npm:7.0.2": version: 7.0.2 resolution: "@storybook/types@npm:7.0.2" @@ -12776,6 +14935,30 @@ __metadata: languageName: node linkType: hard +"@storybook/types@npm:7.4.3": + version: 7.4.3 + resolution: "@storybook/types@npm:7.4.3" + dependencies: + "@storybook/channels": 7.4.3 + "@types/babel__core": ^7.0.0 + "@types/express": ^4.7.0 + file-system-cache: 2.3.0 + checksum: 4108d185086884b742258edc67b9f3837099e63f3b902889f927e0e9cb34ba4da37fbcbe94235388672ba20eefac6f397cd0113e8e873538f31eda521dfb1365 + languageName: node + linkType: hard + +"@storybook/types@npm:7.5.0, @storybook/types@npm:^7.0.12": + version: 7.5.0 + resolution: "@storybook/types@npm:7.5.0" + dependencies: + "@storybook/channels": 7.5.0 + "@types/babel__core": ^7.0.0 + "@types/express": ^4.7.0 + file-system-cache: 2.3.0 + checksum: e74f807660eb9a626c3aea1822d7eb412b4ea129e5254e4e2b8e6f2af292d4ea797ad73e1b64e36ba44fdd3015297f2fde095fdc80690f56f5e050fc1d5576f7 + languageName: node + linkType: hard + "@storybook/ui@npm:6.5.10": version: 6.5.10 resolution: "@storybook/ui@npm:6.5.10" @@ -14164,6 +16347,13 @@ __metadata: languageName: node linkType: hard +"@types/babel__preset-env@npm:^7": + version: 7.9.3 + resolution: "@types/babel__preset-env@npm:7.9.3" + checksum: 7e89a37c4a7ebe841e0bc610e19497fe0642d741e8651c52ea4727782e46ea47d2aaf2656927a684c6618d8981b0febc1fc8c82c4a1d84b4ec5793a283e1ef7f + languageName: node + linkType: hard + "@types/babel__template@npm:*": version: 7.4.1 resolution: "@types/babel__template@npm:7.4.1" @@ -14290,6 +16480,15 @@ __metadata: languageName: node linkType: hard +"@types/cross-spawn@npm:^6.0.2": + version: 6.0.3 + resolution: "@types/cross-spawn@npm:6.0.3" + dependencies: + "@types/node": "*" + checksum: 06d50fa1e1370ef60b9c9085b76adec7d7bc20728fbb02b3c2061d4d922312acf1ba56a7c94d88c27a22fc6241ab6b970c936f3294038a9c97a719fbc8eb8a76 + languageName: node + linkType: hard + "@types/d3-array@npm:^3.0.3": version: 3.0.5 resolution: "@types/d3-array@npm:3.0.5" @@ -14375,6 +16574,13 @@ __metadata: languageName: node linkType: hard +"@types/detect-port@npm:^1.3.0": + version: 1.3.3 + resolution: "@types/detect-port@npm:1.3.3" + checksum: 0dadb520286a5cfd2832d12189dc795cc3589dfd9166d1b033453fb94b0212c4067a847045833e85b0f7c73135c944cb4ccb49c8e683491845c2e8a3da5d5c1c + languageName: node + linkType: hard + "@types/docker-modem@npm:*": version: 3.0.2 resolution: "@types/docker-modem@npm:3.0.2" @@ -14406,6 +16612,20 @@ __metadata: languageName: node linkType: hard +"@types/ejs@npm:^3.1.1": + version: 3.1.2 + resolution: "@types/ejs@npm:3.1.2" + checksum: e4f0745b6ed53a63c08bdfdeb019a7d0e0c400896722b44d6732b4ee6bf6061d2dc965206186b8b0ae2ecd71303c29f1af1feddbca2df0acbd7bd234a74ca518 + languageName: node + linkType: hard + +"@types/emscripten@npm:^1.39.6": + version: 1.39.7 + resolution: "@types/emscripten@npm:1.39.7" + checksum: 9871e4495358cc06cc45b2798022cd097d8ac2eb5b2fae7c276c6c5cadea05507150fad053c73ed346d4cbd844c50a3438604e5d7c3c2a7446b703cacb1ce172 + languageName: node + linkType: hard + "@types/eslint-scope@npm:^3.7.0": version: 3.7.1 resolution: "@types/eslint-scope@npm:3.7.1" @@ -14545,6 +16765,13 @@ __metadata: languageName: node linkType: hard +"@types/find-cache-dir@npm:^3.2.1": + version: 3.2.1 + resolution: "@types/find-cache-dir@npm:3.2.1" + checksum: bf5c4e96da40247cd9e6327f54dfccda961a0fb2d70e3c71bd05def94de4c2e6fb310fe8ecb0f04ecf5dbc52214e184b55a2337b0f87250d4ae1e2e7d58321e4 + languageName: node + linkType: hard + "@types/flat@npm:5.0.2": version: 5.0.2 resolution: "@types/flat@npm:5.0.2" @@ -14793,6 +17020,13 @@ __metadata: languageName: node linkType: hard +"@types/mime-types@npm:^2.1.0": + version: 2.1.1 + resolution: "@types/mime-types@npm:2.1.1" + checksum: 106b5d556add46446a579ad25ff15d6b421851790d887edcad558c90c1e64b1defc72bfbaf4b08f208916e21d9cc45cdb951d77be51268b18221544cfe054a3c + languageName: node + linkType: hard + "@types/mime@npm:*": version: 3.0.1 resolution: "@types/mime@npm:3.0.1" @@ -14838,6 +17072,16 @@ __metadata: languageName: node linkType: hard +"@types/node-fetch@npm:^2.6.4": + version: 2.6.5 + resolution: "@types/node-fetch@npm:2.6.5" + dependencies: + "@types/node": "*" + form-data: ^4.0.0 + checksum: 686ee0d52bb82d73f82c0da0bb025d4af1ba7bd8df4edd09336f6179eb838b6d4b5f0a524677a8faec2b00918d1b08a1690d50fa592c9741a5df6a8041a52495 + languageName: node + linkType: hard + "@types/node@npm:*": version: 16.4.13 resolution: "@types/node@npm:16.4.13" @@ -14887,6 +17131,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^18.0.0": + version: 18.18.6 + resolution: "@types/node@npm:18.18.6" + checksum: a847639b8455fd3dfa6dbc2917274c82c9db789f1d41aaf69f94ac6c9e54c3c1dd29be6e1e1ccd7c17e54db3d78d7011bc4e70544c6447ceca253dccc0a187e1 + languageName: node + linkType: hard + "@types/node@npm:^18.11.18": version: 18.15.0 resolution: "@types/node@npm:18.15.0" @@ -15171,6 +17422,13 @@ __metadata: languageName: node linkType: hard +"@types/semver@npm:^7.3.4": + version: 7.5.2 + resolution: "@types/semver@npm:7.5.2" + checksum: 743aa8a2b58e20b329c19bd2459152cb049d12fafab7279b90ac11e0f268c97efbcb606ea0c681cca03f79015381b40d9b1244349b354270bec3f939ed49f6e9 + languageName: node + linkType: hard + "@types/serve-index@npm:^1.9.1": version: 1.9.1 resolution: "@types/serve-index@npm:1.9.1" @@ -16990,6 +19248,37 @@ __metadata: languageName: node linkType: hard +"@yarnpkg/esbuild-plugin-pnp@npm:^3.0.0-rc.10": + version: 3.0.0-rc.15 + resolution: "@yarnpkg/esbuild-plugin-pnp@npm:3.0.0-rc.15" + dependencies: + tslib: ^2.4.0 + peerDependencies: + esbuild: ">=0.10.0" + checksum: 04da15355a99773b441742814ba4d0f3453a83df47aa07e215f167e156f109ab8e971489c8b1a4ddf3c79d568d35213f496ad52e97298228597e1aacc22680aa + languageName: node + linkType: hard + +"@yarnpkg/fslib@npm:2.10.3": + version: 2.10.3 + resolution: "@yarnpkg/fslib@npm:2.10.3" + dependencies: + "@yarnpkg/libzip": ^2.3.0 + tslib: ^1.13.0 + checksum: 0ca693f61d47bcf165411a121ed9123f512b1b5bfa5e1c6c8f280b4ffdbea9bf2a6db418f99ecfc9624587fdc695b2b64eb0fe7b4028e44095914b25ca99655e + languageName: node + linkType: hard + +"@yarnpkg/libzip@npm:2.3.0, @yarnpkg/libzip@npm:^2.3.0": + version: 2.3.0 + resolution: "@yarnpkg/libzip@npm:2.3.0" + dependencies: + "@types/emscripten": ^1.39.6 + tslib: ^1.13.0 + checksum: 533a4883f69bb013f955d80dc19719881697e6849ea5f0cbe6d87ef1d582b05cbae8a453802f92ad0c852f976296cac3ff7834be79a7e415b65cdf213e448110 + languageName: node + linkType: hard + "@zxing/text-encoding@npm:0.9.0": version: 0.9.0 resolution: "@zxing/text-encoding@npm:0.9.0" @@ -17211,6 +19500,23 @@ __metadata: languageName: node linkType: hard +"adjust-sourcemap-loader@npm:^4.0.0": + version: 4.0.0 + resolution: "adjust-sourcemap-loader@npm:4.0.0" + dependencies: + loader-utils: ^2.0.0 + regex-parser: ^2.2.11 + checksum: d524ae23582f41e2275af5d88faab7a9dc09770ed588244e0a76d3196d0d6a90bf02760c71bc6213dbfef3aef4a86232ac9521bfd629752c32b7af37bc74c660 + languageName: node + linkType: hard + +"agent-base@npm:5": + version: 5.1.1 + resolution: "agent-base@npm:5.1.1" + checksum: 61ae789f3019f1dc10e8cba6d3ae9826949299a4e54aaa1cfa2fa37c95a108e70e95423b963bb987d7891a703fd9a5c383a506f4901819f3ee56f3147c0aa8ab + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -18085,6 +20391,15 @@ __metadata: languageName: node linkType: hard +"ast-types@npm:0.15.2": + version: 0.15.2 + resolution: "ast-types@npm:0.15.2" + dependencies: + tslib: ^2.0.1 + checksum: 24f0d86bf9e4c8dae16fa24b13c1776f2c2677040bcfbd4eb4f27911db49020be4876885e45e6cfcc548ed4dfea3a0742d77e3346b84fae47379cb0b89e9daa0 + languageName: node + linkType: hard + "ast-types@npm:^0.13.4": version: 0.13.4 resolution: "ast-types@npm:0.13.4" @@ -18149,6 +20464,13 @@ __metadata: languageName: node linkType: hard +"async-limiter@npm:~1.0.0": + version: 1.0.1 + resolution: "async-limiter@npm:1.0.1" + checksum: 2b849695b465d93ad44c116220dee29a5aeb63adac16c1088983c339b0de57d76e82533e8e364a93a9f997f28bbfc6a92948cefc120652bd07f3b59f8d75cf2b + languageName: node + linkType: hard + "async-validator@npm:^4.0.2": version: 4.0.7 resolution: "async-validator@npm:4.0.7" @@ -18299,6 +20621,15 @@ __metadata: languageName: node linkType: hard +"babel-core@npm:^7.0.0-bridge.0": + version: 7.0.0-bridge.0 + resolution: "babel-core@npm:7.0.0-bridge.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2a1cb879019dffb08d17bec36e13c3a6d74c94773f41c1fd8b14de13f149cc34b705b0a1e07b42fcf35917b49d78db6ff0c5c3b00b202a5235013d517b5c6bbb + languageName: node + linkType: hard + "babel-eslint@npm:10.0.3": version: 10.0.3 resolution: "babel-eslint@npm:10.0.3" @@ -18538,6 +20869,19 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs2@npm:^0.4.5": + version: 0.4.5 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.5" + dependencies: + "@babel/compat-data": ^7.22.6 + "@babel/helper-define-polyfill-provider": ^0.4.2 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 33a8e06aa54e2858d211c743d179f0487b03222f9ca1bfd7c4865bca243fca942a3358cb75f6bb894ed476cbddede834811fbd6903ff589f055821146f053e1a + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs3@npm:^0.1.0": version: 0.1.7 resolution: "babel-plugin-polyfill-corejs3@npm:0.1.7" @@ -18586,6 +20930,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.8.3": + version: 0.8.3 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.3" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.4.2 + core-js-compat: ^3.31.0 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: dcbb30e551702a82cfd4d2c375da2c317658e55f95e9edcda93b9bbfdcc8fb6e5344efcb144e04d3406859e7682afce7974c60ededd9f12072a48a83dd22a0da + languageName: node + linkType: hard + "babel-plugin-polyfill-regenerator@npm:^0.2.2": version: 0.2.2 resolution: "babel-plugin-polyfill-regenerator@npm:0.2.2" @@ -18619,6 +20975,17 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-regenerator@npm:^0.5.2": + version: 0.5.2 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.2" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.4.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: d962200f604016a9a09bc9b4aaf60a3db7af876bb65bcefaeac04d44ac9d9ec4037cf24ce117760cc141d7046b6394c7eb0320ba9665cb4a2ee64df2be187c93 + languageName: node + linkType: hard + "babel-plugin-react-docgen@npm:^4.2.1": version: 4.2.1 resolution: "babel-plugin-react-docgen@npm:4.2.1" @@ -18852,6 +21219,15 @@ __metadata: languageName: node linkType: hard +"better-opn@npm:^3.0.2": + version: 3.0.2 + resolution: "better-opn@npm:3.0.2" + dependencies: + open: ^8.0.4 + checksum: 1471552fa7f733561e7f49e812be074b421153006ca744de985fb6d38939807959fc5fe9cb819cf09f864782e294704fd3b31711ea14c115baf3330a2f1135de + languageName: node + linkType: hard + "big-integer@npm:1.6.36": version: 1.6.36 resolution: "big-integer@npm:1.6.36" @@ -19334,6 +21710,15 @@ __metadata: languageName: node linkType: hard +"browserify-zlib@npm:^0.1.4": + version: 0.1.4 + resolution: "browserify-zlib@npm:0.1.4" + dependencies: + pako: ~0.2.0 + checksum: abee4cb4349e8a21391fd874564f41b113fe691372913980e6fa06a777e4ea2aad4e942af14ab99bce190d5ac8f5328201432f4ef0eae48c6d02208bc212976f + languageName: node + linkType: hard + "browserify-zlib@npm:^0.2.0": version: 0.2.0 resolution: "browserify-zlib@npm:0.2.0" @@ -19388,6 +21773,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.21.10, browserslist@npm:^4.21.9": + version: 4.21.10 + resolution: "browserslist@npm:4.21.10" + dependencies: + caniuse-lite: ^1.0.30001517 + electron-to-chromium: ^1.4.477 + node-releases: ^2.0.13 + update-browserslist-db: ^1.0.11 + bin: + browserslist: cli.js + checksum: 1e27c0f111a35d1dd0e8fc2c61781b0daefabc2c9471b0b10537ce54843014bceb2a1ce4571af1a82b2bf1e6e6e05d38865916689a158f03bc2c7a4ec2577db8 + languageName: node + linkType: hard + "browserslist@npm:^4.21.3, browserslist@npm:^4.21.4": version: 4.21.4 resolution: "browserslist@npm:4.21.4" @@ -19973,7 +22372,7 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001248, caniuse-lite@npm:^1.0.30001251, caniuse-lite@npm:^1.0.30001280, caniuse-lite@npm:^1.0.30001400": +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001248, caniuse-lite@npm:^1.0.30001251, caniuse-lite@npm:^1.0.30001280, caniuse-lite@npm:^1.0.30001400, caniuse-lite@npm:^1.0.30001517": version: 1.0.30001538 resolution: "caniuse-lite@npm:1.0.30001538" checksum: 94c5d55757a339c7cc175f08a024671e2b4e7c04f130b1015793303d637061347efb6ad84447c3b8137333e742d150b8ad9672716bbf2482646c2e63a56f6c55 @@ -21064,7 +23463,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.0": +"concat-stream@npm:^1.5.0, concat-stream@npm:^1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -21598,6 +23997,15 @@ __metadata: languageName: node linkType: hard +"core-js-compat@npm:^3.31.0": + version: 3.32.2 + resolution: "core-js-compat@npm:3.32.2" + dependencies: + browserslist: ^4.21.10 + checksum: efca146ad71a542e6f196db5ba5aed617e48c615bdf1fbb065471b3267f833ac545bd5fc5ad0642c3d3974b955f0684ff0863d7471d7050ee0284e0a1313942e + languageName: node + linkType: hard + "core-js-compat@npm:^3.8.1": version: 3.16.3 resolution: "core-js-compat@npm:3.16.3" @@ -21720,6 +24128,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.2.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: ^3.3.0 + js-yaml: ^4.1.0 + parse-json: ^5.2.0 + path-type: ^4.0.0 + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0 + languageName: node + linkType: hard + "cp-file@npm:^7.0.0": version: 7.0.0 resolution: "cp-file@npm:7.0.0" @@ -21995,6 +24420,24 @@ __metadata: languageName: node linkType: hard +"css-loader@npm:^6.7.3": + version: 6.8.1 + resolution: "css-loader@npm:6.8.1" + dependencies: + icss-utils: ^5.1.0 + postcss: ^8.4.21 + postcss-modules-extract-imports: ^3.0.0 + postcss-modules-local-by-default: ^4.0.3 + postcss-modules-scope: ^3.0.0 + postcss-modules-values: ^4.0.0 + postcss-value-parser: ^4.2.0 + semver: ^7.3.8 + peerDependencies: + webpack: ^5.0.0 + checksum: 7c1784247bdbe76dc5c55fb1ac84f1d4177a74c47259942c9cfdb7a8e6baef11967a0bc85ac285f26bd26d5059decb848af8154a03fdb4f4894f41212f45eef3 + languageName: node + linkType: hard + "css-mediaquery@npm:^0.1.2": version: 0.1.2 resolution: "css-mediaquery@npm:0.1.2" @@ -22613,6 +25056,16 @@ __metadata: languageName: node linkType: hard +"default-browser-id@npm:3.0.0, default-browser-id@npm:^3.0.0": + version: 3.0.0 + resolution: "default-browser-id@npm:3.0.0" + dependencies: + bplist-parser: ^0.2.0 + untildify: ^4.0.0 + checksum: 279c7ad492542e5556336b6c254a4eaf31b2c63a5433265655ae6e47301197b6cfb15c595a6fdc6463b2ff8e1a1a1ed3cba56038a60e1527ba4ab1628c6b9941 + languageName: node + linkType: hard + "default-browser-id@npm:^1.0.4": version: 1.0.4 resolution: "default-browser-id@npm:1.0.4" @@ -22626,16 +25079,6 @@ __metadata: languageName: node linkType: hard -"default-browser-id@npm:^3.0.0": - version: 3.0.0 - resolution: "default-browser-id@npm:3.0.0" - dependencies: - bplist-parser: ^0.2.0 - untildify: ^4.0.0 - checksum: 279c7ad492542e5556336b6c254a4eaf31b2c63a5433265655ae6e47301197b6cfb15c595a6fdc6463b2ff8e1a1a1ed3cba56038a60e1527ba4ab1628c6b9941 - languageName: node - linkType: hard - "default-browser@npm:^4.0.0": version: 4.0.0 resolution: "default-browser@npm:4.0.0" @@ -22753,6 +25196,13 @@ __metadata: languageName: node linkType: hard +"defu@npm:^6.1.2": + version: 6.1.2 + resolution: "defu@npm:6.1.2" + checksum: 2ec0ff8414d5a1ab2b8c7e9a79bbad6d97d23ea7ebf5dcf80c3c7ffd9715c30f84a3cc47b917379ea756b3db0dc4701ce6400e493a1ae1688dffcd0f884233b2 + languageName: node + linkType: hard + "degenerator@npm:^5.0.0": version: 5.0.1 resolution: "degenerator@npm:5.0.1" @@ -22870,7 +25320,7 @@ __metadata: languageName: node linkType: hard -"detect-indent@npm:^6.0.0": +"detect-indent@npm:^6.0.0, detect-indent@npm:^6.1.0": version: 6.1.0 resolution: "detect-indent@npm:6.1.0" checksum: ab953a73c72dbd4e8fc68e4ed4bfd92c97eb6c43734af3900add963fd3a9316f3bc0578b018b24198d4c31a358571eff5f0656e81a1f3b9ad5c547d58b2d093d @@ -23408,7 +25858,7 @@ __metadata: languageName: node linkType: hard -"duplexify@npm:^3.4.2, duplexify@npm:^3.6.0": +"duplexify@npm:^3.4.2, duplexify@npm:^3.5.0, duplexify@npm:^3.6.0": version: 3.7.1 resolution: "duplexify@npm:3.7.1" dependencies: @@ -23483,7 +25933,7 @@ __metadata: languageName: node linkType: hard -"ejs@npm:^3.1.9": +"ejs@npm:^3.1.8, ejs@npm:^3.1.9": version: 3.1.9 resolution: "ejs@npm:3.1.9" dependencies: @@ -23522,6 +25972,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.477": + version: 1.4.526 + resolution: "electron-to-chromium@npm:1.4.526" + checksum: db37adc0b39b8d3f600e86f5f451744025a174fbe2e42ac4a7dbda809d7b417a0624d2570a8df5cb8f9f1e30d6b9ca9a5079eb09288ddd4a9588c6a39e3c3a0a + languageName: node + linkType: hard + "elliptic@npm:^6.4.0, elliptic@npm:^6.5.3, elliptic@npm:^6.5.4": version: 6.5.4 resolution: "elliptic@npm:6.5.4" @@ -24022,6 +26479,13 @@ __metadata: languageName: node linkType: hard +"esbuild-plugin-alias@npm:^0.2.1": + version: 0.2.1 + resolution: "esbuild-plugin-alias@npm:0.2.1" + checksum: afe2d2c8b5f09d5321cb8d9c0825e8a9f6e03c2d50df92f953a291d4620cc29eddb3da9e33b238f6d8f77738e0277bdcb831f127399449fecf78fb84c04e5da9 + languageName: node + linkType: hard + "esbuild-plugin-svgr@npm:^2.0.0": version: 2.0.0 resolution: "esbuild-plugin-svgr@npm:2.0.0" @@ -24042,6 +26506,17 @@ __metadata: languageName: node linkType: hard +"esbuild-register@npm:^3.5.0": + version: 3.5.0 + resolution: "esbuild-register@npm:3.5.0" + dependencies: + debug: ^4.3.4 + peerDependencies: + esbuild: ">=0.12 <1" + checksum: f4307753c9672a2c901d04a1165031594a854f0a4c6f4c1db08aa393b68a193d38f2df483dc8ca0513e89f7b8998415e7e26fb9830989fb8cdccc5fb5f181c6b + languageName: node + linkType: hard + "esbuild-scss-modules-plugin@npm:^1.1.1": version: 1.1.1 resolution: "esbuild-scss-modules-plugin@npm:1.1.1" @@ -24363,6 +26838,83 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.18.0": + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" + dependencies: + "@esbuild/android-arm": 0.18.20 + "@esbuild/android-arm64": 0.18.20 + "@esbuild/android-x64": 0.18.20 + "@esbuild/darwin-arm64": 0.18.20 + "@esbuild/darwin-x64": 0.18.20 + "@esbuild/freebsd-arm64": 0.18.20 + "@esbuild/freebsd-x64": 0.18.20 + "@esbuild/linux-arm": 0.18.20 + "@esbuild/linux-arm64": 0.18.20 + "@esbuild/linux-ia32": 0.18.20 + "@esbuild/linux-loong64": 0.18.20 + "@esbuild/linux-mips64el": 0.18.20 + "@esbuild/linux-ppc64": 0.18.20 + "@esbuild/linux-riscv64": 0.18.20 + "@esbuild/linux-s390x": 0.18.20 + "@esbuild/linux-x64": 0.18.20 + "@esbuild/netbsd-x64": 0.18.20 + "@esbuild/openbsd-x64": 0.18.20 + "@esbuild/sunos-x64": 0.18.20 + "@esbuild/win32-arm64": 0.18.20 + "@esbuild/win32-ia32": 0.18.20 + "@esbuild/win32-x64": 0.18.20 + dependenciesMeta: + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b + languageName: node + linkType: hard + "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -25707,6 +28259,20 @@ __metadata: languageName: node linkType: hard +"extract-zip@npm:^1.6.6": + version: 1.7.0 + resolution: "extract-zip@npm:1.7.0" + dependencies: + concat-stream: ^1.6.2 + debug: ^2.6.9 + mkdirp: ^0.5.4 + yauzl: ^2.10.0 + bin: + extract-zip: cli.js + checksum: 011bab660d738614555773d381a6ba4815d98c1cfcdcdf027e154ebcc9fc8c9ef637b3ea5c9b2144013100071ee41722ed041fc9aacc60f6198ef747cac0c073 + languageName: node + linkType: hard + "extsprintf@npm:1.3.0": version: 1.3.0 resolution: "extsprintf@npm:1.3.0" @@ -25985,6 +28551,16 @@ __metadata: languageName: node linkType: hard +"file-system-cache@npm:2.3.0": + version: 2.3.0 + resolution: "file-system-cache@npm:2.3.0" + dependencies: + fs-extra: 11.1.1 + ramda: 0.29.0 + checksum: 74afa2870a062500643d41e02d1fbd47a3f30100f9e153dec5233d59f05545f4c8ada6085629d624e043479ac28c0cafc31824f7b49a3f997efab8cc5d05bfee + languageName: node + linkType: hard + "file-system-cache@npm:^1.0.5": version: 1.0.5 resolution: "file-system-cache@npm:1.0.5" @@ -26091,7 +28667,7 @@ __metadata: languageName: node linkType: hard -"find-cache-dir@npm:^3.2.0": +"find-cache-dir@npm:^3.0.0, find-cache-dir@npm:^3.2.0": version: 3.3.2 resolution: "find-cache-dir@npm:3.3.2" dependencies: @@ -26236,6 +28812,13 @@ __metadata: languageName: node linkType: hard +"flow-parser@npm:0.*": + version: 0.216.1 + resolution: "flow-parser@npm:0.216.1" + checksum: c3966f376b20763c842f84aa93f0d7a6014682823adc283715b3025263a5a0ab0acc0d4a9582ec512051936ce5a68c6c2d19cfb5e95356b992200daeeda1a72e + languageName: node + linkType: hard + "flush-write-stream@npm:^1.0.0": version: 1.1.1 resolution: "flush-write-stream@npm:1.1.1" @@ -26480,6 +29063,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:11.1.1, fs-extra@npm:^11.1.0": + version: 11.1.1 + resolution: "fs-extra@npm:11.1.1" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + languageName: node + linkType: hard + "fs-extra@npm:^0.30.0": version: 0.30.0 resolution: "fs-extra@npm:0.30.0" @@ -26504,17 +29098,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.1.0": - version: 11.1.1 - resolution: "fs-extra@npm:11.1.1" - dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd - languageName: node - linkType: hard - "fs-extra@npm:^8.1.0": version: 8.1.0 resolution: "fs-extra@npm:8.1.0" @@ -26837,6 +29420,13 @@ __metadata: languageName: node linkType: hard +"get-npm-tarball-url@npm:^2.0.3": + version: 2.0.3 + resolution: "get-npm-tarball-url@npm:2.0.3" + checksum: 8ad48a6f1126697665e12ebf053e0d1c3b15b3c4f29ea6c458387ac68d044ea1c08f0f2eb5c0fe35447fdd2da4f2fb5c9882feb5a2ea195c773f94e762c9b886 + languageName: node + linkType: hard + "get-own-enumerable-property-symbols@npm:^3.0.0": version: 3.0.2 resolution: "get-own-enumerable-property-symbols@npm:3.0.2" @@ -26874,6 +29464,13 @@ __metadata: languageName: node linkType: hard +"get-port@npm:^5.1.1": + version: 5.1.1 + resolution: "get-port@npm:5.1.1" + checksum: 0162663ffe5c09e748cd79d97b74cd70e5a5c84b760a475ce5767b357fb2a57cb821cee412d646aa8a156ed39b78aab88974eddaa9e5ee926173c036c0713787 + languageName: node + linkType: hard + "get-port@npm:^6.1.2": version: 6.1.2 resolution: "get-port@npm:6.1.2" @@ -26988,6 +29585,23 @@ __metadata: languageName: node linkType: hard +"giget@npm:^1.0.0": + version: 1.1.2 + resolution: "giget@npm:1.1.2" + dependencies: + colorette: ^2.0.19 + defu: ^6.1.2 + https-proxy-agent: ^5.0.1 + mri: ^1.2.0 + node-fetch-native: ^1.0.2 + pathe: ^1.1.0 + tar: ^6.1.13 + bin: + giget: dist/cli.mjs + checksum: 76ad0f7e792ee95dd6c4e1096697fdcce61a2a3235a6c21761fc3e0d1053342074ce71c80059d6d4363fd34152e5d7b2e58221412f300c852ff7d4a12d0321fe + languageName: node + linkType: hard + "git-hooks-list@npm:^3.0.0": version: 3.1.0 resolution: "git-hooks-list@npm:3.1.0" @@ -27136,6 +29750,21 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.0.0": + version: 10.3.5 + resolution: "glob@npm:10.3.5" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^2.0.3 + minimatch: ^9.0.1 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + path-scurry: ^1.10.1 + bin: + glob: dist/cjs/src/bin.js + checksum: 564f4799cae48c0bcc841c88a20b539b5701c27ed5596f8623f588b3c523262d3fc20eb1ea89cab9c75b0912faf40ca5501fc835f982225d0d0599282b09e97a + languageName: node + linkType: hard + "glob@npm:^10.2.2": version: 10.3.3 resolution: "glob@npm:10.3.3" @@ -27558,6 +30187,22 @@ __metadata: languageName: node linkType: hard +"gunzip-maybe@npm:^1.4.2": + version: 1.4.2 + resolution: "gunzip-maybe@npm:1.4.2" + dependencies: + browserify-zlib: ^0.1.4 + is-deflate: ^1.0.0 + is-gzip: ^1.0.0 + peek-stream: ^1.1.0 + pumpify: ^1.3.3 + through2: ^2.0.3 + bin: + gunzip-maybe: bin.js + checksum: bc4d4977c24a2860238df271de75d53dd72a359d19f1248d1c613807dc221d3b8ae09624e3085c8106663e3e1b59db62a85b261d1138c2cc24efad9df577d4e1 + languageName: node + linkType: hard + "handle-thing@npm:^2.0.0": version: 2.0.1 resolution: "handle-thing@npm:2.0.1" @@ -28479,7 +31124,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:5.0.1": +"https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.1": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" dependencies: @@ -28489,6 +31134,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^4.0.0": + version: 4.0.0 + resolution: "https-proxy-agent@npm:4.0.0" + dependencies: + agent-base: 5 + debug: 4 + checksum: 19471d5aae3e747b1c98b17556647e2a1362e68220c6b19585a8527498f32e62e03c41d2872d059d8720d56846bd7460a80ac06f876bccfa786468ff40dd5eef + languageName: node + linkType: hard + "https-proxy-agent@npm:^5.0.0": version: 5.0.0 resolution: "https-proxy-agent@npm:5.0.0" @@ -28711,7 +31366,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.0.0, import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -29279,6 +31934,13 @@ __metadata: languageName: node linkType: hard +"is-deflate@npm:^1.0.0": + version: 1.0.0 + resolution: "is-deflate@npm:1.0.0" + checksum: c2f9f2d3db79ac50c5586697d1e69a55282a2b0cc5e437b3c470dd47f24e40b6216dcd7e024511e21381607bf57afa019343e3bd0e08a119032818b596004262 + languageName: node + linkType: hard + "is-descriptor@npm:^0.1.0": version: 0.1.6 resolution: "is-descriptor@npm:0.1.6" @@ -29423,6 +32085,13 @@ __metadata: languageName: node linkType: hard +"is-gzip@npm:^1.0.0": + version: 1.0.0 + resolution: "is-gzip@npm:1.0.0" + checksum: 0d28931c1f445fa29c900cf9f48e06e9d1d477a3bf7bd7332e7ce68f1333ccd8cb381de2f0f62a9a262d9c0912608a9a71b4a40e788e201b3dbd67072bb20d86 + languageName: node + linkType: hard + "is-hexadecimal@npm:^1.0.0": version: 1.0.4 resolution: "is-hexadecimal@npm:1.0.4" @@ -31068,6 +33737,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:^1.18.2": + version: 1.20.0 + resolution: "jiti@npm:1.20.0" + bin: + jiti: bin/jiti.js + checksum: 7924062b5675142e3e272a27735be84b7bfc0a0eb73217fc2dcafa034f37c4f7b4b9ffc07dd98bcff0f739a8811ce1544db205ae7e97b1c86f0df92c65ce3c72 + languageName: node + linkType: hard + "joi@npm:^17.3.0": version: 17.9.1 resolution: "joi@npm:17.9.1" @@ -31180,6 +33858,37 @@ __metadata: languageName: node linkType: hard +"jscodeshift@npm:^0.14.0": + version: 0.14.0 + resolution: "jscodeshift@npm:0.14.0" + dependencies: + "@babel/core": ^7.13.16 + "@babel/parser": ^7.13.16 + "@babel/plugin-proposal-class-properties": ^7.13.0 + "@babel/plugin-proposal-nullish-coalescing-operator": ^7.13.8 + "@babel/plugin-proposal-optional-chaining": ^7.13.12 + "@babel/plugin-transform-modules-commonjs": ^7.13.8 + "@babel/preset-flow": ^7.13.13 + "@babel/preset-typescript": ^7.13.0 + "@babel/register": ^7.13.16 + babel-core: ^7.0.0-bridge.0 + chalk: ^4.1.2 + flow-parser: 0.* + graceful-fs: ^4.2.4 + micromatch: ^4.0.4 + neo-async: ^2.5.0 + node-dir: ^0.1.17 + recast: ^0.21.0 + temp: ^0.8.4 + write-file-atomic: ^2.3.0 + peerDependencies: + "@babel/preset-env": ^7.1.6 + bin: + jscodeshift: bin/jscodeshift.js + checksum: 54ea6d639455883336f80b38a70648821c88b7942315dc0fbab01bc34a9ad0f0f78e3bd69304b5ab167e4262d6ed7e6284c6d32525ab01c89d9118df89b3e2a0 + languageName: node + linkType: hard + "jsdom@npm:^19.0.0": version: 19.0.0 resolution: "jsdom@npm:19.0.0" @@ -31825,6 +34534,16 @@ __metadata: languageName: node linkType: hard +"less-loader@npm:^11.1.0": + version: 11.1.3 + resolution: "less-loader@npm:11.1.3" + peerDependencies: + less: ^3.5.0 || ^4.0.0 + webpack: ^5.0.0 + checksum: fe0de6b5ab930a4521d04555d9bd77723164bfa0f71eb5724d91c45090af544000e2d7f598cd83ec4e1445e6b943cc0c0dd1445fb2e83fd7c12f4ad3a0db05c5 + languageName: node + linkType: hard + "level-codec@npm:9.0.2, level-codec@npm:^9.0.0": version: 9.0.2 resolution: "level-codec@npm:9.0.2" @@ -34238,7 +36957,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.18, mime-types@npm:^2.1.30, mime-types@npm:^2.1.31, mime-types@npm:~2.1.19, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.18, mime-types@npm:^2.1.25, mime-types@npm:^2.1.30, mime-types@npm:^2.1.31, mime-types@npm:~2.1.19, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -34256,6 +36975,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:^2.0.3": + version: 2.6.0 + resolution: "mime@npm:2.6.0" + bin: + mime: cli.js + checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862 + languageName: node + linkType: hard + "mime@npm:^2.4.4": version: 2.5.2 resolution: "mime@npm:2.5.2" @@ -34599,7 +37327,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:>=0.5 0, mkdirp@npm:^0.5.6": +"mkdirp@npm:>=0.5 0, mkdirp@npm:^0.5.4, mkdirp@npm:^0.5.6": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -34714,7 +37442,7 @@ __metadata: languageName: node linkType: hard -"mri@npm:^1.1.0": +"mri@npm:^1.1.0, mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" checksum: 83f515abbcff60150873e424894a2f65d68037e5a7fcde8a9e2b285ee9c13ac581b63cfc1e6826c4732de3aeb84902f7c1e16b7aff46cd3f897a0f757a894e85 @@ -34956,7 +37684,7 @@ __metadata: languageName: node linkType: hard -"node-dir@npm:^0.1.10": +"node-dir@npm:^0.1.10, node-dir@npm:^0.1.17": version: 0.1.17 resolution: "node-dir@npm:0.1.17" dependencies: @@ -34965,6 +37693,13 @@ __metadata: languageName: node linkType: hard +"node-fetch-native@npm:^1.0.2": + version: 1.4.0 + resolution: "node-fetch-native@npm:1.4.0" + checksum: 92d25d3d480709bf110642876f0d12222641795d266a7730a10a5f117a6d4071ca6e205fba4e76347a29786c7bcce94956a5f2b212607064e81950b35f1af0ae + languageName: node + linkType: hard + "node-fetch@npm:^2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" @@ -35158,6 +37893,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.13": + version: 2.0.13 + resolution: "node-releases@npm:2.0.13" + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + languageName: node + linkType: hard + "node-releases@npm:^2.0.6": version: 2.0.6 resolution: "node-releases@npm:2.0.6" @@ -35920,6 +38662,17 @@ __metadata: languageName: node linkType: hard +"open@npm:^8.0.4": + version: 8.4.2 + resolution: "open@npm:8.4.2" + dependencies: + define-lazy-prop: ^2.0.0 + is-docker: ^2.1.1 + is-wsl: ^2.2.0 + checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 + languageName: node + linkType: hard + "open@npm:^8.0.9, open@npm:^8.4.0": version: 8.4.0 resolution: "open@npm:8.4.0" @@ -36357,6 +39110,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:~0.2.0": + version: 0.2.9 + resolution: "pako@npm:0.2.9" + checksum: 055f9487cd57fbb78df84315873bbdd089ba286f3499daed47d2effdc6253e981f5db6898c23486de76d4a781559f890d643bd3a49f70f1b4a18019c98aa5125 + languageName: node + linkType: hard + "pako@npm:~1.0.5": version: 1.0.11 resolution: "pako@npm:1.0.11" @@ -36717,6 +39477,17 @@ __metadata: languageName: node linkType: hard +"peek-stream@npm:^1.1.0": + version: 1.1.3 + resolution: "peek-stream@npm:1.1.3" + dependencies: + buffer-from: ^1.0.0 + duplexify: ^3.5.0 + through2: ^2.0.3 + checksum: a0e09d6d1a8a01158a3334f20d6b1cdd91747eba24eb06a1d742eefb620385593121a76d4378cc81f77cdce6a66df0575a41041b1189c510254aec91878afc99 + languageName: node + linkType: hard + "pend@npm:~1.2.0": version: 1.2.0 resolution: "pend@npm:1.2.0" @@ -37137,6 +39908,20 @@ __metadata: languageName: node linkType: hard +"postcss-loader@npm:^7.2.4": + version: 7.3.3 + resolution: "postcss-loader@npm:7.3.3" + dependencies: + cosmiconfig: ^8.2.0 + jiti: ^1.18.2 + semver: ^7.3.8 + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + checksum: c724044d6ae56334535c26bb4efc9c151431d44d60bc8300157c760747281a242757d8dab32db72738434531175b38a408cb0b270bb96207c07584dcfcd899ff + languageName: node + linkType: hard + "postcss-media-query-parser@npm:^0.2.3": version: 0.2.3 resolution: "postcss-media-query-parser@npm:0.2.3" @@ -37266,6 +40051,19 @@ __metadata: languageName: node linkType: hard +"postcss-modules-local-by-default@npm:^4.0.3": + version: 4.0.3 + resolution: "postcss-modules-local-by-default@npm:4.0.3" + dependencies: + icss-utils: ^5.0.0 + postcss-selector-parser: ^6.0.2 + postcss-value-parser: ^4.1.0 + peerDependencies: + postcss: ^8.1.0 + checksum: 2f8083687f3d6067885f8863dd32dbbb4f779cfcc7e52c17abede9311d84faf6d3ed8760e7c54c6380281732ae1f78e5e56a28baf3c271b33f450a11c9e30485 + languageName: node + linkType: hard + "postcss-modules-scope@npm:^2.2.0": version: 2.2.0 resolution: "postcss-modules-scope@npm:2.2.0" @@ -37615,6 +40413,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.2.14": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" + dependencies: + nanoid: ^3.3.6 + picocolors: ^1.0.0 + source-map-js: ^1.0.2 + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea + languageName: node + linkType: hard + "postcss@npm:^8.3.5": version: 8.4.20 resolution: "postcss@npm:8.4.20" @@ -37766,6 +40575,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^2.8.0": + version: 2.8.8 + resolution: "prettier@npm:2.8.8" + bin: + prettier: bin-prettier.js + checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 + languageName: node + linkType: hard + "pretty-error@npm:^2.1.1": version: 2.1.2 resolution: "pretty-error@npm:2.1.2" @@ -37945,7 +40763,7 @@ __metadata: languageName: node linkType: hard -"progress@npm:2.0.3, progress@npm:^2.0.0, progress@npm:^2.0.3": +"progress@npm:2.0.3, progress@npm:^2.0.0, progress@npm:^2.0.1, progress@npm:^2.0.3": version: 2.0.3 resolution: "progress@npm:2.0.3" checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 @@ -38158,7 +40976,7 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:1.1.0, proxy-from-env@npm:^1.1.0": +"proxy-from-env@npm:1.1.0, proxy-from-env@npm:^1.0.0, proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 @@ -38287,6 +41105,24 @@ __metadata: languageName: node linkType: hard +"puppeteer-core@npm:^2.1.1": + version: 2.1.1 + resolution: "puppeteer-core@npm:2.1.1" + dependencies: + "@types/mime-types": ^2.1.0 + debug: ^4.1.0 + extract-zip: ^1.6.6 + https-proxy-agent: ^4.0.0 + mime: ^2.0.3 + mime-types: ^2.1.25 + progress: ^2.0.1 + proxy-from-env: ^1.0.0 + rimraf: ^2.6.1 + ws: ^6.1.0 + checksum: 2ddb597ef1b2d162b4aa49833b977734129edf7c8fa558fc38c59d273e79aa1bd079481c642de87f7163665f7f37aa52683da2716bafb7d3cab68c262c36ec28 + languageName: node + linkType: hard + "puppeteer-core@npm:^20.9.0": version: 20.9.0 resolution: "puppeteer-core@npm:20.9.0" @@ -38469,6 +41305,13 @@ __metadata: languageName: node linkType: hard +"ramda@npm:0.29.0": + version: 0.29.0 + resolution: "ramda@npm:0.29.0" + checksum: 9ab26c06eb7545cbb7eebcf75526d6ee2fcaae19e338f165b2bf32772121e7b28192d6664d1ba222ff76188ba26ab307342d66e805dbb02c860560adc4d5dd57 + languageName: node + linkType: hard + "ramda@npm:^0.21.0": version: 0.21.0 resolution: "ramda@npm:0.21.0" @@ -40280,6 +43123,18 @@ __metadata: languageName: node linkType: hard +"recast@npm:^0.21.0": + version: 0.21.5 + resolution: "recast@npm:0.21.5" + dependencies: + ast-types: 0.15.2 + esprima: ~4.0.0 + source-map: ~0.6.1 + tslib: ^2.0.1 + checksum: 03cc7f57562238ba258d468be67bf7446ce7a707bc87a087891dad15afead46c36e9aaeedf2130e2ab5a465244a9c62bfd4127849761cf8f4085abe2f3e5f485 + languageName: node + linkType: hard + "recast@npm:^0.23.1": version: 0.23.1 resolution: "recast@npm:0.23.1" @@ -40503,6 +43358,15 @@ __metadata: languageName: node linkType: hard +"regenerator-transform@npm:^0.15.2": + version: 0.15.2 + resolution: "regenerator-transform@npm:0.15.2" + dependencies: + "@babel/runtime": ^7.8.4 + checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 + languageName: node + linkType: hard + "regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": version: 1.0.2 resolution: "regex-not@npm:1.0.2" @@ -40513,6 +43377,13 @@ __metadata: languageName: node linkType: hard +"regex-parser@npm:^2.2.11": + version: 2.2.11 + resolution: "regex-parser@npm:2.2.11" + checksum: 78200331ec0cc372302d287a4946c38681eb5fe435453fca572cb53cac0ba579e5eb3b9e25eac24c0c80a555fb3ea7a637814a35da1e9bc88e8819110ae5de24 + languageName: node + linkType: hard + "regexp-match-indices@npm:1.0.2": version: 1.0.2 resolution: "regexp-match-indices@npm:1.0.2" @@ -40605,6 +43476,20 @@ __metadata: languageName: node linkType: hard +"regexpu-core@npm:^5.3.1": + version: 5.3.2 + resolution: "regexpu-core@npm:5.3.2" + dependencies: + "@babel/regjsgen": ^0.8.0 + regenerate: ^1.4.2 + regenerate-unicode-properties: ^10.1.0 + regjsparser: ^0.9.1 + unicode-match-property-ecmascript: ^2.0.0 + unicode-match-property-value-ecmascript: ^2.1.0 + checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 + languageName: node + linkType: hard + "registry-auth-token@npm:^4.0.0": version: 4.2.2 resolution: "registry-auth-token@npm:4.2.2" @@ -41016,6 +43901,19 @@ __metadata: languageName: node linkType: hard +"resolve-url-loader@npm:^5.0.0": + version: 5.0.0 + resolution: "resolve-url-loader@npm:5.0.0" + dependencies: + adjust-sourcemap-loader: ^4.0.0 + convert-source-map: ^1.7.0 + loader-utils: ^2.0.0 + postcss: ^8.2.14 + source-map: 0.6.1 + checksum: 6d483733a4c26f75ce930a61943113bf730b5ba33a7186791cf1ae9c2ca02c3e94610bc6484ca008a372ee9e31750eccea74856a89daf1a29b8437ff564d27f2 + languageName: node + linkType: hard + "resolve-url@npm:^0.2.1": version: 0.2.1 resolution: "resolve-url@npm:0.2.1" @@ -41159,7 +44057,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:2, rimraf@npm:^2.2.8, rimraf@npm:^2.5.4, rimraf@npm:^2.6.2, rimraf@npm:^2.6.3": +"rimraf@npm:2, rimraf@npm:^2.2.8, rimraf@npm:^2.5.4, rimraf@npm:^2.6.1, rimraf@npm:^2.6.2, rimraf@npm:^2.6.3": version: 2.7.1 resolution: "rimraf@npm:2.7.1" dependencies: @@ -41181,6 +44079,17 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:~2.6.2": + version: 2.6.3 + resolution: "rimraf@npm:2.6.3" + dependencies: + glob: ^7.1.3 + bin: + rimraf: ./bin.js + checksum: 3ea587b981a19016297edb96d1ffe48af7e6af69660e3b371dbfc73722a73a0b0e9be5c88089fbeeb866c389c1098e07f64929c7414290504b855f54f901ab10 + languageName: node + linkType: hard + "ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": version: 2.0.2 resolution: "ripemd160@npm:2.0.2" @@ -41663,6 +44572,30 @@ __metadata: languageName: node linkType: hard +"sass-loader@npm:^13.2.2": + version: 13.3.2 + resolution: "sass-loader@npm:13.3.2" + dependencies: + neo-async: ^2.6.2 + peerDependencies: + fibers: ">= 3.1.0" + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + sass: ^1.3.0 + sass-embedded: "*" + webpack: ^5.0.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + sass-embedded: + optional: true + checksum: 7394a8d1b818a289b9caabd979543c907b83e28ae08bc80ccb836e0ccabc4ae574c077ab2fa520ba5fb8abb2ec3e7c9822a1cbd8c58a28ff30018be9d1dc6c27 + languageName: node + linkType: hard + "sass@npm:^1.35.2": version: 1.62.1 resolution: "sass@npm:1.62.1" @@ -41676,6 +44609,19 @@ __metadata: languageName: node linkType: hard +"sass@npm:^1.68.0": + version: 1.68.0 + resolution: "sass@npm:1.68.0" + dependencies: + chokidar: ">=3.0.0 <4.0.0" + immutable: ^4.0.0 + source-map-js: ">=0.6.2 <2.0.0" + bin: + sass: sass.js + checksum: 65ccede83c96768beeb8dcaf67957b7c76b12ff1276bfd2849d7be151d46ba1400048a67717e6e5e4969bc75e87348e5530f5f272833f2e60a891c21a33d8ab0 + languageName: node + linkType: hard + "saxes@npm:^5.0.1": version: 5.0.1 resolution: "saxes@npm:5.0.1" @@ -41885,6 +44831,26 @@ __metadata: languageName: node linkType: hard +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + languageName: node + linkType: hard + +"semver@npm:^7.5.3": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + languageName: node + linkType: hard + "send@npm:0.17.1": version: 0.17.1 resolution: "send@npm:0.17.1" @@ -42261,6 +45227,15 @@ __metadata: languageName: node linkType: hard +"simple-update-notifier@npm:^2.0.0": + version: 2.0.0 + resolution: "simple-update-notifier@npm:2.0.0" + dependencies: + semver: ^7.5.3 + checksum: 9ba00d38ce6a29682f64a46213834e4eb01634c2f52c813a9a7b8873ca49cdbb703696f3290f3b27dc067de6d9418b0b84bef22c3eb074acf352529b2d6c27fd + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -42549,6 +45524,13 @@ __metadata: languageName: node linkType: hard +"source-map@npm:0.6.1, source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 + languageName: node + linkType: hard + "source-map@npm:0.8.0-beta.0": version: 0.8.0-beta.0 resolution: "source-map@npm:0.8.0-beta.0" @@ -42565,13 +45547,6 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 - languageName: node - linkType: hard - "source-map@npm:^0.7.0, source-map@npm:^0.7.4": version: 0.7.4 resolution: "source-map@npm:0.7.4" @@ -43008,6 +45983,13 @@ __metadata: languageName: node linkType: hard +"store2@npm:^2.14.2": + version: 2.14.2 + resolution: "store2@npm:2.14.2" + checksum: 6f270fc5bab99b63f45fcc7bd8b99c2714b4adf880f557ed7ffb5ed3987131251165bccde425a00928aaf044870aee79ddeef548576d093c68703ed2edec45d7 + languageName: node + linkType: hard + "storybook-addon-designs@npm:^6.3.1": version: 6.3.1 resolution: "storybook-addon-designs@npm:6.3.1" @@ -43100,6 +46082,18 @@ __metadata: languageName: node linkType: hard +"storybook@npm:^7.4.3": + version: 7.4.3 + resolution: "storybook@npm:7.4.3" + dependencies: + "@storybook/cli": 7.4.3 + bin: + sb: ./index.js + storybook: ./index.js + checksum: 91395d18f545dfa8ffe8f1e70e248f03f85e5a3cc55d07127228480379095efa23cb499265de5e751c2c853d39c1a45ad85d3a3a4d359df61c65df81afab37a0 + languageName: node + linkType: hard + "stream-browserify@npm:^2.0.1": version: 2.0.2 resolution: "stream-browserify@npm:2.0.2" @@ -43551,7 +46545,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1, strip-json-comments@npm:~3.1.1": +"strip-json-comments@npm:^3.0.1, strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1, strip-json-comments@npm:~3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 @@ -43614,6 +46608,15 @@ __metadata: languageName: node linkType: hard +"style-loader@npm:^3.3.2": + version: 3.3.3 + resolution: "style-loader@npm:3.3.3" + peerDependencies: + webpack: ^5.0.0 + checksum: f59c953f56f6a935bd6a1dfa409f1128fed2b66b48ce4a7a75b85862a7156e5e90ab163878962762f528ec4d510903d828da645e143fbffd26f055dc1c094078 + languageName: node + linkType: hard + "style-search@npm:^0.1.0": version: 0.1.0 resolution: "style-search@npm:0.1.0" @@ -44020,7 +47023,7 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:2.1.1, tar-fs@npm:^2.0.0": +"tar-fs@npm:2.1.1, tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.1": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" dependencies: @@ -44134,6 +47137,15 @@ __metadata: languageName: node linkType: hard +"telejson@npm:^7.2.0": + version: 7.2.0 + resolution: "telejson@npm:7.2.0" + dependencies: + memoizerific: ^1.11.3 + checksum: 55a3380c9ff3c5ad84581bb6bda28fc33c6b7c4a0c466894637da687639b8db0d21b0ff4c1bc1a7a92ae6b70662549d09e7b9e8b1ec334b2ef93078762ecdfb9 + languageName: node + linkType: hard + "temp-dir@npm:^2.0.0": version: 2.0.0 resolution: "temp-dir@npm:2.0.0" @@ -44141,6 +47153,15 @@ __metadata: languageName: node linkType: hard +"temp@npm:^0.8.4": + version: 0.8.4 + resolution: "temp@npm:0.8.4" + dependencies: + rimraf: ~2.6.2 + checksum: f35bed78565355dfdf95f730b7b489728bd6b7e35071bcc6497af7c827fb6c111fbe9063afc7b8cbc19522a072c278679f9a0ee81e684aa2c8617cc0f2e9c191 + languageName: node + linkType: hard + "tempy@npm:^1.0.1": version: 1.0.1 resolution: "tempy@npm:1.0.1" @@ -44357,7 +47378,7 @@ __metadata: languageName: node linkType: hard -"through2@npm:^2.0.0": +"through2@npm:^2.0.0, through2@npm:^2.0.3": version: 2.0.5 resolution: "through2@npm:2.0.5" dependencies: @@ -44953,7 +47974,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": +"tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd @@ -45884,6 +48905,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.0.11": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.0.9": version: 1.0.10 resolution: "update-browserslist-db@npm:1.0.10" @@ -46038,6 +49073,18 @@ __metadata: languageName: node linkType: hard +"use-resize-observer@npm:^9.1.0": + version: 9.1.0 + resolution: "use-resize-observer@npm:9.1.0" + dependencies: + "@juggle/resize-observer": ^3.3.1 + peerDependencies: + react: 16.8.0 - 18 + react-dom: 16.8.0 - 18 + checksum: 92be0ac34a3b3cf884cd55847c90792b5b44833dc258e96d650152815ad246afe45825aa223332203004d836535a927ab74f18dc0313229e2c7c69510eddf382 + languageName: node + linkType: hard + "use-sidecar@npm:^1.1.2": version: 1.1.2 resolution: "use-sidecar@npm:1.1.2" @@ -46119,7 +49166,7 @@ __metadata: languageName: node linkType: hard -"util@npm:^0.12.0, util@npm:^0.12.3": +"util@npm:^0.12.0, util@npm:^0.12.3, util@npm:^0.12.4": version: 0.12.5 resolution: "util@npm:0.12.5" dependencies: @@ -47995,6 +51042,17 @@ __metadata: languageName: node linkType: hard +"write-file-atomic@npm:^2.3.0": + version: 2.4.3 + resolution: "write-file-atomic@npm:2.4.3" + dependencies: + graceful-fs: ^4.1.11 + imurmurhash: ^0.1.4 + signal-exit: ^3.0.2 + checksum: 2db81f92ae974fd87ab4a5e7932feacaca626679a7c98fcc73ad8fcea5a1950eab32fa831f79e9391ac99b562ca091ad49be37a79045bd65f595efbb8f4596ae + languageName: node + linkType: hard + "write-file-atomic@npm:^3.0.0": version: 3.0.3 resolution: "write-file-atomic@npm:3.0.3" @@ -48076,6 +51134,15 @@ __metadata: languageName: node linkType: hard +"ws@npm:^6.1.0": + version: 6.2.2 + resolution: "ws@npm:6.2.2" + dependencies: + async-limiter: ~1.0.0 + checksum: aec3154ec51477c094ac2cb5946a156e17561a581fa27005cbf22c53ac57f8d4e5f791dd4bbba6a488602cb28778c8ab7df06251d590507c3c550fd8ebeee949 + languageName: node + linkType: hard + "ws@npm:^7.4.6": version: 7.5.3 resolution: "ws@npm:7.5.3"