@n1xyz/nord-ts 0.0.1 → 0.0.5

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.
Files changed (260) hide show
  1. package/README.md +148 -65
  2. package/dist/bridge/client.d.ts +150 -0
  3. package/dist/bridge/client.js +394 -0
  4. package/dist/bridge/const.d.ts +23 -0
  5. package/dist/bridge/const.js +47 -0
  6. package/dist/bridge/index.d.ts +5 -0
  7. package/dist/bridge/index.js +23 -0
  8. package/dist/bridge/types.d.ts +118 -0
  9. package/dist/bridge/types.js +16 -0
  10. package/dist/bridge/utils.d.ts +64 -0
  11. package/dist/bridge/utils.js +131 -0
  12. package/dist/const.d.ts +2 -5
  13. package/dist/const.js +2 -6
  14. package/dist/gen/common.d.ts +6 -1
  15. package/dist/gen/common.js +19 -9
  16. package/dist/gen/nord.d.ts +76 -21
  17. package/dist/gen/nord.js +987 -423
  18. package/dist/idl/bridge.d.ts +2 -0
  19. package/dist/idl/bridge.js +703 -0
  20. package/dist/index.d.ts +5 -2
  21. package/dist/index.js +18 -2
  22. package/dist/nord/{actions.d.ts → api/actions.d.ts} +6 -6
  23. package/dist/nord/{actions.js → api/actions.js} +6 -10
  24. package/dist/nord/api/core.d.ts +49 -0
  25. package/dist/nord/api/core.js +121 -0
  26. package/dist/nord/api/market.d.ts +36 -0
  27. package/dist/nord/api/market.js +98 -0
  28. package/dist/nord/api/metrics.d.ts +67 -0
  29. package/dist/nord/api/metrics.js +132 -0
  30. package/dist/nord/api/queries.d.ts +81 -0
  31. package/dist/nord/api/queries.js +187 -0
  32. package/dist/nord/client/Nord.d.ts +335 -0
  33. package/dist/nord/client/Nord.js +532 -0
  34. package/dist/nord/client/NordUser.d.ts +320 -0
  35. package/dist/nord/client/NordUser.js +697 -0
  36. package/dist/nord/index.d.ts +9 -2
  37. package/dist/nord/index.js +30 -6
  38. package/dist/nord/models/Subscriber.d.ts +37 -0
  39. package/dist/nord/models/Subscriber.js +25 -0
  40. package/dist/nord/utils/NordError.d.ts +35 -0
  41. package/dist/nord/utils/NordError.js +46 -0
  42. package/dist/types.d.ts +143 -86
  43. package/dist/types.js +12 -1
  44. package/dist/utils.d.ts +9 -0
  45. package/dist/utils.js +20 -1
  46. package/dist/websocket/NordWebSocketClient.d.ts +71 -0
  47. package/dist/websocket/NordWebSocketClient.js +343 -0
  48. package/dist/websocket/events.d.ts +19 -0
  49. package/dist/websocket/events.js +2 -0
  50. package/dist/websocket/index.d.ts +2 -0
  51. package/dist/websocket/index.js +5 -0
  52. package/docs/assets/hierarchy.js +1 -0
  53. package/docs/assets/highlight.css +16 -16
  54. package/docs/assets/icons.js +17 -14
  55. package/docs/assets/icons.svg +1 -1
  56. package/docs/assets/main.js +5 -4
  57. package/docs/assets/navigation.js +1 -1
  58. package/docs/assets/search.js +1 -1
  59. package/docs/assets/style.css +1423 -1227
  60. package/docs/classes/Nord.html +189 -43
  61. package/docs/classes/NordError.html +24 -0
  62. package/docs/classes/NordUser.html +120 -35
  63. package/docs/classes/NordWebSocketClient.html +335 -0
  64. package/docs/classes/SolanaBridgeClient.html +86 -0
  65. package/docs/classes/Subscriber.html +10 -6
  66. package/docs/enums/FillMode.html +5 -5
  67. package/docs/enums/KeyType.html +4 -4
  68. package/docs/enums/MetricPeriod.html +9 -0
  69. package/docs/enums/PdaSeedType.html +9 -0
  70. package/docs/enums/PeakTpsPeriodUnit.html +7 -7
  71. package/docs/enums/Side.html +3 -3
  72. package/docs/enums/WebSocketMessageType.html +7 -0
  73. package/docs/functions/actionQueryRollman.html +6 -0
  74. package/docs/functions/actionsQueryRollman.html +6 -0
  75. package/docs/functions/aggregateMetrics-1.html +7 -0
  76. package/docs/functions/assert.html +1 -1
  77. package/docs/functions/bigIntToProtoU128.html +3 -3
  78. package/docs/functions/blockQueryRollman.html +6 -0
  79. package/docs/functions/blockSummaryQueryRollman.html +6 -0
  80. package/docs/functions/bridgeToBN.html +5 -0
  81. package/docs/functions/bufferToHex.html +4 -0
  82. package/docs/functions/cancelOrder.html +1 -0
  83. package/docs/functions/checkPubKeyLength.html +1 -1
  84. package/docs/functions/checkedFetch.html +4 -4
  85. package/docs/functions/createSession.html +1 -0
  86. package/docs/functions/decodeLengthDelimited.html +7 -6
  87. package/docs/functions/encodeLengthDelimited.html +4 -4
  88. package/docs/functions/fillModeToProtoFillMode.html +4 -4
  89. package/docs/functions/findMarket.html +1 -1
  90. package/docs/functions/findPda.html +6 -0
  91. package/docs/functions/findToken.html +1 -1
  92. package/docs/functions/fromBN.html +5 -0
  93. package/docs/functions/getAccount.html +6 -0
  94. package/docs/functions/getActionNonce.html +5 -0
  95. package/docs/functions/getCurrentTps.html +6 -0
  96. package/docs/functions/getInfo.html +5 -0
  97. package/docs/functions/getMedianLatency.html +6 -0
  98. package/docs/functions/getOrderbook.html +6 -0
  99. package/docs/functions/getPeakTps.html +6 -0
  100. package/docs/functions/getTimestamp.html +5 -0
  101. package/docs/functions/getTotalTransactions.html +5 -0
  102. package/docs/functions/getTrades.html +6 -0
  103. package/docs/functions/getUserAccountIds.html +6 -0
  104. package/docs/functions/hexToBuffer.html +4 -0
  105. package/docs/functions/initWebSocketClient.html +12 -0
  106. package/docs/functions/keypairFromPrivateKey.html +4 -0
  107. package/docs/functions/makeSigningFunction.html +4 -0
  108. package/docs/functions/makeWalletSignFn.html +5 -5
  109. package/docs/functions/marketsStats.html +5 -0
  110. package/docs/functions/optExpect.html +4 -4
  111. package/docs/functions/optMap.html +5 -5
  112. package/docs/functions/optUnwrap.html +2 -2
  113. package/docs/functions/panic.html +1 -1
  114. package/docs/functions/placeOrder.html +1 -0
  115. package/docs/functions/queryAction.html +6 -0
  116. package/docs/functions/queryBlock.html +6 -0
  117. package/docs/functions/queryLastNBlocks.html +5 -0
  118. package/docs/functions/queryPrometheus.html +6 -0
  119. package/docs/functions/queryRecentActions.html +6 -0
  120. package/docs/functions/queryRecentBlocks.html +6 -0
  121. package/docs/functions/revokeSession.html +1 -0
  122. package/docs/functions/shortenPublicKey.html +5 -0
  123. package/docs/functions/signAction.html +2 -2
  124. package/docs/functions/toBN.html +5 -0
  125. package/docs/functions/toScaledU128.html +5 -5
  126. package/docs/functions/toScaledU64.html +5 -5
  127. package/docs/functions/transfer.html +1 -0
  128. package/docs/functions/withdraw.html +1 -0
  129. package/docs/hierarchy.html +1 -0
  130. package/docs/index.html +39 -20
  131. package/docs/interfaces/Account.html +8 -8
  132. package/docs/interfaces/ActionInfo.html +8 -8
  133. package/docs/interfaces/ActionNonceResponse.html +3 -0
  134. package/docs/interfaces/ActionQuery.html +4 -4
  135. package/docs/interfaces/ActionResponse.html +8 -8
  136. package/docs/interfaces/ActionsExtendedInfo.html +10 -10
  137. package/docs/interfaces/ActionsQuery.html +5 -5
  138. package/docs/interfaces/ActionsResponse.html +6 -6
  139. package/docs/interfaces/AggregateMetrics.html +12 -12
  140. package/docs/interfaces/BlockFacts.html +10 -0
  141. package/docs/interfaces/BlockQuery.html +6 -6
  142. package/docs/interfaces/BlockResponse.html +6 -6
  143. package/docs/interfaces/BlockSummary.html +8 -8
  144. package/docs/interfaces/BlockSummaryResponse.html +6 -6
  145. package/docs/interfaces/DeltaEvent.html +6 -6
  146. package/docs/interfaces/DepositSplParams.html +10 -0
  147. package/docs/interfaces/Info.html +3 -3
  148. package/docs/interfaces/Market.html +8 -6
  149. package/docs/interfaces/MarketStats.html +7 -7
  150. package/docs/interfaces/MarketsStatsResponse.html +2 -2
  151. package/docs/interfaces/NordConfig.html +14 -5
  152. package/docs/interfaces/NordWebSocketClientEvents.html +4 -0
  153. package/docs/interfaces/NordWebSocketEvents.html +8 -0
  154. package/docs/interfaces/Order.html +6 -6
  155. package/docs/interfaces/OrderInfo.html +6 -6
  156. package/docs/interfaces/OrderbookEntry.html +4 -0
  157. package/docs/interfaces/OrderbookQuery.html +6 -0
  158. package/docs/interfaces/OrderbookResponse.html +6 -10
  159. package/docs/interfaces/OrderbookSubscription.html +159 -0
  160. package/docs/interfaces/PerpMarketStats.html +5 -5
  161. package/docs/interfaces/RollmanActionExtendedInfo.html +4 -4
  162. package/docs/interfaces/RollmanActionInfo.html +4 -4
  163. package/docs/interfaces/RollmanActionResponse.html +4 -4
  164. package/docs/interfaces/RollmanActionsResponse.html +2 -2
  165. package/docs/interfaces/RollmanBlockResponse.html +3 -3
  166. package/docs/interfaces/SPLTokenInfo.html +10 -0
  167. package/docs/interfaces/SolanaBridgeConfig.html +10 -0
  168. package/docs/interfaces/StateFacts.html +10 -0
  169. package/docs/interfaces/SubscriberConfig.html +3 -3
  170. package/docs/interfaces/TimestampResponse.html +3 -0
  171. package/docs/interfaces/Token.html +5 -5
  172. package/docs/interfaces/TokenInfo.html +5 -0
  173. package/docs/interfaces/Trade.html +5 -5
  174. package/docs/interfaces/TradeSubscription.html +159 -0
  175. package/docs/interfaces/Trades.html +5 -5
  176. package/docs/interfaces/TradesQuery.html +6 -0
  177. package/docs/interfaces/TradesResponse.html +7 -12
  178. package/docs/interfaces/TransferParams.html +8 -0
  179. package/docs/interfaces/UserAccountIdsQuery.html +3 -0
  180. package/docs/interfaces/UserAccountIdsResponse.html +3 -0
  181. package/docs/interfaces/WebSocketDeltaUpdate.html +9 -0
  182. package/docs/interfaces/WebSocketSubscription.html +4 -0
  183. package/docs/interfaces/WebSocketTradeUpdate.html +6 -0
  184. package/docs/interfaces/WebSocketUserUpdate.html +6 -0
  185. package/docs/interfaces/WithdrawalClaim.html +14 -0
  186. package/docs/interfaces/WithdrawalParams.html +8 -0
  187. package/docs/modules.html +1 -77
  188. package/docs/types/BigIntValue.html +2 -2
  189. package/docs/types/WebSocketMessage.html +1 -0
  190. package/docs/variables/DEBUG_KEYS.html +1 -1
  191. package/docs/variables/DEFAULT_FUNDING_AMOUNTS.html +1 -1
  192. package/docs/variables/DEV_TOKEN_INFOS.html +1 -1
  193. package/docs/variables/DEV_URL.html +1 -1
  194. package/docs/variables/MAX_BUFFER_LEN.html +1 -1
  195. package/docs/variables/SESSION_TTL.html +1 -1
  196. package/docs/variables/WEBSERVER_DEV_URL.html +1 -1
  197. package/docs/variables/ZERO_DECIMAL.html +1 -1
  198. package/docs/variables/_private.html +2 -0
  199. package/eslint.config.mjs +66 -0
  200. package/package.json +20 -23
  201. package/src/bridge/client.ts +487 -0
  202. package/src/bridge/const.ts +53 -0
  203. package/src/bridge/index.ts +7 -0
  204. package/src/bridge/types.ts +127 -0
  205. package/src/bridge/utils.ts +140 -0
  206. package/src/const.ts +4 -9
  207. package/src/gen/common.ts +27 -10
  208. package/src/gen/nord.ts +1045 -487
  209. package/src/idl/bridge.ts +702 -0
  210. package/src/index.ts +21 -2
  211. package/src/nord/{actions.ts → api/actions.ts} +12 -16
  212. package/src/nord/api/core.ts +130 -0
  213. package/src/nord/api/market.ts +125 -0
  214. package/src/nord/api/metrics.ts +154 -0
  215. package/src/nord/api/queries.ts +236 -0
  216. package/src/nord/client/Nord.ts +652 -0
  217. package/src/nord/client/NordUser.ts +1101 -0
  218. package/src/nord/index.ts +16 -2
  219. package/src/nord/models/Subscriber.ts +56 -0
  220. package/src/nord/utils/NordError.ts +72 -0
  221. package/src/types.ts +163 -92
  222. package/src/utils.ts +22 -1
  223. package/src/websocket/NordWebSocketClient.ts +432 -0
  224. package/src/websocket/events.ts +31 -0
  225. package/src/websocket/index.ts +2 -0
  226. package/tsconfig.eslint.json +12 -0
  227. package/.eslintignore +0 -1
  228. package/.eslintrc.js +0 -20
  229. package/dist/abis/ERC20_ABI.d.ts +0 -39
  230. package/dist/abis/ERC20_ABI.js +0 -313
  231. package/dist/abis/NORD_GETTERS_FACET_ABI.d.ts +0 -34
  232. package/dist/abis/NORD_GETTERS_FACET_ABI.js +0 -195
  233. package/dist/abis/NORD_RAMP_FACET_ABI.d.ts +0 -35
  234. package/dist/abis/NORD_RAMP_FACET_ABI.js +0 -144
  235. package/dist/abis/index.d.ts +0 -3
  236. package/dist/abis/index.js +0 -9
  237. package/dist/nord/Nord.d.ts +0 -76
  238. package/dist/nord/Nord.js +0 -376
  239. package/dist/nord/NordImpl.d.ts +0 -7
  240. package/dist/nord/NordImpl.js +0 -6
  241. package/dist/nord/NordUser.d.ts +0 -77
  242. package/dist/nord/NordUser.js +0 -249
  243. package/docs/functions/createWebSocketSubscription.html +0 -12
  244. package/docs/interfaces/ERC20TokenInfo.html +0 -5
  245. package/docs/interfaces/OrderbookOrder.html +0 -6
  246. package/docs/interfaces/TradeInfo.html +0 -20
  247. package/docs/interfaces/TradesQueryParams.html +0 -10
  248. package/docs/variables/DEV_CONTRACT_ADDRESS.html +0 -1
  249. package/docs/variables/ERC20_ABI.html +0 -1
  250. package/docs/variables/EVM_DEV_URL.html +0 -1
  251. package/docs/variables/FAUCET_PRIVATE_ADDRESS.html +0 -1
  252. package/docs/variables/NORD_GETTERS_FACET_ABI.html +0 -1
  253. package/docs/variables/NORD_RAMP_FACET_ABI.html +0 -1
  254. package/src/abis/ERC20_ABI.ts +0 -310
  255. package/src/abis/NORD_GETTERS_FACET_ABI.ts +0 -192
  256. package/src/abis/NORD_RAMP_FACET_ABI.ts +0 -141
  257. package/src/abis/index.ts +0 -3
  258. package/src/nord/Nord.ts +0 -504
  259. package/src/nord/NordImpl.ts +0 -8
  260. package/src/nord/NordUser.ts +0 -469
