@rebasepro/client 0.10.1-canary.d8d45b2 → 0.10.1-canary.ff9ccd6

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/auth.d.ts CHANGED
@@ -129,6 +129,7 @@ export declare function createAuth(transport: Transport, options?: CreateAuthOpt
129
129
  }>;
130
130
  signOut: () => Promise<void>;
131
131
  refreshSession: () => Promise<RebaseSession>;
132
+ handleUnauthorized: () => Promise<boolean>;
132
133
  getUser: () => Promise<User>;
133
134
  findUserByEmail: (email: string) => Promise<PublicUserProfile | null>;
134
135
  updateUser: (updates: {
package/dist/index.es.js CHANGED
@@ -321,6 +321,34 @@ function createAuth(transport, options) {
321
321
  transport.setToken(null);
322
322
  emit("SIGNED_OUT", null);
323
323
  }
324
+ /**
325
+ * Recover from a 401 on an ordinary API request.
326
+ *
327
+ * Returns `true` when the caller should retry — we minted a fresh access
328
+ * token. When the refresh is rejected *fatally* (the refresh token itself
329
+ * is invalid, expired or revoked) this client can no longer act as the
330
+ * user at all, so we drop the session and emit `SIGNED_OUT`. UIs gate on
331
+ * that event, so they show their login screen instead of leaving the user
332
+ * staring at "Invalid or expired token" on every view.
333
+ *
334
+ * Transient failures (offline, 5xx, backend restarting) keep the session:
335
+ * the scheduled refresh backs off and retries, and the token is very
336
+ * likely still good once the backend answers again.
337
+ */
338
+ async function handleUnauthorized() {
339
+ if (!currentSession) return false;
340
+ if (authFlowMode !== "cookie" && !currentSession.refreshToken) {
341
+ abandonSessionLocally();
342
+ return false;
343
+ }
344
+ try {
345
+ await refreshSession();
346
+ return true;
347
+ } catch (err) {
348
+ if (isFatalRefreshError(err)) abandonSessionLocally();
349
+ return false;
350
+ }
351
+ }
324
352
  async function attemptScheduledRefresh(attempt) {
325
353
  try {
326
354
  await refreshSession();
@@ -822,6 +850,7 @@ function createAuth(transport, options) {
822
850
  signInWithSpotify,
823
851
  signOut,
824
852
  refreshSession,
853
+ handleUnauthorized,
825
854
  getUser,
826
855
  findUserByEmail,
827
856
  updateUser,
@@ -5040,14 +5069,7 @@ function createRebaseClient(options) {
5040
5069
  } catch (e) {}
5041
5070
  return session?.accessToken || options.token || "";
5042
5071
  },
5043
- onUnauthorized: options.onUnauthorized || (async () => {
5044
- try {
5045
- await auth.refreshSession();
5046
- return true;
5047
- } catch (e) {
5048
- return false;
5049
- }
5050
- })
5072
+ onUnauthorized: options.onUnauthorized || (() => auth.handleUnauthorized())
5051
5073
  });
5052
5074
  auth.onAuthStateChange((event, session) => {
5053
5075
  if (!ws) return;
@@ -5057,14 +5079,7 @@ function createRebaseClient(options) {
5057
5079
  }
5058
5080
  });
5059
5081
  }
5060
- if (!options.onUnauthorized) transport.setOnUnauthorized(async () => {
5061
- try {
5062
- await auth.refreshSession();
5063
- return true;
5064
- } catch (e) {
5065
- return false;
5066
- }
5067
- });
5082
+ if (!options.onUnauthorized) transport.setOnUnauthorized(() => auth.handleUnauthorized());
5068
5083
  /**
5069
5084
  * Suggest the closest known collection key for a mistyped accessor.
5070
5085
  * Uses edit-distance-1 and prefix matching — no external dependency.