@binance/common 2.1.1 → 2.3.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
@@ -372,16 +372,17 @@ const httpRequestFunction = async function(axiosArgs, configuration) {
372
372
  else if (typeof responseData === "object") data = responseData;
373
373
  }
374
374
  const errorMsg = data.msg;
375
+ const errorCode = typeof data.code === "number" ? data.code : void 0;
375
376
  switch (status) {
376
- case 400: throw new BadRequestError(errorMsg);
377
- case 401: throw new UnauthorizedError(errorMsg);
378
- case 403: throw new ForbiddenError(errorMsg);
379
- case 404: throw new NotFoundError(errorMsg);
380
- case 418: throw new RateLimitBanError(errorMsg);
381
- case 429: throw new TooManyRequestsError(errorMsg);
377
+ case 400: throw new BadRequestError(errorMsg, errorCode);
378
+ case 401: throw new UnauthorizedError(errorMsg, errorCode);
379
+ case 403: throw new ForbiddenError(errorMsg, errorCode);
380
+ case 404: throw new NotFoundError(errorMsg, errorCode);
381
+ case 418: throw new RateLimitBanError(errorMsg, errorCode);
382
+ case 429: throw new TooManyRequestsError(errorMsg, errorCode);
382
383
  default:
383
384
  if (status >= 500 && status < 600) throw new ServerError(`Server error: ${status}`, status);
384
- throw new ConnectorClientError(errorMsg);
385
+ throw new ConnectorClientError(errorMsg, errorCode);
385
386
  }
