diff --git a/e2e/api-specs/run-api-spec-tests.js b/e2e/api-specs/run-api-spec-tests.js index 203c113c43d6..45843daf9389 100644 --- a/e2e/api-specs/run-api-spec-tests.js +++ b/e2e/api-specs/run-api-spec-tests.js @@ -1,3 +1,4 @@ /* eslint-disable import/no-commonjs */ require('@babel/register'); +require('ts-node/register'); require('./json-rpc-coverage.js'); diff --git a/e2e/fixtures/fixture-helper.js b/e2e/fixtures/fixture-helper.js index 0af5623711ea..b267ca6b188c 100644 --- a/e2e/fixtures/fixture-helper.js +++ b/e2e/fixtures/fixture-helper.js @@ -1,14 +1,20 @@ /* eslint-disable no-console, import/no-nodejs-modules */ import FixtureServer, { DEFAULT_FIXTURE_SERVER_PORT } from './fixture-server'; import FixtureBuilder from './fixture-builder'; +import { AnvilManager, defaultOptions } from '../seeder/anvil-manager'; import Ganache from '../../app/util/test/ganache'; + import GanacheSeeder from '../../app/util/test/ganache-seeder'; import axios from 'axios'; import path from 'path'; import createStaticServer from '../create-static-server'; -import { DEFAULT_MOCKSERVER_PORT, getFixturesServerPort, getLocalTestDappPort, getMockServerPort } from './utils'; +import { + DEFAULT_MOCKSERVER_PORT, + getFixturesServerPort, + getLocalTestDappPort, + getMockServerPort, +} from './utils'; import Utilities from '../utils/Utilities'; -import { device } from 'detox'; import TestHelpers from '../helpers'; import { startMockServer, stopMockServer } from '../api-mocking/mock-server'; @@ -31,6 +37,84 @@ const isFixtureServerStarted = async () => { } }; +// SRP corresponding to the vault set in the default fixtures - it's an empty test account, not secret +export const defaultGanacheOptions = { + hardfork: 'london', + mnemonic: + 'drive manage close raven tape average sausage pledge riot furnace august tip', +}; + +/** + * + * Normalizes the localNodeOptions into a consistent format to handle different data structures. + * Case 1: A string: localNodeOptions = 'anvil' + * Case 2: Array of strings: localNodeOptions = ['anvil', 'bitcoin'] + * Case 3: Array of objects: localNodeOptions = + * [ + * { type: 'anvil', options: {anvilOpts}}, + * { type: 'bitcoin',options: {bitcoinOpts}}, + * ] + * Case 4: Options object without type: localNodeOptions = {options} + * + * @param {string | object | Array} localNodeOptions - The input local node options. + * @returns {Array} The normalized local node options. + */ +function normalizeLocalNodeOptions(localNodeOptions) { + if (typeof localNodeOptions === 'string') { + // Case 1: Passing a string + return [ + { + type: localNodeOptions, + options: + localNodeOptions === 'ganache' + ? defaultGanacheOptions + : localNodeOptions === 'anvil' + ? defaultOptions + : {}, + }, + ]; + } else if (Array.isArray(localNodeOptions)) { + return localNodeOptions.map((node) => { + if (typeof node === 'string') { + // Case 2: Array of strings + return { + type: node, + options: + node === 'ganache' + ? defaultGanacheOptions + : node === 'anvil' + ? defaultOptions + : {}, + }; + } + if (typeof node === 'object' && node !== null) { + // Case 3: Array of objects + const type = node.type || 'ganache'; + return { + type, + options: + type === 'ganache' + ? { ...defaultGanacheOptions, ...(node.options || {}) } + : type === 'anvil' + ? { ...defaultOptions, ...(node.options || {}) } + : node.options || {}, + }; + } + throw new Error(`Invalid localNodeOptions entry: ${node}`); + }); + } + if (typeof localNodeOptions === 'object' && localNodeOptions !== null) { + // Case 4: Passing an options object without type + return [ + { + type: 'ganache', + options: { ...defaultGanacheOptions, ...localNodeOptions }, + }, + ]; + } + throw new Error(`Invalid localNodeOptions type: ${typeof localNodeOptions}`); +} + /** * Loads a fixture into the fixture server. * @@ -99,40 +183,74 @@ export async function withFixtures(options, testSuite) { smartContract, disableGanache, dapp, + localNodeOptions = 'ganache', dappOptions, dappPath = undefined, dappPaths, testSpecificMock, - launchArgs + launchArgs, } = options; const fixtureServer = new FixtureServer(); let mockServer; let mockServerPort = DEFAULT_MOCKSERVER_PORT; + const localNodeOptsNormalized = normalizeLocalNodeOptions(localNodeOptions); if (testSpecificMock) { mockServerPort = getMockServerPort(); mockServer = await startMockServer(testSpecificMock, mockServerPort); } - let ganacheServer; - if (!disableGanache) { - ganacheServer = new Ganache(); + let localNode; + const localNodes = []; + + try { + // Start servers based on the localNodes array + if (!disableGanache) { + for (let i = 0; i < localNodeOptsNormalized.length; i++) { + const nodeType = localNodeOptsNormalized[i].type; + const nodeOptions = localNodeOptsNormalized[i].options || {}; + + switch (nodeType) { + case 'anvil': + localNode = new AnvilManager(); + await localNode.start(nodeOptions); + localNodes.push(localNode); + await localNode.setAccountBalance('1200'); + + break; + + case 'ganache': + localNode = new Ganache(); + await localNode.start(nodeOptions); + localNodes.push(localNode); + break; + + case 'none': + break; + + default: + throw new Error( + `Unsupported localNode: '${nodeType}'. Cannot start the server.`, + ); + } + } + } + } catch (error) { + console.error(error); + throw error; } + const dappBasePort = getLocalTestDappPort(); let numberOfDapps = dapp ? 1 : 0; const dappServer = []; try { let contractRegistry; - if (ganacheOptions && !disableGanache) { - await ganacheServer.start(ganacheOptions); - - if (smartContract) { - const ganacheSeeder = new GanacheSeeder(ganacheServer.getProvider()); - await ganacheSeeder.deploySmartContract(smartContract); - contractRegistry = ganacheSeeder.getContractRegistry(); - } + if (!disableGanache && smartContract) { + const ganacheSeeder = new GanacheSeeder(localNodes[0].getProvider()); + await ganacheSeeder.deploySmartContract(smartContract); + contractRegistry = ganacheSeeder.getContractRegistry(); } if (dapp) { @@ -171,26 +289,30 @@ export async function withFixtures(options, testSuite) { ); // Due to the fact that the app was already launched on `init.js`, it is necessary to // launch into a fresh installation of the app to apply the new fixture loaded perviously. - if (restartDevice) { - await TestHelpers.launchApp({ - delete: true, - launchArgs: { - fixtureServerPort: `${getFixturesServerPort()}`, - detoxURLBlacklistRegex: Utilities.BlacklistURLs, - mockServerPort: `${mockServerPort}`, - ...(launchArgs || {}), - }, - }); + if (restartDevice) { + await TestHelpers.launchApp({ + delete: true, + launchArgs: { + fixtureServerPort: `${getFixturesServerPort()}`, + detoxURLBlacklistRegex: Utilities.BlacklistURLs, + mockServerPort: `${mockServerPort}`, + ...(launchArgs || {}), + }, + }); } - await testSuite({ contractRegistry, mockServer }); + await testSuite({ contractRegistry, mockServer, localNodes }); // Pass localNodes instead of anvilServer } catch (error) { console.error(error); throw error; } finally { - if (ganacheOptions && !disableGanache) { - await ganacheServer.quit(); + // Clean up all local nodes + for (const server of localNodes) { + if (server) { + await server.quit(); + } } + if (dapp) { for (let i = 0; i < numberOfDapps; i++) { if (dappServer[i] && dappServer[i].listening) { @@ -213,10 +335,3 @@ export async function withFixtures(options, testSuite) { await stopFixtureServer(fixtureServer); } } - -// SRP corresponding to the vault set in the default fixtures - it's an empty test account, not secret -export const defaultGanacheOptions = { - hardfork: 'london', - mnemonic: - 'drive manage close raven tape average sausage pledge riot furnace august tip', -}; diff --git a/e2e/pages/Network/NetworkListModal.js b/e2e/pages/Network/NetworkListModal.js index caff4fc622f0..9e8f3db47ac8 100644 --- a/e2e/pages/Network/NetworkListModal.js +++ b/e2e/pages/Network/NetworkListModal.js @@ -70,6 +70,7 @@ class NetworkListModal { async changeNetworkTo(networkName, custom) { const elem = this.getCustomNetwork(networkName, custom); + await TestHelpers.delay(3000); await Gestures.waitAndTap(elem); await TestHelpers.delay(3000); } @@ -103,6 +104,7 @@ class NetworkListModal { } async tapAddNetworkButton() { + await TestHelpers.delay(3000); await Gestures.waitAndTap(this.addPopularNetworkButton); } async deleteNetwork() { diff --git a/e2e/seeder/anvil-clients.ts b/e2e/seeder/anvil-clients.ts index 12a2293be71d..70f77d17f2f3 100644 --- a/e2e/seeder/anvil-clients.ts +++ b/e2e/seeder/anvil-clients.ts @@ -5,7 +5,6 @@ import { http, } from 'viem'; import { anvil as baseAnvil } from 'viem/chains'; - /** * Creates a set of clients for interacting with an Anvil test node * @param {number} chainId - The chain ID for the network diff --git a/e2e/seeder/anvil-manager.ts b/e2e/seeder/anvil-manager.ts new file mode 100644 index 000000000000..7c9707d4d13f --- /dev/null +++ b/e2e/seeder/anvil-manager.ts @@ -0,0 +1,224 @@ +import { createAnvil, Anvil as AnvilType } from '@viem/anvil'; +import { createAnvilClients } from './anvil-clients'; + +/** + * Represents the available Ethereum hardforks for the Anvil server + * @typedef {('Frontier'|'Homestead'|'Dao'|'Tangerine'|'SpuriousDragon'|'Byzantium'|'Constantinople'|'Petersburg'|'Istanbul'|'Muirglacier'|'Berlin'|'London'|'ArrowGlacier'|'GrayGlacier'|'Paris'|'Shanghai'|'Latest')} Hardfork + */ +type Hardfork = + | 'Frontier' + | 'Homestead' + | 'Dao' + | 'Tangerine' + | 'SpuriousDragon' + | 'Byzantium' + | 'Constantinople' + | 'Petersburg' + | 'Istanbul' + | 'Muirglacier' + | 'Berlin' + | 'London' + | 'ArrowGlacier' + | 'GrayGlacier' + | 'Paris' + | 'Shanghai' + | 'Latest'; + +/** + * Represents a hexadecimal string with '0x' prefix + * @typedef {`0x${string}`} Hex + */ +type Hex = `0x${string}`; + +/** + * Default configuration options for the Anvil server + * @type {Object} + * @property {number} balance - Initial balance for each account in ETH + * @property {number} chainId - Ethereum chain ID + * @property {number} gasLimit - Maximum gas limit per block + * @property {number} gasPrice - Gas price in wei + * @property {Hardfork} hardfork - Ethereum hardfork to use + * @property {string} host - Host address to bind the server to + * @property {string} mnemonic - BIP39 mnemonic for deterministic account generation + * @property {number} port - Port number to run the server on + * @property {boolean} noMining - Whether to disable automatic mining + */ +export const defaultOptions = { + balance: 25, + chainId: 1337, + gasLimit: 30000000, + gasPrice: 2000000000, + hardfork: 'prague' as Hardfork, + host: '127.0.0.1', + mnemonic: + 'drive manage close raven tape average sausage pledge riot furnace august tip', + port: 8545, + noMining: false, +}; + +/** + * Manages an Anvil Ethereum development server instance + * @class + */ +class AnvilManager { + private server: AnvilType | undefined; + + /** + * Check if the Anvil server is running + * @returns {boolean} True if the server is running, false otherwise + */ + isRunning(): boolean { + return this.server !== undefined; + } + + /** + * Start the Anvil server with the specified options + * @param {Object} opts - Server configuration options + * @param {number} [opts.balance] - Initial balance for each account in ETH + * @param {number} [opts.blockTime] - Block time in seconds + * @param {number} [opts.chainId] - Ethereum chain ID + * @param {number} [opts.gasLimit] - Maximum gas limit per block + * @param {number} [opts.gasPrice] - Gas price in wei + * @param {Hardfork} [opts.hardfork] - Ethereum hardfork to use + * @param {string} [opts.host] - Host address to bind the server to + * @param {string} [opts.mnemonic] - BIP39 mnemonic for deterministic account generation + * @param {number} [opts.port] - Port number to run the server on + * @param {boolean} [opts.noMining] - Whether to disable automatic mining + * @throws {Error} If mnemonic is not provided + * @throws {Error} If server fails to start + */ + async start( + opts: { + balance?: number; + blockTime?: number; + chainId?: number; + gasLimit?: number; + gasPrice?: number; + hardfork?: Hardfork; + host?: string; + mnemonic?: string; + port?: number; + noMining?: boolean; + } = {}, + ): Promise { + if (!opts.mnemonic) { + throw new Error('Missing required mnemonic'); + } + + const options = { ...defaultOptions, ...opts }; + const { port } = options; + + try { + // eslint-disable-next-line no-console + console.log('Starting Anvil server...'); + + // Create and start the server instance + this.server = createAnvil({ + ...options, + }); + + await this.server.start(); + // eslint-disable-next-line no-console + console.log(`Server started on port ${port}`); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to start server:', error); + throw error; + } + } + + /** + * Get the provider clients for interacting with the Anvil server + * @returns {Object} Object containing wallet, public, and test clients + * @throws {Error} If server is not running + */ + getProvider() { + if (!this.server) { + throw new Error('Server not running yet'); + } + const { walletClient, publicClient, testClient } = createAnvilClients( + this.server.options.chainId ?? 1337, + this.server.options.port ?? 8545, + ); + + return { walletClient, publicClient, testClient }; + } + + /** + * Get all accounts available on the Anvil server + * @returns {Promise} Array of account addresses + */ + async getAccounts(): Promise { + // eslint-disable-next-line no-console + console.log('Getting accounts...'); + const { walletClient } = this.getProvider(); + + const accounts = await walletClient.getAddresses(); + // eslint-disable-next-line no-console + console.log(`Found ${accounts.length} accounts`); + return accounts; + } + + /** + * Get chain details including logs from the Anvil server + * @returns {Promise} Chain logs + */ + async getChainDetails() { + const { publicClient } = this.getProvider(); + const logs = await publicClient.getLogs(); + + return logs; + } + + /** + * Set the balance for a specific account or the first account if none specified + * @param {string} balance - Balance to set in ETH + * @param {Hex} [address] - Optional address to set balance for + * @throws {Error} If server is not running + */ + async setAccountBalance(balance: string, address?: Hex): Promise { + const { testClient } = this.getProvider(); + const accounts = await this.getAccounts(); + + // Determining which address to use: if address is provided and not empty, use it + // Otherwise, use the first account from getAccounts() + let accountAddress: Hex; + if (address !== undefined) { + accountAddress = address; + } else { + accountAddress = accounts[0] as Hex; + } + + const weiMultiplier = BigInt('1000000000000000000'); // 10^18 + const balanceInWei = BigInt(balance) * weiMultiplier; + await testClient.setBalance({ + address: accountAddress, + value: balanceInWei, + }); + // eslint-disable-next-line no-console + console.log(`Balance set for ${accountAddress}`); + } + + /** + * Stop the Anvil server + * @throws {Error} If server is not running + * @throws {Error} If server fails to stop + */ + async quit(): Promise { + if (!this.server) { + throw new Error('Server not running yet'); + } + try { + // eslint-disable-next-line no-console + console.log('Stopping server...'); + await this.server.stop(); + // eslint-disable-next-line no-console + console.log('Server stopped'); + } catch (e) { + // eslint-disable-next-line no-console + console.log(`Error stopping server: ${e}`); + throw e; + } + } +} +export { AnvilManager }; diff --git a/e2e/seeder/test-launching-clients.ts b/e2e/seeder/test-launching-clients.ts index 39e65f1567ba..21cde5066f43 100644 --- a/e2e/seeder/test-launching-clients.ts +++ b/e2e/seeder/test-launching-clients.ts @@ -1,18 +1,21 @@ -import {createAnvilClients} from './anvil-clients'; -import { createAnvil } from '@viem/anvil'; +import { AnvilManager,defaultOptions } from './anvil-manager'; -async function main(){ - const server = createAnvil(); - await server.start(); +type Hex = `0x${string}`; - const {walletClient} = createAnvilClients(1337, 8545); +async function main(): Promise { + const server = new AnvilManager(); + await server.start(defaultOptions); - const accounts = await walletClient.getAddresses(); + const accounts = await server.getAccounts(); + const firstAccount = accounts[0] as Hex; + const balanceInWei = '10'; - // eslint-disable-next-line no-console - console.log(accounts); + await server.setAccountBalance(balanceInWei,firstAccount); - await server.stop(); + // eslint-disable-next-line no-console + console.log(accounts); + + await server.quit(); } main(); diff --git a/e2e/specs/assets/nft-details.spec.js b/e2e/specs/assets/nft-details.spec.js index d51cd6f7b4c4..12d212eabb55 100644 --- a/e2e/specs/assets/nft-details.spec.js +++ b/e2e/specs/assets/nft-details.spec.js @@ -32,7 +32,6 @@ describe(SmokeNetworkAbstractions('NFT Details page'), () => { .withPermissionControllerConnectedToTestDapp(buildPermissions(['0x539'])) .build(), restartDevice: true, - ganacheOptions: defaultGanacheOptions, smartContract: NFT_CONTRACT, }, async ({ contractRegistry }) => { diff --git a/e2e/specs/settings/example-anvil-e2e.spec.js b/e2e/specs/settings/example-anvil-e2e.spec.js new file mode 100644 index 000000000000..d7895e9ee074 --- /dev/null +++ b/e2e/specs/settings/example-anvil-e2e.spec.js @@ -0,0 +1,86 @@ +import TestHelpers from '../../helpers'; +import { loginToApp } from '../../viewHelper'; +import TabBarComponent from '../../pages/wallet/TabBarComponent'; +import Assertions from '../../utils/Assertions'; +import FixtureBuilder from '../../fixtures/fixture-builder'; +import { withFixtures } from '../../fixtures/fixture-helper'; +import QuoteView from '../../pages/swaps/QuoteView'; +import SwapView from '../../pages/swaps/SwapView'; +import WalletActionsBottomSheet from '../../pages/wallet/WalletActionsBottomSheet'; +import ActivitiesView from '../../pages/Transactions/ActivitiesView'; + +const sourceTokenSymbol = 'ETH'; +const destTokenSymbol = 'DAI'; +const quantity = '.03'; + +describe('NFT Details page', () => { + beforeAll(async () => { + await TestHelpers.reverseServerPort(); + }); + + it('show nft details', async () => { + await withFixtures( + { + fixture: new FixtureBuilder().withGanacheNetwork().build(), + restartDevice: true, + localNodeOptions: [{ type: 'anvil' }], + // ganacheOptions: defaultGanacheOptions, + }, + async () => { + // Launch app and login + await loginToApp(); + + // Navigate to NFT details + await TabBarComponent.tapWallet(); + + await TabBarComponent.tapActions(); + await WalletActionsBottomSheet.tapSwapButton(); + + await Assertions.checkIfVisible(QuoteView.getQuotes); + + await QuoteView.enterSwapAmount(quantity); + + //Select destination token + await QuoteView.tapOnSelectDestToken(); + await QuoteView.tapSearchToken(); + await QuoteView.typeSearchToken(destTokenSymbol); + await TestHelpers.delay(2000); + await QuoteView.selectToken(destTokenSymbol); + + await QuoteView.tapOnGetQuotes(); + await Assertions.checkIfVisible(SwapView.quoteSummary); + await Assertions.checkIfVisible(SwapView.gasFee); + await SwapView.tapIUnderstandPriceWarning(); + await SwapView.tapSwapButton(); + //Wait for Swap to complete + try { + await Assertions.checkIfTextIsDisplayed( + SwapView.generateSwapCompleteLabel( + sourceTokenSymbol, + destTokenSymbol, + ), + 30000, + ); + } catch (e) { + // eslint-disable-next-line no-console + console.log(`Swap complete didn't pop up: ${e}`); + } + // await device.enableSynchronization(); + await TestHelpers.delay(10000); + + // Check the swap activity completed + await TabBarComponent.tapActivity(); + await Assertions.checkIfVisible(ActivitiesView.title); + await Assertions.checkIfVisible( + ActivitiesView.swapActivityTitle(sourceTokenSymbol, destTokenSymbol), + ); + }, + ); + }); +}); + +// await WalletView.tapNftTab(); +// await WalletView.tapOnNftName(); + +// // Verify NFT details are displayed +// await Assertions.checkIfVisible(WalletView.nftTabContainer); diff --git a/package.json b/package.json index 4e55c5213a02..5922d3d5fd7c 100644 --- a/package.json +++ b/package.json @@ -67,9 +67,9 @@ "test:e2e:android:build:qa-release": "NO_FLIPPER='1' IS_TEST='true' detox build -c android.emu.release.qa", "test:e2e:android:run:qa-release": "NO_FLIPPER='1' IS_TEST='true' detox test -c android.emu.release.qa --headless --record-logs all", "test:e2e:ios:debug:build": "IS_TEST='true' detox build -c ios.sim.debug", - "test:e2e:ios:debug:run": "IS_TEST='true' detox reset-lock-file && detox test -c ios.sim.debug", + "test:e2e:ios:debug:run": "IS_TEST='true' NODE_OPTIONS='--experimental-vm-modules' detox reset-lock-file && NODE_OPTIONS='--experimental-vm-modules' detox test -c ios.sim.debug", "test:e2e:android:debug:build": "IS_TEST='true' detox build -c android.emu.debug", - "test:e2e:android:debug:run": "IS_TEST='true' detox test -c android.emu.debug", + "test:e2e:android:debug:run": "IS_TEST='true' NODE_OPTIONS='--experimental-vm-modules' detox test -c android.emu.debug", "test:wdio:ios": "yarn wdio ./wdio/config/ios.config.debug.js", "test:wdio:ios:browserstack": "yarn wdio ./wdio/config/ios.config.browserstack.js", "test:wdio:ios:browserstack:local": "yarn wdio ./wdio/config/ios.config.browserstack.local.js", @@ -539,6 +539,7 @@ "rn-nodeify": "10.3.0", "serve-handler": "^6.1.5", "simple-git": "^3.25.0", + "ts-node": "^10.9.2", "typescript": "~5.4.5", "wdio-cucumberjs-json-reporter": "^4.4.3", "webextension-polyfill": "^0.12.0", @@ -639,7 +640,8 @@ "@storybook/addon-ondevice-controls>core-js": false, "viem>ws>bufferutil": false, "viem>ws>utf-8-validate": false, - "detox>@wix-pilot/core>canvas": true + "detox>@wix-pilot/core>canvas": true, + "ts-node>@swc/core": false } }, "packageManager": "yarn@1.22.22" diff --git a/yarn.lock b/yarn.lock index 614db2ab0d1b..6f418cebf9e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9687,11 +9687,31 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + "@tsconfig/node14@14.1.2": version "14.1.2" resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-14.1.2.tgz#ed84879e927a2f12ae8bb020baa990bd4cc3dabb" integrity sha512-1vncsbfCZ3TBLPxesRYz02Rn7SNJfbLoDVkcZ7F/ixOV6nwxwgdhD1mdPcc5YQ413qBJ8CvMxXMFfJ7oawjo7Q== +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@types/archiver@5.3.2": version "5.3.2" resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.2.tgz#a9f0bcb0f0b991400e7766d35f6e19d163bdadcc" @@ -11864,10 +11884,17 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.10.0, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.10.0, acorn@^8.11.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== adbkit-apkreader@^3.1.2: version "3.2.0" @@ -27701,6 +27728,25 @@ ts-interface-checker@^0.1.9: resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + ts-node@^9: version "9.1.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" @@ -28381,6 +28427,11 @@ uuid@^9.0.0, uuid@^9.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + v8-to-istanbul@^9.0.1: version "9.1.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265"