@n1xyz/nord-ts 0.1.6 → 0.1.7

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 (39) hide show
  1. package/dist/actions.d.ts +57 -0
  2. package/dist/actions.js +229 -0
  3. package/dist/client/Nord.d.ts +379 -0
  4. package/dist/client/Nord.js +718 -0
  5. package/dist/client/NordAdmin.d.ts +225 -0
  6. package/dist/client/NordAdmin.js +394 -0
  7. package/dist/client/NordUser.d.ts +350 -0
  8. package/dist/client/NordUser.js +743 -0
  9. package/dist/error.d.ts +35 -0
  10. package/dist/error.js +49 -0
  11. package/dist/gen/openapi.d.ts +40 -0
  12. package/dist/index.d.ts +6 -1
  13. package/dist/index.js +29 -1
  14. package/dist/nord/client/NordAdmin.js +2 -0
  15. package/dist/types.d.ts +4 -50
  16. package/dist/types.js +1 -24
  17. package/dist/utils.d.ts +8 -11
  18. package/dist/utils.js +54 -41
  19. package/dist/websocket/Subscriber.d.ts +37 -0
  20. package/dist/websocket/Subscriber.js +25 -0
  21. package/dist/websocket/index.d.ts +19 -2
  22. package/dist/websocket/index.js +82 -2
  23. package/package.json +1 -1
  24. package/src/actions.ts +333 -0
  25. package/src/{nord/client → client}/Nord.ts +207 -210
  26. package/src/{nord/client → client}/NordAdmin.ts +123 -153
  27. package/src/{nord/client → client}/NordUser.ts +216 -305
  28. package/src/gen/openapi.ts +40 -0
  29. package/src/index.ts +7 -1
  30. package/src/types.ts +4 -54
  31. package/src/utils.ts +44 -47
  32. package/src/{nord/models → websocket}/Subscriber.ts +2 -2
  33. package/src/websocket/index.ts +105 -2
  34. package/src/nord/api/actions.ts +0 -648
  35. package/src/nord/api/core.ts +0 -96
  36. package/src/nord/api/metrics.ts +0 -269
  37. package/src/nord/client/NordClient.ts +0 -79
  38. package/src/nord/index.ts +0 -25
  39. /package/src/{nord/utils/NordError.ts → error.ts} +0 -0
