feat(v4.0.0-beta.5): BREAKING CHANGE: rename "error" event to "exception" to avoid unhandled exceptions
This commit is contained in:
@@ -91,7 +91,7 @@ function setWsClientEventListeners(
|
|||||||
websocketClient.on('reconnected', (data) => {
|
websocketClient.on('reconnected', (data) => {
|
||||||
console.log(new Date(), accountRef, 'ws has reconnected ', data?.wsKey);
|
console.log(new Date(), accountRef, 'ws has reconnected ', data?.wsKey);
|
||||||
});
|
});
|
||||||
websocketClient.on('error', (data) => {
|
websocketClient.on('exception', (data) => {
|
||||||
console.error(new Date(), accountRef, 'ws exception: ', data);
|
console.error(new Date(), accountRef, 'ws exception: ', data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ function setWsClientEventListeners(
|
|||||||
websocketClient.on('reconnected', (data) => {
|
websocketClient.on('reconnected', (data) => {
|
||||||
console.log(new Date(), accountRef, 'ws has reconnected ', data?.wsKey);
|
console.log(new Date(), accountRef, 'ws has reconnected ', data?.wsKey);
|
||||||
});
|
});
|
||||||
websocketClient.on('error', (data) => {
|
websocketClient.on('exception', (data) => {
|
||||||
console.error(new Date(), accountRef, 'ws exception: ', data);
|
console.error(new Date(), accountRef, 'ws exception: ', data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ wsClient.on('reconnected', (data) => {
|
|||||||
wsClient.on('authenticated', (data) => {
|
wsClient.on('authenticated', (data) => {
|
||||||
console.log('ws has authenticated ', data?.wsKey);
|
console.log('ws has authenticated ', data?.wsKey);
|
||||||
});
|
});
|
||||||
wsClient.on('error', (data) => {
|
wsClient.on('exception', (data) => {
|
||||||
console.error('ws error: ', data);
|
console.error('ws exception: ', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
|||||||
@@ -17,12 +17,8 @@ const logger = {
|
|||||||
* - Heartbeats/ping/pong/reconnects are all handled automatically.
|
* - Heartbeats/ping/pong/reconnects are all handled automatically.
|
||||||
* If a connection drops, the client will clean it up, respawn a fresh connection and resubscribe for you.
|
* If a connection drops, the client will clean it up, respawn a fresh connection and resubscribe for you.
|
||||||
*/
|
*/
|
||||||
const wsClient = new WebsocketClient(
|
|
||||||
{
|
const wsClient = new WebsocketClient();
|
||||||
// demoTrading: true,
|
|
||||||
},
|
|
||||||
logger,
|
|
||||||
);
|
|
||||||
|
|
||||||
wsClient.on('update', (data) => {
|
wsClient.on('update', (data) => {
|
||||||
console.log('raw message received ', JSON.stringify(data));
|
console.log('raw message received ', JSON.stringify(data));
|
||||||
@@ -40,9 +36,10 @@ wsClient.on('reconnect', ({ wsKey }) => {
|
|||||||
wsClient.on('reconnected', (data) => {
|
wsClient.on('reconnected', (data) => {
|
||||||
console.log('ws has reconnected ', data?.wsKey);
|
console.log('ws has reconnected ', data?.wsKey);
|
||||||
});
|
});
|
||||||
// wsClient.on('error', (data) => {
|
|
||||||
// console.error('ws exception: ', data);
|
wsClient.on('exception', (data) => {
|
||||||
// });
|
console.error('ws exception: ', data);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For public V5 topics, use the subscribeV5 method and include the API category this topic is for.
|
* For public V5 topics, use the subscribeV5 method and include the API category this topic is for.
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "bybit-api",
|
"name": "bybit-api",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "bybit-api",
|
"name": "bybit-api",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bybit-api",
|
"name": "bybit-api",
|
||||||
"version": "4.0.0-beta.4",
|
"version": "4.0.0-beta.5",
|
||||||
"description": "Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.",
|
"description": "Complete & robust Node.js SDK for Bybit's REST APIs and WebSockets, with TypeScript & strong end to end tests.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
} from './websockets';
|
} from './websockets';
|
||||||
import { WsOperation } from '../types/websockets/ws-api';
|
import { WsOperation } from '../types/websockets/ws-api';
|
||||||
|
|
||||||
|
type UseTheExceptionEventInstead = never;
|
||||||
|
|
||||||
interface WSClientEventMap<WsKey extends string> {
|
interface WSClientEventMap<WsKey extends string> {
|
||||||
/** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */
|
/** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */
|
||||||
open: (evt: { wsKey: WsKey; event: any }) => void;
|
open: (evt: { wsKey: WsKey; event: any }) => void;
|
||||||
@@ -39,10 +41,10 @@ interface WSClientEventMap<WsKey extends string> {
|
|||||||
/** Received data for topic */
|
/** Received data for topic */
|
||||||
update: (response: any & { wsKey: WsKey }) => void;
|
update: (response: any & { wsKey: WsKey }) => void;
|
||||||
/**
|
/**
|
||||||
* Exception from ws client OR custom listeners (e.g. if you throw inside your event handler)
|
* See for more information: https://github.com/tiagosiebler/bybit-api/issues/413
|
||||||
* @deprecated Use 'exception' instead. The 'error' event had the unintended consequence of throwing an unhandled promise rejection.
|
* @deprecated Use the 'exception' event instead. The 'error' event had the unintended consequence of throwing an unhandled promise rejection.
|
||||||
*/
|
*/
|
||||||
error: (response: any & { wsKey: WsKey; isWSAPIResponse?: boolean }) => void;
|
error: UseTheExceptionEventInstead;
|
||||||
/**
|
/**
|
||||||
* Exception from ws client OR custom listeners (e.g. if you throw inside your event handler)
|
* Exception from ws client OR custom listeners (e.g. if you throw inside your event handler)
|
||||||
*/
|
*/
|
||||||
@@ -57,12 +59,6 @@ interface WSClientEventMap<WsKey extends string> {
|
|||||||
}) => void;
|
}) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmittableEvent<TEvent = any> {
|
|
||||||
eventType: 'response' | 'update' | 'error' | 'authenticated';
|
|
||||||
event: TEvent;
|
|
||||||
isWSAPIResponse?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837
|
// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837
|
||||||
export interface BaseWebsocketClient<
|
export interface BaseWebsocketClient<
|
||||||
TWSKey extends string,
|
TWSKey extends string,
|
||||||
@@ -80,6 +76,12 @@ export interface BaseWebsocketClient<
|
|||||||
): boolean;
|
): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EmittableEvent<TEvent = any> {
|
||||||
|
eventType: 'response' | 'update' | 'exception' | 'authenticated';
|
||||||
|
event: TEvent;
|
||||||
|
isWSAPIResponse?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A midflight WS request event (e.g. subscribe to these topics).
|
* A midflight WS request event (e.g. subscribe to these topics).
|
||||||
*
|
*
|
||||||
@@ -167,12 +169,6 @@ export abstract class BaseWebsocketClient<
|
|||||||
authPrivateRequests: false,
|
authPrivateRequests: false,
|
||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
|
|
||||||
// add default error handling so this doesn't crash node (if the user didn't set a handler)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars, no-unused-vars
|
|
||||||
this.on('error', (e) => {
|
|
||||||
// console.log('basewserr: ', e);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -593,7 +589,7 @@ export abstract class BaseWebsocketClient<
|
|||||||
if (!error.message) {
|
if (!error.message) {
|
||||||
this.logger.error(`${context} due to unexpected error: `, error);
|
this.logger.error(`${context} due to unexpected error: `, error);
|
||||||
this.emit('response', { ...error, wsKey });
|
this.emit('response', { ...error, wsKey });
|
||||||
this.emit('error', { ...error, wsKey });
|
this.emit('exception', { ...error, wsKey });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +624,7 @@ export abstract class BaseWebsocketClient<
|
|||||||
this.logger.error(`parseWsError(${context}, ${error}, ${wsKey}) `, error);
|
this.logger.error(`parseWsError(${context}, ${error}, ${wsKey}) `, error);
|
||||||
|
|
||||||
this.emit('response', { ...error, wsKey });
|
this.emit('response', { ...error, wsKey });
|
||||||
this.emit('error', { ...error, wsKey });
|
this.emit('exception', { ...error, wsKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a signature, build the auth request and send it */
|
/** Get a signature, build the auth request and send it */
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ export class WebsocketClient extends BaseWebsocketClient<
|
|||||||
perWsKeyTopics[derivedWsKey] = [];
|
perWsKeyTopics[derivedWsKey] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
perWsKeyTopics[derivedWsKey].push(wsRequest);
|
perWsKeyTopics[derivedWsKey]!.push(wsRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises: Promise<unknown>[] = [];
|
const promises: Promise<unknown>[] = [];
|
||||||
@@ -755,7 +755,7 @@ export class WebsocketClient extends BaseWebsocketClient<
|
|||||||
}
|
}
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
eventType: 'error',
|
eventType: 'exception',
|
||||||
event: parsed,
|
event: parsed,
|
||||||
isWSAPIResponse: true,
|
isWSAPIResponse: true,
|
||||||
});
|
});
|
||||||
@@ -804,7 +804,7 @@ export class WebsocketClient extends BaseWebsocketClient<
|
|||||||
// Failed request
|
// Failed request
|
||||||
if (parsed.success === false) {
|
if (parsed.success === false) {
|
||||||
results.push({
|
results.push({
|
||||||
eventType: 'error',
|
eventType: 'exception',
|
||||||
event: parsed,
|
event: parsed,
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
@@ -851,7 +851,7 @@ export class WebsocketClient extends BaseWebsocketClient<
|
|||||||
exception: e,
|
exception: e,
|
||||||
eventData: event.data,
|
eventData: event.data,
|
||||||
},
|
},
|
||||||
eventType: 'error',
|
eventType: 'exception',
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.error('Failed to parse event data due to exception: ', {
|
this.logger.error('Failed to parse event data due to exception: ', {
|
||||||
|
|||||||
@@ -9,13 +9,17 @@ describe.skip('Public V5 Websocket client', () => {
|
|||||||
describe('Topics subscription confirmation', () => {
|
describe('Topics subscription confirmation', () => {
|
||||||
it('can subscribeV5 to LINEAR with valid topic', async () => {
|
it('can subscribeV5 to LINEAR with valid topic', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
api.subscribeV5(`publicTrade.${linearSymbol}`, linearCategory),
|
Promise.allSettled(
|
||||||
).resolves.toBeUndefined();
|
api.subscribeV5(`publicTrade.${linearSymbol}`, linearCategory),
|
||||||
|
),
|
||||||
|
).resolves.toStrictEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cannot subscribeV5 to LINEAR with valid topic', async () => {
|
it('cannot subscribeV5 to LINEAR with valid topic', async () => {
|
||||||
try {
|
try {
|
||||||
await api.subscribeV5(`publicTrade.${linearSymbol}X`, linearCategory);
|
await Promise.allSettled(
|
||||||
|
api.subscribeV5(`publicTrade.${linearSymbol}X`, linearCategory),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e).toBeDefined();
|
expect(e).toBeDefined();
|
||||||
expect(e).toMatch(`(publicTrade.${linearSymbol}X) failed to subscribe`);
|
expect(e).toMatch(`(publicTrade.${linearSymbol}X) failed to subscribe`);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function waitForSocketEvent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
wsClient.on(event, (e) => resolver(e));
|
wsClient.on(event, (e) => resolver(e));
|
||||||
wsClient.on('error', (e) => rejector(e));
|
wsClient.on('exception', (e) => rejector(e));
|
||||||
|
|
||||||
// if (event !== 'close') {
|
// if (event !== 'close') {
|
||||||
// wsClient.on('close', (event) => {
|
// wsClient.on('close', (event) => {
|
||||||
@@ -78,21 +78,21 @@ export function waitForSocketEvent(
|
|||||||
|
|
||||||
export function listenToSocketEvents(wsClient: WebsocketClient) {
|
export function listenToSocketEvents(wsClient: WebsocketClient) {
|
||||||
const retVal: Record<
|
const retVal: Record<
|
||||||
'update' | 'open' | 'response' | 'close' | 'error',
|
'update' | 'open' | 'response' | 'close' | 'exception',
|
||||||
typeof jest.fn
|
typeof jest.fn
|
||||||
> = {
|
> = {
|
||||||
open: jest.fn(),
|
open: jest.fn(),
|
||||||
response: jest.fn(),
|
response: jest.fn(),
|
||||||
update: jest.fn(),
|
update: jest.fn(),
|
||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
error: jest.fn(),
|
exception: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
wsClient.on('open', retVal.open);
|
wsClient.on('open', retVal.open);
|
||||||
wsClient.on('response', retVal.response);
|
wsClient.on('response', retVal.response);
|
||||||
wsClient.on('update', retVal.update);
|
wsClient.on('update', retVal.update);
|
||||||
wsClient.on('close', retVal.close);
|
wsClient.on('close', retVal.close);
|
||||||
wsClient.on('error', retVal.error);
|
wsClient.on('exception', retVal.exception);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...retVal,
|
...retVal,
|
||||||
@@ -101,7 +101,7 @@ export function listenToSocketEvents(wsClient: WebsocketClient) {
|
|||||||
wsClient.removeListener('response', retVal.response);
|
wsClient.removeListener('response', retVal.response);
|
||||||
wsClient.removeListener('update', retVal.update);
|
wsClient.removeListener('update', retVal.update);
|
||||||
wsClient.removeListener('close', retVal.close);
|
wsClient.removeListener('close', retVal.close);
|
||||||
wsClient.removeListener('error', retVal.error);
|
wsClient.removeListener('exception', retVal.exception);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user