{"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/AuthCallbackHandler.tsx"],"sourcesContent":["export { AuthProvider, useAuth } from './AuthContext';\nexport type { AuthUser, AuthConfig } from './AuthContext';\n\nexport { AuthCallbackHandler } from './AuthCallbackHandler';\nexport type { AuthCallbackHandlerProps } from './AuthCallbackHandler';","import React, { createContext, useContext, useState, useEffect } from 'react';\nimport { jwtDecode } from 'jwt-decode';\n\nexport interface AuthUser {\n    id: string;\n    email?: string;\n    name?: string;\n    picture?: string;\n    [key: string]: any;\n}\n\nexport interface AuthState {\n    isAuthenticated: boolean;\n    user: AuthUser | null;\n    isLoading: boolean;\n    error: string | null;\n    token: string | null;\n}\n\nexport interface AuthConfig {\n    authServerUrl?: string;\n    tokenStorageKey?: string;\n    redirectPath?: string;\n    onLoginSuccess?: (user: AuthUser, token: string) => void;\n    onLogoutSuccess?: () => void;\n}\n\ninterface AuthContextType extends AuthState {\n    loginWithGoogle: (redirectPath?: string) => void;\n    loginWithGitHub: (redirectPath?: string) => void;\n    loginWithEmail: (email: string, redirectPath?: string) => Promise<void>;\n    logout: (redirectUrl?: string) => void;\n    handleCallback: () => void;\n}\n\nconst DEFAULT_CONFIG: Required<AuthConfig> = {\n    authServerUrl: 'https://auth.mgcmnd.net',\n    tokenStorageKey: 'mgcmnd_auth_token',\n    redirectPath: '/auth/callback',\n    onLoginSuccess: () => { },\n    onLogoutSuccess: () => { },\n};\n\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\n\nexport const AuthProvider: React.FC<{ children: React.ReactNode; config?: AuthConfig }> = ({\n    children,\n    config = {},\n}) => {\n    const cfg = { ...DEFAULT_CONFIG, ...config };\n\n    const [state, setState] = useState<AuthState>({\n        isAuthenticated: false,\n        user: null,\n        isLoading: false,\n        error: null,\n        token: null,\n    });\n\n    const generateState = () => {\n        const array = new Uint8Array(32);\n        window.crypto.getRandomValues(array);\n        return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n    };\n\n    const getRedirectUri = (path?: string) => {\n        const basePath = path || cfg.redirectPath;\n        return `${window.location.origin}${basePath}`;\n    };\n\n    const decodeAndSetToken = (token: string, skipCallback = false) => {\n        try {\n            // Prevent processing the same token multiple times\n            if (state.token === token && state.isAuthenticated) {\n                return;\n            }\n\n            const decoded = jwtDecode<any>(token);\n            const user: AuthUser = {\n                id: decoded.sub || decoded.id,\n                email: decoded.email,\n                name: decoded.name,\n                picture: decoded.picture,\n                ...decoded,\n            };\n\n            localStorage.setItem(cfg.tokenStorageKey, token);\n            setState({\n                isAuthenticated: true,\n                user,\n                isLoading: false,\n                error: null,\n                token,\n            });\n\n            // Only call onLoginSuccess when explicitly logging in (not on mount)\n            if (!skipCallback) {\n                cfg.onLoginSuccess(user, token);\n            }\n        } catch (error) {\n            setState(prev => ({\n                ...prev,\n                isLoading: false,\n                error: 'Invalid token format',\n            }));\n        }\n    };\n\n    // Load token on mount\n    useEffect(() => {\n        const token = localStorage.getItem(cfg.tokenStorageKey);\n        if (token) {\n            // Skip callback on initial load to prevent duplicate calls\n            decodeAndSetToken(token, true);\n        }\n    }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n    // Auth methods\n    const loginWithProvider = (provider: 'google' | 'github', redirectPath?: string) => {\n        const state = generateState();\n        sessionStorage.setItem('oauth_state', state);\n\n        const params = new URLSearchParams({\n            redirect_uri: getRedirectUri(redirectPath),\n            state,\n        });\n\n        window.location.href = `${cfg.authServerUrl}/${provider}/login?${params}`;\n    };\n\n    const loginWithGoogle = (redirectPath?: string) => loginWithProvider('google', redirectPath);\n    const loginWithGitHub = (redirectPath?: string) => loginWithProvider('github', redirectPath);\n\n    const loginWithEmail = async (email: string, redirectPath?: string) => {\n        setState(prev => ({ ...prev, isLoading: true, error: null }));\n\n        try {\n            const state = generateState();\n            sessionStorage.setItem('oauth_state', state);\n\n            const response = await fetch(`${cfg.authServerUrl}/email/login`, {\n                method: 'POST',\n                headers: { 'Content-Type': 'application/json' },\n                body: JSON.stringify({\n                    email,\n                    redirect_uri: getRedirectUri(redirectPath),\n                    state,\n                }),\n            });\n\n            if (!response.ok) {\n                throw new Error('Failed to request email login');\n            }\n\n            setState(prev => ({ ...prev, isLoading: false }));\n        } catch (error) {\n            setState(prev => ({\n                ...prev,\n                isLoading: false,\n                error: error instanceof Error ? error.message : 'Email login failed',\n            }));\n            throw error;\n        }\n    };\n\n    const logout = (redirectUrl?: string) => {\n        localStorage.removeItem(cfg.tokenStorageKey);\n        setState({\n            isAuthenticated: false,\n            user: null,\n            isLoading: false,\n            error: null,\n            token: null,\n        });\n        cfg.onLogoutSuccess();\n\n        if (redirectUrl) {\n            window.location.href = redirectUrl;\n        }\n    };\n\n    const handleCallback = () => {\n        const params = new URLSearchParams(window.location.search);\n        const token = params.get('token');\n        const stateParam = params.get('state');\n        const error = params.get('error');\n        const storedState = sessionStorage.getItem('oauth_state');\n\n        // Clean up\n        sessionStorage.removeItem('oauth_state');\n        window.history.replaceState({}, document.title, window.location.pathname);\n\n        if (error) {\n            setState(prev => ({ ...prev, error }));\n            return;\n        }\n\n        if (stateParam !== storedState) {\n            setState(prev => ({ ...prev, error: 'Invalid state parameter' }));\n            return;\n        }\n\n        if (token) {\n            decodeAndSetToken(token, false); // Explicitly call callback for new login\n        } else {\n            setState(prev => ({ ...prev, error: 'No token received' }));\n        }\n    };\n\n    const value: AuthContextType = {\n        ...state,\n        loginWithGoogle,\n        loginWithGitHub,\n        loginWithEmail,\n        logout,\n        handleCallback,\n    };\n\n    return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n};\n\nexport const useAuth = () => {\n    const context = useContext(AuthContext);\n    if (!context) {\n        throw new Error('useAuth must be used within an AuthProvider');\n    }\n    return context;\n};","import React, { useEffect } from 'react';\nimport { useAuth } from './AuthContext';\n\nexport interface AuthCallbackHandlerProps {\n    onSuccess?: () => void;\n    onError?: (error: string) => void;\n    loading?: React.ReactNode;\n}\n\nexport const AuthCallbackHandler: React.FC<AuthCallbackHandlerProps> = ({\n    onSuccess,\n    onError,\n    loading = <p>Processing authentication...</p>,\n}) => {\n    const { handleCallback, isAuthenticated, error, isLoading } = useAuth();\n\n    useEffect(() => {\n        handleCallback();\n    }, []);\n\n    useEffect(() => {\n        if (!isLoading) {\n            if (isAuthenticated && onSuccess) {\n                onSuccess();\n            } else if (error && onError) {\n                onError(error);\n            }\n        }\n    }, [isLoading, isAuthenticated, error, onSuccess, onError]);\n\n    if (isLoading) {\n        return <>{loading}</>;\n    }\n\n    return null;\n};"],"mappings":"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","names":["state","import_react","import_jsx_runtime"]}