diff --git a/sdk/README.md b/sdk/README.md index 00728e2a8..72f154aaa 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -17,6 +17,8 @@ npm i @drift-labs/sdk ``` +If you are using a gRPC flavored account subscriber, you will need an updated `protoc` installation, please refer to the Protobuf [installation guide](https://grpc.io/docs/protoc-installation/) + ## Getting Started Documentation: diff --git a/sdk/package.json b/sdk/package.json index ec414acce..f3b9ff383 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -40,6 +40,7 @@ "@pythnetwork/client": "2.5.3", "@solana/spl-token": "^0.3.7", "@solana/web3.js": "1.91.7", + "@triton-one/yellowstone-grpc": "0.4.0", "strict-event-emitter-types": "^2.0.0", "uuid": "^8.3.2", "zstddec": "^0.1.0" @@ -68,4 +69,4 @@ "engines": { "node": ">=18" } -} +} \ No newline at end of file diff --git a/sdk/src/accounts/grpcAccountSubscriber.ts b/sdk/src/accounts/grpcAccountSubscriber.ts new file mode 100644 index 000000000..433e8036c --- /dev/null +++ b/sdk/src/accounts/grpcAccountSubscriber.ts @@ -0,0 +1,74 @@ +import { + DataAndSlot, + BufferAndSlot, + AccountSubscriber, + ResubOpts, +} from './types'; +import { AnchorProvider, Program } from '@coral-xyz/anchor'; +import { AccountInfo, Commitment, Context, PublicKey } from '@solana/web3.js'; +import { capitalize } from './utils'; +import Client, { + CommitmentLevel, + SubscribeRequest, + SubscribeRequestFilterAccountsFilter, +} from '@triton-one/yellowstone-grpc'; +import { ChannelOptions } from '@grpc/grpc-js'; + +export class GrpcAccountSubscriber implements AccountSubscriber { + dataAndSlot?: DataAndSlot; + bufferAndSlot?: BufferAndSlot; + accountName: string; + program: Program; + client: Client; + accountPublicKey: PublicKey; + decodeBufferFn: (buffer: Buffer) => T; + onChange: (data: T) => void; + listenerId?: number; + + resubOpts?: ResubOpts; + + commitment?: Commitment; + isUnsubscribing = false; + + timeoutId?: NodeJS.Timeout; + + receivingData: boolean; + + public constructor( + accountName: string, + program: Program, + accountPublicKey: PublicKey, + grpcEndpoint: string, + grpcXToken?: string, + grpcChannelOptions?: ChannelOptions, + // decodeBuffer?: (buffer: Buffer) => T, + commitment?: Commitment + ) { + this.accountName = accountName; + this.program = program; + this.accountPublicKey = accountPublicKey; + this.receivingData = false; + this.commitment = + commitment ?? (this.program.provider as AnchorProvider).opts.commitment; + this.client = new Client(grpcEndpoint, grpcXToken, grpcChannelOptions); + } + + async subscribe(onChange: (data: T) => void): Promise { + if (this.listenerId != null || this.isUnsubscribing) { + return; + } + this.onChange = onChange; + if (!this.dataAndSlot) { + await this.fetch(); + } + } + fetch(): Promise { + throw new Error('Method not implemented.'); + } + unsubscribe(): Promise { + throw new Error('Method not implemented.'); + } + setData(userAccount: T, slot?: number): void { + throw new Error('Method not implemented.'); + } +} diff --git a/sdk/src/accounts/grpcClient.ts b/sdk/src/accounts/grpcClient.ts new file mode 100644 index 000000000..4e4703c0b --- /dev/null +++ b/sdk/src/accounts/grpcClient.ts @@ -0,0 +1,272 @@ +import Client, { + SubscribeRequest, + SubscribeUpdate, + SubscribeRequestFilterAccountsFilter, + SubscribeRequestFilterAccounts, + SubscribeRequestFilterSlots, + SubscribeRequestFilterTransactions, + SubscribeRequestFilterBlocks, + SubscribeRequestFilterBlocksMeta, + SubscribeRequestFilterEntry, +} from '@triton-one/yellowstone-grpc'; +import { ChannelOptions, ClientDuplexStream } from '@grpc/grpc-js'; +import { + SubscribeRequestPing, + SubscribeUpdateAccount, + SubscribeUpdateSlot, +} from '@triton-one/yellowstone-grpc/dist/grpc/geyser'; + +const emptyRequest: SubscribeRequest = { + slots: {}, + accounts: {}, + transactions: {}, + blocks: {}, + blocksMeta: {}, + accountsDataSlice: [], + entry: {}, +}; + +/// A single grpc connection can manage multiple subscriptions (accounts, programs, blocks, etc.) +/// This class is a wrapper around a grpc client to manage multiplexing these subscriptions +/// and avoid unintentionally unsubscribing when multiple account subscribers share a connection. +/// +/// SubscriptionAwareGrpcClient can be safely shared across multiple objects. +export class SubscriptionAwareGrpcClient { + client: Client; + /// the latest set of subscriptions + callbacks: Map< + string, + [(key: string, data: any) => void, keyof SubscribeUpdate] + > = new Map(); + subcribeRequest: SubscribeRequest; + stream?: ClientDuplexStream; + + constructor( + grpcEndpoint: string, + grpcXToken?: string, + grpcChannelOptions?: ChannelOptions + ) { + this.client = new Client(grpcEndpoint, grpcXToken, grpcChannelOptions); + this.subcribeRequest = emptyRequest; + } + + async subscribe() { + if (this.stream) { + return; + } + this.stream = await this.client.subscribe(); + this.stream.on('data', (data: SubscribeUpdate) => { + console.log('DATA:', data); + for (const filter of data.filters) { + if (this.callbacks.has(filter)) { + const [callback, payloadKey] = this.callbacks.get(filter); + callback(filter, data[payloadKey]); + } + } + }); + } + + async unsubscribe() { + if (!this.stream) { + return; + } + + // https://docs.triton.one/project-yellowstone/dragons-mouth-grpc-subscriptions#unsubscribing + this.subcribeRequest = emptyRequest; + this.stream.write(this.subcribeRequest); + this.stream.end(); + this.stream = undefined; + this.callbacks.clear(); + } + + addAccountSubscription( + key: string, + account: string[], + callback: (key: string, data: SubscribeUpdateAccount) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.accounts[key]) { + throw new Error( + `Account subscription key ${key} already exists, existing subscription: ${JSON.stringify( + this.subcribeRequest.accounts[key] + )}, new subscription: ${JSON.stringify(account)}` + ); + } + this.callbacks.set(key, [callback, 'account']); + this.subcribeRequest.accounts[key] = SubscribeRequestFilterAccounts.create({ + account, + }); + this.stream.write(this.subcribeRequest); + } + + addProgramSubscription( + key: string, + owner: string[], + filters: SubscribeRequestFilterAccountsFilter[], + callback: (key: string, data: SubscribeUpdateAccount) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.accounts[key]) { + throw new Error( + `Account subscription key ${key} already exists, existing subscription: ${JSON.stringify( + this.subcribeRequest.accounts[key] + )}, new subscription: ${JSON.stringify({ owner, filters })}` + ); + } + this.callbacks.set(key, [callback, 'account']); + this.subcribeRequest.accounts[key] = SubscribeRequestFilterAccounts.create({ + owner, + filters, + }); + this.stream.write(this.subcribeRequest); + } + + addSlotSubscription( + key: string, + callback: (key: string, data: SubscribeUpdateSlot) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.slots[key]) { + throw new Error(`Slot subscription key ${key} already exists`); + } + this.callbacks.set(key, [callback, 'slot']); + this.subcribeRequest.slots[key] = SubscribeRequestFilterSlots.create({}); + this.stream.write(this.subcribeRequest); + } + + addTransactionSubscription( + key: string, + subscription: SubscribeRequestFilterTransactions, + callback: (key: string, data: any) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.transactions[key]) { + throw new Error( + `Transaction subscription key ${key} already exists, existing subscription: ${JSON.stringify( + this.subcribeRequest.transactions[key] + )}, new subscription: ${JSON.stringify(subscription)}` + ); + } + this.callbacks.set(key, [callback, 'transaction']); + this.subcribeRequest.transactions[key] = subscription; + } + + addBlockSubscription( + key: string, + subscription: SubscribeRequestFilterBlocks, + callback: (key: string, data: any) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.blocks[key]) { + throw new Error( + `Block subscription key ${key} already exists, existing subscription: ${JSON.stringify( + this.subcribeRequest.blocks[key] + )}, new subscription: ${JSON.stringify(subscription)}` + ); + } + this.callbacks.set(key, [callback, 'block']); + this.subcribeRequest.blocks[key] = subscription; + this.stream.write(this.subcribeRequest); + } + + addBlockMetaSubscription( + key: string, + subscription: SubscribeRequestFilterBlocksMeta, + callback: (key: string, data: any) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.blocksMeta[key]) { + throw new Error( + `Block meta subscription key ${key} already exists, existing subscription: ${JSON.stringify( + this.subcribeRequest.blocksMeta[key] + )}, new subscription: ${JSON.stringify(subscription)}` + ); + } + this.callbacks.set(key, [callback, 'blockMeta']); + this.subcribeRequest.blocksMeta[key] = subscription; + this.stream.write(this.subcribeRequest); + } + + addEntrySubscription( + key: string, + subscription: SubscribeRequestFilterEntry, + callback: (key: string, data: any) => void + ) { + if (!this.stream) { + throw new Error('must call subscribe() before adding subscriptions'); + } + if (this.subcribeRequest.entry[key]) { + throw new Error( + `Entry subscription key ${key} already exists, existing subscription: ${JSON.stringify( + this.subcribeRequest.entry[key] + )}, new subscription: ${JSON.stringify(subscription)}` + ); + } + this.callbacks.set(key, [callback, 'entry']); + this.subcribeRequest.entry[key] = subscription; + this.stream.write(this.subcribeRequest); + } + + // addAccountsDataSliceSubscription(subscription: SubscribeRequestAccountsDataSlice, callback: (key: string, data: any) => void) { + // if (!this.stream) { + // throw new Error("must call subscribe() before adding subscriptions"); + // } + // this.callbacks.set(key, callback); + // this.subcribeRequest.accountsDataSlice.push(subscription); + // this.stream.write(this.subcribeRequest); + // } + + addPingSubscription(subscription: SubscribeRequestPing) { + this.subcribeRequest.ping = subscription; + this.stream.write(this.subcribeRequest); + } +} + +const main = async () => { + const client = new SubscriptionAwareGrpcClient( + 'https://api.rpcpool.com:443', + '' + ); + + await client.subscribe(); + + client.addAccountSubscription( + 'BRksHqLiq2gvQw1XxsZq6DXZjD3GB5a9J63tUBgd6QS9-account', + ['BRksHqLiq2gvQw1XxsZq6DXZjD3GB5a9J63tUBgd6QS9'], + (key, data) => { + console.log('ACCOUNT', key, data); + } + ); + + client.addAccountSubscription( + 'BRksHqLiq2gvQw1XxsZq6DXZjD3GB5a9J63tUBgd6QS9-account2', + ['BRksHqLiq2gvQw1XxsZq6DXZjD3GB5a9J63tUBgd6QS9'], + (key, data) => { + console.log('ACCOUNT_2', key, data); + } + ); + + // client.addSlotSubscription('slots', (key, data) => { + // console.log("SLOT", key, data); + // }) + + console.log('waiting...'); + await new Promise((resolve) => setTimeout(resolve, 30_000)); + console.log('done!'); + await client.unsubscribe(); + process.exit(0); +}; + +main(); diff --git a/sdk/yarn.lock b/sdk/yarn.lock index 1113096db..b3a7798ea 100644 --- a/sdk/yarn.lock +++ b/sdk/yarn.lock @@ -109,6 +109,24 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@grpc/grpc-js@^1.8.0": + version "1.10.8" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.10.8.tgz#99787785cd8335be861afd1cd485ae9f058e4484" + integrity sha512-vYVqYzHicDqyKB+NQhAc54I1QWCBLCrYG6unqOIcBTHx+7x8C9lcoLj3KVJXs2VB4lUbpWY+Kk9NipcbXYWmvg== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -167,6 +185,11 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@metaplex-foundation/beet-solana@^0.3.0": version "0.3.1" resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet-solana/-/beet-solana-0.3.1.tgz#4b37cda5c7f32ffd2bdd8b3164edc05c6463ab35" @@ -313,6 +336,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" @@ -408,6 +484,13 @@ rpc-websockets "^7.5.1" superstruct "^0.14.2" +"@triton-one/yellowstone-grpc@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@triton-one/yellowstone-grpc/-/yellowstone-grpc-0.4.0.tgz#f0c047394bec5304fa043cca0a9b52923e57d89d" + integrity sha512-YJaX+ByPtN6aG4HiKfd62Yd5NUZIiEMoBmSfxdRLBEgT3J9WWqoCRqVTzS93sWpP7IJ5pkGBfxMpDlugM8zn3g== + 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" @@ -494,6 +577,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== +"@types/node@>=13.7.0": + version "20.12.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" + integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== + 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" @@ -964,6 +1054,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.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" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1873,6 +1972,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +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.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -1896,6 +2000,11 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.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== + loupe@^2.3.1: version "2.3.6" resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" @@ -2167,6 +2276,24 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +protobufjs@^7.2.5: + version "7.3.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.0.tgz#a32ec0422c039798c41a0700306a6e305b9cb32c" + integrity sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@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" + punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -2506,6 +2633,11 @@ typescript@^4.9.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +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== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -2632,6 +2764,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +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-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -2655,6 +2792,19 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +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"