mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
refactor(auth): navigate for single sign-on at the call sites again
Moving the navigation into the shared helper took both sign-in hand-offs out of what the headerless-transport guard walks, which only reads the component and page trees. The helper now only clears the offline copies with the capped wait, and each page navigates itself. The device registration test checks the end of the no-device rest inside the test that already pairs an iPhone instead of a copy of it.
This commit is contained in:
1 parent
f78c9b0b78
commit
ae005f020b
5 files changed
+22
-32
No files matched your search
@@ -221,21 +221,8 @@ describe("POST /api/devices", () => {
|
||||
};
|
||||
expect(args.data.apnsToken).toBe("deadbeef".repeat(8));
|
||||
expect(args.data.apnsEnvironment).toBe("sandbox");
|
||||
});
|
||||
|
||||
it("ends a pause that was waiting for a paired iPhone", async () => {
|
||||
// A reminder with no iPhone paired rests the APNs channel for an hour;
|
||||
// pairing one must not leave the next reminder waiting it out.
|
||||
vi.mocked(getSession).mockResolvedValue(SESSION_OK as never);
|
||||
const res = await POST(
|
||||
req({
|
||||
token: "abcd1234efgh5678",
|
||||
bundleId: "io.healthlog.app",
|
||||
apnsToken: "deadbeef".repeat(8),
|
||||
apnsEnvironment: "sandbox",
|
||||
}),
|
||||
);
|
||||
expect(res.status).toBe(201);
|
||||
// pairing one ends that rest, so the next reminder does not wait it out.
|
||||
expect(prisma.notificationChannel.updateMany).toHaveBeenCalledWith({
|
||||
where: {
|
||||
userId: "user-1",
|
||||
|
||||
@@ -24,7 +24,7 @@ import { OIDC_MFA_COOKIE, OIDC_MFA_COOKIE_PATH } from "@/lib/auth/oidc-cookie";
|
||||
import { isDashboardSnapshotEnabled } from "@/lib/dashboard/snapshot-flag";
|
||||
import { prefetchDashboardSnapshot } from "@/lib/queries/use-dashboard-snapshot";
|
||||
import { clearOfflineCachesForSessionEnd } from "@/lib/pwa/query-persister";
|
||||
import { leaveForSingleSignOn } from "@/lib/auth/leave-for-single-sign-on";
|
||||
import { clearOfflineCachesBeforeLeaving } from "@/lib/pwa/clear-before-leaving";
|
||||
import { sanitizeSameOriginPath } from "@/lib/url-safety";
|
||||
import { localizedSignInError } from "@/lib/api/localized-error";
|
||||
import { formatDate } from "@/lib/format";
|
||||
@@ -184,7 +184,9 @@ export default function LoginPage() {
|
||||
params.set("client_proto", clientTransport.protocol);
|
||||
params.set("client_host", clientTransport.host);
|
||||
}
|
||||
await leaveForSingleSignOn(`/api/auth/oidc/login?${params}`);
|
||||
// The session starts on the way back; the last account's copies go first.
|
||||
await clearOfflineCachesBeforeLeaving();
|
||||
loadDocument(`/api/auth/oidc/login?${params}`);
|
||||
}
|
||||
|
||||
function getRedirectTarget(): string {
|
||||
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
import { ApiError } from "@/lib/api/api-fetch";
|
||||
import { showErrorToast } from "@/lib/errors/error-toast";
|
||||
import { useFormatters, useTranslations } from "@/lib/i18n/context";
|
||||
import { leaveForSingleSignOn } from "@/lib/auth/leave-for-single-sign-on";
|
||||
import { loadDocument } from "@/lib/navigation/load-document";
|
||||
import { clearOfflineCachesBeforeLeaving } from "@/lib/pwa/clear-before-leaving";
|
||||
import {
|
||||
useClaimProfile,
|
||||
useClaimProfileSso,
|
||||
@@ -110,7 +111,9 @@ export function ClaimProfile({
|
||||
next.searchParams.set("client_proto", clientTransport.protocol);
|
||||
next.searchParams.set("client_host", clientTransport.host);
|
||||
}
|
||||
await leaveForSingleSignOn(`${next.pathname}${next.search}`);
|
||||
// The session starts on the way back; the last account's copies go first.
|
||||
await clearOfflineCachesBeforeLeaving();
|
||||
loadDocument(`${next.pathname}${next.search}`);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { settleWithin } from "@/lib/async/settle-within";
|
||||
import { loadDocument } from "@/lib/navigation/load-document";
|
||||
import { clearOfflineCachesForSessionEnd } from "@/lib/pwa/query-persister";
|
||||
|
||||
/**
|
||||
* Leave for the identity provider. The session starts on the way back, so
|
||||
* the last account's offline copies go first. The wait for them is capped:
|
||||
* WebKit can leave an IndexedDB open hanging after the installed app returns
|
||||
* from the background, and the button must still work then.
|
||||
*/
|
||||
export async function leaveForSingleSignOn(url: string): Promise<void> {
|
||||
await settleWithin(clearOfflineCachesForSessionEnd(), 1_500, undefined);
|
||||
loadDocument(url);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { settleWithin } from "@/lib/async/settle-within";
|
||||
import { clearOfflineCachesForSessionEnd } from "@/lib/pwa/query-persister";
|
||||
|
||||
/**
|
||||
* The session-end wipe before the page leaves for the identity provider,
|
||||
* where the next session starts. The wait is capped: WebKit can leave an
|
||||
* IndexedDB open hanging after the installed app returns from the
|
||||
* background, and the button must still work then.
|
||||
*/
|
||||
export function clearOfflineCachesBeforeLeaving(): Promise<void> {
|
||||
return settleWithin(clearOfflineCachesForSessionEnd(), 1_500, undefined);
|
||||
}
|
||||
Reference in new issue
Block a user