@fenelabs/fene-sdk 0.3.2 → 0.3.3

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/index.js CHANGED
@@ -20,1114 +20,415 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- AnalyticsAPI: () => AnalyticsAPI,
24
- AuthService: () => AuthService,
25
- DelegatorsAPI: () => DelegatorsAPI,
26
- GlobalAPI: () => GlobalAPI,
27
- HTTPClient: () => HTTPClient,
28
- ReferralsAPI: () => ReferralsAPI,
29
- ResonanceSDK: () => ResonanceSDK,
30
- SlashingAPI: () => SlashingAPI,
31
- ValidatorsAPI: () => ValidatorsAPI,
32
- createRetryWrapper: () => createRetryWrapper,
33
- default: () => index_default,
34
- formatNumber: () => formatNumber,
35
- getDataFreshness: () => getDataFreshness,
36
- getOptimalBatchSize: () => getOptimalBatchSize,
37
- getSyncLag: () => getSyncLag,
38
- isCachedData: () => isCachedData,
39
- isServiceUnavailable: () => isServiceUnavailable,
40
- isStaleData: () => isStaleData,
41
- isSyncDegraded: () => isSyncDegraded,
42
- isSyncHealthy: () => isSyncHealthy,
43
- isTimeout: () => isTimeout,
44
- isValidatorNotFound: () => isValidatorNotFound,
45
- validatePagination: () => validatePagination,
46
- weiToEther: () => weiToEther,
47
- withRetry: () => withRetry
23
+ ErrorCode: () => ErrorCode,
24
+ ResonanceClient: () => ResonanceClient,
25
+ ResonanceError: () => ResonanceError,
26
+ createResonanceClient: () => createResonanceClient,
27
+ hasErrorCode: () => hasErrorCode,
28
+ isAuthError: () => isAuthError,
29
+ isNetworkError: () => isNetworkError,
30
+ isNotFoundError: () => isNotFoundError,
31
+ isResonanceError: () => isResonanceError
48
32
  });
49
33
  module.exports = __toCommonJS(index_exports);
50
34
 
51
35
  // src/errors.ts
