@fenelabs/fene-sdk 0.2.0 → 0.3.2
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/CHANGELOG.md +24 -0
- package/README.md +75 -19
- package/dist/index.d.mts +311 -1
- package/dist/index.d.ts +311 -1
- package/dist/index.js +146 -2
- package/dist/index.mjs +130 -1
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to the Resonance SDK will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.1] - 2025-12-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
#### Analytics Helper Utilities
|
|
13
|
+
- **Error handling helpers**: `isValidatorNotFound()`, `isServiceUnavailable()`, `isTimeout()`
|
|
14
|
+
- **Data validation helpers**: `isStaleData()`, `isCachedData()`, `validatePagination()`
|
|
15
|
+
- **Sync monitoring helpers**: `isSyncHealthy()`, `isSyncDegraded()`, `getSyncLag()`
|
|
16
|
+
- **Data freshness**: `getDataFreshness()` - Calculate freshness score (0-100)
|
|
17
|
+
- **Number formatting**: `formatNumber()`, `weiToEther()` - Format large numbers
|
|
18
|
+
- **Batch optimization**: `getOptimalBatchSize()` - Calculate optimal pagination size
|
|
19
|
+
|
|
20
|
+
#### Retry Logic
|
|
21
|
+
- **`withRetry()`** - Execute functions with automatic retry on transient errors
|
|
22
|
+
- **`createRetryWrapper()`** - Create retry-wrapped versions of functions
|
|
23
|
+
- Configurable retry options: max retries, backoff, custom predicates
|
|
24
|
+
- Built-in retry for timeout and 503 errors
|
|
25
|
+
- Exponential backoff with max delay cap
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Enhanced README with utility function documentation
|
|
29
|
+
- Added `examples/analytics-advanced.ts` with advanced usage patterns
|
|
30
|
+
- Improved error handling examples
|
|
31
|
+
|
|
8
32
|
## [0.2.0] - 2025-12-10
|
|
9
33
|
|
|
10
34
|
### Added
|
package/README.md
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Fene Network SDK
|
|
2
2
|
|
|
3
|
-
Official TypeScript/JavaScript SDK for interacting with the
|
|
3
|
+
Official TypeScript/JavaScript SDK for interacting with the Fene Network API.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @
|
|
8
|
+
npm install @fenelabs/fene-sdk
|
|
9
9
|
# or
|
|
10
|
-
yarn add @
|
|
10
|
+
yarn add @fenelabs/fene-sdk
|
|
11
11
|
# or
|
|
12
|
-
pnpm add @
|
|
12
|
+
pnpm add @fenelabs/fene-sdk
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
|
-
import { ResonanceSDK } from '@
|
|
18
|
+
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
19
19
|
|
|
20
20
|
// Initialize the SDK
|
|
21
21
|
const sdk = new ResonanceSDK({
|
|
22
|
-
apiUrl: 'https://api.
|
|
22
|
+
apiUrl: 'https://api.fene.network',
|
|
23
23
|
timeout: 30000, // Optional, default 30s
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -38,10 +38,10 @@ The SDK supports wallet-based authentication using Web3 providers:
|
|
|
38
38
|
|
|
39
39
|
```typescript
|
|
40
40
|
import { ethers } from 'ethers';
|
|
41
|
-
import { ResonanceSDK } from '@
|
|
41
|
+
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
42
42
|
|
|
43
43
|
const sdk = new ResonanceSDK({
|
|
44
|
-
apiUrl: 'https://api.
|
|
44
|
+
apiUrl: 'https://api.fene.network',
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
// Connect wallet (browser environment)
|
|
@@ -249,13 +249,69 @@ console.log('Total Stakes Fetched:', allRewards.stakes.length);
|
|
|
249
249
|
- The rewards endpoint is heavy and **requires pagination** - never fetch without limit/offset
|
|
250
250
|
- Use `getSyncStatus()` to verify data freshness before making critical decisions
|
|
251
251
|
|
|
252
|
+
### Analytics Helper Utilities
|
|
253
|
+
|
|
254
|
+
The SDK provides utility functions for working with analytics data:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import {
|
|
258
|
+
isValidatorNotFound,
|
|
259
|
+
isStaleData,
|
|
260
|
+
isCachedData,
|
|
261
|
+
isSyncHealthy,
|
|
262
|
+
getSyncLag,
|
|
263
|
+
getDataFreshness,
|
|
264
|
+
formatNumber,
|
|
265
|
+
weiToEther,
|
|
266
|
+
withRetry,
|
|
267
|
+
} from '@avenbreaks/resonance-sdk';
|
|
268
|
+
|
|
269
|
+
// Error handling
|
|
270
|
+
try {
|
|
271
|
+
const validator = await sdk.analytics.getValidatorAnalytics(address);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if (isValidatorNotFound(error)) {
|
|
274
|
+
console.log('Validator does not exist');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Data freshness validation
|
|
279
|
+
const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
280
|
+
if (isStaleData(rewards)) {
|
|
281
|
+
console.warn('Data may be outdated');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Sync health monitoring
|
|
285
|
+
const syncStatus = await sdk.analytics.getSyncStatus();
|
|
286
|
+
if (isSyncHealthy(syncStatus, 'protocol_sync')) {
|
|
287
|
+
console.log('Sync is healthy');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Retry logic for heavy queries
|
|
291
|
+
const rewardsWithRetry = await withRetry(
|
|
292
|
+
() => sdk.analytics.getValidatorRewards(address, { limit: 100 }),
|
|
293
|
+
{
|
|
294
|
+
maxRetries: 3,
|
|
295
|
+
initialDelay: 1000,
|
|
296
|
+
onRetry: (error, attempt, delay) => {
|
|
297
|
+
console.log(`Retry ${attempt} after ${delay}ms`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
// Number formatting
|
|
303
|
+
const stats = await sdk.analytics.getProtocolStats();
|
|
304
|
+
console.log(formatNumber(stats.TotalStaking)); // "26,883,345,073,055,930,973,683,712"
|
|
305
|
+
console.log(weiToEther(stats.TotalStaking)); // "26883345.0730"
|
|
306
|
+
```
|
|
307
|
+
|
|
252
308
|
## Advanced Usage
|
|
253
309
|
|
|
254
310
|
### Custom Headers
|
|
255
311
|
|
|
256
312
|
```typescript
|
|
257
313
|
const sdk = new ResonanceSDK({
|
|
258
|
-
apiUrl: 'https://api.
|
|
314
|
+
apiUrl: 'https://api.fene.network',
|
|
259
315
|
headers: {
|
|
260
316
|
'X-Custom-Header': 'value',
|
|
261
317
|
},
|
|
@@ -281,7 +337,7 @@ try {
|
|
|
281
337
|
|
|
282
338
|
```typescript
|
|
283
339
|
const sdk = new ResonanceSDK({
|
|
284
|
-
apiUrl: 'https://api.
|
|
340
|
+
apiUrl: 'https://api.fene.network',
|
|
285
341
|
timeout: 60000, // 60 seconds
|
|
286
342
|
});
|
|
287
343
|
```
|
|
@@ -295,7 +351,7 @@ import type {
|
|
|
295
351
|
ValidatorDetailResponse,
|
|
296
352
|
DelegatorDetailResponse,
|
|
297
353
|
GlobalNetworkResponse,
|
|
298
|
-
} from '@
|
|
354
|
+
} from '@fenelabs/fene-sdk';
|
|
299
355
|
|
|
300
356
|
const processValidator = (validator: ValidatorDetailResponse) => {
|
|
301
357
|
console.log(validator.validator_address);
|
|
@@ -307,10 +363,10 @@ const processValidator = (validator: ValidatorDetailResponse) => {
|
|
|
307
363
|
|
|
308
364
|
```typescript
|
|
309
365
|
import { useEffect, useState } from 'react';
|
|
310
|
-
import { ResonanceSDK } from '@
|
|
366
|
+
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
311
367
|
|
|
312
368
|
const sdk = new ResonanceSDK({
|
|
313
|
-
apiUrl: 'https://api.
|
|
369
|
+
apiUrl: 'https://api.fene.network',
|
|
314
370
|
});
|
|
315
371
|
|
|
316
372
|
function ValidatorList() {
|
|
@@ -348,10 +404,10 @@ function ValidatorList() {
|
|
|
348
404
|
|
|
349
405
|
```typescript
|
|
350
406
|
// app/page.tsx
|
|
351
|
-
import { ResonanceSDK } from '@
|
|
407
|
+
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
352
408
|
|
|
353
409
|
const sdk = new ResonanceSDK({
|
|
354
|
-
apiUrl: process.env.NEXT_PUBLIC_API_URL || 'https://api.
|
|
410
|
+
apiUrl: process.env.NEXT_PUBLIC_API_URL || 'https://api.fene.network',
|
|
355
411
|
});
|
|
356
412
|
|
|
357
413
|
export default async function HomePage() {
|
|
@@ -371,10 +427,10 @@ export default async function HomePage() {
|
|
|
371
427
|
## Node.js Example
|
|
372
428
|
|
|
373
429
|
```typescript
|
|
374
|
-
import { ResonanceSDK } from '@
|
|
430
|
+
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
375
431
|
|
|
376
432
|
const sdk = new ResonanceSDK({
|
|
377
|
-
apiUrl: 'https://api.
|
|
433
|
+
apiUrl: 'https://api.fene.network',
|
|
378
434
|
});
|
|
379
435
|
|
|
380
436
|
async function main() {
|
|
@@ -425,5 +481,5 @@ MIT
|
|
|
425
481
|
## Support
|
|
426
482
|
|
|
427
483
|
For issues and questions, please visit:
|
|
428
|
-
- GitHub Issues: https://github.com/fenelabs/sdk/issues
|
|
484
|
+
- GitHub Issues: https://github.com/fenelabs/fene-sdk/issues
|
|
429
485
|
- Documentation: https://docs.fene.network
|
package/dist/index.d.mts
CHANGED
|
@@ -875,6 +875,316 @@ declare class AnalyticsAPI {
|
|
|
875
875
|
}): Promise<ValidatorRewardsResponse>;
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
+
/**
|
|
879
|
+
* Analytics Helper Utilities
|
|
880
|
+
*
|
|
881
|
+
* Provides utility functions for working with analytics data,
|
|
882
|
+
* including error checking, data validation, and freshness checks.
|
|
883
|
+
*/
|
|
884
|
+
/**
|
|
885
|
+
* Check if error is a validator not found error
|
|
886
|
+
*
|
|
887
|
+
* @param error - Error object to check
|
|
888
|
+
* @returns True if validator was not found
|
|
889
|
+
*
|
|
890
|
+
* @example
|
|
891
|
+
* ```typescript
|
|
892
|
+
* try {
|
|
893
|
+
* const validator = await sdk.analytics.getValidatorAnalytics(address);
|
|
894
|
+
* } catch (error) {
|
|
895
|
+
* if (isValidatorNotFound(error)) {
|
|
896
|
+
* console.log('Validator does not exist');
|
|
897
|
+
* }
|
|
898
|
+
* }
|
|
899
|
+
* ```
|
|
900
|
+
*/
|
|
901
|
+
declare function isValidatorNotFound(error: any): boolean;
|
|
902
|
+
/**
|
|
903
|
+
* Check if error is a service unavailable error (sync in progress)
|
|
904
|
+
*
|
|
905
|
+
* @param error - Error object to check
|
|
906
|
+
* @returns True if service is temporarily unavailable
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* ```typescript
|
|
910
|
+
* try {
|
|
911
|
+
* const stats = await sdk.analytics.getProtocolStats();
|
|
912
|
+
* } catch (error) {
|
|
913
|
+
* if (isServiceUnavailable(error)) {
|
|
914
|
+
* console.log('Analytics service is syncing, try again later');
|
|
915
|
+
* }
|
|
916
|
+
* }
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
919
|
+
declare function isServiceUnavailable(error: any): boolean;
|
|
920
|
+
/**
|
|
921
|
+
* Check if error is a timeout error
|
|
922
|
+
*
|
|
923
|
+
* @param error - Error object to check
|
|
924
|
+
* @returns True if request timed out
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```typescript
|
|
928
|
+
* try {
|
|
929
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 1000 });
|
|
930
|
+
* } catch (error) {
|
|
931
|
+
* if (isTimeout(error)) {
|
|
932
|
+
* console.log('Request timed out, try with smaller limit');
|
|
933
|
+
* }
|
|
934
|
+
* }
|
|
935
|
+
* ```
|
|
936
|
+
*/
|
|
937
|
+
declare function isTimeout(error: any): boolean;
|
|
938
|
+
/**
|
|
939
|
+
* Check if analytics data is stale
|
|
940
|
+
*
|
|
941
|
+
* @param response - Response with metadata
|
|
942
|
+
* @returns True if data is marked as stale
|
|
943
|
+
*
|
|
944
|
+
* @example
|
|
945
|
+
* ```typescript
|
|
946
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
947
|
+
* if (isStaleData(rewards)) {
|
|
948
|
+
* console.warn('Data may be outdated');
|
|
949
|
+
* }
|
|
950
|
+
* ```
|
|
951
|
+
*/
|
|
952
|
+
declare function isStaleData(response: ValidatorRewardsResponse): boolean;
|
|
953
|
+
/**
|
|
954
|
+
* Check if analytics data is from cache
|
|
955
|
+
*
|
|
956
|
+
* @param response - Response with metadata
|
|
957
|
+
* @returns True if data was served from cache
|
|
958
|
+
*
|
|
959
|
+
* @example
|
|
960
|
+
* ```typescript
|
|
961
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
962
|
+
* if (isCachedData(rewards)) {
|
|
963
|
+
* console.log('Serving from cache');
|
|
964
|
+
* }
|
|
965
|
+
* ```
|
|
966
|
+
*/
|
|
967
|
+
declare function isCachedData(response: ValidatorRewardsResponse): boolean;
|
|
968
|
+
/**
|
|
969
|
+
* Check if sync worker is healthy
|
|
970
|
+
*
|
|
971
|
+
* @param syncStatus - Sync status response
|
|
972
|
+
* @param workerName - Worker name to check ('protocol_sync' or 'validator_sync')
|
|
973
|
+
* @returns True if worker is in success state
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* const status = await sdk.analytics.getSyncStatus();
|
|
978
|
+
* if (isSyncHealthy(status, 'protocol_sync')) {
|
|
979
|
+
* console.log('Protocol sync is healthy');
|
|
980
|
+
* }
|
|
981
|
+
* ```
|
|
982
|
+
*/
|
|
983
|
+
declare function isSyncHealthy(syncStatus: SyncStatusResponse, workerName?: 'protocol_sync' | 'validator_sync'): boolean;
|
|
984
|
+
/**
|
|
985
|
+
* Check if sync worker is degraded
|
|
986
|
+
*
|
|
987
|
+
* @param syncStatus - Sync status response
|
|
988
|
+
* @param workerName - Worker name to check
|
|
989
|
+
* @returns True if worker is in degraded state
|
|
990
|
+
*
|
|
991
|
+
* @example
|
|
992
|
+
* ```typescript
|
|
993
|
+
* const status = await sdk.analytics.getSyncStatus();
|
|
994
|
+
* if (isSyncDegraded(status, 'protocol_sync')) {
|
|
995
|
+
* console.warn('Protocol sync is degraded, some data may be incomplete');
|
|
996
|
+
* }
|
|
997
|
+
* ```
|
|
998
|
+
*/
|
|
999
|
+
declare function isSyncDegraded(syncStatus: SyncStatusResponse, workerName?: 'protocol_sync' | 'validator_sync'): boolean;
|
|
1000
|
+
/**
|
|
1001
|
+
* Get sync lag in blocks
|
|
1002
|
+
*
|
|
1003
|
+
* @param syncStatus - Sync status response
|
|
1004
|
+
* @param currentBlock - Current blockchain block number
|
|
1005
|
+
* @param workerName - Worker name to check
|
|
1006
|
+
* @returns Number of blocks behind, or null if unknown
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* ```typescript
|
|
1010
|
+
* const status = await sdk.analytics.getSyncStatus();
|
|
1011
|
+
* const currentBlock = await provider.getBlockNumber();
|
|
1012
|
+
* const lag = getSyncLag(status, currentBlock);
|
|
1013
|
+
* if (lag && lag > 100) {
|
|
1014
|
+
* console.warn(`Analytics is ${lag} blocks behind`);
|
|
1015
|
+
* }
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
declare function getSyncLag(syncStatus: SyncStatusResponse, currentBlock: number, workerName?: 'protocol_sync' | 'validator_sync'): number | null;
|
|
1019
|
+
/**
|
|
1020
|
+
* Calculate data freshness score (0-100)
|
|
1021
|
+
*
|
|
1022
|
+
* @param response - Response with metadata
|
|
1023
|
+
* @param currentBlock - Current blockchain block number
|
|
1024
|
+
* @returns Freshness score (100 = perfectly fresh, 0 = very stale)
|
|
1025
|
+
*
|
|
1026
|
+
* @remarks
|
|
1027
|
+
* Score calculation:
|
|
1028
|
+
* - 100: Data is from current block
|
|
1029
|
+
* - 90-99: Data is 1-10 blocks behind
|
|
1030
|
+
* - 50-89: Data is 11-100 blocks behind
|
|
1031
|
+
* - 0-49: Data is >100 blocks behind
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* ```typescript
|
|
1035
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
1036
|
+
* const currentBlock = await provider.getBlockNumber();
|
|
1037
|
+
* const freshness = getDataFreshness(rewards, currentBlock);
|
|
1038
|
+
*
|
|
1039
|
+
* if (freshness < 50) {
|
|
1040
|
+
* console.warn('Data is very stale');
|
|
1041
|
+
* } else if (freshness < 90) {
|
|
1042
|
+
* console.log('Data is slightly behind');
|
|
1043
|
+
* } else {
|
|
1044
|
+
* console.log('Data is fresh');
|
|
1045
|
+
* }
|
|
1046
|
+
* ```
|
|
1047
|
+
*/
|
|
1048
|
+
declare function getDataFreshness(response: ValidatorRewardsResponse, currentBlock: number): number;
|
|
1049
|
+
/**
|
|
1050
|
+
* Validate pagination options
|
|
1051
|
+
*
|
|
1052
|
+
* @param limit - Limit value
|
|
1053
|
+
* @param offset - Offset value
|
|
1054
|
+
* @throws Error if pagination options are invalid
|
|
1055
|
+
*
|
|
1056
|
+
* @example
|
|
1057
|
+
* ```typescript
|
|
1058
|
+
* try {
|
|
1059
|
+
* validatePagination(50, 0);
|
|
1060
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50, offset: 0 });
|
|
1061
|
+
* } catch (error) {
|
|
1062
|
+
* console.error('Invalid pagination:', error.message);
|
|
1063
|
+
* }
|
|
1064
|
+
* ```
|
|
1065
|
+
*/
|
|
1066
|
+
declare function validatePagination(limit?: number, offset?: number): void;
|
|
1067
|
+
/**
|
|
1068
|
+
* Calculate optimal batch size for pagination
|
|
1069
|
+
*
|
|
1070
|
+
* @param totalItems - Total number of items to fetch
|
|
1071
|
+
* @param maxBatchSize - Maximum batch size (default: 100)
|
|
1072
|
+
* @returns Optimal batch size
|
|
1073
|
+
*
|
|
1074
|
+
* @example
|
|
1075
|
+
* ```typescript
|
|
1076
|
+
* const totalStakers = 250;
|
|
1077
|
+
* const batchSize = getOptimalBatchSize(totalStakers);
|
|
1078
|
+
* // Returns 50 (250 / 5 batches)
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
declare function getOptimalBatchSize(totalItems: number, maxBatchSize?: number): number;
|
|
1082
|
+
/**
|
|
1083
|
+
* Format large numbers with commas
|
|
1084
|
+
*
|
|
1085
|
+
* @param value - Number or string to format
|
|
1086
|
+
* @returns Formatted string with commas
|
|
1087
|
+
*
|
|
1088
|
+
* @example
|
|
1089
|
+
* ```typescript
|
|
1090
|
+
* const staking = stats.TotalStaking;
|
|
1091
|
+
* console.log(formatNumber(staking)); // "26,883,345,073,055,930,973,683,712"
|
|
1092
|
+
* ```
|
|
1093
|
+
*/
|
|
1094
|
+
declare function formatNumber(value: string | number): string;
|
|
1095
|
+
/**
|
|
1096
|
+
* Convert Wei to Ether string
|
|
1097
|
+
*
|
|
1098
|
+
* @param wei - Wei amount as string
|
|
1099
|
+
* @param decimals - Number of decimal places (default: 4)
|
|
1100
|
+
* @returns Ether amount as string
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* ```typescript
|
|
1104
|
+
* const stake = "4000000000000000000000000";
|
|
1105
|
+
* console.log(weiToEther(stake)); // "4000000.0000"
|
|
1106
|
+
* ```
|
|
1107
|
+
*/
|
|
1108
|
+
declare function weiToEther(wei: string, decimals?: number): string;
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Retry Utilities
|
|
1112
|
+
*
|
|
1113
|
+
* Provides retry logic with exponential backoff for handling
|
|
1114
|
+
* transient errors and timeouts.
|
|
1115
|
+
*/
|
|
1116
|
+
interface RetryOptions {
|
|
1117
|
+
/**
|
|
1118
|
+
* Maximum number of retry attempts
|
|
1119
|
+
* @default 3
|
|
1120
|
+
*/
|
|
1121
|
+
maxRetries?: number;
|
|
1122
|
+
/**
|
|
1123
|
+
* Initial delay in milliseconds before first retry
|
|
1124
|
+
* @default 1000
|
|
1125
|
+
*/
|
|
1126
|
+
initialDelay?: number;
|
|
1127
|
+
/**
|
|
1128
|
+
* Maximum delay in milliseconds between retries
|
|
1129
|
+
* @default 10000
|
|
1130
|
+
*/
|
|
1131
|
+
maxDelay?: number;
|
|
1132
|
+
/**
|
|
1133
|
+
* Backoff multiplier for exponential backoff
|
|
1134
|
+
* @default 2
|
|
1135
|
+
*/
|
|
1136
|
+
backoffMultiplier?: number;
|
|
1137
|
+
/**
|
|
1138
|
+
* Function to determine if error should be retried
|
|
1139
|
+
* @default Retries on timeout and 503 errors
|
|
1140
|
+
*/
|
|
1141
|
+
shouldRetry?: (error: any, attempt: number) => boolean;
|
|
1142
|
+
/**
|
|
1143
|
+
* Callback called before each retry
|
|
1144
|
+
*/
|
|
1145
|
+
onRetry?: (error: any, attempt: number, delay: number) => void;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Execute a function with retry logic
|
|
1149
|
+
*
|
|
1150
|
+
* @param fn - Async function to execute
|
|
1151
|
+
* @param options - Retry options
|
|
1152
|
+
* @returns Promise resolving to function result
|
|
1153
|
+
*
|
|
1154
|
+
* @example
|
|
1155
|
+
* ```typescript
|
|
1156
|
+
* const result = await withRetry(
|
|
1157
|
+
* () => sdk.analytics.getValidatorRewards(address, { limit: 100 }),
|
|
1158
|
+
* {
|
|
1159
|
+
* maxRetries: 3,
|
|
1160
|
+
* initialDelay: 1000,
|
|
1161
|
+
* onRetry: (error, attempt, delay) => {
|
|
1162
|
+
* console.log(`Retry attempt ${attempt} after ${delay}ms`);
|
|
1163
|
+
* }
|
|
1164
|
+
* }
|
|
1165
|
+
* );
|
|
1166
|
+
* ```
|
|
1167
|
+
*/
|
|
1168
|
+
declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
1169
|
+
/**
|
|
1170
|
+
* Create a retry wrapper for a function
|
|
1171
|
+
*
|
|
1172
|
+
* @param fn - Function to wrap
|
|
1173
|
+
* @param options - Retry options
|
|
1174
|
+
* @returns Wrapped function with retry logic
|
|
1175
|
+
*
|
|
1176
|
+
* @example
|
|
1177
|
+
* ```typescript
|
|
1178
|
+
* const getRewardsWithRetry = createRetryWrapper(
|
|
1179
|
+
* (address: string, opts: any) => sdk.analytics.getValidatorRewards(address, opts),
|
|
1180
|
+
* { maxRetries: 3 }
|
|
1181
|
+
* );
|
|
1182
|
+
*
|
|
1183
|
+
* const rewards = await getRewardsWithRetry(address, { limit: 50 });
|
|
1184
|
+
* ```
|
|
1185
|
+
*/
|
|
1186
|
+
declare function createRetryWrapper<T extends (...args: any[]) => Promise<any>>(fn: T, options?: RetryOptions): T;
|
|
1187
|
+
|
|
878
1188
|
/**
|
|
879
1189
|
* Resonance Network SDK
|
|
880
1190
|
*
|
|
@@ -934,4 +1244,4 @@ declare class ResonanceSDK {
|
|
|
934
1244
|
logout(): void;
|
|
935
1245
|
}
|
|
936
1246
|
|
|
937
|
-
export { type APIError, type APIResponse, type ActiveValidator, AnalyticsAPI, type AuthResponse, AuthService, type DelegatorDetailResponse, type DelegatorListResponse, type DelegatorReward, type DelegatorRewardsResponse, type DelegatorStakeInfo, type DelegatorStakesResponse, type DelegatorUnbondingResponse, type DelegatorValidatorStake, type DelegatorValidatorsResponse, type DelegatorWithdrawal, type DelegatorWithdrawalsResponse, DelegatorsAPI, type EpochDistribution, type EpochReward, type EpochStakes, type EpochUnclaimed, GlobalAPI, type GlobalNetworkResponse, HTTPClient, type JWTClaims, type LeaderboardDelegatorResponse, type LeaderboardValidatorResponse, type NetworkAPRBreakdownResponse, type NetworkAPRResponse, type PaginationOptions, type ProtocolStats, type QueryParams, type ReferralApplyRequest, type ReferralCreateRequest, type ReferralDelegatorResponse, type ReferralValidateRequest, type ReferralValidateResponse, type ReferralValidatorResponse, ReferralsAPI, ResonanceSDK, type ResponseMetadata, type RewardDTO, type RewardSummary, type SDKConfig, SlashingAPI, type SlashingEventResponse, type StakeDTO, type SyncJobStatus, type SyncStatusResponse, type TopDelegatorRank, type UnbondingInfo, type UnclaimedDelegator, type ValidatorAPRResponse, type ValidatorAnalytics, type ValidatorAnalyticsListResponse, type ValidatorDelegatorsResponse, type ValidatorDetailResponse, type ValidatorEpochResponse, type ValidatorHistoryItem, type ValidatorHistoryResponse, type ValidatorListOptions, type ValidatorListResponse, type ValidatorMetricsResponse, type ValidatorRewardsResponse, type ValidatorStakeBreakdownResponse, type ValidatorWithdrawal, type ValidatorWithdrawalsResponse, ValidatorsAPI, ResonanceSDK as default };
|
|
1247
|
+
export { type APIError, type APIResponse, type ActiveValidator, AnalyticsAPI, type AuthResponse, AuthService, type DelegatorDetailResponse, type DelegatorListResponse, type DelegatorReward, type DelegatorRewardsResponse, type DelegatorStakeInfo, type DelegatorStakesResponse, type DelegatorUnbondingResponse, type DelegatorValidatorStake, type DelegatorValidatorsResponse, type DelegatorWithdrawal, type DelegatorWithdrawalsResponse, DelegatorsAPI, type EpochDistribution, type EpochReward, type EpochStakes, type EpochUnclaimed, GlobalAPI, type GlobalNetworkResponse, HTTPClient, type JWTClaims, type LeaderboardDelegatorResponse, type LeaderboardValidatorResponse, type NetworkAPRBreakdownResponse, type NetworkAPRResponse, type PaginationOptions, type ProtocolStats, type QueryParams, type ReferralApplyRequest, type ReferralCreateRequest, type ReferralDelegatorResponse, type ReferralValidateRequest, type ReferralValidateResponse, type ReferralValidatorResponse, ReferralsAPI, ResonanceSDK, type ResponseMetadata, type RetryOptions, type RewardDTO, type RewardSummary, type SDKConfig, SlashingAPI, type SlashingEventResponse, type StakeDTO, type SyncJobStatus, type SyncStatusResponse, type TopDelegatorRank, type UnbondingInfo, type UnclaimedDelegator, type ValidatorAPRResponse, type ValidatorAnalytics, type ValidatorAnalyticsListResponse, type ValidatorDelegatorsResponse, type ValidatorDetailResponse, type ValidatorEpochResponse, type ValidatorHistoryItem, type ValidatorHistoryResponse, type ValidatorListOptions, type ValidatorListResponse, type ValidatorMetricsResponse, type ValidatorRewardsResponse, type ValidatorStakeBreakdownResponse, type ValidatorWithdrawal, type ValidatorWithdrawalsResponse, ValidatorsAPI, createRetryWrapper, ResonanceSDK as default, formatNumber, getDataFreshness, getOptimalBatchSize, getSyncLag, isCachedData, isServiceUnavailable, isStaleData, isSyncDegraded, isSyncHealthy, isTimeout, isValidatorNotFound, validatePagination, weiToEther, withRetry };
|
package/dist/index.d.ts
CHANGED
|
@@ -875,6 +875,316 @@ declare class AnalyticsAPI {
|
|
|
875
875
|
}): Promise<ValidatorRewardsResponse>;
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
+
/**
|
|
879
|
+
* Analytics Helper Utilities
|
|
880
|
+
*
|
|
881
|
+
* Provides utility functions for working with analytics data,
|
|
882
|
+
* including error checking, data validation, and freshness checks.
|
|
883
|
+
*/
|
|
884
|
+
/**
|
|
885
|
+
* Check if error is a validator not found error
|
|
886
|
+
*
|
|
887
|
+
* @param error - Error object to check
|
|
888
|
+
* @returns True if validator was not found
|
|
889
|
+
*
|
|
890
|
+
* @example
|
|
891
|
+
* ```typescript
|
|
892
|
+
* try {
|
|
893
|
+
* const validator = await sdk.analytics.getValidatorAnalytics(address);
|
|
894
|
+
* } catch (error) {
|
|
895
|
+
* if (isValidatorNotFound(error)) {
|
|
896
|
+
* console.log('Validator does not exist');
|
|
897
|
+
* }
|
|
898
|
+
* }
|
|
899
|
+
* ```
|
|
900
|
+
*/
|
|
901
|
+
declare function isValidatorNotFound(error: any): boolean;
|
|
902
|
+
/**
|
|
903
|
+
* Check if error is a service unavailable error (sync in progress)
|
|
904
|
+
*
|
|
905
|
+
* @param error - Error object to check
|
|
906
|
+
* @returns True if service is temporarily unavailable
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* ```typescript
|
|
910
|
+
* try {
|
|
911
|
+
* const stats = await sdk.analytics.getProtocolStats();
|
|
912
|
+
* } catch (error) {
|
|
913
|
+
* if (isServiceUnavailable(error)) {
|
|
914
|
+
* console.log('Analytics service is syncing, try again later');
|
|
915
|
+
* }
|
|
916
|
+
* }
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
919
|
+
declare function isServiceUnavailable(error: any): boolean;
|
|
920
|
+
/**
|
|
921
|
+
* Check if error is a timeout error
|
|
922
|
+
*
|
|
923
|
+
* @param error - Error object to check
|
|
924
|
+
* @returns True if request timed out
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```typescript
|
|
928
|
+
* try {
|
|
929
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 1000 });
|
|
930
|
+
* } catch (error) {
|
|
931
|
+
* if (isTimeout(error)) {
|
|
932
|
+
* console.log('Request timed out, try with smaller limit');
|
|
933
|
+
* }
|
|
934
|
+
* }
|
|
935
|
+
* ```
|
|
936
|
+
*/
|
|
937
|
+
declare function isTimeout(error: any): boolean;
|
|
938
|
+
/**
|
|
939
|
+
* Check if analytics data is stale
|
|
940
|
+
*
|
|
941
|
+
* @param response - Response with metadata
|
|
942
|
+
* @returns True if data is marked as stale
|
|
943
|
+
*
|
|
944
|
+
* @example
|
|
945
|
+
* ```typescript
|
|
946
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
947
|
+
* if (isStaleData(rewards)) {
|
|
948
|
+
* console.warn('Data may be outdated');
|
|
949
|
+
* }
|
|
950
|
+
* ```
|
|
951
|
+
*/
|
|
952
|
+
declare function isStaleData(response: ValidatorRewardsResponse): boolean;
|
|
953
|
+
/**
|
|
954
|
+
* Check if analytics data is from cache
|
|
955
|
+
*
|
|
956
|
+
* @param response - Response with metadata
|
|
957
|
+
* @returns True if data was served from cache
|
|
958
|
+
*
|
|
959
|
+
* @example
|
|
960
|
+
* ```typescript
|
|
961
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
962
|
+
* if (isCachedData(rewards)) {
|
|
963
|
+
* console.log('Serving from cache');
|
|
964
|
+
* }
|
|
965
|
+
* ```
|
|
966
|
+
*/
|
|
967
|
+
declare function isCachedData(response: ValidatorRewardsResponse): boolean;
|
|
968
|
+
/**
|
|
969
|
+
* Check if sync worker is healthy
|
|
970
|
+
*
|
|
971
|
+
* @param syncStatus - Sync status response
|
|
972
|
+
* @param workerName - Worker name to check ('protocol_sync' or 'validator_sync')
|
|
973
|
+
* @returns True if worker is in success state
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* const status = await sdk.analytics.getSyncStatus();
|
|
978
|
+
* if (isSyncHealthy(status, 'protocol_sync')) {
|
|
979
|
+
* console.log('Protocol sync is healthy');
|
|
980
|
+
* }
|
|
981
|
+
* ```
|
|
982
|
+
*/
|
|
983
|
+
declare function isSyncHealthy(syncStatus: SyncStatusResponse, workerName?: 'protocol_sync' | 'validator_sync'): boolean;
|
|
984
|
+
/**
|
|
985
|
+
* Check if sync worker is degraded
|
|
986
|
+
*
|
|
987
|
+
* @param syncStatus - Sync status response
|
|
988
|
+
* @param workerName - Worker name to check
|
|
989
|
+
* @returns True if worker is in degraded state
|
|
990
|
+
*
|
|
991
|
+
* @example
|
|
992
|
+
* ```typescript
|
|
993
|
+
* const status = await sdk.analytics.getSyncStatus();
|
|
994
|
+
* if (isSyncDegraded(status, 'protocol_sync')) {
|
|
995
|
+
* console.warn('Protocol sync is degraded, some data may be incomplete');
|
|
996
|
+
* }
|
|
997
|
+
* ```
|
|
998
|
+
*/
|
|
999
|
+
declare function isSyncDegraded(syncStatus: SyncStatusResponse, workerName?: 'protocol_sync' | 'validator_sync'): boolean;
|
|
1000
|
+
/**
|
|
1001
|
+
* Get sync lag in blocks
|
|
1002
|
+
*
|
|
1003
|
+
* @param syncStatus - Sync status response
|
|
1004
|
+
* @param currentBlock - Current blockchain block number
|
|
1005
|
+
* @param workerName - Worker name to check
|
|
1006
|
+
* @returns Number of blocks behind, or null if unknown
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* ```typescript
|
|
1010
|
+
* const status = await sdk.analytics.getSyncStatus();
|
|
1011
|
+
* const currentBlock = await provider.getBlockNumber();
|
|
1012
|
+
* const lag = getSyncLag(status, currentBlock);
|
|
1013
|
+
* if (lag && lag > 100) {
|
|
1014
|
+
* console.warn(`Analytics is ${lag} blocks behind`);
|
|
1015
|
+
* }
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
declare function getSyncLag(syncStatus: SyncStatusResponse, currentBlock: number, workerName?: 'protocol_sync' | 'validator_sync'): number | null;
|
|
1019
|
+
/**
|
|
1020
|
+
* Calculate data freshness score (0-100)
|
|
1021
|
+
*
|
|
1022
|
+
* @param response - Response with metadata
|
|
1023
|
+
* @param currentBlock - Current blockchain block number
|
|
1024
|
+
* @returns Freshness score (100 = perfectly fresh, 0 = very stale)
|
|
1025
|
+
*
|
|
1026
|
+
* @remarks
|
|
1027
|
+
* Score calculation:
|
|
1028
|
+
* - 100: Data is from current block
|
|
1029
|
+
* - 90-99: Data is 1-10 blocks behind
|
|
1030
|
+
* - 50-89: Data is 11-100 blocks behind
|
|
1031
|
+
* - 0-49: Data is >100 blocks behind
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* ```typescript
|
|
1035
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
1036
|
+
* const currentBlock = await provider.getBlockNumber();
|
|
1037
|
+
* const freshness = getDataFreshness(rewards, currentBlock);
|
|
1038
|
+
*
|
|
1039
|
+
* if (freshness < 50) {
|
|
1040
|
+
* console.warn('Data is very stale');
|
|
1041
|
+
* } else if (freshness < 90) {
|
|
1042
|
+
* console.log('Data is slightly behind');
|
|
1043
|
+
* } else {
|
|
1044
|
+
* console.log('Data is fresh');
|
|
1045
|
+
* }
|
|
1046
|
+
* ```
|
|
1047
|
+
*/
|
|
1048
|
+
declare function getDataFreshness(response: ValidatorRewardsResponse, currentBlock: number): number;
|
|
1049
|
+
/**
|
|
1050
|
+
* Validate pagination options
|
|
1051
|
+
*
|
|
1052
|
+
* @param limit - Limit value
|
|
1053
|
+
* @param offset - Offset value
|
|
1054
|
+
* @throws Error if pagination options are invalid
|
|
1055
|
+
*
|
|
1056
|
+
* @example
|
|
1057
|
+
* ```typescript
|
|
1058
|
+
* try {
|
|
1059
|
+
* validatePagination(50, 0);
|
|
1060
|
+
* const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50, offset: 0 });
|
|
1061
|
+
* } catch (error) {
|
|
1062
|
+
* console.error('Invalid pagination:', error.message);
|
|
1063
|
+
* }
|
|
1064
|
+
* ```
|
|
1065
|
+
*/
|
|
1066
|
+
declare function validatePagination(limit?: number, offset?: number): void;
|
|
1067
|
+
/**
|
|
1068
|
+
* Calculate optimal batch size for pagination
|
|
1069
|
+
*
|
|
1070
|
+
* @param totalItems - Total number of items to fetch
|
|
1071
|
+
* @param maxBatchSize - Maximum batch size (default: 100)
|
|
1072
|
+
* @returns Optimal batch size
|
|
1073
|
+
*
|
|
1074
|
+
* @example
|
|
1075
|
+
* ```typescript
|
|
1076
|
+
* const totalStakers = 250;
|
|
1077
|
+
* const batchSize = getOptimalBatchSize(totalStakers);
|
|
1078
|
+
* // Returns 50 (250 / 5 batches)
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
declare function getOptimalBatchSize(totalItems: number, maxBatchSize?: number): number;
|
|
1082
|
+
/**
|
|
1083
|
+
* Format large numbers with commas
|
|
1084
|
+
*
|
|
1085
|
+
* @param value - Number or string to format
|
|
1086
|
+
* @returns Formatted string with commas
|
|
1087
|
+
*
|
|
1088
|
+
* @example
|
|
1089
|
+
* ```typescript
|
|
1090
|
+
* const staking = stats.TotalStaking;
|
|
1091
|
+
* console.log(formatNumber(staking)); // "26,883,345,073,055,930,973,683,712"
|
|
1092
|
+
* ```
|
|
1093
|
+
*/
|
|
1094
|
+
declare function formatNumber(value: string | number): string;
|
|
1095
|
+
/**
|
|
1096
|
+
* Convert Wei to Ether string
|
|
1097
|
+
*
|
|
1098
|
+
* @param wei - Wei amount as string
|
|
1099
|
+
* @param decimals - Number of decimal places (default: 4)
|
|
1100
|
+
* @returns Ether amount as string
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* ```typescript
|
|
1104
|
+
* const stake = "4000000000000000000000000";
|
|
1105
|
+
* console.log(weiToEther(stake)); // "4000000.0000"
|
|
1106
|
+
* ```
|
|
1107
|
+
*/
|
|
1108
|
+
declare function weiToEther(wei: string, decimals?: number): string;
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Retry Utilities
|
|
1112
|
+
*
|
|
1113
|
+
* Provides retry logic with exponential backoff for handling
|
|
1114
|
+
* transient errors and timeouts.
|
|
1115
|
+
*/
|
|
1116
|
+
interface RetryOptions {
|
|
1117
|
+
/**
|
|
1118
|
+
* Maximum number of retry attempts
|
|
1119
|
+
* @default 3
|
|
1120
|
+
*/
|
|
1121
|
+
maxRetries?: number;
|
|
1122
|
+
/**
|
|
1123
|
+
* Initial delay in milliseconds before first retry
|
|
1124
|
+
* @default 1000
|
|
1125
|
+
*/
|
|
1126
|
+
initialDelay?: number;
|
|
1127
|
+
/**
|
|
1128
|
+
* Maximum delay in milliseconds between retries
|
|
1129
|
+
* @default 10000
|
|
1130
|
+
*/
|
|
1131
|
+
maxDelay?: number;
|
|
1132
|
+
/**
|
|
1133
|
+
* Backoff multiplier for exponential backoff
|
|
1134
|
+
* @default 2
|
|
1135
|
+
*/
|
|
1136
|
+
backoffMultiplier?: number;
|
|
1137
|
+
/**
|
|
1138
|
+
* Function to determine if error should be retried
|
|
1139
|
+
* @default Retries on timeout and 503 errors
|
|
1140
|
+
*/
|
|
1141
|
+
shouldRetry?: (error: any, attempt: number) => boolean;
|
|
1142
|
+
/**
|
|
1143
|
+
* Callback called before each retry
|
|
1144
|
+
*/
|
|
1145
|
+
onRetry?: (error: any, attempt: number, delay: number) => void;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Execute a function with retry logic
|
|
1149
|
+
*
|
|
1150
|
+
* @param fn - Async function to execute
|
|
1151
|
+
* @param options - Retry options
|
|
1152
|
+
* @returns Promise resolving to function result
|
|
1153
|
+
*
|
|
1154
|
+
* @example
|
|
1155
|
+
* ```typescript
|
|
1156
|
+
* const result = await withRetry(
|
|
1157
|
+
* () => sdk.analytics.getValidatorRewards(address, { limit: 100 }),
|
|
1158
|
+
* {
|
|
1159
|
+
* maxRetries: 3,
|
|
1160
|
+
* initialDelay: 1000,
|
|
1161
|
+
* onRetry: (error, attempt, delay) => {
|
|
1162
|
+
* console.log(`Retry attempt ${attempt} after ${delay}ms`);
|
|
1163
|
+
* }
|
|
1164
|
+
* }
|
|
1165
|
+
* );
|
|
1166
|
+
* ```
|
|
1167
|
+
*/
|
|
1168
|
+
declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
1169
|
+
/**
|
|
1170
|
+
* Create a retry wrapper for a function
|
|
1171
|
+
*
|
|
1172
|
+
* @param fn - Function to wrap
|
|
1173
|
+
* @param options - Retry options
|
|
1174
|
+
* @returns Wrapped function with retry logic
|
|
1175
|
+
*
|
|
1176
|
+
* @example
|
|
1177
|
+
* ```typescript
|
|
1178
|
+
* const getRewardsWithRetry = createRetryWrapper(
|
|
1179
|
+
* (address: string, opts: any) => sdk.analytics.getValidatorRewards(address, opts),
|
|
1180
|
+
* { maxRetries: 3 }
|
|
1181
|
+
* );
|
|
1182
|
+
*
|
|
1183
|
+
* const rewards = await getRewardsWithRetry(address, { limit: 50 });
|
|
1184
|
+
* ```
|
|
1185
|
+
*/
|
|
1186
|
+
declare function createRetryWrapper<T extends (...args: any[]) => Promise<any>>(fn: T, options?: RetryOptions): T;
|
|
1187
|
+
|
|
878
1188
|
/**
|
|
879
1189
|
* Resonance Network SDK
|
|
880
1190
|
*
|
|
@@ -934,4 +1244,4 @@ declare class ResonanceSDK {
|
|
|
934
1244
|
logout(): void;
|
|
935
1245
|
}
|
|
936
1246
|
|
|
937
|
-
export { type APIError, type APIResponse, type ActiveValidator, AnalyticsAPI, type AuthResponse, AuthService, type DelegatorDetailResponse, type DelegatorListResponse, type DelegatorReward, type DelegatorRewardsResponse, type DelegatorStakeInfo, type DelegatorStakesResponse, type DelegatorUnbondingResponse, type DelegatorValidatorStake, type DelegatorValidatorsResponse, type DelegatorWithdrawal, type DelegatorWithdrawalsResponse, DelegatorsAPI, type EpochDistribution, type EpochReward, type EpochStakes, type EpochUnclaimed, GlobalAPI, type GlobalNetworkResponse, HTTPClient, type JWTClaims, type LeaderboardDelegatorResponse, type LeaderboardValidatorResponse, type NetworkAPRBreakdownResponse, type NetworkAPRResponse, type PaginationOptions, type ProtocolStats, type QueryParams, type ReferralApplyRequest, type ReferralCreateRequest, type ReferralDelegatorResponse, type ReferralValidateRequest, type ReferralValidateResponse, type ReferralValidatorResponse, ReferralsAPI, ResonanceSDK, type ResponseMetadata, type RewardDTO, type RewardSummary, type SDKConfig, SlashingAPI, type SlashingEventResponse, type StakeDTO, type SyncJobStatus, type SyncStatusResponse, type TopDelegatorRank, type UnbondingInfo, type UnclaimedDelegator, type ValidatorAPRResponse, type ValidatorAnalytics, type ValidatorAnalyticsListResponse, type ValidatorDelegatorsResponse, type ValidatorDetailResponse, type ValidatorEpochResponse, type ValidatorHistoryItem, type ValidatorHistoryResponse, type ValidatorListOptions, type ValidatorListResponse, type ValidatorMetricsResponse, type ValidatorRewardsResponse, type ValidatorStakeBreakdownResponse, type ValidatorWithdrawal, type ValidatorWithdrawalsResponse, ValidatorsAPI, ResonanceSDK as default };
|
|
1247
|
+
export { type APIError, type APIResponse, type ActiveValidator, AnalyticsAPI, type AuthResponse, AuthService, type DelegatorDetailResponse, type DelegatorListResponse, type DelegatorReward, type DelegatorRewardsResponse, type DelegatorStakeInfo, type DelegatorStakesResponse, type DelegatorUnbondingResponse, type DelegatorValidatorStake, type DelegatorValidatorsResponse, type DelegatorWithdrawal, type DelegatorWithdrawalsResponse, DelegatorsAPI, type EpochDistribution, type EpochReward, type EpochStakes, type EpochUnclaimed, GlobalAPI, type GlobalNetworkResponse, HTTPClient, type JWTClaims, type LeaderboardDelegatorResponse, type LeaderboardValidatorResponse, type NetworkAPRBreakdownResponse, type NetworkAPRResponse, type PaginationOptions, type ProtocolStats, type QueryParams, type ReferralApplyRequest, type ReferralCreateRequest, type ReferralDelegatorResponse, type ReferralValidateRequest, type ReferralValidateResponse, type ReferralValidatorResponse, ReferralsAPI, ResonanceSDK, type ResponseMetadata, type RetryOptions, type RewardDTO, type RewardSummary, type SDKConfig, SlashingAPI, type SlashingEventResponse, type StakeDTO, type SyncJobStatus, type SyncStatusResponse, type TopDelegatorRank, type UnbondingInfo, type UnclaimedDelegator, type ValidatorAPRResponse, type ValidatorAnalytics, type ValidatorAnalyticsListResponse, type ValidatorDelegatorsResponse, type ValidatorDetailResponse, type ValidatorEpochResponse, type ValidatorHistoryItem, type ValidatorHistoryResponse, type ValidatorListOptions, type ValidatorListResponse, type ValidatorMetricsResponse, type ValidatorRewardsResponse, type ValidatorStakeBreakdownResponse, type ValidatorWithdrawal, type ValidatorWithdrawalsResponse, ValidatorsAPI, createRetryWrapper, ResonanceSDK as default, formatNumber, getDataFreshness, getOptimalBatchSize, getSyncLag, isCachedData, isServiceUnavailable, isStaleData, isSyncDegraded, isSyncHealthy, isTimeout, isValidatorNotFound, validatePagination, weiToEther, withRetry };
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,22 @@ __export(index_exports, {
|
|
|
29
29
|
ResonanceSDK: () => ResonanceSDK,
|
|
30
30
|
SlashingAPI: () => SlashingAPI,
|
|
31
31
|
ValidatorsAPI: () => ValidatorsAPI,
|
|
32
|
-
|
|
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
|
|
33
48
|
});
|
|
34
49
|
module.exports = __toCommonJS(index_exports);
|
|
35
50
|
|
|
@@ -927,6 +942,120 @@ var AnalyticsAPI = class {
|
|
|
927
942
|
}
|
|
928
943
|
};
|
|
929
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));
|
|
982
|
+
}
|
|
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
|
+
|
|
930
1059
|
// src/index.ts
|
|
931
1060
|
var ResonanceSDK = class {
|
|
932
1061
|
constructor(config) {
|
|
@@ -985,5 +1114,20 @@ var index_default = ResonanceSDK;
|
|
|
985
1114
|
ReferralsAPI,
|
|
986
1115
|
ResonanceSDK,
|
|
987
1116
|
SlashingAPI,
|
|
988
|
-
ValidatorsAPI
|
|
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
|
|
989
1133
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -892,6 +892,120 @@ var AnalyticsAPI = class {
|
|
|
892
892
|
}
|
|
893
893
|
};
|
|
894
894
|
|
|
895
|
+
// src/utils/analytics-helpers.ts
|
|
896
|
+
function isValidatorNotFound(error) {
|
|
897
|
+
return error instanceof ResonanceAPIError && error.statusCode === 404;
|
|
898
|
+
}
|
|
899
|
+
function isServiceUnavailable(error) {
|
|
900
|
+
return error instanceof ResonanceAPIError && error.statusCode === 503;
|
|
901
|
+
}
|
|
902
|
+
function isTimeout(error) {
|
|
903
|
+
return error instanceof Error && error.message.includes("timeout");
|
|
904
|
+
}
|
|
905
|
+
function isStaleData(response) {
|
|
906
|
+
return response.metadata?.stale === true;
|
|
907
|
+
}
|
|
908
|
+
function isCachedData(response) {
|
|
909
|
+
return response.metadata?.cached === true;
|
|
910
|
+
}
|
|
911
|
+
function isSyncHealthy(syncStatus, workerName = "protocol_sync") {
|
|
912
|
+
const worker = syncStatus[workerName];
|
|
913
|
+
return worker?.status === "success";
|
|
914
|
+
}
|
|
915
|
+
function isSyncDegraded(syncStatus, workerName = "protocol_sync") {
|
|
916
|
+
const worker = syncStatus[workerName];
|
|
917
|
+
return worker?.status === "degraded";
|
|
918
|
+
}
|
|
919
|
+
function getSyncLag(syncStatus, currentBlock, workerName = "protocol_sync") {
|
|
920
|
+
const worker = syncStatus[workerName];
|
|
921
|
+
if (!worker?.last_block) return null;
|
|
922
|
+
return currentBlock - worker.last_block;
|
|
923
|
+
}
|
|
924
|
+
function getDataFreshness(response, currentBlock) {
|
|
925
|
+
const subgraphBlock = response.metadata?.subgraph_block;
|
|
926
|
+
if (!subgraphBlock) return 0;
|
|
927
|
+
const blocksBehind = currentBlock - subgraphBlock;
|
|
928
|
+
if (blocksBehind <= 0) return 100;
|
|
929
|
+
if (blocksBehind <= 10) return 100 - blocksBehind;
|
|
930
|
+
if (blocksBehind <= 100) return 90 - Math.floor((blocksBehind - 10) * 0.44);
|
|
931
|
+
return Math.max(0, 50 - Math.floor((blocksBehind - 100) * 0.5));
|
|
932
|
+
}
|
|
933
|
+
function validatePagination(limit, offset) {
|
|
934
|
+
if (limit !== void 0 && (limit <= 0 || limit > 1e3)) {
|
|
935
|
+
throw new Error("Limit must be between 1 and 1000");
|
|
936
|
+
}
|
|
937
|
+
if (offset !== void 0 && offset < 0) {
|
|
938
|
+
throw new Error("Offset must be non-negative");
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
function getOptimalBatchSize(totalItems, maxBatchSize = 100) {
|
|
942
|
+
if (totalItems <= maxBatchSize) return totalItems;
|
|
943
|
+
const targetBatches = 7;
|
|
944
|
+
const calculatedSize = Math.ceil(totalItems / targetBatches);
|
|
945
|
+
return Math.min(calculatedSize, maxBatchSize);
|
|
946
|
+
}
|
|
947
|
+
function formatNumber(value) {
|
|
948
|
+
const num = typeof value === "string" ? value : value.toString();
|
|
949
|
+
return num.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
950
|
+
}
|
|
951
|
+
function weiToEther(wei, decimals = 4) {
|
|
952
|
+
const weiNum = BigInt(wei);
|
|
953
|
+
const etherNum = Number(weiNum) / 1e18;
|
|
954
|
+
return etherNum.toFixed(decimals);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// src/utils/retry.ts
|
|
958
|
+
function defaultShouldRetry(error, attempt) {
|
|
959
|
+
if (attempt >= 3) return false;
|
|
960
|
+
if (error instanceof Error && error.message.includes("timeout")) {
|
|
961
|
+
return true;
|
|
962
|
+
}
|
|
963
|
+
if (error.statusCode === 503) {
|
|
964
|
+
return true;
|
|
965
|
+
}
|
|
966
|
+
if (error instanceof Error && error.message.includes("fetch failed")) {
|
|
967
|
+
return true;
|
|
968
|
+
}
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
async function withRetry(fn, options = {}) {
|
|
972
|
+
const {
|
|
973
|
+
maxRetries = 3,
|
|
974
|
+
initialDelay = 1e3,
|
|
975
|
+
maxDelay = 1e4,
|
|
976
|
+
backoffMultiplier = 2,
|
|
977
|
+
shouldRetry = defaultShouldRetry,
|
|
978
|
+
onRetry
|
|
979
|
+
} = options;
|
|
980
|
+
let lastError;
|
|
981
|
+
let delay = initialDelay;
|
|
982
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
983
|
+
try {
|
|
984
|
+
return await fn();
|
|
985
|
+
} catch (error) {
|
|
986
|
+
lastError = error;
|
|
987
|
+
if (attempt < maxRetries && shouldRetry(error, attempt)) {
|
|
988
|
+
if (onRetry) {
|
|
989
|
+
onRetry(error, attempt + 1, delay);
|
|
990
|
+
}
|
|
991
|
+
await sleep(delay);
|
|
992
|
+
delay = Math.min(delay * backoffMultiplier, maxDelay);
|
|
993
|
+
} else {
|
|
994
|
+
throw error;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
throw lastError;
|
|
999
|
+
}
|
|
1000
|
+
function sleep(ms) {
|
|
1001
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1002
|
+
}
|
|
1003
|
+
function createRetryWrapper(fn, options = {}) {
|
|
1004
|
+
return ((...args) => {
|
|
1005
|
+
return withRetry(() => fn(...args), options);
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
|
|
895
1009
|
// src/index.ts
|
|
896
1010
|
var ResonanceSDK = class {
|
|
897
1011
|
constructor(config) {
|
|
@@ -950,5 +1064,20 @@ export {
|
|
|
950
1064
|
ResonanceSDK,
|
|
951
1065
|
SlashingAPI,
|
|
952
1066
|
ValidatorsAPI,
|
|
953
|
-
|
|
1067
|
+
createRetryWrapper,
|
|
1068
|
+
index_default as default,
|
|
1069
|
+
formatNumber,
|
|
1070
|
+
getDataFreshness,
|
|
1071
|
+
getOptimalBatchSize,
|
|
1072
|
+
getSyncLag,
|
|
1073
|
+
isCachedData,
|
|
1074
|
+
isServiceUnavailable,
|
|
1075
|
+
isStaleData,
|
|
1076
|
+
isSyncDegraded,
|
|
1077
|
+
isSyncHealthy,
|
|
1078
|
+
isTimeout,
|
|
1079
|
+
isValidatorNotFound,
|
|
1080
|
+
validatePagination,
|
|
1081
|
+
weiToEther,
|
|
1082
|
+
withRetry
|
|
954
1083
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenelabs/fene-sdk",
|
|
3
|
-
"version": "0.2
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Fene Network SDK for interacting with Resonance FPoS blockchain",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -44,18 +44,21 @@
|
|
|
44
44
|
"web3",
|
|
45
45
|
"validator",
|
|
46
46
|
"delegator",
|
|
47
|
+
"dpos",
|
|
48
|
+
"organization",
|
|
49
|
+
"politics",
|
|
47
50
|
"typescript"
|
|
48
51
|
],
|
|
49
52
|
"author": "avenbreaks",
|
|
50
53
|
"license": "MIT",
|
|
51
54
|
"repository": {
|
|
52
55
|
"type": "git",
|
|
53
|
-
"url": "https://github.com/
|
|
56
|
+
"url": "https://github.com/fenelabs/fene-sdk"
|
|
54
57
|
},
|
|
55
58
|
"bugs": {
|
|
56
|
-
"url": "https://github.com/
|
|
59
|
+
"url": "https://github.com/fenelabs/fene-sdk/issues"
|
|
57
60
|
},
|
|
58
|
-
"homepage": "https://github.com/
|
|
61
|
+
"homepage": "https://github.com/fenelabs/fene-sdk#readme",
|
|
59
62
|
"publishConfig": {
|
|
60
63
|
"access": "public"
|
|
61
64
|
},
|