| 1 | "use client"; |
| 2 | |
| 3 | import type { AuthClient } |
| 4 | import { |
| 5 | useAuth, |
| 6 | useSession, |
| 7 | type UseSessionOptions, |
| 8 | } from "@better-auth-ui/react"; |
| 9 | import { useEffect } |
| 10 | |
| 11 | /** |
| 12 | * Whether an unauthenticated visitor should be bounced to sign-in. |
| 13 | * |
| 14 | * `useSession` serves the stale `null` from a signed-out visit while the refetch is in flight, and redirecting on it loops straight back to sign-in. An in-flight fetch is undecided. |
| 15 | */ |
| 16 | export function shouldRedirectToSignIn(session |
| 17 | data: unknown |
| 18 | isPending: boolean |
| 19 | isFetching: boolean |
| 20 | }) { |
| 21 | return !session.data |
| 22 | } |
| 23 | |
| 24 | /** |
| 25 | * `useSession` plus a redirect to sign-in for unauthenticated visitors, with the current URL preserved as `redirectTo`. |
| 26 | * |
| 27 | * Drop-in replacement for `@better-auth-ui/react`'s `useAuthenticate`, which redirects on a stale session value. |
| 28 | */ |
| 29 | export function useAuthenticate<TAuthClient |
| 30 | authClient: TAuthClient |
| 31 | options?: UseSessionOptions |
| 32 | ) { |
| 33 | const { basePaths, |
| 34 | const session = |
| 35 | const { data, |
| 36 | |
| 37 | useEffect(() => |
| 38 | if (!shouldRedirectToSignIn({ |
| 39 | |
| 40 | const currentURL = |
| 41 | const redirectTo = |
| 42 | |
| 43 | navigate({ |
| 44 | to: `${basePaths. |
| 45 | replace: true, |
| 46 | }); |
| 47 | }, [ |
| 48 | basePaths.auth, |
| 49 | data, |
| 50 | isFetching, |
| 51 | isPending, |
| 52 | navigate, |
| 53 | viewPaths.auth.signIn |
| 54 | ]); |
| 55 | |
| 56 | return session; |
| 57 | } |