@fenelabs/fene-sdk 0.3.7 → 0.4.0
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 +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +92 -4
- package/dist/index.mjs +91 -4
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -207,6 +207,7 @@ declare class ResonanceClient {
|
|
|
207
207
|
private onRequest?;
|
|
208
208
|
private onResponse?;
|
|
209
209
|
private onError?;
|
|
210
|
+
private isRefreshing;
|
|
210
211
|
constructor(config?: ResonanceClientConfig);
|
|
211
212
|
setToken(token: string): void;
|
|
212
213
|
clearToken(): void;
|
|
@@ -214,6 +215,19 @@ declare class ResonanceClient {
|
|
|
214
215
|
private executeRequest;
|
|
215
216
|
getNonce(address: Address): Promise<NonceResponse>;
|
|
216
217
|
verify(params: AuthVerifyRequest): Promise<AuthResponse>;
|
|
218
|
+
/**
|
|
219
|
+
* Refresh the access token using the refresh token cookie.
|
|
220
|
+
* Returns true if refresh was successful.
|
|
221
|
+
*/
|
|
222
|
+
refresh(): Promise<boolean>;
|
|
223
|
+
/**
|
|
224
|
+
* Logout and revoke current session.
|
|
225
|
+
*/
|
|
226
|
+
logout(): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Logout from all devices.
|
|
229
|
+
*/
|
|
230
|
+
logoutAll(): Promise<void>;
|
|
217
231
|
getValidators(): Promise<ValidatorSummary[]>;
|
|
218
232
|
getActiveValidators(): Promise<ValidatorSummary[]>;
|
|
219
233
|
getCandidates(): Promise<ValidatorSummary[]>;
|
|
@@ -310,4 +324,14 @@ declare function isAuthError(error: unknown): boolean;
|
|
|
310
324
|
*/
|
|
311
325
|
declare function isNotFoundError(error: unknown): boolean;
|
|
312
326
|
|
|
313
|
-
|
|
327
|
+
type EventCallback = (data?: any) => void;
|
|
328
|
+
declare class EventBus {
|
|
329
|
+
private listeners;
|
|
330
|
+
on(event: string, callback: EventCallback): void;
|
|
331
|
+
off(event: string, callback: EventCallback): void;
|
|
332
|
+
emit(event: string, data?: any): void;
|
|
333
|
+
clear(): void;
|
|
334
|
+
}
|
|
335
|
+
declare const eventBus: EventBus;
|
|
336
|
+
|
|
337
|
+
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 ReferralKey, type RequestContext, ResonanceClient, type ResonanceClientConfig, ResonanceError, type ResponseContext, type RewardHistory, 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
|
@@ -207,6 +207,7 @@ declare class ResonanceClient {
|
|
|
207
207
|
private onRequest?;
|
|
208
208
|
private onResponse?;
|
|
209
209
|
private onError?;
|
|
210
|
+
private isRefreshing;
|
|
210
211
|
constructor(config?: ResonanceClientConfig);
|
|
211
212
|
setToken(token: string): void;
|
|
212
213
|
clearToken(): void;
|
|
@@ -214,6 +215,19 @@ declare class ResonanceClient {
|
|
|
214
215
|
private executeRequest;
|
|
215
216
|
getNonce(address: Address): Promise<NonceResponse>;
|
|
216
217
|
verify(params: AuthVerifyRequest): Promise<AuthResponse>;
|
|
218
|
+
/**
|
|
219
|
+
* Refresh the access token using the refresh token cookie.
|
|
220
|
+
* Returns true if refresh was successful.
|
|
221
|
+
*/
|
|
222
|
+
refresh(): Promise<boolean>;
|
|
223
|
+
/**
|
|
224
|
+
* Logout and revoke current session.
|
|
225
|
+
*/
|
|
226
|
+
logout(): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Logout from all devices.
|
|
229
|
+
*/
|
|
230
|
+
logoutAll(): Promise<void>;
|
|
217
231
|
getValidators(): Promise<ValidatorSummary[]>;
|
|
218
232
|
getActiveValidators(): Promise<ValidatorSummary[]>;
|
|
219
233
|
getCandidates(): Promise<ValidatorSummary[]>;
|
|
@@ -310,4 +324,14 @@ declare function isAuthError(error: unknown): boolean;
|
|
|
310
324
|
*/
|
|
311
325
|
declare function isNotFoundError(error: unknown): boolean;
|
|
312
326
|
|
|
313
|
-
|
|
327
|
+
type EventCallback = (data?: any) => void;
|
|
328
|
+
declare class EventBus {
|
|
329
|
+
private listeners;
|
|
330
|
+
on(event: string, callback: EventCallback): void;
|
|
331
|
+
off(event: string, callback: EventCallback): void;
|
|
332
|
+
emit(event: string, data?: any): void;
|
|
333
|
+
clear(): void;
|
|
334
|
+
}
|
|
335
|
+
declare const eventBus: EventBus;
|
|
336
|
+
|
|
337
|
+
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 ReferralKey, type RequestContext, ResonanceClient, type ResonanceClientConfig, ResonanceError, type ResponseContext, type RewardHistory, 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
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
ResonanceClient: () => ResonanceClient,
|
|
25
25
|
ResonanceError: () => ResonanceError,
|
|
26
26
|
createResonanceClient: () => createResonanceClient,
|
|
27
|
+
eventBus: () => eventBus,
|
|
27
28
|
hasErrorCode: () => hasErrorCode,
|
|
28
29
|
isAuthError: () => isAuthError,
|
|
29
30
|
isNetworkError: () => isNetworkError,
|
|
@@ -112,6 +113,35 @@ function isNotFoundError(error) {
|
|
|
112
113
|
return false;
|
|
113
114
|
}
|
|
114
115
|
|
|
116
|
+
// src/eventBus.ts
|
|
117
|
+
var EventBus = class {
|
|
118
|
+
constructor() {
|
|
119
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
120
|
+
}
|
|
121
|
+
on(event, callback) {
|
|
122
|
+
if (!this.listeners.has(event)) {
|
|
123
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
124
|
+
}
|
|
125
|
+
this.listeners.get(event).add(callback);
|
|
126
|
+
}
|
|
127
|
+
off(event, callback) {
|
|
128
|
+
this.listeners.get(event)?.delete(callback);
|
|
129
|
+
}
|
|
130
|
+
emit(event, data) {
|
|
131
|
+
this.listeners.get(event)?.forEach((cb) => {
|
|
132
|
+
try {
|
|
133
|
+
cb(data);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error(`EventBus error in ${event} handler:`, error);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
clear() {
|
|
140
|
+
this.listeners.clear();
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
var eventBus = new EventBus();
|
|
144
|
+
|
|
115
145
|
// src/client.ts
|
|
116
146
|
var import_meta = {};
|
|
117
147
|
var DEFAULT_CONFIG = {
|
|
@@ -146,6 +176,7 @@ function getEnv(key) {
|
|
|
146
176
|
}
|
|
147
177
|
var ResonanceClient = class {
|
|
148
178
|
constructor(config = {}) {
|
|
179
|
+
this.isRefreshing = false;
|
|
149
180
|
validateConfig(config);
|
|
150
181
|
const defaultUrl = "http://localhost:8080";
|
|
151
182
|
const envUrl = getEnv(ENV_API_URL);
|
|
@@ -219,11 +250,20 @@ var ResonanceClient = class {
|
|
|
219
250
|
const response = await fetch(url, {
|
|
220
251
|
...options,
|
|
221
252
|
headers,
|
|
253
|
+
credentials: "include",
|
|
254
|
+
// ✅ Send httpOnly cookies automatically
|
|
222
255
|
signal: controller.signal
|
|
223
256
|
});
|
|
224
257
|
clearTimeout(timeoutId);
|
|
225
258
|
const duration = Date.now() - startTime;
|
|
226
|
-
if (response.status === 401) {
|
|
259
|
+
if (response.status === 401 && !this.isRefreshing) {
|
|
260
|
+
this.isRefreshing = true;
|
|
261
|
+
const refreshed = await this.refresh();
|
|
262
|
+
this.isRefreshing = false;
|
|
263
|
+
if (refreshed) {
|
|
264
|
+
return this.executeRequest(path, options, attemptNumber);
|
|
265
|
+
}
|
|
266
|
+
eventBus.emit("api:unauthorized", { url, method: options.method || "GET" });
|
|
227
267
|
this.onTokenExpired?.();
|
|
228
268
|
}
|
|
229
269
|
if (!response.ok) {
|
|
@@ -295,7 +335,7 @@ var ResonanceClient = class {
|
|
|
295
335
|
return this.request(`/eth/v1/auth/nonce?address=${address}`);
|
|
296
336
|
}
|
|
297
337
|
async verify(params) {
|
|
298
|
-
|
|
338
|
+
return this.request("/eth/v1/auth/verify", {
|
|
299
339
|
method: "POST",
|
|
300
340
|
body: JSON.stringify({
|
|
301
341
|
address: params.address,
|
|
@@ -303,8 +343,55 @@ var ResonanceClient = class {
|
|
|
303
343
|
nonce: params.nonce
|
|
304
344
|
})
|
|
305
345
|
});
|
|
306
|
-
|
|
307
|
-
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Refresh the access token using the refresh token cookie.
|
|
349
|
+
* Returns true if refresh was successful.
|
|
350
|
+
*/
|
|
351
|
+
async refresh() {
|
|
352
|
+
try {
|
|
353
|
+
const response = await fetch(`${this.baseUrl}/eth/v1/auth/refresh`, {
|
|
354
|
+
method: "POST",
|
|
355
|
+
credentials: "include",
|
|
356
|
+
// Send refresh_token cookie
|
|
357
|
+
headers: { "Content-Type": "application/json" }
|
|
358
|
+
});
|
|
359
|
+
if (response.ok) {
|
|
360
|
+
const data = await response.json();
|
|
361
|
+
return data.success === true;
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
364
|
+
} catch {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Logout and revoke current session.
|
|
370
|
+
*/
|
|
371
|
+
async logout() {
|
|
372
|
+
try {
|
|
373
|
+
await fetch(`${this.baseUrl}/eth/v1/auth/logout`, {
|
|
374
|
+
method: "POST",
|
|
375
|
+
credentials: "include",
|
|
376
|
+
headers: { "Content-Type": "application/json" }
|
|
377
|
+
});
|
|
378
|
+
} catch {
|
|
379
|
+
}
|
|
380
|
+
this.token = void 0;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Logout from all devices.
|
|
384
|
+
*/
|
|
385
|
+
async logoutAll() {
|
|
386
|
+
try {
|
|
387
|
+
await fetch(`${this.baseUrl}/eth/v1/auth/logout-all`, {
|
|
388
|
+
method: "POST",
|
|
389
|
+
credentials: "include",
|
|
390
|
+
headers: { "Content-Type": "application/json" }
|
|
391
|
+
});
|
|
392
|
+
} catch {
|
|
393
|
+
}
|
|
394
|
+
this.token = void 0;
|
|
308
395
|
}
|
|
309
396
|
// ============================================
|
|
310
397
|
// Validators
|
|
@@ -430,6 +517,7 @@ function createResonanceClient(config) {
|
|
|
430
517
|
ResonanceClient,
|
|
431
518
|
ResonanceError,
|
|
432
519
|
createResonanceClient,
|
|
520
|
+
eventBus,
|
|
433
521
|
hasErrorCode,
|
|
434
522
|
isAuthError,
|
|
435
523
|
isNetworkError,
|
package/dist/index.mjs
CHANGED
|
@@ -78,6 +78,35 @@ function isNotFoundError(error) {
|
|
|
78
78
|
return false;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
// src/eventBus.ts
|
|
82
|
+
var EventBus = class {
|
|
83
|
+
constructor() {
|
|
84
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
85
|
+
}
|
|
86
|
+
on(event, callback) {
|
|
87
|
+
if (!this.listeners.has(event)) {
|
|
88
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
89
|
+
}
|
|
90
|
+
this.listeners.get(event).add(callback);
|
|
91
|
+
}
|
|
92
|
+
off(event, callback) {
|
|
93
|
+
this.listeners.get(event)?.delete(callback);
|
|
94
|
+
}
|
|
95
|
+
emit(event, data) {
|
|
96
|
+
this.listeners.get(event)?.forEach((cb) => {
|
|
97
|
+
try {
|
|
98
|
+
cb(data);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`EventBus error in ${event} handler:`, error);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
clear() {
|
|
105
|
+
this.listeners.clear();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var eventBus = new EventBus();
|
|
109
|
+
|
|
81
110
|
// src/client.ts
|
|
82
111
|
var DEFAULT_CONFIG = {
|
|
83
112
|
timeout: 3e4,
|
|
@@ -111,6 +140,7 @@ function getEnv(key) {
|
|
|
111
140
|
}
|
|
112
141
|
var ResonanceClient = class {
|
|
113
142
|
constructor(config = {}) {
|
|
143
|
+
this.isRefreshing = false;
|
|
114
144
|
validateConfig(config);
|
|
115
145
|
const defaultUrl = "http://localhost:8080";
|
|
116
146
|
const envUrl = getEnv(ENV_API_URL);
|
|
@@ -184,11 +214,20 @@ var ResonanceClient = class {
|
|
|
184
214
|
const response = await fetch(url, {
|
|
185
215
|
...options,
|
|
186
216
|
headers,
|
|
217
|
+
credentials: "include",
|
|
218
|
+
// ✅ Send httpOnly cookies automatically
|
|
187
219
|
signal: controller.signal
|
|
188
220
|
});
|
|
189
221
|
clearTimeout(timeoutId);
|
|
190
222
|
const duration = Date.now() - startTime;
|
|
191
|
-
if (response.status === 401) {
|
|
223
|
+
if (response.status === 401 && !this.isRefreshing) {
|
|
224
|
+
this.isRefreshing = true;
|
|
225
|
+
const refreshed = await this.refresh();
|
|
226
|
+
this.isRefreshing = false;
|
|
227
|
+
if (refreshed) {
|
|
228
|
+
return this.executeRequest(path, options, attemptNumber);
|
|
229
|
+
}
|
|
230
|
+
eventBus.emit("api:unauthorized", { url, method: options.method || "GET" });
|
|
192
231
|
this.onTokenExpired?.();
|
|
193
232
|
}
|
|
194
233
|
if (!response.ok) {
|
|
@@ -260,7 +299,7 @@ var ResonanceClient = class {
|
|
|
260
299
|
return this.request(`/eth/v1/auth/nonce?address=${address}`);
|
|
261
300
|
}
|
|
262
301
|
async verify(params) {
|
|
263
|
-
|
|
302
|
+
return this.request("/eth/v1/auth/verify", {
|
|
264
303
|
method: "POST",
|
|
265
304
|
body: JSON.stringify({
|
|
266
305
|
address: params.address,
|
|
@@ -268,8 +307,55 @@ var ResonanceClient = class {
|
|
|
268
307
|
nonce: params.nonce
|
|
269
308
|
})
|
|
270
309
|
});
|
|
271
|
-
|
|
272
|
-
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Refresh the access token using the refresh token cookie.
|
|
313
|
+
* Returns true if refresh was successful.
|
|
314
|
+
*/
|
|
315
|
+
async refresh() {
|
|
316
|
+
try {
|
|
317
|
+
const response = await fetch(`${this.baseUrl}/eth/v1/auth/refresh`, {
|
|
318
|
+
method: "POST",
|
|
319
|
+
credentials: "include",
|
|
320
|
+
// Send refresh_token cookie
|
|
321
|
+
headers: { "Content-Type": "application/json" }
|
|
322
|
+
});
|
|
323
|
+
if (response.ok) {
|
|
324
|
+
const data = await response.json();
|
|
325
|
+
return data.success === true;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
} catch {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Logout and revoke current session.
|
|
334
|
+
*/
|
|
335
|
+
async logout() {
|
|
336
|
+
try {
|
|
337
|
+
await fetch(`${this.baseUrl}/eth/v1/auth/logout`, {
|
|
338
|
+
method: "POST",
|
|
339
|
+
credentials: "include",
|
|
340
|
+
headers: { "Content-Type": "application/json" }
|
|
341
|
+
});
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
344
|
+
this.token = void 0;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Logout from all devices.
|
|
348
|
+
*/
|
|
349
|
+
async logoutAll() {
|
|
350
|
+
try {
|
|
351
|
+
await fetch(`${this.baseUrl}/eth/v1/auth/logout-all`, {
|
|
352
|
+
method: "POST",
|
|
353
|
+
credentials: "include",
|
|
354
|
+
headers: { "Content-Type": "application/json" }
|
|
355
|
+
});
|
|
356
|
+
} catch {
|
|
357
|
+
}
|
|
358
|
+
this.token = void 0;
|
|
273
359
|
}
|
|
274
360
|
// ============================================
|
|
275
361
|
// Validators
|
|
@@ -394,6 +480,7 @@ export {
|
|
|
394
480
|
ResonanceClient,
|
|
395
481
|
ResonanceError,
|
|
396
482
|
createResonanceClient,
|
|
483
|
+
eventBus,
|
|
397
484
|
hasErrorCode,
|
|
398
485
|
isAuthError,
|
|
399
486
|
isNetworkError,
|