fix(core): resolve 68 compiler errors and stabilize Svelte 5 reactivity

- 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.
This commit is contained in:
Scott Idem
2026-02-08 16:05:35 -05:00
parent 356eda5ab4
commit 88bc18cf15
64 changed files with 1175 additions and 1014 deletions

View File

@@ -5,7 +5,7 @@
let log_lvl: number = 0;
// *** Import Svelte specific
// import { tick } from 'svelte';
import { untrack } from 'svelte';
import { goto, invalidateAll } from '$app/navigation';
import '../app.css';
@@ -61,55 +61,60 @@
let { data, children }: Props = $props();
if (log_lvl > 1) {
console.log(`ae_root +layout.svelte data:`, data);
}
let ae_acct = $derived(data[$slct.account_id]);
// Quickly save the data passed from the parent(s) to the Svelte stores, localStorage, and other. This should catch anything that is a child of this layout.svelte file.
$slct.account_id = data.account_id;
if (log_lvl) {
console.log(`*ae_root +layout.svelte* $slct.account_id = ${$slct.account_id}`);
}
let ae_acct = data[$slct.account_id];
if (ae_acct) {
$ae_api = {
...$ae_api,
...(ae_acct.api || {})
};
$effect(() => {
if (log_lvl > 1) {
console.log(`$ae_api = `, $ae_api);
console.log(`ae_root +layout.svelte data:`, data);
}
// FORCE UPDATE: If the incoming data is a valid site (not a fallback ghost),
// we must ensure the ae_loc store is updated regardless of what's in localStorage.
if (ae_acct.loc?.account_id && ae_acct.loc.account_id !== 'ghost') {
$ae_loc = {
...$ae_loc,
...(ae_acct.loc || {})
// Quickly save the data passed from the parent(s) to the Svelte stores, localStorage, and other. This should catch anything that is a child of this layout.svelte file.
$slct.account_id = data.account_id;
if (log_lvl) {
console.log(`*ae_root +layout.svelte* $slct.account_id = ${$slct.account_id}`);
}
});
$effect(() => {
if (ae_acct) {
$ae_api = {
...$ae_api,
...(ae_acct.api || {})
};
if (log_lvl > 1) {
console.log(`$ae_api = `, $ae_api);
}
// FORCE UPDATE: If the incoming data is a valid site (not a fallback ghost),
// we must ensure the ae_loc store is updated regardless of what's in localStorage.
if (ae_acct.loc?.account_id && ae_acct.loc.account_id !== 'ghost') {
$ae_loc = {
...$ae_loc,
...(ae_acct.loc || {})
};
} else {
// If it IS a ghost, we still update it to show the correct fallback message
$ae_loc = {
...$ae_loc,
...(ae_acct.loc || {})
};
}
if (log_lvl > 1) {
console.log(`$ae_loc = `, $ae_loc);
}
$slct = {
...$slct,
...(ae_acct.slct || {})
};
if (log_lvl > 1) {
console.log(`$slct = `, $slct);
}
} else {
// If it IS a ghost, we still update it to show the correct fallback message
$ae_loc = {
...$ae_loc,
...(ae_acct.loc || {})
};
console.warn('ae_root +layout.svelte: ae_acct not found for account_id:', $slct.account_id);
}
if (log_lvl > 1) {
console.log(`$ae_loc = `, $ae_loc);
}
$slct = {
...$slct,
...(ae_acct.slct || {})
};
if (log_lvl > 1) {
console.log(`$slct = `, $slct);
}
} else {
console.warn('ae_root +layout.svelte: ae_acct not found for account_id:', $slct.account_id);
}
});
let flag_clear_idb: boolean = $state(false);
let flag_clear_local: boolean = $state(false);
@@ -373,21 +378,26 @@
}
// END: Expired Cache Check:
// $effect(() => {
if (browser && flag_clear_idb) {
if (log_lvl) {
console.log(`ROOT: Clear IDB...`);
}
flag_clear_idb = false;
$ae_loc.last_cache_refresh = Date.now();
$effect(() => {
// WARNING: This effect manages destructive system state (clearing DBs).
// It MUST use untrack to ensure the reload logic doesn't trigger itself.
if (browser && flag_clear_idb) {
untrack(() => {
if (log_lvl) {
console.log(`ROOT: Clear IDB...`);
}
flag_clear_idb = false;
$ae_loc.last_cache_refresh = Date.now();
clear_idb();
clear_idb();
if (log_lvl) {
console.log(`ROOT: IDB cleared. Reload!`);
if (log_lvl) {
console.log(`ROOT: IDB cleared. Reload!`);
}
window.location.reload();
});
}
window.location.reload();
}
});
// BEGIN: Access Checks:
// Updated 2024-11-21
@@ -458,59 +468,62 @@
// cerberus
}
// $effect(() => {
if (browser && flag_reload) {
if (log_lvl) {
console.log(`ROOT: Reloading page after other flags checked...`);
$effect(() => {
if (browser && flag_reload) {
untrack(() => {
if (log_lvl) {
console.log(`ROOT: Reloading page after other flags checked...`);
}
// // Clear Indexed DB as well
// if (flag_clear_idb) {
// if (log_lvl) {
// console.log(`ROOT: Clearing IndexedDB databases...`);
// }
// clear_idb();
// }
// Clear localStorage and sessionStorage
if (flag_clear_local) {
if (log_lvl) {
console.log(`ROOT: Clearing localStorage...`);
}
clear_local();
}
if (flag_clear_sess) {
if (log_lvl) {
console.log('ROOT: Clearing sessionStorage...');
}
clear_sess();
}
// tick();
// try {
// goto(data.route.id, {replaceState: true, invalidateAll: true});
// } catch (e) {
// console.log('Error going to root page:', e);
// goto('/', {replaceState: true, invalidateAll: true});
// }
// This does not seem to work fast enough or something?
// goto('/', {replaceState: true, invalidateAll: true});
// The page does usually seem to reload correctly?
// window.location.reload(true); // true only works with Firefox
// window.location.reload({forceGet: true});
// location.reload();
// tick();
invalidateAll();
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
});
}
// // Clear Indexed DB as well
// if (flag_clear_idb) {
// if (log_lvl) {
// console.log(`ROOT: Clearing IndexedDB databases...`);
// }
// clear_idb();
// }
// Clear localStorage and sessionStorage
if (flag_clear_local) {
if (log_lvl) {
console.log(`ROOT: Clearing localStorage...`);
}
clear_local();
}
if (flag_clear_sess) {
if (log_lvl) {
console.log('ROOT: Clearing sessionStorage...');
}
clear_sess();
}
// tick();
// try {
// goto(data.route.id, {replaceState: true, invalidateAll: true});
// } catch (e) {
// console.log('Error going to root page:', e);
// goto('/', {replaceState: true, invalidateAll: true});
// }
// This does not seem to work fast enough or something?
// goto('/', {replaceState: true, invalidateAll: true});
// The page does usually seem to reload correctly?
// window.location.reload(true); // true only works with Firefox
// window.location.reload({forceGet: true});
// location.reload();
// tick();
invalidateAll();
// alert('Local and Session Storage cleared and Indexed DBs deleted. You will probably want to refresh the page.');
}
});
function clear_idb() {
indexedDB.deleteDatabase('ae_archives_db'); // Archives module
@@ -543,115 +556,119 @@
sessionStorage.clear();
}
if (browser) {
// save_ds_to_local(ae_acct.ds);
let ae_ds = ae_acct.ds;
if (log_lvl) {
console.log(`ae_ds__ data:`, ae_ds);
}
for (let [key, value] of Object.entries(ae_ds)) {
console.log(`ae_ds__ key: ${key}, value:`, value);
localStorage.setItem(`ae_ds__${key}`, JSON.stringify(value));
}
// This is how the download and upload progress is tracked.
window.addEventListener('message', function (event) {
$effect(() => {
if (browser) {
// save_ds_to_local(ae_acct.ds);
let ae_ds = ae_acct.ds;
if (log_lvl) {
console.log('Message received in root +layout.svelte:', event);
console.log(`ae_ds__ data:`, ae_ds);
}
if (ae_ds) {
for (let [key, value] of Object.entries(ae_ds)) {
console.log(`ae_ds__ key: ${key}, value:`, value);
localStorage.setItem(`ae_ds__${key}`, JSON.stringify(value));
}
}
if (event.data.type == 'api_download_blob') {
// This is how the download and upload progress is tracked.
window.addEventListener('message', function (event) {
if (log_lvl) {
console.log('Download blob (file) message received:', event.data);
console.log('Message received in root +layout.svelte:', event);
}
let task_id = event.data.task_id;
if (event.data.type == 'api_download_blob') {
if (log_lvl) {
console.log('Download blob (file) message received:', event.data);
}
$ae_sess.api_download_kv[task_id] = {
status: event.data.status,
task_id: task_id,
endpoint: event.data.endpoint,
filename: event.data.filename,
size_total: event.data.size_total,
size_loaded: event.data.size_loaded,
percent_completed: event.data.percent_completed
};
} else if (event.data.type == 'api_post_json_form') {
if (log_lvl) {
console.log('Post JSON form message received:', event.data);
let task_id = event.data.task_id;
$ae_sess.api_download_kv[task_id] = {
status: event.data.status,
task_id: task_id,
endpoint: event.data.endpoint,
filename: event.data.filename,
size_total: event.data.size_total,
size_loaded: event.data.size_loaded,
percent_completed: event.data.percent_completed
};
} else if (event.data.type == 'api_post_json_form') {
if (log_lvl) {
console.log('Post JSON form message received:', event.data);
}
let task_id = event.data.task_id;
$ae_sess.api_upload_kv[task_id] = {
status: event.data.status,
task_id: task_id,
endpoint: event.data.endpoint,
filename: event.data.filename,
size_total: event.data.size_total,
size_loaded: event.data.size_loaded,
percent_completed: event.data.percent_completed,
progress: event.data.progress,
rate: event.data.rate
};
}
});
let task_id = event.data.task_id;
let iframe = data.url.searchParams.get('iframe');
if (iframe == 'true') {
console.log('Use iframe layout!');
$ae_loc.iframe = true;
$ae_sess.api_upload_kv[task_id] = {
status: event.data.status,
task_id: task_id,
endpoint: event.data.endpoint,
filename: event.data.filename,
size_total: event.data.size_total,
size_loaded: event.data.size_loaded,
percent_completed: event.data.percent_completed,
progress: event.data.progress,
rate: event.data.rate
};
document.getElementsByTagName('html')[0].classList.add('iframe');
// document.getElementsByTagName('html')[0].classList.remove('dark');
// document.getElementsByTagName('html')[0].classList.remove('light');
$ae_loc.app_cfg.show_element__access_type = false;
$ae_loc.app_cfg.show_element__cfg = false;
} else if (iframe == 'false') {
$ae_loc.iframe = false;
document.getElementsByTagName('html')[0].classList.remove('iframe');
// document.getElementsByTagName('html')[0].classList.add('dark');
// document.getElementsByTagName('html')[0].classList.add('light');
}
});
let iframe = data.url.searchParams.get('iframe');
if (iframe == 'true') {
console.log('Use iframe layout!');
$ae_loc.iframe = true;
document.getElementsByTagName('html')[0].classList.add('iframe');
// document.getElementsByTagName('html')[0].classList.remove('dark');
// document.getElementsByTagName('html')[0].classList.remove('light');
$ae_loc.app_cfg.show_element__access_type = false;
$ae_loc.app_cfg.show_element__cfg = false;
} else if (iframe == 'false') {
$ae_loc.iframe = false;
document.getElementsByTagName('html')[0].classList.remove('iframe');
// document.getElementsByTagName('html')[0].classList.add('dark');
// document.getElementsByTagName('html')[0].classList.add('light');
}
if (!$ae_loc.iframe && $ae_loc.trusted_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else if ($ae_loc.iframe && $ae_loc.manager_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = false;
}
// This is mainly for Precon CHOW
if (data.url.searchParams.get('event_id')) {
$events_slct.event_id = data.url.searchParams.get('event_id');
$events_loc.event_id = data.url.searchParams.get('event_id');
}
if (data.url.searchParams.get('sponsorship_cfg_id')) {
$slct.sponsorship_cfg_id = data.url.searchParams.get('sponsorship_cfg_id');
$ae_loc.mod.sponsorships.cfg_id = data.url.searchParams.get('sponsorship_cfg_id');
}
// *** Electron Native Mode Detection ***
// Explicitly set is_native if the bridge is detected, ensuring reactivity for all child components
// @ts-ignore
if (window.native_app || window.aetherNative) {
if (!$ae_loc.is_native) {
console.log('ELECTRON: Native environment detected via window bridge.');
$ae_loc.is_native = true;
if (!$ae_loc.iframe && $ae_loc.trusted_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else if ($ae_loc.iframe && $ae_loc.manager_access) {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = true;
} else {
$ae_loc.app_cfg.show_element__access_type = true;
$ae_loc.app_cfg.show_element__cfg = false;
}
// Ensure launcher mode is set to native if we're in the bridge
if ($events_loc?.launcher && $events_loc.launcher.app_mode !== 'native') {
$events_loc.launcher.app_mode = 'native';
// This is mainly for Precon CHOW
if (data.url.searchParams.get('event_id')) {
$events_slct.event_id = data.url.searchParams.get('event_id');
$events_loc.event_id = data.url.searchParams.get('event_id');
}
if (data.url.searchParams.get('sponsorship_cfg_id')) {
$slct.sponsorship_cfg_id = data.url.searchParams.get('sponsorship_cfg_id');
$ae_loc.mod.sponsorships.cfg_id = data.url.searchParams.get('sponsorship_cfg_id');
}
// *** Electron Native Mode Detection ***
// Explicitly set is_native if the bridge is detected, ensuring reactivity for all child components
// @ts-ignore
if (window.native_app || window.aetherNative) {
if (!$ae_loc.is_native) {
console.log('ELECTRON: Native environment detected via window bridge.');
$ae_loc.is_native = true;
}
// Ensure launcher mode is set to native if we're in the bridge
if ($events_loc?.launcher && $events_loc.launcher.app_mode !== 'native') {
$events_loc.launcher.app_mode = 'native';
}
}
}
}
});
// We want to loop through all of the data store (ds) key value pairs and set them to localStorage
// $: if (ae_acct.ds) {