feat(express-relay): Support websocket in the js sdk (#1301)

This commit is contained in:
Amin Moghaddam 2024-02-22 09:55:02 +01:00 committed by GitHub
parent 3c1348c530
commit f22c0c8ae6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 424 additions and 172 deletions

View File

@ -35,24 +35,22 @@ import {
const client = new Client({ baseUrl: "https://per-staging.dourolabs.app/" });
function calculateOpportunityBid(
opportunity: OpportunityParams
): BidInfo | null {
function calculateOpportunityBid(opportunity: Opportunity): BidInfo | null {
// searcher implementation here
// if the opportunity is not suitable for the searcher, return null
}
const opportunities = await client.getOpportunities();
for (const opportunity of opportunities) {
const bidInfo = calculateOpportunityBid(order);
if (bidInfo === null) continue;
client.setOpportunityHandler(async (opportunity: Opportunity) => {
const bidInfo = calculateOpportunityBid(opportunity);
if (bidInfo === null) return;
const opportunityBid = await client.signOpportunityBid(
opportunity,
bidInfo,
privateKey // searcher private key with appropriate permissions and assets
);
await client.submitOpportunityBid(opportunityBid);
}
});
await client.subscribeChains([chain_id]); // chain id you want to subscribe to
```
### Example

View File

@ -1,6 +1,6 @@
{
"name": "@pythnetwork/express-relay-evm-js",
"version": "0.1.0",
"version": "0.1.1",
"description": "Utilities for interacting with the express relay protocol",
"homepage": "https://pyth.network",
"author": {
@ -36,20 +36,22 @@
"directory": "express_relay/sdk/js"
},
"dependencies": {
"isomorphic-ws": "^5.0.0",
"openapi-client-axios": "^7.5.4",
"openapi-fetch": "^0.8.2",
"viem": "^2.7.6"
"viem": "^2.7.6",
"ws": "^8.16.0"
},
"devDependencies": {
"@types/yargs": "^17.0.10",
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"eslint": "^8.56.0",
"jest": "^27.5.1",
"openapi-typescript": "^6.5.5",
"prettier": "^2.6.2",
"typescript": "^5.1",
"yargs": "^17.4.1",
"jest": "^27.5.1"
"yargs": "^17.4.1"
},
"license": "Apache-2.0"
}

View File

@ -1,13 +1,9 @@
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { Client } from "../index";
import { checkHex, Client } from "../index";
import { privateKeyToAccount } from "viem/accounts";
import { isHex } from "viem";
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const argv = yargs(hideBin(process.argv))
.option("endpoint", {
description:
@ -18,6 +14,7 @@ const argv = yargs(hideBin(process.argv))
.option("chain-id", {
description: "Chain id to fetch opportunities for. e.g: sepolia",
type: "string",
demandOption: true,
})
.option("bid", {
description: "Bid amount in wei",
@ -43,35 +40,38 @@ async function run() {
throw new Error(`Invalid private key: ${argv.privateKey}`);
}
const DAY_IN_SECONDS = 60 * 60 * 24;
// eslint-disable-next-line no-constant-condition
while (true) {
const opportunities = await client.getOpportunities(argv.chainId);
console.log(`Fetched ${opportunities.length} opportunities`);
for (const opportunity of opportunities) {
const bid = BigInt(argv.bid);
// Bid info should be generated by evaluating the opportunity
// here for simplicity we are using a constant bid and 24 hours of validity
const bidInfo = {
amount: bid,
validUntil: BigInt(Math.round(Date.now() / 1000 + DAY_IN_SECONDS)),
};
const opportunityBid = await client.signOpportunityBid(
opportunity,
bidInfo,
argv.privateKey
client.setOpportunityHandler(async (opportunity) => {
const bid = BigInt(argv.bid);
// Bid info should be generated by evaluating the opportunity
// here for simplicity we are using a constant bid and 24 hours of validity
const bidInfo = {
amount: bid,
validUntil: BigInt(Math.round(Date.now() / 1000 + DAY_IN_SECONDS)),
};
const opportunityBid = await client.signOpportunityBid(
opportunity,
bidInfo,
checkHex(argv.privateKey)
);
try {
await client.submitOpportunityBid(opportunityBid);
console.log(
`Successful bid ${bid} on opportunity ${opportunity.opportunityId}`
);
} catch (error) {
console.error(
`Failed to bid on opportunity ${opportunity.opportunityId}: ${error}`
);
try {
await client.submitOpportunityBid(opportunityBid);
console.log(
`Successful bid ${bid} on opportunity ${opportunity.opportunityId}`
);
} catch (error) {
console.error(
`Failed to bid on opportunity ${opportunity.opportunityId}: ${error}`
);
}
}
await sleep(5000);
});
try {
await client.subscribeChains([argv.chainId]);
console.log(
`Subscribed to chain ${argv.chainId}. Waiting for opportunities...`
);
} catch (error) {
console.error(error);
client.websocket?.close();
}
}

View File

@ -1,5 +1,7 @@
import type { paths } from "./types";
import createClient, { ClientOptions } from "openapi-fetch";
import type { paths, components } from "./types";
import createClient, {
ClientOptions as FetchClientOptions,
} from "openapi-fetch";
import {
Address,
encodeAbiParameters,
@ -10,7 +12,7 @@ import {
keccak256,
} from "viem";
import { privateKeyToAccount, sign, signatureToHex } from "viem/accounts";
import WebSocket from "isomorphic-ws";
/**
* ERC20 token with contract address and amount
*/
@ -118,11 +120,172 @@ function checkTokenQty(token: { contract: string; amount: string }): TokenQty {
};
}
export class Client {
private clientOptions?: ClientOptions;
type ClientOptions = FetchClientOptions & { baseUrl: string };
constructor(clientOptions?: ClientOptions) {
export interface WsOptions {
/**
* Max time to wait for a response from the server in milliseconds
*/
response_timeout: number;
}
const DEFAULT_WS_OPTIONS: WsOptions = {
response_timeout: 5000,
};
export class Client {
public clientOptions: ClientOptions;
public wsOptions: WsOptions;
public websocket?: WebSocket;
public idCounter = 0;
public callbackRouter: Record<
string,
(response: components["schemas"]["ServerResultMessage"]) => void
> = {};
private websocketOpportunityCallback?: (
opportunity: Opportunity
) => Promise<void>;
constructor(clientOptions: ClientOptions, wsOptions?: WsOptions) {
this.clientOptions = clientOptions;
this.wsOptions = { ...DEFAULT_WS_OPTIONS, ...wsOptions };
}
private connectWebsocket() {
const websocketEndpoint = new URL(this.clientOptions.baseUrl);
websocketEndpoint.protocol =
websocketEndpoint.protocol === "https:" ? "wss:" : "ws:";
websocketEndpoint.pathname = "/v1/ws";
this.websocket = new WebSocket(websocketEndpoint.toString());
this.websocket.on("message", async (data) => {
const message:
| components["schemas"]["ServerResultResponse"]
| components["schemas"]["ServerUpdateResponse"] = JSON.parse(
data.toString()
);
if ("id" in message && message.id) {
const callback = this.callbackRouter[message.id];
if (callback !== undefined) {
callback(message);
delete this.callbackRouter[message.id];
}
} else if ("type" in message && message.type === "new_opportunity") {
if (this.websocketOpportunityCallback !== undefined) {
const convertedOpportunity = this.convertOpportunity(
message.opportunity
);
if (convertedOpportunity !== undefined) {
await this.websocketOpportunityCallback(convertedOpportunity);
}
}
} else if ("error" in message) {
// Can not route error messages to the callback router as they don't have an id
console.error(message.error);
}
});
}
/**
* Converts an opportunity from the server to the client format
* Returns undefined if the opportunity version is not supported
* @param opportunity
*/
private convertOpportunity(
opportunity: components["schemas"]["OpportunityParamsWithMetadata"]
): Opportunity | undefined {
if (opportunity.version != "v1") {
console.warn(
`Can not handle opportunity version: ${opportunity.version}. Please upgrade your client.`
);
return undefined;
}
return {
chainId: opportunity.chain_id,
opportunityId: opportunity.opportunity_id,
permissionKey: checkHex(opportunity.permission_key),
contract: checkAddress(opportunity.contract),
calldata: checkHex(opportunity.calldata),
value: BigInt(opportunity.value),
repayTokens: opportunity.repay_tokens.map(checkTokenQty),
receiptTokens: opportunity.receipt_tokens.map(checkTokenQty),
};
}
public setOpportunityHandler(
callback: (opportunity: Opportunity) => Promise<void>
) {
this.websocketOpportunityCallback = callback;
}
/**
* Subscribes to the specified chains
*
* The opportunity handler will be called for opportunities on the specified chains
* If the opportunity handler is not set, an error will be thrown
* @param chains
*/
async subscribeChains(chains: string[]) {
if (this.websocketOpportunityCallback === undefined) {
throw new Error("Opportunity handler not set");
}
return this.sendWebsocketMessage({
method: "subscribe",
params: {
chain_ids: chains,
},
});
}
/**
* Unsubscribes from the specified chains
*
* The opportunity handler will no longer be called for opportunities on the specified chains
* @param chains
*/
async unsubscribeChains(chains: string[]) {
return this.sendWebsocketMessage({
method: "unsubscribe",
params: {
chain_ids: chains,
},
});
}
async sendWebsocketMessage(
msg: components["schemas"]["ClientMessage"]
): Promise<void> {
const msg_with_id: components["schemas"]["ClientRequest"] = {
...msg,
id: (this.idCounter++).toString(),
};
return new Promise((resolve, reject) => {
this.callbackRouter[msg_with_id.id] = (response) => {
if (response.status === "success") {
resolve();
} else {
reject(response.result);
}
};
if (this.websocket === undefined) {
this.connectWebsocket();
}
if (this.websocket !== undefined) {
if (this.websocket.readyState === WebSocket.CONNECTING) {
this.websocket.on("open", () => {
this.websocket?.send(JSON.stringify(msg_with_id));
});
} else if (this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send(JSON.stringify(msg_with_id));
} else {
reject("Websocket connection closing or already closed");
}
}
setTimeout(() => {
delete this.callbackRouter[msg_with_id.id];
reject("Websocket response timeout");
}, this.wsOptions.response_timeout);
});
}
/**
@ -138,22 +301,11 @@ export class Client {
throw new Error("No opportunities found");
}
return opportunities.data.flatMap((opportunity) => {
if (opportunity.version != "v1") {
console.warn(
`Can not handle opportunity version: ${opportunity.version}. Please upgrade your client.`
);
const convertedOpportunity = this.convertOpportunity(opportunity);
if (convertedOpportunity === undefined) {
return [];
}
return {
chainId: opportunity.chain_id,
opportunityId: opportunity.opportunity_id,
permissionKey: checkHex(opportunity.permission_key),
contract: checkAddress(opportunity.contract),
calldata: checkHex(opportunity.calldata),
value: BigInt(opportunity.value),
repayTokens: opportunity.repay_tokens.map(checkTokenQty),
receiptTokens: opportunity.receipt_tokens.map(checkTokenQty),
};
return convertedOpportunity;
});
}

View File

@ -72,6 +72,24 @@ export interface components {
BidResult: {
status: string;
};
ClientMessage:
| {
/** @enum {string} */
method: "subscribe";
params: {
chain_ids: components["schemas"]["ChainId"][];
};
}
| {
/** @enum {string} */
method: "unsubscribe";
params: {
chain_ids: components["schemas"]["ChainId"][];
};
};
ClientRequest: components["schemas"]["ClientMessage"] & {
id: string;
};
ErrorBodyResponse: {
error: string;
};
@ -139,13 +157,37 @@ export interface components {
value: string;
};
/** @description Similar to OpportunityParams, but with the opportunity id included. */
OpportunityParamsWithId: components["schemas"]["OpportunityParams"] & {
OpportunityParamsWithMetadata: components["schemas"]["OpportunityParams"] & {
creation_time: components["schemas"]["UnixTimestamp"];
/**
* @description The opportunity unique id
* @example f47ac10b-58cc-4372-a567-0e02b2c3d479
*/
opportunity_id: string;
};
ServerResultMessage:
| {
/** @enum {string} */
status: "success";
}
| {
result: string;
/** @enum {string} */
status: "error";
};
/**
* @description This enum is used to send the result for a specific client request with the same id
* id is only None when the client message is invalid
*/
ServerResultResponse: components["schemas"]["ServerResultMessage"] & {
id?: string | null;
};
/** @description This enum is used to send an update to the client for any subscriptions made */
ServerUpdateResponse: {
opportunity: components["schemas"]["OpportunityParamsWithMetadata"];
/** @enum {string} */
type: "new_opportunity";
};
TokenQty: {
/**
* @description Token amount
@ -176,9 +218,10 @@ export interface components {
};
};
/** @description Similar to OpportunityParams, but with the opportunity id included. */
OpportunityParamsWithId: {
OpportunityParamsWithMetadata: {
content: {
"application/json": components["schemas"]["OpportunityParams"] & {
creation_time: components["schemas"]["UnixTimestamp"];
/**
* @description The opportunity unique id
* @example f47ac10b-58cc-4372-a567-0e02b2c3d479

269
package-lock.json generated
View File

@ -612,12 +612,14 @@
},
"express_relay/sdk/js": {
"name": "@pythnetwork/express-relay-evm-js",
"version": "0.1.0",
"version": "0.1.1",
"license": "Apache-2.0",
"dependencies": {
"isomorphic-ws": "^5.0.0",
"openapi-client-axios": "^7.5.4",
"openapi-fetch": "^0.8.2",
"viem": "^2.7.6"
"viem": "^2.7.6",
"ws": "^8.16.0"
},
"devDependencies": {
"@types/yargs": "^17.0.10",
@ -1265,6 +1267,14 @@
"node": ">=10.13.0"
}
},
"express_relay/sdk/js/node_modules/isomorphic-ws": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
"peerDependencies": {
"ws": "*"
}
},
"express_relay/sdk/js/node_modules/jest": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
@ -1828,6 +1838,35 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"express_relay/sdk/js/node_modules/openapi-typescript": {
"version": "6.5.5",
"resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.5.5.tgz",
"integrity": "sha512-pMsA8GrMQKtNOPPjKnJbDotA2UpKsIcTHecMw2Bl3M/2eWTVs8zAYBm/cgaE9Qz5GrcVCDIru9GQX/P9vxtUFg==",
"dev": true,
"dependencies": {
"ansi-colors": "^4.1.3",
"fast-glob": "^3.3.1",
"js-yaml": "^4.1.0",
"supports-color": "^9.4.0",
"undici": "^5.23.0",
"yargs-parser": "^21.1.1"
},
"bin": {
"openapi-typescript": "bin/cli.js"
}
},
"express_relay/sdk/js/node_modules/openapi-typescript/node_modules/supports-color": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"express_relay/sdk/js/node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@ -1973,6 +2012,26 @@
}
}
},
"express_relay/sdk/js/node_modules/viem/node_modules/ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"express_relay/sdk/js/node_modules/write-file-atomic": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
@ -1985,6 +2044,26 @@
"typedarray-to-buffer": "^3.1.5"
}
},
"express_relay/sdk/js/node_modules/ws": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"express_relay/sdk/js/node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@ -27568,21 +27647,21 @@
}
},
"node_modules/engine.io-client": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz",
"integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.2.3",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/engine.io-client/node_modules/ws": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"engines": {
"node": ">=10.0.0"
},
@ -27600,9 +27679,9 @@
}
},
"node_modules/engine.io-parser": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz",
"integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==",
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
"engines": {
"node": ">=10.0.0"
}
@ -41349,49 +41428,11 @@
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="
},
"node_modules/openapi-typescript": {
"version": "6.7.4",
"resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.7.4.tgz",
"integrity": "sha512-EZyeW9Wy7UDCKv0iYmKrq2pVZtquXiD/YHiUClAKqiMi42nodx/EQH11K6fLqjt1IZlJmVokrAsExsBMM2RROQ==",
"dev": true,
"dependencies": {
"ansi-colors": "^4.1.3",
"fast-glob": "^3.3.2",
"js-yaml": "^4.1.0",
"supports-color": "^9.4.0",
"undici": "^5.28.2",
"yargs-parser": "^21.1.1"
},
"bin": {
"openapi-typescript": "bin/cli.js"
}
},
"node_modules/openapi-typescript-helpers": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.5.tgz",
"integrity": "sha512-MRffg93t0hgGZbYTxg60hkRIK2sRuEOHEtCUgMuLgbCC33TMQ68AmxskzUlauzZYD47+ENeGV/ElI7qnWqrAxA=="
},
"node_modules/openapi-typescript/node_modules/supports-color": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/openapi-typescript/node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/optimism": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/optimism/-/optimism-0.16.2.tgz",
@ -49325,23 +49366,23 @@
}
},
"node_modules/socket.io-client": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.4.tgz",
"integrity": "sha512-ZpKteoA06RzkD32IbqILZ+Cnst4xewU7ZYK12aS1mzHftFFjpoMz69IuhP/nL25pJfao/amoPI527KnuhFm01g==",
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.2.3",
"socket.io-parser": "~4.2.1"
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
@ -67662,6 +67703,7 @@
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"eslint": "^8.56.0",
"isomorphic-ws": "^5.0.0",
"jest": "^27.5.1",
"openapi-client-axios": "^7.5.4",
"openapi-fetch": "^0.8.2",
@ -67669,6 +67711,7 @@
"prettier": "^2.6.2",
"typescript": "^5.1",
"viem": "^2.7.6",
"ws": "^8.16.0",
"yargs": "^17.4.1"
},
"dependencies": {
@ -68140,6 +68183,12 @@
"is-glob": "^4.0.3"
}
},
"isomorphic-ws": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
"requires": {}
},
"jest": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
@ -68586,6 +68635,28 @@
"p-locate": "^5.0.0"
}
},
"openapi-typescript": {
"version": "6.5.5",
"resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.5.5.tgz",
"integrity": "sha512-pMsA8GrMQKtNOPPjKnJbDotA2UpKsIcTHecMw2Bl3M/2eWTVs8zAYBm/cgaE9Qz5GrcVCDIru9GQX/P9vxtUFg==",
"dev": true,
"requires": {
"ansi-colors": "^4.1.3",
"fast-glob": "^3.3.1",
"js-yaml": "^4.1.0",
"supports-color": "^9.4.0",
"undici": "^5.23.0",
"yargs-parser": "^21.1.1"
},
"dependencies": {
"supports-color": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
"dev": true
}
}
},
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@ -68680,6 +68751,14 @@
"abitype": "1.0.0",
"isows": "1.0.3",
"ws": "8.13.0"
},
"dependencies": {
"ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"requires": {}
}
}
},
"write-file-atomic": {
@ -68694,6 +68773,12 @@
"typedarray-to-buffer": "^3.1.5"
}
},
"ws": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"requires": {}
},
"yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@ -83612,29 +83697,29 @@
}
},
"engine.io-client": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz",
"integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.2.3",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"xmlhttprequest-ssl": "~2.0.0"
},
"dependencies": {
"ws": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"requires": {}
}
}
},
"engine.io-parser": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz",
"integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw=="
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw=="
},
"enhanced-resolve": {
"version": "5.14.0",
@ -94531,34 +94616,6 @@
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="
},
"openapi-typescript": {
"version": "6.7.4",
"resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.7.4.tgz",
"integrity": "sha512-EZyeW9Wy7UDCKv0iYmKrq2pVZtquXiD/YHiUClAKqiMi42nodx/EQH11K6fLqjt1IZlJmVokrAsExsBMM2RROQ==",
"dev": true,
"requires": {
"ansi-colors": "^4.1.3",
"fast-glob": "^3.3.2",
"js-yaml": "^4.1.0",
"supports-color": "^9.4.0",
"undici": "^5.28.2",
"yargs-parser": "^21.1.1"
},
"dependencies": {
"supports-color": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz",
"integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==",
"dev": true
},
"yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true
}
}
},
"openapi-typescript-helpers": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.5.tgz",
@ -100948,20 +101005,20 @@
}
},
"socket.io-client": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.4.tgz",
"integrity": "sha512-ZpKteoA06RzkD32IbqILZ+Cnst4xewU7ZYK12aS1mzHftFFjpoMz69IuhP/nL25pJfao/amoPI527KnuhFm01g==",
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.2.3",
"socket.io-parser": "~4.2.1"
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
}
},
"socket.io-parser": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"