From e64001cf635cbdf747f29a473becd3fb19c36619 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Fri, 27 Mar 2026 13:59:50 -0400 Subject: [PATCH] fix(idaa): add 10s backoff retry on Novi API 429 rate-limit On a 429 response, waits 10 seconds then retries once. If the retry also returns 429, throws and denies access (Reload/Retry button covers that case). verify_in_flight and novi_verifying stay true during the wait so the spinner remains visible and no concurrent calls can sneak in. Co-Authored-By: Claude Sonnet 4.6 --- src/routes/idaa/(idaa)/+layout.svelte | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/routes/idaa/(idaa)/+layout.svelte b/src/routes/idaa/(idaa)/+layout.svelte index 76c9ea40..cde4d444 100644 --- a/src/routes/idaa/(idaa)/+layout.svelte +++ b/src/routes/idaa/(idaa)/+layout.svelte @@ -111,11 +111,13 @@ $effect(() => { * Verifies a Novi UUID against the Novi API and sets permissions accordingly. * "All or nothing" — if no API key is configured or the call fails, access is denied. * Called from within untrack(), so store writes here will not trigger reactive loops. + * On a 429 rate-limit response, waits 10 seconds and retries once before failing. */ async function verify_novi_uuid( uuid: string, api_key: string | null, - api_root_url: string + api_root_url: string, + is_retry: boolean = false ) { console.log(`IDAA Layout: Starting Novi UUID verification for ${uuid}...`); if (!api_key) { @@ -138,6 +140,16 @@ async function verify_novi_uuid( headers }); + if (response.status === 429) { + if (is_retry) { + throw new Error(`Novi API rate limited for UUID ${uuid} (retry also failed)`); + } + console.warn(`IDAA Layout: Novi API rate limited (429) for ${uuid}. Retrying in 10s...`); + await new Promise((resolve) => setTimeout(resolve, 10_000)); + await verify_novi_uuid(uuid, api_key, api_root_url, true); + return; + } + if (!response.ok) { throw new Error(`Novi API returned ${response.status} for UUID ${uuid}`); }