import React, { useMemo, useCallback } from "react"; import type { MoonSDKConfig } from "@moonup/moon-sdk"; import { MoonSDK } from "@moonup/moon-sdk"; import type { Session, SupabaseClient, User } from "@supabase/supabase-js"; import { supabase } from "../supabase"; export interface MoonAuthContextType { session: Session | null; user: User | null; signOut: () => Promise; supabaseClient: SupabaseClient; moon: MoonSDK | null; isAuthenticated: boolean; isLoading: boolean; connect: ( accessToken?: string, refreshToken?: string ) => Promise; disconnect: () => Promise; } export const MoonAuthContext = React.createContext( { session: null, user: null, signOut: async () => { }, supabaseClient: supabase, moon: null, isAuthenticated: false, isLoading: true, connect: async ( accessToken?: string, refreshToken?: string, ): Promise => { console.log( "connecting" ); console.log( "accessToken", accessToken ); console.log( "refreshToken", refreshToken ); }, disconnect: async (): Promise => { }, } ); export type MoonAuthProviderProps = { sdkConfig?: MoonSDKConfig; children: React.ReactNode; }; export const MoonAuthProvider = ( { children, sdkConfig, }: MoonAuthProviderProps ) => { const [ user, setUser ] = React.useState( null ); const [ moon ] = React.useState( new MoonSDK( { authInstance: supabase, ...sdkConfig, } ), ); const [ session, setSession ] = React.useState( null ); const [ isLoading, setIsLoading ] = React.useState( true ); const [ isAuthenticated, setIsAuthenticated ] = React.useState( false ); React.useEffect( () => { setIsLoading( true ); const { data: authListener } = supabase.auth.onAuthStateChange( async ( event, newSession ) => { // console.log("Auth state change:", event, newSession); switch ( event ) { case "INITIAL_SESSION": // Initial session will always be null, so we don't need to do anything here break; case "SIGNED_IN": case "TOKEN_REFRESHED": case "USER_UPDATED": if ( newSession ) { setSession( newSession ); setUser( newSession.user ); setIsAuthenticated( true ); moon.moonAPIService.setSecurityData( newSession.access_token ); } break; case "SIGNED_OUT": setSession( null ); setUser( null ); setIsAuthenticated( false ); await moon.disconnect(); break; case "PASSWORD_RECOVERY": // Handle password recovery if needed break; default: // Handle any other events if needed break; } }, ); const initializeAuth = async () => { // Initialize Moon first const { data: { session: initialSession }, error, } = await supabase.auth.getSession(); if ( error ) { console.error( "Error fetching session:", error ); setIsLoading( false ); return; } if ( initialSession ) { setSession( initialSession ); setUser( initialSession.user ); setIsAuthenticated( true ); moon.moonAPIService.setSecurityData( initialSession.access_token ); } setIsLoading( false ); // Set up auth listener after Moon is initialized }; initializeAuth(); return () => { authListener?.subscription.unsubscribe(); }; }, [ moon ] ); const signOut = useCallback( async () => { setIsLoading( true ); await supabase.auth.signOut( {} ); setSession( null ); setUser( null ); setIsAuthenticated( false ); setIsLoading( false ); }, [] ); const connect = useCallback( async ( accessToken?: string, refreshToken?: string ): Promise => { if ( moon ) { const session = await moon.connect( accessToken, refreshToken ); setSession( session ); setIsAuthenticated( true ); setUser( session.user ); } }, [ moon ], ); const disconnect = useCallback( async (): Promise => { if ( moon ) { await moon.disconnect(); setSession( null ); setIsAuthenticated( false ); setUser( null ); } }, [ moon ] ); const value = useMemo( () => ( { moon, session, user, signOut, supabaseClient: supabase, isAuthenticated, isLoading, connect, disconnect, } ), [ moon, session, user, signOut, isAuthenticated, isLoading, connect, disconnect, ], ); return ( { !isLoading && children } ); }; export const useMoonAuth = () => React.useContext( MoonAuthContext );