@@ -0,0 +1,432 @@
1
+ import WebSocket from "ws";
2
+ import { EventEmitter } from "events";
3
+ import {
4
+ WebSocketMessage,
5
+ WebSocketMessageType,
6
+ WebSocketSubscription,
7
+ WebSocketTradeUpdate,
8
+ WebSocketDeltaUpdate,
9
+ WebSocketUserUpdate,
10
+ } from "../types";
11
+ import { NordWebSocketClientEvents } from "./events";
12
+
13
+ // Define a type that works for both Node.js ws and browser WebSocket
14
+ type BrowserWebSocket = {
15
+ OPEN: number;
16
+ CONNECTING: number;
17
+ CLOSING: number;
18
+ CLOSED: number;
19
+ readyState: number;
20
+ send: (data: string) => void;
21
+ close: () => void;
22
+ onopen: ((this: any, ev: any) => any) | null;
23
+ onmessage: ((this: any, ev: { data: any }) => any) | null;
24
+ onclose: ((this: any, ev: any) => any) | null;
25
+ onerror: ((this: any, ev: any) => any) | null;
26
+ };
27
+
28
+ type WebSocketInstance = WebSocket | BrowserWebSocket;
29
+
30
+ const VALID_STREAM_TYPES = ["trades", "deltas", "user"];
31
+
32
+ // Constants for WebSocket readyState
33
+ const WS_OPEN = 1;
34
+
35
+ /**
36
+ * WebSocket client for Nord exchange
37
+ *
38
+ * This client connects to one of the specific Nord WebSocket endpoints:
39
+ * - /ws/trades - For trade updates
40
+ * - /ws/deltas - For orderbook delta updates
41
+ * - /ws/user - For user-specific updates
42
+ *
43
+ * Each endpoint handles a specific type of data and subscriptions must match
44
+ * the endpoint type (e.g., only 'trades@BTCUSDC' subscriptions are valid on
45
+ * the /ws/trades endpoint).
46
+ */
47
+ export class NordWebSocketClient
48
+ extends EventEmitter
49
+ implements NordWebSocketClientEvents
50
+ {
51
+ private ws: WebSocketInstance | null = null;
52
+ private url: string;
53
+ private subscriptions: Set<string> = new Set();
54
+ private reconnectAttempts: number = 0;
55
+ private maxReconnectAttempts: number = 5;
56
+ private reconnectDelay: number = 1000;
57
+ private pingInterval: NodeJS.Timeout | null = null;
58
+ private pingTimeout: NodeJS.Timeout | null = null;
59
+ private isBrowser: boolean;
60
+
61
+ /**
62
+ * Create a new NordWebSocketClient
63
+ * @param url WebSocket server URL
64
+ */
65
+ constructor(url: string) {
66
+ super();
67
+ this.url = url;
68
+ // Check if we're in a browser environment
69
+ // The most reliable way is to check for Node.js process
70
+ this.isBrowser =
71
+ typeof process === "undefined" ||
72
+ !process.versions ||
73
+ !process.versions.node;
74
+ }
75
+
76
+ /**
77
+ * Validate stream format
78
+ * @param stream Stream identifier to validate
79
+ * @throws Error if stream format is invalid
80
+ */
81
+ private validateStream(stream: string): void {
82
+ const [type, params] = stream.split("@");
83
+
84
+ if (!type || !params) {
85
+ throw new Error(
86
+ `Invalid stream format: ${stream}. Expected format: <type>@<params>`,
87
+ );
88
+ }
89
+
90
+ // Extract the endpoint from the URL
91
+ const urlPath = new URL(this.url).pathname;
92
+ const endpoint = urlPath.split("/").pop();
93
+
94
+ // Ensure the stream type matches the endpoint we're connected to
95
+ if (endpoint && type !== endpoint) {
96
+ throw new Error(
97
+ `Stream type '${type}' doesn't match the connected endpoint '${endpoint}'`,
98
+ );
99
+ }
100
+
101
+ if (!VALID_STREAM_TYPES.includes(type)) {
102
+ throw new Error(
103
+ `Invalid stream type: ${type}. Valid types are: ${VALID_STREAM_TYPES.join(", ")}`,
104
+ );
105
+ }
106
+
107
+ if (type === "user" && !/^\d+$/.test(params)) {
108
+ throw new Error(
109
+ `Invalid user ID in stream: ${params}. Expected numeric ID`,
110
+ );
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Setup WebSocket ping/pong heartbeat
116
+ */
117
+ private setupHeartbeat(): void {
118
+ if (this.pingInterval) {
119
+ clearInterval(this.pingInterval);
120
+ }
121
+ if (this.pingTimeout) {
122
+ clearTimeout(this.pingTimeout);
123
+ }
124
+
125
+ // In browser, we rely on the browser's WebSocket implementation to handle ping/pong
126
+ if (this.isBrowser) {
127
+ return;
128
+ }
129
+
130
+ this.pingInterval = setInterval(() => {
131
+ if (this.ws && !this.isBrowser) {
132
+ // Only use ping() method in Node.js environment
133
+ (this.ws as WebSocket).ping();
134
+
135
+ // Set timeout for pong response
136
+ this.pingTimeout = setTimeout(() => {
137
+ this.emit("error", new Error("WebSocket ping timeout"));
138
+ this.close();
139
+ this.reconnect();
140
+ }, 5000); // 5 second timeout
141
+ }
142
+ }, 30000); // Send ping every 30 seconds
143
+ }
144
+
145
+ /**
146
+ * Get the appropriate WebSocket class based on environment
147
+ */
148
+ private getWebSocketClass(): any {
149
+ if (this.isBrowser) {
150
+ // In browser environments
151
+ // @ts-expect-error - Check for WebSocket in globalThis
152
+ if (typeof globalThis !== "undefined" && globalThis.WebSocket) {
153
+ // @ts-expect-error - Return WebSocket from globalThis
154
+ return globalThis.WebSocket;
155
+ }
156
+ throw new Error("WebSocket is not available in this environment");
157
+ } else {
158
+ // In Node.js
159
+ return WebSocket;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Connect to the Nord WebSocket server
165
+ */
166
+ public connect(): void {
167
+ if (this.ws) {
168
+ return;
169
+ }
170
+
171
+ try {
172
+ const WebSocketClass = this.getWebSocketClass();
173
+
174
+ if (this.isBrowser) {
175
+ // Browser WebSocket setup
176
+ this.ws = new WebSocketClass(this.url) as BrowserWebSocket;
177
+
178
+ (this.ws as BrowserWebSocket).onopen = () => {
179
+ this.emit("connected");
180
+ this.reconnectAttempts = 0;
181
+ this.reconnectDelay = 1000;
182
+
183
+ // Resubscribe to previous subscriptions
184
+ if (this.subscriptions.size > 0) {
185
+ this.subscribe([...this.subscriptions]);
186
+ }
187
+ };
188
+
189
+ (this.ws as BrowserWebSocket).onmessage = (event: { data: any }) => {
190
+ try {
191
+ const message = JSON.parse(
192
+ event.data as string,
193
+ ) as WebSocketMessage;
194
+ this.handleMessage(message);
195
+ } catch (error) {
196
+ this.emit(
197
+ "error",
198
+ new Error(
199
+ `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`,
200
+ ),
201
+ );
202
+ }
203
+ };
204
+
205
+ (this.ws as BrowserWebSocket).onclose = (event: any) => {
206
+ const reason =
207
+ event && event.reason ? ` Reason: ${event.reason}` : "";
208
+ const code = event && event.code ? ` Code: ${event.code}` : "";
209
+ this.emit("disconnected");
210
+ console.log(`WebSocket closed.${code}${reason}`);
211
+ this.reconnect();
212
+ };
213
+
214
+ (this.ws as BrowserWebSocket).onerror = (event: any) => {
215
+ const errorMsg = `WebSocket error: ${event && event.type ? event.type : "unknown"}`;
216
+ console.error(errorMsg, event);
217
+ this.emit("error", new Error(errorMsg));
218
+ };
219
+ } else {
220
+ // Node.js WebSocket setup
221
+ const nodeWs = new WebSocketClass(this.url) as WebSocket;
222
+ this.ws = nodeWs;
223
+
224
+ nodeWs.on("open", () => {
225
+ this.emit("connected");
226
+ this.reconnectAttempts = 0;
227
+ this.reconnectDelay = 1000;
228
+ this.setupHeartbeat();
229
+
230
+ // Resubscribe to previous subscriptions
231
+ if (this.subscriptions.size > 0) {
232
+ this.subscribe([...this.subscriptions]);
233
+ }
234
+ });
235
+
236
+ nodeWs.on("message", (data: WebSocket.Data) => {
237
+ try {
238
+ const message = JSON.parse(data.toString()) as WebSocketMessage;
239
+ this.handleMessage(message);
240
+ } catch (error) {
241
+ this.emit(
242
+ "error",
243
+ new Error(
244
+ `Failed to parse message: ${error instanceof Error ? error.message : String(error)}`,
245
+ ),
246
+ );
247
+ }
248
+ });
249
+
250
+ nodeWs.on("close", (code: number, reason: string) => {
251
+ this.emit("disconnected");
252
+ console.log(`WebSocket closed. Code: ${code} Reason: ${reason}`);
253
+ if (this.pingInterval) {
254
+ clearInterval(this.pingInterval);
255
+ }
256
+ if (this.pingTimeout) {
257
+ clearTimeout(this.pingTimeout);
258
+ }
259
+ this.reconnect();
260
+ });
261
+
262
+ nodeWs.on("error", (error: Error) => {
263
+ console.error("WebSocket error:", error);
264
+ this.emit("error", error);
265
+ });
266
+
267
+ nodeWs.on("pong", () => {
268
+ if (this.pingTimeout) {
269
+ clearTimeout(this.pingTimeout);
270
+ }
271
+ });
272
+ }
273
+ } catch (error) {
274
+ const errorMsg = `Failed to initialize WebSocket: ${error instanceof Error ? error.message : String(error)}`;
275
+ console.error(errorMsg);
276
+ this.emit("error", new Error(errorMsg));
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Subscribe to one or more streams
282
+ * @param streams Array of streams to subscribe to (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
283
+ */
284
+ public subscribe(streams: string[]): void {
285
+ // Validate all streams first
286
+ try {
287
+ streams.forEach((stream) => this.validateStream(stream));
288
+ } catch (error) {
289
+ this.emit(
290
+ "error",
291
+ error instanceof Error ? error : new Error(String(error)),
292
+ );
293
+ return;
294
+ }
295
+
296
+ if (
297
+ !this.ws ||
298
+ (this.isBrowser
299
+ ? (this.ws as BrowserWebSocket).readyState !== WS_OPEN
300
+ : (this.ws as WebSocket).readyState !== WebSocket.OPEN)
301
+ ) {
302
+ streams.forEach((stream) => this.subscriptions.add(stream));
303
+ return;
304
+ }
305
+
306
+ const message: WebSocketSubscription = {
307
+ type: WebSocketMessageType.Subscribe,
308
+ streams,
309
+ };
310
+
311
+ try {
312
+ const messageStr = JSON.stringify(message);
313
+ if (this.isBrowser) {
314
+ (this.ws as BrowserWebSocket).send(messageStr);
315
+ } else {
316
+ (this.ws as WebSocket).send(messageStr);
317
+ }
318
+ streams.forEach((stream) => this.subscriptions.add(stream));
319
+ } catch (error) {
320
+ this.emit(
321
+ "error",
322
+ error instanceof Error ? error : new Error(String(error)),
323
+ );
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Unsubscribe from one or more streams
329
+ * @param streams Array of streams to unsubscribe from
330
+ */
331
+ public unsubscribe(streams: string[]): void {
332
+ // Validate all streams first
333
+ try {
334
+ streams.forEach((stream) => this.validateStream(stream));
335
+ } catch (error) {
336
+ this.emit(
337
+ "error",
338
+ error instanceof Error ? error : new Error(String(error)),
339
+ );
340
+ return;
341
+ }
342
+
343
+ if (
344
+ !this.ws ||
345
+ (this.isBrowser
346
+ ? (this.ws as BrowserWebSocket).readyState !== WS_OPEN
347
+ : (this.ws as WebSocket).readyState !== WebSocket.OPEN)
348
+ ) {
349
+ streams.forEach((stream) => this.subscriptions.delete(stream));
350
+ return;
351
+ }
352
+
353
+ const message: WebSocketSubscription = {
354
+ type: WebSocketMessageType.Unsubscribe,
355
+ streams,
356
+ };
357
+
358
+ try {
359
+ const messageStr = JSON.stringify(message);
360
+ if (this.isBrowser) {
361
+ (this.ws as BrowserWebSocket).send(messageStr);
362
+ } else {
363
+ (this.ws as WebSocket).send(messageStr);
364
+ }
365
+ streams.forEach((stream) => this.subscriptions.delete(stream));
366
+ } catch (error) {
367
+ this.emit(
368
+ "error",
369
+ error instanceof Error ? error : new Error(String(error)),
370
+ );
371
+ }
372
+ }
373
+
374
+ /**
375
+ * Close the WebSocket connection
376
+ */
377
+ public close(): void {
378
+ if (this.ws) {
379
+ if (this.isBrowser) {
380
+ (this.ws as BrowserWebSocket).close();
381
+ } else {
382
+ (this.ws as WebSocket).close();
383
+ }
384
+ this.ws = null;
385
+ }
386
+ if (this.pingInterval) {
387
+ clearInterval(this.pingInterval);
388
+ this.pingInterval = null;
389
+ }
390
+ if (this.pingTimeout) {
391
+ clearTimeout(this.pingTimeout);
392
+ this.pingTimeout = null;
393
+ }
394
+ this.subscriptions.clear();
395
+ }
396
+
397
+ /**
398
+ * Handle incoming WebSocket messages
399
+ * @param message WebSocket message
400
+ */
401
+ private handleMessage(message: WebSocketMessage): void {
402
+ switch (message.type) {
403
+ case WebSocketMessageType.TradeUpdate:
404
+ this.emit("trade", message as WebSocketTradeUpdate);
405
+ break;
406
+ case WebSocketMessageType.DeltaUpdate:
407
+ this.emit("delta", message as WebSocketDeltaUpdate);
408
+ break;
409
+ case WebSocketMessageType.UserUpdate:
410
+ this.emit("user", message as WebSocketUserUpdate);
411
+ break;
412
+ default:
413
+ this.emit("error", new Error(`Unknown message type: ${message.type}`));
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Attempt to reconnect to the WebSocket server
419
+ */
420
+ private reconnect(): void {
421
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
422
+ this.emit("error", new Error("Max reconnection attempts reached"));
423
+ return;
424
+ }
425
+
426
+ setTimeout(() => {
427
+ this.reconnectAttempts++;
428
+ this.reconnectDelay *= 2; // Exponential backoff
429
+ this.connect();
430
+ }, this.reconnectDelay);
431
+ }
432
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ WebSocketTradeUpdate,
3
+ WebSocketDeltaUpdate,
4
+ WebSocketUserUpdate,
5
+ } from "../types";
6
+
7
+ /**
8
+ * Event type definitions for the NordWebSocketClient
9
+ */
10
+ export interface NordWebSocketEvents {
11
+ connected: () => void;
12
+ disconnected: () => void;
13
+ error: (error: Error) => void;
14
+ trade: (update: WebSocketTradeUpdate) => void;
15
+ delta: (update: WebSocketDeltaUpdate) => void;
16
+ user: (update: WebSocketUserUpdate) => void;
17
+ }
18
+
19
+ /**
20
+ * Type declaration for NordWebSocketClient event methods
21
+ */
22
+ export declare interface NordWebSocketClientEvents {
23
+ on<E extends keyof NordWebSocketEvents>(
24
+ event: E,
25
+ listener: NordWebSocketEvents[E],
26
+ ): this;
27
+ emit<E extends keyof NordWebSocketEvents>(
28
+ event: E,
29
+ ...args: Parameters<NordWebSocketEvents[E]>
30
+ ): boolean;
31
+ }
@@ -0,0 +1,2 @@
1
+ export { NordWebSocketClient } from "./NordWebSocketClient";
2
+ export { NordWebSocketEvents, NordWebSocketClientEvents } from "./events";
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "."
6
+ },
7
+ "include": [
8
+ "src/**/*.ts",
9
+ "tests/**/*.ts",
10
+ "jest.config.ts"
11
+ ]
12
+ }
package/.eslintignore DELETED
@@ -1 +0,0 @@
1
- src/gen/*
package/.eslintrc.js DELETED
@@ -1,20 +0,0 @@
1
- module.exports = {
2
- env: {
3
- browser: true,
4
- es2021: true,
5
- },
6
- extends: [
7
- "prettier",
8
- "plugin:@typescript-eslint/eslint-recommended",
9
- "plugin:@typescript-eslint/recommended",
10
- ],
11
- parser: "@typescript-eslint/parser",
12
- plugins: ["@typescript-eslint"],
13
- parserOptions: {
14
- ecmaVersion: "latest",
15
- sourceType: "module",
16
- },
17
- rules: {
18
- "@typescript-eslint/no-explicit-any": "warn",
19
- },
20
- };
@@ -1,39 +0,0 @@
1
- export declare const ERC20_ABI: ({
2
- type: string;
3
- name: string;
4
- inputs: {
5
- name: string;
6
- type: string;
7
- internalType: string;
8
- }[];
9
- outputs: {
10
- name: string;
11
- type: string;
12
- internalType: string;
13
- }[];
14
- stateMutability: string;
15
- anonymous?: undefined;
16
- } | {
17
- type: string;
18
- name: string;
19
- inputs: {
20
- name: string;
21
- type: string;
22
- indexed: boolean;
23
- internalType: string;
24
- }[];
25
- anonymous: boolean;
26
- outputs?: undefined;
27
- stateMutability?: undefined;
28
- } | {
29
- type: string;
30
- name: string;
31
- inputs: {
32
- name: string;
33
- type: string;
34
- internalType: string;
35
- }[];
36
- outputs?: undefined;
37
- stateMutability?: undefined;
38
- anonymous?: undefined;
39
- })[];