UNPKG

bitget-api

Version:

Complete Node.js & JavaScript SDK for Bitget V1-V3 REST APIs & WebSockets, with TypeScript & end-to-end tests.

227 lines 7.33 kB
export const WS_LOGGER_CATEGORY = { category: 'bitget-ws' }; export const WS_BASE_URL_MAP = { mixv1: { all: { livenet: 'wss://ws.bitget.com/mix/v1/stream', demo: 'NotSupportedForV1', }, }, spotv1: { all: { livenet: 'wss://ws.bitget.com/spot/v1/stream', demo: 'NotSupportedForV1', }, }, v2Public: { all: { livenet: 'wss://ws.bitget.com/v2/ws/public', demo: 'wss://wspap.bitget.com/v2/ws/public', }, }, v2Private: { all: { livenet: 'wss://ws.bitget.com/v2/ws/private', demo: 'wss://wspap.bitget.com/v2/ws/private', }, }, v3Public: { all: { livenet: 'wss://ws.bitget.com/v3/ws/public', demo: 'wss://wspap.bitget.com/v3/ws/public', }, }, v3Private: { all: { livenet: 'wss://ws.bitget.com/v3/ws/private', demo: 'wss://wspap.bitget.com/v3/ws/private', }, }, }; /** Should be one WS key per unique URL */ export const WS_KEY_MAP = { spotv1: 'spotv1', mixv1: 'mixv1', v2Public: 'v2Public', v2Private: 'v2Private', v3Public: 'v3Public', v3Private: 'v3Private', }; /** Any WS keys in this list will trigger auth on connect, if credentials are available */ export const WS_AUTH_ON_CONNECT_KEYS = [ WS_KEY_MAP.spotv1, WS_KEY_MAP.mixv1, WS_KEY_MAP.v2Private, WS_KEY_MAP.v3Private, ]; /** Any WS keys in this list will ALWAYS skip the authentication process, even if credentials are available */ export const PUBLIC_WS_KEYS = []; /** * Used to automatically determine if a sub request should be to a public or private ws (when there's two separate connections). * Unnecessary if there's only one connection to handle both public & private topics. */ export const PRIVATE_TOPICS = ['account', 'orders', 'positions', 'ordersAlgo']; export const PRIVATE_TOPICS_V2 = [ 'account', 'orders', 'positions', 'orders-algo', 'positions-history', 'orders-crossed', 'account-crossed', 'account-isolated', 'orders-isolated', ]; export const PRIVATE_TOPICS_V3 = [ 'account', 'position', 'fill', 'order', ]; export async function getWsUrl(wsKey, options, logger) { if (options.wsUrl) { return options.wsUrl; } const isDemoTrading = options.demoTrading; const networkKey = isDemoTrading ? 'demo' : 'livenet'; switch (wsKey) { case WS_KEY_MAP.spotv1: case WS_KEY_MAP.mixv1: { throw new Error('Use the WebsocketClient instead of WebsocketClientV2 for V1 websockets'); } case WS_KEY_MAP.v2Private: { return WS_BASE_URL_MAP.v2Private.all[networkKey]; } case WS_KEY_MAP.v2Public: { return WS_BASE_URL_MAP.v2Public.all[networkKey]; } case WS_KEY_MAP.v3Private: { return WS_BASE_URL_MAP.v3Private.all[networkKey]; } case WS_KEY_MAP.v3Public: { return WS_BASE_URL_MAP.v3Public.all[networkKey]; } default: { logger.error('getWsUrl(): Unhandled wsKey: ', { ...WS_LOGGER_CATEGORY, wsKey, }); throw neverGuard(wsKey, 'getWsUrl(): Unhandled wsKey'); } } } export function isPrivateChannel(channel) { return (PRIVATE_TOPICS.includes(channel) || PRIVATE_TOPICS_V2.includes(channel) || PRIVATE_TOPICS_V3.includes(channel)); } export function getWsKeyForTopicV1(subscribeEvent, // eslint-disable-next-line @typescript-eslint/no-unused-vars _isPrivate) { const instType = subscribeEvent.instType.toUpperCase(); switch (instType) { case 'SP': case 'SPBL': { return WS_KEY_MAP.spotv1; } case 'MC': case 'UMCBL': case 'DMCBL': { return WS_KEY_MAP.mixv1; } default: { throw neverGuard(instType, `getWsKeyForTopicV1(): Unhandled market ${'instrumentId'}`); } } } export function getWsKeyForTopicV2(subscribeEvent, isPrivate) { return isPrivate || isPrivateChannel(subscribeEvent.channel) ? WS_KEY_MAP.v2Private : WS_KEY_MAP.v2Public; } /** Force subscription requests to be sent in smaller batches, if a number is returned */ export function getMaxTopicsPerSubscribeEvent(wsKey) { switch (wsKey) { case 'mixv1': case 'spotv1': case 'v2Public': case 'v2Private': case 'v3Public': case 'v3Private': { // Technically there doesn't seem to be a documented cap, but there is a size limit per request. Doesn't hurt to batch requests. return 15; } default: { throw neverGuard(wsKey, 'getWsKeyForTopic(): Unhandled wsKey'); } } } export const WS_ERROR_ENUM = { INVALID_ACCESS_KEY: 30011, }; export function neverGuard(x, msg) { return new Error(`Unhandled value exception "${x}", ${msg}`); } /** * #305: ws.terminate() is undefined in browsers. * This only works in node.js, not in browsers. * Does nothing if `ws` is undefined. Does nothing in browsers. */ export function safeTerminateWs(ws, fallbackToClose) { if (!ws) { return false; } if (typeof ws['terminate'] === 'function') { ws.terminate(); return true; } else if (fallbackToClose) { ws.close(); } return false; } /** * Users can conveniently pass topics as strings or objects (object has topic name + optional params). * * This method normalises topics into objects (object has topic name + optional params). */ export function getNormalisedTopicRequests(wsTopicRequests) { const normalisedTopicRequests = []; for (const wsTopicRequest of wsTopicRequests) { // passed as string, convert to object if (typeof wsTopicRequest === 'string') { const topicRequest = { topic: wsTopicRequest, payload: undefined, }; normalisedTopicRequests.push(topicRequest); continue; } // already a normalised object, thanks to user normalisedTopicRequests.push(wsTopicRequest); } return normalisedTopicRequests; } /** * WebSocket.ping() is not available in browsers. This is a simple check used to * disable heartbeats in browers, for exchanges that use native WebSocket ping/pong frames. */ export function isWSPingFrameAvailable() { return typeof WebSocket.prototype['ping'] === 'function'; } /** * WebSocket.pong() is not available in browsers. This is a simple check used to * disable heartbeats in browers, for exchanges that use native WebSocket ping/pong frames. */ export function isWSPongFrameAvailable() { return typeof WebSocket.prototype['pong'] === 'function'; } /** * WS API promises are stored using a primary key. This key is constructed using * properties found in every request & reply. */ export function getPromiseRefForWSAPIRequest(requestEvent) { // Responses don't have any other info we can use to connect them to the request. Just the "id" field... const promiseRef = [requestEvent.id].join('_'); return promiseRef; } //# sourceMappingURL=websocket-util.js.map