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

@ -78,6 +78,13 @@ export function createOAuthStore(
resolvePersistLoad = resolve;
rejectPersistLoad = reject;
});
// Zustand kicks off async hydration as soon as the store is created, before
// any consumer calls `OAuthStorageBase.load()`. If that initial read fails
// and no one is awaiting yet, `persistLoadPromise` would reject with no
// handler and surface as an unhandled rejection. Attach a no-op handler so
// the promise is always "handled"; real awaiters still observe the rejection
// through the reference returned by `waitForOAuthStorePersistLoad`.
void persistLoadPromise.catch(() => {});
const settlePersistLoad = (error?: unknown) => {
if (persistLoadSettled) {