@@ -1,96 +0,0 @@
1
- import { SubscriptionPattern } from "../../types";
2
- import { NordWebSocketClient } from "../../websocket/index";
3
- import { NordError } from "../utils/NordError";
4
-
5
- /**
6
- * Initialize a WebSocket client for Nord
7
- *
8
- * Connects to the Nord WebSocket endpoint with support for multiple subscription types:
9
- * - trades@SYMBOL - For trade updates
10
- * - deltas@SYMBOL - For orderbook delta updates
11
- * - account@ACCOUNT_ID - For user-specific updates
12
- *
13
- * @param webServerUrl - Base URL for the Nord web server
14
- * @param subscriptions - Array of subscriptions (e.g., ["trades@BTCUSDC", "deltas@BTCUSDC", "account@42"])
15
- * @returns WebSocket client
16
- * @throws {NordError} If initialization fails or invalid subscription is provided
17
- */
18
- export function initWebSocketClient(
19
- webServerUrl: string,
20
- subscriptions?: SubscriptionPattern[] | "trades" | "delta" | "account",
21
- ): NordWebSocketClient {
22
- try {
23
- // Determine URL and subscriptions based on parameters
24
- let wsUrl = webServerUrl.replace(/^http/, "ws") + `/ws`;
25
-
26
- // Validate subscriptions parameter
27
- if (typeof subscriptions === "string") {
28
- // Legacy mode - handle endpoint string
29
- if (
30
- subscriptions === "trades" ||
31
- subscriptions === "delta" ||
32
- subscriptions === "account"
33
- ) {
34
- wsUrl += `/${subscriptions}`;
35
- } else {
36
- throw new NordError(
37
- `Invalid endpoint: ${subscriptions}. Must be "trades", "deltas", or "account".`,
38
- );
39
- }
40
- } else if (Array.isArray(subscriptions) && subscriptions.length > 0) {
41
- // New mode - validate and combine subscriptions in URL
42
- subscriptions.forEach(validateSubscription);
43
- wsUrl += `/${subscriptions.join("&")}`;
44
- } else {
45
- // Default to trades endpoint if no subscriptions specified
46
- wsUrl += `/trades`;
47
- }
48
-
49
- console.log(`Initializing WebSocket client with URL: ${wsUrl}`);
50
-
51
- // Create and connect the WebSocket client
52
- const ws = new NordWebSocketClient(wsUrl);
53
-
54
- // Add error handler
55
- ws.on("error", (error) => {
56
- console.error("Nord WebSocket error:", error);
57
- });
58
-
59
- // Add connected handler for debugging
60
- ws.on("connected", () => {
61
- console.log("Nord WebSocket connected successfully");
62
- });
63
-
64
- // Connect the WebSocket
65
- ws.connect();
66
- return ws;
67
- } catch (error) {
68
- console.error("Failed to initialize WebSocket client:", error);
69
- throw new NordError("Failed to initialize WebSocket client", {
70
- cause: error,
71
- });
72
- }
73
- }
74
-
75
- /**
76
- * Validates a subscription string follows the correct format
77
- *
78
- * @param subscription - The subscription to validate
79
- * @throws {NordError} If the subscription format is invalid
80
- */
81
- function validateSubscription(subscription: string): void {
82
- const [type, param] = subscription.split("@");
83
-
84
- if (!type || !param || !["trades", "deltas", "account"].includes(type)) {
85
- throw new NordError(
86
- `Invalid subscription format: ${subscription}. Expected format: "trades@SYMBOL", "deltas@SYMBOL", or "account@ID"`,
87
- );
88
- }
89
-
90
- // Additional validation for account subscriptions
91
- if (type === "account" && isNaN(Number(param))) {
92
- throw new NordError(
93
- `Invalid account ID in subscription: ${subscription}. Account ID must be a number.`,
94
- );
95
- }
96
- }
@@ -1,269 +0,0 @@
1
- import { AggregateMetrics, PeakTpsPeriodUnit } from "../../types";
2
- import { checkedFetch } from "../../utils";
3
- import { NordError } from "../utils/NordError";
4
-
5
- /**
6
- * Time periods for metrics queries
7
- */
8
- export enum MetricPeriod {
9
- ONE_MINUTE = "1m",
10
- FIVE_MINUTES = "5m",
11
- FIFTEEN_MINUTES = "15m",
12
- ONE_HOUR = "1h",
13
- FOUR_HOURS = "4h",
14
- ONE_DAY = "24h",
15
- ONE_WEEK = "7d",
16
- }
17
-
18
- /**
19
- * Fetch aggregate metrics from the Nord API
20
- *
21
- * @param webServerUrl - Base URL for the Nord web server
22
- * @param txPeakTpsPeriod - Period for peak TPS calculation
23
- * @param txPeakTpsPeriodUnit - Unit for peak TPS period
24
- * @returns Aggregate metrics
25
- * @throws {NordError} If the request fails
26
- */
27
- export async function aggregateMetrics(
28
- webServerUrl: string,
29
- txPeakTpsPeriod = 1,
30
- txPeakTpsPeriodUnit: PeakTpsPeriodUnit = PeakTpsPeriodUnit.Day,
31
- ): Promise<AggregateMetrics> {
32
- try {
33
- const response = await checkedFetch(
34
- `${webServerUrl}/metrics?tx_peak_tps_period=${txPeakTpsPeriod}&tx_peak_tps_period_unit=${txPeakTpsPeriodUnit}`,
35
- );
36
-
37
- // Get the raw text response (Prometheus format)
38
- const text = await response.text();
39
-
40
- // Parse the Prometheus-formatted metrics text into an AggregateMetrics object
41
- const metrics: AggregateMetrics = {
42
- blocks_total: 0,
43
- tx_total: extractMetricValue(text, "nord_requests_ok_count"),
44
- tx_tps: calculateTps(text),
45
- tx_tps_peak: calculatePeakTps(text),
46
- request_latency_average: extractLatency(text),
47
- };
48
-
49
- return metrics;
50
- } catch (error) {
51
- throw new NordError("Failed to fetch aggregate metrics", { cause: error });
52
- }
53
- }
54
-
55
- /**
56
- * Extract a metric value from Prometheus-formatted text
57
- *
58
- * @param text - Prometheus-formatted metrics text
59
- * @param metricName - Name of the metric to extract
60
- * @returns The metric value as a number, or 0 if not found
61
- */
62
- function extractMetricValue(text: string, metricName: string): number {
63
- const regex = new RegExp(`^${metricName}\\s+([\\d.]+)`, "m");
64
- const match = text.match(regex);
65
- return match ? parseFloat(match[1]) : 0;
66
- }
67
-
68
- /**
69
- * Calculate TPS from Prometheus metrics
70
- *
71
- * @param text - Prometheus-formatted metrics text
72
- * @returns Calculated TPS value
73
- */
74
- function calculateTps(text: string): number {
75
- // Use the request count and latency to estimate TPS
76
- const requestCount = extractMetricValue(text, "nord_requests_ok_count");
77
- const latencySum = extractSummaryValue(text, "nord_requests_ok_latency_sum");
78
- const latencyCount = extractSummaryValue(
79
- text,
80
- "nord_requests_ok_latency_count",
81
- );
82
-
83
- if (latencySum > 0 && latencyCount > 0) {
84
- // Average latency in seconds
85
- const avgLatency = latencySum / latencyCount;
86
- // If we have valid latency data, estimate TPS as requests per second
87
- return avgLatency > 0 ? requestCount / (latencyCount * avgLatency) : 0;
88
- }
89
-
90
- // Fallback: just return a small fraction of the total request count
91
- return requestCount > 0 ? requestCount / 100 : 0;
92
- }
93
-
94
- /**
95
- * Calculate peak TPS from Prometheus metrics
96
- *
97
- * @param text - Prometheus-formatted metrics text
98
- * @returns Calculated peak TPS value
99
- */
100
- function calculatePeakTps(text: string): number {
101
- // For peak TPS, we'll use a simple heuristic: 2x the current TPS estimate
102
- // TODO: fix this
103
- return calculateTps(text) * 2;
104
- }
105
-
106
- /**
107
- * Extract latency from Prometheus metrics
108
- *
109
- * @param text - Prometheus-formatted metrics text
110
- * @returns Average latency in seconds
111
- */
112
- function extractLatency(text: string): number {
113
- // TODO: fix - using average for latency is kinda wack. ok to merge for now but should change.
114
- const latencySum = extractSummaryValue(text, "nord_requests_ok_latency_sum");
115
- const latencyCount = extractSummaryValue(
116
- text,
117
- "nord_requests_ok_latency_count",
118
- );
119
-
120
- return latencyCount > 0 ? latencySum / latencyCount : 0;
121
- }
122
-
123
- /**
124
- * Extract a summary value from Prometheus-formatted text
125
- *
126
- * @param text - Prometheus-formatted metrics text
127
- * @param metricName - Name of the metric to extract
128
- * @returns The metric value as a number, or 0 if not found
129
- */
130
- function extractSummaryValue(text: string, metricName: string): number {
131
- const regex = new RegExp(`^${metricName}\\s+([\\d.]+)`, "m");
132
- const match = text.match(regex);
133
- return match ? parseFloat(match[1]) : 0;
134
- }
135
-
136
- /**
137
- * Get current transactions per second
138
- *
139
- * @param webServerUrl - Base URL for the Nord web server
140
- * @param period - Time period for the query
141
- * @returns Current TPS value
142
- * @throws {NordError} If the request fails
143
- */
144
- export async function getCurrentTps(
145
- webServerUrl: string,
146
- period: string = "1m",
147
- ): Promise<number> {
148
- try {
149
- // nord_tx_count doesn't exist in the metrics, use nord_requests_ok_count instead
150
- return await queryPrometheus(
151
- webServerUrl,
152
- `sum(rate(nord_requests_ok_count[${period}]))`,
153
- );
154
- } catch (error) {
155
- throw new NordError(`Failed to get current TPS for period ${period}`, {
156
- cause: error,
157
- });
158
- }
159
- }
160
-
161
- /**
162
- * Get peak transactions per second
163
- *
164
- * @param webServerUrl - Base URL for the Nord web server
165
- * @param period - Time period for the query
166
- * @returns Peak TPS value
167
- * @throws {NordError} If the request fails
168
- */
169
- export async function getPeakTps(
170
- webServerUrl: string,
171
- period: string = "24h",
172
- ): Promise<number> {
173
- try {
174
- // nord_tx_count doesn't exist in the metrics, use nord_requests_ok_count instead
175
- return await queryPrometheus(
176
- webServerUrl,
177
- `max_over_time(sum(rate(nord_requests_ok_count[1m]))[${period}:])`,
178
- );
179
- } catch (error) {
180
- throw new NordError(`Failed to get peak TPS for period ${period}`, {
181
- cause: error,
182
- });
183
- }
184
- }
185
-
186
- /**
187
- * Get median transaction latency
188
- *
189
- * @param webServerUrl - Base URL for the Nord web server
190
- * @param period - Time period for the query
191
- * @returns Median latency in milliseconds
192
- * @throws {NordError} If the request fails
193
- */
194
- export async function getMedianLatency(
195
- webServerUrl: string,
196
- period: string = "1m",
197
- ): Promise<number> {
198
- try {
199
- // nord_tx_latency_ms doesn't exist, use nord_requests_ok_latency instead
200
- // which contains the latency data in the summary metric
201
- return await queryPrometheus(
202
- webServerUrl,
203
- `quantile_over_time(0.5, nord_requests_ok_latency[${period}]) * 1000`, // Convert to milliseconds
204
- );
205
- } catch (error) {
206
- throw new NordError(`Failed to get median latency for period ${period}`, {
207
- cause: error,
208
- });
209
- }
210
- }
211
-
212
- /**
213
- * Get total transaction count
214
- *
215
- * @param webServerUrl - Base URL for the Nord web server
216
- * @returns Total transaction count
217
- * @throws {NordError} If the request fails
218
- */
219
- export async function getTotalTransactions(
220
- webServerUrl: string,
221
- ): Promise<number> {
222
- try {
223
- // nord_tx_count doesn't exist, use nord_requests_ok_count instead
224
- return await queryPrometheus(webServerUrl, "sum(nord_requests_ok_count)");
225
- } catch (error) {
226
- throw new NordError("Failed to get total transactions", { cause: error });
227
- }
228
- }
229
-
230
- /**
231
- * Query Prometheus metrics
232
- *
233
- * @param webServerUrl - Base URL for the Nord web server
234
- * @param params - Prometheus query parameters
235
- * @returns Query result as a number
236
- * @throws {NordError} If the request fails
237
- */
238
- export async function queryPrometheus(
239
- webServerUrl: string,
240
- params: string,
241
- ): Promise<number> {
242
- try {
243
- const response = await checkedFetch(
244
- `${webServerUrl}/prometheus?query=${encodeURIComponent(params)}`,
245
- );
246
-
247
- // Handle raw text response
248
- const text = await response.text();
249
- try {
250
- // Try to parse as JSON first
251
- const data = JSON.parse(text);
252
- return data.data.result[0]?.value[1] || 0;
253
- } catch (error) {
254
- console.log("Prometheus query failed:", error);
255
- // Try to find a number in the response
256
- const numberMatch = text.match(/[\d.]+/);
257
- if (numberMatch) {
258
- return parseFloat(numberMatch[0]);
259
- }
260
-
261
- // Return 0 if no number is found
262
- return 0;
263
- }
264
- } catch (error) {
265
- throw new NordError(`Failed to query Prometheus: ${params}`, {
266
- cause: error,
267
- });
268
- }
269
- }
@@ -1,79 +0,0 @@
1
- import { Connection, PublicKey } from "@solana/web3.js";
2
- import type { Transaction } from "@solana/web3.js";
3
- import * as proto from "../../gen/nord_pb";
4
- import { createAction, sendAction } from "../api/actions";
5
- import { Nord } from "./Nord";
6
-
7
- export interface NordClientParams {
8
- nord: Nord;
9
- address: PublicKey;
10
- walletSignFn: (message: Uint8Array | string) => Promise<Uint8Array>;
11
- sessionSignFn: (message: Uint8Array) => Promise<Uint8Array>;
12
- transactionSignFn: <T extends Transaction>(tx: T) => Promise<T>;
13
- connection?: Connection;
14
- sessionId?: bigint;
15
- sessionPubKey: Uint8Array;
16
- publicKey: PublicKey;
17
- }
18
-
19
- export abstract class NordClient {
20
- public readonly nord: Nord;
21
- public readonly address: PublicKey;
22
- public readonly walletSignFn: (
23
- message: Uint8Array | string,
24
- ) => Promise<Uint8Array>;
25
- public readonly sessionSignFn: (message: Uint8Array) => Promise<Uint8Array>;
26
- public readonly transactionSignFn: <T extends Transaction>(
27
- tx: T,
28
- ) => Promise<T>;
29
- public connection: Connection;
30
- public sessionId?: bigint;
31
- public sessionPubKey: Uint8Array;
32
- public publicKey: PublicKey;
33
- public lastTs = 0;
34
-
35
- protected actionNonce = 0;
36
-
37
- protected constructor(params: NordClientParams) {
38
- this.nord = params.nord;
39
- this.address = params.address;
40
- this.walletSignFn = params.walletSignFn;
41
- this.sessionSignFn = params.sessionSignFn;
42
- this.transactionSignFn = params.transactionSignFn;
43
- this.connection =
44
- params.connection ??
45
- new Connection(params.nord.solanaUrl, {
46
- commitment: "confirmed",
47
- });
48
- this.sessionId = params.sessionId;
49
- this.sessionPubKey = new Uint8Array(params.sessionPubKey);
50
- this.publicKey = params.publicKey;
51
- }
52
-
53
- protected async submitSignedAction(
54
- kind: proto.Action["kind"],
55
- makeSignedMessage: (message: Uint8Array) => Promise<Uint8Array>,
56
- ): Promise<proto.Receipt> {
57
- const nonce = this.nextActionNonce();
58
- const currentTimestamp = await this.nord.getTimestamp();
59
- const action = createAction(currentTimestamp, nonce, kind);
60
- return sendAction(this.nord.webServerUrl, makeSignedMessage, action);
61
- }
62
-
63
- protected nextActionNonce(): number {
64
- return ++this.actionNonce;
65
- }
66
-
67
- protected cloneClientState(target: NordClient): void {
68
- target.connection = this.connection;
69
- target.sessionId = this.sessionId;
70
- target.sessionPubKey = new Uint8Array(this.sessionPubKey);
71
- target.publicKey = this.publicKey;
72
- target.lastTs = this.lastTs;
73
- target.actionNonce = this.actionNonce;
74
- }
75
-
76
- getSolanaPublicKey(): PublicKey {
77
- return this.address;
78
- }
79
- }
package/src/nord/index.ts DELETED
@@ -1,25 +0,0 @@
1
- // Export main client classes
2
- export { Nord } from "./client/Nord";
3
- export { NordUser } from "./client/NordUser";
4
- export { NordAdmin, AclRole } from "./client/NordAdmin";
5
- export { NordClient } from "./client/NordClient";
6
- export type { NordClientParams } from "./client/NordClient";
7
- export type {
8
- CreateTokenParams,
9
- CreateMarketParams,
10
- PythSetWormholeGuardiansParams,
11
- PythSetSymbolFeedParams,
12
- FreezeMarketParams,
13
- UnfreezeMarketParams,
14
- } from "./client/NordAdmin";
15
-
16
- // Export utility classes
17
- export { NordError } from "./utils/NordError";
18
-
19
- // Export API modules
20
- export * from "./api/core";
21
- export * from "./api/metrics";
22
- export * from "./api/actions";
23
-
24
- // Export models
25
- export * from "./models/Subscriber";
File without changes