UNPKG

binance

Version:

Professional Node.js & JavaScript SDK for Binance REST APIs & WebSockets, with TypeScript & end-to-end tests.

647 lines 27.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebsocketAPIClient = void 0; const typeGuards_1 = require("./util/typeGuards"); const websocket_util_1 = require("./util/websockets/websocket-util"); const websocket_client_1 = require("./websocket-client"); function getFuturesMarketWsKey(market) { if (market === 'usdm') { return websocket_util_1.WS_KEY_MAP.usdmWSAPI; } return websocket_util_1.WS_KEY_MAP.coinmWSAPI; } /** * 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 */ class WebsocketAPIClient { constructor(options, logger) { /** * Minimal state store around automating sticky "userDataStream.subscribe" sessions */ this.subscribedUserDataStreamState = {}; this.wsClient = new websocket_client_1.WebsocketClient(options, logger); this.options = Object.assign({ resubscribeUserDataStreamAfterReconnect: true, resubscribeUserDataStreamDelaySeconds: 2, attachEventListeners: true }, options); this.logger = this.wsClient.logger; this.setupDefaultEventListeners(); this.wsClient.on('reconnected', ({ wsKey }) => { this.handleWSReconnectedEvent({ wsKey }); }); } getWSClient() { return this.wsClient; } setTimeOffsetMs(newOffset) { return this.getWSClient().setTimeOffsetMs(newOffset); } /* * * SPOT - General requests * */ /** * Test connectivity to the WebSocket API */ testSpotConnectivity(wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'ping', undefined, { authIsOptional: true }); } /** * Test connectivity to the WebSocket API and get the current server time */ getSpotServerTime(wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'time', undefined, { authIsOptional: true }); } /** * Query current exchange trading rules, rate limits, and symbol information */ getSpotExchangeInfo(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'exchangeInfo', params, { authIsOptional: true }); } /* * * SPOT - Market data requests * */ /** * Get current order book * Note: If you need to continuously monitor order book updates, consider using WebSocket Streams */ getSpotOrderBook(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'depth', params, { authIsOptional: true }); } /** * Get recent trades * Note: If you need access to real-time trading activity, consider using WebSocket Streams */ getSpotRecentTrades(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'trades.recent', params, { authIsOptional: true }); } /** * Get historical trades * Note: If fromId is not specified, the most recent trades are returned */ getSpotHistoricalTrades(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'trades.historical', params, { authIsOptional: true }); } /** * Get aggregate trades * Note: An aggregate trade represents one or more individual trades that fill at the same time */ getSpotAggregateTrades(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'trades.aggregate', params, { authIsOptional: true }); } /** * Get klines (candlestick bars) * Note: If you need access to real-time kline updates, consider using WebSocket Streams */ getSpotKlines(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'klines', params, { authIsOptional: true }); } /** * Get klines (candlestick bars) optimized for presentation * Note: This request is similar to klines, having the same parameters and response */ getSpotUIKlines(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'uiKlines', params, { authIsOptional: true }); } /** * Get current average price for a symbol */ getSpotAveragePrice(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'avgPrice', params, { authIsOptional: true }); } /** * Get 24-hour rolling window price change statistics * Note: If you need to continuously monitor trading statistics, consider using WebSocket Streams */ getSpot24hrTicker(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'ticker.24hr', params, { authIsOptional: true }); } /** * Get price change statistics for a trading day */ getSpotTradingDayTicker(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'ticker.tradingDay', params, { authIsOptional: true }); } /** * Get rolling window price change statistics with a custom window * Note: Window size precision is limited to 1 minute */ getSpotTicker(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'ticker', params, { authIsOptional: true }); } /** * Get the latest market price for a symbol * Note: If you need access to real-time price updates, consider using WebSocket Streams */ getSpotSymbolPriceTicker(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'ticker.price', params, { authIsOptional: true }); } /** * Get the current best price and quantity on the order book * Note: If you need access to real-time order book ticker updates, consider using WebSocket Streams */ getSpotSymbolOrderBookTicker(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'ticker.book', params, { authIsOptional: true }); } /* * * SPOT - Session authentication requests * * Note: authentication is automatic * */ getSpotSessionStatus(wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'session.status'); } /* * * SPOT - Trading requests * */ /** * Submit a spot order */ submitNewSpotOrder(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'order.place', params); } /** * Test order placement * Note: Validates new order parameters and verifies your signature but does not send the order into the matching engine */ testSpotOrder(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'order.test', params); } /** * Check execution status of an order * Note: If both orderId and origClientOrderId parameters are specified, only orderId is used */ getSpotOrderStatus(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'order.status', params); } /** * Cancel an active order * Note: If both orderId and origClientOrderId parameters are specified, only orderId is used */ cancelSpotOrder(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'order.cancel', params); } /** * Cancel an existing order and immediately place a new order * Note: If both cancelOrderId and cancelOrigClientOrderId parameters are specified, only cancelOrderId is used */ cancelReplaceSpotOrder(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'order.cancelReplace', params); } /** * Reduce the quantity of an existing open order. * * Read for more info: https://developers.binance.com/docs/binance-spot-api-docs/faqs/order_amend_keep_priority */ amendSpotOrderKeepPriority(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'order.amend.keepPriority', params); } /** * Query execution status of all open orders * Note: If you need to continuously monitor order status updates, consider using WebSocket Streams */ getSpotOpenOrders(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'openOrders.status', params); } /** * Cancel all open orders on a symbol * Note: This includes orders that are part of an order list */ cancelAllSpotOpenOrders(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'openOrders.cancelAll', params); } /** * Place a new order list * Note: This is a deprecated endpoint, consider using placeOCOOrderList instead */ placeSpotOrderList(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'orderList.place', params); } /** * Place a new OCO (One-Cancels-the-Other) order list * Note: Activation of one order immediately cancels the other */ placeSpotOCOOrderList(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'orderList.place.oco', params); } /** * Place a new OTO (One-Triggers-the-Other) order list * Note: The pending order is placed only when the working order is fully filled */ placeSpotOTOOrderList(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'orderList.place.oto', params); } /** * Place a new OTOCO (One-Triggers-One-Cancels-the-Other) order list * Note: The pending orders are placed only when the working order is fully filled */ placeSpotOTOCOOrderList(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'orderList.place.otoco', params); } /** * Check execution status of an order list * Note: If both origClientOrderId and orderListId parameters are specified, only origClientOrderId is used */ getSpotOrderListStatus(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'orderList.status', params); } /** * Cancel an active order list * Note: If both orderListId and listClientOrderId parameters are specified, only orderListId is used */ cancelSpotOrderList(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'orderList.cancel', params); } /** * Query execution status of all open order lists * Note: If you need to continuously monitor order status updates, consider using WebSocket Streams */ getSpotOpenOrderLists(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'openOrderLists.status', params); } /** * Place a new order using Smart Order Routing (SOR) * Note: Only supports LIMIT and MARKET orders. quoteOrderQty is not supported */ placeSpotSOROrder(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'sor.order.place', params); } /** * Test new order creation and signature/recvWindow using Smart Order Routing (SOR) * Note: Creates and validates a new order but does not send it into the matching engine */ testSpotSOROrder(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'sor.order.test', params); } /* * * SPOT - Account requests * */ /** * Query information about your account, including balances * Note: Weight: 20 */ getSpotAccountInformation(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'account.status', params); } /** * Query your current unfilled order count for all intervals * Note: Weight: 40 */ getSpotOrderRateLimits(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'account.rateLimits.orders', params); } /** * Query information about all your orders – active, canceled, filled – filtered by time range * Note: Weight: 20 */ getSpotAllOrders(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'allOrders', params); } /** * Query information about all your order lists, filtered by time range * Note: Weight: 20 */ getSpotAllOrderLists(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'allOrderLists', params); } /** * Query information about all your trades, filtered by time range * Note: Weight: 20 */ getSpotMyTrades(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'myTrades', params); } /** * Displays the list of orders that were expired due to STP * Note: Weight varies based on query type (2-20) */ getSpotPreventedMatches(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'myPreventedMatches', params); } /** * Retrieves allocations resulting from SOR order placement * Note: Weight: 20 */ getSpotAllocations(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'myAllocations', params); } /** * Get current account commission rates * Note: Weight: 20 */ getSpotAccountCommission(params, wsKey) { return this.wsClient.sendWSAPIRequest(wsKey || websocket_util_1.WS_KEY_MAP.mainWSAPI, 'account.commission', params); } /* * * FUTURES - Market data requests * */ /** * Get current order book for futures * Note: If you need to continuously monitor order book updates, consider using WebSocket Streams */ getFuturesOrderBook(params) { return this.wsClient.sendWSAPIRequest(websocket_util_1.WS_KEY_MAP.usdmWSAPI, 'depth', params, { authIsOptional: true }); } /** * Get latest price for a futures symbol or symbols * Note: If symbol is not provided, prices for all symbols will be returned */ getFuturesSymbolPriceTicker(params) { return this.wsClient.sendWSAPIRequest(websocket_util_1.WS_KEY_MAP.usdmWSAPI, 'ticker.price', params, { authIsOptional: true }); } /** * Get best price/qty on the order book for a futures symbol or symbols * Note: If symbol is not provided, bookTickers for all symbols will be returned */ getFuturesSymbolOrderBookTicker(params) { return this.wsClient.sendWSAPIRequest(websocket_util_1.WS_KEY_MAP.usdmWSAPI, 'ticker.book', params, { authIsOptional: true }); } /* * * FUTURES - Trading requests * */ /** * Submit a futures order * * This endpoint is used for both USDM and COINM futures. */ submitNewFuturesOrder(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'order.place', params); } /** * Modify an existing futures order * * This endpoint is used for both USDM and COINM futures. */ modifyFuturesOrder(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'order.modify', params); } /** * Cancel a futures order * * This endpoint is used for both USDM and COINM futures. */ cancelFuturesOrder(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'order.cancel', params); } /** * Query futures order status * * This endpoint is used for both USDM and COINM futures. */ getFuturesOrderStatus(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'order.status', params); } /** * Get current position information (V2) * Note: Only symbols that have positions or open orders will be returned */ getFuturesPositionV2(params) { return this.wsClient.sendWSAPIRequest(websocket_util_1.WS_KEY_MAP.usdmWSAPI, 'v2/account.position', params); } /** * Get current position information * Note: Only symbols that have positions or open orders will be returned * * This endpoint is used for both USDM and COINM futures. */ getFuturesPosition(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'account.position', params); } /* * * FUTURES - Account requests * */ /** * Get account balance information (V2) * Note: Returns balance information for all assets */ getFuturesAccountBalanceV2(params) { return this.wsClient.sendWSAPIRequest(websocket_util_1.WS_KEY_MAP.usdmWSAPI, 'v2/account.balance', params); } /** * Get account balance information * Note: Returns balance information for all assets * * This endpoint is used for both USDM and COINM futures. */ getFuturesAccountBalance(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'account.balance', params); } /** * Get account information (V2) * Note: Returns detailed account information including positions and assets */ getFuturesAccountStatusV2(params) { return this.wsClient.sendWSAPIRequest(websocket_util_1.WS_KEY_MAP.usdmWSAPI, 'v2/account.status', params); } /** * Get account information * Note: Returns detailed account information including positions and assets * * This endpoint is used for both USDM and COINM futures. */ getFuturesAccountStatus(market, params) { return this.wsClient.sendWSAPIRequest(getFuturesMarketWsKey(market), 'account.status', params); } /* * * User data stream requests * */ /** * Start the user data stream for an apiKey (passed as param). * * Note: for "Spot" markets, the listenKey workflow is deprecated, use `subscribeUserDataStream()` instead. * * @param params * @param wsKey * @returns listenKey */ startUserDataStreamForKey(params, wsKey = websocket_util_1.WS_KEY_MAP.mainWSAPI) { return this.wsClient.sendWSAPIRequest(wsKey, 'userDataStream.start', params); } /** * Attempt to "ping" a listen key. * * Note: for "Spot" markets, the listenKey workflow is deprecated, use `subscribeUserDataStream()` instead. * * @param params * @param wsKey * @returns */ pingUserDataStreamForKey(params, wsKey = websocket_util_1.WS_KEY_MAP.mainWSAPI) { return this.wsClient.sendWSAPIRequest(wsKey, 'userDataStream.ping', params); } /** * Stop the user data stream listen key. * * @param params * @param wsKey * @returns */ stopUserDataStreamForKey(params, wsKey = websocket_util_1.WS_KEY_MAP.mainWSAPI) { return this.wsClient.sendWSAPIRequest(wsKey, 'userDataStream.stop', params); } /** * Request user data stream subscription on the currently authenticated connection. * * If reconnected, this will automatically resubscribe unless you unsubscribe manually. */ subscribeUserDataStream(wsKey) { return __awaiter(this, void 0, void 0, function* () { const resolvedWsKey = this.options.testnet ? (0, websocket_util_1.getTestnetWsKey)(wsKey) : wsKey; const res = yield this.wsClient.sendWSAPIRequest(resolvedWsKey, 'userDataStream.subscribe'); // Used to track whether this connection had the general "userDataStream.subscribe" called. // Used as part of `resubscribeUserDataStreamAfterReconnect` to know which connections to resub. this.subscribedUserDataStreamState[resolvedWsKey] = { subscribedAt: new Date(), subscribeAttempt: 0, }; return res; }); } /** * Unsubscribe from the user data stream subscription on the currently authenticated connection. * * If reconnected, this will also stop it from automatically resubscribing after reconnect. */ unsubscribeUserDataStream(wsKey) { const resolvedWsKey = this.options.testnet ? (0, websocket_util_1.getTestnetWsKey)(wsKey) : wsKey; delete this.subscribedUserDataStreamState[resolvedWsKey]; return this.wsClient.sendWSAPIRequest(resolvedWsKey, 'userDataStream.unsubscribe'); } /** * * * * * * * * Private methods for handling some of the convenience/automation provided by the WS API Client * * * * * * * */ 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('reconnecting', ({ wsKey }) => { console.log(new Date(), 'ws automatically reconnecting.... ', wsKey); }) .on('reconnected', (data) => { console.log(new Date(), 'ws has reconnected ', data === null || data === void 0 ? void 0 : data.wsKey); }) .on('authenticated', (data) => { console.info(new Date(), 'ws has authenticated ', data === null || data === void 0 ? void 0 : data.wsKey); }) .on('exception', (data) => { console.error(new Date(), 'ws exception: ', JSON.stringify(data)); }); } } tryResubscribeUserDataStream(wsKey) { return __awaiter(this, void 0, void 0, function* () { var _a; const subscribeState = this.getSubscribedUserDataStreamState(wsKey); const respawnDelayInSeconds = this.options.resubscribeUserDataStreamDelaySeconds; this.logger.error('tryResubscribeUserDataStream(): resubscribing to user data stream....', Object.assign(Object.assign({}, websocket_util_1.WS_LOGGER_CATEGORY), { wsKey })); try { if ((_a = this.subscribedUserDataStreamState[wsKey]) === null || _a === void 0 ? void 0 : _a.respawnTimeout) { clearTimeout(this.subscribedUserDataStreamState[wsKey].respawnTimeout); delete this.subscribedUserDataStreamState[wsKey].respawnTimeout; } subscribeState.subscribeAttempt++; yield this.subscribeUserDataStream(wsKey); this.subscribedUserDataStreamState[wsKey] = Object.assign(Object.assign({}, subscribeState), { subscribedAt: new Date(), subscribeAttempt: 0 }); this.logger.info('tryResubscribeUserDataStream()->ok', Object.assign(Object.assign(Object.assign({}, websocket_util_1.WS_LOGGER_CATEGORY), subscribeState), { wsKey })); } catch (e) { this.logger.error('tryResubscribeUserDataStream() exception - retry after timeout', Object.assign(Object.assign({}, websocket_util_1.WS_LOGGER_CATEGORY), { wsKey, exception: e, subscribeState })); subscribeState.respawnTimeout = setTimeout(() => { this.tryResubscribeUserDataStream(wsKey); }, 1000 * respawnDelayInSeconds); this.subscribedUserDataStreamState[wsKey] = Object.assign({}, subscribeState); } }); } getSubscribedUserDataStreamState(wsKey) { const subscribedState = this.subscribedUserDataStreamState[wsKey] || { subscribedAt: new Date(), subscribeAttempt: 0, }; return subscribedState; } handleWSReconnectedEvent(params) { var _a; const wsKey = params.wsKey; // Not a WS API connection if (!(0, typeGuards_1.isWSAPIWsKey)(wsKey)) { return; } const fnName = 'handleWSReconnectedEvent()'; // For the workflow without the listen key if ( // Feature enabled this.options.resubscribeUserDataStreamAfterReconnect && // Was subscribed to user data stream (without listen key) this.subscribedUserDataStreamState[wsKey]) { // Delay existing timer, if exists if ((_a = this.subscribedUserDataStreamState[wsKey]) === null || _a === void 0 ? void 0 : _a.respawnTimeout) { clearTimeout(this.subscribedUserDataStreamState[wsKey].respawnTimeout); delete this.subscribedUserDataStreamState[wsKey].respawnTimeout; this.logger.error(`${fnName} -> resubUserData(): Respawn timer already active while trying to queue respawn...delaying existing timer further...`, Object.assign(Object.assign({}, websocket_util_1.WS_LOGGER_CATEGORY), { wsKey })); } this.logger.trace(`${fnName} -> resubUserData():: queued resubscribe for wsKey user data stream`, Object.assign(Object.assign({}, websocket_util_1.WS_LOGGER_CATEGORY), { wsKey })); // Queue resubscribe workflow this.subscribedUserDataStreamState[wsKey].respawnTimeout = setTimeout(() => { this.tryResubscribeUserDataStream(wsKey); }, 1000 * this.options.resubscribeUserDataStreamDelaySeconds); } } } exports.WebsocketAPIClient = WebsocketAPIClient; //# sourceMappingURL=websocket-api-client.js.map