@n1xyz/nord-ts 0.0.1 → 0.0.4

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 (237) hide show
  1. package/.eslintrc.js +11 -0
  2. package/README.md +148 -65
  3. package/dist/bridge/NordUser.d.ts +78 -0
  4. package/dist/bridge/NordUser.js +196 -0
  5. package/dist/bridge/client.d.ts +150 -0
  6. package/dist/bridge/client.js +394 -0
  7. package/dist/bridge/const.d.ts +23 -0
  8. package/dist/bridge/const.js +47 -0
  9. package/dist/bridge/index.d.ts +5 -0
  10. package/dist/bridge/index.js +23 -0
  11. package/dist/bridge/types.d.ts +118 -0
  12. package/dist/bridge/types.js +16 -0
  13. package/dist/bridge/utils.d.ts +64 -0
  14. package/dist/bridge/utils.js +131 -0
  15. package/dist/client.d.ts +70 -0
  16. package/dist/client.js +129 -0
  17. package/dist/const.d.ts +2 -5
  18. package/dist/const.js +18 -22
  19. package/dist/constants/endpoints.d.ts +65 -0
  20. package/dist/constants/endpoints.js +68 -0
  21. package/dist/gen/common.d.ts +6 -1
  22. package/dist/gen/common.js +19 -9
  23. package/dist/gen/nord.d.ts +75 -17
  24. package/dist/gen/nord.js +987 -423
  25. package/dist/idl/bridge.d.ts +2 -0
  26. package/dist/idl/bridge.js +703 -0
  27. package/dist/index.d.ts +8 -5
  28. package/dist/index.js +18 -2
  29. package/dist/models/account.d.ts +58 -0
  30. package/dist/models/account.js +6 -0
  31. package/dist/models/index.d.ts +8 -0
  32. package/dist/models/index.js +28 -0
  33. package/dist/models/market.d.ts +137 -0
  34. package/dist/models/market.js +6 -0
  35. package/dist/models/order.d.ts +211 -0
  36. package/dist/models/order.js +6 -0
  37. package/dist/models/token.d.ts +50 -0
  38. package/dist/models/token.js +6 -0
  39. package/dist/nord/Nord.d.ts +222 -49
  40. package/dist/nord/Nord.js +290 -278
  41. package/dist/nord/NordError.d.ts +23 -0
  42. package/dist/nord/NordError.js +48 -0
  43. package/dist/nord/NordImpl.d.ts +6 -2
  44. package/dist/nord/NordImpl.js +21 -1
  45. package/dist/nord/NordUser.d.ts +208 -42
  46. package/dist/nord/NordUser.js +389 -157
  47. package/dist/nord/Subscriber.d.ts +37 -0
  48. package/dist/nord/Subscriber.js +29 -0
  49. package/dist/nord/api/actions.d.ts +101 -0
  50. package/dist/nord/api/actions.js +250 -0
  51. package/dist/nord/api/core.d.ts +49 -0
  52. package/dist/nord/api/core.js +121 -0
  53. package/dist/nord/api/index.d.ts +1 -0
  54. package/dist/nord/api/index.js +17 -0
  55. package/dist/nord/api/market.d.ts +36 -0
  56. package/dist/nord/api/market.js +98 -0
  57. package/dist/nord/api/metrics.d.ts +67 -0
  58. package/dist/nord/api/metrics.js +132 -0
  59. package/dist/nord/api/orderFunctions.d.ts +168 -0
  60. package/dist/nord/api/orderFunctions.js +133 -0
  61. package/dist/nord/api/queries.d.ts +81 -0
  62. package/dist/nord/api/queries.js +187 -0
  63. package/dist/nord/client/Nord.d.ts +335 -0
  64. package/dist/nord/client/Nord.js +532 -0
  65. package/dist/nord/client/NordUser.d.ts +320 -0
  66. package/dist/nord/client/NordUser.js +701 -0
  67. package/dist/nord/core.d.ts +48 -0
  68. package/dist/nord/core.js +97 -0
  69. package/dist/nord/index.d.ts +9 -2
  70. package/dist/nord/index.js +30 -6
  71. package/dist/nord/market.d.ts +36 -0
  72. package/dist/nord/market.js +90 -0
  73. package/dist/nord/metrics.d.ts +67 -0
  74. package/dist/nord/metrics.js +124 -0
  75. package/dist/nord/models/Subscriber.d.ts +37 -0
  76. package/dist/nord/models/Subscriber.js +29 -0
  77. package/dist/nord/queries.d.ts +81 -0
  78. package/dist/nord/queries.js +181 -0
  79. package/dist/nord/types.d.ts +88 -0
  80. package/dist/nord/types.js +2 -0
  81. package/dist/nord/utils/NordError.d.ts +35 -0
  82. package/dist/nord/utils/NordError.js +46 -0
  83. package/dist/nord/websocket.d.ts +49 -0
  84. package/dist/nord/websocket.js +107 -0
  85. package/dist/operations/account.d.ts +58 -0
  86. package/dist/operations/account.js +112 -0
  87. package/dist/operations/market.d.ts +65 -0
  88. package/dist/operations/market.js +131 -0
  89. package/dist/operations/orders.d.ts +57 -0
  90. package/dist/operations/orders.js +129 -0
  91. package/dist/solana/NordUser.d.ts +78 -0
  92. package/dist/solana/NordUser.js +196 -0
  93. package/dist/solana/client.d.ts +139 -0
  94. package/dist/solana/client.js +360 -0
  95. package/dist/solana/const.d.ts +23 -0
  96. package/dist/solana/const.js +47 -0
  97. package/dist/solana/index.d.ts +5 -0
  98. package/dist/solana/index.js +23 -0
  99. package/dist/solana/types.d.ts +118 -0
  100. package/dist/solana/types.js +16 -0
  101. package/dist/solana/utils.d.ts +64 -0
  102. package/dist/solana/utils.js +131 -0
  103. package/dist/types/api.d.ts +152 -0
  104. package/dist/types/api.js +6 -0
  105. package/dist/types/config.d.ts +34 -0
  106. package/dist/types/config.js +6 -0
  107. package/dist/types.d.ts +144 -87
  108. package/dist/types.js +13 -2
  109. package/dist/utils/errors.d.ts +96 -0
  110. package/dist/utils/errors.js +132 -0
  111. package/dist/utils/http.d.ts +35 -0
  112. package/dist/utils/http.js +105 -0
  113. package/dist/utils.d.ts +14 -5
  114. package/dist/utils.js +26 -7
  115. package/dist/websocket/NordWebSocketClient.d.ts +71 -0
  116. package/dist/websocket/NordWebSocketClient.js +343 -0
  117. package/dist/websocket/client.d.ts +93 -0
  118. package/dist/websocket/client.js +222 -0
  119. package/dist/websocket/events.d.ts +19 -0
  120. package/dist/websocket/events.js +2 -0
  121. package/dist/websocket/index.d.ts +2 -0
  122. package/dist/websocket/index.js +5 -0
  123. package/dist/websocket.d.ts +55 -0
  124. package/dist/websocket.js +211 -0
  125. package/docs/assets/navigation.js +1 -1
  126. package/docs/assets/search.js +1 -1
  127. package/docs/classes/Nord.html +2 -15
  128. package/docs/classes/NordUser.html +4 -4
  129. package/docs/enums/FillMode.html +2 -2
  130. package/docs/enums/KeyType.html +2 -2
  131. package/docs/enums/PeakTpsPeriodUnit.html +2 -2
  132. package/docs/enums/Side.html +2 -2
  133. package/docs/functions/assert.html +1 -1
  134. package/docs/functions/bigIntToProtoU128.html +1 -1
  135. package/docs/functions/checkPubKeyLength.html +1 -1
  136. package/docs/functions/checkedFetch.html +1 -1
  137. package/docs/functions/decodeLengthDelimited.html +1 -1
  138. package/docs/functions/encodeLengthDelimited.html +1 -1
  139. package/docs/functions/fillModeToProtoFillMode.html +1 -1
  140. package/docs/functions/findMarket.html +1 -1
  141. package/docs/functions/findToken.html +1 -1
  142. package/docs/functions/makeWalletSignFn.html +1 -1
  143. package/docs/functions/optExpect.html +1 -1
  144. package/docs/functions/optMap.html +1 -1
  145. package/docs/functions/optUnwrap.html +1 -1
  146. package/docs/functions/panic.html +1 -1
  147. package/docs/functions/signAction.html +1 -1
  148. package/docs/functions/toScaledU128.html +1 -1
  149. package/docs/functions/toScaledU64.html +1 -1
  150. package/docs/interfaces/Account.html +2 -2
  151. package/docs/interfaces/ActionInfo.html +2 -2
  152. package/docs/interfaces/ActionQuery.html +2 -2
  153. package/docs/interfaces/ActionResponse.html +2 -2
  154. package/docs/interfaces/ActionsExtendedInfo.html +2 -2
  155. package/docs/interfaces/ActionsQuery.html +2 -2
  156. package/docs/interfaces/ActionsResponse.html +2 -2
  157. package/docs/interfaces/AggregateMetrics.html +2 -2
  158. package/docs/interfaces/BlockQuery.html +2 -2
  159. package/docs/interfaces/BlockResponse.html +2 -2
  160. package/docs/interfaces/BlockSummary.html +2 -2
  161. package/docs/interfaces/BlockSummaryResponse.html +2 -2
  162. package/docs/interfaces/DeltaEvent.html +2 -2
  163. package/docs/interfaces/ERC20TokenInfo.html +2 -2
  164. package/docs/interfaces/Info.html +2 -2
  165. package/docs/interfaces/Market.html +2 -2
  166. package/docs/interfaces/MarketStats.html +2 -2
  167. package/docs/interfaces/MarketsStatsResponse.html +2 -2
  168. package/docs/interfaces/NordConfig.html +2 -2
  169. package/docs/interfaces/Order.html +2 -2
  170. package/docs/interfaces/OrderInfo.html +2 -2
  171. package/docs/interfaces/PerpMarketStats.html +2 -2
  172. package/docs/interfaces/RollmanActionExtendedInfo.html +2 -2
  173. package/docs/interfaces/RollmanActionInfo.html +2 -2
  174. package/docs/interfaces/RollmanActionResponse.html +2 -2
  175. package/docs/interfaces/RollmanActionsResponse.html +2 -2
  176. package/docs/interfaces/RollmanBlockResponse.html +2 -2
  177. package/docs/interfaces/SubscriberConfig.html +2 -2
  178. package/docs/interfaces/Token.html +2 -2
  179. package/docs/interfaces/Trade.html +2 -2
  180. package/docs/interfaces/Trades.html +2 -2
  181. package/docs/modules.html +0 -7
  182. package/docs/types/BigIntValue.html +1 -1
  183. package/docs/variables/DEBUG_KEYS.html +1 -1
  184. package/docs/variables/DEFAULT_FUNDING_AMOUNTS.html +1 -1
  185. package/docs/variables/DEV_CONTRACT_ADDRESS.html +1 -1
  186. package/docs/variables/DEV_TOKEN_INFOS.html +1 -1
  187. package/docs/variables/DEV_URL.html +1 -1
  188. package/docs/variables/ERC20_ABI.html +1 -1
  189. package/docs/variables/EVM_DEV_URL.html +1 -1
  190. package/docs/variables/FAUCET_PRIVATE_ADDRESS.html +1 -1
  191. package/docs/variables/MAX_BUFFER_LEN.html +1 -1
  192. package/docs/variables/NORD_GETTERS_FACET_ABI.html +1 -1
  193. package/docs/variables/NORD_RAMP_FACET_ABI.html +1 -1
  194. package/docs/variables/SESSION_TTL.html +1 -1
  195. package/docs/variables/WEBSERVER_DEV_URL.html +1 -1
  196. package/docs/variables/ZERO_DECIMAL.html +1 -1
  197. package/package.json +10 -12
  198. package/src/bridge/client.ts +487 -0
  199. package/src/bridge/const.ts +53 -0
  200. package/src/bridge/index.ts +7 -0
  201. package/src/bridge/types.ts +127 -0
  202. package/src/bridge/utils.ts +140 -0
  203. package/src/const.ts +20 -25
  204. package/src/gen/common.ts +27 -10
  205. package/src/gen/nord.ts +1044 -483
  206. package/src/idl/bridge.ts +702 -0
  207. package/src/index.ts +24 -5
  208. package/src/nord/{actions.ts → api/actions.ts} +33 -37
  209. package/src/nord/api/core.ts +130 -0
  210. package/src/nord/api/market.ts +125 -0
  211. package/src/nord/api/metrics.ts +154 -0
  212. package/src/nord/api/queries.ts +236 -0
  213. package/src/nord/client/Nord.ts +652 -0
  214. package/src/nord/client/NordUser.ts +1105 -0
  215. package/src/nord/index.ts +16 -2
  216. package/src/nord/models/Subscriber.ts +57 -0
  217. package/src/nord/utils/NordError.ts +72 -0
  218. package/src/types.ts +170 -99
  219. package/src/utils.ts +40 -19
  220. package/src/websocket/NordWebSocketClient.ts +432 -0
  221. package/src/websocket/events.ts +31 -0
  222. package/src/websocket/index.ts +2 -0
  223. package/tests/utils.spec.ts +24 -24
  224. package/docs/classes/Subscriber.html +0 -6
  225. package/docs/functions/createWebSocketSubscription.html +0 -12
  226. package/docs/interfaces/OrderbookOrder.html +0 -6
  227. package/docs/interfaces/OrderbookResponse.html +0 -10
  228. package/docs/interfaces/TradeInfo.html +0 -20
  229. package/docs/interfaces/TradesQueryParams.html +0 -10
  230. package/docs/interfaces/TradesResponse.html +0 -12
  231. package/src/abis/ERC20_ABI.ts +0 -310
  232. package/src/abis/NORD_GETTERS_FACET_ABI.ts +0 -192
  233. package/src/abis/NORD_RAMP_FACET_ABI.ts +0 -141
  234. package/src/abis/index.ts +0 -3
  235. package/src/nord/Nord.ts +0 -504
  236. package/src/nord/NordImpl.ts +0 -8
  237. package/src/nord/NordUser.ts +0 -469
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ /**
3
+ * WebSocket client for real-time data
4
+ * @module websocket/client
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.WebSocketClient = void 0;
8
+ /**
9
+ * WebSocket client for real-time data
10
+ */
11
+ class WebSocketClient {
12
+ /**
13
+ * Create a new WebSocket client
14
+ *
15
+ * @param baseUrl - Base URL for the WebSocket server
16
+ */
17
+ constructor(baseUrl) {
18
+ /**
19
+ * WebSocket connection
20
+ */
21
+ this.ws = null;
22
+ /**
23
+ * Map of subscription IDs to callbacks
24
+ */
25
+ this.subscriptions = new Map();
26
+ /**
27
+ * Whether the WebSocket is connected
28
+ */
29
+ this.connected = false;
30
+ /**
31
+ * Whether the WebSocket is connecting
32
+ */
33
+ this.connecting = false;
34
+ /**
35
+ * Queue of messages to send when connected
36
+ */
37
+ this.messageQueue = [];
38
+ // Convert HTTP/HTTPS to WS/WSS
39
+ this.baseUrl = baseUrl.replace(/^http/, 'ws') + '/ws';
40
+ }
41
+ /**
42
+ * Connect to the WebSocket server
43
+ *
44
+ * @returns Promise that resolves when connected
45
+ */
46
+ connect() {
47
+ if (this.connected) {
48
+ return Promise.resolve();
49
+ }
50
+ if (this.connecting) {
51
+ return new Promise((resolve) => {
52
+ // Check connection status every 100ms
53
+ const interval = setInterval(() => {
54
+ if (this.connected) {
55
+ clearInterval(interval);
56
+ resolve();
57
+ }
58
+ }, 100);
59
+ });
60
+ }
61
+ this.connecting = true;
62
+ return new Promise((resolve, reject) => {
63
+ try {
64
+ this.ws = new WebSocket(this.baseUrl);
65
+ this.ws.onopen = () => {
66
+ this.connected = true;
67
+ this.connecting = false;
68
+ // Send queued messages
69
+ while (this.messageQueue.length > 0) {
70
+ const message = this.messageQueue.shift();
71
+ if (message && this.ws) {
72
+ this.ws.send(message);
73
+ }
74
+ }
75
+ resolve();
76
+ };
77
+ this.ws.onclose = () => {
78
+ this.connected = false;
79
+ this.ws = null;
80
+ // Attempt to reconnect after 5 seconds
81
+ setTimeout(() => {
82
+ if (!this.connected && !this.connecting) {
83
+ this.connect();
84
+ }
85
+ }, 5000);
86
+ };
87
+ this.ws.onerror = (error) => {
88
+ if (!this.connected) {
89
+ this.connecting = false;
90
+ reject(error);
91
+ }
92
+ console.error('WebSocket error:', error);
93
+ };
94
+ this.ws.onmessage = (event) => {
95
+ try {
96
+ const data = JSON.parse(event.data);
97
+ // Handle subscription updates
98
+ if (data.type === 'update' && data.subscriptionId && this.subscriptions.has(data.subscriptionId)) {
99
+ const callback = this.subscriptions.get(data.subscriptionId);
100
+ if (callback) {
101
+ callback(data.data);
102
+ }
103
+ }
104
+ }
105
+ catch (error) {
106
+ console.error('Error processing WebSocket message:', error);
107
+ }
108
+ };
109
+ }
110
+ catch (error) {
111
+ this.connecting = false;
112
+ reject(error);
113
+ }
114
+ });
115
+ }
116
+ /**
117
+ * Disconnect from the WebSocket server
118
+ */
119
+ disconnect() {
120
+ if (this.ws) {
121
+ this.ws.close();
122
+ this.ws = null;
123
+ this.connected = false;
124
+ }
125
+ }
126
+ /**
127
+ * Send a message to the WebSocket server
128
+ *
129
+ * @param message - Message to send
130
+ */
131
+ sendMessage(message) {
132
+ const messageStr = JSON.stringify(message);
133
+ if (this.connected && this.ws) {
134
+ this.ws.send(messageStr);
135
+ }
136
+ else {
137
+ // Queue message to send when connected
138
+ this.messageQueue.push(messageStr);
139
+ this.connect();
140
+ }
141
+ }
142
+ /**
143
+ * Generate a unique subscription ID
144
+ *
145
+ * @returns Unique subscription ID
146
+ */
147
+ generateSubscriptionId() {
148
+ return Math.random().toString(36).substring(2, 15);
149
+ }
150
+ /**
151
+ * Subscribe to orderbook updates for a specific market
152
+ *
153
+ * @param market - Market symbol (e.g., "BTCUSDC")
154
+ * @param callback - Callback function to handle updates
155
+ * @returns Subscription ID
156
+ */
157
+ subscribeToOrderbook(market, callback) {
158
+ const subscriptionId = this.generateSubscriptionId();
159
+ this.subscriptions.set(subscriptionId, callback);
160
+ this.sendMessage({
161
+ type: 'subscribe',
162
+ channel: 'orderbook',
163
+ market,
164
+ subscriptionId
165
+ });
166
+ return subscriptionId;
167
+ }
168
+ /**
169
+ * Subscribe to trade updates for a specific market
170
+ *
171
+ * @param market - Market symbol (e.g., "BTCUSDC")
172
+ * @param callback - Callback function to handle updates
173
+ * @returns Subscription ID
174
+ */
175
+ subscribeToTrades(market, callback) {
176
+ const subscriptionId = this.generateSubscriptionId();
177
+ this.subscriptions.set(subscriptionId, callback);
178
+ this.sendMessage({
179
+ type: 'subscribe',
180
+ channel: 'trades',
181
+ market,
182
+ subscriptionId
183
+ });
184
+ return subscriptionId;
185
+ }
186
+ /**
187
+ * Subscribe to user updates for a specific account
188
+ *
189
+ * @param accountId - Account ID
190
+ * @param callback - Callback function to handle updates
191
+ * @returns Subscription ID
192
+ */
193
+ subscribeToUserUpdates(accountId, callback) {
194
+ const subscriptionId = this.generateSubscriptionId();
195
+ this.subscriptions.set(subscriptionId, callback);
196
+ this.sendMessage({
197
+ type: 'subscribe',
198
+ channel: 'user',
199
+ accountId,
200
+ subscriptionId
201
+ });
202
+ return subscriptionId;
203
+ }
204
+ /**
205
+ * Unsubscribe from a subscription
206
+ *
207
+ * @param subscriptionId - Subscription ID to unsubscribe from
208
+ * @returns Whether the unsubscription was successful
209
+ */
210
+ unsubscribe(subscriptionId) {
211
+ if (!this.subscriptions.has(subscriptionId)) {
212
+ return false;
213
+ }
214
+ this.subscriptions.delete(subscriptionId);
215
+ this.sendMessage({
216
+ type: 'unsubscribe',
217
+ subscriptionId
218
+ });
219
+ return true;
220
+ }
221
+ }
222
+ exports.WebSocketClient = WebSocketClient;
@@ -0,0 +1,19 @@
1
+ import { WebSocketTradeUpdate, WebSocketDeltaUpdate, WebSocketUserUpdate } from '../types';
2
+ /**
3
+ * Event type definitions for the NordWebSocketClient
4
+ */
5
+ export interface NordWebSocketEvents {
6
+ connected: () => void;
7
+ disconnected: () => void;
8
+ error: (error: Error) => void;
9
+ trade: (update: WebSocketTradeUpdate) => void;
10
+ delta: (update: WebSocketDeltaUpdate) => void;
11
+ user: (update: WebSocketUserUpdate) => void;
12
+ }
13
+ /**
14
+ * Type declaration for NordWebSocketClient event methods
15
+ */
16
+ export declare interface NordWebSocketClientEvents {
17
+ on<E extends keyof NordWebSocketEvents>(event: E, listener: NordWebSocketEvents[E]): this;
18
+ emit<E extends keyof NordWebSocketEvents>(event: E, ...args: Parameters<NordWebSocketEvents[E]>): boolean;
19
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export { NordWebSocketClient } from './NordWebSocketClient';
2
+ export { NordWebSocketEvents, NordWebSocketClientEvents } from './events';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NordWebSocketClient = void 0;
4
+ var NordWebSocketClient_1 = require("./NordWebSocketClient");
5
+ Object.defineProperty(exports, "NordWebSocketClient", { enumerable: true, get: function () { return NordWebSocketClient_1.NordWebSocketClient; } });
@@ -0,0 +1,55 @@
1
+ import { EventEmitter } from "events";
2
+ import { WebSocketTradeUpdate, WebSocketDeltaUpdate, WebSocketUserUpdate } from "./types";
3
+ export declare class NordWebSocketClient extends EventEmitter {
4
+ private ws;
5
+ private url;
6
+ private subscriptions;
7
+ private reconnectAttempts;
8
+ private maxReconnectAttempts;
9
+ private reconnectDelay;
10
+ private pingInterval;
11
+ private pingTimeout;
12
+ constructor(url: string);
13
+ /**
14
+ * Validate stream format
15
+ * @param stream Stream identifier to validate
16
+ * @throws Error if stream format is invalid
17
+ */
18
+ private validateStream;
19
+ /**
20
+ * Setup WebSocket ping/pong heartbeat
21
+ */
22
+ private setupHeartbeat;
23
+ /**
24
+ * Connect to the Nord WebSocket server
25
+ */
26
+ connect(): void;
27
+ /**
28
+ * Subscribe to one or more streams
29
+ * @param streams Array of streams to subscribe to (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
30
+ */
31
+ subscribe(streams: string[]): void;
32
+ /**
33
+ * Unsubscribe from one or more streams
34
+ * @param streams Array of streams to unsubscribe from
35
+ */
36
+ unsubscribe(streams: string[]): void;
37
+ /**
38
+ * Close the WebSocket connection
39
+ */
40
+ close(): void;
41
+ private handleMessage;
42
+ private reconnect;
43
+ }
44
+ export interface NordWebSocketEvents {
45
+ connected: () => void;
46
+ disconnected: () => void;
47
+ error: (error: Error) => void;
48
+ trade: (update: WebSocketTradeUpdate) => void;
49
+ delta: (update: WebSocketDeltaUpdate) => void;
50
+ user: (update: WebSocketUserUpdate) => void;
51
+ }
52
+ export declare interface NordWebSocketClient {
53
+ on<E extends keyof NordWebSocketEvents>(event: E, listener: NordWebSocketEvents[E]): this;
54
+ emit<E extends keyof NordWebSocketEvents>(event: E, ...args: Parameters<NordWebSocketEvents[E]>): boolean;
55
+ }
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NordWebSocketClient = void 0;
7
+ const ws_1 = __importDefault(require("ws"));
8
+ const events_1 = require("events");
9
+ const types_1 = require("./types");
10
+ const VALID_STREAM_TYPES = ["trades", "deltas", "user"];
11
+ class NordWebSocketClient extends events_1.EventEmitter {
12
+ constructor(url) {
13
+ super();
14
+ this.ws = null;
15
+ this.subscriptions = new Set();
16
+ this.reconnectAttempts = 0;
17
+ this.maxReconnectAttempts = 5;
18
+ this.reconnectDelay = 1000;
19
+ this.pingInterval = null;
20
+ this.pingTimeout = null;
21
+ this.url = url;
22
+ }
23
+ /**
24
+ * Validate stream format
25
+ * @param stream Stream identifier to validate
26
+ * @throws Error if stream format is invalid
27
+ */
28
+ validateStream(stream) {
29
+ const [type, params] = stream.split("@");
30
+ if (!type || !params) {
31
+ throw new Error(`Invalid stream format: ${stream}. Expected format: <type>@<params>`);
32
+ }
33
+ if (!VALID_STREAM_TYPES.includes(type)) {
34
+ throw new Error(`Invalid stream type: ${type}. Valid types are: ${VALID_STREAM_TYPES.join(", ")}`);
35
+ }
36
+ if (type === "user" && !/^\d+$/.test(params)) {
37
+ throw new Error(`Invalid user ID in stream: ${params}. Expected numeric ID`);
38
+ }
39
+ }
40
+ /**
41
+ * Setup WebSocket ping/pong heartbeat
42
+ */
43
+ setupHeartbeat() {
44
+ if (this.pingInterval) {
45
+ clearInterval(this.pingInterval);
46
+ }
47
+ if (this.pingTimeout) {
48
+ clearTimeout(this.pingTimeout);
49
+ }
50
+ this.pingInterval = setInterval(() => {
51
+ if (this.ws?.readyState === ws_1.default.OPEN) {
52
+ this.ws.ping();
53
+ // Set timeout for pong response
54
+ this.pingTimeout = setTimeout(() => {
55
+ this.emit("error", new Error("WebSocket ping timeout"));
56
+ this.close();
57
+ this.reconnect();
58
+ }, 5000); // 5 second timeout
59
+ }
60
+ }, 30000); // Send ping every 30 seconds
61
+ }
62
+ /**
63
+ * Connect to the Nord WebSocket server
64
+ */
65
+ connect() {
66
+ if (this.ws) {
67
+ return;
68
+ }
69
+ this.ws = new ws_1.default(this.url);
70
+ this.ws.on("open", () => {
71
+ this.emit("connected");
72
+ this.reconnectAttempts = 0;
73
+ this.reconnectDelay = 1000;
74
+ this.setupHeartbeat();
75
+ // Resubscribe to previous subscriptions
76
+ if (this.subscriptions.size > 0) {
77
+ this.subscribe([...this.subscriptions]);
78
+ }
79
+ });
80
+ this.ws.on("message", (data) => {
81
+ try {
82
+ const message = JSON.parse(data.toString());
83
+ this.handleMessage(message);
84
+ }
85
+ catch (error) {
86
+ this.emit("error", new Error(`Failed to parse message: ${error}`));
87
+ }
88
+ });
89
+ this.ws.on("close", () => {
90
+ this.emit("disconnected");
91
+ if (this.pingInterval) {
92
+ clearInterval(this.pingInterval);
93
+ }
94
+ if (this.pingTimeout) {
95
+ clearTimeout(this.pingTimeout);
96
+ }
97
+ this.reconnect();
98
+ });
99
+ this.ws.on("error", (error) => {
100
+ this.emit("error", error);
101
+ });
102
+ this.ws.on("pong", () => {
103
+ if (this.pingTimeout) {
104
+ clearTimeout(this.pingTimeout);
105
+ }
106
+ });
107
+ }
108
+ /**
109
+ * Subscribe to one or more streams
110
+ * @param streams Array of streams to subscribe to (e.g. ["trades@BTCUSDC", "deltas@BTCUSDC"])
111
+ */
112
+ subscribe(streams) {
113
+ // Validate all streams first
114
+ try {
115
+ streams.forEach(stream => this.validateStream(stream));
116
+ }
117
+ catch (error) {
118
+ this.emit("error", error instanceof Error ? error : new Error(String(error)));
119
+ return;
120
+ }
121
+ if (!this.ws || this.ws.readyState !== ws_1.default.OPEN) {
122
+ streams.forEach(stream => this.subscriptions.add(stream));
123
+ return;
124
+ }
125
+ const message = {
126
+ type: types_1.WebSocketMessageType.Subscribe,
127
+ streams,
128
+ };
129
+ try {
130
+ this.ws.send(JSON.stringify(message));
131
+ streams.forEach(stream => this.subscriptions.add(stream));
132
+ }
133
+ catch (error) {
134
+ this.emit("error", error instanceof Error ? error : new Error(String(error)));
135
+ }
136
+ }
137
+ /**
138
+ * Unsubscribe from one or more streams
139
+ * @param streams Array of streams to unsubscribe from
140
+ */
141
+ unsubscribe(streams) {
142
+ // Validate all streams first
143
+ try {
144
+ streams.forEach(stream => this.validateStream(stream));
145
+ }
146
+ catch (error) {
147
+ this.emit("error", error instanceof Error ? error : new Error(String(error)));
148
+ return;
149
+ }
150
+ if (!this.ws || this.ws.readyState !== ws_1.default.OPEN) {
151
+ streams.forEach(stream => this.subscriptions.delete(stream));
152
+ return;
153
+ }
154
+ const message = {
155
+ type: types_1.WebSocketMessageType.Unsubscribe,
156
+ streams,
157
+ };
158
+ try {
159
+ this.ws.send(JSON.stringify(message));
160
+ streams.forEach(stream => this.subscriptions.delete(stream));
161
+ }
162
+ catch (error) {
163
+ this.emit("error", error instanceof Error ? error : new Error(String(error)));
164
+ }
165
+ }
166
+ /**
167
+ * Close the WebSocket connection
168
+ */
169
+ close() {
170
+ if (this.ws) {
171
+ this.ws.close();
172
+ this.ws = null;
173
+ }
174
+ if (this.pingInterval) {
175
+ clearInterval(this.pingInterval);
176
+ this.pingInterval = null;
177
+ }
178
+ if (this.pingTimeout) {
179
+ clearTimeout(this.pingTimeout);
180
+ this.pingTimeout = null;
181
+ }
182
+ this.subscriptions.clear();
183
+ }
184
+ handleMessage(message) {
185
+ switch (message.type) {
186
+ case types_1.WebSocketMessageType.TradeUpdate:
187
+ this.emit("trade", message);
188
+ break;
189
+ case types_1.WebSocketMessageType.DeltaUpdate:
190
+ this.emit("delta", message);
191
+ break;
192
+ case types_1.WebSocketMessageType.UserUpdate:
193
+ this.emit("user", message);
194
+ break;
195
+ default:
196
+ this.emit("error", new Error(`Unknown message type: ${message.type}`));
197
+ }
198
+ }
199
+ reconnect() {
200
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
201
+ this.emit("error", new Error("Max reconnection attempts reached"));
202
+ return;
203
+ }
204
+ setTimeout(() => {
205
+ this.reconnectAttempts++;
206
+ this.reconnectDelay *= 2; // Exponential backoff
207
+ this.connect();
208
+ }, this.reconnectDelay);
209
+ }
210
+ }
211
+ exports.NordWebSocketClient = NordWebSocketClient;
@@ -1 +1 @@
1
- window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5WYWXPaPhTFvwvPnaZN03R5M2BnmMSGeiH/ZToeYV+IByN5ZNEm0+l3r7AJ3qQr91XnnB+6krXx/6+JgGcx+Tpxsjx3WQqTN5OCiCfZAvR4KK9e298+iUMuxX1G08nXz7/fXJL38BK+FIPguVmfWwHZh0W5Ap6xNKKZ6BMGBj0ryIY9P7XpEx7jaZNIclKWUF6dWruZ99f9VFQCVydPCpYOjpsy4dlGlW80jGAlCTvS1khlVADfkkQSzlo3fv3xthMXGaMLumUawqtshnw7An9BKJVuxvhQFoyWgJBeLWZYaT8LoCmkhgo7vhFYU63lyGLLEdWWo8rd7TjsiAAXBM+SUs3rmTDgNGfJXl9mIxshaIkdhxEVHA8HgvXobBgLMnetZ8TAc8gFsX+AZjE2Mgax/dn1u5DtQb8muxYMpkWYgi7he1CXUUvmcCCIUH+FLd2MKSsfOk8qIwY+7cszRrfZTolrZAyy5Gl7z27lK8UY1U7NRTUiNoztDd24WEbB0FEeuDCkPKAL02fQ82A4n+X5gdB6OzTu6Fr36J8Yh/4rJDq2SudoNL461NYRcPPerTJi4OZCgyy/vgkDVpugklIpaJSTVF1VpRij2k/kohoR6mVRS+ZwdfauCCcHjNNymZHoZHct6AGb7RZUrEl+bJGEvPjLI7WReoR3Xz69/3jdPk3taXQX39v/Bg3kB+EZ2eSnw/SidjkfugjHih7C2Im8+cK7iy13GXmhhqe0ovB1PFt6oW/Nwtiaz3070JCHPgM2XN7bXrzwnKWW2LIYYJH/oINICQlX14zYmi5U8YuIAdZujPSgJSMQOS0zO4xX/mJthTY20Gongnatf+Jp5Di2Hz/YngrZdSAob+nP4zs7DG0/iB3r1A/NwKmdJrRvuasR3K4NgQZyZBZLLw5D5dS0ZATyaE8D21/LwUFmeWBCgP/Z/lLaZgvXUrLaOoI5vZ556/K6PdL68LuqlW709qYV3VT7U8hWnAkWyYe2ijIwIcDkCZL96ri5h5cHoDtJUgAHJhMQUgdEomeddQzDQT4DH2ETyLNb3sDqQ7c4MZRUvR35kRQSlkJdknz9ZIdMQKrCK40IGOhIsNKIgLfnv7bOkzv8B6xBa6wonKb9h1Wb96oaEL1LT5eguPd0AAeyh0eS53IOsx11lJy+B8GxQtjPBSTKii4iDnBJoUlLBY9G9CfXpmsRARSEZokqXAlIsJTDUt+nVelGRRCCBQnJIdXtMW19DOb2BqXc3gwg3/8AbpPhh+kVAAA="
1
+ window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5WYWXObMBSF/4ufM03iJm6bN2yLDBMDLovTZTqMDLLDGAsGRJpMp/+9Mnhhka7oq845H1xJXAQ//4wYeWOjh5EeJ4mZRmR0Ncowe+EjhJb74vo0/uGF7RMu7mIajR4+/706J5/Iu/ee9YLHYXluSfDOy4olyeM08mnMuoSeQc5y4/6dH8bkCSvNo0siTHBRkOL6MNrO3I67Kb8guTh5UKC0FoZpSRt1xpSRfINDnj9q7fj4ftKKszilBt2kEsJJVkO+liR/ByiVrsY4pMhSWhCAdLKoYQV6Y4RGJFJU2PINwKpqLQYWWwyothhU7nabky1mxCQsj8NCzOuYIOA0ScOdvMyLrISAJbYcSpRb7vcYuqOjYShIfWsdIwSek4Rh9EokD+NFhiDImY1vvHRH5M9k2wLBpAhV0MT5jojLqCV12GWYiXdhQ1djisoHrpPICIEPXXWW0k28FeIuMgSx86jZsRv5SlFGpUtzViEEf31lqmnueCCckybJHtO63Sg7ptQ9+BLD0P+FBHeI0DkYDe8+sXUAXN0bRUYI7JbrIszjNcmB7d01QcCqyQgplQJGcxyJq6oUZVS8p2sJ7O7x1qBshZOycXXGz4y8n1+kDuHmy6fb+3GzlaOp/xg8oe/uBfKK8xivk0MnP6ttzsc2Qtf8hRfovjU3rMdAM23f8iQ8oRWEr4KZbXmONvMCbT53kCsh930KrGc/ISswLN2WEhsWBcx3FjIIl4Bw9Y4LtKkhip9FCLAyA+AOGjIA4csyQ16wdIyV5iFoosVOAG1q34Kpr+vICRbIEiHbDgBl2c48eESehxw30LXDfUgmTuxUoR3NXA7gtm0A1OUzY9hW4HnCpWnIAOQZTV3krPjkAKvcMwHAH8ixuW1mmJqQ1dQBzOHDLW+cnDYlrd8M17XSjk7uGtF11Z+8dJmnLPX5V56I0jMBwPCFhLtlueZfzQtCt5wkAPZMKiCJdMJCOeuoA5iIhPzjv74aPxXH+5iRSMQTGgEwoQPBQiMA3hx/WBznvf9f44KWWEE4jboH7ibvpCoQnZd1myB4X7cAe7wjzzhJ+GEx3lJdyOl6AFyaMfSWkVBY0VmEASbOJGmuwFGf/s6l6VoEABmmcSgKVwIQLPi01OdAUfqiAgiWuiFOSCR7/Jv6EMzkDqRM7nqQX/8AH8q1Qb8TAAA="
@@ -1 +1 @@
1
- window.searchData = "data:application/octet-stream;base64,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";
1
+ window.searchData = "data:application/octet-stream;base64,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";