From ab294c2a0b4b587a501249cd1669fcedbfe80dc4 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 25 Mar 2026 18:31:39 -0400 Subject: [PATCH] Sorry. Quick save to make something live before deadline. --- src/lib/ae_core/ae_core__site.ts | 21 +++++++++++++++ src/routes/idaa/(idaa)/+layout.svelte | 38 ++++++++++++++++++++------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/lib/ae_core/ae_core__site.ts b/src/lib/ae_core/ae_core__site.ts index 71bb4d55..59aa3bdb 100644 --- a/src/lib/ae_core/ae_core__site.ts +++ b/src/lib/ae_core/ae_core__site.ts @@ -1,4 +1,6 @@ import type { key_val } from '$lib/stores/ae_stores'; +import { ae_loc } from '$lib/stores/ae_stores'; +import { get } from 'svelte/store'; import { api } from '$lib/api/api'; import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie'; @@ -198,6 +200,25 @@ async function _refresh_site_domain_background({ properties_to_save: properties_to_save__site_domain, log_lvl }); + + // WHY: The fast-path returns stale Dexie cache, then this background refresh + // runs after the page renders. If cfg_json changed server-side (e.g. a Novi + // API key was added), the stale cfg is already in $ae_loc. We push the fresh + // cfg_json into the store here so any layout tracking it (e.g. IDAA Novi + // verification) gets notified and can retry with the correct config. + if (result.cfg_json) { + const current_cfg = get(ae_loc).site_cfg_json; + if ( + JSON.stringify(current_cfg) !== + JSON.stringify(result.cfg_json) + ) { + ae_loc.update((loc) => ({ + ...loc, + site_cfg_json: result.cfg_json + })); + } + } + return result; } } catch (error: any) { diff --git a/src/routes/idaa/(idaa)/+layout.svelte b/src/routes/idaa/(idaa)/+layout.svelte index b9865d08..a66e418f 100644 --- a/src/routes/idaa/(idaa)/+layout.svelte +++ b/src/routes/idaa/(idaa)/+layout.svelte @@ -26,9 +26,13 @@ interface Props { let { data, children }: Props = $props(); -// True while the async Novi API verification call is in flight. -// Prevents the access gate from flashing "Access Denied" during the network round-trip. -let novi_verifying: boolean = $state(false); +// True while verification is in flight OR while waiting for site config to load. +// Pre-initialized to true if a UUID is present so there is no flash of "Access Denied" +// on first render before the effect has a chance to run. +let novi_verifying: boolean = $state( + typeof window !== 'undefined' && + !!new URLSearchParams(window.location.search).get('uuid') +); // Effect 1: Set URL origin and params (unchanged from original) $effect(() => { @@ -51,27 +55,41 @@ $effect(() => { const uuid = data.url.searchParams.get('uuid'); // tracked — re-runs if URL changes + // WHY tracked outside untrack: on first load the fast-path returns a stale Dexie + // cache, so site_cfg_json may be missing novi_idaa_api_key when this effect first + // runs. The background refresh in ae_core__site.ts pushes fresh cfg_json into + // $ae_loc after the API responds. Tracking here means this effect re-runs at that + // point and retries verification with the correct key — no manual reload needed. + const site_cfg_json = $ae_loc.site_cfg_json; + untrack(() => { if (!uuid) { // No UUID in URL — non-Novi path, nothing to do here. $idaa_loc.novi_verified = false; + novi_verifying = false; + return; + } + + // Already verified for this exact UUID — don't repeat the round-trip. + // This guard fires when site_cfg_json changes for reasons unrelated to Novi. + if ($idaa_loc.novi_verified && $idaa_loc.novi_uuid === uuid) { + novi_verifying = false; return; } // Load admin/trusted lists from site config first — needed by verify function. // Only override if site_cfg_json actually provides them; falling back to [] would // silently overwrite the hardcoded defaults in ae_idaa_stores.ts. - if ($ae_loc.site_cfg_json?.novi_admin_li?.length) { - $idaa_loc.novi_admin_li = $ae_loc.site_cfg_json.novi_admin_li; + if (site_cfg_json?.novi_admin_li?.length) { + $idaa_loc.novi_admin_li = site_cfg_json.novi_admin_li; } - if ($ae_loc.site_cfg_json?.novi_trusted_li?.length) { - $idaa_loc.novi_trusted_li = $ae_loc.site_cfg_json.novi_trusted_li; + if (site_cfg_json?.novi_trusted_li?.length) { + $idaa_loc.novi_trusted_li = site_cfg_json.novi_trusted_li; } - const novi_api_key = $ae_loc.site_cfg_json?.novi_idaa_api_key ?? null; + const novi_api_key = site_cfg_json?.novi_idaa_api_key ?? null; const novi_api_root_url = - $ae_loc.site_cfg_json?.novi_api_root_url ?? - 'https://www.idaa.org/api'; + site_cfg_json?.novi_api_root_url ?? 'https://www.idaa.org/api'; // Fire-and-forget the async verification. After the first await, Svelte's // reactive tracking no longer applies, so writes to stores are safe.