// ==========================================
// Chat Switchboard – Application (Chat Surface)
// ==========================================
// Boot, auth, init, listener dispatch.
// Shared state (App) and model loading (fetchModels) live in app-state.js
// (loaded by base.html for all surfaces).
// Domain logic lives in chat.js, notes.js, settings-handlers.js,
// admin-handlers.js. UI rendering in ui-*.js files.
async function init() {
console.log('🔀 Chat Switchboard initializing...');
initBranding(); // Apply branding before splash is visible
API.loadTokens();
let health = null;
try {
health = await API.health();
console.log('✅ Backend reachable:', health.version);
} catch (e) {
console.error('❌ Backend unreachable:', e.message);
const splashErr = document.getElementById('splashError');
if (e.proxyBlocked) {
splashErr.innerHTML =
`Network proxy blocked this request
` +
`Proxy response: "${API._esc(e.proxyTitle)}"
` +
`Ask your network admin to whitelist this domain. ` +
`Run diagnostics`;
} else if (e.name === 'TimeoutError' || e.name === 'AbortError') {
splashErr.innerHTML =
`Connection timed out
` +
`Server may be starting up, or a proxy is blocking the connection. ` +
`Run diagnostics`;
} else {
splashErr.innerHTML =
`Cannot reach server
` +
`${API._esc(e.message)}. ` +
`Run diagnostics`;
}
showSplash(null);
return;
}
if (API.isAuthed) {
try {
await API.getProfile();
console.log('✅ Session valid for', API.user?.username);
} catch (e) {
console.warn('⚠️ Session expired, clearing');
API.clearTokens();
}
}
if (API.isAuthed) {
try {
await startApp();
} catch (e) {
console.error('💥 startApp crashed:', e);
// Surface the error visibly (crash banner from chat.html)
const b = document.getElementById('crashBanner');
const d = document.getElementById('crashDetail');
if (b && d) { b.style.display = ''; d.textContent += 'startApp: ' + e.message + '\n' + (e.stack || '') + '\n'; }
}
} else {
showSplash(health);
}
}
async function startApp() {
hideSplash();
UI.restoreSidebar();
await loadSettings();
// Load extensions BEFORE chats so block renderers (mermaid, katex, csv, diff)
// are registered when messages are first rendered.
try {
await Extensions.loadAll(); // fetch manifests + inject