chore(): deprecate pre-V5 authentication workflows
This commit is contained in:
@@ -272,7 +272,7 @@ export class RestClientV5 extends BaseRestClient {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
getClientType() {
|
getClientType() {
|
||||||
return REST_CLIENT_TYPE_ENUM.v3;
|
return REST_CLIENT_TYPE_ENUM.v5;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchServerTime(): Promise<number> {
|
async fetchServerTime(): Promise<number> {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import BaseRestClient from './util/BaseRestClient';
|
|||||||
*/
|
*/
|
||||||
export class SpotClientV3 extends BaseRestClient {
|
export class SpotClientV3 extends BaseRestClient {
|
||||||
getClientType() {
|
getClientType() {
|
||||||
// Follows the same authentication mechanism as other v3 APIs (e.g. USDC)
|
// Doesn't really matter here, since the only remaining endpoint does not require auth.
|
||||||
return REST_CLIENT_TYPE_ENUM.v3;
|
return REST_CLIENT_TYPE_ENUM.v5;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchServerTime(): Promise<number> {
|
async fetchServerTime(): Promise<number> {
|
||||||
|
|||||||
@@ -164,10 +164,6 @@ export default abstract class BaseRestClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSpotV1Client() {
|
|
||||||
return this.clientType === REST_CLIENT_TYPE_ENUM.spot;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(endpoint: string, params?: any) {
|
get(endpoint: string, params?: any) {
|
||||||
return this._call('GET', endpoint, params, true);
|
return this._call('GET', endpoint, params, true);
|
||||||
}
|
}
|
||||||
@@ -263,56 +259,34 @@ export default abstract class BaseRestClient {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// USDC endpoints, unified margin and a few others use a different way of authenticating requests (headers instead of params)
|
|
||||||
if (this.clientType === REST_CLIENT_TYPE_ENUM.v3) {
|
|
||||||
const signResult = await this.prepareSignParams(
|
|
||||||
method,
|
|
||||||
'v5auth',
|
|
||||||
params,
|
|
||||||
isPublicApi,
|
|
||||||
);
|
|
||||||
|
|
||||||
const headers: AxiosRequestConfig['headers'] = {
|
|
||||||
'X-BAPI-SIGN-TYPE': 2,
|
|
||||||
'X-BAPI-API-KEY': this.key,
|
|
||||||
'X-BAPI-TIMESTAMP': signResult.timestamp,
|
|
||||||
'X-BAPI-SIGN': signResult.sign,
|
|
||||||
'X-BAPI-RECV-WINDOW': signResult.recvWindow,
|
|
||||||
...options.headers,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (method === 'GET') {
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
headers,
|
|
||||||
params: signResult.originalParams,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
headers,
|
|
||||||
data: signResult.originalParams,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const signResult = await this.prepareSignParams(
|
const signResult = await this.prepareSignParams(
|
||||||
method,
|
method,
|
||||||
'v2auth',
|
'v5auth',
|
||||||
params,
|
params,
|
||||||
isPublicApi,
|
isPublicApi,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (method === 'GET' || this.isSpotV1Client()) {
|
const headers: AxiosRequestConfig['headers'] = {
|
||||||
|
'X-BAPI-SIGN-TYPE': 2,
|
||||||
|
'X-BAPI-API-KEY': this.key,
|
||||||
|
'X-BAPI-TIMESTAMP': signResult.timestamp,
|
||||||
|
'X-BAPI-SIGN': signResult.sign,
|
||||||
|
'X-BAPI-RECV-WINDOW': signResult.recvWindow,
|
||||||
|
...options.headers,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (method === 'GET') {
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
params: signResult.paramsWithSign,
|
headers,
|
||||||
|
params: signResult.originalParams,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
data: signResult.paramsWithSign,
|
headers,
|
||||||
|
data: signResult.originalParams,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,11 +450,7 @@ export default abstract class BaseRestClient {
|
|||||||
|
|
||||||
// Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen.
|
// Optional, set to 5000 by default. Increase if timestamp/recv_window errors are seen.
|
||||||
if (recvWindow) {
|
if (recvWindow) {
|
||||||
if (this.isSpotV1Client()) {
|
res.originalParams.recv_window = recvWindow;
|
||||||
res.originalParams.recvWindow = recvWindow;
|
|
||||||
} else {
|
|
||||||
res.originalParams.recv_window = recvWindow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const sortProperties = true;
|
const sortProperties = true;
|
||||||
const encodeValues = false;
|
const encodeValues = false;
|
||||||
|
|||||||
@@ -207,39 +207,13 @@ export function isTopicSubscriptionConfirmation(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isWSAPIResponse(
|
|
||||||
msg: unknown,
|
|
||||||
): msg is Omit<WSAPIResponse, 'wsKey'> {
|
|
||||||
if (typeof msg !== 'object' || !msg) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof msg['op'] !== 'string') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (WS_API_Operations as string[]).includes(msg['op']);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isTopicSubscriptionSuccess(
|
|
||||||
msg: unknown,
|
|
||||||
): msg is WebsocketSucceededTopicSubscriptionConfirmationEvent {
|
|
||||||
if (!isTopicSubscriptionConfirmation(msg)) return false;
|
|
||||||
return msg.success === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const APIID = 'bybitapinode';
|
export const APIID = 'bybitapinode';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to switch how authentication/requests work under the hood (primarily for SPOT since it's different there)
|
* Used to switch how authentication/requests work under the hood (primarily for SPOT since it's different there)
|
||||||
*/
|
*/
|
||||||
export const REST_CLIENT_TYPE_ENUM = {
|
export const REST_CLIENT_TYPE_ENUM = {
|
||||||
accountAsset: 'accountAsset',
|
v5: 'v5',
|
||||||
inverse: 'inverse',
|
|
||||||
inverseFutures: 'inverseFutures',
|
|
||||||
linear: 'linear',
|
|
||||||
spot: 'spot',
|
|
||||||
v3: 'v3',
|
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type RestClientType =
|
export type RestClientType =
|
||||||
|
|||||||
@@ -2,12 +2,15 @@
|
|||||||
* Use type guards to narrow down types with minimal efforts.
|
* Use type guards to narrow down types with minimal efforts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { WebsocketSucceededTopicSubscriptionConfirmationEvent } from '../types';
|
||||||
|
import { WSAPIResponse, WS_API_Operations } from '../types/websockets/ws-api';
|
||||||
import {
|
import {
|
||||||
WSAccountOrderEventV5,
|
WSAccountOrderEventV5,
|
||||||
WSExecutionEventV5,
|
WSExecutionEventV5,
|
||||||
WSOrderbookEventV5,
|
WSOrderbookEventV5,
|
||||||
WSPositionEventV5,
|
WSPositionEventV5,
|
||||||
} from '../types/websockets/ws-events';
|
} from '../types/websockets/ws-events';
|
||||||
|
import { isTopicSubscriptionConfirmation } from './requestUtils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type guard to detect a V5 orderbook event (delta & snapshots)
|
* Type guard to detect a V5 orderbook event (delta & snapshots)
|
||||||
@@ -92,3 +95,28 @@ export function isWsExecutionEventV5(
|
|||||||
|
|
||||||
return event['topic'] === 'execution';
|
return event['topic'] === 'execution';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function neverGuard(x: never, msg: string): Error {
|
||||||
|
return new Error(`Unhandled value exception "${x}", ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWSAPIResponse(
|
||||||
|
msg: unknown,
|
||||||
|
): msg is Omit<WSAPIResponse, 'wsKey'> {
|
||||||
|
if (typeof msg !== 'object' || !msg) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof msg['op'] !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (WS_API_Operations as string[]).includes(msg['op']);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTopicSubscriptionSuccess(
|
||||||
|
msg: unknown,
|
||||||
|
): msg is WebsocketSucceededTopicSubscriptionConfirmationEvent {
|
||||||
|
if (!isTopicSubscriptionConfirmation(msg)) return false;
|
||||||
|
return msg.success === true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { neverGuard } from './websockets';
|
import { neverGuard } from './typeGuards';
|
||||||
|
|
||||||
function bufferToB64(buffer: ArrayBuffer): string {
|
function bufferToB64(buffer: ArrayBuffer): string {
|
||||||
let binary = '';
|
let binary = '';
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
import { DefaultLogger } from '../logger';
|
import { DefaultLogger } from '../logger';
|
||||||
import { WSAPIRequest } from '../../types/websockets/ws-api';
|
import { WSAPIRequest } from '../../types/websockets/ws-api';
|
||||||
|
import { neverGuard } from '../typeGuards';
|
||||||
|
|
||||||
export const WS_LOGGER_CATEGORY = { category: 'bybit-ws' };
|
export const WS_LOGGER_CATEGORY = { category: 'bybit-ws' };
|
||||||
|
|
||||||
@@ -301,10 +302,6 @@ export const WS_ERROR_ENUM = {
|
|||||||
USDC_OPTION_AUTH_FAILED: '3303006',
|
USDC_OPTION_AUTH_FAILED: '3303006',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function neverGuard(x: never, msg: string): Error {
|
|
||||||
return new Error(`Unhandled value exception "${x}", ${msg}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #305: ws.terminate() is undefined in browsers.
|
* #305: ws.terminate() is undefined in browsers.
|
||||||
* This only works in node.js, not in browsers.
|
* This only works in node.js, not in browsers.
|
||||||
|
|||||||
Reference in New Issue
Block a user