fix(auth): guard OAuth-storage async paths against unhandled rejections

Review follow-ups on the RemoteOAuthStorage web migration:

- useEmaIdpLoginState.logout(): add a .catch to the now-async
  clearEmaIdpSession call so a storage failure no longer surfaces as an
  unhandled rejection; leave loginState unchanged on failure (the session
  was not actually cleared). Add a test asserting no unhandled rejection.
- createOAuthStore: attach a no-op catch to the eager persistLoadPromise
  so a hydration read that fails before any load() awaits it does not
  become an unhandled rejection; real awaiters still observe the rejection
  via the shared reference.
- storage-remote.test: replace `as unknown as typeof fetch` double-casts
  with the typed vi.fn<typeof fetch>() pattern the same PR established.
- remoteOAuthStorage: correct the doc comment to describe the cache-of-one
  accurately instead of implying a keyed map.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-07-08 10:59:40 -04:00
commit ba48e06ffd

View file

@ -40,9 +40,17 @@ export function useEmaIdpLoginState(
const logout = useCallback(() => {
if (!normalizedIssuer) return;
void clearEmaIdpSession(storage, normalizedIssuer).then(() => {
setLoginState("none");
});
void clearEmaIdpSession(storage, normalizedIssuer)
.then(() => {
setLoginState("none");
})
.catch(() => {
// Clearing the persisted IdP session failed (e.g. the storage backend
// is unreachable). Swallow the rejection so it does not surface as an
// unhandled promise, and leave loginState unchanged so the UI keeps
// reflecting the still-present session rather than falsely showing
// signed-out.
});
}, [storage, normalizedIssuer]);
return { loginState, refresh, logout };