SIGN IN SIGN UP

fix: Rate-limit-resilient usage polling + silent token refresh

The /api/oauth/usage endpoint enforces a tight long-window per-account
quota (observed Retry-After values up to 36 minutes, see
anthropics/claude-code#31637). The previous polling pattern - every
saved account fetched back-to-back within ~100ms, on every refresh,
with no backoff - tripped it constantly: in a real 3-account setup,
56% of all usage requests (1113 of 1998) came back 429, and the UI
showed 'API Rate Limited' or 'Token expired' most of the time.

Polling changes:
- Detect 429 as a typed error carrying the Retry-After header value.
- Park a rate-limited account until the server-given deadline
  (floor 60s, cap 1h) instead of hammering it; keep the last known
  usage sample so the UI shows stale percentages, not an error banner.
- Retry once, politely (>=3s), only when Retry-After is short (<=30s);
  long deadlines rethrow and park.
- Round-robin: each cycle fetches the active account plus ONE
  non-active account instead of all of them, with a 1.5s stagger
  between the two requests (bursts reliably got all but one 429'd).
- Re-entrancy guard on refresh() so overlapping refreshes (timer +
  manual + post-switch) cannot double-burst.

Token refresh:
- Non-active backup credentials now refresh in place via a direct
  POST to the OAuth token endpoint (Claude Code's public PKCE client
  id) when they expire - no keychain swap, so no race with running
  Claude Code sessions. Access tokens only live ~8 hours, so without
  this every non-active account sat in a permanent 'Token expired'
  state between switches. A rejected refresh grant (dead/rotated
  refresh token) still surfaces as 'Session expired. Re-authenticate'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
S
Sandor Bogyo committed
72065eb7fe204befbef9cd84b392faf1c3269962
Parent: 1f3b9c8