fix(ui): login page refresh loop — guard 401 redirect + gate background polls on auth
The global mesh-detection poll (added for the device-detected modal) fired on the login page, 401'd, and the session-expired handler redirected to /login — reloading the page we were already on, forever. Background polls now run only when authenticated, and a 401 never redirects when the path is already /login. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
4e11f80771
commit
23e214a85c
@ -117,8 +117,12 @@ class RPCClient {
|
||||
try { localStorage.removeItem('neode-auth') } catch { /* noop */ }
|
||||
|
||||
const isOnboarding = window.location.pathname.startsWith('/onboarding')
|
||||
// Already on the login page: redirecting = a full reload of the
|
||||
// page we're on. Any background poll that 401s would refresh
|
||||
// /login in a loop forever (seen with the global mesh poll).
|
||||
const isLogin = window.location.pathname.startsWith('/login')
|
||||
console.warn(`[RPC] 401 on ${method} | path=${window.location.pathname} | onboarding=${isOnboarding} | redirecting=${RPCClient._sessionExpiredRedirecting}`)
|
||||
if (!isOnboarding && !RPCClient._sessionExpiredRedirecting) {
|
||||
if (!isOnboarding && !isLogin && !RPCClient._sessionExpiredRedirecting) {
|
||||
RPCClient._sessionExpiredRedirecting = true
|
||||
console.warn(`[RPC] Session expired — redirecting to /login in 300ms`)
|
||||
setTimeout(() => {
|
||||
|
||||
@ -280,9 +280,14 @@ export const useMeshStore = defineStore('mesh', () => {
|
||||
* (the Mesh view's own 5s poll takes over while it is mounted). */
|
||||
function startGlobalDetection(intervalMs = 15000) {
|
||||
if (globalDetectTimer) return
|
||||
void fetchStatus()
|
||||
// Never poll unauthenticated — a 401 from a background poll on the
|
||||
// login page caused a login-refresh loop (2026-07-14, .116).
|
||||
const authed = () => {
|
||||
try { return !!localStorage.getItem('neode-auth') } catch { return false }
|
||||
}
|
||||
if (authed()) void fetchStatus()
|
||||
globalDetectTimer = setInterval(() => {
|
||||
if (document.visibilityState === 'visible') void fetchStatus()
|
||||
if (document.visibilityState === 'visible' && authed()) void fetchStatus()
|
||||
}, intervalMs)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user