Files
OSIT-AE-App-Svelte/src/routes/+layout.ts
Scott Idem efdf1188a6 Fix: Persist native sync timers and implement monitor UI
- Implemented safe merge in root layout to preserve local timer overrides.
- Added Native Sync Monitor UI to background sync component.
- Exposed loop periods and hash prefix length in Launcher Config.
- Ensured manual adjustments survive page refreshes.
2026-01-23 16:56:02 -05:00

311 lines
12 KiB
TypeScript

/** @type {import('./$types').LayoutLoad} */
// console.log(`ae_root +layout.ts: start`);
import { error } from '@sveltejs/kit';
import { lookup_site_domain_v3 } from '$lib/ae_core/ae_core__site';
import type { key_val } from '$lib/stores/ae_stores';
import type { ae_SiteDomain } from '$lib/types/ae_types';
export const ssr = false;
export const prerender = false;
import {
PUBLIC_AE_API_PROTOCOL,
PUBLIC_AE_API_SERVER,
PUBLIC_AE_API_BAK_SERVER,
PUBLIC_AE_API_PORT,
PUBLIC_AE_API_PATH,
PUBLIC_AE_API_SECRET_KEY,
PUBLIC_AE_API_CRUD_SUPER_KEY,
PUBLIC_AE_NO_ACCOUNT_ID,
PUBLIC_AE_NO_ACCOUNT_ID_TOKEN
} from '$env/static/public';
const api_base_url = `${PUBLIC_AE_API_PROTOCOL}://${PUBLIC_AE_API_SERVER}:${PUBLIC_AE_API_PORT}${PUBLIC_AE_API_PATH}`;
const api_base_url_bak = `${PUBLIC_AE_API_PROTOCOL}://${PUBLIC_AE_API_BAK_SERVER}:${PUBLIC_AE_API_PORT}${PUBLIC_AE_API_PATH}`;
const api_secret_key = PUBLIC_AE_API_SECRET_KEY;
const api_crud_super_key = PUBLIC_AE_API_CRUD_SUPER_KEY;
const ae_account_id: null | string = null;
const ae_no_account_id = PUBLIC_AE_NO_ACCOUNT_ID;
const ae_no_account_id_token = PUBLIC_AE_NO_ACCOUNT_ID_TOKEN;
const ae_api_init: key_val = {
ver: '2024-08-11_11',
base_url: api_base_url,
base_url_bak: api_base_url_bak,
api_secret_key: api_secret_key,
api_secret_key_bak: api_secret_key,
api_crud_super_key: api_crud_super_key,
headers: {},
account_id: ae_account_id
};
const ae_api_headers: key_val = {
'Content-Type': 'application/json',
'x-aether-api-key': api_secret_key,
'x-ae-ignore-extra-fields': 'true'
};
ae_api_init['headers'] = ae_api_headers;
export async function load({ fetch, params, parent, route, url }) {
const log_lvl: number = 1;
let account_id: any;
const ae_acct: key_val = {
api: {
...ae_api_init,
headers: { ...ae_api_headers } // Local clone
},
ds: {},
loc: {
account_id: '',
site_id: '',
site_domain_id: '',
iframe: false
},
sess: {},
slct: {}
};
// Initialize API fetch with SvelteKit fetch
ae_api_init['fetch'] = fetch;
// IMMEDIATE AUTH SYNC: Read JWT from localStorage to avoid race conditions
if (typeof localStorage !== 'undefined') {
try {
const ae_loc_raw = localStorage.getItem('ae_loc');
if (ae_loc_raw) {
const ae_loc_json = JSON.parse(ae_loc_raw);
if (ae_loc_json.jwt) {
ae_api_init['jwt'] = ae_loc_json.jwt;
}
}
} catch (e) {
// Silently fail on storage read
}
}
const ae_loc_init: key_val = {};
const ds_code_li: null | key_val = {};
const data_struct: key_val = {
account_id: null,
ae_acct: {},
ae_loc: {},
ae_api: ae_api_init,
ae_ds: {},
ae_hub: {},
ae_m_sponsorships: {},
ae_m_events: {},
ae_m_events_speakers: {},
ae_m_idaa: {},
ae_slct: {},
iframe: false,
ae_root_layout_ts: true,
params: params,
route: route,
url: url,
sections: [
{ slug: 'new', title: 'New Test' },
{ slug: 'manage', title: 'Manage Test' },
{ slug: 'test', title: 'Test Test' }
],
submenu: {}
};
const fqdn = url.host;
let result: any = null;
let api_error = false;
let is_native = false;
// Detect Aether Native Bridge (Electron)
if (typeof window !== 'undefined' && (window as any).aetherNative) {
is_native = true;
if (log_lvl) console.log('ROOT LOAD: Detected Aether Native Bridge. Requesting device config...');
try {
const native_device_config = await (window as any).aetherNative.get_device_config();
if (native_device_config) {
if (log_lvl) console.log('ROOT LOAD: Native device config received:', native_device_config);
// Map native device config to the expected result structure
result = {
...native_device_config,
// Ensure naming consistency
account_id: native_device_config.account_id || native_device_config.account_id_random,
site_id: native_device_config.site_id || native_device_config.site_id_random,
site_domain_id: native_device_config.site_domain_id || native_device_config.site_domain_id_random,
};
// Inject native device metadata into the location state with SAFE MERGE
if (native_device_config.native_device) {
const incoming_dev = native_device_config.native_device;
// 1. Recover existing user overrides from localStorage
let existing_dev = {};
try {
const raw = localStorage.getItem('ae_loc');
if (raw) existing_dev = JSON.parse(raw).native_device || {};
} catch (e) {}
// 2. Merge: Priority to EXISTING overrides for specific timers
ae_loc_init['native_device'] = {
...incoming_dev,
// Persist these specific user-controlled fields
check_event_loop_period: (existing_dev as any).check_event_loop_period || incoming_dev.check_event_loop_period,
check_event_device_loop_period: (existing_dev as any).check_event_device_loop_period || incoming_dev.check_event_device_loop_period,
check_event_location_loop_period: (existing_dev as any).check_event_location_loop_period || incoming_dev.check_event_location_loop_period,
check_event_session_loop_period: (existing_dev as any).check_event_session_loop_period || incoming_dev.check_event_session_loop_period,
hash_prefix_length: (existing_dev as any).hash_prefix_length || incoming_dev.hash_prefix_length
};
// Map specific operational paths
ae_loc_init['local_file_cache_path'] = incoming_dev.local_file_cache_path;
ae_loc_init['host_file_temp_path'] = incoming_dev.host_file_temp_path;
ae_loc_init['recording_path'] = incoming_dev.recording_path;
}
// IMPORTANT: Update API settings with the native-authorized key if present
if (native_device_config.aether_api_key) {
ae_api_init['api_secret_key'] = native_device_config.aether_api_key;
ae_api_headers['x-aether-api-key'] = native_device_config.aether_api_key;
}
}
} catch (err) {
console.error('ROOT LOAD: Failed to fetch native device config.', err);
}
}
// Perform standard FQDN lookup if not native or if native fetch failed
if (!result) {
try {
if (log_lvl) console.log(`ROOT LOAD: Starting site lookup V3 for ${fqdn}...`);
// Use dedicated Agent Key for Bootstrap and include the unauthenticated bypass header ONLY for this request
const bootstrap_api_cfg = {
...ae_api_init,
api_secret_key: 'IDF68Em5X4HTZlswRNgepQ',
headers: {
...ae_api_init.headers,
'x-aether-api-key': 'IDF68Em5X4HTZlswRNgepQ',
'x-no-account-id': 'bypass' // Force explicit bypass for bootstrap
}
};
result = await lookup_site_domain_v3({
api_cfg: bootstrap_api_cfg,
fqdn,
view: 'base',
log_lvl
});
if (log_lvl) console.log(`ROOT LOAD: Site lookup result for ${fqdn}:`, result);
} catch (err) {
console.error(`ROOT LOAD: Site lookup critical failure for ${fqdn}.`, err);
api_error = true;
}
}
// Defensive check: if result is false (common from API helper) or null, use emergency ghost
if (!result || typeof result !== 'object' || result.account_id === 'ghost') {
console.warn(`ROOT LOAD: Falsy or Ghost result for ${fqdn}. Forcing fallback message.`);
result = {
id: 'ghost',
id_random: 'ghost',
account_id_random: 'ghost',
account_code: 'ghost',
account_name: api_error ? 'API Connection Failed' : 'Domain Not Registered',
site_id_random: 'ghost',
site_domain_id_random: 'ghost',
enable: '1',
cfg_json: {},
style_href: '',
header_image_path: ''
};
}
const json_data = result;
// ... rest of the mapping logic ...
account_id = json_data.account_id || json_data.account_id_random || 'ghost';
data_struct.account_id = account_id;
ae_acct.account_id = account_id;
if (log_lvl) console.log(`ROOT LOAD: Using account_id: ${account_id}`);
// Update the local clones
ae_acct.api.account_id = account_id;
ae_acct.api.headers['x-account-id'] = account_id;
ae_loc_init['is_native'] = is_native;
ae_loc_init['account_id'] = account_id;
ae_loc_init['account_code'] = json_data.account_code || 'ghost';
ae_loc_init['account_name'] = json_data.account_name || 'Ghost Account';
ae_loc_init['site_id'] = json_data.site_id || json_data.site_id_random || 'ghost';
ae_loc_init['site_domain_id'] = json_data.site_domain_id || json_data.site_domain_id_random || 'ghost';
ae_loc_init['site_enable'] = json_data.enable || '1';
ae_loc_init['site_header_image_path'] = json_data.header_image_path || '';
ae_loc_init['site_style_href'] = json_data.style_href || '';
ae_loc_init['site_google_tracking_id'] = json_data.google_tracking_id || '';
ae_loc_init['site_access_code_kv'] = json_data.access_code_kv_json || {};
ae_loc_init['site_cfg_json'] = json_data.cfg_json || {};
ae_loc_init['site_access_key'] = json_data.access_key || '';
ae_loc_init['site_domain_access_key'] = json_data.site_domain_access_key || '';
ae_loc_init['base_url'] = url.origin;
ae_loc_init['hostname'] = url.hostname;
if (!ae_loc_init['site_access_key'] && !ae_loc_init['site_domain_access_key']) {
ae_loc_init['key_checked'] = true;
ae_loc_init['allow_access'] = true;
} else {
const access_key = url.searchParams.get('key');
if (access_key) {
if (log_lvl) {
console.log(`root +layout.ts: access_key = ${access_key}`);
}
if (access_key == ae_loc_init['site_access_key']) {
ae_loc_init['key_checked'] = ae_loc_init['site_access_key'];
ae_loc_init['allow_access'] = ae_loc_init['site_access_key'];
}
else if (access_key == ae_loc_init['site_domain_access_key']) {
ae_loc_init['key_checked'] = ae_loc_init['site_domain_access_key'];
ae_loc_init['allow_access'] = ae_loc_init['site_domain_access_key'];
} else {
ae_loc_init['key_checked'] = true;
ae_loc_init['allow_access'] = false;
}
} else {
ae_loc_init['key_checked'] = true;
}
}
// if (!account_id) {
// error(500, {
// message: 'The account ID was not found! Check the API.'
// });
// }
ae_loc_init['account_name'] = json_data.account_name || 'Account Name Not Set';
// ae_acct['api'] = ae_api_init; // DO NOT USE: This overwrites our isolated clone from line 65
ae_acct['loc'] = ae_loc_init;
ae_acct['ds'] = ds_code_li;
ae_acct['slct'] = {
account_id: account_id,
site_domain_id: ae_loc_init.site_domain_id,
site_id: ae_loc_init.site_id,
event_id: ae_loc_init.site_cfg_json?.slct__event_id,
event_badge_template_id: ae_loc_init.site_cfg_json?.slct__event_badge_template_id,
sponsorship_cfg_id: ae_loc_init.site_cfg_json?.slct__sponsorship_cfg_id
};
data_struct[account_id] = ae_acct;
if (log_lvl) console.log('ROOT LOAD: Final data_struct structure ready.', Object.keys(data_struct));
return data_struct;
}