/** * New-deploy detection for the SPA. * * The server stamps every response with `X-App-Version`. `apiFetch` feeds that * header here via `reportServerVersion`. When it differs from the version baked * into THIS bundle at build time (`BUILD_VERSION`), a deploy has happened — we * latch it and notify subscribers (the refresh banner). We never force a * reload; the user picks the moment (they may be mid-form). */ // Injected by Vite `define` at build time; falls back to "dev" in tests / when // running unbuilt. `typeof` guard avoids a ReferenceError when undefined. declare const __APP_VERSION__: string; export const BUILD_VERSION: string = typeof __APP_VERSION__ !== "undefined" ? __APP_VERSION__ : "dev"; let newVersion: string | null = null; const listeners = new Set<() => void>(); /** * Compare a server-reported version against this bundle's build version. Latches * the first genuine mismatch and notifies subscribers exactly once. */ export function reportServerVersion( serverVersion: string | null | undefined, ): void { if (newVersion) return; // already latched — banner is up if (!serverVersion || serverVersion === BUILD_VERSION) return; newVersion = serverVersion; for (const l of listeners) l(); } export function subscribeNewVersion(listener: () => void): () => void { listeners.add(listener); return () => { listeners.delete(listener); }; } export function getNewVersion(): string | null { return newVersion; } /** Test-only: reset the module singleton between cases. */ export function __resetVersionStateForTest(): void { newVersion = null; listeners.clear(); }