diff --git a/package.json b/package.json index 13de820..f9d181a 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "lib/index.js", "license": "Apache-2.0", "dependencies": { + "@coral-xyz/anchor": "^0.29.0", "@drift-labs/sdk": "2.49.0-beta.12", "@opentelemetry/api": "^1.1.0", "@opentelemetry/auto-instrumentations-node": "^0.31.1", @@ -13,6 +14,7 @@ "@project-serum/anchor": "^0.19.1-beta.1", "@project-serum/serum": "^0.13.65", "@solana/web3.js": "^1.73.3", + "@triton-one/yellowstone-grpc": "^0.3.0", "@types/redis": "^4.0.11", "@types/ws": "^8.5.8", "async-mutex": "^0.4.0", diff --git a/src/dlobProvider.ts b/src/dlobProvider.ts index bf34a21..e0dc287 100644 --- a/src/dlobProvider.ts +++ b/src/dlobProvider.ts @@ -1,5 +1,6 @@ import { DLOB, OrderSubscriber, UserAccount, UserMap } from '@drift-labs/sdk'; import { PublicKey } from '@solana/web3.js'; +import { GeyserOrderSubscriber } from './grpc/OrderSubscriberGRPC'; export type DLOBProvider = { subscribe(): Promise; @@ -82,3 +83,41 @@ export function getDLOBProviderFromOrderSubscriber( }, }; } + +export function getDLOBProviderFromGrpcOrderSubscriber( + orderSubscriber: GeyserOrderSubscriber +): DLOBProvider { + return { + subscribe: async () => { + await orderSubscriber.subscribe(); + }, + getDLOB: async (slot: number) => { + return await orderSubscriber.getDLOB(slot); + }, + getUniqueAuthorities: () => { + const authorities = new Set(); + for (const { userAccount } of orderSubscriber.usersAccounts.values()) { + authorities.add(userAccount.authority); + } + return Array.from(authorities.values()); + }, + getUserAccounts: function* () { + for (const [ + key, + { userAccount }, + ] of orderSubscriber.usersAccounts.entries()) { + yield { userAccount: userAccount, publicKey: new PublicKey(key) }; + } + }, + getUserAccount: (publicKey) => { + return orderSubscriber.usersAccounts.get(publicKey.toString()) + ?.userAccount; + }, + size(): number { + return orderSubscriber.usersAccounts.size; + }, + fetch() { + return orderSubscriber.fetch(); + }, + }; +} diff --git a/src/grpc/OrderSubscriberGRPC.ts b/src/grpc/OrderSubscriberGRPC.ts new file mode 100644 index 0000000..ca4c935 --- /dev/null +++ b/src/grpc/OrderSubscriberGRPC.ts @@ -0,0 +1,253 @@ +import { BorshAccountsCoder } from '@coral-xyz/anchor'; +import { Commitment, PublicKey, RpcResponseAndContext } from '@solana/web3.js'; +import { Buffer } from 'buffer'; +import Client, { + CommitmentLevel, + SubscribeRequest, + SubscribeUpdate, +} from '@triton-one/yellowstone-grpc'; +import { + BN, + DLOB, + DriftClient, + UserAccount, + getUserFilter, + getUserWithOrderFilter, +} from '@drift-labs/sdk'; +import { ClientDuplexStream } from '@grpc/grpc-js'; + +type grpcDlobConfig = { + endpoint: string; + token: string; +}; + +export class GeyserOrderSubscriber { + usersAccounts = new Map(); + commitment: Commitment; + driftClient: DriftClient; + config: grpcDlobConfig; + stream: ClientDuplexStream; + + fetchPromise?: Promise; + fetchPromiseResolver: () => void; + mostRecentSlot: number; + + constructor(driftClient: DriftClient, config: grpcDlobConfig) { + this.driftClient = driftClient; + this.config = config; + } + + public async subscribe(): Promise { + const client = new Client(this.config.endpoint, this.config.token); + this.stream = await client.subscribe(); + const request: SubscribeRequest = { + slots: {}, + accounts: { + drift: { + owner: [this.driftClient.program.programId.toBase58()], + filters: [ + { + memcmp: { + offset: '0', + bytes: BorshAccountsCoder.accountDiscriminator('User'), + }, + }, + { + memcmp: { + offset: '4350', + bytes: Uint8Array.from([1]), + }, + }, + ], + account: [], + }, + }, + transactions: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + commitment: CommitmentLevel.PROCESSED, + entry: {}, + }; + + this.stream.on('data', (chunk: any) => { + if (!chunk.account) { + return; + } + const slot = Number(chunk.account.slot); + this.tryUpdateUserAccount( + new PublicKey(chunk.account.account.pubkey).toBase58(), + 'grpc', + chunk.account.account.data, + slot + ); + }); + + return new Promise((resolve, reject) => { + this.stream.write(request, (err) => { + if (err === null || err === undefined) { + resolve(); + } else { + reject(err); + } + }); + }).catch((reason) => { + console.error(reason); + throw reason; + }); + } + + async fetch(): Promise { + if (this.fetchPromise) { + return this.fetchPromise; + } + + this.fetchPromise = new Promise((resolver) => { + this.fetchPromiseResolver = resolver; + }); + + try { + const rpcRequestArgs = [ + this.driftClient.program.programId.toBase58(), + { + commitment: this.commitment, + filters: [getUserFilter(), getUserWithOrderFilter()], + encoding: 'base64', + withContext: true, + }, + ]; + + const rpcJSONResponse: any = + // @ts-ignore + await this.driftClient.connection._rpcRequest( + 'getProgramAccounts', + rpcRequestArgs + ); + + const rpcResponseAndContext: RpcResponseAndContext< + Array<{ + pubkey: PublicKey; + account: { + data: [string, string]; + }; + }> + > = rpcJSONResponse.result; + + const slot: number = rpcResponseAndContext.context.slot; + + const programAccountSet = new Set(); + for (const programAccount of rpcResponseAndContext.value) { + const key = programAccount.pubkey.toString(); + programAccountSet.add(key); + this.tryUpdateUserAccount( + key, + 'raw', + programAccount.account.data, + slot + ); + // give event loop a chance to breathe + await new Promise((resolve) => setTimeout(resolve, 0)); + } + + for (const key of this.usersAccounts.keys()) { + if (!programAccountSet.has(key)) { + this.usersAccounts.delete(key); + } + // give event loop a chance to breathe + await new Promise((resolve) => setTimeout(resolve, 0)); + } + } catch (e) { + console.error(e); + } finally { + this.fetchPromiseResolver(); + this.fetchPromise = undefined; + } + } + + tryUpdateUserAccount( + key: string, + dataType: 'raw' | 'grpc', + data: string[] | Buffer | UserAccount, + slot: number + ): void { + if (!this.mostRecentSlot || slot > this.mostRecentSlot) { + this.mostRecentSlot = slot; + } + + const slotAndUserAccount = this.usersAccounts.get(key); + if (!slotAndUserAccount || slotAndUserAccount.slot <= slot) { + // Polling leads to a lot of redundant decoding, so we only decode if data is from a fresh slot + let buffer: Buffer; + if (dataType === 'raw') { + buffer = Buffer.from(data[0], data[1]); + } else { + buffer = data as Buffer; + } + + const newLastActiveSlot = new BN( + buffer.subarray(4328, 4328 + 8), + undefined, + 'le' + ); + if ( + slotAndUserAccount && + slotAndUserAccount.userAccount.lastActiveSlot.gt(newLastActiveSlot) + ) { + return; + } + + const userAccount = + this.driftClient.program.account.user.coder.accounts.decodeUnchecked( + 'User', + buffer + ) as UserAccount; + + if (userAccount.hasOpenOrder) { + this.usersAccounts.set(key, { slot, userAccount }); + } else { + this.usersAccounts.delete(key); + } + } + } + + public async getDLOB(slot: number): Promise { + const dlob = new DLOB(); + for (const [key, { userAccount }] of this.usersAccounts.entries()) { + const userAccountPubkey = new PublicKey(key); + for (const order of userAccount.orders) { + dlob.insertOrder(order, userAccountPubkey, slot); + } + } + return dlob; + } + + public getSlot(): number { + return this.mostRecentSlot ?? 0; + } + + public async unsubscribe(): Promise { + return new Promise((resolve, reject) => { + this.stream.write( + { + slots: {}, + accounts: {}, + transactions: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + entry: {}, + }, + (err) => { + if (err === null || err === undefined) { + resolve(); + } else { + reject(err); + } + } + ); + }).catch((reason) => { + console.error(reason); + throw reason; + }); + } +} diff --git a/src/index.ts b/src/index.ts index 44c2c72..d8deef8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -66,7 +66,6 @@ const WS_FALLBACK_FETCH_INTERVAL = ORDERBOOK_UPDATE_INTERVAL * 10; const useWebsocket = process.env.USE_WEBSOCKET?.toLowerCase() === 'true'; const useOrderSubscriber = process.env.USE_ORDER_SUBSCRIBER?.toLowerCase() === 'true'; - const rateLimitCallsPerSecond = process.env.RATE_LIMIT_CALLS_PER_SECOND ? parseInt(process.env.RATE_LIMIT_CALLS_PER_SECOND) : 1; diff --git a/src/publishers/dlobPublisher.ts b/src/publishers/dlobPublisher.ts index d174921..0e90f56 100644 --- a/src/publishers/dlobPublisher.ts +++ b/src/publishers/dlobPublisher.ts @@ -27,14 +27,16 @@ import { DLOBSubscriberIO } from '../dlob-subscriber/DLOBSubscriberIO'; import { RedisClient } from '../utils/redisClient'; import { DLOBProvider, + getDLOBProviderFromGrpcOrderSubscriber, getDLOBProviderFromOrderSubscriber, getDLOBProviderFromUserMap, } from '../dlobProvider'; import FEATURE_FLAGS from '../utils/featureFlags'; +import { GeyserOrderSubscriber } from '../grpc/OrderSubscriberGRPC'; require('dotenv').config(); const stateCommitment: Commitment = 'processed'; -const ORDERBOOK_UPDATE_INTERVAL = 1000; +const ORDERBOOK_UPDATE_INTERVAL = 400; const WS_FALLBACK_FETCH_INTERVAL = ORDERBOOK_UPDATE_INTERVAL * 10; const driftEnv = (process.env.ENV || 'devnet') as DriftEnv; const commitHash = process.env.COMMIT; @@ -49,10 +51,15 @@ let driftClient: DriftClient; const opts = program.opts(); setLogLevel(opts.debug ? 'debug' : 'info'); -const endpoint = process.env.ENDPOINT; +const token = process.env.TOKEN; +const endpoint = token + ? process.env.ENDPOINT + `/${token}` + : process.env.ENDPOINT; const wsEndpoint = process.env.WS_ENDPOINT; const useOrderSubscriber = process.env.USE_ORDER_SUBSCRIBER?.toLowerCase() === 'true'; + +const useGrpc = process.env.USE_GRPC?.toLowerCase() === 'true'; const useWebsocket = process.env.USE_WEBSOCKET?.toLowerCase() === 'true'; logger.info(`RPC endpoint: ${endpoint}`); @@ -126,7 +133,7 @@ const main = async () => { bulkAccountLoader = new BulkAccountLoader( connection, stateCommitment, - ORDERBOOK_UPDATE_INTERVAL + ORDERBOOK_UPDATE_INTERVAL < 1000 ? 1000 : ORDERBOOK_UPDATE_INTERVAL ); accountSubscription = { @@ -206,6 +213,13 @@ const main = async () => { slotSource = { getSlot: () => orderSubscriber.getSlot(), }; + } else if (useGrpc) { + const grpcOrderSubscriber = new GeyserOrderSubscriber(driftClient, { + endpoint: endpoint, + token: token, + }); + + dlobProvider = getDLOBProviderFromGrpcOrderSubscriber(grpcOrderSubscriber); } else { const userMap = new UserMap({ driftClient, diff --git a/yarn.lock b/yarn.lock index 9194fd2..0738dbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -63,6 +63,26 @@ superstruct "^0.15.4" toml "^3.0.0" +"@coral-xyz/anchor@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.29.0.tgz#bd0be95bedfb30a381c3e676e5926124c310ff12" + integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== + dependencies: + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.68.0" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + "@coral-xyz/borsh@^0.28.0": version "0.28.0" resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.28.0.tgz#fa368a2f2475bbf6f828f4657f40a52102e02b6d" @@ -71,6 +91,14 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" +"@coral-xyz/borsh@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.29.0.tgz#79f7045df2ef66da8006d47f5399c7190363e71f" + integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -142,6 +170,24 @@ resolved "https://registry.yarnpkg.com/@fastify/error/-/error-2.0.0.tgz#a9f94af56eb934f0ab1ce4ef9f0ced6ebf2319dc" integrity sha512-wI3fpfDT0t7p8E6dA2eTECzzOd+bZsZCJ2Hcv+Onn2b7ZwK3RwD27uW2QDaMtQhAfWQQP+WNK7nKf0twLsBf9w== +"@grpc/grpc-js@^1.8.0": + version "1.9.12" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.12.tgz#a45b23a7d9ee1eadc9fa8fe480e27edbc6544cdd" + integrity sha512-Um5MBuge32TS3lAKX02PGCnFM4xPT996yLgZNb5H03pn6NyJ4Iwn5YcPq6Jj9yxGRk7WOgaZFtVRH5iTdYBeUg== + dependencies: + "@grpc/proto-loader" "^0.7.8" + "@types/node" ">=12.12.47" + +"@grpc/proto-loader@^0.7.8": + version "0.7.10" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.10.tgz#6bf26742b1b54d0a473067743da5d3189d06d720" + integrity sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.4" + yargs "^17.7.2" + "@hapi/b64@5.x.x": version "5.0.0" resolved "https://registry.yarnpkg.com/@hapi/b64/-/b64-5.0.0.tgz#b8210cbd72f4774985e78569b77e97498d24277d" @@ -899,6 +945,59 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@pythnetwork/client@2.5.3": version "2.5.3" resolved "https://registry.yarnpkg.com/@pythnetwork/client/-/client-2.5.3.tgz#86c9f92d01d8f282fdd8b5b11039da654e263988" @@ -1083,6 +1182,13 @@ rpc-websockets "^7.5.1" superstruct "^0.14.2" +"@triton-one/yellowstone-grpc@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@triton-one/yellowstone-grpc/-/yellowstone-grpc-0.3.0.tgz#2318b98b9ee80871e4ee8f9259f3d8673bf2c576" + integrity sha512-HJ7K7asSLKj8UY7AcuqOzNPnztBHSaMsjkkkexNkDEzJF2ZvwNNnhdmd/AndrL0GNDgS8DeFcP/Dm2X+nRp4zQ== + dependencies: + "@grpc/grpc-js" "^1.8.0" + "@tsconfig/node10@^1.0.7": version "1.0.9" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" @@ -1359,6 +1465,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== +"@types/node@>=12.12.47", "@types/node@>=13.7.0": + version "20.10.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.3.tgz#4900adcc7fc189d5af5bb41da8f543cea6962030" + integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== + dependencies: + undici-types "~5.26.4" + "@types/node@^12.12.54": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -1905,6 +2018,15 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + cluster-key-slot@1.1.2, cluster-key-slot@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" @@ -2209,6 +2331,11 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2627,6 +2754,11 @@ generic-pool@3.9.0: resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" @@ -3020,6 +3152,11 @@ light-my-request@^4.2.0: process-warning "^1.0.0" set-cookie-parser "^2.4.1" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -3056,6 +3193,11 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -3458,6 +3600,24 @@ prom-client@^15.0.0: "@opentelemetry/api" "^1.4.0" tdigest "^0.1.1" +protobufjs@^7.2.4: + version "7.2.5" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.5.tgz#45d5c57387a6d29a17aab6846dcc283f9b8e7f2d" + integrity sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-addr@^2.0.7, proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -3571,6 +3731,11 @@ regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -3893,7 +4058,7 @@ string-similarity@^4.0.1: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== -string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4103,6 +4268,11 @@ uid2@0.0.3: resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" integrity sha512-5gSP1liv10Gjp8cMEnFd6shzkL/D6W1uhXSFNCxDC+YI8+L8wkCYCbJ7n77Ezb4wE/xzMogecE+DtamEe9PZjg== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -4226,6 +4396,15 @@ word-wrap@^1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -4251,11 +4430,34 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@4.0.0, yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"