@binance/common 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -140,6 +140,42 @@ function randomString() {
140
140
  return crypto.default.randomBytes(16).toString("hex");
141
141
  }
142
142
  /**
143
+ * Generates a cryptographically secure random 32-bit unsigned integer.
144
+ *
145
+ * Uses the Web Crypto API to generate a random value between 0 and 4,294,967,295 (2^32 - 1).
146
+ *
147
+ * @returns A random 32-bit unsigned integer.
148
+ */
149
+ function randomInteger() {
150
+ const array = new Uint32Array(1);
151
+ crypto.default.getRandomValues(array);
152
+ return array[0];
153
+ }
154
+ /**
155
+ * Normalizes a stream ID to ensure it is valid, generating a random ID if needed.
156
+ *
157
+ * For string inputs:
158
+ * - Returns the input if it's a valid 32-character hexadecimal string (case-insensitive)
159
+ * - Otherwise, generates a new random hexadecimal string using `randomString()`
160
+ *
161
+ * For number inputs:
162
+ * - Returns the input if it's a finite, non-negative integer within the safe integer range
163
+ * - Otherwise, generates a new random integer using `randomInteger()`
164
+ *
165
+ * For null or undefined inputs:
166
+ * - Generates a new random hexadecimal string using `randomString()`
167
+ *
168
+ * @param id - The stream ID to normalize (string, number, null, or undefined).
169
+ * @param streamIdIsStrictlyNumber - Boolean forcing an id to be a number or not.
170
+ * @returns A valid stream ID as either a 32-character hexadecimal string or a safe integer.
171
+ */
172
+ function normalizeStreamId(id, streamIdIsStrictlyNumber) {
173
+ const isValidNumber = typeof id === "number" && Number.isFinite(id) && Number.isInteger(id) && id >= 0 && id <= Number.MAX_SAFE_INTEGER;
174
+ if (streamIdIsStrictlyNumber || typeof id === "number") return isValidNumber ? id : randomInteger();
175
+ if (typeof id === "string") return id && /^[0-9a-f]{32}$/i.test(id) ? id : randomString();
176
+ return randomString();
177
+ }
178
+ /**
143
179
  * Validates the provided time unit string and returns it if it is either 'MILLISECOND' or 'MICROSECOND'.
144
180
  *
145
181
  * @param timeUnit - The time unit string to be validated.
@@ -682,7 +718,9 @@ const DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binan
682
718
  const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
683
719
  const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL = "wss://stream.binancefuture.com";
684
720
  const DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = "https://eapi.binance.com";
685
- const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://nbstream.binance.com/eoptions";
721
+ const DERIVATIVES_TRADING_OPTIONS_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
722
+ const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
723
+ const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_TESTNET_URL = "wss://fstream.binancefuture.com";
686
724
  const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = "https://papi.binance.com";
687
725
  const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
688
726
  const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm";
@@ -944,10 +982,11 @@ var WebsocketCommon = class WebsocketCommon extends WebsocketEventEmitter {
944
982
  * In 'single' mode, returns the first connection in the pool.
945
983
  * In 'pool' mode, filters and returns connections that are ready for use.
946
984
  * @param allowNonEstablishedWebsockets - Optional flag to include non-established WebSocket connections.
985
+ * @param urlPath - Optional URL path to filter connections.
947
986
  * @returns An array of available WebSocket connections.
948
987
  */
