()
| 1406 | // then revokes terminal 1 server-side, and terminal 1's memoize never |
| 1407 | // re-reads — infinite /login regress (CC-1096, GH#24317). |
| 1408 | async function invalidateOAuthCacheIfDiskChanged(): Promise<void> { |
| 1409 | try { |
| 1410 | const { mtimeMs } = await stat( |
| 1411 | getExistingPlainTextStoragePath() ?? getPrimaryPlainTextStoragePath(), |
| 1412 | ) |
| 1413 | if (mtimeMs !== lastCredentialsMtimeMs) { |
| 1414 | lastCredentialsMtimeMs = mtimeMs |
| 1415 | clearOAuthTokenCache() |
| 1416 | } |
| 1417 | } catch { |
| 1418 | // ENOENT — macOS keychain path (file deleted on migration). Clear only |
| 1419 | // the memoize so it delegates to the keychain cache's 30s TTL instead |
| 1420 | // of caching forever on top. `security find-generic-password` is |
| 1421 | // ~15ms; bounded to once per 30s by the keychain cache. |
| 1422 | getClaudeAIOAuthTokens.cache?.clear?.() |
| 1423 | } |
| 1424 | } |
| 1425 | |
| 1426 | // In-flight dedup: when N managed proxy connectors hit 401 with the same |
| 1427 | // token simultaneously (common at startup — #20930), only one should clear |
no test coverage detected