@n1xyz/nord-ts 0.0.20 → 0.0.22

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.
@@ -1,5 +1,4 @@
1
- import { Account, Info, SubscriptionPattern } from "../../types";
2
- import { checkedFetch } from "../../utils";
1
+ import { SubscriptionPattern } from "../../types";
3
2
  import { NordWebSocketClient } from "../../websocket/index";
4
3
  import { NordError } from "../utils/NordError";
5
4
 
@@ -19,12 +18,10 @@ import { NordError } from "../utils/NordError";
19
18
  export function initWebSocketClient(
20
19
  webServerUrl: string,
21
20
  subscriptions?: SubscriptionPattern[] | "trades" | "delta" | "account",
22
- initialSubscriptions?: SubscriptionPattern[],
23
21
  ): NordWebSocketClient {
24
22
  try {
25
23
  // Determine URL and subscriptions based on parameters
26
24
  let wsUrl = webServerUrl.replace(/^http/, "ws") + `/ws`;
27
- let wsSubscriptions: SubscriptionPattern[] = [];
28
25
 
29
26
  // Validate subscriptions parameter
30
27
  if (typeof subscriptions === "string") {
@@ -35,12 +32,6 @@ export function initWebSocketClient(
35
32
  subscriptions === "account"
36
33
  ) {
37
34
  wsUrl += `/${subscriptions}`;
38
- // If initialSubscriptions provided, use them
39
- if (initialSubscriptions && initialSubscriptions.length > 0) {
40
- // Validate initialSubscriptions
41
- initialSubscriptions.forEach(validateSubscription);
42
- wsSubscriptions = initialSubscriptions;
43
- }
44
35
  } else {
45
36
  throw new NordError(
46
37
  `Invalid endpoint: ${subscriptions}. Must be "trades", "deltas", or "account".`,
@@ -68,12 +59,6 @@ export function initWebSocketClient(
68
59
  // Add connected handler for debugging
69
60
  ws.on("connected", () => {
70
61
  console.log("Nord WebSocket connected successfully");
71
-
72
- // Subscribe to additional subscriptions if provided
73
- // For new format, these are already part of the URL
74
- if (wsSubscriptions.length > 0) {
75
- ws.subscribe(wsSubscriptions);
76
- }
77
62
  });
78
63
 
79
64
  // Connect the WebSocket
@@ -1,12 +1,16 @@
1
+ import { ProtonClient } from "@n1xyz/proton";
2
+ import { Connection, PublicKey } from "@solana/web3.js";
1
3
  import { EventEmitter } from "events";
2
- import { PublicKey, Connection } from "@solana/web3.js";
3
4
  import createClient, { Client, FetchOptions } from "openapi-fetch";
5
+ import * as proto from "../../gen/nord_pb";
6
+ import type { paths } from "../../gen/openapi.ts";
4
7
  import {
5
- Info,
6
8
  Account,
7
9
  ActionResponse,
8
10
  AggregateMetrics,
11
+ Info,
9
12
  Market,
13
+ MarketStats,
10
14
  NordConfig,
11
15
  OrderbookQuery,
12
16
  OrderbookResponse,
@@ -15,18 +19,13 @@ import {
15
19
  Token,
16
20
  TradesResponse,
17
21
  User,
18
- MarketStats,
19
22
  } from "../../types";
20
- import { ProtonClient } from "@n1xyz/proton";
21
- import * as proto from "../../gen/nord";
22
- // import { base64 } from "@scure/base";
23
+ import * as utils from "../../utils";
23
24
  import { NordWebSocketClient } from "../../websocket/index";
24
25
  import * as core from "../api/core";
25
26
  import * as metrics from "../api/metrics";
26
- import * as utils from "../../utils";
27
27
  import { OrderbookSubscription, TradeSubscription } from "../models/Subscriber";
28
28
  import { NordError } from "../utils/NordError";
29
- import type { paths } from "../../gen/openapi.ts";
30
29
 
31
30
  /**
32
31
  * User subscription interface
@@ -306,9 +305,9 @@ export class Nord {
306
305
  actionId: x.actionId,
307
306
  action: utils.decodeLengthDelimited(
308
307
  Buffer.from(x.payload, "base64"),
309
- proto.Action,
308
+ proto.ActionSchema,
310
309
  ),
311
- physicalExecTime: new Date(x.physicalTime * 1000),
310
+ physicalExecTime: new Date(x.physicalTime),
312
311
  }));
313
312
  }
314
313
 
@@ -427,7 +426,6 @@ export class Nord {
427
426
  wsClient.on("delta", handleDelta);
428
427
 
429
428
  subscription.close = () => {
430
- wsClient.unsubscribe([`deltas@${symbol}`]);
431
429
  wsClient.removeListener("delta", handleDelta);
432
430
  subscription.removeAllListeners();
433
431
  };
@@ -471,7 +469,6 @@ export class Nord {
471
469
  wsClient.on("trades", handleTrade);
472
470
 
473
471
  subscription.close = () => {
474
- wsClient.unsubscribe([`trades@${symbol}`]);
475
472
  wsClient.removeListener("trades", handleTrade);
476
473
  subscription.removeAllListeners();
477
474
  };
@@ -507,7 +504,6 @@ export class Nord {
507
504
  wsClient.on("account", handleAccountUpdate);
508
505
 
509
506
  subscription.close = () => {
510
- wsClient.unsubscribe([`account@${accountId}`]);
511
507
  wsClient.removeListener("account", handleAccountUpdate);
512
508
  subscription.removeAllListeners();
513
509
  };
@@ -4,14 +4,19 @@ import {
4
4
  TOKEN_PROGRAM_ID,
5
5
  TOKEN_2022_PROGRAM_ID,
6
6
  } from "@solana/spl-token";
7
- import { Connection, PublicKey, Transaction } from "@solana/web3.js";
7
+ import {
8
+ Connection,
9
+ PublicKey,
10
+ Transaction,
11
+ SendOptions,
12
+ } from "@solana/web3.js";
8
13
  import Decimal from "decimal.js";
9
14
  import * as ed from "@noble/ed25519";
10
15
  import { sha512 } from "@noble/hashes/sha512";
11
16
  ed.etc.sha512Sync = sha512;
12
17
  import { floatToScaledBigIntLossy } from "@n1xyz/proton";
13
- import { FillMode, Order, Side, SPLTokenInfo } from "../../types";
14
- import * as proto from "../../gen/nord";
18
+ import { FillMode, Side, SPLTokenInfo, QuoteSize } from "../../types";
19
+ import * as proto from "../../gen/nord_pb";
15
20
  import {
16
21
  BigIntValue,
17
22
  checkedFetch,
@@ -87,8 +92,8 @@ export interface PlaceOrderParams {
87
92
  /** Order price */
88
93
  price?: Decimal.Value;
89
94
 
90
- /** Quote size (for market orders) */
91
- quoteSize?: Decimal.Value;
95
+ /** Quote size object (requires non-zero price and size) */
96
+ quoteSize?: QuoteSize;
92
97
 
93
98
  /** Account ID to place the order from */
94
99
  accountId?: number;
@@ -142,8 +147,8 @@ export interface UserAtomicSubaction {
142
147
  /** Order price */
143
148
  price?: Decimal.Value;
144
149
 
145
- /** Quote size (for market orders) */
146
- quoteSize?: Decimal.Value;
150
+ /** Quote size object (for market-style placement) */
151
+ quoteSize?: QuoteSize;
147
152
 
148
153
  /** The client order ID of the order. */
149
154
  clientOrderId?: BigIntValue;
@@ -471,6 +476,7 @@ export class NordUser {
471
476
  * @param amount - Amount to deposit
472
477
  * @param tokenId - Token ID
473
478
  * @param recipient - Recipient address; defaults to the user's address
479
+ * @param sendOptions - Send options for .sendTransaction
474
480
  * @returns Transaction signature
475
481
  * @throws {NordError} If required parameters are missing or operation fails
476
482
  */
@@ -478,10 +484,12 @@ export class NordUser {
478
484
  amount,
479
485
  tokenId,
480
486
  recipient,
487
+ sendOptions,
481
488
  }: Readonly<{
482
489
  amount: number;
483
490
  tokenId: number;
484
491
  recipient?: PublicKey;
492
+ sendOptions?: SendOptions;
485
493
  }>): Promise<string> {
486
494
  try {
487
495
  // Find the token info
@@ -502,8 +510,7 @@ export class NordUser {
502
510
  sourceTokenAccount: fromAccount,
503
511
  });
504
512
 
505
- const { blockhash } =
506
- await this.connection.getLatestBlockhash("confirmed");
513
+ const { blockhash } = await this.connection.getLatestBlockhash();
507
514
  const tx = new Transaction();
508
515
 
509
516
  tx.add(ix);
@@ -515,6 +522,7 @@ export class NordUser {
515
522
 
516
523
  const signature = await this.connection.sendRawTransaction(
517
524
  signedTx.serialize(),
525
+ sendOptions,
518
526
  );
519
527
 
520
528
  return signature;
@@ -657,7 +665,7 @@ export class NordUser {
657
665
  * @throws {NordError} If the operation fails
658
666
  */
659
667
  async refreshSession(): Promise<void> {
660
- this.sessionId = await createSession(
668
+ const result = await createSession(
661
669
  this.nord.webServerUrl,
662
670
  this.walletSignFn,
663
671
  await this.nord.getTimestamp(),
@@ -667,6 +675,7 @@ export class NordUser {
667
675
  sessionPubkey: this.sessionPubKey,
668
676
  },
669
677
  );
678
+ this.sessionId = result.sessionId;
670
679
  }
671
680
  /**
672
681
  * Revoke a session
@@ -746,10 +755,14 @@ export class NordUser {
746
755
  * Place an order on the exchange
747
756
  *
748
757
  * @param params - Order parameters
749
- * @returns Order ID if successful
758
+ * @returns Object containing actionId, orderId (if posted), fills, and clientOrderId
750
759
  * @throws {NordError} If the operation fails
751
760
  */
752
- async placeOrder(params: PlaceOrderParams): Promise<bigint | undefined> {
761
+ async placeOrder(params: PlaceOrderParams): Promise<{
762
+ actionId: bigint;
763
+ orderId?: bigint;
764
+ fills: proto.Receipt_Trade[];
765
+ }> {
753
766
  try {
754
767
  this.checkSessionValidity();
755
768
  const market = findMarket(this.nord.markets, params.marketId);
@@ -757,7 +770,7 @@ export class NordUser {
757
770
  throw new NordError(`Market with ID ${params.marketId} not found`);
758
771
  }
759
772
 
760
- return placeOrder(
773
+ const result = await placeOrder(
761
774
  this.nord.webServerUrl,
762
775
  this.sessionSignFn,
763
776
  await this.nord.getTimestamp(),
@@ -776,6 +789,7 @@ export class NordUser {
776
789
  quoteSize: params.quoteSize,
777
790
  },
778
791
  );
792
+ return result;
779
793
  } catch (error) {
780
794
  throw new NordError("Failed to place order", { cause: error });
781
795
  }
@@ -786,18 +800,22 @@ export class NordUser {
786
800
  *
787
801
  * @param orderId - Order ID to cancel
788
802
  * @param providedAccountId - Account ID that placed the order
789
- * @returns Action ID if successful
803
+ * @returns Object containing actionId, cancelled orderId, and accountId
790
804
  * @throws {NordError} If the operation fails
791
805
  */
792
806
  async cancelOrder(
793
807
  orderId: BigIntValue,
794
808
  providedAccountId?: number,
795
- ): Promise<bigint> {
809
+ ): Promise<{
810
+ actionId: bigint;
811
+ orderId: bigint;
812
+ accountId: number;
813
+ }> {
796
814
  const accountId =
797
815
  providedAccountId != null ? providedAccountId : this.accountIds?.[0];
798
816
  try {
799
817
  this.checkSessionValidity();
800
- return cancelOrder(
818
+ const result = await cancelOrder(
801
819
  this.nord.webServerUrl,
802
820
  this.sessionSignFn,
803
821
  await this.nord.getTimestamp(),
@@ -808,6 +826,7 @@ export class NordUser {
808
826
  orderId,
809
827
  },
810
828
  );
829
+ return result;
811
830
  } catch (error) {
812
831
  throw new NordError(`Failed to cancel order ${orderId}`, {
813
832
  cause: error,
@@ -860,7 +879,10 @@ export class NordUser {
860
879
  async atomic(
861
880
  userActions: UserAtomicSubaction[],
862
881
  providedAccountId?: number,
863
- ): Promise<proto.Receipt_AtomicResult> {
882
+ ): Promise<{
883
+ actionId: bigint;
884
+ results: proto.Receipt_AtomicSubactionResultKind[];
885
+ }> {
864
886
  try {
865
887
  this.checkSessionValidity();
866
888
 
@@ -889,8 +911,7 @@ export class NordUser {
889
911
  priceDecimals: market.priceDecimals,
890
912
  size: act.size,
891
913
  price: act.price,
892
- quoteSizeSize: act.quoteSize, // treated as quote size; we pass only size component
893
- quoteSizePrice: undefined,
914
+ quoteSize: act.quoteSize,
894
915
  clientOrderId: act.clientOrderId,
895
916
  } as ApiAtomicSubaction;
896
917
  }
package/src/types.ts CHANGED
@@ -1,5 +1,7 @@
1
- import * as proto from "./gen/nord";
1
+ import * as proto from "./gen/nord_pb";
2
2
  import type { components } from "./gen/openapi.ts";
3
+ import Decimal from "decimal.js";
4
+ import { toScaledU64 } from "./utils";
3
5
 
4
6
  /**
5
7
  * The peak TPS rate is queried over the specified period.
@@ -251,21 +253,11 @@ export interface ActionNonceResponse {
251
253
  * WebSocket message types
252
254
  */
253
255
  export enum WebSocketMessageType {
254
- Subscribe = "subscribe",
255
- Unsubscribe = "unsubscribe",
256
256
  TradeUpdate = "trades",
257
257
  DeltaUpdate = "delta",
258
258
  AccountUpdate = "account",
259
259
  }
260
260
 
261
- /**
262
- * WebSocket subscription request
263
- */
264
- export interface WebSocketSubscription {
265
- e: WebSocketMessageType;
266
- streams: string[]; // Array of streams to subscribe/unsubscribe (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
267
- }
268
-
269
261
  /**
270
262
  * WebSocket trade update message
271
263
  */
@@ -300,7 +292,6 @@ export interface WebSocketAccountUpdate {
300
292
  }
301
293
 
302
294
  export type WebSocketMessage =
303
- | WebSocketSubscription
304
295
  | WebSocketTradeUpdate
305
296
  | WebSocketDeltaUpdate
306
297
  | WebSocketAccountUpdate;
@@ -311,3 +302,32 @@ export interface SPLTokenInfo {
311
302
  tokenId: number;
312
303
  name: string;
313
304
  }
305
+
306
+ // Positive decimal price and size.
307
+ export class QuoteSize {
308
+ price: Decimal;
309
+ size: Decimal;
310
+ constructor(quotePrice: Decimal.Value, quoteSize: Decimal.Value) {
311
+ const p = new Decimal(quotePrice);
312
+ const s = new Decimal(quoteSize);
313
+ if (p.isZero() || s.isZero()) {
314
+ throw new Error("quotePrice and quoteSize must be non-zero");
315
+ }
316
+ this.price = p;
317
+ this.size = s;
318
+ }
319
+
320
+ value(): Decimal {
321
+ return this.price.mul(this.size);
322
+ }
323
+
324
+ toScaledU64(
325
+ marketPriceDecimals: number,
326
+ marketSizeDecimals: number,
327
+ ): { price: bigint; size: bigint } {
328
+ return {
329
+ price: toScaledU64(this.price, marketPriceDecimals),
330
+ size: toScaledU64(this.size, marketSizeDecimals),
331
+ };
332
+ }
333
+ }
package/src/utils.ts CHANGED
@@ -4,8 +4,9 @@ import { bls12_381 as bls } from "@noble/curves/bls12-381";
4
4
  import { secp256k1 as secp } from "@noble/curves/secp256k1";
5
5
  import { sha256 } from "@noble/hashes/sha256";
6
6
  import { KeyType, type Market, type Token } from "./types";
7
- import * as proto from "./gen/nord";
8
- import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
7
+ import { sizeDelimitedPeek } from "@bufbuild/protobuf/wire";
8
+ import { fromBinary, type Message } from "@bufbuild/protobuf";
9
+ import type { GenMessage } from "@bufbuild/protobuf/codegenv2";
9
10
  import { ethers } from "ethers";
10
11
  import fetch from "node-fetch";
11
12
  import { RequestInfo, RequestInit, Response } from "node-fetch";
@@ -101,6 +102,7 @@ export function makeWalletSignFn(
101
102
  signingKey.sign(ethers.hashMessage(message)).serialized;
102
103
  }
103
104
 
105
+ // Returned numbers do fit into specified bits range, or error is thrown.
104
106
  function makeToScaledBigUint(params: {
105
107
  precision: number;
106
108
  exponent: number;
@@ -176,63 +178,42 @@ export const toScaledU128 = makeToScaledBigUint({
176
178
  exponent: 56,
177
179
  });
178
180
 
179
- /**
180
- * Encodes any protobuf message into a length-delimited format,
181
- * i.e. prefixed with its length encoded as varint
182
- * @param message message object
183
- * @param coder associated coder object which implements `MessageFns` interface
184
- * @returns Encoded message as Uint8Array, prefixed with its length
185
- */
186
- export function encodeLengthDelimited<T, M extends proto.MessageFns<T>>(
187
- message: T,
188
- coder: M,
189
- ): Uint8Array {
190
- const encoded = coder.encode(message).finish();
191
- if (encoded.byteLength > MAX_PAYLOAD_SIZE) {
192
- throw new Error(
193
- `Encoded message size (${encoded.byteLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
194
- );
195
- }
196
- const encodedLength = new BinaryWriter().uint32(encoded.byteLength).finish();
197
- return new Uint8Array([...encodedLength, ...encoded]);
198
- }
199
-
200
181
  /**
201
182
  * Decodes any protobuf message from a length-delimited format,
202
183
  * i.e. prefixed with its length encoded as varint
203
184
  *
204
- * NB: Please note that due to limitations of Typescript type inference
205
- * it requires to specify variable type explicitly:
206
- *
207
- * ```
208
- * const foo: proto.Bar = decodeLengthDelimited(bytes, proto.Bar);
209
- * ```
210
- *
211
- * @param bytes Byte array with encoded message
212
- * @param coder associated coder object which implements `MessageFns` interface
213
- * @returns Decoded Action as Uint8Array.
185
+ * @param bytes Byte array with encoded message
186
+ * @param schema Message schema for decoding
187
+ * @returns Decoded message
214
188
  */
215
- export function decodeLengthDelimited<T, M extends proto.MessageFns<T>>(
189
+ export function decodeLengthDelimited<T extends Message>(
216
190
  bytes: Uint8Array,
217
- coder: M,
191
+ schema: GenMessage<T>,
218
192
  ): T {
219
- const lengthReader = new BinaryReader(bytes);
220
- const msgLength = lengthReader.uint32();
221
- const startsAt = lengthReader.pos;
193
+ // use sizeDelimitedPeek to extract the message length and offset
194
+ const peekResult = sizeDelimitedPeek(bytes);
195
+
196
+ if (peekResult.size === null || peekResult.offset === null) {
197
+ throw new Error("Failed to parse size-delimited message");
198
+ }
222
199
 
223
- if (msgLength > MAX_PAYLOAD_SIZE) {
200
+ if (peekResult.size > MAX_PAYLOAD_SIZE) {
224
201
  throw new Error(
225
- `Encoded message size (${msgLength} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
202
+ `Encoded message size (${peekResult.size} bytes) is greater than max payload size (${MAX_PAYLOAD_SIZE} bytes).`,
226
203
  );
227
204
  }
228
205
 
229
- if (startsAt + msgLength > bytes.byteLength) {
206
+ if (peekResult.offset + peekResult.size > bytes.length) {
230
207
  throw new Error(
231
- `Encoded message size (${msgLength} bytes) is greater than remaining buffer size (${bytes.byteLength - startsAt} bytes).`,
208
+ `Encoded message size (${peekResult.size} bytes) is greater than remaining buffer size (${bytes.length - peekResult.offset} bytes).`,
232
209
  );
233
210
  }
234
211
 
235
- return coder.decode(bytes.slice(startsAt, startsAt + msgLength));
212
+ // decode the message using the offset and size from peek
213
+ return fromBinary(
214
+ schema,
215
+ bytes.slice(peekResult.offset, peekResult.offset + peekResult.size),
216
+ );
236
217
  }
237
218
 
238
219
  export function checkPubKeyLength(keyType: KeyType, len: number): void {
@@ -4,8 +4,6 @@ import {
4
4
  WebSocketAccountUpdate,
5
5
  WebSocketDeltaUpdate,
6
6
  WebSocketMessage,
7
- WebSocketMessageType,
8
- WebSocketSubscription,
9
7
  WebSocketTradeUpdate,
10
8
  } from "../types";
11
9
  import { NordWebSocketClientEvents } from "./events";
@@ -29,9 +27,6 @@ type WebSocketInstance = WebSocket | BrowserWebSocket;
29
27
 
30
28
  const VALID_STREAM_TYPES = ["trades", "delta", "account"];
31
29
 
32
- // Constants for WebSocket readyState
33
- const WS_OPEN = 1;
34
-
35
30
  /**
36
31
  * WebSocket client for Nord exchange
37
32
  *
@@ -47,7 +42,6 @@ export class NordWebSocketClient
47
42
  {
48
43
  private ws: WebSocketInstance | null = null;
49
44
  private url: string;
50
- private subscriptions: Set<string> = new Set();
51
45
  private reconnectAttempts: number = 0;
52
46
  private maxReconnectAttempts: number = 5;
53
47
  private reconnectDelay: number = 1000;
@@ -174,11 +168,6 @@ export class NordWebSocketClient
174
168
  this.emit("connected");
175
169
  this.reconnectAttempts = 0;
176
170
  this.reconnectDelay = 1000;
177
-
178
- // Resubscribe to previous subscriptions
179
- if (this.subscriptions.size > 0) {
180
- this.subscribe([...this.subscriptions]);
181
- }
182
171
  };
183
172
 
184
173
  (this.ws as BrowserWebSocket).onmessage = (event: { data: any }) => {
@@ -197,18 +186,13 @@ export class NordWebSocketClient
197
186
  }
198
187
  };
199
188
 
200
- (this.ws as BrowserWebSocket).onclose = (event: any) => {
201
- const reason =
202
- event && event.reason ? ` Reason: ${event.reason}` : "";
203
- const code = event && event.code ? ` Code: ${event.code}` : "";
189
+ (this.ws as BrowserWebSocket).onclose = (_event: any) => {
204
190
  this.emit("disconnected");
205
- console.log(`WebSocket closed.${code}${reason}`);
206
191
  this.reconnect();
207
192
  };
208
193
 
209
194
  (this.ws as BrowserWebSocket).onerror = (event: any) => {
210
195
  const errorMsg = `WebSocket error: ${event && event.type ? event.type : "unknown"}`;
211
- console.error(errorMsg, event);
212
196
  this.emit("error", new Error(errorMsg));
213
197
  };
214
198
  } else {
@@ -221,11 +205,6 @@ export class NordWebSocketClient
221
205
  this.reconnectAttempts = 0;
222
206
  this.reconnectDelay = 1000;
223
207
  this.setupHeartbeat();
224
-
225
- // Resubscribe to previous subscriptions
226
- if (this.subscriptions.size > 0) {
227
- this.subscribe([...this.subscriptions]);
228
- }
229
208
  });
230
209
 
231
210
  nodeWs.on("message", (data: WebSocket.Data) => {
@@ -242,9 +221,8 @@ export class NordWebSocketClient
242
221
  }
243
222
  });
244
223
 
245
- nodeWs.on("close", (code: number, reason: string) => {
224
+ nodeWs.on("close", (_code: number, _reason: string) => {
246
225
  this.emit("disconnected");
247
- console.log(`WebSocket closed. Code: ${code} Reason: ${reason}`);
248
226
  if (this.pingInterval) {
249
227
  clearInterval(this.pingInterval);
250
228
  }
@@ -255,7 +233,6 @@ export class NordWebSocketClient
255
233
  });
256
234
 
257
235
  nodeWs.on("error", (error: Error) => {
258
- console.error("WebSocket error:", error);
259
236
  this.emit("error", error);
260
237
  });
261
238
 
@@ -267,105 +244,10 @@ export class NordWebSocketClient
267
244
  }
268
245
  } catch (error) {
269
246
  const errorMsg = `Failed to initialize WebSocket: ${error instanceof Error ? error.message : String(error)}`;
270
- console.error(errorMsg);
271
247
  this.emit("error", new Error(errorMsg));
272
248
  }
273
249
  }
274
250
 
275
- /**
276
- * Subscribe to one or more streams
277
- * @param streams Array of streams to subscribe to (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
278
- */
279
- public subscribe(streams: string[]): void {
280
- // Validate all streams first
281
- try {
282
- streams.forEach((stream) => this.validateStream(stream));
283
- } catch (error) {
284
- this.emit(
285
- "error",
286
- error instanceof Error ? error : new Error(String(error)),
287
- );
288
- return;
289
- }
290
-
291
- if (
292
- !this.ws ||
293
- (this.isBrowser
294
- ? (this.ws as BrowserWebSocket).readyState !== WS_OPEN
295
- : (this.ws as WebSocket).readyState !== WebSocket.OPEN)
296
- ) {
297
- streams.forEach((stream) => this.subscriptions.add(stream));
298
- return;
299
- }
300
-
301
- const message: WebSocketSubscription = {
302
- e: WebSocketMessageType.Subscribe,
303
- streams,
304
- };
305
-
306
- try {
307
- const messageStr = JSON.stringify(message);
308
- if (this.isBrowser) {
309
- (this.ws as BrowserWebSocket).send(messageStr);
310
- } else {
311
- (this.ws as WebSocket).send(messageStr);
312
- }
313
- streams.forEach((stream) => this.subscriptions.add(stream));
314
- } catch (error) {
315
- this.emit(
316
- "error",
317
- error instanceof Error ? error : new Error(String(error)),
318
- );
319
- }
320
- }
321
-
322
- /**
323
- * Unsubscribe from one or more streams
324
- * @param streams Array of streams to unsubscribe from
325
- */
326
- public unsubscribe(streams: string[]): void {
327
- // Validate all streams first
328
- try {
329
- streams.forEach((stream) => this.validateStream(stream));
330
- } catch (error) {
331
- this.emit(
332
- "error",
333
- error instanceof Error ? error : new Error(String(error)),
334
- );
335
- return;
336
- }
337
-
338
- if (
339
- !this.ws ||
340
- (this.isBrowser
341
- ? (this.ws as BrowserWebSocket).readyState !== WS_OPEN
342
- : (this.ws as WebSocket).readyState !== WebSocket.OPEN)
343
- ) {
344
- streams.forEach((stream) => this.subscriptions.delete(stream));
345
- return;
346
- }
347
-
348
- const message: WebSocketSubscription = {
349
- e: WebSocketMessageType.Unsubscribe,
350
- streams,
351
- };
352
-
353
- try {
354
- const messageStr = JSON.stringify(message);
355
- if (this.isBrowser) {
356
- (this.ws as BrowserWebSocket).send(messageStr);
357
- } else {
358
- (this.ws as WebSocket).send(messageStr);
359
- }
360
- streams.forEach((stream) => this.subscriptions.delete(stream));
361
- } catch (error) {
362
- this.emit(
363
- "error",
364
- error instanceof Error ? error : new Error(String(error)),
365
- );
366
- }
367
- }
368
-
369
251
  /**
370
252
  * Close the WebSocket connection
371
253
  */
@@ -386,7 +268,6 @@ export class NordWebSocketClient
386
268
  clearTimeout(this.pingTimeout);
387
269
  this.pingTimeout = null;
388
270
  }
389
- this.subscriptions.clear();
390
271
  }
391
272
 
392
273
  /**