52
- var ResonanceAPIError = class extends Error {
53
- constructor(statusCode, code, message) {
36
+ var ErrorCode = {
37
+ // Validator errors
38
+ VALIDATOR_NOT_FOUND: "VALIDATOR_NOT_FOUND",
39
+ VALIDATOR_INACTIVE: "VALIDATOR_INACTIVE",
40
+ // Delegator errors
41
+ DELEGATOR_NOT_FOUND: "DELEGATOR_NOT_FOUND",
42
+ NOT_WHITELISTED: "NOT_WHITELISTED",
43
+ // Referral errors
44
+ REFERRAL_KEY_INVALID: "REFERRAL_KEY_INVALID",
45
+ REFERRAL_KEY_EXPIRED: "REFERRAL_KEY_EXPIRED",
46
+ REFERRAL_KEY_USED: "REFERRAL_KEY_USED",
47
+ // Auth errors
48
+ INVALID_SIGNATURE: "INVALID_SIGNATURE",
49
+ NONCE_EXPIRED: "NONCE_EXPIRED",
50
+ UNAUTHORIZED: "UNAUTHORIZED",
51
+ // Service errors (graceful degradation)
52
+ RPC_UNAVAILABLE: "RPC_UNAVAILABLE",
53
+ CACHE_UNAVAILABLE: "CACHE_UNAVAILABLE",
54
+ DATABASE_UNAVAILABLE: "DATABASE_UNAVAILABLE",
55
+ // General errors
56
+ BAD_REQUEST: "BAD_REQUEST",
57
+ INTERNAL_ERROR: "INTERNAL_ERROR",
58
+ RATE_LIMITED: "RATE_LIMITED",
59
+ TIMEOUT: "TIMEOUT",
60
+ NETWORK_ERROR: "NETWORK_ERROR"
61
+ };
62
+ var ResonanceError = class _ResonanceError extends Error {
63
+ constructor(code, message, details, statusCode) {
54
64
  super(message);
55
- this.statusCode = statusCode;
65
+ this.name = "ResonanceError";
56
66
  this.code = code;
57
- this.name = "ResonanceAPIError";
58
- }
59
- };
60
-
61
- // src/client.ts
62
- var HTTPClient = class {
63
- constructor(config) {
64
- this.baseUrl = config.apiUrl.replace(/\/$/, "");
65
- this.timeout = config.timeout || 3e4;
66
- this.headers = {
67
- "Content-Type": "application/json",
68
- ...config.headers
69
- };
70
- }
71
- /**
72
- * Build URL with query parameters
73
- */
74
- buildUrl(path, params) {
75
- const url = new URL(`${this.baseUrl}${path}`);
76
- if (params) {
77
- Object.entries(params).forEach(([key, value]) => {
78
- if (value !== void 0 && value !== null) {
79
- url.searchParams.append(key, String(value));
80
- }
81
- });
67
+ this.details = details;
68
+ this.statusCode = statusCode;
69
+ if (Error.captureStackTrace) {
70
+ Error.captureStackTrace(this, _ResonanceError);
82
71
  }
83
- return url.toString();
84
72
  }
85
73
  /**
86
- * Set authorization token
74
+ * Check if this is a specific error code
87
75
  */
88
- setAuthToken(token) {
89
- if (token) {
90
- this.headers["Authorization"] = `Bearer ${token}`;
91
- } else {
92
- delete this.headers["Authorization"];
93
- }
76
+ is(code) {
77
+ return this.code === code;
94
78
  }
95
79
  /**
96
- * Set custom header
80
+ * Convert to JSON representation
97
81
  */
98
- setHeader(key, value) {
99
- this.headers[key] = value;
82
+ toJSON() {
83
+ return {
84
+ code: this.code,
85
+ message: this.message,
86
+ details: this.details
87
+ };
100
88
  }
101
- /**
102
- * Make HTTP GET request
103
- */
104
- async get(path, params) {
105
- const url = this.buildUrl(path, params);
106
- const controller = new AbortController();
107
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
108
- try {
109
- const response = await fetch(url, {
110
- method: "GET",
111
- headers: this.headers,
112
- signal: controller.signal
113
- });
114
- clearTimeout(timeoutId);
115
- if (!response.ok) {
116
- await this.handleError(response);
117
- }
118
- const json = await response.json();
119
- return json.data !== void 0 ? json.data : json;
120
- } catch (error) {
121
- if (error instanceof Error && error.name === "AbortError") {
122
- throw new Error(`Request timeout after ${this.timeout}ms`);
89
+ };
90
+ function isResonanceError(error) {
91
+ return error instanceof ResonanceError;
92
+ }
93
+ function hasErrorCode(error, code) {
94
+ return isResonanceError(error) && error.is(code);
95
+ }
96
+ function isNetworkError(error) {
97
+ if (isResonanceError(error)) {
98
+ return error.is(ErrorCode.RPC_UNAVAILABLE) || error.is(ErrorCode.CACHE_UNAVAILABLE) || error.is(ErrorCode.DATABASE_UNAVAILABLE);
99
+ }
100
+ return false;
101
+ }
102
+ function isAuthError(error) {
103
+ if (isResonanceError(error)) {
104
+ return error.is(ErrorCode.UNAUTHORIZED) || error.is(ErrorCode.INVALID_SIGNATURE) || error.is(ErrorCode.NONCE_EXPIRED);
105
+ }
106
+ return false;
107
+ }
108
+ function isNotFoundError(error) {
109
+ if (isResonanceError(error)) {
110
+ return error.is(ErrorCode.VALIDATOR_NOT_FOUND) || error.is(ErrorCode.DELEGATOR_NOT_FOUND);
111
+ }
112
+ return false;
113
+ }
114
+
115
+ // src/client.ts
116
+ var import_meta = {};
117
+ var DEFAULT_CONFIG = {
118
+ timeout: 3e4,
119
+ retries: 2,
120
+ retryDelay: 1e3
121
+ };
122
+ function validateConfig(config) {
123
+ if (config.timeout !== void 0 && (config.timeout < 0 || config.timeout > 3e5)) {
124
+ throw new Error("timeout must be between 0 and 300000ms (5 minutes)");
125
+ }
126
+ if (config.retries !== void 0 && (config.retries < 0 || config.retries > 5)) {
127
+ throw new Error("retries must be between 0 and 5");
128
+ }
129
+ if (config.retryDelay !== void 0 && (config.retryDelay < 0 || config.retryDelay > 1e4)) {
130
+ throw new Error("retryDelay must be between 0 and 10000ms");
131
+ }
132
+ if (config.baseUrl && !config.baseUrl.match(/^https?:\/\//)) {
133
+ throw new Error("baseUrl must start with http:// or https://");
134
+ }
135
+ }
136
+ var ENV_API_URL = "RESONANCE_API_URL";
137
+ var ENV_API_TOKEN = "RESONANCE_API_TOKEN";
138
+ function getEnv(key) {
139
+ if (typeof process !== "undefined" && process.env) {
140
+ return process.env[key];
141
+ }
142
+ if (typeof import_meta !== "undefined" && import_meta.env) {
143
+ return import_meta.env[`VITE_${key}`] || import_meta.env[`NEXT_PUBLIC_${key}`];
144
+ }
145
+ return void 0;
146
+ }
147
+ var ResonanceClient = class {
148
+ constructor(config = {}) {
149
+ validateConfig(config);
150
+ const defaultUrl = "http://localhost:8080";
151
+ const envUrl = getEnv(ENV_API_URL);
152
+ const baseUrl = config.baseUrl || envUrl || defaultUrl;
153
+ this.baseUrl = baseUrl.replace(/\/$/, "");
154
+ this.token = config.token || getEnv(ENV_API_TOKEN);
155
+ this.timeout = config.timeout ?? DEFAULT_CONFIG.timeout;
156
+ this.retries = config.retries ?? DEFAULT_CONFIG.retries;
157
+ this.retryDelay = config.retryDelay ?? DEFAULT_CONFIG.retryDelay;
158
+ this.onTokenExpired = config.onTokenExpired;
159
+ this.onRequest = config.onRequest;
160
+ this.onResponse = config.onResponse;
161
+ this.onError = config.onError;
162
+ }
163
+ // ============================================
164
+ // Helper Methods
165
+ // ============================================
166
+ setToken(token) {
167
+ this.token = token;
168
+ }
169
+ clearToken() {
170
+ this.token = void 0;
171
+ }
172
+ async request(path, options = {}) {
173
+ let lastError = null;
174
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
175
+ try {
176
+ return await this.executeRequest(path, options, attempt);
177
+ } catch (error) {
178
+ lastError = error;
179
+ if (error instanceof ResonanceError) {
180
+ if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {
181
+ throw error;
182
+ }
183
+ }
184
+ if (attempt >= this.retries) {
185
+ throw error;
186
+ }
187
+ const delay = this.retryDelay * Math.pow(2, attempt);
188
+ await new Promise((resolve) => setTimeout(resolve, delay));
123
189
  }
124
- throw error;
125
190
  }
191
+ throw lastError || new Error("Request failed");
126
192
  }
127
- /**
128
- * Make HTTP POST request
129
- */
130
- async post(path, body) {
131
- const url = this.buildUrl(path);
132
- const controller = new AbortController();
133
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
193
+ async executeRequest(path, options, attemptNumber) {
194
+ const startTime = Date.now();
195
+ const url = `${this.baseUrl}${path}`;
196
+ const headers = {
197
+ "Content-Type": "application/json",
198
+ ...options.headers
199
+ };
200
+ if (this.token) {
201
+ headers["Authorization"] = `Bearer ${this.token}`;
202
+ }
203
+ const requestContext = {
204
+ method: options.method || "GET",
205
+ url,
206
+ headers,
207
+ body: options.body,
208
+ timestamp: startTime,
209
+ attemptNumber
210
+ };
134
211
  try {
135
- const response = await fetch(url, {
136
- method: "POST",
137
- headers: this.headers,
138
- body: body ? JSON.stringify(body) : void 0,
139
- signal: controller.signal
140
- });
141
- clearTimeout(timeoutId);
142
- if (!response.ok) {
143
- await this.handleError(response);
144
- }
145
- const json = await response.json();
146
- return json.data !== void 0 ? json.data : json;
147
- } catch (error) {
148
- if (error instanceof Error && error.name === "AbortError") {
149
- throw new Error(`Request timeout after ${this.timeout}ms`);
150
- }
151
- throw error;
212
+ this.onRequest?.(requestContext);
213
+ } catch (hookError) {
214
+ console.error("onRequest hook error:", hookError);
152
215
  }
153
- }
154
- /**
155
- * Make HTTP DELETE request
156
- */
157
- async delete(path) {
158
- const url = this.buildUrl(path);
159
216
  const controller = new AbortController();
160
217
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
161
218
  try {
162
219
  const response = await fetch(url, {
163
- method: "DELETE",
164
- headers: this.headers,
220
+ ...options,
221
+ headers,
165
222
  signal: controller.signal
166
223
  });
167
224
  clearTimeout(timeoutId);
225
+ const duration = Date.now() - startTime;
226
+ if (response.status === 401) {
227
+ this.onTokenExpired?.();
228
+ }
168
229
  if (!response.ok) {
169
- await this.handleError(response);
230
+ const error = await response.json().catch(() => null);
231
+ const resonanceError = error && typeof error === "object" && "code" in error && "message" in error ? new ResonanceError(
232
+ error.code,
233
+ error.message,
234
+ error.details,
235
+ response.status
236
+ ) : new ResonanceError(
237
+ "INTERNAL_ERROR",
238
+ error?.error || `HTTP ${response.status}`,
239
+ void 0,
240
+ response.status
241
+ );
242
+ try {
243
+ this.onError?.(resonanceError, requestContext);
244
+ } catch (hookError) {
245
+ console.error("onError hook error:", hookError);
246
+ }
247
+ throw resonanceError;
170
248
  }
171
- const json = await response.json();
172
- return json.data !== void 0 ? json.data : json;
249
+ const data = await response.json();
250
+ const responseContext = {
251
+ ...requestContext,
252
+ status: response.status,
253
+ statusText: response.statusText,
254
+ duration,
255
+ data
256
+ };
257
+ try {
258
+ this.onResponse?.(responseContext);
259
+ } catch (hookError) {
260
+ console.error("onResponse hook error:", hookError);
261
+ }
262
+ return data;
173
263
  } catch (error) {
264
+ clearTimeout(timeoutId);
174
265
  if (error instanceof Error && error.name === "AbortError") {
175
- throw new Error(`Request timeout after ${this.timeout}ms`);
176
- }
177
- throw error;
178
- }
179
- }
180
- /**
181
- * Handle HTTP errors
182
- */
183
- async handleError(response) {
184
- let errorCode = "UNKNOWN_ERROR";
185
- let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
186
- try {
187
- const errorData = await response.json();
188
- if (errorData.error) {
189
- errorCode = errorData.error.code;
190
- errorMessage = errorData.error.message;
266
+ const timeoutError = new ResonanceError(
267
+ "TIMEOUT",
268
+ `Request timed out after ${this.timeout}ms`,
269
+ { url, timeout: this.timeout },
270
+ 408
271
+ );
272
+ try {
273
+ this.onError?.(timeoutError, requestContext);
274
+ } catch (hookError) {
275
+ console.error("onError hook error:", hookError);
276
+ }
277
+ throw timeoutError;
191
278
  }
192
- } catch {
193
- }
194
- throw new ResonanceAPIError(response.status, errorCode, errorMessage);
195
- }
196
- /*
197
- * Automatic Retry transient errors network
198
- */
199
- async fetchWithRetry(url, options, retries = 3) {
200
- for (let i = 0; i < retries; i++) {
201
- try {
202
- return await fetch(url, options);
203
- } catch (error) {
204
- if (i === retries - 1) throw error;
205
- await new Promise((resolve) => setTimeout(resolve, 1e3 * (i + 1)));
279
+ if (error instanceof Error) {
280
+ const networkError = error instanceof ResonanceError ? error : new ResonanceError("NETWORK_ERROR", error.message, void 0, 0);
281
+ try {
282
+ this.onError?.(networkError, requestContext);
283
+ } catch (hookError) {
284
+ console.error("onError hook error:", hookError);
285
+ }
286
+ throw networkError;
206
287
  }
288
+ throw error;
207
289
  }
208
- throw new Error("Max retries reached");
209
290
  }
210
- };
211
-
212
- // src/auth.ts
213
- var AuthService = class {
214
- constructor(apiUrl) {
215
- this.tokenKey = "resonance_jwt_token";
216
- this.apiUrl = apiUrl;
217
- }
218
- /**
219
- * Get nonce for wallet authentication
220
- * POST /eth/v1/auth/nonce
221
- */
291
+ // ============================================
292
+ // Auth
293
+ // ============================================
222
294
  async getNonce(address) {
223
- const response = await fetch(`${this.apiUrl}/eth/v1/auth/nonce`, {
224
- method: "POST",
225
- headers: { "Content-Type": "application/json" },
226
- body: JSON.stringify({ address })
227
- });
228
- if (!response.ok) {
229
- throw new Error("Failed to get nonce");
230
- }
231
- const result = await response.json();
232
- return result.data;
295
+ return this.request(`/eth/v1/auth/nonce?address=${address}`);
233
296
  }
234
- /**
235
- * Verify wallet signature and get JWT token
236
- * POST /eth/v1/auth/verify
237
- */
238
- async verify(params) {
239
- const response = await fetch(`${this.apiUrl}/eth/v1/auth/verify`, {
297
+ async verify(address, signature) {
298
+ const result = await this.request("/eth/v1/auth/verify", {
240
299
  method: "POST",
241
- headers: { "Content-Type": "application/json" },
242
- body: JSON.stringify(params)
300
+ body: JSON.stringify({ address, signature })
243
301
  });
244
- if (!response.ok) {
245
- throw new Error("Authentication failed");
246
- }
247
- const result = await response.json();
248
- const token = result.data.token;
249
- if (typeof window !== "undefined") {
250
- sessionStorage.setItem(this.tokenKey, token);
251
- }
252
- return { token };
302
+ this.token = result.token;
303
+ return result;
253
304
  }
254
- /**
255
- * Connect wallet and authenticate
256
- */
257
- async connectWallet(provider, role = "delegator") {
258
- const signer = await provider.getSigner();
259
- const address = await signer.getAddress();
260
- const timestamp = Math.floor(Date.now() / 1e3);
261
- const nonce = Math.floor(Math.random() * 1e6);
262
- const message = `Sign this message to login to Resonance Dashboard
263
-
264
- Address: ${address}
265
- Role: ${role}
266
- Nonce: ${nonce}
267
- Timestamp: ${timestamp}
268
-
269
- This will not trigger any blockchain transaction or cost gas fees.`;
270
- const signature = await signer.signMessage(message);
271
- const response = await fetch(`${this.apiUrl}/auth/login`, {
272
- method: "POST",
273
- headers: { "Content-Type": "application/json" },
274
- body: JSON.stringify({
275
- address,
276
- message,
277
- signature,
278
- role,
279
- timestamp,
280
- nonce
281
- })
282
- });
283
- if (!response.ok) {
284
- throw new Error("Authentication failed");
285
- }
286
- const data = await response.json();
287
- if (typeof window !== "undefined") {
288
- sessionStorage.setItem(this.tokenKey, data.token);
289
- }
290
- return data;
305
+ // ============================================
306
+ // Validators
307
+ // ============================================
308
+ async getValidators() {
309
+ return this.request("/eth/v1/validators");
291
310
  }
292
- /**
293
- * Get stored JWT token
294
- */
295
- getToken() {
296
- if (typeof window === "undefined") return null;
297
- return sessionStorage.getItem(this.tokenKey);
298
- }
299
- /**
300
- * Check if user is authenticated
301
- */
302
- isAuthenticated() {
303
- const token = this.getToken();
304
- if (!token) return false;
305
- try {
306
- const claims = this.parseToken(token);
307
- return claims.exp * 1e3 > Date.now();
308
- } catch {
309
- return false;
310
- }
311
- }
312
- /**
313
- * Parse JWT token to get claims
314
- */
315
- parseToken(token) {
316
- const payload = token.split(".")[1];
317
- const decoded = atob(payload);
318
- return JSON.parse(decoded);
319
- }
320
- /**
321
- * Get user info from token
322
- */
323
- getUserInfo() {
324
- const token = this.getToken();
325
- if (!token) return null;
326
- try {
327
- const claims = this.parseToken(token);
328
- return {
329
- address: claims.address,
330
- role: claims.role
331
- };
332
- } catch {
333
- return null;
334
- }
335
- }
336
- /**
337
- * Logout user
338
- */
339
- logout() {
340
- if (typeof window !== "undefined") {
341
- sessionStorage.removeItem(this.tokenKey);
342
- }
343
- }
344
- /**
345
- * Check if token is expiring soon (within 5 minutes)
346
- */
347
- isTokenExpiringSoon() {
348
- const token = this.getToken();
349
- if (!token) return true;
350
- try {
351
- const claims = this.parseToken(token);
352
- const expiresAt = claims.exp * 1e3;
353
- const fiveMinutes = 5 * 60 * 1e3;
354
- return expiresAt - Date.now() < fiveMinutes;
355
- } catch {
356
- return true;
357
- }
311
+ async getActiveValidators() {
312
+ return this.request("/eth/v1/validators/active");
358
313
  }
359
- };
360
-
361
- // src/validators.ts
362
- var ValidatorsAPI = class {
363
- constructor(client) {
364
- this.client = client;
314
+ async getCandidates() {
315
+ return this.request("/eth/v1/validators/candidates");
365
316
  }
366
- /**
367
- * Get all validators
368
- * GET /eth/v1/validators
369
- */
370
- async getAll() {
371
- return this.client.get("/eth/v1/validators");
317
+ async getValidator(address) {
318
+ return this.request(`/eth/v1/validators/${address}`);
372
319
  }
373
- /**
374
- * Get validator details
375
- * GET /eth/v1/validators/:address
376
- */
377
- async get(address) {
378
- return this.client.get(`/eth/v1/validators/${address}`);
320
+ async getValidatorDelegators(address) {
321
+ return this.request(`/eth/v1/validators/${address}/delegators`);
379
322
  }
380
- /**
381
- * Get validator delegators
382
- * GET /eth/v1/validators/:address/delegators
383
- */
384
- async getDelegators(address) {
385
- return this.client.get(`/eth/v1/validators/${address}/delegators`);
323
+ // ============================================
324
+ // Delegators
325
+ // ============================================
326
+ async getDelegator(address) {
327
+ return this.request(`/eth/v1/delegators/${address}`);
386
328
  }
387
- /**
388
- * Get validator stake breakdown
389
- * GET /eth/v1/validators/:address/stake
390
- */
391
- async getStakeBreakdown(address) {
392
- return this.client.get(`/eth/v1/validators/${address}/stake`);
329
+ async getDelegatorStakes(address) {
330
+ return this.request(`/eth/v1/delegators/${address}/stakes`);
393
331
  }
394
- /**
395
- * Get validator epoch details
396
- * GET /eth/v1/validators/:address/epochs/:epoch
397
- */
398
- async getEpoch(address, epoch) {
399
- return this.client.get(`/eth/v1/validators/${address}/epochs/${epoch}`);
332
+ async getDelegatorRewards(address) {
333
+ return this.request(`/eth/v1/delegators/${address}/rewards`);
400
334
  }
401
- /**
402
- * Get validator history
403
- * GET /eth/v1/validators/:address/history
404
- * @param address - Validator address
405
- * @param fromEpoch - Optional starting epoch
406
- * @param toEpoch - Optional ending epoch
407
- */
408
- async getHistory(address, fromEpoch, toEpoch) {
409
- const params = {};
410
- if (fromEpoch !== void 0) params.from_epoch = fromEpoch;
411
- if (toEpoch !== void 0) params.to_epoch = toEpoch;
412
- return this.client.get(
413
- `/eth/v1/validators/${address}/history`,
414
- params
415
- );
335
+ // ============================================
336
+ // Referral
337
+ // ============================================
338
+ async getReferralKey(key) {
339
+ return this.request(`/eth/v1/referral/key/${key}`);
416
340
  }
417
- /**
418
- * Get validator withdrawals
419
- * GET /eth/v1/validators/:address/withdrawals
420
- * @param address - Validator address
421
- * @param limit - Optional limit
422
- * @param offset - Optional offset
423
- */
424
- async getWithdrawals(address, limit, offset) {
425
- const params = {};
426
- if (limit !== void 0) params.limit = limit;
427
- if (offset !== void 0) params.offset = offset;
428
- return this.client.get(
429
- `/eth/v1/validators/${address}/withdrawals`,
430
- params
431
- );
341
+ async getValidatorKeys(address) {
342
+ return this.request(`/eth/v1/referral/validator/${address}`);
432
343
  }
433
- /**
434
- * Get validator metrics
435
- * GET /eth/v1/validators/:address/metrics
436
- */
437
- async getMetrics(address) {
438
- return this.client.get(`/eth/v1/validators/${address}/metrics`);
439
- }
440
- /**
441
- * Get validator slashing events
442
- * GET /eth/v1/validators/:address/slashing
443
- */
444
- async getSlashing(address) {
445
- return this.client.get(`/eth/v1/validators/${address}/slashing`);
446
- }
447
- /**
448
- * Get validator APR
449
- * GET /eth/v1/validators/:address/apr
450
- */
451
- async getAPR(address) {
452
- return this.client.get(`/eth/v1/validators/${address}/apr`);
453
- }
454
- };
455
-
456
- // src/delegators.ts
457
- var DelegatorsAPI = class {
458
- constructor(client) {
459
- this.client = client;
460
- }
461
- /**
462
- * Get all delegators
463
- * GET /eth/v1/delegators
464
- */
465
- async getAll() {
466
- return this.client.get("/eth/v1/delegators");
467
- }
468
- /**
469
- * Get delegator details
470
- * GET /eth/v1/delegators/:address
471
- */
472
- async get(address) {
473
- return this.client.get(`/eth/v1/delegators/${address}`);
474
- }
475
- /**
476
- * Get delegator stakes breakdown per validator
477
- * GET /eth/v1/delegators/:address/stakes
478
- */
479
- async getStakes(address) {
480
- return this.client.get(`/eth/v1/delegators/${address}/stakes`);
481
- }
482
- /**
483
- * Get delegator rewards history
484
- * GET /eth/v1/delegators/:address/rewards
485
- * @param address - Delegator address
486
- * @param limit - Optional limit
487
- * @param offset - Optional offset
488
- */
489
- async getRewards(address, limit, offset) {
490
- const params = {};
491
- if (limit !== void 0) params.limit = limit;
492
- if (offset !== void 0) params.offset = offset;
493
- return this.client.get(
494
- `/eth/v1/delegators/${address}/rewards`,
495
- params
496
- );
497
- }
498
- /**
499
- * Get delegator withdrawals history
500
- * GET /eth/v1/delegators/:address/withdrawals
501
- * @param address - Delegator address
502
- * @param limit - Optional limit
503
- * @param offset - Optional offset
504
- */
505
- async getWithdrawals(address, limit, offset) {
506
- const params = {};
507
- if (limit !== void 0) params.limit = limit;
508
- if (offset !== void 0) params.offset = offset;
509
- return this.client.get(
510
- `/eth/v1/delegators/${address}/withdrawals`,
511
- params
512
- );
513
- }
514
- /**
515
- * Get delegator unbonding status
516
- * GET /eth/v1/delegators/:address/unbonding
517
- */
518
- async getUnbonding(address) {
519
- return this.client.get(`/eth/v1/delegators/${address}/unbonding`);
520
- }
521
- /**
522
- * Get delegator active validators
523
- * GET /eth/v1/delegators/:address/validators
524
- */
525
- async getValidators(address) {
526
- return this.client.get(`/eth/v1/delegators/${address}/validators`);
527
- }
528
- };
529
-
530
- // src/referrals.ts
531
- var ReferralsAPI = class {
532
- constructor(client) {
533
- this.client = client;
534
- }
535
- /**
536
- * Validate a referral code
537
- * GET /eth/v1/referrals/validate?code=CODE
538
- */
539
- async validate(referralCode) {
540
- return this.client.get("/eth/v1/referrals/validate", {
541
- code: referralCode
344
+ async checkWhitelist(data) {
345
+ return this.request("/eth/v1/referral/whitelist", {
346
+ method: "POST",
347
+ body: JSON.stringify(data)
542
348
  });
543
349
  }
544
- /**
545
- * Create a new referral code
546
- * POST /eth/v1/referrals
547
- * @param request - Referral creation request
548
- */
549
- async create(request) {
550
- return this.client.post("/eth/v1/referrals", request);
350
+ // ============================================
351
+ // Geo
352
+ // ============================================
353
+ async getGeoNodes() {
354
+ return this.request("/eth/v1/geo/nodes");
551
355
  }
552
- /**
553
- * Apply a referral code
554
- * POST /eth/v1/referrals/apply
555
- * @param request - Referral application request
556
- */
557
- async apply(request) {
558
- return this.client.post("/eth/v1/referrals/apply", request);
559
- }
560
- /**
561
- * Delete a referral code
562
- * DELETE /eth/v1/referrals/:referral_code
563
- * @param referralCode - The referral code to delete
564
- */
565
- async delete(referralCode) {
566
- return this.client.delete(`/eth/v1/referrals/${referralCode}`);
567
- }
568
- /**
569
- * Unlink a delegator from referral
570
- * DELETE /eth/v1/referrals/unlink/:delegator_address
571
- * @param delegatorAddress - The delegator address to unlink
572
- */
573
- async unlink(delegatorAddress) {
574
- return this.client.delete(`/eth/v1/referrals/unlink/${delegatorAddress}`);
575
- }
576
- /**
577
- * Get delegator referral information
578
- * GET /eth/v1/referrals/delegators/:delegator_address
579
- */
580
- async getDelegatorReferral(delegatorAddress) {
581
- return this.client.get(
582
- `/eth/v1/referrals/delegators/${delegatorAddress}`
583
- );
356
+ async getGeoValidators() {
357
+ return this.request("/eth/v1/geo/validators");
584
358
  }
585
- /**
586
- * Get validator referral information
587
- * GET /eth/v1/referrals/validators/:validator_address
588
- */
589
- async getValidatorReferral(validatorAddress) {
590
- return this.client.get(
591
- `/eth/v1/referrals/validators/${validatorAddress}`
592
- );
359
+ async getGeoStats() {
360
+ return this.request("/eth/v1/geo/stats");
593
361
  }
594
- };
595
-
596
- // src/global.ts
597
- var GlobalAPI = class {
598
- constructor(client) {
599
- this.client = client;
362
+ async updateGeoLocation(data) {
363
+ return this.request("/eth/v1/geo/update", {
364
+ method: "POST",
365
+ body: JSON.stringify(data)
366
+ });
600
367
  }
601
- /**
602
- * Get global network statistics
603
- * GET /eth/v1/global
604
- */
605
- async getStats() {
606
- return this.client.get("/eth/v1/global");
368
+ // ============================================
369
+ // Stats
370
+ // ============================================
371
+ async getNetworkStats() {
372
+ return this.request("/eth/v1/stats/network");
607
373
  }
608
- /**
609
- * Get network APR (from /global endpoint)
610
- * GET /eth/v1/global/network_apr
611
- */
612
- async getNetworkAPRFromGlobal() {
613
- return this.client.get("/eth/v1/global/network_apr");
374
+ async getCurrentEpoch() {
375
+ return this.request("/eth/v1/stats/epoch/current");
614
376
  }
615
- /**
616
- * Get network APR (from /network endpoint)
617
- * GET /eth/v1/network/apr
618
- */
377
+ // ============================================
378
+ // APR
379
+ // ============================================
619
380
  async getNetworkAPR() {
620
- return this.client.get("/eth/v1/network/apr");
621
- }
622
- /**
623
- * Get network APR breakdown
624
- * GET /eth/v1/network/apr/breakdown
625
- */
626
- async getNetworkAPRBreakdown() {
627
- return this.client.get("/eth/v1/network/apr/breakdown");
628
- }
629
- /**
630
- * Get delegator leaderboard
631
- * GET /eth/v1/leaderboard/delegators
632
- * @param limit - Optional limit (default backend value)
633
- * @param offset - Optional offset for pagination
634
- */
635
- async getLeaderboardDelegators(limit, offset) {
636
- const params = {};
637
- if (limit !== void 0) params.limit = limit;
638
- if (offset !== void 0) params.offset = offset;
639
- return this.client.get(
640
- "/eth/v1/leaderboard/delegators",
641
- params
642
- );
643
- }
644
- /**
645
- * Get validator leaderboard
646
- * GET /eth/v1/leaderboard/validators
647
- * @param limit - Optional limit (default backend value)
648
- * @param offset - Optional offset for pagination
649
- */
650
- async getLeaderboardValidators(limit, offset) {
651
- const params = {};
652
- if (limit !== void 0) params.limit = limit;
653
- if (offset !== void 0) params.offset = offset;
654
- return this.client.get(
655
- "/eth/v1/leaderboard/validators",
656
- params
657
- );
658
- }
659
- };
660
-
661
- // src/slashing.ts
662
- var SlashingAPI = class {
663
- constructor(client) {
664
- this.client = client;
665
- }
666
- /**
667
- * Get slashing events
668
- * GET /eth/v1/slashing/events
669
- * @param validatorAddress - Optional validator address filter
670
- * @param limit - Optional limit
671
- * @param offset - Optional offset
672
- */
673
- async getEvents(validatorAddress, limit, offset) {
674
- const params = {};
675
- if (validatorAddress) params.validator_address = validatorAddress;
676
- if (limit !== void 0) params.limit = limit;
677
- if (offset !== void 0) params.offset = offset;
678
- return this.client.get("/eth/v1/slashing/events", params);
679
- }
680
- };
681
-
682
- // src/modules/analytics.ts
683
- var AnalyticsAPI = class {
684
- constructor(client) {
685
- this.basePath = "/eth/v1/analytics";
686
- this.client = client;
687
- }
688
- /**
689
- * Get protocol-level statistics
690
- *
691
- * Returns aggregated statistics about the entire protocol including
692
- * total staking, validator counts, and rewards distribution.
693
- *
694
- * @returns Protocol statistics from subgraph
695
- *
696
- * @example
697
- * ```typescript
698
- * const stats = await sdk.analytics.getProtocolStats();
699
- * console.log(`Total Staking: ${stats.TotalStaking}`);
700
- * console.log(`Active Validators: ${stats.ActiveValidators}`);
701
- * ```
702
- */
703
- async getProtocolStats() {
704
- return this.client.get(`${this.basePath}/protocol`);
705
- }
706
- /**
707
- * Get sync status of analytics workers
708
- *
709
- * Returns the current synchronization status of background workers
710
- * that index blockchain data into the analytics database.
711
- *
712
- * @returns Sync status for each worker
713
- *
714
- * @example
715
- * ```typescript
716
- * const status = await sdk.analytics.getSyncStatus();
717
- * if (status.protocol_sync.status === 'success') {
718
- * console.log(`Last synced at block: ${status.protocol_sync.last_block}`);
719
- * }
720
- * ```
721
- */
722
- async getSyncStatus() {
723
- return this.client.get(`${this.basePath}/sync-status`);
724
- }
725
- /**
726
- * Get all validators with analytics data
727
- *
728
- * Returns a paginated list of validators with their analytics metrics
729
- * including uptime, signed blocks, and staker counts.
730
- *
731
- * @param options - Pagination and filter options
732
- * @returns Paginated list of validators
733
- *
734
- * @example
735
- * ```typescript
736
- * // Get first 20 validators
737
- * const result = await sdk.analytics.getAllValidators({ limit: 20 });
738
- *
739
- * // Get next page
740
- * const nextPage = await sdk.analytics.getAllValidators({
741
- * limit: 20,
742
- * offset: 20
743
- * });
744
- *
745
- * // Filter by status
746
- * const active = await sdk.analytics.getAllValidators({
747
- * status: 'active',
748
- * limit: 50
749
- * });
750
- * ```
751
- */
752
- async getAllValidators(options) {
753
- const params = {};
754
- if (options?.limit) params.limit = options.limit;
755
- if (options?.offset) params.offset = options.offset;
756
- if (options?.status) params.status = options.status;
757
- const response = await this.client.get(
758
- `${this.basePath}/validators`,
759
- params
760
- );
761
- if (Array.isArray(response)) {
762
- return {
763
- count: response.length,
764
- data: response
765
- };
381
+ return this.request("/eth/v1/apr/network");
382
+ }
383
+ async getValidatorAPR(address) {
384
+ return this.request(`/eth/v1/apr/validator/${address}`);
385
+ }
386
+ // ============================================
387
+ // Storage
388
+ // ============================================
389
+ async uploadAvatar(file) {
390
+ const formData = new FormData();
391
+ formData.append("file", file);
392
+ const headers = {};
393
+ if (this.token) {
394
+ headers["Authorization"] = `Bearer ${this.token}`;
766
395
  }
767
- return response;
768
- }
769
- /**
770
- * Get top validators by uptime
771
- *
772
- * Returns validators sorted by uptime percentage in descending order.
773
- * Useful for displaying leaderboards or finding most reliable validators.
774
- *
775
- * @param limit - Maximum number of validators to return (default: 10)
776
- * @returns Top validators by uptime
777
- *
778
- * @example
779
- * ```typescript
780
- * // Get top 5 validators
781
- * const top5 = await sdk.analytics.getTopValidators(5);
782
- *
783
- * top5.data.forEach((validator, index) => {
784
- * console.log(`#${index + 1}: ${validator.moniker} - ${validator.uptime}% uptime`);
785
- * });
786
- * ```
787
- */
788
- async getTopValidators(limit = 10) {
789
- const response = await this.client.get(
790
- `${this.basePath}/validators/top`,
791
- { limit }
792
- );
793
- if (Array.isArray(response)) {
794
- return {
795
- count: response.length,
796
- data: response
797
- };
396
+ const response = await fetch(`${this.baseUrl}/eth/v1/storage/avatar`, {
397
+ method: "POST",
398
+ headers,
399
+ body: formData
400
+ });
401
+ if (!response.ok) {
402
+ const error = await response.json().catch(() => ({ error: "Upload failed" }));
403
+ throw new Error(error.error);
798
404
  }
799
- return response;
405
+ return response.json();
800
406
  }
801
- /**
802
- * Get analytics data for a specific validator
803
- *
804
- * Returns detailed analytics metrics for a single validator including
805
- * performance statistics and current status.
806
- *
807
- * @param address - Validator address (with or without 0x prefix)
808
- * @returns Validator analytics data
809
- *
810
- * @throws {ResonanceAPIError} 404 if validator not found
811
- *
812
- * @example
813
- * ```typescript
814
- * const validator = await sdk.analytics.getValidatorAnalytics('0x1234...');
815
- * console.log(`${validator.moniker}: ${validator.uptime}% uptime`);
816
- * console.log(`Signed: ${validator.signed_blocks}, Missed: ${validator.missed_blocks}`);
817
- * ```
818
- */
819
- async getValidatorAnalytics(address) {
820
- const cleanAddress = address.toLowerCase().replace(/^0x/, "");
821
- return this.client.get(
822
- `${this.basePath}/validators/0x${cleanAddress}`
823
- );
407
+ async getAvatar(address) {
408
+ return this.request(`/eth/v1/storage/avatar/${address}`);
824
409
  }
825
- /**
826
- * Get validator rewards with pagination
827
- *
828
- * Returns detailed reward and stake information for a validator.
829
- * This is a heavy endpoint that MUST use pagination.
830
- *
831
- * @param address - Validator address (with or without 0x prefix)
832
- * @param options - Pagination options (required)
833
- * @returns Validator rewards, stakes, and summary
834
- *
835
- * @throws {ResonanceAPIError} 404 if validator not found
836
- *
837
- * @remarks
838
- * This endpoint can return large amounts of data. Always use pagination
839
- * with reasonable limit values (recommended: 50-100).
840
- *
841
- * @example
842
- * ```typescript
843
- * // Get first page of rewards
844
- * const page1 = await sdk.analytics.getValidatorRewards('0x1234...', {
845
- * limit: 50,
846
- * offset: 0
847
- * });
848
- *
849
- * console.log(`Total stakers: ${page1.summary.total_stakers}`);
850
- * console.log(`Has more data: ${page1.metadata.has_more}`);
851
- *
852
- * // Get next page if available
853
- * if (page1.metadata.has_more) {
854
- * const page2 = await sdk.analytics.getValidatorRewards('0x1234...', {
855
- * limit: 50,
856
- * offset: 50
857
- * });
858
- * }
859
- * ```
860
- */
861
- async getValidatorRewards(address, options) {
862
- const cleanAddress = address.toLowerCase().replace(/^0x/, "");
863
- const limit = options.limit || 50;
864
- const offset = options.offset || 0;
865
- return this.client.get(
866
- `${this.basePath}/validators/0x${cleanAddress}/rewards`,
867
- { limit, offset }
868
- );
410
+ // ============================================
411
+ // Analytics
412
+ // ============================================
413
+ async getDailyBlockStats(days = 7) {
414
+ return this.request(`/eth/v1/analytics/blocks?days=${days}`);
869
415
  }
870
- /**
871
- * Get all validator rewards with automatic pagination
872
- *
873
- * Automatically fetches all pages of validator rewards data.
874
- * Use with caution as this can make multiple API calls.
875
- *
876
- * @param address - Validator address (with or without 0x prefix)
877
- * @param options - Batch size and safety limits
878
- * @returns Complete validator rewards data
879
- *
880
- * @throws {ResonanceAPIError} 404 if validator not found
881
- * @throws {Error} If max pages limit is reached
882
- *
883
- * @remarks
884
- * This method will make multiple API calls. Use maxPages to prevent
885
- * infinite loops or excessive API usage.
886
- *
887
- * @example
888
- * ```typescript
889
- * // Fetch all rewards with default settings
890
- * const allRewards = await sdk.analytics.getAllValidatorRewards('0x1234...');
891
- *
892
- * // Custom batch size and limit
893
- * const rewards = await sdk.analytics.getAllValidatorRewards('0x1234...', {
894
- * batchSize: 100,
895
- * maxPages: 5
896
- * });
897
- *
898
- * console.log(`Total rewards: ${rewards.summary.total_rewards}`);
899
- * console.log(`Total API calls made: ${Math.ceil(rewards.stakes.length / 100)}`);
900
- * ```
901
- */
902
- async getAllValidatorRewards(address, options) {
903
- const batchSize = options?.batchSize || 50;
904
- const maxPages = options?.maxPages || 10;
905
- let offset = 0;
906
- let page = 0;
907
- let firstResponse = null;
908
- const allRewards = [];
909
- const allStakes = [];
910
- while (page < maxPages) {
911
- const response = await this.getValidatorRewards(address, {
912
- limit: batchSize,
913
- offset
914
- });
915
- if (!firstResponse) {
916
- firstResponse = response;
917
- }
918
- allRewards.push(...response.rewards);
919
- allStakes.push(...response.stakes);
920
- if (!response.metadata.has_more) {
921
- break;
922
- }
923
- offset += batchSize;
924
- page++;
925
- }
926
- if (page >= maxPages && firstResponse?.metadata.has_more) {
927
- throw new Error(
928
- `Reached maximum page limit (${maxPages}). Use manual pagination for more control.`
929
- );
930
- }
931
- return {
932
- ...firstResponse,
933
- rewards: allRewards,
934
- stakes: allStakes,
935
- metadata: {
936
- ...firstResponse.metadata,
937
- has_more: false,
938
- limit: allRewards.length,
939
- offset: 0
940
- }
941
- };
416
+ async getValidatorRewardHistory(address, limit = 100) {
417
+ return this.request(`/eth/v1/analytics/rewards/${address}?limit=${limit}`);
942
418
  }
943
419
  };
944
-
945
- // src/utils/analytics-helpers.ts
946
- function isValidatorNotFound(error) {
947
- return error instanceof ResonanceAPIError && error.statusCode === 404;
948
- }
949
- function isServiceUnavailable(error) {
950
- return error instanceof ResonanceAPIError && error.statusCode === 503;
951
- }
952
- function isTimeout(error) {
953
- return error instanceof Error && error.message.includes("timeout");
954
- }
955
- function isStaleData(response) {
956
- return response.metadata?.stale === true;
957
- }
958
- function isCachedData(response) {
959
- return response.metadata?.cached === true;
960
- }
961
- function isSyncHealthy(syncStatus, workerName = "protocol_sync") {
962
- const worker = syncStatus[workerName];
963
- return worker?.status === "success";
964
- }
965
- function isSyncDegraded(syncStatus, workerName = "protocol_sync") {
966
- const worker = syncStatus[workerName];
967
- return worker?.status === "degraded";
968
- }
969
- function getSyncLag(syncStatus, currentBlock, workerName = "protocol_sync") {
970
- const worker = syncStatus[workerName];
971
- if (!worker?.last_block) return null;
972
- return currentBlock - worker.last_block;
973
- }
974
- function getDataFreshness(response, currentBlock) {
975
- const subgraphBlock = response.metadata?.subgraph_block;
976
- if (!subgraphBlock) return 0;
977
- const blocksBehind = currentBlock - subgraphBlock;
978
- if (blocksBehind <= 0) return 100;
979
- if (blocksBehind <= 10) return 100 - blocksBehind;
980
- if (blocksBehind <= 100) return 90 - Math.floor((blocksBehind - 10) * 0.44);
981
- return Math.max(0, 50 - Math.floor((blocksBehind - 100) * 0.5));
420
+ function createResonanceClient(config) {
421
+ return new ResonanceClient(config);
982
422
  }
983
- function validatePagination(limit, offset) {
984
- if (limit !== void 0 && (limit <= 0 || limit > 1e3)) {
985
- throw new Error("Limit must be between 1 and 1000");
986
- }
987
- if (offset !== void 0 && offset < 0) {
988
- throw new Error("Offset must be non-negative");
989
- }
990
- }
991
- function getOptimalBatchSize(totalItems, maxBatchSize = 100) {
992
- if (totalItems <= maxBatchSize) return totalItems;
993
- const targetBatches = 7;
994
- const calculatedSize = Math.ceil(totalItems / targetBatches);
995
- return Math.min(calculatedSize, maxBatchSize);
996
- }
997
- function formatNumber(value) {
998
- const num = typeof value === "string" ? value : value.toString();
999
- return num.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1000
- }
1001
- function weiToEther(wei, decimals = 4) {
1002
- const weiNum = BigInt(wei);
1003
- const etherNum = Number(weiNum) / 1e18;
1004
- return etherNum.toFixed(decimals);
1005
- }
1006
-
1007
- // src/utils/retry.ts
1008
- function defaultShouldRetry(error, attempt) {
1009
- if (attempt >= 3) return false;
1010
- if (error instanceof Error && error.message.includes("timeout")) {
1011
- return true;
1012
- }
1013
- if (error.statusCode === 503) {
1014
- return true;
1015
- }
1016
- if (error instanceof Error && error.message.includes("fetch failed")) {
1017
- return true;
1018
- }
1019
- return false;
1020
- }
1021
- async function withRetry(fn, options = {}) {
1022
- const {
1023
- maxRetries = 3,
1024
- initialDelay = 1e3,
1025
- maxDelay = 1e4,
1026
- backoffMultiplier = 2,
1027
- shouldRetry = defaultShouldRetry,
1028
- onRetry
1029
- } = options;
1030
- let lastError;
1031
- let delay = initialDelay;
1032
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
1033
- try {
1034
- return await fn();
1035
- } catch (error) {
1036
- lastError = error;
1037
- if (attempt < maxRetries && shouldRetry(error, attempt)) {
1038
- if (onRetry) {
1039
- onRetry(error, attempt + 1, delay);
1040
- }
1041
- await sleep(delay);
1042
- delay = Math.min(delay * backoffMultiplier, maxDelay);
1043
- } else {
1044
- throw error;
1045
- }
1046
- }
1047
- }
1048
- throw lastError;
1049
- }
1050
- function sleep(ms) {
1051
- return new Promise((resolve) => setTimeout(resolve, ms));
1052
- }
1053
- function createRetryWrapper(fn, options = {}) {
1054
- return ((...args) => {
1055
- return withRetry(() => fn(...args), options);
1056
- });
1057
- }
1058
-
1059
- // src/index.ts
1060
- var ResonanceSDK = class {
1061
- constructor(config) {
1062
- this.client = new HTTPClient(config);
1063
- this.auth = new AuthService(config.apiUrl);
1064
- this.validators = new ValidatorsAPI(this.client);
1065
- this.delegators = new DelegatorsAPI(this.client);
1066
- this.referrals = new ReferralsAPI(this.client);
1067
- this.global = new GlobalAPI(this.client);
1068
- this.slashing = new SlashingAPI(this.client);
1069
- this.analytics = new AnalyticsAPI(this.client);
1070
- }
1071
- /**
1072
- * Set authentication token for API requests
1073
- * @param token - JWT token
1074
- */
1075
- setAuthToken(token) {
1076
- this.client.setAuthToken(token);
1077
- }
1078
- /**
1079
- * Set custom header for API requests
1080
- * @param key - Header key
1081
- * @param value - Header value
1082
- */
1083
- setHeader(key, value) {
1084
- this.client.setHeader(key, value);
1085
- }
1086
- /**
1087
- * Get the current auth token from storage
1088
- */
1089
- getAuthToken() {
1090
- return this.auth.getToken();
1091
- }
1092
- /**
1093
- * Check if user is authenticated
1094
- */
1095
- isAuthenticated() {
1096
- return this.auth.isAuthenticated();
1097
- }
1098
- /**
1099
- * Logout user and clear auth token
1100
- */
1101
- logout() {
1102
- this.auth.logout();
1103
- this.client.setAuthToken(null);
1104
- }
1105
- };
1106
- var index_default = ResonanceSDK;
1107
423
  // Annotate the CommonJS export names for ESM import in node:
1108
424
  0 && (module.exports = {
1109
- AnalyticsAPI,
1110
- AuthService,
1111
- DelegatorsAPI,
1112
- GlobalAPI,
1113
- HTTPClient,
1114
- ReferralsAPI,
1115
- ResonanceSDK,
1116
- SlashingAPI,
1117
- ValidatorsAPI,
1118
- createRetryWrapper,
1119
- formatNumber,
1120
- getDataFreshness,
1121
- getOptimalBatchSize,
1122
- getSyncLag,
1123
- isCachedData,
1124
- isServiceUnavailable,
1125
- isStaleData,
1126
- isSyncDegraded,
1127
- isSyncHealthy,
1128
- isTimeout,
1129
- isValidatorNotFound,
1130
- validatePagination,
1131
- weiToEther,
1132
- withRetry
425
+ ErrorCode,
426
+ ResonanceClient,
427
+ ResonanceError,
428
+ createResonanceClient,
429
+ hasErrorCode,
430
+ isAuthError,
431
+ isNetworkError,
432
+ isNotFoundError,
433
+ isResonanceError
1133
434
  });