diff --git a/csv-table-hub-main/src/__tests__/session.test.ts b/csv-table-hub-main/src/__tests__/session.test.ts index d5fbecd..6037403 100644 --- a/csv-table-hub-main/src/__tests__/session.test.ts +++ b/csv-table-hub-main/src/__tests__/session.test.ts @@ -130,7 +130,10 @@ describe("requireSession (route guard)", () => { thrown = e; } expect(isRedirect(thrown)).toBe(true); - expect((thrown as { options: { to: string } }).options.to).toBe("/auth"); + const { options } = thrown as { options: { to: string; reloadDocument?: boolean } }; + expect(options.to).toBe("/auth"); + // #133: a client-side redirect during hydration crashed the router (React #520/#422). + expect(options.reloadDocument).toBe(true); }); it("lets a signed-in user through", () => { diff --git a/csv-table-hub-main/src/lib/session.ts b/csv-table-hub-main/src/lib/session.ts index 3fd75a9..a791a38 100644 --- a/csv-table-hub-main/src/lib/session.ts +++ b/csv-table-hub-main/src/lib/session.ts @@ -98,9 +98,11 @@ export function authHeaders(): Record { return s ? { Authorization: `Bearer ${s.token}` } : {}; } -/** Route guard (#96): send anyone without a live session to the sign-in page. */ +/** Route guard (#96): send anyone without a live session to the sign-in page. + * A full page load, not a client-side redirect: redirecting while the first + * page hydrates broke the router's match tree (React #520/#422, #133). */ export function requireSession(): void { - if (!getSession()) throw redirect({ to: "/auth" }); + if (!getSession()) throw redirect({ to: "/auth", reloadDocument: true }); } /** Change your own password (#117). This session stays; the server ends all others. */