binance
Version:
Professional Node.js & JavaScript SDK for Binance REST APIs & WebSockets, with TypeScript & end-to-end tests.
610 lines • 24.8 kB
JavaScript
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WS_ERROR_ENUM = exports.WS_AUTH_ON_CONNECT_KEYS = exports.WS_KEY_MM_URL_MAP = exports.WS_KEY_URL_MAP = exports.WS_KEYS_FUTURES = exports.WS_KEYS_SPOT = exports.WS_KEY_MAP = exports.EVENT_TYPES_USER_DATA = exports.WS_LOGGER_CATEGORY = void 0;
exports.getWsURLSuffix = getWsURLSuffix;
exports.isPrivateWsTopic = isPrivateWsTopic;
exports.getTestnetWsKey = getTestnetWsKey;
exports.getWsUrl = getWsUrl;
exports.getMaxTopicsPerSubscribeEvent = getMaxTopicsPerSubscribeEvent;
exports.safeTerminateWs = safeTerminateWs;
exports.getPromiseRefForWSAPIRequest = getPromiseRefForWSAPIRequest;
exports.getNormalisedTopicRequests = getNormalisedTopicRequests;
exports.getTopicsPerWSKey = getTopicsPerWSKey;
exports.parseEventTypeFromMessage = parseEventTypeFromMessage;
exports.resolveUserDataMarketForWsKey = resolveUserDataMarketForWsKey;
exports.resolveWsKeyForLegacyMarket = resolveWsKeyForLegacyMarket;
exports.parseRawWsMessageLegacy = parseRawWsMessageLegacy;
exports.parseRawWsMessage = parseRawWsMessage;
exports.getContextFromWsKey = getContextFromWsKey;
exports.getLegacyWsStoreKeyWithContext = getLegacyWsStoreKeyWithContext;
exports.getLegacyWsKeyContext = getLegacyWsKeyContext;
exports.getRealWsKeyFromDerivedWsKey = getRealWsKeyFromDerivedWsKey;
exports.appendEventMarket = appendEventMarket;
exports.isWSPingFrameAvailable = isWSPingFrameAvailable;
exports.isWSPongFrameAvailable = isWSPongFrameAvailable;
/* eslint-disable @typescript-eslint/no-unused-vars */
const isomorphic_ws_1 = __importDefault(require("isomorphic-ws"));
const typeGuards_1 = require("../typeGuards");
exports.WS_LOGGER_CATEGORY = { category: 'binance-ws' };
exports.EVENT_TYPES_USER_DATA = [
'balanceUpdate',
'executionReport',
'listStatus',
'listenKeyExpired',
'outboundAccountPosition',
'ACCOUNT_CONFIG_UPDATE',
'ACCOUNT_UPDATE',
'MARGIN_CALL',
'ORDER_TRADE_UPDATE',
'TRADE_LITE',
'CONDITIONAL_ORDER_TRIGGER_REJECT',
];
exports.WS_KEY_MAP = {
// https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams
main: 'main', // spot, margin, isolated margin, user data
main2: 'main2', // spot, margin, isolated margin, user data | alternative
main3: 'main3', // spot, margin, isolated margin | alternative | MARKET DATA ONLY | NO USER DATA
// https://developers.binance.com/docs/binance-spot-api-docs/testnet/web-socket-streams#general-wss-information
mainTestnetPublic: 'mainTestnetPublic',
mainTestnetUserData: 'mainTestnetUserData',
// https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/general-api-information
mainWSAPI: 'mainWSAPI', // trading over WS in spot, margin, isolated margin. User data supported too.
mainWSAPI2: 'mainWSAPI2', // trading over WS in spot, margin, isolated margin. User data supported too.
mainWSAPITestnet: 'mainWSAPITestnet', // trading over WS in spot, margin, isolated margin | TESTNET
// https://developers.binance.com/docs/margin_trading/risk-data-stream
marginRiskUserData: 'marginRiskUserData',
// https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-market-streams
// market data, user data
usdm: 'usdm',
// https://developers.binance.com/docs/derivatives/usds-margined-futures/general-info
usdmTestnet: 'usdmTestnet',
// https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-api-general-info
// ONLY WS API | NO USER DATA
usdmWSAPI: 'usdmWSAPI',
usdmWSAPITestnet: 'usdmWSAPITestnet',
// https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-market-streams
// market data, user data
coinm: 'coinm',
coinm2: 'coinm2',
// https://developers.binance.com/docs/derivatives/coin-margined-futures/general-info
coinmTestnet: 'coinmTestnet',
// https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-api-general-info
// ONLY WS API | NO USER DATA
coinmWSAPI: 'coinmWSAPI',
coinmWSAPITestnet: 'coinmWSAPITestnet',
eoptions: 'eoptions',
// optionsTestnet: 'optionsTestnet',
// https://developers.binance.com/docs/derivatives/portfolio-margin/user-data-streams
portfolioMarginUserData: 'portfolioMarginUserData',
// https://developers.binance.com/docs/derivatives/portfolio-margin-pro/portfolio-margin-pro-user-data-stream
portfolioMarginProUserData: 'portfolioMarginProUserData',
};
exports.WS_KEYS_SPOT = [
exports.WS_KEY_MAP.main,
exports.WS_KEY_MAP.main2,
exports.WS_KEY_MAP.main3,
exports.WS_KEY_MAP.mainTestnetPublic,
exports.WS_KEY_MAP.mainTestnetUserData,
exports.WS_KEY_MAP.mainWSAPI,
exports.WS_KEY_MAP.mainWSAPI2,
exports.WS_KEY_MAP.mainWSAPITestnet,
exports.WS_KEY_MAP.marginRiskUserData,
];
exports.WS_KEYS_FUTURES = [
exports.WS_KEY_MAP.usdm,
exports.WS_KEY_MAP.usdmTestnet,
exports.WS_KEY_MAP.usdmWSAPI,
exports.WS_KEY_MAP.usdmWSAPITestnet,
exports.WS_KEY_MAP.coinm,
exports.WS_KEY_MAP.coinm2,
exports.WS_KEY_MAP.coinmTestnet,
exports.WS_KEY_MAP.coinmWSAPI,
exports.WS_KEY_MAP.coinmWSAPITestnet,
];
exports.WS_KEY_URL_MAP = {
// https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams
main: 'wss://stream.binance.com:9443', // spot, margin, isolated margin, user data
main2: 'wss://stream.binance.com:443', // spot, margin, isolated margin, user data | alternative
main3: 'wss://data-stream.binance.vision', // spot, margin, isolated margin | alternative | MARKET DATA ONLY | NO USER DATA
// https://developers.binance.com/docs/binance-spot-api-docs/testnet/web-socket-streams#general-wss-information
mainTestnetPublic: 'wss://stream.testnet.binance.vision',
mainTestnetUserData: 'wss://stream.testnet.binance.vision:9443',
// https://developers.binance.com/docs/binance-spot-api-docs/websocket-api/general-api-information
mainWSAPI: 'wss://ws-api.binance.com:443',
mainWSAPI2: 'wss://ws-api.binance.com:9443',
mainWSAPITestnet: 'wss://ws-api.testnet.binance.vision',
// https://developers.binance.com/docs/margin_trading/risk-data-stream
// Margin websocket only support Cross Margin Accounts
marginRiskUserData: 'wss://margin-stream.binance.com',
// https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-market-streams
// market data, user data
usdm: 'wss://fstream.binance.com',
// https://developers.binance.com/docs/derivatives/usds-margined-futures/general-info
usdmTestnet: 'wss://stream.binancefuture.com',
// https://developers.binance.com/docs/derivatives/usds-margined-futures/websocket-api-general-info
// ONLY WS API
// Suffix is handled in getWsURLSuffix
usdmWSAPI: 'wss://ws-fapi.binance.com',
usdmWSAPITestnet: 'wss://testnet.binancefuture.com',
// https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-market-streams
// market data, user data
coinm: 'wss://dstream.binance.com',
coinm2: 'wss://dstream-auth.binance.com', // Warning, coinm2 requires a listenkey
// https://developers.binance.com/docs/derivatives/coin-margined-futures/general-info
coinmTestnet: 'wss://dstream.binancefuture.com',
// https://developers.binance.com/docs/derivatives/coin-margined-futures/websocket-api-general-info
// ONLY WS API | NO USER DATA
// Suffix is handled in getWsURLSuffix
coinmWSAPI: 'wss://ws-dapi.binance.com',
coinmWSAPITestnet: 'coinmWSAPITestnet',
// https://developers.binance.com/docs/derivatives/option/websocket-market-streams
// https://developers.binance.com/docs/derivatives/option/user-data-streams
eoptions: 'wss://nbstream.binance.com/eoptions',
// optionsTestnet: 'wss://testnetws.binanceops.com',
// https://developers.binance.com/docs/derivatives/portfolio-margin/user-data-streams
portfolioMarginUserData: 'wss://fstream.binance.com',
// https://developers.binance.com/docs/derivatives/portfolio-margin-pro/portfolio-margin-pro-user-data-stream
portfolioMarginProUserData: 'wss://fstream.binance.com',
};
exports.WS_KEY_MM_URL_MAP = {
// Spot connections - no MM endpoints
main: undefined,
main2: undefined,
main3: undefined,
mainTestnetPublic: undefined,
mainTestnetUserData: undefined,
mainWSAPI: undefined,
mainWSAPI2: undefined,
mainWSAPITestnet: undefined,
marginRiskUserData: undefined,
// USDM Futures MM endpoints
usdm: 'wss://fstream-mm.binance.com',
usdmTestnet: undefined, // No MM endpoint for testnet
usdmWSAPI: 'wss://ws-fapi-mm.binance.com',
usdmWSAPITestnet: undefined, // No MM endpoint for testnet
// COINM Futures MM endpoints
coinm: 'wss://dstream-mm.binance.com',
coinm2: undefined, // No MM endpoint for coinm2
coinmTestnet: undefined, // No MM endpoint for testnet
coinmWSAPI: 'wss://ws-dapi-mm.binance.com',
coinmWSAPITestnet: undefined, // No MM endpoint for testnet
// Other connections - no MM endpoints
eoptions: undefined,
portfolioMarginUserData: undefined,
portfolioMarginProUserData: undefined,
};
function getWsURLSuffix(wsKey, connectionType) {
switch (wsKey) {
case 'main':
case 'main2':
case 'main3':
case 'marginRiskUserData':
case 'mainTestnetPublic':
case 'mainTestnetUserData': {
switch (connectionType) {
case 'market':
return '/stream';
case 'userData':
return '/ws';
default: {
throw (0, typeGuards_1.neverGuard)(connectionType, `Unhandled connectionType "${wsKey}/${connectionType}"`);
}
}
}
case 'mainWSAPITestnet':
case 'mainWSAPI':
case 'mainWSAPI2': {
return '/ws-api/v3';
}
case 'usdm':
case 'usdmTestnet': {
switch (connectionType) {
case 'market':
return '/stream';
case 'userData':
return '/ws';
default: {
throw (0, typeGuards_1.neverGuard)(connectionType, `Unhandled connectionType "${wsKey}/${connectionType}"`);
}
}
}
case 'usdmWSAPI':
case 'usdmWSAPITestnet': {
return '/ws-fapi/v1';
}
case 'coinmWSAPI':
case 'coinmWSAPITestnet': {
return '/ws-dapi/v1';
}
case 'coinm':
case 'coinmTestnet':
case 'eoptions':
switch (connectionType) {
case 'market':
return '/stream';
case 'userData':
return '/ws';
default: {
throw (0, typeGuards_1.neverGuard)(connectionType, `Unhandled connectionType "${wsKey}/${connectionType}"`);
}
}
case 'coinm2':
return '/stream&listenKey=';
case 'portfolioMarginUserData':
return '/pm/ws'; // pm/ws/listenKeyHere
case 'portfolioMarginProUserData':
return '/pm-classic/ws';
default: {
throw (0, typeGuards_1.neverGuard)(wsKey, `Unhandled WsKey "${wsKey}"`);
}
}
}
exports.WS_AUTH_ON_CONNECT_KEYS = [];
/** Used to automatically determine if a sub request should be to the public or private ws (when there's two) */
const PRIVATE_TOPICS = [];
function isPrivateWsTopic(topic) {
return PRIVATE_TOPICS.includes(topic);
}
function getTestnetWsKey(wsKey) {
switch (wsKey) {
case exports.WS_KEY_MAP.mainTestnetPublic:
case exports.WS_KEY_MAP.mainTestnetUserData:
case exports.WS_KEY_MAP.coinmTestnet:
case exports.WS_KEY_MAP.usdmTestnet:
case exports.WS_KEY_MAP.mainWSAPITestnet:
case exports.WS_KEY_MAP.usdmWSAPITestnet:
case exports.WS_KEY_MAP.coinmWSAPITestnet: {
return wsKey;
}
case exports.WS_KEY_MAP.main:
case exports.WS_KEY_MAP.main2:
case exports.WS_KEY_MAP.main3: {
return exports.WS_KEY_MAP.mainTestnetUserData;
}
case exports.WS_KEY_MAP.mainWSAPI:
case exports.WS_KEY_MAP.mainWSAPI2: {
return exports.WS_KEY_MAP.mainWSAPITestnet;
}
case exports.WS_KEY_MAP.usdm: {
return exports.WS_KEY_MAP.usdmTestnet;
}
case exports.WS_KEY_MAP.usdmWSAPI: {
return exports.WS_KEY_MAP.usdmWSAPITestnet;
}
case exports.WS_KEY_MAP.coinm:
case exports.WS_KEY_MAP.coinm2: {
return exports.WS_KEY_MAP.coinmTestnet;
}
case exports.WS_KEY_MAP.coinmWSAPI: {
return exports.WS_KEY_MAP.coinmWSAPITestnet;
}
case exports.WS_KEY_MAP.marginRiskUserData:
case exports.WS_KEY_MAP.eoptions:
case exports.WS_KEY_MAP.portfolioMarginUserData:
case exports.WS_KEY_MAP.portfolioMarginProUserData: {
throw new Error(`Testnet not supported for "${wsKey}"`);
}
default:
throw (0, typeGuards_1.neverGuard)(wsKey, `Unhandled wsKey "${wsKey}"`);
}
}
function getWsUrl(wsKey, wsClientOptions, logger) {
const wsUrl = wsClientOptions.wsUrl;
if (wsUrl) {
return wsUrl;
}
const isTestnet = !!wsClientOptions.testnet;
const useMMSubdomain = !!wsClientOptions.useMMSubdomain;
const resolvedWsKey = isTestnet ? getTestnetWsKey(wsKey) : wsKey;
// Use MM endpoints if requested and available
if (useMMSubdomain && !isTestnet) {
const mmUrl = exports.WS_KEY_MM_URL_MAP[resolvedWsKey];
if (mmUrl) {
return mmUrl;
}
}
return exports.WS_KEY_URL_MAP[resolvedWsKey];
}
function getMaxTopicsPerSubscribeEvent(wsKey) {
switch (wsKey) {
// case 'v5': {
// if (wsKey === WS_KEY_MAP.v5SpotPublic) {
// return 10;
// }
// return null;
// }
default: {
return 250;
// throw neverGuard(wsKey, 'getMaxTopicsPerSubscribeEvent(): Unhandled wsKey');
}
}
}
exports.WS_ERROR_ENUM = {
NOT_AUTHENTICATED_SPOT_V3: '-1004',
API_ERROR_GENERIC: '10001',
API_SIGN_AUTH_FAILED: '10003',
USDC_OPTION_AUTH_FAILED: '3303006',
};
/**
* #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.
*/
function safeTerminateWs(ws, fallbackToClose) {
if (!ws) {
return false;
}
if (typeof ws['terminate'] === 'function') {
ws.terminate();
return true;
}
else if (fallbackToClose) {
ws.close();
}
return false;
}
/**
* WS API promises are stored using a primary key. This key is constructed using
* properties found in every request & reply.
*
* The counterpart to this is in resolveEmittableEvents
*/
function getPromiseRefForWSAPIRequest(wsKey, requestEvent) {
const promiseRef = [wsKey, requestEvent.id].join('_');
return promiseRef;
}
/**
* 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).
*/
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;
}
/**
* Groups topics in request into per-wsKey groups
* @param normalisedTopicRequests
* @param wsKey
* @param isPrivateTopic
* @returns
*/
function getTopicsPerWSKey(normalisedTopicRequests, wsKey) {
const perWsKeyTopics = {};
// Sort into per wsKey arrays, in case topics are mixed together for different wsKeys
for (const topicRequest of normalisedTopicRequests) {
const derivedWsKey = wsKey;
if (!perWsKeyTopics[derivedWsKey] ||
!Array.isArray(perWsKeyTopics[derivedWsKey])) {
perWsKeyTopics[derivedWsKey] = [];
}
perWsKeyTopics[derivedWsKey].push(topicRequest);
}
return perWsKeyTopics;
}
/**
* Some of the newer multiplex websocket topics don't include an eventType ("e") property.
*
* This attempts to extract that from the streamName, which is included with these incoming events.
*/
function parseEventTypeFromMessage(wsKey, parsedMsg) {
// console.log(`parseEventTypeFromMessage(${wsKey})`, parsedMsg);
if (parsedMsg === null || parsedMsg === void 0 ? void 0 : parsedMsg.e) {
return parsedMsg.e;
}
const streamName = (parsedMsg === null || parsedMsg === void 0 ? void 0 : parsedMsg.stream) || (parsedMsg === null || parsedMsg === void 0 ? void 0 : parsedMsg.streamName);
if (streamName && typeof streamName === 'string') {
// console.log(`parseEventTypeFromMessage(${wsKey}) `, streamName, parsedMsg);
const eventType = streamName.split('@');
// All symbol streams can be returned as is, just need to extract the left-most text before any @ or _
if (streamName.startsWith('!')) {
const subEventType = eventType[0].split('_');
return subEventType[0].replace('!', '');
}
// Per symbol streams can have the symbol trimmed off (string before first "@")
// E.g. btcusdt@kline_5m@+08:00 -> kline_5m@+08:00
if (eventType.length) {
// remove first, keep the rest rejoined
eventType.shift();
// Edge case, for european options, the suffix is a variable date so will never match the map
if (wsKey === 'eoptions') {
return eventType[0];
}
return eventType.join('@');
}
console.error('parseEventTypeFromMessage(): Cannot extract event type from message: ', parsedMsg);
}
if (parsedMsg === null || parsedMsg === void 0 ? void 0 : parsedMsg.data) {
return parseEventTypeFromMessage(wsKey, parsedMsg.data);
}
if (Array.isArray(parsedMsg) && parsedMsg.length) {
return parseEventTypeFromMessage(wsKey, parsedMsg[0]);
}
return;
}
function resolveUserDataMarketForWsKey(wsKey) {
switch (wsKey) {
case 'main':
case 'main2':
case 'main3':
case 'mainWSAPI':
case 'mainWSAPI2':
case 'marginRiskUserData':
return 'spot';
case 'mainTestnetPublic':
case 'mainTestnetUserData':
case 'mainWSAPITestnet':
return 'spotTestnet';
case 'usdm':
case 'usdmWSAPI':
return 'usdm';
case 'usdmTestnet':
case 'usdmWSAPITestnet':
return 'usdmTestnet';
case 'coinm':
case 'coinm2':
case 'coinmWSAPI':
return 'coinm';
case 'coinmTestnet':
case 'coinmWSAPITestnet':
return 'coinmTestnet';
case 'eoptions':
return 'options';
case 'portfolioMarginUserData':
case 'portfolioMarginProUserData':
return 'portfoliom';
default: {
throw (0, typeGuards_1.neverGuard)(wsKey, `resolveMarketForWsKey(): Unhandled WsKey "${wsKey}"`);
}
}
}
/**
* Used by the legacy subscribe* utility methods to determine which wsKey to route the subscription to.
*/
function resolveWsKeyForLegacyMarket(market) {
switch (market) {
case 'spot': {
return 'main';
}
case 'coinm': {
return 'coinm';
}
case 'usdm': {
return 'usdm';
}
}
}
function parseRawWsMessageLegacy(event, options) {
if (typeof event === 'string') {
const parsedEvent = typeof options.customParseJSONFn === 'function'
? options.customParseJSONFn(event)
: JSON.parse(event);
// WS events are wrapped into "data"
if (parsedEvent.data) {
if (typeof parsedEvent.data === 'string') {
return parseRawWsMessageLegacy(parsedEvent.data, options);
}
return parsedEvent.data;
}
// WS API wraps responses in "event"
if (parsedEvent.event) {
const { event } = parsedEvent, other = __rest(parsedEvent, ["event"]);
return Object.assign(Object.assign({}, other), event);
}
return parsedEvent;
}
if (event === null || event === void 0 ? void 0 : event.data) {
return parseRawWsMessageLegacy(event.data, options);
}
return event;
}
/**
* One simple purpose - extract JSON event from raw WS Message.
*
* Any mapping or additonal handling should not be done here.
*/
function parseRawWsMessage(event, options) {
// WS MessageLike->data (contains JSON as a string)
if (event === null || event === void 0 ? void 0 : event.data) {
return parseRawWsMessage(event.data, options);
}
if (typeof event === 'string') {
// For:
// - multiplex subscriptions, as of v3
// - user data, dedicated listen key connection
// - user data, via ws api (Without listen key)
// - ws api responses
if (typeof options.customParseJSONFn === 'function') {
return options.customParseJSONFn(event);
}
const parsedEvent = JSON.parse(event);
return parsedEvent;
}
return event;
}
/**
* @deprecated Only works for legacy WS client, where one connection exists per key
*/
function getContextFromWsKey(legacyWsKey) {
const [market, streamName, symbol, listenKey, wsKey, ...otherParams] = legacyWsKey.split('_');
return {
symbol: symbol === 'undefined' ? undefined : symbol,
legacyWsKey,
wsKey,
market: market,
isTestnet: market.includes('estnet'),
isUserData: legacyWsKey.includes('userData'),
streamName,
listenKey: listenKey === 'undefined' ? undefined : listenKey,
otherParams,
};
}
/**
* The legacy WS client creates a deterministic WS Key based on consistent input parameters
*/
function getLegacyWsStoreKeyWithContext(market, streamName, symbol = undefined, listenKey = undefined, ...otherParams) {
return [market, streamName, symbol, listenKey, ...otherParams].join('_');
}
function getLegacyWsKeyContext(wsKey) {
if (wsKey.indexOf('userData') !== -1) {
return getContextFromWsKey(wsKey);
}
return undefined;
}
function getRealWsKeyFromDerivedWsKey(wsKey) {
if (!wsKey.includes('userData')) {
return wsKey;
}
const legacyWsKeyContext = getLegacyWsKeyContext(wsKey);
if (!legacyWsKeyContext || !legacyWsKeyContext.wsKey) {
throw new Error(`getRealWsKeyFromDerivedWsKey(): no context found in supplied wsKey: "${wsKey}" | "${legacyWsKeyContext}"`);
}
return legacyWsKeyContext.wsKey;
}
function appendEventMarket(wsMsg, wsKey) {
const { market } = getContextFromWsKey(wsKey);
wsMsg.wsMarket = market;
wsMsg.wsKey = wsKey;
}
/**
* 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.
*/
function isWSPingFrameAvailable() {
return typeof isomorphic_ws_1.default.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.
*/
function isWSPongFrameAvailable() {
return typeof isomorphic_ws_1.default.prototype['pong'] === 'function';
}
//# sourceMappingURL=websocket-util.js.map