@fenelabs/fene-sdk 0.5.0 → 0.7.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/dist/index.d.mts CHANGED
@@ -22,6 +22,10 @@ interface AuthResponse {
22
22
  role: "validator" | "delegator";
23
23
  expires_at: number;
24
24
  }
25
+ interface RefreshResponse {
26
+ success: boolean;
27
+ expires_at?: number;
28
+ }
25
29
  declare enum ValidatorStatus {
26
30
  NOT_EXIST = 0,
27
31
  CREATED = 1,
@@ -95,15 +99,13 @@ interface WhitelistCheckResponse {
95
99
  }
96
100
  interface GeoNode {
97
101
  address: string;
98
- ip: string;
99
- latitude: number;
100
- longitude: number;
101
- city: string;
102
+ role: "validator" | "delegator";
103
+ lat: number;
104
+ lng: number;
102
105
  country: string;
103
- country_code: string;
104
- last_seen: string;
105
- node_type: "validator" | "rpc" | "bootstrap";
106
+ city?: string;
106
107
  online: boolean;
108
+ last_seen: number;
107
109
  }
108
110
  interface GeoStats {
109
111
  total_nodes: number;
@@ -112,9 +114,51 @@ interface GeoStats {
112
114
  cities: number;
113
115
  }
114
116
  interface GeoUpdateRequest {
117
+ lat: number;
118
+ lng: number;
119
+ }
120
+ interface GeoAutoDetectResponse {
121
+ success: boolean;
122
+ address: string;
123
+ role: "validator" | "delegator";
115
124
  latitude: number;
116
125
  longitude: number;
117
- node_type: string;
126
+ country: string;
127
+ city: string;
128
+ is_online: boolean;
129
+ }
130
+ interface UserProfile {
131
+ address: string;
132
+ roles: ("validator" | "delegator")[];
133
+ validator?: ValidatorProfileInfo;
134
+ delegations?: DelegationInfo[];
135
+ total_delegation_stake: string;
136
+ total_pending_rewards: string;
137
+ avatar_url?: string;
138
+ geo?: GeoLocation;
139
+ }
140
+ interface ValidatorProfileInfo {
141
+ address: string;
142
+ moniker: string;
143
+ self_stake: string;
144
+ total_stake: string;
145
+ commission_rate: number;
146
+ delegator_count: number;
147
+ claimable_reward: string;
148
+ apr: number;
149
+ }
150
+ interface DelegationInfo {
151
+ validator_address: string;
152
+ validator_moniker: string;
153
+ stake_amount: string;
154
+ pending_rewards: string;
155
+ apr: number;
156
+ }
157
+ interface GeoLocation {
158
+ lat: number;
159
+ lng: number;
160
+ country: string;
161
+ city?: string;
118
162
  }
119
163
  interface NetworkStats {
120
164
  total_validators: number;
@@ -255,9 +299,9 @@ declare class ResonanceClient {
255
299
  verify(params: AuthVerifyRequest): Promise<AuthResponse>;
256
300
  /**
257
301
  * Refresh the access token using the refresh token cookie.
258
- * Returns true if refresh was successful.
302
+ * Returns { success: boolean, expires_at?: number }
259
303
  */
260
- refresh(): Promise<boolean>;
304
+ refresh(): Promise<RefreshResponse>;
261
305
  /**
262
306
  * Logout and revoke current session.
263
307
  */
@@ -277,10 +321,36 @@ declare class ResonanceClient {
277
321
  getReferralKey(key: string): Promise<ReferralKey>;
278
322
  getValidatorKeys(address: Address): Promise<ReferralKey[]>;
279
323
  checkWhitelist(data: WhitelistCheckRequest): Promise<WhitelistCheckResponse>;
280
- getGeoNodes(): Promise<GeoNode[]>;
281
- getGeoValidators(): Promise<GeoNode[]>;
324
+ /**
325
+ * Get user profile with roles, validator info, delegations, avatar, and geo
326
+ * @param address The user wallet address
327
+ */
328
+ getUserProfile(address: Address): Promise<UserProfile>;
329
+ /**
330
+ * Get user avatar URL
331
+ * @param address The user wallet address
332
+ */
333
+ getUserAvatar(address: Address): Promise<{
334
+ url: string;
335
+ }>;
336
+ /**
337
+ * Upload user avatar
338
+ * @param address The user wallet address (must match authenticated user)
339
+ * @param file The image file to upload (png, jpg, or webp)
340
+ */
341
+ uploadUserAvatar(address: Address, file: File): Promise<UploadResponse>;
342
+ /**
343
+ * Get all geo nodes, optionally filtered by role
344
+ * @param role Optional filter: "validator" or "delegator"
345
+ */
346
+ getGeoNodes(role?: "validator" | "delegator"): Promise<GeoNode[]>;
282
347
  getGeoStats(): Promise<GeoStats>;
283
348
  updateGeoLocation(data: GeoUpdateRequest): Promise<void>;
349
+ /**
350
+ * Auto-detect user geo location from IP and save to server.
351
+ * Should be called after successful login.
352
+ */
353
+ autoDetectGeo(): Promise<GeoAutoDetectResponse>;
284
354
  getNetworkStats(): Promise<NetworkStats>;
285
355
  getCurrentEpoch(): Promise<EpochInfo>;
286
356
  getNetworkAPR(): Promise<NetworkAPR>;
@@ -375,4 +445,4 @@ declare class EventBus {
375
445
  }
376
446
  declare const eventBus: EventBus;
377
447
 
378
- export { type APIErrorResponse, type Address, type AuthResponse, type AuthVerifyRequest, type AvatarResponse, type DailyBlockStats, type Delegator, type DelegatorRewards, type DelegatorStake, DelegatorStatus, type EpochInfo, ErrorCode, type ErrorCodeType, type GeoNode, type GeoStats, type GeoUpdateRequest, type NetworkAPR, type NetworkStats, type NonceResponse, type PaginatedResponse, type PriceResponse, type ReferralKey, type RequestContext, ResonanceClient, type ResonanceClientConfig, ResonanceError, type ResponseContext, type RewardHistory, type Transaction, type TransactionStats, type TransactionsList, type TransactionsParams, type UploadResponse, type Validator, type ValidatorAPR, ValidatorStatus, type ValidatorSummary, type WhitelistCheckRequest, type WhitelistCheckResponse, createResonanceClient, eventBus, hasErrorCode, isAuthError, isNetworkError, isNotFoundError, isResonanceError };
448
+ export { type APIErrorResponse, type Address, type AuthResponse, type AuthVerifyRequest, type AvatarResponse, type DailyBlockStats, type Delegator, type DelegatorRewards, type DelegatorStake, DelegatorStatus, type EpochInfo, ErrorCode, type ErrorCodeType, type GeoNode, type GeoStats, type GeoUpdateRequest, type NetworkAPR, type NetworkStats, type NonceResponse, type PaginatedResponse, type PriceResponse, type ReferralKey, type RefreshResponse, type RequestContext, ResonanceClient, type ResonanceClientConfig, ResonanceError, type ResponseContext, type RewardHistory, type Transaction, type TransactionStats, type TransactionsList, type TransactionsParams, type UploadResponse, type Validator, type ValidatorAPR, ValidatorStatus, type ValidatorSummary, type WhitelistCheckRequest, type WhitelistCheckResponse, createResonanceClient, eventBus, hasErrorCode, isAuthError, isNetworkError, isNotFoundError, isResonanceError };
package/dist/index.d.ts CHANGED
@@ -22,6 +22,10 @@ interface AuthResponse {
22
22
  role: "validator" | "delegator";
23
23
  expires_at: number;
24
24
  }
25
+ interface RefreshResponse {
26
+ success: boolean;
27
+ expires_at?: number;
28
+ }
25
29
  declare enum ValidatorStatus {
26
30
  NOT_EXIST = 0,
27
31
  CREATED = 1,
@@ -95,15 +99,13 @@ interface WhitelistCheckResponse {
95
99
  }
96
100
  interface GeoNode {
97
101
  address: string;
98
- ip: string;
99
- latitude: number;
100
- longitude: number;
101
- city: string;
102
+ role: "validator" | "delegator";
103
+ lat: number;
104
+ lng: number;
102
105
  country: string;
103
- country_code: string;
104
- last_seen: string;
105
- node_type: "validator" | "rpc" | "bootstrap";
106
+ city?: string;
106
107
  online: boolean;
108
+ last_seen: number;
107
109
  }
108
110
  interface GeoStats {
109
111
  total_nodes: number;
@@ -112,9 +114,51 @@ interface GeoStats {
112
114
  cities: number;
113
115
  }
114
116
  interface GeoUpdateRequest {
117
+ lat: number;
118
+ lng: number;
119
+ }
120
+ interface GeoAutoDetectResponse {
121
+ success: boolean;
122
+ address: string;
123
+ role: "validator" | "delegator";
115
124
  latitude: number;
116
125
  longitude: number;
117
- node_type: string;
126
+ country: string;
127
+ city: string;
128
+ is_online: boolean;
129
+ }
130
+ interface UserProfile {
131
+ address: string;
132
+ roles: ("validator" | "delegator")[];
133
+ validator?: ValidatorProfileInfo;
134
+ delegations?: DelegationInfo[];
135
+ total_delegation_stake: string;
136
+ total_pending_rewards: string;
137
+ avatar_url?: string;
138
+ geo?: GeoLocation;
139
+ }
140
+ interface ValidatorProfileInfo {
141
+ address: string;
142
+ moniker: string;
143
+ self_stake: string;
144
+ total_stake: string;
145
+ commission_rate: number;
146
+ delegator_count: number;
147
+ claimable_reward: string;
148
+ apr: number;
149
+ }
150
+ interface DelegationInfo {
151
+ validator_address: string;
152
+ validator_moniker: string;
153
+ stake_amount: string;
154
+ pending_rewards: string;
155
+ apr: number;
156
+ }
157
+ interface GeoLocation {
158
+ lat: number;
159
+ lng: number;
160
+ country: string;
161
+ city?: string;
118
162
  }
119
163
  interface NetworkStats {
120
164
  total_validators: number;
@@ -255,9 +299,9 @@ declare class ResonanceClient {
255
299
  verify(params: AuthVerifyRequest): Promise<AuthResponse>;
256
300
  /**
257
301
  * Refresh the access token using the refresh token cookie.
258
- * Returns true if refresh was successful.
302
+ * Returns { success: boolean, expires_at?: number }
259
303
  */
260
- refresh(): Promise<boolean>;
304
+ refresh(): Promise<RefreshResponse>;
261
305
  /**
262
306
  * Logout and revoke current session.
263
307
  */
@@ -277,10 +321,36 @@ declare class ResonanceClient {
277
321
  getReferralKey(key: string): Promise<ReferralKey>;
278
322
  getValidatorKeys(address: Address): Promise<ReferralKey[]>;
279
323
  checkWhitelist(data: WhitelistCheckRequest): Promise<WhitelistCheckResponse>;
280
- getGeoNodes(): Promise<GeoNode[]>;
281
- getGeoValidators(): Promise<GeoNode[]>;
324
+ /**
325
+ * Get user profile with roles, validator info, delegations, avatar, and geo
326
+ * @param address The user wallet address
327
+ */
328
+ getUserProfile(address: Address): Promise<UserProfile>;
329
+ /**
330
+ * Get user avatar URL
331
+ * @param address The user wallet address
332
+ */
333
+ getUserAvatar(address: Address): Promise<{
334
+ url: string;
335
+ }>;
336
+ /**
337
+ * Upload user avatar
338
+ * @param address The user wallet address (must match authenticated user)
339
+ * @param file The image file to upload (png, jpg, or webp)
340
+ */
341
+ uploadUserAvatar(address: Address, file: File): Promise<UploadResponse>;
342
+ /**
343
+ * Get all geo nodes, optionally filtered by role
344
+ * @param role Optional filter: "validator" or "delegator"
345
+ */
346
+ getGeoNodes(role?: "validator" | "delegator"): Promise<GeoNode[]>;
282
347
  getGeoStats(): Promise<GeoStats>;
283
348
  updateGeoLocation(data: GeoUpdateRequest): Promise<void>;
349
+ /**
350
+ * Auto-detect user geo location from IP and save to server.
351
+ * Should be called after successful login.
352
+ */
353
+ autoDetectGeo(): Promise<GeoAutoDetectResponse>;
284
354
  getNetworkStats(): Promise<NetworkStats>;
285
355
  getCurrentEpoch(): Promise<EpochInfo>;
286
356
  getNetworkAPR(): Promise<NetworkAPR>;
@@ -375,4 +445,4 @@ declare class EventBus {
375
445
  }
376
446
  declare const eventBus: EventBus;
377
447
 
378
- export { type APIErrorResponse, type Address, type AuthResponse, type AuthVerifyRequest, type AvatarResponse, type DailyBlockStats, type Delegator, type DelegatorRewards, type DelegatorStake, DelegatorStatus, type EpochInfo, ErrorCode, type ErrorCodeType, type GeoNode, type GeoStats, type GeoUpdateRequest, type NetworkAPR, type NetworkStats, type NonceResponse, type PaginatedResponse, type PriceResponse, type ReferralKey, type RequestContext, ResonanceClient, type ResonanceClientConfig, ResonanceError, type ResponseContext, type RewardHistory, type Transaction, type TransactionStats, type TransactionsList, type TransactionsParams, type UploadResponse, type Validator, type ValidatorAPR, ValidatorStatus, type ValidatorSummary, type WhitelistCheckRequest, type WhitelistCheckResponse, createResonanceClient, eventBus, hasErrorCode, isAuthError, isNetworkError, isNotFoundError, isResonanceError };
448
+ export { type APIErrorResponse, type Address, type AuthResponse, type AuthVerifyRequest, type AvatarResponse, type DailyBlockStats, type Delegator, type DelegatorRewards, type DelegatorStake, DelegatorStatus, type EpochInfo, ErrorCode, type ErrorCodeType, type GeoNode, type GeoStats, type GeoUpdateRequest, type NetworkAPR, type NetworkStats, type NonceResponse, type PaginatedResponse, type PriceResponse, type ReferralKey, type RefreshResponse, type RequestContext, ResonanceClient, type ResonanceClientConfig, ResonanceError, type ResponseContext, type RewardHistory, type Transaction, type TransactionStats, type TransactionsList, type TransactionsParams, type UploadResponse, type Validator, type ValidatorAPR, ValidatorStatus, type ValidatorSummary, type WhitelistCheckRequest, type WhitelistCheckResponse, createResonanceClient, eventBus, hasErrorCode, isAuthError, isNetworkError, isNotFoundError, isResonanceError };
package/dist/index.js CHANGED
@@ -349,7 +349,7 @@ var ResonanceClient = class {
349
349
  }
350
350
  /**
351
351
  * Refresh the access token using the refresh token cookie.
352
- * Returns true if refresh was successful.
352
+ * Returns { success: boolean, expires_at?: number }
353
353
  */
354
354
  async refresh() {
355
355
  try {
@@ -361,11 +361,14 @@ var ResonanceClient = class {
361
361
  });
362
362
  if (response.ok) {
363
363
  const data = await response.json();
364
- return data.success === true;
364
+ return {
365
+ success: data.success === true,
366
+ expires_at: data.expires_at
367
+ };
365
368
  }
366
- return false;
369
+ return { success: false };
367
370
  } catch {
368
- return false;
371
+ return { success: false };
369
372
  }
370
373
  }
371
374
  /**
@@ -442,13 +445,60 @@ var ResonanceClient = class {
442
445
  });
443
446
  }
444
447
  // ============================================
445
- // Geo
448
+ // User Profile
446
449
  // ============================================
447
- async getGeoNodes() {
448
- return this.request("/eth/v1/geo/nodes");
450
+ /**
451
+ * Get user profile with roles, validator info, delegations, avatar, and geo
452
+ * @param address The user wallet address
453
+ */
454
+ async getUserProfile(address) {
455
+ return this.request(`/eth/v1/user/${address}/profile`);
449
456
  }
450
- async getGeoValidators() {
451
- return this.request("/eth/v1/geo/validators");
457
+ /**
458
+ * Get user avatar URL
459
+ * @param address The user wallet address
460
+ */
461
+ async getUserAvatar(address) {
462
+ return this.request(`/eth/v1/user/${address}/avatar`);
463
+ }
464
+ /**
465
+ * Upload user avatar
466
+ * @param address The user wallet address (must match authenticated user)
467
+ * @param file The image file to upload (png, jpg, or webp)
468
+ */
469
+ async uploadUserAvatar(address, file) {
470
+ const formData = new FormData();
471
+ formData.append("file", file);
472
+ const response = await fetch(
473
+ `${this.baseUrl}/eth/v1/user/${address}/avatar`,
474
+ {
475
+ method: "POST",
476
+ credentials: "include",
477
+ // Send httpOnly cookies
478
+ body: formData
479
+ }
480
+ );
481
+ if (!response.ok) {
482
+ const error = await response.json().catch(() => ({ error: "Upload failed" }));
483
+ throw new ResonanceError(
484
+ "UPLOAD_FAILED",
485
+ error.error || "Failed to upload avatar",
486
+ void 0,
487
+ response.status
488
+ );
489
+ }
490
+ return response.json();
491
+ }
492
+ // ============================================
493
+ // Geo
494
+ // ============================================
495
+ /**
496
+ * Get all geo nodes, optionally filtered by role
497
+ * @param role Optional filter: "validator" or "delegator"
498
+ */
499
+ async getGeoNodes(role) {
500
+ const params = role ? `?role=${role}` : "";
501
+ return this.request(`/eth/v1/geo/nodes${params}`);
452
502
  }
453
503
  async getGeoStats() {
454
504
  return this.request("/eth/v1/geo/stats");
@@ -459,6 +509,15 @@ var ResonanceClient = class {
459
509
  body: JSON.stringify(data)
460
510
  });
461
511
  }
512
+ /**
513
+ * Auto-detect user geo location from IP and save to server.
514
+ * Should be called after successful login.
515
+ */
516
+ async autoDetectGeo() {
517
+ return this.request("/eth/v1/geo/auto-detect", {
518
+ method: "POST"
519
+ });
520
+ }
462
521
  // ============================================
463
522
  // Stats
464
523
  // ============================================
package/dist/index.mjs CHANGED
@@ -313,7 +313,7 @@ var ResonanceClient = class {
313
313
  }
314
314
  /**
315
315
  * Refresh the access token using the refresh token cookie.
316
- * Returns true if refresh was successful.
316
+ * Returns { success: boolean, expires_at?: number }
317
317
  */
318
318
  async refresh() {
319
319
  try {
@@ -325,11 +325,14 @@ var ResonanceClient = class {
325
325
  });
326
326
  if (response.ok) {
327
327
  const data = await response.json();
328
- return data.success === true;
328
+ return {
329
+ success: data.success === true,
330
+ expires_at: data.expires_at
331
+ };
329
332
  }
330
- return false;
333
+ return { success: false };
331
334
  } catch {
332
- return false;
335
+ return { success: false };
333
336
  }
334
337
  }
335
338
  /**
@@ -406,13 +409,60 @@ var ResonanceClient = class {
406
409
  });
407
410
  }
408
411
  // ============================================
409
- // Geo
412
+ // User Profile
410
413
  // ============================================
411
- async getGeoNodes() {
412
- return this.request("/eth/v1/geo/nodes");
414
+ /**
415
+ * Get user profile with roles, validator info, delegations, avatar, and geo
416
+ * @param address The user wallet address
417
+ */
418
+ async getUserProfile(address) {
419
+ return this.request(`/eth/v1/user/${address}/profile`);
413
420
  }
414
- async getGeoValidators() {
415
- return this.request("/eth/v1/geo/validators");
421
+ /**
422
+ * Get user avatar URL
423
+ * @param address The user wallet address
424
+ */
425
+ async getUserAvatar(address) {
426
+ return this.request(`/eth/v1/user/${address}/avatar`);
427
+ }
428
+ /**
429
+ * Upload user avatar
430
+ * @param address The user wallet address (must match authenticated user)
431
+ * @param file The image file to upload (png, jpg, or webp)
432
+ */
433
+ async uploadUserAvatar(address, file) {
434
+ const formData = new FormData();
435
+ formData.append("file", file);
436
+ const response = await fetch(
437
+ `${this.baseUrl}/eth/v1/user/${address}/avatar`,
438
+ {
439
+ method: "POST",
440
+ credentials: "include",
441
+ // Send httpOnly cookies
442
+ body: formData
443
+ }
444
+ );
445
+ if (!response.ok) {
446
+ const error = await response.json().catch(() => ({ error: "Upload failed" }));
447
+ throw new ResonanceError(
448
+ "UPLOAD_FAILED",
449
+ error.error || "Failed to upload avatar",
450
+ void 0,
451
+ response.status
452
+ );
453
+ }
454
+ return response.json();
455
+ }
456
+ // ============================================
457
+ // Geo
458
+ // ============================================
459
+ /**
460
+ * Get all geo nodes, optionally filtered by role
461
+ * @param role Optional filter: "validator" or "delegator"
462
+ */
463
+ async getGeoNodes(role) {
464
+ const params = role ? `?role=${role}` : "";
465
+ return this.request(`/eth/v1/geo/nodes${params}`);
416
466
  }
417
467
  async getGeoStats() {
418
468
  return this.request("/eth/v1/geo/stats");
@@ -423,6 +473,15 @@ var ResonanceClient = class {
423
473
  body: JSON.stringify(data)
424
474
  });
425
475
  }
476
+ /**
477
+ * Auto-detect user geo location from IP and save to server.
478
+ * Should be called after successful login.
479
+ */
480
+ async autoDetectGeo() {
481
+ return this.request("/eth/v1/geo/auto-detect", {
482
+ method: "POST"
483
+ });
484
+ }
426
485
  // ============================================
427
486
  // Stats
428
487
  // ============================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fenelabs/fene-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.7.2",
4
4
  "description": "TypeScript SDK for Fene API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -20,6 +20,7 @@
20
20
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
21
21
  "lint": "tsc --noEmit",
22
22
  "test": "vitest run",
23
+ "watch": "esbuild src/app.ts --bundle --sourcemap --outdir=www --servedir=www --watch",
23
24
  "prepublishOnly": "pnpm run build"
24
25
  },
25
26
  "keywords": [
@@ -33,9 +34,17 @@
33
34
  "license": "MIT",
34
35
  "repository": {
35
36
  "type": "git",
36
- "url": "https://github.com/fenelabs/fene-sdk"
37
+ "url": "https://github.com/fenelabs/fene-sdk.git"
38
+ },
39
+ "publishConfig": {
40
+ "registry": "https://registry.npmjs.org/",
41
+ "access": "public"
42
+ },
43
+ "dependencies": {
44
+ "esbuild": ">=0.25.0"
37
45
  },
38
46
  "devDependencies": {
47
+ "esbuild": "^0.25.2",
39
48
  "@types/node": "^25.0.3",
40
49
  "tsup": "^8.0.0",
41
50
  "typescript": "^5.3.0",