perf(hydration): implement cache-first site discovery and SWR event loading
- Refactored lookup_site_domain_v3 to be cache-first, unblocking root layout. - Implemented Stale-While-Revalidate (SWR) pattern for load_ae_obj_id__event. - Added global hydration overlay and loading spinner to +layout.svelte. - Updated site domain whitelist to persist critical account/styling metadata in Dexie. - Refactored root load function to return immediately if cached site data is found.
This commit is contained in:
@@ -91,7 +91,7 @@ export async function lookup_site_domain({
|
||||
} as any;
|
||||
}
|
||||
|
||||
// Updated 2026-01-07
|
||||
// Updated 2026-01-26 (Cache-First Optimization)
|
||||
export async function lookup_site_domain_v3({
|
||||
api_cfg,
|
||||
fqdn,
|
||||
@@ -104,12 +104,34 @@ export async function lookup_site_domain_v3({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_SiteDomain | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** lookup_site_domain_v3() *** fqdn=${fqdn}`);
|
||||
console.log(`*** lookup_site_domain_v3() *** fqdn=${fqdn} (Cache-First)`);
|
||||
}
|
||||
|
||||
// 1. FAST PATH: Check local cache first
|
||||
let cached = null;
|
||||
try {
|
||||
cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
||||
if (cached) {
|
||||
if (log_lvl) console.log('BOOTSTRAP: Cache hit. Returning cached site domain immediately.');
|
||||
|
||||
// Trigger background refresh to keep cache fresh, but don't await it
|
||||
_refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl: 0 });
|
||||
|
||||
return cached as any;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('BOOTSTRAP: Cache read failed.', err);
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API if cache is empty
|
||||
return await _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl });
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper to perform the actual API fetch and cache update
|
||||
*/
|
||||
async function _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl }: any) {
|
||||
try {
|
||||
// CRITICAL: For the unauthenticated Bootstrap lookup, we must NOT send
|
||||
// any existing auth tokens or account IDs that might be in the global config.
|
||||
const guest_api_cfg = { ...api_cfg };
|
||||
guest_api_cfg.headers = { ...api_cfg.headers };
|
||||
|
||||
@@ -134,30 +156,19 @@ export async function lookup_site_domain_v3({
|
||||
and: [{ field: 'fqdn', op: 'eq', value: fqdn }]
|
||||
};
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`BOOTSTRAP SEARCH: fqdn=${fqdn}`);
|
||||
console.log(`BOOTSTRAP HEADERS:`, guest_api_cfg.headers);
|
||||
console.log(`BOOTSTRAP QUERY:`, JSON.stringify(search_query));
|
||||
}
|
||||
|
||||
// We use search because we are looking up by a unique field (fqdn) rather than ID.
|
||||
// The backend should return a list, but since FQDN is unique, it will have 1 item.
|
||||
const result_li = await api.search_ae_obj_v3({
|
||||
api_cfg: guest_api_cfg,
|
||||
obj_type: 'site_domain',
|
||||
search_query,
|
||||
view, // This view should ideally join with site and account for the root lookup
|
||||
view,
|
||||
enabled: 'enabled',
|
||||
hidden: 'all',
|
||||
limit: 1,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (log_lvl) console.log(`BOOTSTRAP RESULT:`, result_li);
|
||||
|
||||
if (result_li && result_li.length > 0) {
|
||||
const result = result_li[0];
|
||||
// Standardize and save to cache
|
||||
const processed_obj_li = await process_ae_obj__site_domain_props({
|
||||
obj_li: [result],
|
||||
log_lvl
|
||||
@@ -172,12 +183,9 @@ export async function lookup_site_domain_v3({
|
||||
return result;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('Site domain lookup V3 failed.', error);
|
||||
if (log_lvl) console.log('Site domain refresh V3 failed.', error);
|
||||
}
|
||||
|
||||
if (log_lvl) console.log('Attempting to load site domain from local cache (V3 fallback)...');
|
||||
const cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
||||
return (cached as any) || null;
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function load_ae_obj_id__site({
|
||||
@@ -661,6 +669,10 @@ const properties_to_save__site_domain = [
|
||||
'site_domain_id_random',
|
||||
'site_id',
|
||||
'site_id_random',
|
||||
'account_id',
|
||||
'account_id_random',
|
||||
'account_code',
|
||||
'account_name',
|
||||
'fqdn',
|
||||
'access_key',
|
||||
'enable',
|
||||
@@ -671,6 +683,11 @@ const properties_to_save__site_domain = [
|
||||
'sort',
|
||||
'group',
|
||||
'notes',
|
||||
'header_image_path',
|
||||
'style_href',
|
||||
'google_tracking_id',
|
||||
'access_code_kv_json',
|
||||
'cfg_json',
|
||||
'created_on',
|
||||
'updated_on',
|
||||
'tmp_sort_1',
|
||||
|
||||
Reference in New Issue
Block a user