// Pure decisions for the /sign-in OAuth flow. Extracted so the // signed-query ordering and the signed-in render/redirect contract can // be unit-tested without React/DOM. The page consumes these helpers; do // not duplicate the logic in `pages/sign-in.tsx`. // tessera-local UI params that may appear next to a signed RP-initiated // /authorize query (e.g. `?error=social_unavailable&`). The // extractor skips them so the rebuilt slice is byte-equal to what // Better Auth signed. const SIGNED_QUERY_LOCAL_KEYS = new Set(["error", "redirect"]); // Returns the original signed parameter sequence through `sig`, with // tessera-local UI params filtered out. Returns null when the URL is // not an RP-initiated /authorize (no `client_id` + `sig` pair). export const signedOAuthQueryFromParams = (params: URLSearchParams): string | null => { if (!params.has("client_id") || !params.has("sig")) return null; const signed = new URLSearchParams(); for (const [key, value] of params.entries()) { if (SIGNED_QUERY_LOCAL_KEYS.has(key)) continue; signed.append(key, value); if (key === "sig") return signed.toString(); } return null; }; // Builds the social `errorCallbackURL`. Signed params come first so the // extractor's stop-at-sig invariant is preserved end-to-end even if a // stale tab loads the URL: `?error=...&` would also recover via // the extractor's blocklist, but constructing it signed-first removes // the dependency on that hardening for current code paths. export const socialErrorCallbackURL = (signedOAuthQuery: string | null): string => signedOAuthQuery ? `/sign-in?${signedOAuthQuery}&error=social_unavailable` : "/sign-in?error=social_unavailable"; // Better Auth reaches /sign-in even with an active session when the RP // requests `prompt=login` or `prompt=create`. Auto-navigating away on // the basis of "user has a session" alone would drop the RP's signed // authorization request. Redirect only when no signed query is present. export const shouldRedirectSignedInFromSignIn = (input: { sessionPending: boolean; signedInUserId: string | null; signedOAuthQuery: string | null; }): boolean => { if (input.sessionPending) return false; if (!input.signedInUserId) return false; if (input.signedOAuthQuery) return false; return true; };