From 5a6ea1e53a875fa716f4e2f68097caf9c43d86c3 Mon Sep 17 00:00:00 2001 From: Xevion Date: Thu, 29 Jan 2026 20:04:50 -0600 Subject: [PATCH] fix: handle backend startup delays with retry logic in auth --- web/src/lib/auth.svelte.ts | 40 +++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/web/src/lib/auth.svelte.ts b/web/src/lib/auth.svelte.ts index 56e15ed..01b97a0 100644 --- a/web/src/lib/auth.svelte.ts +++ b/web/src/lib/auth.svelte.ts @@ -24,17 +24,39 @@ class AuthStore { return this.state.mode === "authenticated"; } + /** + * Attempt to load the current user session from the backend. + * Only transitions to "unauthenticated" on a definitive 401/403. + * Retries indefinitely on transient failures (network errors, 5xx) + * so that a slow backend startup doesn't kick the user to login. + */ async init() { - try { - const response = await fetch("/api/auth/me"); - if (response.ok) { - const user: User = await response.json(); - this.state = { mode: "authenticated", user }; - } else { - this.state = { mode: "unauthenticated" }; + const MAX_DELAY_MS = 7_000; + let delayMs = 500; + + for (;;) { + try { + const response = await fetch("/api/auth/me"); + + if (response.ok) { + const user: User = await response.json(); + this.state = { mode: "authenticated", user }; + return; + } + + // Definitive rejection — no session or not authorized + if (response.status === 401 || response.status === 403) { + this.state = { mode: "unauthenticated" }; + return; + } + + // Server error (5xx) or unexpected status — retry + } catch { + // Network error (backend not up yet) — retry } - } catch { - this.state = { mode: "unauthenticated" }; + + await new Promise((r) => setTimeout(r, delayMs)); + delayMs = Math.min(delayMs * 2, MAX_DELAY_MS); } }