386
387
  } else {
387
388
  if (retries > 0 && attempt >= retries) lastError = /* @__PURE__ */ new Error(`Request failed after ${retries} retries`);
@@ -718,7 +719,9 @@ const DERIVATIVES_TRADING_USDS_FUTURES_WS_API_TESTNET_URL = "wss://testnet.binan
718
719
  const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
719
720
  const DERIVATIVES_TRADING_USDS_FUTURES_WS_STREAMS_TESTNET_URL = "wss://stream.binancefuture.com";
720
721
  const DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = "https://eapi.binance.com";
721
- const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://nbstream.binance.com/eoptions";
722
+ const DERIVATIVES_TRADING_OPTIONS_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
723
+ const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = "wss://fstream.binance.com";
724
+ const DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_TESTNET_URL = "wss://fstream.binancefuture.com";
722
725
  const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = "https://papi.binance.com";
723
726
  const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_TESTNET_URL = "https://testnet.binancefuture.com";
724
727
  const DERIVATIVES_TRADING_PORTFOLIO_MARGIN_WS_STREAMS_PROD_URL = "wss://fstream.binance.com/pm";
@@ -756,10 +759,11 @@ const WALLET_REST_API_PROD_URL = "https://api.binance.com";
756
759
  * @param msg - An optional error message.
757
760
  */
758
761
  var ConnectorClientError = class ConnectorClientError extends Error {
759
- constructor(msg) {
762
+ constructor(msg, code) {
760
763
  super(msg || "An unexpected error occurred.");
761
764
  Object.setPrototypeOf(this, ConnectorClientError.prototype);
762
765
  this.name = "ConnectorClientError";
766
+ this.code = code;
763
767
  }
764
768
  };
765
769
  /**
@@ -780,10 +784,11 @@ var RequiredError = class RequiredError extends Error {
780
784
  * @param msg - An optional error message.
781
785
  */
782
786
  var UnauthorizedError = class UnauthorizedError extends Error {
783
- constructor(msg) {
787
+ constructor(msg, code) {
784
788
  super(msg || "Unauthorized access. Authentication required.");
785
789
  Object.setPrototypeOf(this, UnauthorizedError.prototype);
786
790
  this.name = "UnauthorizedError";
791
+ this.code = code;
787
792
  }
788
793
  };
789
794
  /**
@@ -791,10 +796,11 @@ var UnauthorizedError = class UnauthorizedError extends Error {
791
796
  * @param msg - An optional error message.
792
797
  */
793
798
  var ForbiddenError = class ForbiddenError extends Error {
794
- constructor(msg) {
799
+ constructor(msg, code) {
795
800
  super(msg || "Access to the requested resource is forbidden.");
796
801
  Object.setPrototypeOf(this, ForbiddenError.prototype);
797
802
  this.name = "ForbiddenError";
803
+ this.code = code;
798
804
  }
799
805
  };
800
806
  /**
@@ -802,10 +808,11 @@ var ForbiddenError = class ForbiddenError extends Error {
802
808
  * @param msg - An optional error message.
803
809
  */
804
810
  var TooManyRequestsError = class TooManyRequestsError extends Error {
805
- constructor(msg) {
811
+ constructor(msg, code) {
806
812
  super(msg || "Too many requests. You are being rate-limited.");
807
813
  Object.setPrototypeOf(this, TooManyRequestsError.prototype);
808
814
  this.name = "TooManyRequestsError";
815
+ this.code = code;
809
816
  }
810
817
  };
811
818
  /**
@@ -813,10 +820,11 @@ var TooManyRequestsError = class TooManyRequestsError extends Error {
813
820
  * @param msg - An optional error message.
814
821
  */
815
822
  var RateLimitBanError = class RateLimitBanError extends Error {
816
- constructor(msg) {
823
+ constructor(msg, code) {
817
824
  super(msg || "The IP address has been banned for exceeding rate limits.");
818
825
  Object.setPrototypeOf(this, RateLimitBanError.prototype);
819
826
  this.name = "RateLimitBanError";
827
+ this.code = code;
820
828
  }
821
829
  };
822
830
  /**
@@ -848,10 +856,11 @@ var NetworkError = class NetworkError extends Error {
848
856
  * @param msg - An optional error message.
849
857
  */
850
858
  var NotFoundError = class NotFoundError extends Error {
851
- constructor(msg) {
859
+ constructor(msg, code) {
852
860
  super(msg || "The requested resource was not found.");
853
861
  Object.setPrototypeOf(this, NotFoundError.prototype);
854
862
  this.name = "NotFoundError";
863
+ this.code = code;
855
864
  }
856
865
  };
857
866
  /**
@@ -859,10 +868,11 @@ var NotFoundError = class NotFoundError extends Error {
859
868
  * @param msg - An optional error message.
860
869
  */
861
870
  var BadRequestError = class BadRequestError extends Error {
862
- constructor(msg) {
871
+ constructor(msg, code) {
863
872
  super(msg || "The request was invalid or cannot be otherwise served.");
864
873
  Object.setPrototypeOf(this, BadRequestError.prototype);
865
874
  this.name = "BadRequestError";
875
+ this.code = code;
866
876
  }
867
877
  };
868
878
 
@@ -980,10 +990,11 @@ var WebsocketCommon = class WebsocketCommon extends WebsocketEventEmitter {
980
990
  * In 'single' mode, returns the first connection in the pool.
981
991
  * In 'pool' mode, filters and returns connections that are ready for use.
982
992
  * @param allowNonEstablishedWebsockets - Optional flag to include non-established WebSocket connections.
993
+ * @param urlPath - Optional URL path to filter connections.
983
994
  * @returns An array of available WebSocket connections.
984
995
  */
985
- getAvailableConnections(allowNonEstablishedWebsockets = false) {
986
- if (this.mode === "single") return [this.connectionPool[0]];
996
+ getAvailableConnections(allowNonEstablishedWebsockets = false, urlPath) {
997
+ if (this.mode === "single" && !urlPath) return [this.connectionPool[0]];
987
998
  return this.connectionPool.filter((connection) => this.isConnectionReady(connection, allowNonEstablishedWebsockets));
988
999
  }
989
1000
  /**
@@ -992,10 +1003,14 @@ var WebsocketCommon = class WebsocketCommon extends WebsocketEventEmitter {
992
1003
  * If the connection mode is 'pool', it returns an available connection from the pool,
993
1004
  * using a round-robin selection strategy. If no available connections are found, it throws an error.
994
1005
  * @param allowNonEstablishedWebsockets - A boolean indicating whether to allow connections that are not established.
1006
+ * @param urlPath - An optional URL path to filter connections.
995
1007
  * @returns {WebsocketConnection} The selected WebSocket connection.
996
1008
  */
997
- getConnection(allowNonEstablishedWebsockets = false) {
998
- const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets);
1009
+ getConnection(allowNonEstablishedWebsockets = false, urlPath) {
1010
+ const availableConnections = this.getAvailableConnections(allowNonEstablishedWebsockets, urlPath).filter((connection) => {
1011
+ if (urlPath) return connection.urlPath === urlPath;
1012
+ return true;
1013
+ });
999
1014
  if (availableConnections.length === 0) throw new Error("No available Websocket connections are ready.");
1000
1015
  const selectedConnection = availableConnections[this.roundRobinIndex % availableConnections.length];
1001
1016
  this.roundRobinIndex = (this.roundRobinIndex + 1) % availableConnections.length;
@@ -1193,14 +1208,15 @@ var WebsocketCommon = class WebsocketCommon extends WebsocketEventEmitter {
1193
1208
  /**
1194
1209
  * Connects all WebSocket connections in the pool
1195
1210
  * @param url - The Websocket server URL.
1211
+ * @param connections - An optional array of WebSocket connections to connect. If not provided, all connections in the pool are connected.
1196
1212
  * @returns A promise that resolves when all connections are established.
1197
1213
  */
1198
- async connectPool(url) {
1199
- const connectPromises = this.connectionPool.map((connection) => new Promise((resolve, reject) => {
1214
+ async connectPool(url, connections) {
1215
+ const connectPromises = (connections ?? this.connectionPool).map((connection) => new Promise((resolve, reject) => {
1200
1216
  this.initConnect(url, false, connection);
1201
- connection.ws?.on("open", () => resolve());
1202
- connection.ws?.on("error", (err) => reject(err));
1203
- connection.ws?.on("close", () => reject(/* @__PURE__ */ new Error("Connection closed unexpectedly.")));
1217
+ connection.ws?.once("open", () => resolve());
1218
+ connection.ws?.once("error", (err) => reject(err));
1219
+ connection.ws?.once("close", () => reject(/* @__PURE__ */ new Error("Connection closed unexpectedly.")));
1204
1220
  }));
1205
1221
  await Promise.all(connectPromises);
1206
1222
  }
@@ -1479,7 +1495,7 @@ var WebsocketAPIBase = class extends WebsocketCommon {
1479
1495
  }
1480
1496
  };
1481
1497
  var WebsocketStreamsBase = class extends WebsocketCommon {
1482
- constructor(configuration, connectionPool = []) {
1498
+ constructor(configuration, connectionPool = [], urlPaths = []) {
1483
1499
  super(configuration, connectionPool);
1484
1500
  this.streamConnectionMap = /* @__PURE__ */ new Map();
1485
1501
  this.streamIdIsStrictlyNumber = false;
@@ -1487,14 +1503,42 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1487
1503
  this.logger = Logger.getInstance();
1488
1504
  this.configuration = configuration;
1489
1505
  this.wsURL = configuration.wsURL;
1506
+ this.urlPaths = urlPaths;
1507
+ this.ensurePoolSizeForUrlPaths();
1508
+ }
1509
+ /**
1510
+ * Ensures the connection pool has the required size based on the configured mode and number of URL paths.
1511
+ *
1512
+ * If no URL paths are configured, the method returns early without modifications.
1513
+ * In 'pool' mode, the pool size is multiplied by the number of URL paths.
1514
+ * In 'single' mode, only one connection per URL path is maintained.
1515
+ *
1516
+ * New connections are initialized with unique IDs and default state flags when the pool
1517
+ * size is less than the expected size.
1518
+ *
1519
+ * @private
1520
+ * @returns {void}
1521
+ */
1522
+ ensurePoolSizeForUrlPaths() {
1523
+ if (this.urlPaths.length === 0) return;
1524
+ const expected = ((this.configuration?.mode ?? "single") === "pool" && this.configuration?.poolSize ? this.configuration.poolSize : 1) * this.urlPaths.length;
1525
+ while (this.connectionPool.length < expected) this.connectionPool.push({
1526
+ id: randomString(),
1527
+ closeInitiated: false,
1528
+ reconnectionPending: false,
1529
+ renewalPending: false,
1530
+ pendingRequests: /* @__PURE__ */ new Map(),
1531
+ pendingSubscriptions: []
1532
+ });
1490
1533
  }
1491
1534
  /**
1492
1535
  * Formats the WebSocket URL for a given stream or streams.
1493
1536
  * @param streams - Array of stream names to include in the URL.
1537
+ * @param urlPath - Optional URL path to include in the WebSocket URL.
1494
1538
  * @returns The formatted WebSocket URL with the provided streams.
1495
1539
  */
1496
- prepareURL(streams = []) {
1497
- let url = `${this.wsURL}/stream?streams=${streams.join("/")}`;
1540
+ prepareURL(streams = [], urlPath) {
1541
+ let url = `${urlPath ? `${this.wsURL}/${urlPath}` : this.wsURL}/stream?streams=${streams.join("/")}`;
1498
1542
  if (this.configuration?.timeUnit) try {
1499
1543
  const _timeUnit = validateTimeUnit(this.configuration.timeUnit);
1500
1544
  url = `${url}${url.includes("?") ? "&" : "?"}timeUnit=${_timeUnit}`;
@@ -1510,22 +1554,24 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1510
1554
  * @returns The formatted WebSocket URL with streams and optional parameters.
1511
1555
  */
1512
1556
  getReconnectURL(url, targetConnection) {
1513
- const streams = Array.from(this.streamConnectionMap.keys()).filter((stream) => this.streamConnectionMap.get(stream) === targetConnection);
1514
- return this.prepareURL(streams);
1557
+ const streams = Array.from(this.streamConnectionMap.keys()).filter((stream) => this.streamConnectionMap.get(stream) === targetConnection).map((key) => key.includes("::") ? key.split("::").slice(1).join("::") : key);
1558
+ return this.prepareURL(streams, targetConnection?.urlPath);
1515
1559
  }
1516
1560
  /**
1517
1561
  * Handles subscription to streams and assigns them to specific connections
1518
1562
  * @param streams Array of stream names to subscribe to
1563
+ * @param urlPath Optional URL path for the streams
1519
1564
  * @returns Map of connections to streams
1520
1565
  */
1521
- handleStreamAssignment(streams) {
1566
+ handleStreamAssignment(streams, urlPath) {
1522
1567
  const connectionStreamMap = /* @__PURE__ */ new Map();
1523
1568
  streams.forEach((stream) => {
1524
- if (!this.streamCallbackMap.has(stream)) this.streamCallbackMap.set(stream, /* @__PURE__ */ new Set());
1525
- let connection = this.streamConnectionMap.get(stream);
1569
+ const key = this.streamKey(stream, urlPath);
1570
+ if (!this.streamCallbackMap.has(key)) this.streamCallbackMap.set(key, /* @__PURE__ */ new Set());
1571
+ let connection = this.streamConnectionMap.get(key);
1526
1572
  if (!connection || connection.closeInitiated || connection.reconnectionPending) {
1527
- connection = this.getConnection(true);
1528
- this.streamConnectionMap.set(stream, connection);
1573
+ connection = this.getConnection(true, urlPath);
1574
+ this.streamConnectionMap.set(key, connection);
1529
1575
  }
1530
1576
  if (!connectionStreamMap.has(connection)) connectionStreamMap.set(connection, []);
1531
1577
  connectionStreamMap.get(connection)?.push(stream);
@@ -1571,7 +1617,10 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1571
1617
  try {
1572
1618
  const parsedData = (0, json_with_bigint.JSONParse)(data);
1573
1619
  const streamName = parsedData?.stream;
1574
- if (streamName && this.streamCallbackMap.has(streamName)) this.streamCallbackMap.get(streamName)?.forEach((callback) => callback(parsedData.data));
1620
+ if (streamName) {
1621
+ const key = this.streamKey(streamName, connection?.urlPath);
1622
+ if (this.streamCallbackMap.has(key)) this.streamCallbackMap.get(key)?.forEach((callback) => callback(parsedData.data));
1623
+ }
1575
1624
  } catch (error) {
1576
1625
  this.logger.error("Failed to parse WebSocket message:", data, error);
1577
1626
  }
@@ -1589,6 +1638,15 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1589
1638
  super.onOpen(url, targetConnection, oldWSConnection);
1590
1639
  }
1591
1640
  /**
1641
+ * Generates a stream key by combining a stream name with an optional URL path.
1642
+ * @param stream - The stream name to use as the key or suffix.
1643
+ * @param urlPath - Optional URL path to prepend to the stream name.
1644
+ * @returns A stream key in the format `urlPath::stream` if urlPath is provided, otherwise just the stream name.
1645
+ */
1646
+ streamKey(stream, urlPath) {
1647
+ return urlPath ? `${urlPath}::${stream}` : stream;
1648
+ }
1649
+ /**
1592
1650
  * Connects to the WebSocket server and subscribes to the specified streams.
1593
1651
  * This method returns a Promise that resolves when the connection is established,
1594
1652
  * or rejects with an error if the connection fails to be established within 10 seconds.
@@ -1601,7 +1659,15 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1601
1659
  const timeout = setTimeout(() => {
1602
1660
  reject(/* @__PURE__ */ new Error("Websocket connection timed out"));
1603
1661
  }, 1e4);
1604
- this.connectPool(this.prepareURL(streams)).then(() => resolve()).catch((error) => reject(error)).finally(() => clearTimeout(timeout));
1662
+ const basePoolSize = (this.configuration?.mode ?? "single") === "pool" && this.configuration?.poolSize ? this.configuration.poolSize : 1;
1663
+ const connections = this.urlPaths.length > 0 ? this.urlPaths.map((path, i) => {
1664
+ const start = i * basePoolSize;
1665
+ const end = start + basePoolSize;
1666
+ const subset = this.connectionPool.slice(start, end);
1667
+ subset.forEach((c) => c.urlPath = path);
1668
+ return this.connectPool(this.prepareURL(streams, path), subset);
1669
+ }) : [this.connectPool(this.prepareURL(streams))];
1670
+ Promise.all(connections).then(() => resolve()).catch((error) => reject(error)).finally(() => clearTimeout(timeout));
1605
1671
  });
1606
1672
  }
1607
1673
  /**
@@ -1618,17 +1684,21 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1618
1684
  * Handles both single and pool modes
1619
1685
  * @param stream Single stream name or array of stream names to subscribe to
1620
1686
  * @param id Optional subscription ID
1687
+ * @param urlPath Optional URL path for the streams
1621
1688
  * @returns void
1622
1689
  */
1623
- subscribe(stream, id) {
1624
- const streams = (Array.isArray(stream) ? stream : [stream]).filter((stream$1) => !this.streamConnectionMap.has(stream$1));
1625
- this.handleStreamAssignment(streams).forEach((streams$1, connection) => {
1690
+ subscribe(stream, id, urlPath) {
1691
+ const streams = (Array.isArray(stream) ? stream : [stream]).filter((stream$1) => {
1692
+ const key = this.streamKey(stream$1, urlPath);
1693
+ return !this.streamConnectionMap.has(key);
1694
+ });
1695
+ this.handleStreamAssignment(streams, urlPath).forEach((assignedStreams, connection) => {
1626
1696
  if (!this.isConnected(connection)) {
1627
- this.logger.info(`Connection ${connection.id} is not ready. Queuing subscription for streams: ${streams$1}`);
1628
- connection.pendingSubscriptions?.push(...streams$1);
1697
+ this.logger.info(`Connection ${connection.id} is not ready. Queuing subscription for streams: ${assignedStreams}`);
1698
+ connection.pendingSubscriptions?.push(...assignedStreams);
1629
1699
  return;
1630
1700
  }
1631
- this.sendSubscriptionPayload(connection, streams$1, id);
1701
+ this.sendSubscriptionPayload(connection, assignedStreams, id);
1632
1702
  });
1633
1703
  }
1634
1704
  /**
@@ -1636,16 +1706,18 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1636
1706
  * Handles both single and pool modes
1637
1707
  * @param stream Single stream name or array of stream names to unsubscribe from
1638
1708
  * @param id Optional unsubscription ID
1709
+ * @param urlPath Optional URL path for the streams
1639
1710
  * @returns void
1640
1711
  */
1641
- unsubscribe(stream, id) {
1712
+ unsubscribe(stream, id, urlPath) {
1642
1713
  (Array.isArray(stream) ? stream : [stream]).forEach((stream$1) => {
1643
- const connection = this.streamConnectionMap.get(stream$1);
1714
+ const key = this.streamKey(stream$1, urlPath);
1715
+ const connection = this.streamConnectionMap.get(key);
1644
1716
  if (!connection || !connection.ws || !this.isConnected(connection)) {
1645
1717
  this.logger.warn(`Stream ${stream$1} not associated with an active connection.`);
1646
1718
  return;
1647
1719
  }
1648
- if (!this.streamCallbackMap.has(stream$1) || this.streamCallbackMap.get(stream$1)?.size === 0) {
1720
+ if (!this.streamCallbackMap.has(key) || this.streamCallbackMap.get(key)?.size === 0) {
1649
1721
  const payload = {
1650
1722
  method: "UNSUBSCRIBE",
1651
1723
  params: [stream$1],
@@ -1653,8 +1725,8 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1653
1725
  };
1654
1726
  this.logger.debug("UNSUBSCRIBE", payload);
1655
1727
  this.send(JSON.stringify(payload), void 0, false, 0, connection);
1656
- this.streamConnectionMap.delete(stream$1);
1657
- this.streamCallbackMap.delete(stream$1);
1728
+ this.streamConnectionMap.delete(key);
1729
+ this.streamCallbackMap.delete(key);
1658
1730
  }
1659
1731
  });
1660
1732
  }
@@ -1664,7 +1736,9 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1664
1736
  * @returns `true` if the stream is currently subscribed, `false` otherwise.
1665
1737
  */
1666
1738
  isSubscribed(stream) {
1667
- return this.streamConnectionMap.has(stream);
1739
+ if (this.streamConnectionMap.has(stream)) return true;
1740
+ for (const key of this.streamConnectionMap.keys()) if (key.endsWith(`::${stream}`)) return true;
1741
+ return false;
1668
1742
  }
1669
1743
  };
1670
1744
  /**
@@ -1674,10 +1748,12 @@ var WebsocketStreamsBase = class extends WebsocketCommon {
1674
1748
  * @param {WebsocketAPIBase | WebsocketStreamsBase} websocketBase The WebSocket base instance
1675
1749
  * @param {string} streamOrId The stream identifier
1676
1750
  * @param {string} [id] Optional additional identifier
1751
+ * @param {string} [urlPath] Optional URL path for the stream
1677
1752
  * @returns {WebsocketStream<T>} A stream handler with methods to register callbacks and unsubscribe
1678
1753
  */
1679
- function createStreamHandler(websocketBase, streamOrId, id) {
1680
- if (websocketBase instanceof WebsocketStreamsBase) websocketBase.subscribe(streamOrId, id);
1754
+ function createStreamHandler(websocketBase, streamOrId, id, urlPath) {
1755
+ const key = websocketBase instanceof WebsocketStreamsBase ? websocketBase.streamKey(streamOrId, urlPath) : streamOrId;
1756
+ if (websocketBase instanceof WebsocketStreamsBase) websocketBase.subscribe(streamOrId, id, urlPath);
1681
1757
  let registeredCallback;
1682
1758
  return {
1683
1759
  on: (event, callback) => {
@@ -1687,14 +1763,14 @@ function createStreamHandler(websocketBase, streamOrId, id) {
1687
1763
  websocketBase.logger.error(`Error in stream callback: ${err}`);
1688
1764
  });
1689
1765
  };
1690
- const callbackSet = websocketBase.streamCallbackMap.get(streamOrId) ?? /* @__PURE__ */ new Set();
1766
+ const callbackSet = websocketBase.streamCallbackMap.get(key) ?? /* @__PURE__ */ new Set();
1691
1767
  callbackSet.add(registeredCallback);
1692
- websocketBase.streamCallbackMap.set(streamOrId, callbackSet);
1768
+ websocketBase.streamCallbackMap.set(key, callbackSet);
1693
1769
  }
1694
1770
  },
1695
1771
  unsubscribe: () => {
1696
- if (registeredCallback) websocketBase.streamCallbackMap.get(streamOrId)?.delete(registeredCallback);
1697
- if (websocketBase instanceof WebsocketStreamsBase) websocketBase.unsubscribe(streamOrId, id);
1772
+ if (registeredCallback) websocketBase.streamCallbackMap.get(key)?.delete(registeredCallback);
1773
+ if (websocketBase instanceof WebsocketStreamsBase) websocketBase.unsubscribe(streamOrId, id, urlPath);
1698
1774
  }
1699
1775
  };
1700
1776
  }
@@ -1717,7 +1793,9 @@ exports.DERIVATIVES_TRADING_COIN_FUTURES_WS_API_TESTNET_URL = DERIVATIVES_TRADIN
1717
1793
  exports.DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL = DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_PROD_URL;
1718
1794
  exports.DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL = DERIVATIVES_TRADING_COIN_FUTURES_WS_STREAMS_TESTNET_URL;
1719
1795
  exports.DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL = DERIVATIVES_TRADING_OPTIONS_REST_API_PROD_URL;
1796
+ exports.DERIVATIVES_TRADING_OPTIONS_REST_API_TESTNET_URL = DERIVATIVES_TRADING_OPTIONS_REST_API_TESTNET_URL;
1720
1797
  exports.DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL = DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_PROD_URL;
1798
+ exports.DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_TESTNET_URL = DERIVATIVES_TRADING_OPTIONS_WS_STREAMS_TESTNET_URL;
1721
1799
  exports.DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL = DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_REST_API_PROD_URL;
1722
1800
  exports.DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL = DERIVATIVES_TRADING_PORTFOLIO_MARGIN_PRO_WS_STREAMS_PROD_URL;
1723
1801
  exports.DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL = DERIVATIVES_TRADING_PORTFOLIO_MARGIN_REST_API_PROD_URL;