feat(): start websocket API client wrapper, chore(): misc typo fixes & cleaning

This commit is contained in:
tiagosiebler
2025-05-19 12:38:04 +01:00
parent b5e109d362
commit c4cc09489f
5 changed files with 150 additions and 13 deletions

View File

@@ -1,6 +1,7 @@
export * from './rest-client-v5'; export * from './rest-client-v5';
export * from './spot-client-v3'; export * from './spot-client-v3';
export * from './websocket-client'; export * from './websocket-client';
export * from './websocket-api-client';
export * from './util/logger'; export * from './util/logger';
export * from './util'; export * from './util';
export * from './types'; export * from './types';

View File

@@ -124,7 +124,7 @@ export abstract class BaseWebsocketClient<
*/ */
private wsStore: WsStore<TWSKey, WsTopicRequest<string>>; private wsStore: WsStore<TWSKey, WsTopicRequest<string>>;
protected logger: typeof DefaultLogger; public logger: typeof DefaultLogger;
protected options: WebsocketClientOptions; protected options: WebsocketClientOptions;

View File

@@ -3,6 +3,8 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export type LogParams = null | any; export type LogParams = null | any;
export type DefaultLogger = typeof DefaultLogger;
export const DefaultLogger = { export const DefaultLogger = {
/** Ping/pong events and other raw messages that might be noisy. Enable this while troubleshooting. */ /** Ping/pong events and other raw messages that might be noisy. Enable this while troubleshooting. */
trace: (..._params: LogParams): void => { trace: (..._params: LogParams): void => {

134
src/websocket-api-client.ts Normal file
View File

@@ -0,0 +1,134 @@
import { OrderParamsV5, OrderResultV5 } from './types';
import { WSAPIResponse } from './types/websockets/ws-api';
import { WSClientConfigurableOptions } from './types/websockets/ws-general';
import { DefaultLogger } from './util';
import { WS_KEY_MAP } from './util/websockets/websocket-util';
import { WebsocketClient } from './websocket-client';
/**
* Configurable options specific to only the REST-like WebsocketAPIClient
*/
export interface WSAPIClientConfigurableOptions {
/**
* Default: true
*
* Attach default event listeners, which will console log any high level
* events (opened/reconnecting/reconnected/etc).
*
* If you disable this, you should set your own event listeners
* on the embedded WS Client `wsApiClient.getWSClient().on(....)`.
*/
attachEventListeners: boolean;
}
/**
* This is a minimal Websocket API wrapper around the WebsocketClient.
*
* Some methods support passing in a custom "wsKey". This is a reference to which WS connection should
* be used to transmit that message. This is only useful if you wish to use an alternative wss
* domain that is supported by the SDK.
*
* Note: To use testnet, don't set the wsKey - use `testnet: true` in
* the constructor instead.
*
* Note: You can also directly use the sendWSAPIRequest() method to make WS API calls, but some
* may find the below methods slightly more intuitive.
*
* Refer to the WS API promises example for a more detailed example on using sendWSAPIRequest() directly:
* https://github.com/tiagosiebler/binance/blob/master/examples/WebSockets/ws-api-raw-promises.ts#L108
*/
export class WebsocketAPIClient {
private wsClient: WebsocketClient;
private logger: DefaultLogger;
private options: WSClientConfigurableOptions & WSAPIClientConfigurableOptions;
constructor(
options?: WSClientConfigurableOptions &
Partial<WSAPIClientConfigurableOptions>,
logger?: DefaultLogger,
) {
this.wsClient = new WebsocketClient(options, logger);
this.options = {
attachEventListeners: true,
...options,
};
this.logger = this.wsClient.logger;
this.setupDefaultEventListeners();
}
public getWSClient(): WebsocketClient {
return this.wsClient;
}
public setTimeOffsetMs(newOffset: number): void {
return this.getWSClient().setTimeOffsetMs(newOffset);
}
/*
* Bybit WebSocket API Methods
* https://bybit-exchange.github.io/docs/v5/websocket/trade/guideline
*/
/**
* Submit a new order
*
* @param params
* @returns
*/
submitNewOrder(
params: OrderParamsV5,
): Promise<WSAPIResponse<OrderResultV5, 'order.create'>> {
return this.wsClient.sendWSAPIRequest(
WS_KEY_MAP.v5PrivateTrade,
'order.create',
params,
);
}
/**
*
*
*
*
*
*
*
* Private methods for handling some of the convenience/automation provided by the WS API Client
*
*
*
*
*
*
*
*/
private setupDefaultEventListeners() {
if (this.options.attachEventListeners) {
/**
* General event handlers for monitoring the WebsocketClient
*/
this.wsClient
.on('open', (data) => {
console.log(new Date(), 'ws connected', data.wsKey);
})
.on('reconnect', ({ wsKey }) => {
console.log(new Date(), 'ws automatically reconnecting.... ', wsKey);
})
.on('reconnected', (data) => {
console.log(new Date(), 'ws has reconnected ', data?.wsKey);
})
.on('authenticated', (data) => {
console.info(new Date(), 'ws has authenticated ', data?.wsKey);
})
.on('exception', (data) => {
console.error(new Date(), 'ws exception: ', JSON.stringify(data));
});
}
}
}

View File

@@ -343,23 +343,23 @@ export class WebsocketClient extends BaseWebsocketClient<
// do not trigger excess property checks // do not trigger excess property checks
// Without these overloads, TypeScript won't complain if you include an // Without these overloads, TypeScript won't complain if you include an
// unexpected property with your request (if it doesn't clash with an existing property) // unexpected property with your request (if it doesn't clash with an existing property)
sendWSAPIRequest<TWSOpreation extends WSAPIOperation = 'order.create'>( sendWSAPIRequest<TWSOperation extends WSAPIOperation = 'order.create'>(
wsKey: typeof WS_KEY_MAP.v5PrivateTrade, wsKey: typeof WS_KEY_MAP.v5PrivateTrade,
operation: TWSOpreation, operation: TWSOperation,
params: WsAPITopicRequestParamMap[TWSOpreation], params: WsAPITopicRequestParamMap[TWSOperation],
): Promise<WsAPIOperationResponseMap[TWSOpreation]>; ): Promise<WsAPIOperationResponseMap[TWSOperation]>;
sendWSAPIRequest<TWSOpreation extends WSAPIOperation = 'order.amend'>( sendWSAPIRequest<TWSOperation extends WSAPIOperation = 'order.amend'>(
wsKey: typeof WS_KEY_MAP.v5PrivateTrade, wsKey: typeof WS_KEY_MAP.v5PrivateTrade,
operation: TWSOpreation, operation: TWSOperation,
params: WsAPITopicRequestParamMap[TWSOpreation], params: WsAPITopicRequestParamMap[TWSOperation],
): Promise<WsAPIOperationResponseMap[TWSOpreation]>; ): Promise<WsAPIOperationResponseMap[TWSOperation]>;
sendWSAPIRequest<TWSOpreation extends WSAPIOperation = 'order.cancel'>( sendWSAPIRequest<TWSOperation extends WSAPIOperation = 'order.cancel'>(
wsKey: typeof WS_KEY_MAP.v5PrivateTrade, wsKey: typeof WS_KEY_MAP.v5PrivateTrade,
operation: TWSOpreation, operation: TWSOperation,
params: WsAPITopicRequestParamMap[TWSOpreation], params: WsAPITopicRequestParamMap[TWSOperation],
): Promise<WsAPIOperationResponseMap[TWSOpreation]>; ): Promise<WsAPIOperationResponseMap[TWSOperation]>;
async sendWSAPIRequest< async sendWSAPIRequest<
TWSKey extends keyof WsAPIWsKeyTopicMap, TWSKey extends keyof WsAPIWsKeyTopicMap,