@n1xyz/nord-ts 0.0.12 → 0.0.14
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/nord/api/core.d.ts +8 -8
- package/dist/nord/api/core.js +55 -14
- package/dist/nord/api/metrics.js +1 -1
- package/dist/nord/client/Nord.d.ts +39 -68
- package/dist/nord/client/Nord.js +97 -115
- package/dist/nord/client/NordUser.d.ts +0 -17
- package/dist/nord/client/NordUser.js +0 -28
- package/dist/types.d.ts +36 -13
- package/dist/types.js +2 -2
- package/dist/websocket/NordWebSocketClient.d.ts +0 -3
- package/dist/websocket/NordWebSocketClient.js +10 -13
- package/dist/websocket/events.d.ts +2 -2
- package/package.json +1 -1
- package/src/idl/bridge.ts +0 -1
- package/src/nord/api/core.ts +69 -17
- package/src/nord/api/metrics.ts +26 -20
- package/src/nord/api/queries.ts +7 -11
- package/src/nord/client/Nord.ts +126 -156
- package/src/nord/client/NordUser.ts +0 -49
- package/src/types.ts +38 -13
- package/src/websocket/NordWebSocketClient.ts +11 -14
- package/src/websocket/events.ts +2 -2
- package/test.ts +0 -107
package/dist/types.d.ts
CHANGED
|
@@ -15,6 +15,16 @@ export declare enum PeakTpsPeriodUnit {
|
|
|
15
15
|
Month = "m",
|
|
16
16
|
Year = "y"
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Nord subscription type for trades or deltas
|
|
20
|
+
*/
|
|
21
|
+
export type SubscriptionType = 'trades' | 'deltas' | 'account';
|
|
22
|
+
/**
|
|
23
|
+
* Pattern for a valid Nord subscription
|
|
24
|
+
* Format should be: "<type>@<parameter>"
|
|
25
|
+
* Examples: "trades@BTCUSDC", "deltas@ETHUSDC", "account@42"
|
|
26
|
+
*/
|
|
27
|
+
export type SubscriptionPattern = `${SubscriptionType}@${string}` | string;
|
|
18
28
|
/**
|
|
19
29
|
* Configuration options for the Nord client
|
|
20
30
|
*/
|
|
@@ -27,11 +37,24 @@ export interface NordConfig {
|
|
|
27
37
|
solanaUrl: string;
|
|
28
38
|
/** Whether to initialize WebSockets on creation, defaults to true */
|
|
29
39
|
initWebSockets?: boolean;
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Initial subscriptions for the trades WebSocket
|
|
42
|
+
* Supports both formats:
|
|
43
|
+
* - Legacy format: ["BTCUSDC", "ETHUSDC"]
|
|
44
|
+
* - New format: ["trades@BTCUSDC", "trades@ETHUSDC"]
|
|
45
|
+
*/
|
|
46
|
+
tradesSubscriptions?: SubscriptionPattern[];
|
|
47
|
+
/**
|
|
48
|
+
* Initial subscriptions for the deltas WebSocket
|
|
49
|
+
* Supports both formats:
|
|
50
|
+
* - Legacy format: ["BTCUSDC", "ETHUSDC"]
|
|
51
|
+
* - New format: ["deltas@BTCUSDC", "deltas@ETHUSDC"]
|
|
52
|
+
*/
|
|
53
|
+
deltasSubscriptions?: SubscriptionPattern[];
|
|
34
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Configuration options for the Nord client
|
|
57
|
+
*/
|
|
35
58
|
export interface TokenInfo {
|
|
36
59
|
address: string;
|
|
37
60
|
precision: number;
|
|
@@ -355,22 +378,22 @@ export interface ActionNonceResponse {
|
|
|
355
378
|
export declare enum WebSocketMessageType {
|
|
356
379
|
Subscribe = "subscribe",
|
|
357
380
|
Unsubscribe = "unsubscribe",
|
|
358
|
-
TradeUpdate = "
|
|
381
|
+
TradeUpdate = "trades",
|
|
359
382
|
DeltaUpdate = "delta",
|
|
360
|
-
|
|
383
|
+
AccountUpdate = "account"
|
|
361
384
|
}
|
|
362
385
|
/**
|
|
363
386
|
* WebSocket subscription request
|
|
364
387
|
*/
|
|
365
388
|
export interface WebSocketSubscription {
|
|
366
|
-
|
|
389
|
+
e: WebSocketMessageType;
|
|
367
390
|
streams: string[];
|
|
368
391
|
}
|
|
369
392
|
/**
|
|
370
393
|
* WebSocket trade update message
|
|
371
394
|
*/
|
|
372
395
|
export interface WebSocketTradeUpdate {
|
|
373
|
-
|
|
396
|
+
e: WebSocketMessageType.TradeUpdate;
|
|
374
397
|
symbol: string;
|
|
375
398
|
trades: Trade[];
|
|
376
399
|
timestamp: number;
|
|
@@ -379,7 +402,7 @@ export interface WebSocketTradeUpdate {
|
|
|
379
402
|
* WebSocket delta update message
|
|
380
403
|
*/
|
|
381
404
|
export interface WebSocketDeltaUpdate {
|
|
382
|
-
|
|
405
|
+
e: WebSocketMessageType.DeltaUpdate;
|
|
383
406
|
last_update_id: number;
|
|
384
407
|
update_id: number;
|
|
385
408
|
market_symbol: string;
|
|
@@ -390,11 +413,11 @@ export interface WebSocketDeltaUpdate {
|
|
|
390
413
|
/**
|
|
391
414
|
* WebSocket user update message
|
|
392
415
|
*/
|
|
393
|
-
export interface
|
|
394
|
-
|
|
395
|
-
|
|
416
|
+
export interface WebSocketAccountUpdate {
|
|
417
|
+
e: WebSocketMessageType.AccountUpdate;
|
|
418
|
+
accountId: number;
|
|
396
419
|
account: Account;
|
|
397
420
|
timestamp: number;
|
|
398
421
|
}
|
|
399
|
-
export type WebSocketMessage = WebSocketSubscription | WebSocketTradeUpdate | WebSocketDeltaUpdate |
|
|
422
|
+
export type WebSocketMessage = WebSocketSubscription | WebSocketTradeUpdate | WebSocketDeltaUpdate | WebSocketAccountUpdate;
|
|
400
423
|
export {};
|
package/dist/types.js
CHANGED
|
@@ -97,7 +97,7 @@ var WebSocketMessageType;
|
|
|
97
97
|
(function (WebSocketMessageType) {
|
|
98
98
|
WebSocketMessageType["Subscribe"] = "subscribe";
|
|
99
99
|
WebSocketMessageType["Unsubscribe"] = "unsubscribe";
|
|
100
|
-
WebSocketMessageType["TradeUpdate"] = "
|
|
100
|
+
WebSocketMessageType["TradeUpdate"] = "trades";
|
|
101
101
|
WebSocketMessageType["DeltaUpdate"] = "delta";
|
|
102
|
-
WebSocketMessageType["
|
|
102
|
+
WebSocketMessageType["AccountUpdate"] = "account";
|
|
103
103
|
})(WebSocketMessageType || (exports.WebSocketMessageType = WebSocketMessageType = {}));
|
|
@@ -4,9 +4,6 @@ import { NordWebSocketClientEvents } from "./events";
|
|
|
4
4
|
* WebSocket client for Nord exchange
|
|
5
5
|
*
|
|
6
6
|
* This client connects to one of the specific Nord WebSocket endpoints:
|
|
7
|
-
* - /ws/trades - For trade updates
|
|
8
|
-
* - /ws/deltas - For orderbook delta updates
|
|
9
|
-
* - /ws/user - For user-specific updates
|
|
10
7
|
*
|
|
11
8
|
* Each endpoint handles a specific type of data and subscriptions must match
|
|
12
9
|
* the endpoint type (e.g., only 'trades@BTCUSDC' subscriptions are valid on
|
|
@@ -7,16 +7,13 @@ exports.NordWebSocketClient = void 0;
|
|
|
7
7
|
const ws_1 = __importDefault(require("ws"));
|
|
8
8
|
const events_1 = require("events");
|
|
9
9
|
const types_1 = require("../types");
|
|
10
|
-
const VALID_STREAM_TYPES = ["trades", "
|
|
10
|
+
const VALID_STREAM_TYPES = ["trades", "delta", "account"];
|
|
11
11
|
// Constants for WebSocket readyState
|
|
12
12
|
const WS_OPEN = 1;
|
|
13
13
|
/**
|
|
14
14
|
* WebSocket client for Nord exchange
|
|
15
15
|
*
|
|
16
16
|
* This client connects to one of the specific Nord WebSocket endpoints:
|
|
17
|
-
* - /ws/trades - For trade updates
|
|
18
|
-
* - /ws/deltas - For orderbook delta updates
|
|
19
|
-
* - /ws/user - For user-specific updates
|
|
20
17
|
*
|
|
21
18
|
* Each endpoint handles a specific type of data and subscriptions must match
|
|
22
19
|
* the endpoint type (e.g., only 'trades@BTCUSDC' subscriptions are valid on
|
|
@@ -64,8 +61,8 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
64
61
|
if (!VALID_STREAM_TYPES.includes(type)) {
|
|
65
62
|
throw new Error(`Invalid stream type: ${type}. Valid types are: ${VALID_STREAM_TYPES.join(", ")}`);
|
|
66
63
|
}
|
|
67
|
-
if (type === "
|
|
68
|
-
throw new Error(`Invalid
|
|
64
|
+
if (type === "account" && !/^\d+$/.test(params)) {
|
|
65
|
+
throw new Error(`Invalid account ID in stream: ${params}. Expected numeric ID`);
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
68
|
/**
|
|
@@ -228,7 +225,7 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
228
225
|
return;
|
|
229
226
|
}
|
|
230
227
|
const message = {
|
|
231
|
-
|
|
228
|
+
e: types_1.WebSocketMessageType.Subscribe,
|
|
232
229
|
streams,
|
|
233
230
|
};
|
|
234
231
|
try {
|
|
@@ -266,7 +263,7 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
266
263
|
return;
|
|
267
264
|
}
|
|
268
265
|
const message = {
|
|
269
|
-
|
|
266
|
+
e: types_1.WebSocketMessageType.Unsubscribe,
|
|
270
267
|
streams,
|
|
271
268
|
};
|
|
272
269
|
try {
|
|
@@ -311,18 +308,18 @@ class NordWebSocketClient extends events_1.EventEmitter {
|
|
|
311
308
|
* @param message WebSocket message
|
|
312
309
|
*/
|
|
313
310
|
handleMessage(message) {
|
|
314
|
-
switch (message.
|
|
311
|
+
switch (message.e) {
|
|
315
312
|
case types_1.WebSocketMessageType.TradeUpdate:
|
|
316
|
-
this.emit("
|
|
313
|
+
this.emit("trades", message);
|
|
317
314
|
break;
|
|
318
315
|
case types_1.WebSocketMessageType.DeltaUpdate:
|
|
319
316
|
this.emit("delta", message);
|
|
320
317
|
break;
|
|
321
|
-
case types_1.WebSocketMessageType.
|
|
322
|
-
this.emit("
|
|
318
|
+
case types_1.WebSocketMessageType.AccountUpdate:
|
|
319
|
+
this.emit("account", message);
|
|
323
320
|
break;
|
|
324
321
|
default:
|
|
325
|
-
this.emit("error", new Error(`Unknown message type: ${message.
|
|
322
|
+
this.emit("error", new Error(`Unknown message type: ${message.e}`));
|
|
326
323
|
}
|
|
327
324
|
}
|
|
328
325
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WebSocketTradeUpdate, WebSocketDeltaUpdate,
|
|
1
|
+
import { WebSocketTradeUpdate, WebSocketDeltaUpdate, WebSocketAccountUpdate } from "../types";
|
|
2
2
|
/**
|
|
3
3
|
* Event type definitions for the NordWebSocketClient
|
|
4
4
|
*/
|
|
@@ -8,7 +8,7 @@ export interface NordWebSocketEvents {
|
|
|
8
8
|
error: (error: Error) => void;
|
|
9
9
|
trade: (update: WebSocketTradeUpdate) => void;
|
|
10
10
|
delta: (update: WebSocketDeltaUpdate) => void;
|
|
11
|
-
|
|
11
|
+
account: (update: WebSocketAccountUpdate) => void;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Type declaration for NordWebSocketClient event methods
|
package/package.json
CHANGED
package/src/idl/bridge.ts
CHANGED
package/src/nord/api/core.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Account, Info } from "../../types";
|
|
1
|
+
import { Account, Info, SubscriptionPattern } from "../../types";
|
|
2
2
|
import { checkedFetch } from "../../utils";
|
|
3
3
|
import { NordWebSocketClient } from "../../websocket/index";
|
|
4
4
|
import { NordError } from "../utils/NordError";
|
|
@@ -77,27 +77,55 @@ export async function getAccount(
|
|
|
77
77
|
/**
|
|
78
78
|
* Initialize a WebSocket client for Nord
|
|
79
79
|
*
|
|
80
|
-
* Connects to
|
|
81
|
-
* -
|
|
82
|
-
* -
|
|
83
|
-
* -
|
|
80
|
+
* Connects to the Nord WebSocket endpoint with support for multiple subscription types:
|
|
81
|
+
* - trades@SYMBOL - For trade updates
|
|
82
|
+
* - deltas@SYMBOL - For orderbook delta updates
|
|
83
|
+
* - account@ACCOUNT_ID - For user-specific updates
|
|
84
84
|
*
|
|
85
85
|
* @param webServerUrl - Base URL for the Nord web server
|
|
86
|
-
* @param
|
|
87
|
-
* @param initialSubscriptions - Optional array of initial subscriptions (e.g., ["trades@BTCUSDC"])
|
|
86
|
+
* @param subscriptions - Array of subscriptions (e.g., ["trades@BTCUSDC", "deltas@BTCUSDC", "account@42"])
|
|
88
87
|
* @returns WebSocket client
|
|
88
|
+
* @throws {NordError} If initialization fails or invalid subscription is provided
|
|
89
89
|
*/
|
|
90
90
|
export function initWebSocketClient(
|
|
91
91
|
webServerUrl: string,
|
|
92
|
-
|
|
93
|
-
initialSubscriptions?:
|
|
92
|
+
subscriptions?: SubscriptionPattern[] | "trades" | "delta" | "account",
|
|
93
|
+
initialSubscriptions?: SubscriptionPattern[],
|
|
94
94
|
): NordWebSocketClient {
|
|
95
95
|
try {
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
// Determine URL and subscriptions based on parameters
|
|
97
|
+
let wsUrl = webServerUrl.replace(/^http/, "ws") + `/ws`;
|
|
98
|
+
let wsSubscriptions: SubscriptionPattern[] = [];
|
|
99
|
+
|
|
100
|
+
// Validate subscriptions parameter
|
|
101
|
+
if (typeof subscriptions === "string") {
|
|
102
|
+
// Legacy mode - handle endpoint string
|
|
103
|
+
if (
|
|
104
|
+
subscriptions === "trades" ||
|
|
105
|
+
subscriptions === "delta" ||
|
|
106
|
+
subscriptions === "account"
|
|
107
|
+
) {
|
|
108
|
+
wsUrl += `/${subscriptions}`;
|
|
109
|
+
// If initialSubscriptions provided, use them
|
|
110
|
+
if (initialSubscriptions && initialSubscriptions.length > 0) {
|
|
111
|
+
// Validate initialSubscriptions
|
|
112
|
+
initialSubscriptions.forEach(validateSubscription);
|
|
113
|
+
wsSubscriptions = initialSubscriptions;
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
throw new NordError(
|
|
117
|
+
`Invalid endpoint: ${subscriptions}. Must be "trades", "deltas", or "account".`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
} else if (Array.isArray(subscriptions) && subscriptions.length > 0) {
|
|
121
|
+
// New mode - validate and combine subscriptions in URL
|
|
122
|
+
subscriptions.forEach(validateSubscription);
|
|
123
|
+
wsUrl += `/${subscriptions.join("&")}`;
|
|
124
|
+
} else {
|
|
125
|
+
// Default to trades endpoint if no subscriptions specified
|
|
126
|
+
wsUrl += `/trades`;
|
|
127
|
+
}
|
|
128
|
+
|
|
101
129
|
console.log(`Initializing WebSocket client with URL: ${wsUrl}`);
|
|
102
130
|
|
|
103
131
|
// Create and connect the WebSocket client
|
|
@@ -112,9 +140,10 @@ export function initWebSocketClient(
|
|
|
112
140
|
ws.on("connected", () => {
|
|
113
141
|
console.log("Nord WebSocket connected successfully");
|
|
114
142
|
|
|
115
|
-
// Subscribe to
|
|
116
|
-
|
|
117
|
-
|
|
143
|
+
// Subscribe to additional subscriptions if provided
|
|
144
|
+
// For new format, these are already part of the URL
|
|
145
|
+
if (wsSubscriptions.length > 0) {
|
|
146
|
+
ws.subscribe(wsSubscriptions);
|
|
118
147
|
}
|
|
119
148
|
});
|
|
120
149
|
|
|
@@ -128,3 +157,26 @@ export function initWebSocketClient(
|
|
|
128
157
|
});
|
|
129
158
|
}
|
|
130
159
|
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Validates a subscription string follows the correct format
|
|
163
|
+
*
|
|
164
|
+
* @param subscription - The subscription to validate
|
|
165
|
+
* @throws {NordError} If the subscription format is invalid
|
|
166
|
+
*/
|
|
167
|
+
function validateSubscription(subscription: string): void {
|
|
168
|
+
const [type, param] = subscription.split("@");
|
|
169
|
+
|
|
170
|
+
if (!type || !param || !["trades", "deltas", "account"].includes(type)) {
|
|
171
|
+
throw new NordError(
|
|
172
|
+
`Invalid subscription format: ${subscription}. Expected format: "trades@SYMBOL", "deltas@SYMBOL", or "account@ID"`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Additional validation for account subscriptions
|
|
177
|
+
if (type === "account" && isNaN(Number(param))) {
|
|
178
|
+
throw new NordError(
|
|
179
|
+
`Invalid account ID in subscription: ${subscription}. Account ID must be a number.`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
package/src/nord/api/metrics.ts
CHANGED
|
@@ -33,19 +33,19 @@ export async function aggregateMetrics(
|
|
|
33
33
|
const response = await checkedFetch(
|
|
34
34
|
`${webServerUrl}/metrics?tx_peak_tps_period=${txPeakTpsPeriod}&tx_peak_tps_period_unit=${txPeakTpsPeriodUnit}`,
|
|
35
35
|
);
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
// Get the raw text response (Prometheus format)
|
|
38
38
|
const text = await response.text();
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
// Parse the Prometheus-formatted metrics text into an AggregateMetrics object
|
|
41
41
|
const metrics: AggregateMetrics = {
|
|
42
42
|
blocks_total: 0,
|
|
43
43
|
tx_total: extractMetricValue(text, "nord_requests_ok_count"),
|
|
44
44
|
tx_tps: calculateTps(text),
|
|
45
45
|
tx_tps_peak: calculatePeakTps(text),
|
|
46
|
-
request_latency_average: extractLatency(text)
|
|
46
|
+
request_latency_average: extractLatency(text),
|
|
47
47
|
};
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
return metrics;
|
|
50
50
|
} catch (error) {
|
|
51
51
|
throw new NordError("Failed to fetch aggregate metrics", { cause: error });
|
|
@@ -54,20 +54,20 @@ export async function aggregateMetrics(
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Extract a metric value from Prometheus-formatted text
|
|
57
|
-
*
|
|
57
|
+
*
|
|
58
58
|
* @param text - Prometheus-formatted metrics text
|
|
59
59
|
* @param metricName - Name of the metric to extract
|
|
60
60
|
* @returns The metric value as a number, or 0 if not found
|
|
61
61
|
*/
|
|
62
62
|
function extractMetricValue(text: string, metricName: string): number {
|
|
63
|
-
const regex = new RegExp(`^${metricName}\\s+([\\d.]+)`,
|
|
63
|
+
const regex = new RegExp(`^${metricName}\\s+([\\d.]+)`, "m");
|
|
64
64
|
const match = text.match(regex);
|
|
65
65
|
return match ? parseFloat(match[1]) : 0;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Calculate TPS from Prometheus metrics
|
|
70
|
-
*
|
|
70
|
+
*
|
|
71
71
|
* @param text - Prometheus-formatted metrics text
|
|
72
72
|
* @returns Calculated TPS value
|
|
73
73
|
*/
|
|
@@ -75,22 +75,25 @@ function calculateTps(text: string): number {
|
|
|
75
75
|
// Use the request count and latency to estimate TPS
|
|
76
76
|
const requestCount = extractMetricValue(text, "nord_requests_ok_count");
|
|
77
77
|
const latencySum = extractSummaryValue(text, "nord_requests_ok_latency_sum");
|
|
78
|
-
const latencyCount = extractSummaryValue(
|
|
79
|
-
|
|
78
|
+
const latencyCount = extractSummaryValue(
|
|
79
|
+
text,
|
|
80
|
+
"nord_requests_ok_latency_count",
|
|
81
|
+
);
|
|
82
|
+
|
|
80
83
|
if (latencySum > 0 && latencyCount > 0) {
|
|
81
84
|
// Average latency in seconds
|
|
82
85
|
const avgLatency = latencySum / latencyCount;
|
|
83
86
|
// If we have valid latency data, estimate TPS as requests per second
|
|
84
87
|
return avgLatency > 0 ? requestCount / (latencyCount * avgLatency) : 0;
|
|
85
88
|
}
|
|
86
|
-
|
|
89
|
+
|
|
87
90
|
// Fallback: just return a small fraction of the total request count
|
|
88
91
|
return requestCount > 0 ? requestCount / 100 : 0;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
/**
|
|
92
95
|
* Calculate peak TPS from Prometheus metrics
|
|
93
|
-
*
|
|
96
|
+
*
|
|
94
97
|
* @param text - Prometheus-formatted metrics text
|
|
95
98
|
* @returns Calculated peak TPS value
|
|
96
99
|
*/
|
|
@@ -101,26 +104,29 @@ function calculatePeakTps(text: string): number {
|
|
|
101
104
|
|
|
102
105
|
/**
|
|
103
106
|
* Extract latency from Prometheus metrics
|
|
104
|
-
*
|
|
107
|
+
*
|
|
105
108
|
* @param text - Prometheus-formatted metrics text
|
|
106
109
|
* @returns Average latency in seconds
|
|
107
110
|
*/
|
|
108
111
|
function extractLatency(text: string): number {
|
|
109
112
|
const latencySum = extractSummaryValue(text, "nord_requests_ok_latency_sum");
|
|
110
|
-
const latencyCount = extractSummaryValue(
|
|
111
|
-
|
|
113
|
+
const latencyCount = extractSummaryValue(
|
|
114
|
+
text,
|
|
115
|
+
"nord_requests_ok_latency_count",
|
|
116
|
+
);
|
|
117
|
+
|
|
112
118
|
return latencyCount > 0 ? latencySum / latencyCount : 0;
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
/**
|
|
116
122
|
* Extract a summary value from Prometheus-formatted text
|
|
117
|
-
*
|
|
123
|
+
*
|
|
118
124
|
* @param text - Prometheus-formatted metrics text
|
|
119
125
|
* @param metricName - Name of the metric to extract
|
|
120
126
|
* @returns The metric value as a number, or 0 if not found
|
|
121
127
|
*/
|
|
122
128
|
function extractSummaryValue(text: string, metricName: string): number {
|
|
123
|
-
const regex = new RegExp(`^${metricName}\\s+([\\d.]+)`,
|
|
129
|
+
const regex = new RegExp(`^${metricName}\\s+([\\d.]+)`, "m");
|
|
124
130
|
const match = text.match(regex);
|
|
125
131
|
return match ? parseFloat(match[1]) : 0;
|
|
126
132
|
}
|
|
@@ -235,21 +241,21 @@ export async function queryPrometheus(
|
|
|
235
241
|
const response = await checkedFetch(
|
|
236
242
|
`${webServerUrl}/prometheus?query=${encodeURIComponent(params)}`,
|
|
237
243
|
);
|
|
238
|
-
|
|
244
|
+
|
|
239
245
|
// Handle raw text response
|
|
240
246
|
const text = await response.text();
|
|
241
247
|
try {
|
|
242
248
|
// Try to parse as JSON first
|
|
243
249
|
const data = JSON.parse(text);
|
|
244
250
|
return data.data.result[0]?.value[1] || 0;
|
|
245
|
-
} catch (
|
|
246
|
-
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.log("Prometheus query failed:", error);
|
|
247
253
|
// Try to find a number in the response
|
|
248
254
|
const numberMatch = text.match(/[\d.]+/);
|
|
249
255
|
if (numberMatch) {
|
|
250
256
|
return parseFloat(numberMatch[0]);
|
|
251
257
|
}
|
|
252
|
-
|
|
258
|
+
|
|
253
259
|
// Return 0 if no number is found
|
|
254
260
|
return 0;
|
|
255
261
|
}
|
package/src/nord/api/queries.ts
CHANGED
|
@@ -2,17 +2,12 @@ import {
|
|
|
2
2
|
ActionQuery,
|
|
3
3
|
ActionResponse,
|
|
4
4
|
ActionsResponse,
|
|
5
|
-
BlockQuery,
|
|
6
|
-
BlockResponse,
|
|
7
|
-
BlockSummaryResponse,
|
|
8
5
|
RollmanActionResponse,
|
|
9
6
|
RollmanActionsResponse,
|
|
10
|
-
RollmanBlockResponse,
|
|
11
7
|
} from "../../types";
|
|
12
8
|
import { checkedFetch } from "../../utils";
|
|
13
9
|
import { NordError } from "../utils/NordError";
|
|
14
10
|
|
|
15
|
-
|
|
16
11
|
/**
|
|
17
12
|
* Query a specific action
|
|
18
13
|
*
|
|
@@ -60,9 +55,12 @@ export async function queryRecentActions(
|
|
|
60
55
|
);
|
|
61
56
|
return await response.json();
|
|
62
57
|
} catch (error) {
|
|
63
|
-
throw new NordError(
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
throw new NordError(
|
|
59
|
+
`Failed to query recent actions (from ${from} to ${to})`,
|
|
60
|
+
{
|
|
61
|
+
cause: error,
|
|
62
|
+
},
|
|
63
|
+
);
|
|
66
64
|
}
|
|
67
65
|
}
|
|
68
66
|
|
|
@@ -73,9 +71,7 @@ export async function queryRecentActions(
|
|
|
73
71
|
* @returns Last action ID
|
|
74
72
|
* @throws {NordError} If the request fails
|
|
75
73
|
*/
|
|
76
|
-
export async function getLastActionId(
|
|
77
|
-
webServerUrl: string,
|
|
78
|
-
): Promise<number> {
|
|
74
|
+
export async function getLastActionId(webServerUrl: string): Promise<number> {
|
|
79
75
|
try {
|
|
80
76
|
const response = await checkedFetch(`${webServerUrl}/last_actionid`);
|
|
81
77
|
const data = await response.json();
|