@cubee_ee/sdk 0.2.4 → 0.2.6
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.
|
@@ -4,6 +4,16 @@ export interface CubeBackendClientParams {
|
|
|
4
4
|
apiEndpoint: string;
|
|
5
5
|
apiKey?: string;
|
|
6
6
|
defaultHeaders?: Record<string, string>;
|
|
7
|
+
/**
|
|
8
|
+
* Called when tokens are refreshed automatically after a 401.
|
|
9
|
+
* The frontend should persist the new tokens (e.g. to localStorage).
|
|
10
|
+
*/
|
|
11
|
+
onTokenRefreshed?: (tokens: AuthTokens) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Called when both access and refresh tokens are expired/invalid.
|
|
14
|
+
* The frontend should trigger a full re-authentication (SIWS sign-in).
|
|
15
|
+
*/
|
|
16
|
+
onAuthExpired?: () => void;
|
|
7
17
|
}
|
|
8
18
|
export type StatsKind = "tvl" | "volume" | "swap_count" | "avg_swap" | "median_swap" | "fees_lp" | "fees_protocol" | "users_total" | "dau" | "mau" | "deposits" | "removals";
|
|
9
19
|
export type StatsWindow = "1d" | "7d" | "30d" | "all";
|
|
@@ -99,12 +109,47 @@ export interface LeaderboardEpochResponse {
|
|
|
99
109
|
};
|
|
100
110
|
epochs: EpochHistoryEntry[];
|
|
101
111
|
}
|
|
112
|
+
export interface ReferralBindResponse {
|
|
113
|
+
referrer: string;
|
|
114
|
+
bound: true;
|
|
115
|
+
}
|
|
116
|
+
export interface ReferralRates {
|
|
117
|
+
l1Percent: number;
|
|
118
|
+
l2Percent: number;
|
|
119
|
+
}
|
|
120
|
+
export interface ReferralStats {
|
|
121
|
+
totalReferrals: number;
|
|
122
|
+
l1Count: number;
|
|
123
|
+
l2Count: number;
|
|
124
|
+
totalBonusPoints: number;
|
|
125
|
+
l1BonusPoints: number;
|
|
126
|
+
l2BonusPoints: number;
|
|
127
|
+
}
|
|
128
|
+
export interface ReferralStatusResponse {
|
|
129
|
+
referredBy: string | null;
|
|
130
|
+
referralCode: string;
|
|
131
|
+
customCodes: string[];
|
|
132
|
+
rates: ReferralRates;
|
|
133
|
+
stats: ReferralStats;
|
|
134
|
+
}
|
|
135
|
+
export interface ReferralEntry {
|
|
136
|
+
address: string;
|
|
137
|
+
points: number;
|
|
138
|
+
boundAt: string;
|
|
139
|
+
}
|
|
140
|
+
export interface ReferralListResponse {
|
|
141
|
+
total: number;
|
|
142
|
+
page: number;
|
|
143
|
+
limit: number;
|
|
144
|
+
data: ReferralEntry[];
|
|
145
|
+
}
|
|
102
146
|
export interface NonceResponse {
|
|
103
147
|
nonce: string;
|
|
104
148
|
message: string;
|
|
105
149
|
}
|
|
106
|
-
export interface
|
|
150
|
+
export interface AuthTokens {
|
|
107
151
|
accessToken: string;
|
|
152
|
+
refreshToken: string;
|
|
108
153
|
wallet: string;
|
|
109
154
|
expiresIn: string;
|
|
110
155
|
}
|
|
@@ -112,10 +157,18 @@ export interface AuthVerifyResponse {
|
|
|
112
157
|
* REST wrapper around the Cube backend. Every method is a SdkResult; no
|
|
113
158
|
* exceptions escape. If a request fails, the result carries a
|
|
114
159
|
* human-readable error plus the original cause.
|
|
160
|
+
*
|
|
161
|
+
* Auto-refresh: when a request gets 401, the client automatically tries
|
|
162
|
+
* to refresh tokens via POST /api/auth/refresh. If successful, the
|
|
163
|
+
* original request is retried once with the new access token.
|
|
115
164
|
*/
|
|
116
165
|
export declare class CubeBackendClient {
|
|
117
166
|
private readonly endpoint;
|
|
118
167
|
private readonly headers;
|
|
168
|
+
private refreshToken;
|
|
169
|
+
private refreshInFlight;
|
|
170
|
+
private readonly onTokenRefreshed?;
|
|
171
|
+
private readonly onAuthExpired?;
|
|
119
172
|
constructor(params: CubeBackendClientParams);
|
|
120
173
|
listPools(): Promise<SdkResult<PoolSummary[]>>;
|
|
121
174
|
getPool(addr: string): Promise<SdkResult<PoolSummary>>;
|
|
@@ -145,18 +198,57 @@ export declare class CubeBackendClient {
|
|
|
145
198
|
getLeaderboardEpoch(): Promise<SdkResult<LeaderboardEpochResponse>>;
|
|
146
199
|
getTokenPrices(mints: string[]): Promise<SdkResult<PriceMap>>;
|
|
147
200
|
getStats(kind: StatsKind, window?: StatsWindow, poolAddr?: string, unit?: "usd" | "token"): Promise<SdkResult<StatsSeries>>;
|
|
201
|
+
/**
|
|
202
|
+
* Bind the authenticated user as a referral of the given referrer.
|
|
203
|
+
* The code can be a wallet address or a custom referral code.
|
|
204
|
+
* Requires authentication (setTokens must be called first).
|
|
205
|
+
*/
|
|
206
|
+
bindReferral(code: string): Promise<SdkResult<ReferralBindResponse>>;
|
|
207
|
+
/**
|
|
208
|
+
* Get the authenticated user's referral status: referrer, referral code,
|
|
209
|
+
* custom codes, bonus rates (L1/L2 %), and aggregated stats.
|
|
210
|
+
* Requires authentication.
|
|
211
|
+
*/
|
|
212
|
+
getReferralStatus(): Promise<SdkResult<ReferralStatusResponse>>;
|
|
213
|
+
/**
|
|
214
|
+
* Get a paginated list of the authenticated user's direct referrals (L1).
|
|
215
|
+
* Requires authentication.
|
|
216
|
+
*/
|
|
217
|
+
getMyReferrals(page?: number, limit?: number): Promise<SdkResult<ReferralListResponse>>;
|
|
148
218
|
/** Request a SIWS nonce + pre-built message for the given wallet. */
|
|
149
219
|
getNonce(wallet: string): Promise<SdkResult<NonceResponse>>;
|
|
150
|
-
/** Submit signed SIWS message to receive
|
|
151
|
-
verifySignature(message: string, signature: string): Promise<SdkResult<
|
|
152
|
-
/**
|
|
220
|
+
/** Submit signed SIWS message to receive access + refresh tokens. */
|
|
221
|
+
verifySignature(message: string, signature: string): Promise<SdkResult<AuthTokens>>;
|
|
222
|
+
/**
|
|
223
|
+
* Set both tokens. Call this after verifySignature() and on app init
|
|
224
|
+
* (restoring tokens from storage).
|
|
225
|
+
*/
|
|
226
|
+
setTokens(accessToken: string, refreshToken: string): void;
|
|
227
|
+
/** Clear both tokens (logout). */
|
|
228
|
+
clearTokens(): void;
|
|
229
|
+
/** @deprecated Use setTokens() instead. */
|
|
153
230
|
setAccessToken(token: string): void;
|
|
154
|
-
/**
|
|
231
|
+
/** @deprecated Use clearTokens() instead. */
|
|
155
232
|
clearAccessToken(): void;
|
|
156
233
|
/** Generic GET with retry. Callers that need it for other endpoints. */
|
|
157
234
|
get<T>(path: string): Promise<SdkResult<T>>;
|
|
158
235
|
post<T>(path: string, body: unknown): Promise<SdkResult<T>>;
|
|
159
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Core request method with auto-refresh on 401.
|
|
238
|
+
* If a request gets 401 and we have a refresh token:
|
|
239
|
+
* 1. Call POST /api/auth/refresh (deduplicated if concurrent)
|
|
240
|
+
* 2. On success: update tokens, notify via callback, retry original request
|
|
241
|
+
* 3. On failure: notify via onAuthExpired callback, return original error
|
|
242
|
+
*/
|
|
243
|
+
private requestWithRefresh;
|
|
244
|
+
private rawRequest;
|
|
245
|
+
/**
|
|
246
|
+
* Attempt to refresh tokens. Returns true if successful.
|
|
247
|
+
* Deduplicates concurrent refresh attempts.
|
|
248
|
+
*/
|
|
249
|
+
private tryRefresh;
|
|
250
|
+
private doRefresh;
|
|
251
|
+
private is401;
|
|
160
252
|
/**
|
|
161
253
|
* Fetch a response envelope of the form `{ data: T, ... }` and unwrap
|
|
162
254
|
* the `.data` field. The existing Cube backend wraps most endpoints
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CubeBackendClient.d.ts","sourceRoot":"","sources":["../../src/clients/CubeBackendClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAW,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"CubeBackendClient.d.ts","sourceRoot":"","sources":["../../src/clients/CubeBackendClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,15 +7,23 @@ const retry_1 = require("../utils/retry");
|
|
|
7
7
|
* REST wrapper around the Cube backend. Every method is a SdkResult; no
|
|
8
8
|
* exceptions escape. If a request fails, the result carries a
|
|
9
9
|
* human-readable error plus the original cause.
|
|
10
|
+
*
|
|
11
|
+
* Auto-refresh: when a request gets 401, the client automatically tries
|
|
12
|
+
* to refresh tokens via POST /api/auth/refresh. If successful, the
|
|
13
|
+
* original request is retried once with the new access token.
|
|
10
14
|
*/
|
|
11
15
|
class CubeBackendClient {
|
|
12
16
|
constructor(params) {
|
|
17
|
+
this.refreshToken = null;
|
|
18
|
+
this.refreshInFlight = null;
|
|
13
19
|
this.endpoint = params.apiEndpoint.replace(/\/$/, "");
|
|
14
20
|
this.headers = {
|
|
15
21
|
"Content-Type": "application/json",
|
|
16
22
|
...(params.apiKey ? { Authorization: `Bearer ${params.apiKey}` } : {}),
|
|
17
23
|
...(params.defaultHeaders ?? {}),
|
|
18
24
|
};
|
|
25
|
+
this.onTokenRefreshed = params.onTokenRefreshed;
|
|
26
|
+
this.onAuthExpired = params.onAuthExpired;
|
|
19
27
|
}
|
|
20
28
|
listPools() {
|
|
21
29
|
return this.get("/api/pools");
|
|
@@ -101,34 +109,96 @@ class CubeBackendClient {
|
|
|
101
109
|
qs.set("pool", poolAddr);
|
|
102
110
|
return this.get(`/api/stats/${kind}?${qs.toString()}`);
|
|
103
111
|
}
|
|
112
|
+
// ── Referral ──
|
|
113
|
+
/**
|
|
114
|
+
* Bind the authenticated user as a referral of the given referrer.
|
|
115
|
+
* The code can be a wallet address or a custom referral code.
|
|
116
|
+
* Requires authentication (setTokens must be called first).
|
|
117
|
+
*/
|
|
118
|
+
bindReferral(code) {
|
|
119
|
+
return this.post("/api/referral/bind", { code });
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the authenticated user's referral status: referrer, referral code,
|
|
123
|
+
* custom codes, bonus rates (L1/L2 %), and aggregated stats.
|
|
124
|
+
* Requires authentication.
|
|
125
|
+
*/
|
|
126
|
+
getReferralStatus() {
|
|
127
|
+
return this.get("/api/referral/my");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get a paginated list of the authenticated user's direct referrals (L1).
|
|
131
|
+
* Requires authentication.
|
|
132
|
+
*/
|
|
133
|
+
getMyReferrals(page = 1, limit = 20) {
|
|
134
|
+
const qs = new URLSearchParams({
|
|
135
|
+
page: String(page),
|
|
136
|
+
limit: String(limit),
|
|
137
|
+
});
|
|
138
|
+
return this.get(`/api/referral/my/referrals?${qs.toString()}`);
|
|
139
|
+
}
|
|
104
140
|
// ── Auth ──
|
|
105
141
|
/** Request a SIWS nonce + pre-built message for the given wallet. */
|
|
106
142
|
getNonce(wallet) {
|
|
107
143
|
return this.get(`/api/auth/nonce?wallet=${encodeURIComponent(wallet)}`);
|
|
108
144
|
}
|
|
109
|
-
/** Submit signed SIWS message to receive
|
|
145
|
+
/** Submit signed SIWS message to receive access + refresh tokens. */
|
|
110
146
|
verifySignature(message, signature) {
|
|
111
147
|
return this.post("/api/auth/verify", {
|
|
112
148
|
message,
|
|
113
149
|
signature,
|
|
114
150
|
});
|
|
115
151
|
}
|
|
116
|
-
/**
|
|
152
|
+
/**
|
|
153
|
+
* Set both tokens. Call this after verifySignature() and on app init
|
|
154
|
+
* (restoring tokens from storage).
|
|
155
|
+
*/
|
|
156
|
+
setTokens(accessToken, refreshToken) {
|
|
157
|
+
this.headers["Authorization"] = `Bearer ${accessToken}`;
|
|
158
|
+
this.refreshToken = refreshToken;
|
|
159
|
+
}
|
|
160
|
+
/** Clear both tokens (logout). */
|
|
161
|
+
clearTokens() {
|
|
162
|
+
delete this.headers["Authorization"];
|
|
163
|
+
this.refreshToken = null;
|
|
164
|
+
}
|
|
165
|
+
/** @deprecated Use setTokens() instead. */
|
|
117
166
|
setAccessToken(token) {
|
|
118
167
|
this.headers["Authorization"] = `Bearer ${token}`;
|
|
119
168
|
}
|
|
120
|
-
/**
|
|
169
|
+
/** @deprecated Use clearTokens() instead. */
|
|
121
170
|
clearAccessToken() {
|
|
122
171
|
delete this.headers["Authorization"];
|
|
172
|
+
this.refreshToken = null;
|
|
123
173
|
}
|
|
124
174
|
/** Generic GET with retry. Callers that need it for other endpoints. */
|
|
125
175
|
get(path) {
|
|
126
|
-
return this.
|
|
176
|
+
return this.requestWithRefresh("GET", path);
|
|
127
177
|
}
|
|
128
178
|
post(path, body) {
|
|
129
|
-
return this.
|
|
179
|
+
return this.requestWithRefresh("POST", path, body);
|
|
180
|
+
}
|
|
181
|
+
// ── Private: HTTP layer with auto-refresh ──
|
|
182
|
+
/**
|
|
183
|
+
* Core request method with auto-refresh on 401.
|
|
184
|
+
* If a request gets 401 and we have a refresh token:
|
|
185
|
+
* 1. Call POST /api/auth/refresh (deduplicated if concurrent)
|
|
186
|
+
* 2. On success: update tokens, notify via callback, retry original request
|
|
187
|
+
* 3. On failure: notify via onAuthExpired callback, return original error
|
|
188
|
+
*/
|
|
189
|
+
async requestWithRefresh(method, path, body) {
|
|
190
|
+
const result = await this.rawRequest(method, path, body);
|
|
191
|
+
// Don't auto-refresh for auth endpoints themselves
|
|
192
|
+
const isAuthPath = path.startsWith("/api/auth/");
|
|
193
|
+
if (!isAuthPath && !result.ok && this.is401(result) && this.refreshToken) {
|
|
194
|
+
const refreshed = await this.tryRefresh();
|
|
195
|
+
if (refreshed) {
|
|
196
|
+
return this.rawRequest(method, path, body);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
130
200
|
}
|
|
131
|
-
async
|
|
201
|
+
async rawRequest(method, path, body) {
|
|
132
202
|
const url = `${this.endpoint}${path}`;
|
|
133
203
|
const fetchOpts = {
|
|
134
204
|
method,
|
|
@@ -138,7 +208,9 @@ class CubeBackendClient {
|
|
|
138
208
|
const raw = await (0, retry_1.safeCall)(async () => {
|
|
139
209
|
const res = await fetch(url, fetchOpts);
|
|
140
210
|
if (!res.ok) {
|
|
141
|
-
|
|
211
|
+
const error = new Error(`${method} ${path} → HTTP ${res.status} ${res.statusText}`);
|
|
212
|
+
error.status = res.status;
|
|
213
|
+
throw error;
|
|
142
214
|
}
|
|
143
215
|
return (await res.json());
|
|
144
216
|
});
|
|
@@ -146,6 +218,42 @@ class CubeBackendClient {
|
|
|
146
218
|
return raw;
|
|
147
219
|
return (0, result_1.ok)(raw.data);
|
|
148
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Attempt to refresh tokens. Returns true if successful.
|
|
223
|
+
* Deduplicates concurrent refresh attempts.
|
|
224
|
+
*/
|
|
225
|
+
async tryRefresh() {
|
|
226
|
+
// Deduplicate: if a refresh is already in flight, wait for it
|
|
227
|
+
if (this.refreshInFlight) {
|
|
228
|
+
return this.refreshInFlight;
|
|
229
|
+
}
|
|
230
|
+
this.refreshInFlight = this.doRefresh();
|
|
231
|
+
try {
|
|
232
|
+
return await this.refreshInFlight;
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
this.refreshInFlight = null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async doRefresh() {
|
|
239
|
+
const res = await this.rawRequest("POST", "/api/auth/refresh", {
|
|
240
|
+
refreshToken: this.refreshToken,
|
|
241
|
+
});
|
|
242
|
+
if (res.ok) {
|
|
243
|
+
this.setTokens(res.data.accessToken, res.data.refreshToken);
|
|
244
|
+
this.onTokenRefreshed?.(res.data);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
// Refresh failed — both tokens are dead
|
|
248
|
+
this.clearTokens();
|
|
249
|
+
this.onAuthExpired?.();
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
is401(result) {
|
|
253
|
+
if (result.ok)
|
|
254
|
+
return false;
|
|
255
|
+
return result.error.humanMessage.includes("HTTP 401");
|
|
256
|
+
}
|
|
149
257
|
/**
|
|
150
258
|
* Fetch a response envelope of the form `{ data: T, ... }` and unwrap
|
|
151
259
|
* the `.data` field. The existing Cube backend wraps most endpoints
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CubeBackendClient.js","sourceRoot":"","sources":["../../src/clients/CubeBackendClient.ts"],"names":[],"mappings":";;;AAAA,4CAAqD;AAErD,0CAA0C;
|
|
1
|
+
{"version":3,"file":"CubeBackendClient.js","sourceRoot":"","sources":["../../src/clients/CubeBackendClient.ts"],"names":[],"mappings":";;;AAAA,4CAAqD;AAErD,0CAA0C;AAqM1C;;;;;;;;GAQG;AACH,MAAa,iBAAiB;IAQ5B,YAAY,MAA+B;QALnC,iBAAY,GAAkB,IAAI,CAAC;QACnC,oBAAe,GAA4B,IAAI,CAAC;QAKtD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,GAAG;YACb,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,GAAG,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;SACjC,CAAC;QACF,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAChD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IAC5C,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,GAAG,CAAgB,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,GAAG,CAAc,cAAc,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;;;OAIG;IACH,YAAY,CACV,KAAa,EACb,MAAc;QAEd,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,YAAY,CAAU,cAAc,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,UAAU,CAAI,IAAa;QACzB,OAAO,IAAI,CAAC,aAAa,CAAI,YAAY,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,mBAAmB,CAAI,MAAc,EAAE,MAAc;QACnD,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,YAAY,CAAI,sBAAsB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,YAAY,CAAI,kBAAkB,CAAC,CAAC;IAClD,CAAC;IAED,YAAY,CAAI,MAAc;QAC5B,OAAO,IAAI,CAAC,YAAY,CAAI,+BAA+B,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,YAAY,CAAI,mBAAmB,CAAC,CAAC;IACnD,CAAC;IAED,YAAY,CAAI,QAAgB,EAAE;QAChC,OAAO,IAAI,CAAC,YAAY,CAAI,+BAA+B,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,cAAc,CAAI,IAAY;QAC5B,OAAO,IAAI,CAAC,YAAY,CAAI,cAAc,IAAI,WAAW,CAAC,CAAC;IAC7D,CAAC;IAED,eAAe,CAAI,IAAY,EAAE,QAAgB,EAAE,EAAE,SAAiB,CAAC;QACrE,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC,YAAY,CAAI,cAAc,IAAI,iBAAiB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,YAAY,CACV,OAAe,EACf,QAAgB,EAChB,QAAgB,EAChB,aAAqB,CAAC;QAEtB,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC;YAC7B,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;SAC/B,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,YAAY,CACtB,yBAAyB,EAAE,CAAC,QAAQ,EAAE,EAAE,CACzC,CAAC;IACJ,CAAC;IAED,oBAAoB;IAEpB,cAAc,CACZ,OAAe,CAAC,EAChB,QAAgB,EAAE;QAElB,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC;YAC7B,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACrB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAsB,oBAAoB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,kBAAkB,CAChB,OAAe;QAEf,OAAO,IAAI,CAAC,YAAY,CACtB,yBAAyB,kBAAkB,CAAC,OAAO,CAAC,EAAE,CACvD,CAAC;IACJ,CAAC;IAED,yBAAyB,CACvB,OAAe,EACf,OAAe,CAAC,EAChB,QAAgB,EAAE;QAElB,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC;YAC7B,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACrB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CACb,yBAAyB,kBAAkB,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,QAAQ,EAAE,EAAE,CAChF,CAAC;IACJ,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,GAAG,CAA2B,wBAAwB,CAAC,CAAC;IACtE,CAAC;IAED,cAAc,CAAC,KAAe;QAC5B,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,GAAG,CAAW,eAAe,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,QAAQ,CACN,IAAe,EACf,SAAsB,IAAI,EAC1B,QAAiB,EACjB,OAAwB,KAAK;QAE7B,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,IAAI,QAAQ;YAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,GAAG,CAAc,cAAc,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,iBAAiB;IAEjB;;;;OAIG;IACH,YAAY,CAAC,IAAY;QACvB,OAAO,IAAI,CAAC,IAAI,CAAuB,oBAAoB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;IAED;;;;OAIG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,GAAG,CAAyB,kBAAkB,CAAC,CAAC;IAC9D,CAAC;IAED;;;OAGG;IACH,cAAc,CACZ,OAAe,CAAC,EAChB,QAAgB,EAAE;QAElB,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC;YAC7B,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACrB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CACb,8BAA8B,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC9C,CAAC;IACJ,CAAC;IAED,aAAa;IAEb,qEAAqE;IACrE,QAAQ,CAAC,MAAc;QACrB,OAAO,IAAI,CAAC,GAAG,CACb,0BAA0B,kBAAkB,CAAC,MAAM,CAAC,EAAE,CACvD,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,eAAe,CACb,OAAe,EACf,SAAiB;QAEjB,OAAO,IAAI,CAAC,IAAI,CAAa,kBAAkB,EAAE;YAC/C,OAAO;YACP,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,WAAmB,EAAE,YAAoB;QACjD,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,WAAW,EAAE,CAAC;QACxD,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAED,kCAAkC;IAClC,WAAW;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,2CAA2C;IAC3C,cAAc,CAAC,KAAa;QAC1B,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;IACpD,CAAC;IAED,6CAA6C;IAC7C,gBAAgB;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,wEAAwE;IACxE,GAAG,CAAI,IAAY;QACjB,OAAO,IAAI,CAAC,kBAAkB,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,CAAI,IAAY,EAAE,IAAa;QACjC,OAAO,IAAI,CAAC,kBAAkB,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,8CAA8C;IAE9C;;;;;;OAMG;IACK,KAAK,CAAC,kBAAkB,CAC9B,MAAsB,EACtB,IAAY,EACZ,IAAc;QAEd,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE5D,mDAAmD;QACnD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACzE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,IAAI,CAAC,UAAU,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,UAAU,CACtB,MAAsB,EACtB,IAAY,EACZ,IAAc;QAEd,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAE,CAAC;QACtC,MAAM,SAAS,GAAgB;YAC7B,MAAM;YACN,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC5D,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAA,gBAAQ,EAAC,KAAK,IAAI,EAAE;YACpC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACxC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,KAAK,GAAG,IAAI,KAAK,CACrB,GAAG,MAAM,IAAI,IAAI,WAAW,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAC3D,CAAC;gBACD,KAAa,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;gBACnC,MAAM,KAAK,CAAC;YACd,CAAC;YACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,GAAG,CAAC;QACxB,OAAO,IAAA,WAAE,EAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,UAAU;QACtB,8DAA8D;QAC9D,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,eAAe,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC;QACpC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS;QACrB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,CAAa,MAAM,EAAE,mBAAmB,EAAE;YACzE,YAAY,EAAE,IAAI,CAAC,YAAY;SAChC,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;YACX,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC5D,IAAI,CAAC,gBAAgB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,wCAAwC;QACxC,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,MAA0B;QACtC,IAAI,MAAM,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACxD,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,YAAY,CAAI,IAAY;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAc,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,GAAG,CAAC;QACxB,OAAO,IAAA,WAAE,EAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,aAAa,CAAI,IAAY,EAAE,IAAa;QACxD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAc,IAAI,EAAE,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,GAAG,CAAC;QACxB,OAAO,IAAA,WAAE,EAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,+EAA+E;IACvE,KAAK,CAAC,WAAW,CAAI,IAAY;QACvC,OAAO,IAAI,CAAC,GAAG,CAAI,IAAI,CAAC,CAAC;IAC3B,CAAC;CACF;AArWD,8CAqWC"}
|
package/package.json
CHANGED
|
@@ -6,6 +6,16 @@ export interface CubeBackendClientParams {
|
|
|
6
6
|
apiEndpoint: string;
|
|
7
7
|
apiKey?: string;
|
|
8
8
|
defaultHeaders?: Record<string, string>;
|
|
9
|
+
/**
|
|
10
|
+
* Called when tokens are refreshed automatically after a 401.
|
|
11
|
+
* The frontend should persist the new tokens (e.g. to localStorage).
|
|
12
|
+
*/
|
|
13
|
+
onTokenRefreshed?: (tokens: AuthTokens) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Called when both access and refresh tokens are expired/invalid.
|
|
16
|
+
* The frontend should trigger a full re-authentication (SIWS sign-in).
|
|
17
|
+
*/
|
|
18
|
+
onAuthExpired?: () => void;
|
|
9
19
|
}
|
|
10
20
|
|
|
11
21
|
export type StatsKind =
|
|
@@ -131,6 +141,48 @@ export interface LeaderboardEpochResponse {
|
|
|
131
141
|
epochs: EpochHistoryEntry[];
|
|
132
142
|
}
|
|
133
143
|
|
|
144
|
+
// ── Referral types ──
|
|
145
|
+
|
|
146
|
+
export interface ReferralBindResponse {
|
|
147
|
+
referrer: string;
|
|
148
|
+
bound: true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface ReferralRates {
|
|
152
|
+
l1Percent: number;
|
|
153
|
+
l2Percent: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface ReferralStats {
|
|
157
|
+
totalReferrals: number;
|
|
158
|
+
l1Count: number;
|
|
159
|
+
l2Count: number;
|
|
160
|
+
totalBonusPoints: number;
|
|
161
|
+
l1BonusPoints: number;
|
|
162
|
+
l2BonusPoints: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface ReferralStatusResponse {
|
|
166
|
+
referredBy: string | null;
|
|
167
|
+
referralCode: string;
|
|
168
|
+
customCodes: string[];
|
|
169
|
+
rates: ReferralRates;
|
|
170
|
+
stats: ReferralStats;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface ReferralEntry {
|
|
174
|
+
address: string;
|
|
175
|
+
points: number;
|
|
176
|
+
boundAt: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ReferralListResponse {
|
|
180
|
+
total: number;
|
|
181
|
+
page: number;
|
|
182
|
+
limit: number;
|
|
183
|
+
data: ReferralEntry[];
|
|
184
|
+
}
|
|
185
|
+
|
|
134
186
|
// ── Auth types ──
|
|
135
187
|
|
|
136
188
|
export interface NonceResponse {
|
|
@@ -138,8 +190,9 @@ export interface NonceResponse {
|
|
|
138
190
|
message: string;
|
|
139
191
|
}
|
|
140
192
|
|
|
141
|
-
export interface
|
|
193
|
+
export interface AuthTokens {
|
|
142
194
|
accessToken: string;
|
|
195
|
+
refreshToken: string;
|
|
143
196
|
wallet: string;
|
|
144
197
|
expiresIn: string;
|
|
145
198
|
}
|
|
@@ -148,10 +201,18 @@ export interface AuthVerifyResponse {
|
|
|
148
201
|
* REST wrapper around the Cube backend. Every method is a SdkResult; no
|
|
149
202
|
* exceptions escape. If a request fails, the result carries a
|
|
150
203
|
* human-readable error plus the original cause.
|
|
204
|
+
*
|
|
205
|
+
* Auto-refresh: when a request gets 401, the client automatically tries
|
|
206
|
+
* to refresh tokens via POST /api/auth/refresh. If successful, the
|
|
207
|
+
* original request is retried once with the new access token.
|
|
151
208
|
*/
|
|
152
209
|
export class CubeBackendClient {
|
|
153
210
|
private readonly endpoint: string;
|
|
154
211
|
private readonly headers: Record<string, string>;
|
|
212
|
+
private refreshToken: string | null = null;
|
|
213
|
+
private refreshInFlight: Promise<boolean> | null = null;
|
|
214
|
+
private readonly onTokenRefreshed?: (tokens: AuthTokens) => void;
|
|
215
|
+
private readonly onAuthExpired?: () => void;
|
|
155
216
|
|
|
156
217
|
constructor(params: CubeBackendClientParams) {
|
|
157
218
|
this.endpoint = params.apiEndpoint.replace(/\/$/, "");
|
|
@@ -160,6 +221,8 @@ export class CubeBackendClient {
|
|
|
160
221
|
...(params.apiKey ? { Authorization: `Bearer ${params.apiKey}` } : {}),
|
|
161
222
|
...(params.defaultHeaders ?? {}),
|
|
162
223
|
};
|
|
224
|
+
this.onTokenRefreshed = params.onTokenRefreshed;
|
|
225
|
+
this.onAuthExpired = params.onAuthExpired;
|
|
163
226
|
}
|
|
164
227
|
|
|
165
228
|
listPools(): Promise<SdkResult<PoolSummary[]>> {
|
|
@@ -293,6 +356,43 @@ export class CubeBackendClient {
|
|
|
293
356
|
return this.get<StatsSeries>(`/api/stats/${kind}?${qs.toString()}`);
|
|
294
357
|
}
|
|
295
358
|
|
|
359
|
+
// ── Referral ──
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Bind the authenticated user as a referral of the given referrer.
|
|
363
|
+
* The code can be a wallet address or a custom referral code.
|
|
364
|
+
* Requires authentication (setTokens must be called first).
|
|
365
|
+
*/
|
|
366
|
+
bindReferral(code: string): Promise<SdkResult<ReferralBindResponse>> {
|
|
367
|
+
return this.post<ReferralBindResponse>("/api/referral/bind", { code });
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get the authenticated user's referral status: referrer, referral code,
|
|
372
|
+
* custom codes, bonus rates (L1/L2 %), and aggregated stats.
|
|
373
|
+
* Requires authentication.
|
|
374
|
+
*/
|
|
375
|
+
getReferralStatus(): Promise<SdkResult<ReferralStatusResponse>> {
|
|
376
|
+
return this.get<ReferralStatusResponse>("/api/referral/my");
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get a paginated list of the authenticated user's direct referrals (L1).
|
|
381
|
+
* Requires authentication.
|
|
382
|
+
*/
|
|
383
|
+
getMyReferrals(
|
|
384
|
+
page: number = 1,
|
|
385
|
+
limit: number = 20,
|
|
386
|
+
): Promise<SdkResult<ReferralListResponse>> {
|
|
387
|
+
const qs = new URLSearchParams({
|
|
388
|
+
page: String(page),
|
|
389
|
+
limit: String(limit),
|
|
390
|
+
});
|
|
391
|
+
return this.get<ReferralListResponse>(
|
|
392
|
+
`/api/referral/my/referrals?${qs.toString()}`,
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
296
396
|
// ── Auth ──
|
|
297
397
|
|
|
298
398
|
/** Request a SIWS nonce + pre-built message for the given wallet. */
|
|
@@ -302,37 +402,81 @@ export class CubeBackendClient {
|
|
|
302
402
|
);
|
|
303
403
|
}
|
|
304
404
|
|
|
305
|
-
/** Submit signed SIWS message to receive
|
|
405
|
+
/** Submit signed SIWS message to receive access + refresh tokens. */
|
|
306
406
|
verifySignature(
|
|
307
407
|
message: string,
|
|
308
408
|
signature: string,
|
|
309
|
-
): Promise<SdkResult<
|
|
310
|
-
return this.post<
|
|
409
|
+
): Promise<SdkResult<AuthTokens>> {
|
|
410
|
+
return this.post<AuthTokens>("/api/auth/verify", {
|
|
311
411
|
message,
|
|
312
412
|
signature,
|
|
313
413
|
});
|
|
314
414
|
}
|
|
315
415
|
|
|
316
|
-
/**
|
|
416
|
+
/**
|
|
417
|
+
* Set both tokens. Call this after verifySignature() and on app init
|
|
418
|
+
* (restoring tokens from storage).
|
|
419
|
+
*/
|
|
420
|
+
setTokens(accessToken: string, refreshToken: string): void {
|
|
421
|
+
this.headers["Authorization"] = `Bearer ${accessToken}`;
|
|
422
|
+
this.refreshToken = refreshToken;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Clear both tokens (logout). */
|
|
426
|
+
clearTokens(): void {
|
|
427
|
+
delete this.headers["Authorization"];
|
|
428
|
+
this.refreshToken = null;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** @deprecated Use setTokens() instead. */
|
|
317
432
|
setAccessToken(token: string): void {
|
|
318
433
|
this.headers["Authorization"] = `Bearer ${token}`;
|
|
319
434
|
}
|
|
320
435
|
|
|
321
|
-
/**
|
|
436
|
+
/** @deprecated Use clearTokens() instead. */
|
|
322
437
|
clearAccessToken(): void {
|
|
323
438
|
delete this.headers["Authorization"];
|
|
439
|
+
this.refreshToken = null;
|
|
324
440
|
}
|
|
325
441
|
|
|
326
442
|
/** Generic GET with retry. Callers that need it for other endpoints. */
|
|
327
443
|
get<T>(path: string): Promise<SdkResult<T>> {
|
|
328
|
-
return this.
|
|
444
|
+
return this.requestWithRefresh<T>("GET", path);
|
|
329
445
|
}
|
|
330
446
|
|
|
331
447
|
post<T>(path: string, body: unknown): Promise<SdkResult<T>> {
|
|
332
|
-
return this.
|
|
448
|
+
return this.requestWithRefresh<T>("POST", path, body);
|
|
333
449
|
}
|
|
334
450
|
|
|
335
|
-
|
|
451
|
+
// ── Private: HTTP layer with auto-refresh ──
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Core request method with auto-refresh on 401.
|
|
455
|
+
* If a request gets 401 and we have a refresh token:
|
|
456
|
+
* 1. Call POST /api/auth/refresh (deduplicated if concurrent)
|
|
457
|
+
* 2. On success: update tokens, notify via callback, retry original request
|
|
458
|
+
* 3. On failure: notify via onAuthExpired callback, return original error
|
|
459
|
+
*/
|
|
460
|
+
private async requestWithRefresh<T>(
|
|
461
|
+
method: "GET" | "POST",
|
|
462
|
+
path: string,
|
|
463
|
+
body?: unknown,
|
|
464
|
+
): Promise<SdkResult<T>> {
|
|
465
|
+
const result = await this.rawRequest<T>(method, path, body);
|
|
466
|
+
|
|
467
|
+
// Don't auto-refresh for auth endpoints themselves
|
|
468
|
+
const isAuthPath = path.startsWith("/api/auth/");
|
|
469
|
+
if (!isAuthPath && !result.ok && this.is401(result) && this.refreshToken) {
|
|
470
|
+
const refreshed = await this.tryRefresh();
|
|
471
|
+
if (refreshed) {
|
|
472
|
+
return this.rawRequest<T>(method, path, body);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private async rawRequest<T>(
|
|
336
480
|
method: "GET" | "POST",
|
|
337
481
|
path: string,
|
|
338
482
|
body?: unknown
|
|
@@ -346,7 +490,11 @@ export class CubeBackendClient {
|
|
|
346
490
|
const raw = await safeCall(async () => {
|
|
347
491
|
const res = await fetch(url, fetchOpts);
|
|
348
492
|
if (!res.ok) {
|
|
349
|
-
|
|
493
|
+
const error = new Error(
|
|
494
|
+
`${method} ${path} → HTTP ${res.status} ${res.statusText}`,
|
|
495
|
+
);
|
|
496
|
+
(error as any).status = res.status;
|
|
497
|
+
throw error;
|
|
350
498
|
}
|
|
351
499
|
return (await res.json()) as T;
|
|
352
500
|
});
|
|
@@ -354,6 +502,46 @@ export class CubeBackendClient {
|
|
|
354
502
|
return ok(raw.data);
|
|
355
503
|
}
|
|
356
504
|
|
|
505
|
+
/**
|
|
506
|
+
* Attempt to refresh tokens. Returns true if successful.
|
|
507
|
+
* Deduplicates concurrent refresh attempts.
|
|
508
|
+
*/
|
|
509
|
+
private async tryRefresh(): Promise<boolean> {
|
|
510
|
+
// Deduplicate: if a refresh is already in flight, wait for it
|
|
511
|
+
if (this.refreshInFlight) {
|
|
512
|
+
return this.refreshInFlight;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
this.refreshInFlight = this.doRefresh();
|
|
516
|
+
try {
|
|
517
|
+
return await this.refreshInFlight;
|
|
518
|
+
} finally {
|
|
519
|
+
this.refreshInFlight = null;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private async doRefresh(): Promise<boolean> {
|
|
524
|
+
const res = await this.rawRequest<AuthTokens>("POST", "/api/auth/refresh", {
|
|
525
|
+
refreshToken: this.refreshToken,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
if (res.ok) {
|
|
529
|
+
this.setTokens(res.data.accessToken, res.data.refreshToken);
|
|
530
|
+
this.onTokenRefreshed?.(res.data);
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Refresh failed — both tokens are dead
|
|
535
|
+
this.clearTokens();
|
|
536
|
+
this.onAuthExpired?.();
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
private is401(result: SdkResult<unknown>): boolean {
|
|
541
|
+
if (result.ok) return false;
|
|
542
|
+
return result.error.humanMessage.includes("HTTP 401");
|
|
543
|
+
}
|
|
544
|
+
|
|
357
545
|
/**
|
|
358
546
|
* Fetch a response envelope of the form `{ data: T, ... }` and unwrap
|
|
359
547
|
* the `.data` field. The existing Cube backend wraps most endpoints
|