@n1xyz/nord-ts 0.1.7 → 0.1.8
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/actions.js +39 -82
- package/dist/bundle.js +79181 -0
- package/dist/client/Nord.d.ts +2 -2
- package/dist/client/Nord.js +46 -78
- package/dist/client/NordAdmin.d.ts +2 -2
- package/dist/client/NordAdmin.js +57 -89
- package/dist/client/NordUser.js +118 -147
- package/dist/const.js +5 -8
- package/dist/error.js +7 -5
- package/dist/gen/nord_pb.js +88 -92
- package/dist/gen/openapi.d.ts +5 -6
- package/dist/gen/openapi.js +1 -2
- package/dist/index.js +10 -49
- package/dist/types.d.ts +1 -0
- package/dist/types.js +21 -60
- package/dist/utils.js +38 -86
- package/dist/websocket/NordWebSocketClient.js +12 -17
- package/dist/websocket/Subscriber.js +6 -7
- package/dist/websocket/events.js +1 -2
- package/dist/websocket/index.js +10 -15
- package/package.json +2 -3
- package/dist/api/client.d.ts +0 -14
- package/dist/api/client.js +0 -45
- package/dist/bridge/client.d.ts +0 -151
- package/dist/bridge/client.js +0 -434
- package/dist/bridge/const.d.ts +0 -23
- package/dist/bridge/const.js +0 -47
- package/dist/bridge/index.d.ts +0 -4
- package/dist/bridge/index.js +0 -23
- package/dist/bridge/types.d.ts +0 -120
- package/dist/bridge/types.js +0 -18
- package/dist/bridge/utils.d.ts +0 -64
- package/dist/bridge/utils.js +0 -131
- package/dist/gen/common.d.ts +0 -68
- package/dist/gen/common.js +0 -215
- package/dist/gen/nord.d.ts +0 -882
- package/dist/gen/nord.js +0 -6520
- package/dist/idl/bridge.d.ts +0 -569
- package/dist/idl/bridge.js +0 -8
- package/dist/idl/bridge.json +0 -1506
- package/dist/idl/index.d.ts +0 -607
- package/dist/idl/index.js +0 -8
- package/dist/nord/api/actions.d.ts +0 -126
- package/dist/nord/api/actions.js +0 -397
- package/dist/nord/api/core.d.ts +0 -16
- package/dist/nord/api/core.js +0 -81
- package/dist/nord/api/market.d.ts +0 -36
- package/dist/nord/api/market.js +0 -96
- package/dist/nord/api/metrics.d.ts +0 -67
- package/dist/nord/api/metrics.js +0 -229
- package/dist/nord/api/queries.d.ts +0 -46
- package/dist/nord/api/queries.js +0 -109
- package/dist/nord/api/triggers.d.ts +0 -7
- package/dist/nord/api/triggers.js +0 -38
- package/dist/nord/client/Nord.d.ts +0 -396
- package/dist/nord/client/Nord.js +0 -747
- package/dist/nord/client/NordAdmin.d.ts +0 -259
- package/dist/nord/client/NordAdmin.js +0 -395
- package/dist/nord/client/NordClient.d.ts +0 -33
- package/dist/nord/client/NordClient.js +0 -45
- package/dist/nord/client/NordUser.d.ts +0 -362
- package/dist/nord/client/NordUser.js +0 -781
- package/dist/nord/index.d.ts +0 -11
- package/dist/nord/index.js +0 -36
- package/dist/nord/models/Subscriber.d.ts +0 -37
- package/dist/nord/models/Subscriber.js +0 -25
- package/dist/nord/utils/NordError.d.ts +0 -35
- package/dist/nord/utils/NordError.js +0 -49
- package/src/actions.ts +0 -333
- package/src/client/Nord.ts +0 -934
- package/src/client/NordAdmin.ts +0 -484
- package/src/client/NordUser.ts +0 -1122
- package/src/const.ts +0 -34
- package/src/error.ts +0 -76
- package/src/gen/.gitkeep +0 -0
- package/src/gen/nord_pb.ts +0 -5053
- package/src/gen/openapi.ts +0 -2904
- package/src/index.ts +0 -11
- package/src/types.ts +0 -327
- package/src/utils.ts +0 -266
- package/src/websocket/NordWebSocketClient.ts +0 -316
- package/src/websocket/Subscriber.ts +0 -56
- package/src/websocket/events.ts +0 -31
- package/src/websocket/index.ts +0 -105
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
import WebSocket from "ws";
|
|
3
|
-
import {
|
|
4
|
-
WebSocketAccountUpdate,
|
|
5
|
-
WebSocketDeltaUpdate,
|
|
6
|
-
WebSocketMessage,
|
|
7
|
-
WebSocketTradeUpdate,
|
|
8
|
-
} from "../types";
|
|
9
|
-
import { NordWebSocketClientEvents } from "./events";
|
|
10
|
-
|
|
11
|
-
// Define a type that works for both Node.js ws and browser WebSocket
|
|
12
|
-
type BrowserWebSocket = {
|
|
13
|
-
OPEN: number;
|
|
14
|
-
CONNECTING: number;
|
|
15
|
-
CLOSING: number;
|
|
16
|
-
CLOSED: number;
|
|
17
|
-
readyState: number;
|
|
18
|
-
send: (data: string) => void;
|
|
19
|
-
close: () => void;
|
|
20
|
-
onopen: ((this: any, ev: any) => any) | null;
|
|
21
|
-
onmessage: ((this: any, ev: { data: any }) => any) | null;
|
|
22
|
-
onclose: ((this: any, ev: any) => any) | null;
|
|
23
|
-
onerror: ((this: any, ev: any) => any) | null;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
type WebSocketInstance = WebSocket | BrowserWebSocket;
|
|
27
|
-
|
|
28
|
-
const VALID_STREAM_TYPES = ["trades", "delta", "account"];
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* WebSocket client for Nord exchange
|
|
32
|
-
*
|
|
33
|
-
* This client connects to one of the specific Nord WebSocket endpoints:
|
|
34
|
-
*
|
|
35
|
-
* Each endpoint handles a specific type of data and subscriptions must match
|
|
36
|
-
* the endpoint type (e.g., only 'trades@BTCUSDC' subscriptions are valid on
|
|
37
|
-
* the /ws/trades endpoint).
|
|
38
|
-
*/
|
|
39
|
-
export class NordWebSocketClient
|
|
40
|
-
extends EventEmitter
|
|
41
|
-
implements NordWebSocketClientEvents
|
|
42
|
-
{
|
|
43
|
-
private ws: WebSocketInstance | null = null;
|
|
44
|
-
private url: string;
|
|
45
|
-
private reconnectAttempts: number = 0;
|
|
46
|
-
private maxReconnectAttempts: number = 5;
|
|
47
|
-
private reconnectDelay: number = 1000;
|
|
48
|
-
private pingInterval: NodeJS.Timeout | null = null;
|
|
49
|
-
private pingTimeout: NodeJS.Timeout | null = null;
|
|
50
|
-
private isBrowser: boolean;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Create a new NordWebSocketClient
|
|
54
|
-
* @param url WebSocket server URL
|
|
55
|
-
*/
|
|
56
|
-
constructor(url: string) {
|
|
57
|
-
super();
|
|
58
|
-
this.url = url;
|
|
59
|
-
// Check if we're in a browser environment
|
|
60
|
-
// The most reliable way is to check for Node.js process
|
|
61
|
-
this.isBrowser =
|
|
62
|
-
typeof process === "undefined" ||
|
|
63
|
-
!process.versions ||
|
|
64
|
-
!process.versions.node;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Validate stream format
|
|
69
|
-
* @param stream Stream identifier to validate
|
|
70
|
-
* @throws Error if stream format is invalid
|
|
71
|
-
*/
|
|
72
|
-
private validateStream(stream: string): void {
|
|
73
|
-
const [type, params] = stream.split("@");
|
|
74
|
-
|
|
75
|
-
if (!type || !params) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
`Invalid stream format: ${stream}. Expected format: <type>@<params>`,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Extract the endpoint from the URL
|
|
82
|
-
const urlPath = new URL(this.url).pathname;
|
|
83
|
-
const endpoint = urlPath.split("/").pop();
|
|
84
|
-
|
|
85
|
-
// Ensure the stream type matches the endpoint we're connected to
|
|
86
|
-
if (endpoint && type !== endpoint) {
|
|
87
|
-
throw new Error(
|
|
88
|
-
`Stream type '${type}' doesn't match the connected endpoint '${endpoint}'`,
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (!VALID_STREAM_TYPES.includes(type)) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
`Invalid stream type: ${type}. Valid types are: ${VALID_STREAM_TYPES.join(", ")}`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (type === "account" && !/^\d+$/.test(params)) {
|
|
99
|
-
throw new Error(
|
|
100
|
-
`Invalid account ID in stream: ${params}. Expected numeric ID`,
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Setup WebSocket ping/pong heartbeat
|
|
107
|
-
*/
|
|
108
|
-
private setupHeartbeat(): void {
|
|
109
|
-
if (this.pingInterval) {
|
|
110
|
-
clearInterval(this.pingInterval);
|
|
111
|
-
}
|
|
112
|
-
if (this.pingTimeout) {
|
|
113
|
-
clearTimeout(this.pingTimeout);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// In browser, we rely on the browser's WebSocket implementation to handle ping/pong
|
|
117
|
-
if (this.isBrowser) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
this.pingInterval = setInterval(() => {
|
|
122
|
-
if (this.ws && !this.isBrowser) {
|
|
123
|
-
// Only use ping() method in Node.js environment
|
|
124
|
-
(this.ws as WebSocket).ping();
|
|
125
|
-
|
|
126
|
-
// Set timeout for pong response
|
|
127
|
-
this.pingTimeout = setTimeout(() => {
|
|
128
|
-
this.emit("error", new Error("WebSocket ping timeout"));
|
|
129
|
-
this.close();
|
|
130
|
-
this.reconnect();
|
|
131
|
-
}, 5000); // 5 second timeout
|
|
132
|
-
}
|
|
133
|
-
}, 30000); // Send ping every 30 seconds
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Get the appropriate WebSocket class based on environment
|
|
138
|
-
*/
|
|
139
|
-
private getWebSocketClass(): any {
|
|
140
|
-
if (this.isBrowser) {
|
|
141
|
-
// In browser environments
|
|
142
|
-
if (typeof globalThis !== "undefined" && globalThis.WebSocket) {
|
|
143
|
-
return globalThis.WebSocket;
|
|
144
|
-
}
|
|
145
|
-
throw new Error("WebSocket is not available in this environment");
|
|
146
|
-
} else {
|
|
147
|
-
// In Node.js
|
|
148
|
-
return WebSocket;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Connect to the Nord WebSocket server
|
|
154
|
-
*/
|
|
155
|
-
public connect(): void {
|
|
156
|
-
if (this.ws) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const WebSocketClass = this.getWebSocketClass();
|
|
162
|
-
|
|
163
|
-
if (this.isBrowser) {
|
|
164
|
-
// Browser WebSocket setup
|
|
165
|
-
this.ws = new WebSocketClass(this.url) as BrowserWebSocket;
|
|
166
|
-
|
|
167
|
-
(this.ws as BrowserWebSocket).onopen = () => {
|
|
168
|
-
this.emit("connected");
|
|
169
|
-
this.reconnectAttempts = 0;
|
|
170
|
-
this.reconnectDelay = 1000;
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
(this.ws as BrowserWebSocket).onmessage = (event: { data: any }) => {
|
|
174
|
-
try {
|
|
175
|
-
const message = JSON.parse(
|
|
176
|
-
event.data as string,
|
|
177
|
-
) as WebSocketMessage;
|
|
178
|
-
this.handleMessage(message);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
this.emit(
|
|
181
|
-
"error",
|
|
182
|
-
new Error(
|
|
183
|
-
`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`,
|
|
184
|
-
),
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
(this.ws as BrowserWebSocket).onclose = (_event: any) => {
|
|
190
|
-
this.emit("disconnected");
|
|
191
|
-
this.reconnect();
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
(this.ws as BrowserWebSocket).onerror = (event: any) => {
|
|
195
|
-
const errorMsg = `WebSocket error: ${event && event.type ? event.type : "unknown"}`;
|
|
196
|
-
this.emit("error", new Error(errorMsg));
|
|
197
|
-
};
|
|
198
|
-
} else {
|
|
199
|
-
// Node.js WebSocket setup
|
|
200
|
-
const nodeWs = new WebSocketClass(this.url) as WebSocket;
|
|
201
|
-
this.ws = nodeWs;
|
|
202
|
-
|
|
203
|
-
nodeWs.on("open", () => {
|
|
204
|
-
this.emit("connected");
|
|
205
|
-
this.reconnectAttempts = 0;
|
|
206
|
-
this.reconnectDelay = 1000;
|
|
207
|
-
this.setupHeartbeat();
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
nodeWs.on("message", (data: WebSocket.Data) => {
|
|
211
|
-
try {
|
|
212
|
-
const message = JSON.parse(data.toString()) as WebSocketMessage;
|
|
213
|
-
this.handleMessage(message);
|
|
214
|
-
} catch (error) {
|
|
215
|
-
this.emit(
|
|
216
|
-
"error",
|
|
217
|
-
new Error(
|
|
218
|
-
`Failed to parse message: ${error instanceof Error ? error.message : String(error)}`,
|
|
219
|
-
),
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
nodeWs.on("close", (_code: number, _reason: string) => {
|
|
225
|
-
this.emit("disconnected");
|
|
226
|
-
if (this.pingInterval) {
|
|
227
|
-
clearInterval(this.pingInterval);
|
|
228
|
-
}
|
|
229
|
-
if (this.pingTimeout) {
|
|
230
|
-
clearTimeout(this.pingTimeout);
|
|
231
|
-
}
|
|
232
|
-
this.reconnect();
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
nodeWs.on("error", (error: Error) => {
|
|
236
|
-
this.emit("error", error);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
nodeWs.on("pong", () => {
|
|
240
|
-
if (this.pingTimeout) {
|
|
241
|
-
clearTimeout(this.pingTimeout);
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
} catch (error) {
|
|
246
|
-
const errorMsg = `Failed to initialize WebSocket: ${error instanceof Error ? error.message : String(error)}`;
|
|
247
|
-
this.emit("error", new Error(errorMsg));
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Close the WebSocket connection
|
|
253
|
-
*/
|
|
254
|
-
public close(): void {
|
|
255
|
-
if (this.ws) {
|
|
256
|
-
if (this.isBrowser) {
|
|
257
|
-
(this.ws as BrowserWebSocket).close();
|
|
258
|
-
} else {
|
|
259
|
-
(this.ws as WebSocket).close();
|
|
260
|
-
}
|
|
261
|
-
this.ws = null;
|
|
262
|
-
}
|
|
263
|
-
if (this.pingInterval) {
|
|
264
|
-
clearInterval(this.pingInterval);
|
|
265
|
-
this.pingInterval = null;
|
|
266
|
-
}
|
|
267
|
-
if (this.pingTimeout) {
|
|
268
|
-
clearTimeout(this.pingTimeout);
|
|
269
|
-
this.pingTimeout = null;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Handle incoming WebSocket messages
|
|
275
|
-
* @param message WebSocket message
|
|
276
|
-
*/
|
|
277
|
-
private handleMessage(message: WebSocketMessage): void {
|
|
278
|
-
if (!message || typeof message !== "object") {
|
|
279
|
-
this.emit("error", new Error(`Unexpected message type: ${message}`));
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const hasOwn = (k: string) =>
|
|
284
|
-
Object.prototype.hasOwnProperty.call(message, k);
|
|
285
|
-
if (hasOwn("trades")) {
|
|
286
|
-
this.emit("trades", message as WebSocketTradeUpdate);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
if (hasOwn("delta")) {
|
|
290
|
-
this.emit("delta", message as WebSocketDeltaUpdate);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
if (hasOwn("account")) {
|
|
294
|
-
this.emit("account", message as WebSocketAccountUpdate);
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
this.emit("error", new Error(`Unexpected message type: ${message}`));
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Attempt to reconnect to the WebSocket server
|
|
303
|
-
*/
|
|
304
|
-
private reconnect(): void {
|
|
305
|
-
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
306
|
-
this.emit("error", new Error("Max reconnection attempts reached"));
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
setTimeout(() => {
|
|
311
|
-
this.reconnectAttempts++;
|
|
312
|
-
this.reconnectDelay *= 2; // Exponential backoff
|
|
313
|
-
this.connect();
|
|
314
|
-
}, this.reconnectDelay);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
import {
|
|
3
|
-
Account,
|
|
4
|
-
DeltaEvent,
|
|
5
|
-
OrderbookResponse,
|
|
6
|
-
SubscriberConfig,
|
|
7
|
-
StreamTrade,
|
|
8
|
-
Trades,
|
|
9
|
-
} from "../types";
|
|
10
|
-
import { MAX_BUFFER_LEN } from "../utils";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Subscriber class for handling WebSocket subscriptions
|
|
14
|
-
*/
|
|
15
|
-
export class Subscriber {
|
|
16
|
-
streamURL: string;
|
|
17
|
-
buffer: (DeltaEvent | Trades | Account)[];
|
|
18
|
-
maxBufferLen: number;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Create a new Subscriber instance
|
|
22
|
-
* @param config Subscriber configuration
|
|
23
|
-
*/
|
|
24
|
-
constructor(config: SubscriberConfig) {
|
|
25
|
-
this.streamURL = config.streamURL;
|
|
26
|
-
this.buffer = [];
|
|
27
|
-
this.maxBufferLen = config.maxBufferLen ?? MAX_BUFFER_LEN;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Subscribe to WebSocket events
|
|
32
|
-
*/
|
|
33
|
-
subscribe(): void {
|
|
34
|
-
// TODO: Implement subscription logic
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Interface for orderbook subscription
|
|
40
|
-
*/
|
|
41
|
-
export interface OrderbookSubscription extends EventEmitter {
|
|
42
|
-
on(event: "message", listener: (data: OrderbookResponse) => void): this;
|
|
43
|
-
on(event: "error", listener: (error: Error) => void): this;
|
|
44
|
-
close(): void;
|
|
45
|
-
removeAllListeners(event?: string): this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Interface for trade subscription
|
|
50
|
-
*/
|
|
51
|
-
export interface TradeSubscription extends EventEmitter {
|
|
52
|
-
on(event: "message", listener: (data: StreamTrade[]) => void): this;
|
|
53
|
-
on(event: "error", listener: (error: Error) => void): this;
|
|
54
|
-
close(): void;
|
|
55
|
-
removeAllListeners(event?: string): this;
|
|
56
|
-
}
|
package/src/websocket/events.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
WebSocketTradeUpdate,
|
|
3
|
-
WebSocketDeltaUpdate,
|
|
4
|
-
WebSocketAccountUpdate,
|
|
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
|
-
account: (update: WebSocketAccountUpdate) => 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
|
-
}
|
package/src/websocket/index.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { NordWebSocketClient } from "./NordWebSocketClient";
|
|
2
|
-
import { NordError } from "../error";
|
|
3
|
-
import type { SubscriptionPattern } from "../types";
|
|
4
|
-
import type { NordWebSocketEvents, NordWebSocketClientEvents } from "./events";
|
|
5
|
-
import { Subscriber } from "./Subscriber";
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
NordWebSocketClient,
|
|
9
|
-
NordWebSocketEvents,
|
|
10
|
-
NordWebSocketClientEvents,
|
|
11
|
-
Subscriber,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Initialize a WebSocket client for Nord
|
|
16
|
-
*
|
|
17
|
-
* Connects to the Nord WebSocket endpoint with support for multiple subscription types:
|
|
18
|
-
* - trades@SYMBOL - For trade updates
|
|
19
|
-
* - deltas@SYMBOL - For orderbook delta updates
|
|
20
|
-
* - account@ACCOUNT_ID - For user-specific updates
|
|
21
|
-
*
|
|
22
|
-
* @param webServerUrl - Base URL for the Nord web server
|
|
23
|
-
* @param subscriptions - Array of subscriptions (e.g., ["trades@BTCUSDC", "deltas@BTCUSDC", "account@42"])
|
|
24
|
-
* @returns WebSocket client
|
|
25
|
-
* @throws {NordError} If initialization fails or invalid subscription is provided
|
|
26
|
-
*/
|
|
27
|
-
export function initWebSocketClient(
|
|
28
|
-
webServerUrl: string,
|
|
29
|
-
subscriptions?: SubscriptionPattern[] | "trades" | "delta" | "account",
|
|
30
|
-
): NordWebSocketClient {
|
|
31
|
-
try {
|
|
32
|
-
// Determine URL and subscriptions based on parameters
|
|
33
|
-
let wsUrl = webServerUrl.replace(/^http/, "ws") + `/ws`;
|
|
34
|
-
|
|
35
|
-
// Validate subscriptions parameter
|
|
36
|
-
if (typeof subscriptions === "string") {
|
|
37
|
-
// Legacy mode - handle endpoint string
|
|
38
|
-
if (
|
|
39
|
-
subscriptions === "trades" ||
|
|
40
|
-
subscriptions === "delta" ||
|
|
41
|
-
subscriptions === "account"
|
|
42
|
-
) {
|
|
43
|
-
wsUrl += `/${subscriptions}`;
|
|
44
|
-
} else {
|
|
45
|
-
throw new NordError(
|
|
46
|
-
`Invalid endpoint: ${subscriptions}. Must be "trades", "deltas", or "account".`,
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
} else if (Array.isArray(subscriptions) && subscriptions.length > 0) {
|
|
50
|
-
// New mode - validate and combine subscriptions in URL
|
|
51
|
-
subscriptions.forEach(validateSubscription);
|
|
52
|
-
wsUrl += `/${subscriptions.join("&")}`;
|
|
53
|
-
} else {
|
|
54
|
-
// Default to trades endpoint if no subscriptions specified
|
|
55
|
-
wsUrl += `/trades`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
console.log(`Initializing WebSocket client with URL: ${wsUrl}`);
|
|
59
|
-
|
|
60
|
-
// Create and connect the WebSocket client
|
|
61
|
-
const ws = new NordWebSocketClient(wsUrl);
|
|
62
|
-
|
|
63
|
-
// Add error handler
|
|
64
|
-
ws.on("error", (error) => {
|
|
65
|
-
console.error("Nord WebSocket error:", error);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Add connected handler for debugging
|
|
69
|
-
ws.on("connected", () => {
|
|
70
|
-
console.log("Nord WebSocket connected successfully");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Connect the WebSocket
|
|
74
|
-
ws.connect();
|
|
75
|
-
return ws;
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.error("Failed to initialize WebSocket client:", error);
|
|
78
|
-
throw new NordError("Failed to initialize WebSocket client", {
|
|
79
|
-
cause: error,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Validates a subscription string follows the correct format
|
|
86
|
-
*
|
|
87
|
-
* @param subscription - The subscription to validate
|
|
88
|
-
* @throws {NordError} If the subscription format is invalid
|
|
89
|
-
*/
|
|
90
|
-
function validateSubscription(subscription: string): void {
|
|
91
|
-
const [type, param] = subscription.split("@");
|
|
92
|
-
|
|
93
|
-
if (!type || !param || !["trades", "deltas", "account"].includes(type)) {
|
|
94
|
-
throw new NordError(
|
|
95
|
-
`Invalid subscription format: ${subscription}. Expected format: "trades@SYMBOL", "deltas@SYMBOL", or "account@ID"`,
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Additional validation for account subscriptions
|
|
100
|
-
if (type === "account" && isNaN(Number(param))) {
|
|
101
|
-
throw new NordError(
|
|
102
|
-
`Invalid account ID in subscription: ${subscription}. Account ID must be a number.`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
}
|