refactor(ui): parse the scoped theme entry at the boundary; runtime-switch owns transient keys

The scoped theme entry is now parsed by one boundary parser with a
stated invariant instead of ad hoc typeof narrowing, and the runtime
keys that mean "no instance connected" live next to the code that
produces them so a new sentinel cannot miss the theme-storage guard.
This commit is contained in:
Bohdan Triapitsyn
2026-08-30 13:29:52 +03:00
parent 73fd2e9d9d
commit 6eec839fbf
4 changed files with 63 additions and 55 deletions
+11
View File
@@ -51,6 +51,17 @@ const normalizeRuntimeUrlKey = (value: string): string => {
}
};
// Runtime keys that mean "no instance connected": the uninitialized default
// (`normalizeRuntimeUrlKey` of an empty/unparseable base URL) and the mobile
// disconnect state (`MobileApp` switches to it when the connection drops).
// Per-instance client state (e.g. the scoped theme entry) must not be read
// from or written under them.
export const MOBILE_DISCONNECTED_RUNTIME_KEY = 'mobile-disconnected';
const UNINITIALIZED_RUNTIME_KEY = 'url:default';
export const isTransientRuntimeKey = (runtimeKey: string): boolean =>
runtimeKey === '' || runtimeKey === UNINITIALIZED_RUNTIME_KEY || runtimeKey === MOBILE_DISCONNECTED_RUNTIME_KEY;
const readInjectedApiBaseUrl = (): string => {
if (typeof window === 'undefined') return '';
const injected = (window as typeof window & { __OPENCHAMBER_API_BASE_URL__?: string }).__OPENCHAMBER_API_BASE_URL__;