Reload when the server is running a newer build
Being signed out and picking up a new version are separate things, and only the first was happening. An immutable instance holds sessions in memory, so a deploy signs everyone out -- but a 401 only swaps the view to the sign-in form, client-side. The tab keeps the bundle it already has, and the old JavaScript goes on talking to the new server until someone happens to reload by hand. The pieces for fixing it were already there. index.html is served no-cache and the assets under it are content-hashed and immutable, so a reload is all it takes; Vite bakes the build's own version in as APP_VERSION; and /api/health reports the server's. What was missing was something to compare them. The check runs on a 401 rather than on a timer, which is the moment it matters and costs one small request. It compares versions rather than reloading on every 401, so an ordinary session expiry still lands on the sign-in form with the page intact. And it runs before the sign-in form is shown rather than after, because reloading a form someone has already started typing into would throw the password away. Failing to reach the server is not a reason to throw away what is on screen, so anything other than a clear answer leaves the page alone. The version that was reloaded for is remembered for the session, so a server that keeps reporting a version the bundle does not match -- a stale proxy cache, a half-finished deploy -- cannot put the tab in a reload loop.
This commit is contained in:
@@ -5,6 +5,7 @@ import { push, type PushState } from "@/jmap/push";
|
||||
import { accountForCapability, ownAccountForCapability } from "@/lib/accountRouting";
|
||||
import { setServerLocale } from "@/lib/datetime";
|
||||
import { flushSettingsPush, stopSettingsSync } from "@/lib/settingsSync";
|
||||
import { reloadIfServerRebuilt } from "@/lib/staleBuild";
|
||||
import { unsubscribeThisDevice } from "@/lib/webpush";
|
||||
|
||||
export type AuthStatus = "loading" | "anonymous" | "authenticated";
|
||||
@@ -119,7 +120,12 @@ client.onUnauthenticated(() => {
|
||||
push.stop();
|
||||
stopSettingsSync();
|
||||
client.session = null;
|
||||
useSession.setState({ status: "anonymous", session: null, accountId: null });
|
||||
// Ask before showing the sign-in form rather than after. A deploy is the
|
||||
// usual reason to be signed out here, and reloading a form someone has
|
||||
// already started typing into would throw the password away.
|
||||
void reloadIfServerRebuilt().then((reloading) => {
|
||||
if (!reloading) useSession.setState({ status: "anonymous", session: null, accountId: null });
|
||||
});
|
||||
});
|
||||
|
||||
push.onConnection((state) => useSession.setState({ pushConnected: state === "connected", pushState: state }));
|
||||
|
||||
Reference in New Issue
Block a user