@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.
- package/.eslintrc.js +11 -0
- package/README.md +148 -65
- package/dist/bridge/NordUser.d.ts +78 -0
- package/dist/bridge/NordUser.js +196 -0
- package/dist/bridge/client.d.ts +150 -0
- package/dist/bridge/client.js +394 -0
- package/dist/bridge/const.d.ts +23 -0
- package/dist/bridge/const.js +47 -0
- package/dist/bridge/index.d.ts +5 -0
- package/dist/bridge/index.js +23 -0
- package/dist/bridge/types.d.ts +118 -0
- package/dist/bridge/types.js +16 -0
- package/dist/bridge/utils.d.ts +64 -0
- package/dist/bridge/utils.js +131 -0
- package/dist/client.d.ts +70 -0
- package/dist/client.js +129 -0
- package/dist/const.d.ts +2 -5
- package/dist/const.js +18 -22
- package/dist/constants/endpoints.d.ts +65 -0
- package/dist/constants/endpoints.js +68 -0
- package/dist/gen/common.d.ts +6 -1
- package/dist/gen/common.js +19 -9
- package/dist/gen/nord.d.ts +75 -17
- package/dist/gen/nord.js +987 -423
- package/dist/idl/bridge.d.ts +2 -0
- package/dist/idl/bridge.js +703 -0
- package/dist/index.d.ts +8 -5
- package/dist/index.js +18 -2
- package/dist/models/account.d.ts +58 -0
- package/dist/models/account.js +6 -0
- package/dist/models/index.d.ts +8 -0
- package/dist/models/index.js +28 -0
- package/dist/models/market.d.ts +137 -0
- package/dist/models/market.js +6 -0
- package/dist/models/order.d.ts +211 -0
- package/dist/models/order.js +6 -0
- package/dist/models/token.d.ts +50 -0
- package/dist/models/token.js +6 -0
- package/dist/nord/Nord.d.ts +222 -49
- package/dist/nord/Nord.js +290 -278
- package/dist/nord/NordError.d.ts +23 -0
- package/dist/nord/NordError.js +48 -0
- package/dist/nord/NordImpl.d.ts +6 -2
- package/dist/nord/NordImpl.js +21 -1
- package/dist/nord/NordUser.d.ts +208 -42
- package/dist/nord/NordUser.js +389 -157
- package/dist/nord/Subscriber.d.ts +37 -0
- package/dist/nord/Subscriber.js +29 -0
- package/dist/nord/api/actions.d.ts +101 -0
- package/dist/nord/api/actions.js +250 -0
- package/dist/nord/api/core.d.ts +49 -0
- package/dist/nord/api/core.js +121 -0
- package/dist/nord/api/index.d.ts +1 -0
- package/dist/nord/api/index.js +17 -0
- package/dist/nord/api/market.d.ts +36 -0
- package/dist/nord/api/market.js +98 -0
- package/dist/nord/api/metrics.d.ts +67 -0
- package/dist/nord/api/metrics.js +132 -0
- package/dist/nord/api/orderFunctions.d.ts +168 -0
- package/dist/nord/api/orderFunctions.js +133 -0
- package/dist/nord/api/queries.d.ts +81 -0
- package/dist/nord/api/queries.js +187 -0
- package/dist/nord/client/Nord.d.ts +335 -0
- package/dist/nord/client/Nord.js +532 -0
- package/dist/nord/client/NordUser.d.ts +320 -0
- package/dist/nord/client/NordUser.js +701 -0
- package/dist/nord/core.d.ts +48 -0
- package/dist/nord/core.js +97 -0
- package/dist/nord/index.d.ts +9 -2
- package/dist/nord/index.js +30 -6
- package/dist/nord/market.d.ts +36 -0
- package/dist/nord/market.js +90 -0
- package/dist/nord/metrics.d.ts +67 -0
- package/dist/nord/metrics.js +124 -0
- package/dist/nord/models/Subscriber.d.ts +37 -0
- package/dist/nord/models/Subscriber.js +29 -0
- package/dist/nord/queries.d.ts +81 -0
- package/dist/nord/queries.js +181 -0
- package/dist/nord/types.d.ts +88 -0
- package/dist/nord/types.js +2 -0
- package/dist/nord/utils/NordError.d.ts +35 -0
- package/dist/nord/utils/NordError.js +46 -0
- package/dist/nord/websocket.d.ts +49 -0
- package/dist/nord/websocket.js +107 -0
- package/dist/operations/account.d.ts +58 -0
- package/dist/operations/account.js +112 -0
- package/dist/operations/market.d.ts +65 -0
- package/dist/operations/market.js +131 -0
- package/dist/operations/orders.d.ts +57 -0
- package/dist/operations/orders.js +129 -0
- package/dist/solana/NordUser.d.ts +78 -0
- package/dist/solana/NordUser.js +196 -0
- package/dist/solana/client.d.ts +139 -0
- package/dist/solana/client.js +360 -0
- package/dist/solana/const.d.ts +23 -0
- package/dist/solana/const.js +47 -0
- package/dist/solana/index.d.ts +5 -0
- package/dist/solana/index.js +23 -0
- package/dist/solana/types.d.ts +118 -0
- package/dist/solana/types.js +16 -0
- package/dist/solana/utils.d.ts +64 -0
- package/dist/solana/utils.js +131 -0
- package/dist/types/api.d.ts +152 -0
- package/dist/types/api.js +6 -0
- package/dist/types/config.d.ts +34 -0
- package/dist/types/config.js +6 -0
- package/dist/types.d.ts +144 -87
- package/dist/types.js +13 -2
- package/dist/utils/errors.d.ts +96 -0
- package/dist/utils/errors.js +132 -0
- package/dist/utils/http.d.ts +35 -0
- package/dist/utils/http.js +105 -0
- package/dist/utils.d.ts +14 -5
- package/dist/utils.js +26 -7
- package/dist/websocket/NordWebSocketClient.d.ts +71 -0
- package/dist/websocket/NordWebSocketClient.js +343 -0
- package/dist/websocket/client.d.ts +93 -0
- package/dist/websocket/client.js +222 -0
- package/dist/websocket/events.d.ts +19 -0
- package/dist/websocket/events.js +2 -0
- package/dist/websocket/index.d.ts +2 -0
- package/dist/websocket/index.js +5 -0
- package/dist/websocket.d.ts +55 -0
- package/dist/websocket.js +211 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/Nord.html +2 -15
- package/docs/classes/NordUser.html +4 -4
- package/docs/enums/FillMode.html +2 -2
- package/docs/enums/KeyType.html +2 -2
- package/docs/enums/PeakTpsPeriodUnit.html +2 -2
- package/docs/enums/Side.html +2 -2
- package/docs/functions/assert.html +1 -1
- package/docs/functions/bigIntToProtoU128.html +1 -1
- package/docs/functions/checkPubKeyLength.html +1 -1
- package/docs/functions/checkedFetch.html +1 -1
- package/docs/functions/decodeLengthDelimited.html +1 -1
- package/docs/functions/encodeLengthDelimited.html +1 -1
- package/docs/functions/fillModeToProtoFillMode.html +1 -1
- package/docs/functions/findMarket.html +1 -1
- package/docs/functions/findToken.html +1 -1
- package/docs/functions/makeWalletSignFn.html +1 -1
- package/docs/functions/optExpect.html +1 -1
- package/docs/functions/optMap.html +1 -1
- package/docs/functions/optUnwrap.html +1 -1
- package/docs/functions/panic.html +1 -1
- package/docs/functions/signAction.html +1 -1
- package/docs/functions/toScaledU128.html +1 -1
- package/docs/functions/toScaledU64.html +1 -1
- package/docs/interfaces/Account.html +2 -2
- package/docs/interfaces/ActionInfo.html +2 -2
- package/docs/interfaces/ActionQuery.html +2 -2
- package/docs/interfaces/ActionResponse.html +2 -2
- package/docs/interfaces/ActionsExtendedInfo.html +2 -2
- package/docs/interfaces/ActionsQuery.html +2 -2
- package/docs/interfaces/ActionsResponse.html +2 -2
- package/docs/interfaces/AggregateMetrics.html +2 -2
- package/docs/interfaces/BlockQuery.html +2 -2
- package/docs/interfaces/BlockResponse.html +2 -2
- package/docs/interfaces/BlockSummary.html +2 -2
- package/docs/interfaces/BlockSummaryResponse.html +2 -2
- package/docs/interfaces/DeltaEvent.html +2 -2
- package/docs/interfaces/ERC20TokenInfo.html +2 -2
- package/docs/interfaces/Info.html +2 -2
- package/docs/interfaces/Market.html +2 -2
- package/docs/interfaces/MarketStats.html +2 -2
- package/docs/interfaces/MarketsStatsResponse.html +2 -2
- package/docs/interfaces/NordConfig.html +2 -2
- package/docs/interfaces/Order.html +2 -2
- package/docs/interfaces/OrderInfo.html +2 -2
- package/docs/interfaces/PerpMarketStats.html +2 -2
- package/docs/interfaces/RollmanActionExtendedInfo.html +2 -2
- package/docs/interfaces/RollmanActionInfo.html +2 -2
- package/docs/interfaces/RollmanActionResponse.html +2 -2
- package/docs/interfaces/RollmanActionsResponse.html +2 -2
- package/docs/interfaces/RollmanBlockResponse.html +2 -2
- package/docs/interfaces/SubscriberConfig.html +2 -2
- package/docs/interfaces/Token.html +2 -2
- package/docs/interfaces/Trade.html +2 -2
- package/docs/interfaces/Trades.html +2 -2
- package/docs/modules.html +0 -7
- package/docs/types/BigIntValue.html +1 -1
- package/docs/variables/DEBUG_KEYS.html +1 -1
- package/docs/variables/DEFAULT_FUNDING_AMOUNTS.html +1 -1
- package/docs/variables/DEV_CONTRACT_ADDRESS.html +1 -1
- package/docs/variables/DEV_TOKEN_INFOS.html +1 -1
- package/docs/variables/DEV_URL.html +1 -1
- package/docs/variables/ERC20_ABI.html +1 -1
- package/docs/variables/EVM_DEV_URL.html +1 -1
- package/docs/variables/FAUCET_PRIVATE_ADDRESS.html +1 -1
- package/docs/variables/MAX_BUFFER_LEN.html +1 -1
- package/docs/variables/NORD_GETTERS_FACET_ABI.html +1 -1
- package/docs/variables/NORD_RAMP_FACET_ABI.html +1 -1
- package/docs/variables/SESSION_TTL.html +1 -1
- package/docs/variables/WEBSERVER_DEV_URL.html +1 -1
- package/docs/variables/ZERO_DECIMAL.html +1 -1
- package/package.json +10 -12
- package/src/bridge/client.ts +487 -0
- package/src/bridge/const.ts +53 -0
- package/src/bridge/index.ts +7 -0
- package/src/bridge/types.ts +127 -0
- package/src/bridge/utils.ts +140 -0
- package/src/const.ts +20 -25
- package/src/gen/common.ts +27 -10
- package/src/gen/nord.ts +1044 -483
- package/src/idl/bridge.ts +702 -0
- package/src/index.ts +24 -5
- package/src/nord/{actions.ts → api/actions.ts} +33 -37
- package/src/nord/api/core.ts +130 -0
- package/src/nord/api/market.ts +125 -0
- package/src/nord/api/metrics.ts +154 -0
- package/src/nord/api/queries.ts +236 -0
- package/src/nord/client/Nord.ts +652 -0
- package/src/nord/client/NordUser.ts +1105 -0
- package/src/nord/index.ts +16 -2
- package/src/nord/models/Subscriber.ts +57 -0
- package/src/nord/utils/NordError.ts +72 -0
- package/src/types.ts +170 -99
- package/src/utils.ts +40 -19
- package/src/websocket/NordWebSocketClient.ts +432 -0
- package/src/websocket/events.ts +31 -0
- package/src/websocket/index.ts +2 -0
- package/tests/utils.spec.ts +24 -24
- package/docs/classes/Subscriber.html +0 -6
- package/docs/functions/createWebSocketSubscription.html +0 -12
- package/docs/interfaces/OrderbookOrder.html +0 -6
- package/docs/interfaces/OrderbookResponse.html +0 -10
- package/docs/interfaces/TradeInfo.html +0 -20
- package/docs/interfaces/TradesQueryParams.html +0 -10
- package/docs/interfaces/TradesResponse.html +0 -12
- package/src/abis/ERC20_ABI.ts +0 -310
- package/src/abis/NORD_GETTERS_FACET_ABI.ts +0 -192
- package/src/abis/NORD_RAMP_FACET_ABI.ts +0 -141
- package/src/abis/index.ts +0 -3
- package/src/nord/Nord.ts +0 -504
- package/src/nord/NordImpl.ts +0 -8
- 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,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,
|
|
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="
|
package/docs/assets/search.js
CHANGED
|
@@ -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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";
|