Prettier for IDAA pages only

This commit is contained in:
Scott Idem
2026-03-24 12:28:07 -04:00
parent b74c6d0e9c
commit 12a9472064
39 changed files with 8673 additions and 8050 deletions

View File

@@ -1,199 +1,211 @@
<script lang="ts">
import { untrack } from 'svelte';
let log_lvl: number = 0;
import { untrack } from 'svelte';
let log_lvl: number = 0;
// *** Import Svelte specific
import { browser } from '$app/environment';
// *** Import Svelte specific
import { browser } from '$app/environment';
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
import { idaa_loc, idaa_sess, idaa_slct } from '$lib/stores/ae_idaa_stores';
// *** Import Aether specific variables and functions
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
import { idaa_loc, idaa_sess, idaa_slct } from '$lib/stores/ae_idaa_stores';
interface Props {
/** @type {import('./$types').LayoutData} */
data: any;
children?: import('svelte').Snippet;
interface Props {
/** @type {import('./$types').LayoutData} */
data: any;
children?: import('svelte').Snippet;
}
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);
// Effect 1: Set URL origin and params (unchanged from original)
$effect(() => {
untrack(() => {
$ae_loc.url_origin = data.url.origin;
$ae_loc.params = data.params;
});
if (log_lvl > 1) {
console.log(`+layout.svelte data:`, data);
}
});
let { data, children }: Props = $props();
// Effect 2: Novi UUID verification
// Only fires when a uuid is present in the URL (i.e. the Novi iframe path).
// Non-Novi sign-in paths (User/Pass, shared passcode) will never have a uuid param,
// so this block won't run for them — their permissions are unaffected.
$effect(() => {
if (!browser) return;
// 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);
const uuid = data.url.searchParams.get('uuid'); // tracked — re-runs if URL changes
// Effect 1: Set URL origin and params (unchanged from original)
$effect(() => {
untrack(() => {
$ae_loc.url_origin = data.url.origin;
$ae_loc.params = data.params;
});
if (log_lvl > 1) {
console.log(`+layout.svelte data:`, data);
}
});
// Effect 2: Novi UUID verification
// Only fires when a uuid is present in the URL (i.e. the Novi iframe path).
// Non-Novi sign-in paths (User/Pass, shared passcode) will never have a uuid param,
// so this block won't run for them — their permissions are unaffected.
$effect(() => {
if (!browser) return;
const uuid = data.url.searchParams.get('uuid'); // tracked — re-runs if URL changes
untrack(() => {
if (!uuid) {
// No UUID in URL — non-Novi path, nothing to do here.
$idaa_loc.novi_verified = 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 ($ae_loc.site_cfg_json?.novi_trusted_li?.length) {
$idaa_loc.novi_trusted_li = $ae_loc.site_cfg_json.novi_trusted_li;
}
const novi_api_key = $ae_loc.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';
// Fire-and-forget the async verification. After the first await, Svelte's
// reactive tracking no longer applies, so writes to stores are safe.
novi_verifying = true;
verify_novi_uuid(uuid, novi_api_key, novi_api_root_url);
});
});
/**
* 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.
*/
async function verify_novi_uuid(
uuid: string,
api_key: string | null,
api_root_url: string
) {
if (!api_key) {
// No Novi API key in site config. All-or-nothing means no UUID-based access.
console.warn('IDAA Layout: Novi API key not configured. UUID-based access denied.');
$idaa_loc.novi_uuid = null;
$idaa_loc.novi_email = null;
$idaa_loc.novi_full_name = null;
untrack(() => {
if (!uuid) {
// No UUID in URL — non-Novi path, nothing to do here.
$idaa_loc.novi_verified = false;
novi_verifying = false;
return;
}
try {
if (log_lvl > 1) {
console.log(`IDAA Layout: Verifying Novi UUID ${uuid} via API...`);
}
const headers = new Headers();
headers.append('Authorization', `Basic ${api_key}`);
const response = await fetch(`${api_root_url}/customers/${uuid}`, {
method: 'GET',
headers
});
if (!response.ok) {
throw new Error(`Novi API returned ${response.status} for UUID ${uuid}`);
}
const result = await response.json();
// Build display name: prefer "First L." format, fall back to full Name field.
const first_name = result?.FirstName ?? null;
const last_initial = result?.LastName
? `${result.LastName.charAt(0).toUpperCase()}.`
: '';
const verified_name =
first_name && last_initial
? `${first_name} ${last_initial}`
: (result?.Name ?? null);
// Normalize email — Novi occasionally includes spaces where + should be.
const verified_email = result?.Email
? result.Email.replace(/\s+/g, '+')
: null;
$idaa_loc.novi_uuid = uuid;
$idaa_loc.novi_email = verified_email;
$idaa_loc.novi_full_name = verified_name;
$idaa_loc.novi_verified = true;
console.log(
`IDAA Layout: Novi UUID verified. Name: ${verified_name}, Email: ${verified_email}`
);
// Determine permission level based on verified UUID.
// UUID confirmed real → at minimum authenticated. Check lists for higher levels.
let target_novi_level = 'authenticated';
if ($idaa_loc.novi_admin_li?.includes(uuid)) {
target_novi_level = 'administrator';
} else if ($idaa_loc.novi_trusted_li?.includes(uuid)) {
target_novi_level = 'trusted';
}
// PERMISSION UPGRADE STRATEGY: only apply if higher than current level.
// This prevents a global 'manager' from being downgraded by the IDAA layout.
const current_level = $ae_loc.access_type || 'anonymous';
if (ae_util.compare_access_levels(target_novi_level, current_level) === 1) {
console.log(
`IDAA Layout: Upgrading access from ${current_level} to ${target_novi_level} (Novi verified)`
);
const perms = ae_util.process_permission_checks(target_novi_level);
$ae_loc = { ...$ae_loc, ...perms };
} else {
if (log_lvl > 1) {
console.log(
`IDAA Layout: Keeping current access ${current_level} (Novi level ${target_novi_level} is not an upgrade)`
);
}
}
// Reset BB query filters to safe defaults in case they were left in a non-default state.
$idaa_loc.bb.qry__hidden = 'not_hidden';
$idaa_loc.bb.qry__enabled = 'enabled';
} catch (error) {
// Verification failed — all-or-nothing means deny access.
console.error(`IDAA Layout: Novi UUID verification failed for ${uuid}:`, error);
$idaa_loc.novi_uuid = null;
$idaa_loc.novi_email = null;
$idaa_loc.novi_full_name = null;
$idaa_loc.novi_verified = false;
} finally {
novi_verifying = false;
// 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 ($ae_loc.site_cfg_json?.novi_trusted_li?.length) {
$idaa_loc.novi_trusted_li = $ae_loc.site_cfg_json.novi_trusted_li;
}
const novi_api_key = $ae_loc.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';
// Fire-and-forget the async verification. After the first await, Svelte's
// reactive tracking no longer applies, so writes to stores are safe.
novi_verifying = true;
verify_novi_uuid(uuid, novi_api_key, novi_api_root_url);
});
});
/**
* 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.
*/
async function verify_novi_uuid(
uuid: string,
api_key: string | null,
api_root_url: string
) {
if (!api_key) {
// No Novi API key in site config. All-or-nothing means no UUID-based access.
console.warn(
'IDAA Layout: Novi API key not configured. UUID-based access denied.'
);
$idaa_loc.novi_uuid = null;
$idaa_loc.novi_email = null;
$idaa_loc.novi_full_name = null;
$idaa_loc.novi_verified = false;
novi_verifying = false;
return;
}
try {
if (log_lvl > 1) {
console.log(`IDAA Layout: Verifying Novi UUID ${uuid} via API...`);
}
const headers = new Headers();
headers.append('Authorization', `Basic ${api_key}`);
const response = await fetch(`${api_root_url}/customers/${uuid}`, {
method: 'GET',
headers
});
if (!response.ok) {
throw new Error(
`Novi API returned ${response.status} for UUID ${uuid}`
);
}
const result = await response.json();
// Build display name: prefer "First L." format, fall back to full Name field.
const first_name = result?.FirstName ?? null;
const last_initial = result?.LastName
? `${result.LastName.charAt(0).toUpperCase()}.`
: '';
const verified_name =
first_name && last_initial
? `${first_name} ${last_initial}`
: (result?.Name ?? null);
// Normalize email — Novi occasionally includes spaces where + should be.
const verified_email = result?.Email
? result.Email.replace(/\s+/g, '+')
: null;
$idaa_loc.novi_uuid = uuid;
$idaa_loc.novi_email = verified_email;
$idaa_loc.novi_full_name = verified_name;
$idaa_loc.novi_verified = true;
console.log(
`IDAA Layout: Novi UUID verified. Name: ${verified_name}, Email: ${verified_email}`
);
// Determine permission level based on verified UUID.
// UUID confirmed real → at minimum authenticated. Check lists for higher levels.
let target_novi_level = 'authenticated';
if ($idaa_loc.novi_admin_li?.includes(uuid)) {
target_novi_level = 'administrator';
} else if ($idaa_loc.novi_trusted_li?.includes(uuid)) {
target_novi_level = 'trusted';
}
// PERMISSION UPGRADE STRATEGY: only apply if higher than current level.
// This prevents a global 'manager' from being downgraded by the IDAA layout.
const current_level = $ae_loc.access_type || 'anonymous';
if (
ae_util.compare_access_levels(target_novi_level, current_level) ===
1
) {
console.log(
`IDAA Layout: Upgrading access from ${current_level} to ${target_novi_level} (Novi verified)`
);
const perms = ae_util.process_permission_checks(target_novi_level);
$ae_loc = { ...$ae_loc, ...perms };
} else {
if (log_lvl > 1) {
console.log(
`IDAA Layout: Keeping current access ${current_level} (Novi level ${target_novi_level} is not an upgrade)`
);
}
}
// Reset BB query filters to safe defaults in case they were left in a non-default state.
$idaa_loc.bb.qry__hidden = 'not_hidden';
$idaa_loc.bb.qry__enabled = 'enabled';
} catch (error) {
// Verification failed — all-or-nothing means deny access.
console.error(
`IDAA Layout: Novi UUID verification failed for ${uuid}:`,
error
);
$idaa_loc.novi_uuid = null;
$idaa_loc.novi_email = null;
$idaa_loc.novi_full_name = null;
$idaa_loc.novi_verified = false;
} finally {
novi_verifying = false;
}
}
</script>
{#if !browser}
<!-- SSR / pre-hydration placeholder -->
<p class="text-sm text-gray-500 text-center">
<p class="text-center text-sm text-gray-500">
<span class="fas fa-spinner fa-spin"></span>
Loading...
</p>
{:else if novi_verifying}
<!-- Async Novi API call is in flight — show spinner to prevent Access Denied flash -->
<div class="container flex flex-col gap-2 w-full items-center justify-center p-8 m-8">
<p class="text-sm text-gray-500 text-center">
<div
class="container m-8 flex w-full flex-col items-center justify-center gap-2 p-8">
<p class="text-center text-sm text-gray-500">
<span class="fas fa-spinner fa-spin"></span>
Verifying identity...
</p>
@@ -208,10 +220,13 @@
{$idaa_loc.novi_email ?? 'email not set'}
</span>
{:else}
<p class="text-sm text-gray-500 text-center">IDAA Novi UUID not found!</p>
<p class="text-center text-sm text-gray-500">
IDAA Novi UUID not found!
</p>
{/if}
{:else}
<div class="container flex flex-col gap-1 w-full items-center justify-center font-bold p-8 m-8">
<div
class="container m-8 flex w-full flex-col items-center justify-center gap-1 p-8 font-bold">
<h1>
<span class="text-red-500">
<span class="fas fa-exclamation-triangle"></span>