949
- getAvailableConnections(allowNonEstablishedWebsockets = false) {
950
- if (this.mode === "single") return [this.connectionPool[0]];
988
+ getAvailableConnections(allowNonEstablishedWebsockets = false, urlPath) {
989
+ if (this.mode === "single" && !urlPath) return [this.connectionPool[0]];
951
990
  return this.connectionPool.filter((connection) => this.isConnectionReady(connection, allowNonEstablishedWebsockets));
952
991
  }
953
992
  /**
@@ -956,10 +995,14 @@ var WebsocketCommon = class WebsocketCommon extends WebsocketEventEmitter {
956
995
  * If the connection mode is 'pool', it returns an available connection from the pool,
957
996
  * using a round-robin selection strategy. If no available connections are found, it throws an error.
958
997
  * @param allowNonEstablishedWebsockets - A boolean indicating whether to allow connections that are not established.
998
+ * @param urlPath - An optional URL path to filter connections.
959
999
  * @returns {WebsocketConnection} The selected WebSocket connection.
960
1000
  */
961
- getConnection(allowNonEstablishedWebsockets = false) {
962
- const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets);
1001
+ getConnection(allowNonEstablishedWebsockets = false, urlPath) {
1002
+ const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets, urlPath).filter((connection) => {
1003
+ if (urlPath) return connection.urlPath === urlPath;
1004
+ return true;
1005
+ });
963
1006
  if (availableConnections.length === 0) throw new Error("No available Websocket connections are ready.");
964
1007
  const selectedConnection = availableConnections[this.roundRobinIndex % availableConnections.length];
965
1008
  this.roundRobinIndex = (this.roundRobinIndex + 1) % availableConnections.length;
@@ -1157,14 +1200,15 @@ var WebsocketCommon = class WebsocketCommon extends WebsocketEventEmitter {
1157
1200
  /**
1158
1201
  * Connects all WebSocket connections in the pool
1159
1202
  * @param url - The Websocket server URL.
1203
+ * @param connections - An optional array of WebSocket connections to connect. If not provided, all connections in the pool are connected.
1160
1204
  * @returns A promise that resolves when all connections are established.
1161
1205
  */
1162
- async connectPool(url) {
1163
- const connectPromises = this.connectionPool.map((connection) => new Promise((resolve, reject) => {
1206
+ async connectPool(url, connections) {
1207
+ const connectPromises = (connections ?? this.connectionPool).map((connection) => new Promise((resolve, reject) => {
1164
1208
  this.initConnect(url, false, connection);
1165
- connection.ws?.on("open", () => resolve());
1166
- connection.ws?.on("error", (err) => reject(err));
1167
- connection.ws?.on("close", () => reject(/* @__PURE__ */ new Error("Connection closed unexpectedly.")));
1209
+ connection.ws?.once("open", () => resolve());
1210
+ connection.ws?.once("error", (err) => reject(err));
1211
+ connection.ws?.once("close", () => reject(/* @__PURE__ */ new Error("Connection closed unexpectedly.")));
1168
1212
  }));
1169
1213
  await Promise.all(connectPromises);
1170
1214
  }
@@ -1443,21 +1487,50 @@ var WebsocketAPIBase = class extends WebsocketCommon {
1443
1487
  }
1444
1488
  };
1445
1489
  var WebsocketStreamsBase = class extends WebsocketCommon {
1446
- constructor(configuration, connectionPool = []) {
1490
+ constructor(configuration, connectionPool = [], urlPaths = []) {
1447
1491
  super(configuration, connectionPool);
1448
1492
  this.streamConnectionMap = /* @__PURE__ */ new Map();
1493
+ this.streamIdIsStrictlyNumber = false;
1449
1494
  this.streamCallbackMap = /* @__PURE__ */ new Map();
1450
1495
  this.logger = Logger.getInstance();
1451
1496
  this.configuration = configuration;
1452
1497
  this.wsURL = configuration.wsURL;
1498
+ this.urlPaths = urlPaths;
1499
+ this.ensurePoolSizeForUrlPaths();
1500
+ }
1501
+ /**
1502
+ * Ensures the connection pool has the required size based on the configured mode and number of URL paths.
1503
+ *
1504
+ * If no URL paths are configured, the method returns early without modifications.
1505
+ * In 'pool' mode, the pool size is multiplied by the number of URL paths.
1506
+ * In 'single' mode, only one connection per URL path is maintained.
1507
+ *
1508
+ * New connections are initialized with unique IDs and default state flags when the pool
1509
+ * size is less than the expected size.
1510
+ *
1511
+ * @private
1512
+ * @returns {void}
1513
+ */
1514
+ ensurePoolSizeForUrlPaths() {
1515
+ if (this.urlPaths.length === 0) return;
1516
+ const expected = ((this.configuration?.mode ?? "single") === "pool" && this.configuration?.poolSize ? this.configuration.poolSize : 1) * this.urlPaths.length;
1517
+ while (this.connectionPool.length < expected) this.connectionPool.push({
1518
+ id: randomString(),
1519
+ closeInitiated: false,
1520
+ reconnectionPending: false,
1521
+ renewalPending: false,
1522
+ pendingRequests: /* @__PURE__ */ new Map(),
1523
+ pendingSubscriptions: []
1524
+ });
1453
1525
  }
1454
1526
  /**
1455
1527
  * Formats the WebSocket URL for a given stream or streams.
1456
1528
  * @param streams - Array of stream names to include in the URL.
1529
+ * @param urlPath - Optional URL path to include in the WebSocket URL.
1457
1530
  * @returns The formatted WebSocket URL with the provided streams.
1458
1531
  */
1459
- prepareURL(streams = []) {
1460
- let url = `${this.wsURL}/stream?streams=${streams.join("/")}`;
1532
+ prepareURL(streams = [], urlPath) {
1533
+ let url = `${urlPath ? `${this.wsURL}/${urlPath}` : this.wsURL}/stream?streams=${streams.join("/")}`;
1461
1534
  if (this.configuration?.timeUnit) try {
1462
1535
  const _timeUnit = validateTimeUnit(this.configuration.timeUnit);
1463
1536
  url = `${url}${url.includes("?") ? "&" : "?"}timeUnit=${_timeUnit}`;
@@ -1473,22 +1546,24 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1473
1546
  * @returns The formatted WebSocket URL with streams and optional parameters.
1474
1547
  */
1475
1548
  getReconnectURL(url, targetConnection) {
1476
- const streams = Array.from(this.streamConnectionMap.keys()).filter((stream) => this.streamConnectionMap.get(stream) === targetConnection);
1477
- return this.prepareURL(streams);
1549
+ const streams = Array.from(this.streamConnectionMap.keys()).filter((stream) => this.streamConnectionMap.get(stream) === targetConnection).map((key) => key.includes("::") ? key.split("::").slice(1).join("::") : key);
1550
+ return this.prepareURL(streams, targetConnection?.urlPath);
1478
1551
  }
1479
1552
  /**
1480
1553
  * Handles subscription to streams and assigns them to specific connections
1481
1554
  * @param streams Array of stream names to subscribe to
1555
+ * @param urlPath Optional URL path for the streams
1482
1556
  * @returns Map of connections to streams
1483
1557
  */
1484
- handleStreamAssignment(streams) {
1558
+ handleStreamAssignment(streams, urlPath) {
1485
1559
  const connectionStreamMap = /* @__PURE__ */ new Map();
1486
1560
  streams.forEach((stream) => {
1487
- if (!this.streamCallbackMap.has(stream)) this.streamCallbackMap.set(stream, /* @__PURE__ */ new Set());
1488
- let connection = this.streamConnectionMap.get(stream);
1561
+ const key = this.streamKey(stream, urlPath);
1562
+ if (!this.streamCallbackMap.has(key)) this.streamCallbackMap.set(key, /* @__PURE__ */ new Set());
1563
+ let connection = this.streamConnectionMap.get(key);
1489
1564
  if (!connection || connection.closeInitiated || connection.reconnectionPending) {
1490
- connection = this.getConnection(true);
1491
- this.streamConnectionMap.set(stream, connection);
1565
+ connection = this.getConnection(true, urlPath);
1566
+ this.streamConnectionMap.set(key, connection);
1492
1567
  }
1493
1568
  if (!connectionStreamMap.has(connection)) connectionStreamMap.set(connection, []);
1494
1569
  connectionStreamMap.get(connection)?.push(stream);
@@ -1505,7 +1580,7 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1505
1580
  const payload = {
1506
1581
  method: "SUBSCRIBE",
1507
1582
  params: streams,
1508
- id: id && /^[0-9a-f]{32}$/.test(id) ? id : randomString()
1583
+ id: normalizeStreamId(id, this.streamIdIsStrictlyNumber)
1509
1584
  };
1510
1585
  this.logger.debug("SUBSCRIBE", payload);
1511
1586
  this.send(JSON.stringify(payload), void 0, false, 0, connection);
@@ -1534,7 +1609,10 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1534
1609
  try {
1535
1610
  const parsedData = (0, json_with_bigint.JSONParse)(data);
1536
1611
  const streamName = parsedData?.stream;
1537
- if (streamName && this.streamCallbackMap.has(streamName)) this.streamCallbackMap.get(streamName)?.forEach((callback) => callback(parsedData.data));
1612
+ if (streamName) {
1613
+ const key = this.streamKey(streamName, connection?.urlPath);
1614
+ if (this.streamCallbackMap.has(key)) this.streamCallbackMap.get(key)?.forEach((callback) => callback(parsedData.data));
1615
+ }
1538
1616
  } catch (error) {
1539
1617
  this.logger.error("Failed to parse WebSocket message:", data, error);
1540
1618
  }
@@ -1552,6 +1630,15 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1552
1630
  super.onOpen(url, targetConnection, oldWSConnection);
1553
1631
  }
1554
1632
  /**
1633
+ * Generates a stream key by combining a stream name with an optional URL path.
1634
+ * @param stream - The stream name to use as the key or suffix.
1635
+ * @param urlPath - Optional URL path to prepend to the stream name.
1636
+ * @returns A stream key in the format `urlPath::stream` if urlPath is provided, otherwise just the stream name.
1637
+ */
1638
+ streamKey(stream, urlPath) {
1639
+ return urlPath ? `${urlPath}::${stream}` : stream;
1640
+ }
1641
+ /**
1555
1642
  * Connects to the WebSocket server and subscribes to the specified streams.
1556
1643
  * This method returns a Promise that resolves when the connection is established,
1557
1644
  * or rejects with an error if the connection fails to be established within 10 seconds.
@@ -1564,7 +1651,15 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1564
1651
  const timeout = setTimeout(() => {
1565
1652
  reject(/* @__PURE__ */ new Error("Websocket connection timed out"));
1566
1653
  }, 1e4);
1567
- this.connectPool(this.prepareURL(streams)).then(() => resolve()).catch((error) => reject(error)).finally(() => clearTimeout(timeout));
1654
+ const basePoolSize = (this.configuration?.mode ?? "single") === "pool" && this.configuration?.poolSize ? this.configuration.poolSize : 1;
1655
+ const connections = this.urlPaths.length > 0 ? this.urlPaths.map((path, i) => {
1656
+ const start = i * basePoolSize;
1657
+ const end = start + basePoolSize;
1658
+ const subset = this.connectionPool.slice(start, end);
1659
+ subset.forEach((c) => c.urlPath = path);
1660
+ return this.connectPool(this.prepareURL(streams, path), subset);
1661
+ }) : [this.connectPool(this.prepareURL(streams))];
1662
+ Promise.all(connections).then(() => resolve()).catch((error) => reject(error)).finally(() => clearTimeout(timeout));
1568
1663
  });
1569
1664
  }
1570
1665
  /**
@@ -1581,17 +1676,21 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1581
1676
  * Handles both single and pool modes
1582
1677
  * @param stream Single stream name or array of stream names to subscribe to
1583
1678
  * @param id Optional subscription ID
1679
+ * @param urlPath Optional URL path for the streams
1584
1680
  * @returns void
1585
1681
  */
1586
- subscribe(stream, id) {
1587
- const streams = (Array.isArray(stream) ? stream : [stream]).filter((stream$1) => !this.streamConnectionMap.has(stream$1));
1588
- this.handleStreamAssignment(streams).forEach((streams$1, connection) => {
1682
+ subscribe(stream, id, urlPath) {
1683
+ const streams = (Array.isArray(stream) ? stream : [stream]).filter((stream$1) => {
1684
+ const key = this.streamKey(stream$1, urlPath);
1685
+ return !this.streamConnectionMap.has(key);
1686
+ });
1687
+ this.handleStreamAssignment(streams, urlPath).forEach((assignedStreams, connection) => {
1589
1688
  if (!this.isConnected(connection)) {
1590
- this.logger.info(`Connection ${connection.id} is not ready. Queuing subscription for streams: ${streams$1}`);
1591
- connection.pendingSubscriptions?.push(...streams$1);
1689
+ this.logger.info(`Connection ${connection.id} is not ready. Queuing subscription for streams: ${assignedStreams}`);
1690
+ connection.pendingSubscriptions?.push(...assignedStreams);
1592
1691
  return;
1593
1692
  }
1594
- this.sendSubscriptionPayload(connection, streams$1, id);
1693
+ this.sendSubscriptionPayload(connection, assignedStreams, id);
1595
1694
  });
1596
1695
  }
1597
1696
  /**
@@ -1599,25 +1698,27 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1599
1698
  * Handles both single and pool modes
1600
1699
  * @param stream Single stream name or array of stream names to unsubscribe from
1601
1700
  * @param id Optional unsubscription ID
1701
+ * @param urlPath Optional URL path for the streams
1602
1702
  * @returns void
1603
1703
  */
1604
- unsubscribe(stream, id) {
1704
+ unsubscribe(stream, id, urlPath) {
1605
1705
  (Array.isArray(stream) ? stream : [stream]).forEach((stream$1) => {
1606
- const connection = this.streamConnectionMap.get(stream$1);
1706
+ const key = this.streamKey(stream$1, urlPath);
1707
+ const connection = this.streamConnectionMap.get(key);
1607
1708
  if (!connection || !connection.ws || !this.isConnected(connection)) {
1608
1709
  this.logger.warn(`Stream ${stream$1} not associated with an active connection.`);
1609
1710
  return;
1610
1711
  }
1611
- if (!this.streamCallbackMap.has(stream$1) || this.streamCallbackMap.get(stream$1)?.size === 0) {
1712
+ if (!this.streamCallbackMap.has(key) || this.streamCallbackMap.get(key)?.size === 0) {
1612
1713
  const payload = {
1613
1714
  method: "UNSUBSCRIBE",
1614
1715
  params: [stream$1],
1615
- id: id && /^[0-9a-f]{32}$/.test(id) ? id : randomString()
1716
+ id: normalizeStreamId(id, this.streamIdIsStrictlyNumber)
1616
1717
  };
1617
1718
  this.logger.debug("UNSUBSCRIBE", payload);
1618
1719
  this.send(JSON.stringify(payload), void 0, false, 0, connection);
1619
- this.streamConnectionMap.delete(stream$1);
1620
- this.streamCallbackMap.delete(stream$1);
1720
+ this.streamConnectionMap.delete(key);
1721
+ this.streamCallbackMap.delete(key);
1621
1722
  }
1622
1723
  });
1623
1724
  }
@@ -1627,7 +1728,9 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1627
1728
  * @returns `true` if the stream is currently subscribed, `false` otherwise.
1628
1729
  */
1629
1730
  isSubscribed(stream) {
1630
- return this.streamConnectionMap.has(stream);
1731
+ if (this.streamConnectionMap.has(stream)) return true;
1732
+ for (const key of this.streamConnectionMap.keys()) if (key.endsWith(`::${stream}`)) return true;
1733
+ return false;
1631
1734
  }
1632
1735
  };
1633
1736
  /**
@@ -1637,10 +1740,12 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1637
1740
  * @param {WebsocketAPIBase | WebsocketStreamsBase} websocketBase The WebSocket base instance
1638
1741
  * @param {string} streamOrId The stream identifier
1639
1742
  * @param {string} [id] Optional additional identifier
1743
+ * @param {string} [urlPath] Optional URL path for the stream
1640
1744
  * @returns {WebsocketStream<T>} A stream handler with methods to register callbacks and unsubscribe
1641
1745
  */
1642
- function createStreamHandler(websocketBase, streamOrId, id) {
1643
- if (websocketBase instanceof WebsocketStreamsBase) websocketBase.subscribe(streamOrId, id);
1746
+ function createStreamHandler(websocketBase, streamOrId, id, urlPath) {
1747
+ const key = websocketBase instanceof WebsocketStreamsBase ? websocketBase.streamKey(streamOrId, urlPath) : streamOrId;
1748
+ if (websocketBase instanceof WebsocketStreamsBase) websocketBase.subscribe(streamOrId, id, urlPath);
1644
1749
  let registeredCallback;
1645
1750
  return {
1646
1751
  on: (event, callback) => {
@@ -1650,14 +1755,14 @@ function createStreamHandler(websocketBase, streamOrId, id) {
1650
1755
  websocketBase.logger.error(`Error in stream callback: ${err}`);
1651
1756
  });
1652
1757
  };
1653
- const callbackSet = websocketBase.streamCallbackMap.get(streamOrId) ?? /* @__PURE__ */ new Set();
1758
+ const callbackSet = websocketBase.streamCallbackMap.get(key) ?? /* @__PURE__ */ new Set();
1654
1759
  callbackSet.add(registeredCallback);
1655
- websocketBase.streamCallbackMap.set(streamOrId, callbackSet);
1760
+ websocketBase.streamCallbackMap.set(key, callbackSet);
1656
1761
  }
1657
1762
  },
1658
1763
  unsubscribe: () => {
1659
- if (registeredCallback) websocketBase.streamCallbackMap.get(streamOrId)?.delete(registeredCallback);
1660
- if (websocketBase instanceof WebsocketStreamsBase) websocketBase.unsubscribe(streamOrId, id);
1764
+ if (registeredCallback) websocketBase.streamCallbackMap.get(key)?.delete(registeredCallback);
1765
+ if (websocketBase instanceof WebsocketStreamsBase) websocketBase.unsubscribe(streamOrId, id, urlPath);
1661
1766
  }
1662
1767
  };
1663
1768
  }
@@ -1680,7 +1785,9 @@ exports.DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL = DERIVATIVES_TRADIN
1680
1785
  exports.DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL;
1681
1786
  exports.DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL = DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL;
1682
1787
  exports.DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL;
1788
+ exports.DERIVATIVES_TRADING_OPTIONS_REST_API_TESTNET_URL = DERIVATIVES_TRADING_OPTIONS_REST_API_TESTNET_URL;
1683
1789
  exports.DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL;
1790
+ exports.DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_TESTNET_URL = DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_TESTNET_URL;
1684
1791
  exports.DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL;
1685
1792
  exports.DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL = DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL;
1686
1793
  exports.DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL;
@@ -1742,8 +1849,10 @@ exports.getSignature = getSignature;
1742
1849
  exports.getTimestamp = getTimestamp;
1743
1850
  exports.httpRequestFunction = httpRequestFunction;
1744
1851
  exports.normalizeScientificNumbers = normalizeScientificNumbers;
1852
+ exports.normalizeStreamId = normalizeStreamId;
1745
1853
  exports.parseCustomHeaders = parseCustomHeaders;
1746
1854
  exports.parseRateLimitHeaders = parseRateLimitHeaders;
1855
+ exports.randomInteger = randomInteger;
1747
1856
  exports.randomString = randomString;
1748
1857
  exports.removeEmptyValue = removeEmptyValue;
1749
1858
  exports.replaceWebsocketStreamsPlaceholders = replaceWebsocketStreamsPlaceholders;