From 33529ebf0df7698310518b7d7e3d23632939449f Mon Sep 17 00:00:00 2001 From: Stefan Nikolov Date: Thu, 10 Aug 2023 17:48:53 +0300 Subject: [PATCH] fix(typescript): Make DiscordMonitor hang-up safe and refactor --- relay/package.json | 2 + relay/tsconfig.json | 3 +- relay/utils/discord_monitor.ts | 320 ++++++++++++++++++++------------- yarn.lock | 225 ++++++++++++++++++++++- 4 files changed, 421 insertions(+), 129 deletions(-) diff --git a/relay/package.json b/relay/package.json index 88ea5120f..e26990ce4 100644 --- a/relay/package.json +++ b/relay/package.json @@ -11,6 +11,8 @@ "author": "", "license": "ISC", "dependencies": { + "@effect/schema": "^0.33.0", + "discord.js": "^14.12.1", "ts-node": "^10.9.1", "web3": "^1.10.0", "yargs": "^17.7.1" diff --git a/relay/tsconfig.json b/relay/tsconfig.json index 231d9a6c9..6db4f02c3 100644 --- a/relay/tsconfig.json +++ b/relay/tsconfig.json @@ -4,6 +4,7 @@ "./hardhat.config.ts" ], "compilerOptions": { - "moduleResolution": "nodenext" + "moduleResolution": "nodenext", + "strictPropertyInitialization": false, } } diff --git a/relay/utils/discord_monitor.ts b/relay/utils/discord_monitor.ts index c8eaa2ad0..2a9fc15b0 100644 --- a/relay/utils/discord_monitor.ts +++ b/relay/utils/discord_monitor.ts @@ -1,152 +1,218 @@ import { SolidityContract } from '../implementations/solidity-contract'; import { BeaconApi } from '../implementations/beacon-api'; -import { ethers } from "ethers"; -import {sleep} from '../../libs/typescript/ts-utils/common-utils'; +import { ethers } from 'ethers'; +import { sleep } from '../../libs/typescript/ts-utils/common-utils'; +import { GatewayIntentBits, Events, Partials } from 'discord.js'; +import * as Discord from 'discord.js'; import lc_abi_json from '../../beacon-light-client/solidity/artifacts/contracts/bridge/src/truth/eth/BeaconLightClient.sol/BeaconLightClient.json'; -const env = require('dotenv').config({path: '../../.env'}).parsed; - -const { GatewayIntentBits, SlashCommandBuilder, Events,Partials } = require('discord.js'); -const Discord = require('discord.js'); +const env = process.env; interface ContractData { - RPC: string; - Address: string; - SolidityContract?: SolidityContract; + RPC: string; + Address: string; + SolidityContract?: SolidityContract; } type SolidityDictionary = { - [name: string]: ContractData; + [name: string]: ContractData; }; class DiscordMonitor { - client: any; - beaconApi: BeaconApi; - contracts: SolidityDictionary = {}; - - alert_threshold: number; - - constructor(alert_threshold: number) { - - this.alert_threshold = alert_threshold; - - this.beaconApi = new BeaconApi([ - 'http://unstable.prater.beacon-api.nimbus.team/', - ]); - - this.client = new Discord.Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.DirectMessages - ], - partials: [ - Partials.Channel, - Partials.Message, - Partials.DirectMessages, - Partials.Reaction - ] - }); - - this.client.login(env.token); - this.client.on(Events.ClientReady, async interaction => { - console.log('Client Ready!') - console.log(`Logged in as ${this.client.user.tag}!`) - }); - - // Track contracts if initialized in .env - if (env.GOERLI_RPC && env.LC_GOERLI){ - this.contracts['Goerli'] = {RPC: env.GOERLI_RPC, Address: env.LC_GOERLI}; - } - if (env.OPTIMISTIC_GOERLI_RPC && env.LC_OPTIMISTIC_GOERLI) { - this.contracts['OptimisticGoerli'] = {RPC: env.OPTIMISTIC_GOERLI_RPC, Address: env.LC_OPTIMISTIC_GOERLI}; - } - if (env.BASE_GOERLI_RPC && env.LC_BASE_GOERLI) { - this.contracts['BaseGoerli'] = {RPC: env.BASE_GOERLI_RPC, Address: env.LC_BASE_GOERLI}; - } - if (env.ARBITRUM_GOERLI_RPC && env.LC_ARBITRUM_GOERLI) { - this.contracts['ArbitrumGoerli'] = {RPC: env.ARBITRUM_GOERLI_RPC, Address: env.LC_ARBITRUM_GOERLI}; - } - if (env.SEPOLIA_RPC && env.LC_SEPOLIA) { - this.contracts['Sepolia'] = {RPC: env.SEPOLIA_RPC, Address: env.LC_SEPOLIA}; - } - if (env.MUMBAI_RPC && env.LC_MUMBAI) { - this.contracts['Mumbai'] = {RPC: env.MUMBAI_RPC, Address: env.LC_MUMBAI}; - } - if (env.FANTOM_RPC && env.LC_FANTOM) { - this.contracts['Fantom'] = {RPC: env.FANTOM_RPC, Address: env.LC_FANTOM}; - } - if (env.CHIADO_RPC && env.LC_CHIADO) { - this.contracts['Chiado'] = {RPC: env.CHIADO_RPC, Address: env.LC_CHIADO}; - } - if (env.GNOSIS_RPC && env.LC_GNOSIS) { - this.contracts['Gnosis'] = {RPC: env.GNOSIS_RPC, Address: env.LC_GNOSIS}; - } - if (env.BSC_RPC && env.LC_BSC) { - this.contracts['BSC'] = {RPC: env.BSC_RPC, Address: env.LC_BSC}; - } - if (env.AURORA_RPC && env.LC_AURORA) { - this.contracts['Aurora'] = {RPC: env.AURORA_RPC, Address: env.LC_AURORA}; - } - - // Instantiate SolidityContracts from .env - for (var endpoint in this.contracts) { - - var curLightClient = new ethers.Contract( - this.contracts[endpoint].Address, - lc_abi_json.abi, - new ethers.providers.JsonRpcProvider(this.contracts[endpoint].RPC) // Provider - ); - - var curSolidityContract = new SolidityContract( - curLightClient, - this.contracts[endpoint].RPC, - ); - this.contracts[endpoint].SolidityContract= curSolidityContract; - } + client: Discord.Client; + beaconApi: BeaconApi; + contracts: SolidityDictionary = {}; + channel: Discord.Channel; + + alert_threshold: number; + + public static async initializeDiscordMonitor( + alert_threshold: number, + ): Promise { + let discordMonitor = new DiscordMonitor(alert_threshold); + + discordMonitor.alert_threshold = alert_threshold; + + discordMonitor.beaconApi = new BeaconApi([ + 'http://unstable.prater.beacon-api.nimbus.team/', + ]); + + discordMonitor.client = new Discord.Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.DirectMessages, + ], + partials: [Partials.Channel, Partials.Message, Partials.Reaction], + }); + + const result = await discordMonitor.client.login(env.token); + + await discordMonitor.client.on(Events.ClientReady, async interaction => { + console.log('Client Ready!'); + console.log(`Logged in as ${discordMonitor.client.user?.tag}!`); + }); + + return discordMonitor; + } + + private constructor(alert_threshold: number) { + // Track contracts if initialized in .env + if (env.GOERLI_RPC && env.LC_GOERLI) { + this.contracts['Goerli'] = { + RPC: env.GOERLI_RPC, + Address: env.LC_GOERLI, + }; } - - private async getSlotDelay(contract: SolidityContract) { - return await this.beaconApi.getCurrentHeadSlot() - await contract.optimisticHeaderSlot(); + if (env.OPTIMISTIC_GOERLI_RPC && env.LC_OPTIMISTIC_GOERLI) { + this.contracts['OptimisticGoerli'] = { + RPC: env.OPTIMISTIC_GOERLI_RPC, + Address: env.LC_OPTIMISTIC_GOERLI, + }; } - - private async respondToMessage() { //TODO: Implement responsive commands - this.client.on(Events.MessageCreate, (message) => { - if (message.author.bot) return false; - - // Nice to have, responsive bot - console.log(`Message from ${message.author.username}: ${message.content}`); - if (message.content === '') console.log('Empty message') //TODO: Bot can't read user messages - }); + if (env.BASE_GOERLI_RPC && env.LC_BASE_GOERLI) { + this.contracts['BaseGoerli'] = { + RPC: env.BASE_GOERLI_RPC, + Address: env.LC_BASE_GOERLI, + }; } - private async dispatchMessage(messageToSend) { - this.client.channels.cache.get(env.channel_id).send(messageToSend) + if (env.ARBITRUM_GOERLI_RPC && env.LC_ARBITRUM_GOERLI) { + this.contracts['ArbitrumGoerli'] = { + RPC: env.ARBITRUM_GOERLI_RPC, + Address: env.LC_ARBITRUM_GOERLI, + }; + } + if (env.SEPOLIA_RPC && env.LC_SEPOLIA) { + this.contracts['Sepolia'] = { + RPC: env.SEPOLIA_RPC, + Address: env.LC_SEPOLIA, + }; + } + if (env.MUMBAI_RPC && env.LC_MUMBAI) { + this.contracts['Mumbai'] = { + RPC: env.MUMBAI_RPC, + Address: env.LC_MUMBAI, + }; + } + if (env.FANTOM_RPC && env.LC_FANTOM) { + this.contracts['Fantom'] = { + RPC: env.FANTOM_RPC, + Address: env.LC_FANTOM, + }; + } + if (env.CHIADO_RPC && env.LC_CHIADO) { + this.contracts['Chiado'] = { + RPC: env.CHIADO_RPC, + Address: env.LC_CHIADO, + }; + } + if (env.GNOSIS_RPC && env.LC_GNOSIS) { + this.contracts['Gnosis'] = { + RPC: env.GNOSIS_RPC, + Address: env.LC_GNOSIS, + }; + } + if (env.BSC_RPC && env.LC_BSC) { + this.contracts['BSC'] = { RPC: env.BSC_RPC, Address: env.LC_BSC }; + } + if (env.AURORA_RPC && env.LC_AURORA) { + this.contracts['Aurora'] = { + RPC: env.AURORA_RPC, + Address: env.LC_AURORA, + }; } - public async monitor_delay() { - - for (var contract of Object.keys(this.contracts)) { - var name = contract; - var delay = await this.getSlotDelay(this.contracts[contract].SolidityContract!) - - // Dispatch - var minutes_delay = delay * 1 / 5; + // Instantiate SolidityContracts from .env + for (let endpoint in this.contracts) { + let curLightClient = new ethers.Contract( + this.contracts[endpoint].Address, + lc_abi_json.abi, + new ethers.providers.JsonRpcProvider(this.contracts[endpoint].RPC), // Provider + ); + + let curSolidityContract = new SolidityContract( + curLightClient, + this.contracts[endpoint].RPC, + ); + this.contracts[endpoint].SolidityContract = curSolidityContract; + } + } + + private async getSlotDelay(contract: SolidityContract) { + return ( + (await this.beaconApi.getCurrentHeadSlot()) - + (await contract.optimisticHeaderSlot()) + ); + } + + private async respondToMessage() { + //TODO: Implement responsive commands + this.client.on(Events.MessageCreate, message => { + if (message.author.bot) return; + + // Nice to have, responsive bot + console.log( + `Message from ${message.author.username}: ${message.content}`, + ); + if (message.content === '') console.log('Empty message'); //TODO: Bot can't read user messages + }); + } + + public async dispatchMessage(messageToSend) { + let channel = this.client.channels.cache.get( + env.channel_id!, + ) as Discord.TextChannel; + if (!channel) { + channel = (await this.client.channels.fetch( + env.channel_id!, + )) as Discord.TextChannel; + } - if (minutes_delay >= this.alert_threshold || delay < 0) { - var message = `Contract: ${ name } is behind Beacon Head with ${ minutes_delay } minutes` - this.dispatchMessage(message); - } - } + await channel.send(messageToSend); + } + + public async monitor_delay() { + for (let contract of Object.keys(this.contracts)) { + let name = contract; + let delay = await this.getSlotDelay( + this.contracts[contract].SolidityContract!, + ); + + // Dispatch + const minutes_delay = (delay * 1) / 5; + if (minutes_delay >= this.alert_threshold || delay < 0) { + let message = `Contract: ${name} is behind Beacon Head with ${minutes_delay} minutes`; + this.dispatchMessage(message); + } } + } } (async () => { - var monitor = new DiscordMonitor(env.ping_threshold); - while(true) { - await monitor.monitor_delay(); - await sleep(env.ping_timeout); + let monitor = await DiscordMonitor.initializeDiscordMonitor( + Number(env.ping_threshold), + ); + + monitor.dispatchMessage('Relayer bot starting!'); + + let retry_counter = 0; + while (true) { + if (retry_counter >= 10) { + throw new Error( + `Failed connection to Discord after ${retry_counter} retries`, + ); } -})(); + const msTimeout = 10_000; + let waitPromise = new Promise<'timeout'>(resolve => + setTimeout(() => resolve('timeout'), msTimeout), + ); + let response = await Promise.race([monitor.monitor_delay(), waitPromise]); + + retry_counter += response == 'timeout' ? 1 : 0; + + await sleep(env.ping_timeout); + } +})(); diff --git a/yarn.lock b/yarn.lock index 1455b81bc..c3c996a99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -730,6 +730,90 @@ __metadata: languageName: node linkType: hard +"@discordjs/builders@npm:^1.6.5": + version: 1.6.5 + resolution: "@discordjs/builders@npm:1.6.5" + dependencies: + "@discordjs/formatters": ^0.3.2 + "@discordjs/util": ^1.0.1 + "@sapphire/shapeshift": ^3.9.2 + discord-api-types: 0.37.50 + fast-deep-equal: ^3.1.3 + ts-mixer: ^6.0.3 + tslib: ^2.6.1 + checksum: 9c5c4d483a79a7c2f73d661433365f2996ae3bc74f95b70a2a31a26b582b7327d45217a78dfe8e304737661731690ef6e34ade7575f63fe8ab61d70ca53b2279 + languageName: node + linkType: hard + +"@discordjs/collection@npm:^1.5.3": + version: 1.5.3 + resolution: "@discordjs/collection@npm:1.5.3" + checksum: fefed19bea0f69053d195f9d9dc8af07ca5d8c9b1064581e0aa14bda2b70e632b93c164d5ef3e4910f5442369612ff4eec8d52a700aec562510c19b223f67023 + languageName: node + linkType: hard + +"@discordjs/formatters@npm:^0.3.2": + version: 0.3.2 + resolution: "@discordjs/formatters@npm:0.3.2" + dependencies: + discord-api-types: 0.37.50 + checksum: 653c88595fc6c25c1beedcd88b05a3f1241fef69844cc96e45f2cd34fea9ff07892c7f3b57edb4008ad59f7e62bca1b7b35400c6200b07ed42eef7189672d509 + languageName: node + linkType: hard + +"@discordjs/rest@npm:^2.0.1": + version: 2.0.1 + resolution: "@discordjs/rest@npm:2.0.1" + dependencies: + "@discordjs/collection": ^1.5.3 + "@discordjs/util": ^1.0.1 + "@sapphire/async-queue": ^1.5.0 + "@sapphire/snowflake": ^3.5.1 + "@vladfrangu/async_event_emitter": ^2.2.2 + discord-api-types: 0.37.50 + magic-bytes.js: ^1.0.15 + tslib: ^2.6.1 + undici: 5.22.1 + checksum: 36e33489293956e6356e68d69857c2ea910aa376be8c530d6aa640f5887d119d2c0abb736b427353bbdad92c534917fd38adb3a8529c87bdd010c75017ae6b27 + languageName: node + linkType: hard + +"@discordjs/util@npm:^1.0.1": + version: 1.0.1 + resolution: "@discordjs/util@npm:1.0.1" + checksum: b55d5284cd8306b0e77a303c41fa99dcc650babaf9ef2f02ea38b1f8ecc7218a7694128714343379dbf6b2a402a0851e00862c0d974ad07b8e980722f5139d73 + languageName: node + linkType: hard + +"@discordjs/ws@npm:^1.0.1": + version: 1.0.1 + resolution: "@discordjs/ws@npm:1.0.1" + dependencies: + "@discordjs/collection": ^1.5.3 + "@discordjs/rest": ^2.0.1 + "@discordjs/util": ^1.0.1 + "@sapphire/async-queue": ^1.5.0 + "@types/ws": ^8.5.5 + "@vladfrangu/async_event_emitter": ^2.2.2 + discord-api-types: 0.37.50 + tslib: ^2.6.1 + ws: ^8.13.0 + checksum: d34f17646606dbac82989c3aa3fddd1e2a23da532b96f1fc130a0ddb6735079523f09a70b560b315f3e6634b6336accc48680539e4c62cf34826d79c6304778a + languageName: node + linkType: hard + +"@effect/schema@npm:^0.33.0": + version: 0.33.2 + resolution: "@effect/schema@npm:0.33.2" + dependencies: + fast-check: ^3.12.0 + peerDependencies: + "@effect/data": ^0.17.1 + "@effect/io": ^0.38.0 + checksum: 066b90505d63d12537798cd589dcabab708213313b6f3e13faa933826fafabddb85ecd2c9e95745f7b5f90b9c3a276f14639e9a1fe6a57b1399ccd3500ef6719 + languageName: node + linkType: hard + "@ethereum-waffle/chai@npm:4.0.10": version: 4.0.10 resolution: "@ethereum-waffle/chai@npm:4.0.10" @@ -2461,6 +2545,30 @@ __metadata: languageName: node linkType: hard +"@sapphire/async-queue@npm:^1.5.0": + version: 1.5.0 + resolution: "@sapphire/async-queue@npm:1.5.0" + checksum: 983dbd1fd1b1798496e5edb6a0db7e4d90015160e1028f20475eab0a92625513f1e8d938bc0305811a9cec461c94e01b1e4191615ff03ba49356f568f3255250 + languageName: node + linkType: hard + +"@sapphire/shapeshift@npm:^3.9.2": + version: 3.9.2 + resolution: "@sapphire/shapeshift@npm:3.9.2" + dependencies: + fast-deep-equal: ^3.1.3 + lodash: ^4.17.21 + checksum: 0d4572281a2a43dc444f56aef7462d16fdc49cdf0e625d521bfeae4b2219e35b53b7752b4e7396e402ce3b1a21c86afc4c3c82ce1547822a6e844116bb220760 + languageName: node + linkType: hard + +"@sapphire/snowflake@npm:^3.5.1": + version: 3.5.1 + resolution: "@sapphire/snowflake@npm:3.5.1" + checksum: 8fc025020adab1a7a1a5d2cf07704d598cc1977b50e5fcd3a5dd239f00934dc936d3a4d5ae336e71d8bf1d88ec27aa814b34de79e38ff097b7b9ba5a7977a683 + languageName: node + linkType: hard + "@scure/base@npm:~1.1.0": version: 1.1.1 resolution: "@scure/base@npm:1.1.1" @@ -3044,6 +3152,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.5.5": + version: 8.5.5 + resolution: "@types/ws@npm:8.5.5" + dependencies: + "@types/node": "*" + checksum: d00bf8070e6938e3ccf933010921c6ce78ac3606696ce37a393b27a9a603f7bd93ea64f3c5fa295a2f743575ba9c9a9fdb904af0f5fe2229bf2adf0630386e4a + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 21.0.0 resolution: "@types/yargs-parser@npm:21.0.0" @@ -3060,6 +3177,13 @@ __metadata: languageName: node linkType: hard +"@vladfrangu/async_event_emitter@npm:^2.2.2": + version: 2.2.2 + resolution: "@vladfrangu/async_event_emitter@npm:2.2.2" + checksum: ed948294fea1a2dc8b8f307f4061bf65e2043a946132f288702f0572a806ebe3123b8c7e522e70d2abbd3616f5d67027c9e59df9ef80b0195f7502a848a426ba + languageName: node + linkType: hard + "DendrETH-darwinia@workspace:beacon-light-client/solidity": version: 0.0.0-use.local resolution: "DendrETH-darwinia@workspace:beacon-light-client/solidity" @@ -3135,6 +3259,8 @@ __metadata: version: 0.0.0-use.local resolution: "Relay@workspace:relay" dependencies: + "@effect/schema": ^0.33.0 + discord.js: ^14.12.1 ts-node: ^10.9.1 web3: ^1.10.0 yargs: ^17.7.1 @@ -5371,6 +5497,35 @@ __metadata: languageName: node linkType: hard +"discord-api-types@npm:0.37.50": + version: 0.37.50 + resolution: "discord-api-types@npm:0.37.50" + checksum: 08dc5145dbefda5f52b479cd42d96ac2b8110300861855e1f92cc8a0a6525a4059e32724cd5237490c286f5afd86797a86823238cd5eee016198560bb36f6d43 + languageName: node + linkType: hard + +"discord.js@npm:^14.12.1": + version: 14.13.0 + resolution: "discord.js@npm:14.13.0" + dependencies: + "@discordjs/builders": ^1.6.5 + "@discordjs/collection": ^1.5.3 + "@discordjs/formatters": ^0.3.2 + "@discordjs/rest": ^2.0.1 + "@discordjs/util": ^1.0.1 + "@discordjs/ws": ^1.0.1 + "@sapphire/snowflake": ^3.5.1 + "@types/ws": ^8.5.5 + discord-api-types: 0.37.50 + fast-deep-equal: ^3.1.3 + lodash.snakecase: ^4.1.1 + tslib: ^2.6.1 + undici: 5.22.1 + ws: ^8.13.0 + checksum: c273645ac2f92a5052914261c40d04f7fbf81f8d2542f7f0ec9b2e5f9006ff7436d7c6254db924a12826b7f3b49cbfdd577807a0a4ed396036e106f39701a167 + languageName: node + linkType: hard + "dom-walk@npm:^0.1.0": version: 0.1.2 resolution: "dom-walk@npm:0.1.2" @@ -6173,7 +6328,16 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.1": +"fast-check@npm:^3.12.0": + version: 3.13.0 + resolution: "fast-check@npm:3.13.0" + dependencies: + pure-rand: ^6.0.0 + checksum: 5bbc41214c8dea95b5e31d67605586c60ba863f3b1c37b447c4f6637c20df4ce0b8fa286a51558fff439625f865be90a2cc07e909545b47f5638efb9e57f8f85 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d @@ -8961,6 +9125,13 @@ __metadata: languageName: node linkType: hard +"lodash.snakecase@npm:^4.1.1": + version: 4.1.1 + resolution: "lodash.snakecase@npm:4.1.1" + checksum: 1685ed3e83dda6eae5a4dcaee161a51cd210aabb3e1c09c57150e7dd8feda19e4ca0d27d0631eabe8d0f4eaa51e376da64e8c018ae5415417c5890d42feb72a8 + languageName: node + linkType: hard + "lodash.truncate@npm:^4.4.2": version: 4.4.2 resolution: "lodash.truncate@npm:4.4.2" @@ -9084,6 +9255,13 @@ __metadata: languageName: node linkType: hard +"magic-bytes.js@npm:^1.0.15": + version: 1.0.17 + resolution: "magic-bytes.js@npm:1.0.17" + checksum: 8afda0fee0f834a77304ca8e32e49acde4e0a03c0bee6a629959ae78c8dbf7e007e29395cefadd7205635b52bf4e9575b7c94ef015795b7d720814930723c0db + languageName: node + linkType: hard + "make-dir@npm:^3.0.0, make-dir@npm:^3.1.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" @@ -10616,6 +10794,13 @@ __metadata: languageName: node linkType: hard +"pure-rand@npm:^6.0.0": + version: 6.0.3 + resolution: "pure-rand@npm:6.0.3" + checksum: d08701cfd1528c5f9cdca996776c498c92767722561f9b8f9e62645d5025c8a3bf60b90f76f262aaab124e6bb1d58e1b0850722dbca2846a19b708801956e56b + languageName: node + linkType: hard + "qs@npm:6.10.3": version: 6.10.3 resolution: "qs@npm:6.10.3" @@ -12353,6 +12538,13 @@ __metadata: languageName: node linkType: hard +"ts-mixer@npm:^6.0.3": + version: 6.0.3 + resolution: "ts-mixer@npm:6.0.3" + checksum: 7fbaba0a413bf817835a6a23d46bccf4192dd4d7345b6bae9d594c88acffac35bf4995ef3cce753090c8abcdf2afd16dba8899365584a1f960ccc2a15bf2e2d6 + languageName: node + linkType: hard + "ts-node@npm:^10.9.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" @@ -12405,6 +12597,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.6.1": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad + languageName: node + linkType: hard + "tsort@npm:0.0.1": version: 0.0.1 resolution: "tsort@npm:0.0.1" @@ -12596,6 +12795,15 @@ __metadata: languageName: node linkType: hard +"undici@npm:5.22.1": + version: 5.22.1 + resolution: "undici@npm:5.22.1" + dependencies: + busboy: ^1.6.0 + checksum: 048a3365f622be44fb319316cedfaa241c59cf7f3368ae7667a12323447e1822e8cc3d00f6956c852d1478a6fde1cbbe753f49e05f2fdaed229693e716ebaf35 + languageName: node + linkType: hard + "undici@npm:^5.14.0, undici@npm:^5.4.0": version: 5.20.0 resolution: "undici@npm:5.20.0" @@ -13363,6 +13571,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:^8.13.0": + version: 8.14.1 + resolution: "ws@npm:8.14.1" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 9e310be2b0ff69e1f87d8c6d093ecd17a1ed4c37f281d17c35e8c30e2bd116401775b3d503249651374e6e0e1e9905db62fff096b694371c77561aee06bc3466 + languageName: node + linkType: hard + "xhr-request-promise@npm:^0.1.2": version: 0.1.3 resolution: "xhr-request-promise@npm:0.1.3"