55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
/**
|
||
* Build-Version-Check: Auto-Reload when a newer build is detected on the server
|
||
*
|
||
* Every GET API response includes the header X-Build-Time with the server's build
|
||
* timestamp. If it's newer than the one embedded in the frontend bundle, a toast
|
||
* is shown and the page is automatically reloaded after a short delay.
|
||
*/
|
||
import { buildTime } from "./buildInfo"
|
||
import { addToast } from "./toast"
|
||
|
||
/** Prevents multiple triggers within the same page session */
|
||
let triggered = false
|
||
|
||
const RELOAD_DELAY_MS = 3000
|
||
const STORAGE_KEY = "__build_reload__"
|
||
|
||
/**
|
||
* Checks whether the server has a newer build than the current frontend bundle.
|
||
* Only runs in the browser (SSR-safe).
|
||
*
|
||
* @param serverBuildTime - ISO timestamp from the X-Build-Time response header
|
||
*/
|
||
export function checkBuildVersion(serverBuildTime: string | null | undefined): void {
|
||
if (!serverBuildTime || typeof window === "undefined") return
|
||
if (triggered) return
|
||
|
||
// Only react if the server build is actually newer
|
||
if (serverBuildTime <= buildTime) return
|
||
|
||
// Loop protection: if we already reloaded for this exact build, don't reload again
|
||
// (e.g. CDN/cache still serving old bundle)
|
||
try {
|
||
if (sessionStorage.getItem(STORAGE_KEY) === serverBuildTime) return
|
||
} catch (_) {
|
||
// sessionStorage not available (e.g. privacy mode) – continue anyway
|
||
}
|
||
|
||
triggered = true
|
||
|
||
// Show toast notification
|
||
addToast("New version available – page will refresh…", "info", RELOAD_DELAY_MS + 2000)
|
||
|
||
// Remember that we're reloading for this build timestamp
|
||
try {
|
||
sessionStorage.setItem(STORAGE_KEY, serverBuildTime)
|
||
} catch (_) {
|
||
// ignore
|
||
}
|
||
|
||
// Auto-reload after short delay so toast is visible
|
||
setTimeout(() => {
|
||
window.location.reload()
|
||
}, RELOAD_DELAY_MS)
|
||
}
|