- Add `inc_file_counts` flag to `load_ae_obj_id__event_session` — maps to
backend alt view (v_event_session_w_file_count) when true; default stays
lightweight. Callers never pass raw view names.
- Preserve-on-write fallback in `_refresh_session_id_background` keeps
cached file_count/file_count_all if API response omits them.
- Session detail +page.ts uses `inc_file_counts: true` so SvelteKit prefetch
no longer clobbers counts via bulkPut on hover.
- Remove explicit `view: 'alt'` from launcher +page.ts (now invalid param).
- Session list link: flex-1 + min-w-0 for full-row width; name flex-1 pushes
badge group right; code + file_count stacked in flex-col items-end.
- Hover styling: button-like appearance with slow fade-out (duration-500) /
fast snap-in (hover:duration-150).
- Session +page.svelte: use url_session_id (string) for link_to_id props and
auth__kv.session[] index — fixes TS type error from number|undefined.
- IDAA layout: dormant tech notice banner (guarded by 1==3, remove when ready).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When navigating within the iframe (e.g. meeting list → meeting detail),
the UUID is only present on the initial iframe src URL — internal SvelteKit
<a href> links don't carry it forward. The layout effect was unconditionally
clearing novi_verified on every navigation that lacked a UUID, causing
"Access Denied" on every internal link click.
Fix: if a valid TTL-cached Novi session exists when no UUID is in the URL,
treat it as internal navigation and preserve the session rather than wiping it.
Non-Novi paths (no session, no UUID) still clear and deny as before.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: url_uuid was read once from window.location.search (const),
assuming UUID changes always cause a full iframe reload (Novi impersonation).
Manual URL edits within the same SvelteKit session keep the layout mounted,
leaving url_uuid stale — the TTL cache then hit for the OLD valid UUID,
granting access under the wrong identity without re-verifying.
Fix:
- url_uuid is now $derived from $page.url.searchParams, updated on every
SvelteKit navigation
- url_uuid is read outside untrack() in Effect 2 so UUID changes trigger
a fresh verification run
- verify_failed (boolean) replaced with verify_failed_for_uuid (string|null)
so the retry-loop latch is keyed to the specific failed UUID — a different
UUID in the URL is always a clean slate that gets verified fresh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Security fixes (3 layers):
1. layout: verify_novi_uuid now rejects Novi 200 responses with no member
data — prevents non-existent UUIDs from passing as verified members
2. layout: access gate now requires $idaa_loc.novi_verified in addition to
novi_uuid (stale UUID alone was insufficient)
3. video_conferences: onMount guard aborts Jitsi init if the layout-verified
UUID doesn't match the URL UUID (defense-in-depth)
Also fixes an infinite verification loop: when verification fails, writes to
$idaa_loc trigger storage events that cause $ae_loc to re-notify subscribers,
re-running Effect 2 indefinitely. Added verify_failed latch to stop retries —
the UUID is fixed for the page lifetime, retrying always produces the same result.
Feature: "Open Externally" button + modal (iframe mode only) lets IDAA members
escape the Novi iframe when scrolling/layout is broken. Options: copy link to
clipboard or open in new tab. Accessible to all users without edit-mode.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If the "Verifying identity..." spinner is still visible after 8 seconds,
show an escape-hatch button that clears ae_loc + ae_idaa_loc from
localStorage and reloads — forcing a fresh site config fetch which
re-populates novi_idaa_api_key so verification can actually run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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 <noreply@anthropic.com>
UUID is set by Novi via iframe src at page load and never changes within a
session (impersonation = full iframe reload). Reading it once from
window.location.search eliminates reactive noise from SvelteKit client-side
navigation causing spurious re-verification runs.
Removed:
- verify_dep $derived.by (reactive UUID + site_cfg narrowing)
- dedupe snapshot + last_effect_* tracking variables
- verify_backoff_attempts and exponential backoff retry logic
- novi_rate_limited_until writes and UUID-change guards
- ~80 lines of complexity
Kept:
- site_cfg_json read outside untrack (effect still re-runs when API key loads async)
- verify_in_flight concurrency guard
- TTL cache (prevents duplicate calls on SWR site_cfg updates)
- All permission upgrade and store write logic
NOTE: If Novi adds dynamic impersonation (no full reload), see comment at
url_uuid declaration for what to restore.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Critical bugs fixed:
- $derived(() => {}) stored the function itself; uuid/api_key were always
undefined so verification never fired. Fixed to $derived.by(() => {}).
- novi_verifying pre-initialized to true (flash prevention) was also used as
the concurrency guard — guard saw it as in-flight and exited immediately,
leaving the spinner stuck forever. Split into separate verify_in_flight flag.
- $idaa_loc reads in dedupe snapshot (outside untrack) subscribed the effect
to idaa_loc writes, causing needless re-runs post-verification.
- Rate limit was not UUID-aware: 429 on one UUID blocked impersonation
(new UUID). TTL and rate-limit guards now both bypass when UUID changes.
Also includes: store defaults for novi_verified_ts + novi_rate_limited_until,
docs update, iframe template g_uuid param (prior agent changes).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WHY: Novi UUID verification is async — on first iframe load the API call
may not complete before the access gate renders, leaving the user stuck on
Access Denied with no way to retry without manually reloading the host page.
The Reload/Retry button calls location.reload() to re-trigger verification.
Only shown in iframe mode where the timing race is the known failure path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set log_lvl to 0 in all pages and layouts that had it left at 1 or 2
from development. Also remove two hardcoded `log_lvl = 2` overrides
inside function bodies in reports_files.svelte and
reports_presenters.svelte that were forcing verbose output regardless
of the module-level setting.
Affected: launcher location page, leads pages (2), pres_mgmt reports (2),
presenter +page.ts, IDAA layouts (2), IDAA archives, IDAA recovery
meetings page, journals pages (2).
Previously, IDAA iframe access relied on trusting URL params (uuid, email,
full_name) passed from Novi — any 36-char string granted authenticated access
with no actual verification.
The (idaa)/+layout.svelte now performs an async Novi API call on every UUID
load to verify the UUID exists, fetches name/email directly from Novi (cannot
be spoofed via URL), and sets $idaa_loc.novi_verified on success.
All-or-nothing: if novi_idaa_api_key is absent or the call fails, access denied.
- ae_idaa_stores.ts: add novi_verified boolean field to idaa_loc
- (idaa)/+layout.svelte: async UUID verification with spinner to prevent
Access Denied flash; permission upgrade-only strategy preserved
- video_conferences/+page.svelte: skip duplicate Novi member details call if
layout already verified ($idaa_loc.novi_verified check)
- iframe HTML files: remove browser-side Novi API fetch and email/full_name
params; pass only uuid; add README/START/STOP/WARNING comments for client
staff; fix iframe-before-script DOM ordering bug
- documentation: CLIENT__IDAA_and_customized_mods.md updated with full
verification flow, site_cfg_json fields, permission table, access gate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ae_idaa_stores.ts: update default novi_admin_li UUID; add staff UUID to
novi_trusted_li hardcoded defaults.
- +layout.svelte (idaa): only overwrite admin/trusted lists from site_cfg_json
when the list is non-empty, so hardcoded defaults are never silently cleared.
Remove $ae_loc.iframe requirement for 'authenticated' access level — the
presence of a valid Novi UUID in the URL is sufficient proof regardless of
whether the iframe flag is set yet.
Standardized access level hierarchy (super > manager > administrator > trusted) and added hierarchical comparison utilities to 'ae_util'.
Refactored IDAA layout to use an 'Upgrade-Only' permission strategy, preventing context-specific identifications from downgrading global Manager privileges.
Implemented strict gated filtering in the Journal Entry list: hidden and disabled items now correctly require both the appropriate hierarchical role (Trusted/Admin) AND active Edit Mode.
- Refactored layouts to derive account data from stable props instead of reactive stores.
- Wrapped store updates in untrack() with deep equality guards to prevent infinite re-renders.
- Resolved duplicate untrack declarations and missing imports across the project.
- Added fetch safeguards to Element_data_store to prevent redundant API calls.
- Standardized hydration patterns to break circular dependencies during initial load.
- Fixed 'Captured initial value' warnings in 65+ components by implementing
proper sync effects with 'untrack' and derived states.
- Hardened Event Settings JSON editors using a temporary string-buffer pattern
to safely decouple object-based data from CodeMirror's string requirements.
- Resolved strict TypeScript mismatches across core routes (Accounts, Sites, etc.)
and improved property indexing safety in views.
- Patched Flowbite-Svelte Drawer transitions for Svelte 5 compatibility using
prop spreading.
- Added comprehensive safety comments to high-risk reactivity blocks.
- Synchronized 'ae_types.ts' with V3 backend models.
Migrated the ESLint configuration to the new flat config format ()
and addressed several initial linting errors.
Key changes include:
- Updated ESLint configuration to treat as warnings instead of errors.
- Fixed errors in by declaring and .
- Corrected error in by using instead of an out-of-scope .
- Resolved error in by replacing the undefined directive with the component.
- Addressed errors in by replacing with and with .
- Fixed errors in by importing necessary modules (, , ) and adding missing props (, , , , ).