@cubee_ee/sdk 0.2.4 → 0.2.5

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";
@@ -103,8 +113,9 @@ export interface NonceResponse {
103
113
  nonce: string;
104
114
  message: string;
105
115
  }
106
- export interface AuthVerifyResponse {
116
+ export interface AuthTokens {
107
117
  accessToken: string;
118
+ refreshToken: string;
108
119
  wallet: string;
109
120
  expiresIn: string;
110
121
  }
@@ -112,10 +123,18 @@ export interface AuthVerifyResponse {
112
123
  * REST wrapper around the Cube backend. Every method is a SdkResult; no
113
124
  * exceptions escape. If a request fails, the result carries a
114
125
  * human-readable error plus the original cause.
126
+ *
127
+ * Auto-refresh: when a request gets 401, the client automatically tries
128
+ * to refresh tokens via POST /api/auth/refresh. If successful, the
129
+ * original request is retried once with the new access token.
115
130
  */
116
131
  export declare class CubeBackendClient {
117
132
  private readonly endpoint;
118
133
  private readonly headers;
134
+ private refreshToken;
135
+ private refreshInFlight;
136
+ private readonly onTokenRefreshed?;
137
+ private readonly onAuthExpired?;
119
138
  constructor(params: CubeBackendClientParams);
120
139
  listPools(): Promise<SdkResult<PoolSummary[]>>;
121
140
  getPool(addr: string): Promise<SdkResult<PoolSummary>>;
@@ -147,16 +166,38 @@ export declare class CubeBackendClient {
147
166
  getStats(kind: StatsKind, window?: StatsWindow, poolAddr?: string, unit?: "usd" | "token"): Promise<SdkResult<StatsSeries>>;
148
167
  /** Request a SIWS nonce + pre-built message for the given wallet. */
149
168
  getNonce(wallet: string): Promise<SdkResult<NonceResponse>>;
150
- /** Submit signed SIWS message to receive a JWT access token. */
151
- verifySignature(message: string, signature: string): Promise<SdkResult<AuthVerifyResponse>>;
152
- /** Set the JWT token for subsequent authenticated requests. */
169
+ /** Submit signed SIWS message to receive access + refresh tokens. */
170
+ verifySignature(message: string, signature: string): Promise<SdkResult<AuthTokens>>;
171
+ /**
172
+ * Set both tokens. Call this after verifySignature() and on app init
173
+ * (restoring tokens from storage).
174
+ */
175
+ setTokens(accessToken: string, refreshToken: string): void;
176
+ /** Clear both tokens (logout). */
177
+ clearTokens(): void;
178
+ /** @deprecated Use setTokens() instead. */
153
179
  setAccessToken(token: string): void;
154
- /** Clear the JWT token (logout). */
180
+ /** @deprecated Use clearTokens() instead. */
155
181
  clearAccessToken(): void;
156
182
  /** Generic GET with retry. Callers that need it for other endpoints. */
157
183
  get<T>(path: string): Promise<SdkResult<T>>;
158
184
  post<T>(path: string, body: unknown): Promise<SdkResult<T>>;
159
- private request;
185
+ /**
186
+ * Core request method with auto-refresh on 401.
187
+ * If a request gets 401 and we have a refresh token:
188
+ * 1. Call POST /api/auth/refresh (deduplicated if concurrent)
189
+ * 2. On success: update tokens, notify via callback, retry original request
190
+ * 3. On failure: notify via onAuthExpired callback, return original error
191
+ */
192
+ private requestWithRefresh;
193
+ private rawRequest;
194
+ /**
195
+ * Attempt to refresh tokens. Returns true if successful.
196
+ * Deduplicates concurrent refresh attempts.
197
+ */
198
+ private tryRefresh;
199
+ private doRefresh;
200
+ private is401;
160
201
  /**
161
202
  * Fetch a response envelope of the form `{ data: T, ... }` and unwrap
162
203
  * 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":"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"}
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");
@@ -106,29 +114,63 @@ class CubeBackendClient {
106
114
  getNonce(wallet) {
107
115
  return this.get(`/api/auth/nonce?wallet=${encodeURIComponent(wallet)}`);
108
116
  }
109
- /** Submit signed SIWS message to receive a JWT access token. */
117
+ /** Submit signed SIWS message to receive access + refresh tokens. */
110
118
  verifySignature(message, signature) {
111
119
  return this.post("/api/auth/verify", {
112
120
  message,
113
121
  signature,
114
122
  });
115
123
  }
116
- /** Set the JWT token for subsequent authenticated requests. */
124
+ /**
125
+ * Set both tokens. Call this after verifySignature() and on app init
126
+ * (restoring tokens from storage).
127
+ */
128
+ setTokens(accessToken, refreshToken) {
129
+ this.headers["Authorization"] = `Bearer ${accessToken}`;
130
+ this.refreshToken = refreshToken;
131
+ }
132
+ /** Clear both tokens (logout). */
133
+ clearTokens() {
134
+ delete this.headers["Authorization"];
135
+ this.refreshToken = null;
136
+ }
137
+ /** @deprecated Use setTokens() instead. */
117
138
  setAccessToken(token) {
118
139
  this.headers["Authorization"] = `Bearer ${token}`;
119
140
  }
120
- /** Clear the JWT token (logout). */
141
+ /** @deprecated Use clearTokens() instead. */
121
142
  clearAccessToken() {
122
143
  delete this.headers["Authorization"];
144
+ this.refreshToken = null;
123
145
  }
124
146
  /** Generic GET with retry. Callers that need it for other endpoints. */
125
147
  get(path) {
126
- return this.request("GET", path);
148
+ return this.requestWithRefresh("GET", path);
127
149
  }
128
150
  post(path, body) {
129
- return this.request("POST", path, body);
151
+ return this.requestWithRefresh("POST", path, body);
130
152
  }
131
- async request(method, path, body) {
153
+ // ── Private: HTTP layer with auto-refresh ──
154
+ /**
155
+ * Core request method with auto-refresh on 401.
156
+ * If a request gets 401 and we have a refresh token:
157
+ * 1. Call POST /api/auth/refresh (deduplicated if concurrent)
158
+ * 2. On success: update tokens, notify via callback, retry original request
159
+ * 3. On failure: notify via onAuthExpired callback, return original error
160
+ */
161
+ async requestWithRefresh(method, path, body) {
162
+ const result = await this.rawRequest(method, path, body);
163
+ // Don't auto-refresh for auth endpoints themselves
164
+ const isAuthPath = path.startsWith("/api/auth/");
165
+ if (!isAuthPath && !result.ok && this.is401(result) && this.refreshToken) {
166
+ const refreshed = await this.tryRefresh();
167
+ if (refreshed) {
168
+ return this.rawRequest(method, path, body);
169
+ }
170
+ }
171
+ return result;
172
+ }
173
+ async rawRequest(method, path, body) {
132
174
  const url = `${this.endpoint}${path}`;
133
175
  const fetchOpts = {
134
176
  method,
@@ -138,7 +180,9 @@ class CubeBackendClient {
138
180
  const raw = await (0, retry_1.safeCall)(async () => {
139
181
  const res = await fetch(url, fetchOpts);
140
182
  if (!res.ok) {
141
- throw new Error(`${method} ${path} → HTTP ${res.status} ${res.statusText}`);
183
+ const error = new Error(`${method} ${path} → HTTP ${res.status} ${res.statusText}`);
184
+ error.status = res.status;
185
+ throw error;
142
186
  }
143
187
  return (await res.json());
144
188
  });
@@ -146,6 +190,42 @@ class CubeBackendClient {
146
190
  return raw;
147
191
  return (0, result_1.ok)(raw.data);
148
192
  }
193
+ /**
194
+ * Attempt to refresh tokens. Returns true if successful.
195
+ * Deduplicates concurrent refresh attempts.
196
+ */
197
+ async tryRefresh() {
198
+ // Deduplicate: if a refresh is already in flight, wait for it
199
+ if (this.refreshInFlight) {
200
+ return this.refreshInFlight;
201
+ }
202
+ this.refreshInFlight = this.doRefresh();
203
+ try {
204
+ return await this.refreshInFlight;
205
+ }
206
+ finally {
207
+ this.refreshInFlight = null;
208
+ }
209
+ }
210
+ async doRefresh() {
211
+ const res = await this.rawRequest("POST", "/api/auth/refresh", {
212
+ refreshToken: this.refreshToken,
213
+ });
214
+ if (res.ok) {
215
+ this.setTokens(res.data.accessToken, res.data.refreshToken);
216
+ this.onTokenRefreshed?.(res.data);
217
+ return true;
218
+ }
219
+ // Refresh failed — both tokens are dead
220
+ this.clearTokens();
221
+ this.onAuthExpired?.();
222
+ return false;
223
+ }
224
+ is401(result) {
225
+ if (result.ok)
226
+ return false;
227
+ return result.error.humanMessage.includes("HTTP 401");
228
+ }
149
229
  /**
150
230
  * Fetch a response envelope of the form `{ data: T, ... }` and unwrap
151
231
  * 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;AAgJ1C;;;;GAIG;AACH,MAAa,iBAAiB;IAI5B,YAAY,MAA+B;QACzC,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;IACJ,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,aAAa;IAEb,qEAAqE;IACrE,QAAQ,CAAC,MAAc;QACrB,OAAO,IAAI,CAAC,GAAG,CACb,0BAA0B,kBAAkB,CAAC,MAAM,CAAC,EAAE,CACvD,CAAC;IACJ,CAAC;IAED,gEAAgE;IAChE,eAAe,CACb,OAAe,EACf,SAAiB;QAEjB,OAAO,IAAI,CAAC,IAAI,CAAqB,kBAAkB,EAAE;YACvD,OAAO;YACP,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,+DAA+D;IAC/D,cAAc,CAAC,KAAa;QAC1B,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;IACpD,CAAC;IAED,oCAAoC;IACpC,gBAAgB;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACvC,CAAC;IAED,wEAAwE;IACxE,GAAG,CAAI,IAAY;QACjB,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,CAAI,IAAY,EAAE,IAAa;QACjC,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,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,IAAI,KAAK,CAAC,GAAG,MAAM,IAAI,IAAI,WAAW,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;YAC9E,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;;;;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;AAlOD,8CAkOC"}
1
+ {"version":3,"file":"CubeBackendClient.js","sourceRoot":"","sources":["../../src/clients/CubeBackendClient.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubee_ee/sdk",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -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 =
@@ -138,8 +148,9 @@ export interface NonceResponse {
138
148
  message: string;
139
149
  }
140
150
 
141
- export interface AuthVerifyResponse {
151
+ export interface AuthTokens {
142
152
  accessToken: string;
153
+ refreshToken: string;
143
154
  wallet: string;
144
155
  expiresIn: string;
145
156
  }
@@ -148,10 +159,18 @@ export interface AuthVerifyResponse {
148
159
  * REST wrapper around the Cube backend. Every method is a SdkResult; no
149
160
  * exceptions escape. If a request fails, the result carries a
150
161
  * human-readable error plus the original cause.
162
+ *
163
+ * Auto-refresh: when a request gets 401, the client automatically tries
164
+ * to refresh tokens via POST /api/auth/refresh. If successful, the
165
+ * original request is retried once with the new access token.
151
166
  */
152
167
  export class CubeBackendClient {
153
168
  private readonly endpoint: string;
154
169
  private readonly headers: Record<string, string>;
170
+ private refreshToken: string | null = null;
171
+ private refreshInFlight: Promise<boolean> | null = null;
172
+ private readonly onTokenRefreshed?: (tokens: AuthTokens) => void;
173
+ private readonly onAuthExpired?: () => void;
155
174
 
156
175
  constructor(params: CubeBackendClientParams) {
157
176
  this.endpoint = params.apiEndpoint.replace(/\/$/, "");
@@ -160,6 +179,8 @@ export class CubeBackendClient {
160
179
  ...(params.apiKey ? { Authorization: `Bearer ${params.apiKey}` } : {}),
161
180
  ...(params.defaultHeaders ?? {}),
162
181
  };
182
+ this.onTokenRefreshed = params.onTokenRefreshed;
183
+ this.onAuthExpired = params.onAuthExpired;
163
184
  }
164
185
 
165
186
  listPools(): Promise<SdkResult<PoolSummary[]>> {
@@ -302,37 +323,81 @@ export class CubeBackendClient {
302
323
  );
303
324
  }
304
325
 
305
- /** Submit signed SIWS message to receive a JWT access token. */
326
+ /** Submit signed SIWS message to receive access + refresh tokens. */
306
327
  verifySignature(
307
328
  message: string,
308
329
  signature: string,
309
- ): Promise<SdkResult<AuthVerifyResponse>> {
310
- return this.post<AuthVerifyResponse>("/api/auth/verify", {
330
+ ): Promise<SdkResult<AuthTokens>> {
331
+ return this.post<AuthTokens>("/api/auth/verify", {
311
332
  message,
312
333
  signature,
313
334
  });
314
335
  }
315
336
 
316
- /** Set the JWT token for subsequent authenticated requests. */
337
+ /**
338
+ * Set both tokens. Call this after verifySignature() and on app init
339
+ * (restoring tokens from storage).
340
+ */
341
+ setTokens(accessToken: string, refreshToken: string): void {
342
+ this.headers["Authorization"] = `Bearer ${accessToken}`;
343
+ this.refreshToken = refreshToken;
344
+ }
345
+
346
+ /** Clear both tokens (logout). */
347
+ clearTokens(): void {
348
+ delete this.headers["Authorization"];
349
+ this.refreshToken = null;
350
+ }
351
+
352
+ /** @deprecated Use setTokens() instead. */
317
353
  setAccessToken(token: string): void {
318
354
  this.headers["Authorization"] = `Bearer ${token}`;
319
355
  }
320
356
 
321
- /** Clear the JWT token (logout). */
357
+ /** @deprecated Use clearTokens() instead. */
322
358
  clearAccessToken(): void {
323
359
  delete this.headers["Authorization"];
360
+ this.refreshToken = null;
324
361
  }
325
362
 
326
363
  /** Generic GET with retry. Callers that need it for other endpoints. */
327
364
  get<T>(path: string): Promise<SdkResult<T>> {
328
- return this.request<T>("GET", path);
365
+ return this.requestWithRefresh<T>("GET", path);
329
366
  }
330
367
 
331
368
  post<T>(path: string, body: unknown): Promise<SdkResult<T>> {
332
- return this.request<T>("POST", path, body);
369
+ return this.requestWithRefresh<T>("POST", path, body);
370
+ }
371
+
372
+ // ── Private: HTTP layer with auto-refresh ──
373
+
374
+ /**
375
+ * Core request method with auto-refresh on 401.
376
+ * If a request gets 401 and we have a refresh token:
377
+ * 1. Call POST /api/auth/refresh (deduplicated if concurrent)
378
+ * 2. On success: update tokens, notify via callback, retry original request
379
+ * 3. On failure: notify via onAuthExpired callback, return original error
380
+ */
381
+ private async requestWithRefresh<T>(
382
+ method: "GET" | "POST",
383
+ path: string,
384
+ body?: unknown,
385
+ ): Promise<SdkResult<T>> {
386
+ const result = await this.rawRequest<T>(method, path, body);
387
+
388
+ // Don't auto-refresh for auth endpoints themselves
389
+ const isAuthPath = path.startsWith("/api/auth/");
390
+ if (!isAuthPath && !result.ok && this.is401(result) && this.refreshToken) {
391
+ const refreshed = await this.tryRefresh();
392
+ if (refreshed) {
393
+ return this.rawRequest<T>(method, path, body);
394
+ }
395
+ }
396
+
397
+ return result;
333
398
  }
334
399
 
335
- private async request<T>(
400
+ private async rawRequest<T>(
336
401
  method: "GET" | "POST",
337
402
  path: string,
338
403
  body?: unknown
@@ -346,7 +411,11 @@ export class CubeBackendClient {
346
411
  const raw = await safeCall(async () => {
347
412
  const res = await fetch(url, fetchOpts);
348
413
  if (!res.ok) {
349
- throw new Error(`${method} ${path} → HTTP ${res.status} ${res.statusText}`);
414
+ const error = new Error(
415
+ `${method} ${path} → HTTP ${res.status} ${res.statusText}`,
416
+ );
417
+ (error as any).status = res.status;
418
+ throw error;
350
419
  }
351
420
  return (await res.json()) as T;
352
421
  });
@@ -354,6 +423,46 @@ export class CubeBackendClient {
354
423
  return ok(raw.data);
355
424
  }
356
425
 
426
+ /**
427
+ * Attempt to refresh tokens. Returns true if successful.
428
+ * Deduplicates concurrent refresh attempts.
429
+ */
430
+ private async tryRefresh(): Promise<boolean> {
431
+ // Deduplicate: if a refresh is already in flight, wait for it
432
+ if (this.refreshInFlight) {
433
+ return this.refreshInFlight;
434
+ }
435
+
436
+ this.refreshInFlight = this.doRefresh();
437
+ try {
438
+ return await this.refreshInFlight;
439
+ } finally {
440
+ this.refreshInFlight = null;
441
+ }
442
+ }
443
+
444
+ private async doRefresh(): Promise<boolean> {
445
+ const res = await this.rawRequest<AuthTokens>("POST", "/api/auth/refresh", {
446
+ refreshToken: this.refreshToken,
447
+ });
448
+
449
+ if (res.ok) {
450
+ this.setTokens(res.data.accessToken, res.data.refreshToken);
451
+ this.onTokenRefreshed?.(res.data);
452
+ return true;
453
+ }
454
+
455
+ // Refresh failed — both tokens are dead
456
+ this.clearTokens();
457
+ this.onAuthExpired?.();
458
+ return false;
459
+ }
460
+
461
+ private is401(result: SdkResult<unknown>): boolean {
462
+ if (result.ok) return false;
463
+ return result.error.humanMessage.includes("HTTP 401");
464
+ }
465
+
357
466
  /**
358
467
  * Fetch a response envelope of the form `{ data: T, ... }` and unwrap
359
468
  * the `.data` field. The existing Cube backend wraps most endpoints