import * as React from "react" ; import _logger , { proxyLogger } from "../lib/logger" ; import parseUrl from "../lib/parse-url" ; import { Session } from ".." ; import { BroadcastChannel , CtxOrReq , apiBaseUrl , fetchData , now , NextAuthClientConfig , } from "../client/_utils" ; import type { ClientSafeProvider , LiteralUnion , SessionProviderProps , SignInAuthorisationParams , SignInOptions , SignInResponse , SignOutParams , SignOutResponse , UseSessionOptions , } from "./types" ; import type { BuiltInProviderType , RedirectableProviderType , } from "../providers" ; export * from "./types" ; const __NEXTAUTH = { baseUrl : parseUrl ( process . env . NEXTAUTH_URL ?? process . env . VERCEL_URL ) . origin , basePath : parseUrl ( process . env . NEXTAUTH_URL ) . path , baseUrlServer : parseUrl ( process . env . NEXTAUTH_URL_INTERNAL ?? process . env . NEXTAUTH_URL ?? process . env . VERCEL_URL ) . origin , basePathServer : parseUrl ( process . env . NEXTAUTH_URL_INTERNAL ?? process . env . NEXTAUTH_URL ) . path , _lastSync : 0 , _session : undefined , _getSession : ( ) => { } , } ; const broadcast = BroadcastChannel ( ) ; const logger = proxyLogger ( _logger , __NEXTAUTH . basePath ) ; export type SessionContextValue < R extends boolean = false > = R extends true ? { data : Session ; status : "authenticated" ; } | { data : null ; status : "loading" ; } : { data : Session ; status : "authenticated" ; } | { data : null ; status : "unauthenticated" | "loading" ; } ; const SessionContext = React . createContext < SessionContextValue | undefined > ( undefined ) ; /**
 * React Hook that gives you access
 * to the logged in user's session data.
 *
 * [Documentation](https://next-auth.js.org/getting-started/client#usesession)
 */ export function useSession < R extends boolean > ( options ? ) { const value = React . useContext ( SessionContext ) ; if ( ! value && process . env . NODE_ENV !== "production" ) { throw new Error ( "[next-auth]: `useSession` must be wrapped in a <SessionProvider />" ) ; } const { required , onUnauthenticated } = options ?? { } ; const requiredAndNotLoading = required && value . status === "unauthenticated" ; React . useEffect ( ( ) => { if ( requiredAndNotLoading ) { const url = `/api/auth/signin?${ new URLSearchParams ( { error : "SessionRequired" , callbackUrl : window . location . href , } ) }` ; if ( onUnauthenticated ) onUnauthenticated ( ) ; else window . location . href = url ; } } , [ requiredAndNotLoading , onUnauthenticated ] ) ; if ( requiredAndNotLoading ) { return { data : value . data , status : "loading" } as const ; } return value ; } export type GetSessionParams = CtxOrReq & { event ? : "storage" | "timer" | "hidden" | string ; triggerEvent ? : boolean ; broadcast ? : boolean ; } ; export async function getSession ( params ? ) { const session = await fetchData < Session > ( "session" , __NEXTAUTH , logger , params ) ; if ( params ?. broadcast ?? true ) { broadcast . post ( { event : "session" , data : { trigger : "getSession" } } ) ; } return session ; } /**
 * Returns the current Cross Site Request Forgery Token (CSRF Token)
 * required to make POST requests (e.g. for signing in and signing out).
 * You likely only need to use this if you are not using the built-in
 * `signIn()` and `signOut()` methods.
 *
 * [Documentation](https://next-auth.js.org/getting-started/client#getcsrftoken)
 */ export async function getCsrfToken ( params ? ) { const response = await fetchData < { csrfToken : string ; } > ( "csrf" , __NEXTAUTH , logger , params ) ; return response ?. csrfToken ; } /**
 * It calls `/api/auth/providers` and returns
 * a list of the currently configured authentication providers.
 * It can be useful if you are creating a dynamic custom sign in page.
 *
 * [Documentation](https://next-auth.js.org/getting-started/client#getproviders)
 */ export async function getProviders ( ) { return await fetchData < Record < LiteralUnion < BuiltInProviderType > , ClientSafeProvider > > ( "providers" , __NEXTAUTH , logger ) ; } /**
 * Client-side method to initiate a signin flow
 * or send the user to the signin page listing all possible providers.
 * Automatically adds the CSRF token to the request.
 *
 * [Documentation](https://next-auth.js.org/getting-started/client#signin)
 */ export async function signIn < P extends RedirectableProviderType | undefined = undefined > ( provider ? , options ? , authorizationParams ? ) { const { callbackUrl = window . location . href , redirect = true } = options ?? { } ; const baseUrl = apiBaseUrl ( __NEXTAUTH ) ; const providers = await getProviders ( ) ; if ( ! providers ) { window . location . href = `${ baseUrl }/error` ; return ; } if ( ! provider || ! ( provider in providers ) ) { window . location . href = `${ baseUrl }/signin?${ new URLSearchParams ( { callbackUrl , } ) }` ; return ; } const isCredentials = providers [ provider ] . type === "credentials" ; const isEmail = providers [ provider ] . type === "email" ; const isSupportingReturn = isCredentials || isEmail ; const signInUrl = `${ baseUrl }/${ isCredentials ? "callback" : "signin" }/${ provider }` ; const _signInUrl = `${ signInUrl }?${ new URLSearchParams ( authorizationParams ) }` ; const res = await fetch ( _signInUrl , { method : "post" , headers : { "Content-Type" : "application/x-www-form-urlencoded" , } , body : new URLSearchParams ( { ... options , csrfToken : await getCsrfToken ( ) , callbackUrl , json : true , } ) , } ) ; const data = await res . json ( ) ; if ( redirect || ! isSupportingReturn ) { const url = data . url ?? callbackUrl ; window . location . href = url ; if ( url . includes ( "#" ) ) window . location . reload ( ) ; return ; } const error = new URL ( data . url ) . searchParams . get ( "error" ) ; if ( res . ok ) { await __NEXTAUTH . _getSession ( { event : "storage" } ) ; } return { error , status : res . status , ok : res . ok , url : error ? null : data . url , } as any ; } /**
 * Signs the user out, by removing the session cookie.
 * Automatically adds the CSRF token to the request.
 *
 * [Documentation](https://next-auth.js.org/getting-started/client#signout)
 */ export async function signOut < R extends boolean = true > ( options ? ) { const { callbackUrl = window . location . href } = options ?? { } ; const baseUrl = apiBaseUrl ( __NEXTAUTH ) ; const fetchOptions = { method : "post" , headers : { "Content-Type" : "application/x-www-form-urlencoded" , } , body : new URLSearchParams ( { csrfToken : await getCsrfToken ( ) , callbackUrl , json : true , } ) , } ; const res = await fetch ( `${ baseUrl }/signout` , fetchOptions ) ; const data = await res . json ( ) ; broadcast . post ( { event : "session" , data : { trigger : "signout" } } ) ; if ( options ?. redirect ?? true ) { const url = data . url ?? callbackUrl ; window . location . href = url ; if ( url . includes ( "#" ) ) window . location . reload ( ) ; return ; } await __NEXTAUTH . _getSession ( { event : "storage" } ) ; return data ; } /**
 * Provider to wrap the app in to make session data available globally.
 * Can also be used to throttle the number of requests to the endpoint
 * `/api/auth/session`.
 *
 * [Documentation](https://next-auth.js.org/getting-started/client#sessionprovider)
 */ export function SessionProvider ( props ) { const { children , basePath } = props ; if ( basePath ) __NEXTAUTH . basePath = basePath ; /**
     * If session was `null`, there was an attempt to fetch it,
     * but it failed, but we still treat it as a valid initial value.
     */ const hasInitialSession = props . session !== undefined ; /** If session was passed, initialize as already synced */ __NEXTAUTH . _lastSync = hasInitialSession ? now ( ) : 0 ; const [ session , setSession ] = React . useState ( ( ) => { if ( hasInitialSession ) __NEXTAUTH . _session = props . session ; return props . session ; } ) ; /** If session was passed, initialize as not loading */ const [ loading , setLoading ] = React . useState ( ! hasInitialSession ) ; React . useEffect ( ( ) => { __NEXTAUTH . _getSession = async ( { event } = { } ) => { try { const storageEvent = event === "storage" ; if ( storageEvent || __NEXTAUTH . _session === undefined ) { __NEXTAUTH . _lastSync = now ( ) ; __NEXTAUTH . _session = await getSession ( { broadcast : ! storageEvent , } ) ; setSession ( __NEXTAUTH . _session ) ; return ; } if ( ! event || __NEXTAUTH . _session === null || now ( ) < __NEXTAUTH . _lastSync ) { return ; } __NEXTAUTH . _lastSync = now ( ) ; __NEXTAUTH . _session = await getSession ( ) ; setSession ( __NEXTAUTH . _session ) ; } catch ( error ) { logger . error ( "CLIENT_SESSION_ERROR" , error as Error ) ; } finally { setLoading ( false ) ; } } ; __NEXTAUTH . _getSession ( ) ; } , [ ] ) ; React . useEffect ( ( ) => { const unsubscribe = broadcast . receive ( ( ) => __NEXTAUTH . _getSession ( { event : "storage" } ) ) ; return ( ) => unsubscribe ( ) ; } , [ ] ) ; React . useEffect ( ( ) => { const visibilityHandler = ( ) => { if ( document . visibilityState === "visible" ) __NEXTAUTH . _getSession ( { event : "visibilitychange" } ) ; } ; document . addEventListener ( "visibilitychange" , visibilityHandler , false ) ; return ( ) => document . removeEventListener ( "visibilitychange" , visibilityHandler , false ) ; } , [ ] ) ; React . useEffect ( ( ) => { const { refetchInterval } = props ; if ( refetchInterval ) { const refetchIntervalTimer = setInterval ( ( ) => { if ( __NEXTAUTH . _session ) { __NEXTAUTH . _getSession ( { event : "poll" } ) ; } } , refetchInterval * 1000 ) ; return ( ) => clearInterval ( refetchIntervalTimer ) ; } } , [ props . refetchInterval ] ) ; const value = React . useMemo ( ( ) => ( { data : session , status : loading ? "loading" : session ? "authenticated" : "unauthenticated" , } ) , [ session , loading ] ) ; return ( < SessionContext . Provider value = { value } > { children } < /SessionContext.Provider>); }