@insforge/react 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atoms.cjs.map +1 -1
- package/dist/atoms.js.map +1 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.js.map +1 -1
- package/dist/forms.cjs.map +1 -1
- package/dist/forms.js.map +1 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +35 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +35 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/hooks.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/navigation/NavigationContext.tsx","../src/provider/InsforgeProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useUser.ts","../src/hooks/usePublicAuthConfig.ts"],"names":["createContext","useContext","InsforgeContext","useState","useEffect"],"mappings":"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","file":"hooks.cjs","sourcesContent":["import { createContext, useContext, ReactNode } from 'react';\nimport type { NavigationAdapter } from './types';\n\nconst NavigationContext = createContext<NavigationAdapter | null>(null);\n\nexport interface NavigationProviderProps {\n adapter: NavigationAdapter;\n children: ReactNode;\n}\n\n/**\n * Navigation Provider\n * Injects navigation adapter into the component tree\n */\nexport function NavigationProvider({ adapter, children }: NavigationProviderProps) {\n return <NavigationContext.Provider value={adapter}>{children}</NavigationContext.Provider>;\n}\n\n/**\n * Hook to access navigation adapter\n * @throws Error if used outside NavigationProvider\n */\nexport function useNavigationAdapter(): NavigationAdapter {\n const adapter = useContext(NavigationContext);\n\n if (!adapter) {\n return {\n useSearchParams: () => new URLSearchParams(),\n Link: ({ href, children }) => <a href={href}>{children}</a>,\n };\n }\n\n return adapter;\n}\n","import { useContext, useEffect, useState, useMemo, type ReactNode } from 'react';\nimport type { InsforgeUser, OAuthProvider } from '../types';\nimport { NavigationProvider, BrowserNavigationAdapter } from '../navigation';\nimport { InsforgeManager, type InsforgeManagerState } from '../core/InsforgeManager';\nimport { InsforgeContext, type InsforgeContextValue } from '../contexts';\n\nexport interface InsforgeProviderProps {\n children: ReactNode;\n baseUrl: string;\n /**\n * URL to redirect to after successful sign in (when token is detected in URL)\n * @default '/'\n */\n afterSignInUrl?: string;\n onAuthChange?: (user: InsforgeUser | null) => void;\n onSignIn?: (authToken: string) => Promise<void>;\n onSignOut?: () => Promise<void>;\n}\n\n/**\n * Unified Insforge Provider - manages authentication state and configuration\n *\n * Uses singleton InsforgeManager to manage state across packages.\n * Context only subscribes to Manager and triggers React re-renders.\n *\n * @example\n * ```tsx\n * // Basic usage (React/Vite)\n * import { InsforgeProvider } from '@insforge/react';\n *\n * export default function App() {\n * return (\n * <InsforgeProvider\n * baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}\n * >\n * {children}\n * </InsforgeProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With cookie sync (Next.js optimization)\n * <InsforgeProvider\n * baseUrl={baseUrl}\n * onSignIn={async (authToken) => {\n * await signIn(authToken);\n * }}\n * onSignOut={async () => {\n * await signOut();\n * }}\n * >\n * {children}\n * </InsforgeProvider>\n * ```\n */\nexport function InsforgeProviderCore({\n children,\n baseUrl,\n afterSignInUrl = '/',\n onAuthChange,\n onSignIn,\n onSignOut,\n}: InsforgeProviderProps) {\n // Get singleton Manager instance\n const manager = useMemo(\n () =>\n InsforgeManager.getInstance({\n baseUrl,\n afterSignInUrl,\n onAuthChange,\n onSignIn,\n onSignOut,\n }),\n [baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut]\n );\n\n // Subscribe to Manager state\n const [state, setState] = useState<InsforgeManagerState>(() => manager.getState());\n\n useEffect(() => {\n const unsubscribe = manager.subscribe((newState) => {\n setState(newState);\n });\n\n void manager.initialize();\n\n return unsubscribe;\n }, [manager]);\n\n // Handle OAuth callback\n useEffect(() => {\n if (typeof window !== 'undefined') {\n manager.handleOAuthCallback(state.isLoaded, state.user);\n }\n }, [manager, state.isLoaded, state.user]);\n\n // Create stable method references that delegate to manager\n const contextValue = useMemo<InsforgeContextValue>(\n () => ({\n // State from Manager\n user: state.user,\n isLoaded: state.isLoaded,\n isSignedIn: state.isSignedIn,\n\n // Methods delegated to Manager\n setUser: (user: InsforgeUser | null) => manager.setUser(user),\n signIn: (email: string, password: string) => manager.signIn(email, password),\n signUp: (email: string, password: string) => manager.signUp(email, password),\n signOut: () => manager.signOut(),\n updateUser: (data: Partial<InsforgeUser>) => manager.updateUser(data),\n reloadAuth: () => manager.reloadAuth(),\n sendVerificationEmail: (email: string) => manager.sendVerificationEmail(email),\n sendResetPasswordEmail: (email: string) => manager.sendResetPasswordEmail(email),\n resetPassword: (token: string, newPassword: string) =>\n manager.resetPassword(token, newPassword),\n verifyEmail: (otp: string, email?: string) => manager.verifyEmail(otp, email),\n exchangeResetPasswordToken: (email: string, code: string) =>\n manager.exchangeResetPasswordToken(email, code),\n loginWithOAuth: (provider: OAuthProvider, redirectTo: string) =>\n manager.loginWithOAuth(provider, redirectTo),\n getPublicAuthConfig: () => manager.getPublicAuthConfig(),\n\n // Config\n baseUrl: manager.getConfig().baseUrl,\n afterSignInUrl: manager.getConfig().afterSignInUrl || '/',\n }),\n [state, manager]\n );\n\n return <InsforgeContext.Provider value={contextValue}>{children}</InsforgeContext.Provider>;\n}\n\nexport function InsforgeProvider(props: InsforgeProviderProps) {\n return (\n <NavigationProvider adapter={BrowserNavigationAdapter}>\n <InsforgeProviderCore {...props} />\n </NavigationProvider>\n );\n}\n\n/**\n * Hook to access Insforge context\n *\n * Works seamlessly across packages thanks to singleton Manager.\n * Context instance is guaranteed to be consistent.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isSignedIn, signOut } = useInsforge();\n *\n * if (!isSignedIn) return <SignIn />;\n *\n * return (\n * <div>\n * <p>Welcome {user.email}</p>\n * <button onClick={signOut}>Sign Out</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInsforge(): InsforgeContextValue {\n const context = useContext(InsforgeContext);\n\n if (!context) {\n return {\n user: null,\n isLoaded: false,\n isSignedIn: false,\n setUser: () => {},\n signIn: () => Promise.resolve({ error: 'SSR mode' }),\n signUp: () => Promise.resolve({ error: 'SSR mode' }),\n signOut: () => Promise.resolve(),\n updateUser: () => Promise.resolve({ error: 'SSR mode' }),\n reloadAuth: () => Promise.resolve({ success: false, error: 'SSR mode' }),\n sendVerificationEmail: () => Promise.resolve(null),\n sendResetPasswordEmail: () => Promise.resolve(null),\n resetPassword: () => Promise.resolve(null),\n verifyEmail: () => Promise.resolve(null),\n exchangeResetPasswordToken: () => Promise.resolve({ error: { message: 'SSR mode' } }),\n loginWithOAuth: () => Promise.resolve(),\n getPublicAuthConfig: () => Promise.resolve(null),\n baseUrl: '',\n afterSignInUrl: '/',\n };\n }\n\n return context;\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access authentication methods\n *\n * @returns Object containing:\n * - `signIn`: Function to sign in with email and password\n * - `signUp`: Function to sign up with email and password\n * - `signOut`: Function to sign out the current user\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `isSignedIn`: Boolean indicating if user is currently signed in\n *\n * @example\n * ```tsx\n * function LoginForm() {\n * const { signIn, signUp, signOut, isLoaded, isSignedIn } = useAuth();\n *\n * async function handleLogin(email: string, password: string) {\n * try {\n * await signIn(email, password);\n * // User is now signed in\n * } catch (error) {\n * console.error('Sign in failed:', error);\n * }\n * }\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <form onSubmit={(e) => { e.preventDefault(); handleLogin(email, password); }}>\n * {/* form fields *\\/}\n * </form>\n * );\n * }\n * ```\n */\nexport function useAuth() {\n const { signIn, signUp, signOut, isLoaded, isSignedIn } = useInsforge();\n return { signIn, signUp, signOut, isLoaded, isSignedIn };\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access current user data\n *\n * @returns Object containing:\n * - `user`: Current user object (InsforgeUser | null)\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `updateUser`: Function to update user profile data (returns { error: string } | null)\n * - `setUser`: Internal function to manually set user state\n *\n * @example\n * ```tsx\n * function UserProfile() {\n * const { user, isLoaded, updateUser } = useUser();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n * if (!user) return <div>Not signed in</div>;\n *\n * async function handleUpdate(name: string) {\n * const result = await updateUser({ name });\n * if (result?.error) {\n * console.error(result.error);\n * } else {\n * console.log('User updated successfully');\n * }\n * }\n *\n * return (\n * <div>\n * <p>Email: {user.email}</p>\n * {user.name && <p>Name: {user.name}</p>}\n * {user.avatarUrl && <img src={user.avatarUrl} alt=\"Avatar\" />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useUser() {\n const { user, isLoaded, updateUser, setUser } = useInsforge();\n return { user, isLoaded, updateUser, setUser };\n}\n","import { useState, useEffect } from 'react';\nimport type { GetPublicAuthConfigResponse } from '@insforge/shared-schemas';\nimport { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to get all public authentication configuration (OAuth + Email) from Insforge backend\n *\n * **IMPORTANT: This hook should ONLY be used in SignIn and SignUp components.**\n *\n * This hook lazily fetches all public authentication configuration from the backend\n * only when the component mounts. Using it in other components will cause unnecessary\n * API calls on every page load.\n *\n * @returns Object containing OAuth providers, email auth config, and loading state\n * - `authConfig`: Email authentication configuration object with password rules\n * - `isLoaded`: Boolean indicating if the config has been fetched\n *\n * @example\n * ```tsx\n * // ✅ Correct usage - only in SignIn/SignUp components\n * function SignUp() {\n * const { authConfig, isLoaded } = usePublicAuthConfig();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * <p>OAuth providers: {authConfig?.oauthProviders.length}</p>\n * <p>Password min length: {authConfig?.passwordMinLength}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @requires Must be used within InsforgeProvider\n */\nexport function usePublicAuthConfig(): {\n authConfig: GetPublicAuthConfigResponse | null;\n isLoaded: boolean;\n} {\n const { getPublicAuthConfig } = useInsforge();\n const [authConfig, setAuthConfig] = useState<GetPublicAuthConfigResponse | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n async function fetchConfig() {\n const result = await getPublicAuthConfig();\n if (result) {\n setAuthConfig(result);\n } else {\n console.error('[usePublicAuthConfig] Failed to get public auth config');\n setAuthConfig(null);\n }\n setIsLoaded(true);\n }\n\n void fetchConfig();\n }, [getPublicAuthConfig]);\n\n return { authConfig, isLoaded };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/navigation/NavigationContext.tsx","../src/provider/InsforgeProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useUser.ts","../src/hooks/usePublicAuthConfig.ts"],"names":["createContext","useContext","InsforgeContext","useState","useEffect"],"mappings":"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","file":"hooks.cjs","sourcesContent":["import { createContext, useContext, ReactNode } from 'react';\nimport type { NavigationAdapter } from './types';\n\nconst NavigationContext = createContext<NavigationAdapter | null>(null);\n\nexport interface NavigationProviderProps {\n adapter: NavigationAdapter;\n children: ReactNode;\n}\n\n/**\n * Navigation Provider\n * Injects navigation adapter into the component tree\n */\nexport function NavigationProvider({ adapter, children }: NavigationProviderProps) {\n return <NavigationContext.Provider value={adapter}>{children}</NavigationContext.Provider>;\n}\n\n/**\n * Hook to access navigation adapter\n * @throws Error if used outside NavigationProvider\n */\nexport function useNavigationAdapter(): NavigationAdapter {\n const adapter = useContext(NavigationContext);\n\n if (!adapter) {\n return {\n useSearchParams: () => new URLSearchParams(),\n Link: ({ href, children }) => <a href={href}>{children}</a>,\n };\n }\n\n return adapter;\n}\n","import { useContext, useEffect, useState, useMemo, type ReactNode } from 'react';\nimport type { InsforgeUser, OAuthProvider } from '../types';\nimport { NavigationProvider, BrowserNavigationAdapter } from '../navigation';\nimport { InsforgeManager, type InsforgeManagerState } from '../core/InsforgeManager';\nimport { InsforgeContext, type InsforgeContextValue } from '../contexts';\n\nexport interface InsforgeProviderProps {\n children: ReactNode;\n baseUrl: string;\n /**\n * URL to redirect to after successful sign in (when token is detected in URL)\n * @default '/'\n */\n afterSignInUrl?: string;\n onAuthChange?: (user: InsforgeUser | null) => void;\n onSignIn?: (authToken: string) => Promise<void>;\n onSignOut?: () => Promise<void>;\n}\n\n/**\n * Unified Insforge Provider - manages authentication state and configuration\n *\n * Uses singleton InsforgeManager to manage state across packages.\n * Context only subscribes to Manager and triggers React re-renders.\n *\n * @example\n * ```tsx\n * // Basic usage (React/Vite)\n * import { InsforgeProvider } from '@insforge/react';\n *\n * export default function App() {\n * return (\n * <InsforgeProvider\n * baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}\n * >\n * {children}\n * </InsforgeProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With cookie sync (Next.js optimization)\n * <InsforgeProvider\n * baseUrl={baseUrl}\n * onSignIn={async (authToken) => {\n * await signIn(authToken);\n * }}\n * onSignOut={async () => {\n * await signOut();\n * }}\n * >\n * {children}\n * </InsforgeProvider>\n * ```\n */\nexport function InsforgeProviderCore({\n children,\n baseUrl,\n afterSignInUrl = '/',\n onAuthChange,\n onSignIn,\n onSignOut,\n}: InsforgeProviderProps) {\n // Get singleton Manager instance\n const manager = useMemo(\n () =>\n InsforgeManager.getInstance({\n baseUrl,\n afterSignInUrl,\n onAuthChange,\n onSignIn,\n onSignOut,\n }),\n [baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut]\n );\n\n // Subscribe to Manager state\n const [state, setState] = useState<InsforgeManagerState>(() => manager.getState());\n\n useEffect(() => {\n const unsubscribe = manager.subscribe((newState) => {\n setState(newState);\n });\n\n // Initialize auth state (only runs once due to isLoaded check in Manager)\n void manager.initialize();\n\n return () => {\n unsubscribe();\n };\n }, [manager]);\n\n // Handle auth redirect after successful authentication\n useEffect(() => {\n if (typeof window !== 'undefined') {\n manager.handleAuthRedirect(state.isLoaded, state.user);\n }\n }, [manager, state.isLoaded, state.user]);\n\n // Create stable method references that delegate to manager\n const contextValue = useMemo<InsforgeContextValue>(\n () => ({\n // State from Manager\n user: state.user,\n isLoaded: state.isLoaded,\n isSignedIn: state.isSignedIn,\n\n // Methods delegated to Manager\n setUser: (user: InsforgeUser | null) => manager.setUser(user),\n signIn: (email: string, password: string) => manager.signIn(email, password),\n signUp: (email: string, password: string) => manager.signUp(email, password),\n signOut: () => manager.signOut(),\n updateUser: (data: Partial<InsforgeUser>) => manager.updateUser(data),\n reloadAuth: () => manager.reloadAuth(),\n sendVerificationEmail: (email: string) => manager.sendVerificationEmail(email),\n sendResetPasswordEmail: (email: string) => manager.sendResetPasswordEmail(email),\n resetPassword: (token: string, newPassword: string) =>\n manager.resetPassword(token, newPassword),\n verifyEmail: (otp: string, email?: string) => manager.verifyEmail(otp, email),\n exchangeResetPasswordToken: (email: string, code: string) =>\n manager.exchangeResetPasswordToken(email, code),\n loginWithOAuth: (provider: OAuthProvider, redirectTo: string) =>\n manager.loginWithOAuth(provider, redirectTo),\n getPublicAuthConfig: () => manager.getPublicAuthConfig(),\n\n // Config\n baseUrl: manager.getConfig().baseUrl,\n afterSignInUrl: manager.getConfig().afterSignInUrl || '/',\n }),\n [state, manager]\n );\n\n return <InsforgeContext.Provider value={contextValue}>{children}</InsforgeContext.Provider>;\n}\n\nexport function InsforgeProvider(props: InsforgeProviderProps) {\n return (\n <NavigationProvider adapter={BrowserNavigationAdapter}>\n <InsforgeProviderCore {...props} />\n </NavigationProvider>\n );\n}\n\n/**\n * Hook to access Insforge context\n *\n * Works seamlessly across packages thanks to singleton Manager.\n * Context instance is guaranteed to be consistent.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isSignedIn, signOut } = useInsforge();\n *\n * if (!isSignedIn) return <SignIn />;\n *\n * return (\n * <div>\n * <p>Welcome {user.email}</p>\n * <button onClick={signOut}>Sign Out</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInsforge(): InsforgeContextValue {\n const context = useContext(InsforgeContext);\n\n if (!context) {\n return {\n user: null,\n isLoaded: false,\n isSignedIn: false,\n setUser: () => {},\n signIn: () => Promise.resolve({ error: 'SSR mode' }),\n signUp: () => Promise.resolve({ error: 'SSR mode' }),\n signOut: () => Promise.resolve(),\n updateUser: () => Promise.resolve({ error: 'SSR mode' }),\n reloadAuth: () => Promise.resolve({ success: false, error: 'SSR mode' }),\n sendVerificationEmail: () => Promise.resolve(null),\n sendResetPasswordEmail: () => Promise.resolve(null),\n resetPassword: () => Promise.resolve(null),\n verifyEmail: () => Promise.resolve(null),\n exchangeResetPasswordToken: () => Promise.resolve({ error: { message: 'SSR mode' } }),\n loginWithOAuth: () => Promise.resolve(),\n getPublicAuthConfig: () => Promise.resolve(null),\n baseUrl: '',\n afterSignInUrl: '/',\n };\n }\n\n return context;\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access authentication methods\n *\n * @returns Object containing:\n * - `signIn`: Function to sign in with email and password\n * - `signUp`: Function to sign up with email and password\n * - `signOut`: Function to sign out the current user\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `isSignedIn`: Boolean indicating if user is currently signed in\n *\n * @example\n * ```tsx\n * function LoginForm() {\n * const { signIn, signUp, signOut, isLoaded, isSignedIn } = useAuth();\n *\n * async function handleLogin(email: string, password: string) {\n * try {\n * await signIn(email, password);\n * // User is now signed in\n * } catch (error) {\n * console.error('Sign in failed:', error);\n * }\n * }\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <form onSubmit={(e) => { e.preventDefault(); handleLogin(email, password); }}>\n * {/* form fields *\\/}\n * </form>\n * );\n * }\n * ```\n */\nexport function useAuth() {\n const { signIn, signUp, signOut, isLoaded, isSignedIn } = useInsforge();\n return { signIn, signUp, signOut, isLoaded, isSignedIn };\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access current user data\n *\n * @returns Object containing:\n * - `user`: Current user object (InsforgeUser | null)\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `updateUser`: Function to update user profile data (returns { error: string } | null)\n * - `setUser`: Internal function to manually set user state\n *\n * @example\n * ```tsx\n * function UserProfile() {\n * const { user, isLoaded, updateUser } = useUser();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n * if (!user) return <div>Not signed in</div>;\n *\n * async function handleUpdate(name: string) {\n * const result = await updateUser({ name });\n * if (result?.error) {\n * console.error(result.error);\n * } else {\n * console.log('User updated successfully');\n * }\n * }\n *\n * return (\n * <div>\n * <p>Email: {user.email}</p>\n * {user.name && <p>Name: {user.name}</p>}\n * {user.avatarUrl && <img src={user.avatarUrl} alt=\"Avatar\" />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useUser() {\n const { user, isLoaded, updateUser, setUser } = useInsforge();\n return { user, isLoaded, updateUser, setUser };\n}\n","import { useState, useEffect } from 'react';\nimport type { GetPublicAuthConfigResponse } from '@insforge/shared-schemas';\nimport { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to get all public authentication configuration (OAuth + Email) from Insforge backend\n *\n * **IMPORTANT: This hook should ONLY be used in SignIn and SignUp components.**\n *\n * This hook lazily fetches all public authentication configuration from the backend\n * only when the component mounts. Using it in other components will cause unnecessary\n * API calls on every page load.\n *\n * @returns Object containing OAuth providers, email auth config, and loading state\n * - `authConfig`: Email authentication configuration object with password rules\n * - `isLoaded`: Boolean indicating if the config has been fetched\n *\n * @example\n * ```tsx\n * // ✅ Correct usage - only in SignIn/SignUp components\n * function SignUp() {\n * const { authConfig, isLoaded } = usePublicAuthConfig();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * <p>OAuth providers: {authConfig?.oauthProviders.length}</p>\n * <p>Password min length: {authConfig?.passwordMinLength}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @requires Must be used within InsforgeProvider\n */\nexport function usePublicAuthConfig(): {\n authConfig: GetPublicAuthConfigResponse | null;\n isLoaded: boolean;\n} {\n const { getPublicAuthConfig } = useInsforge();\n const [authConfig, setAuthConfig] = useState<GetPublicAuthConfigResponse | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n async function fetchConfig() {\n const result = await getPublicAuthConfig();\n if (result) {\n setAuthConfig(result);\n } else {\n console.error('[usePublicAuthConfig] Failed to get public auth config');\n setAuthConfig(null);\n }\n setIsLoaded(true);\n }\n\n void fetchConfig();\n }, [getPublicAuthConfig]);\n\n return { authConfig, isLoaded };\n}\n"]}
|
package/dist/hooks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/navigation/NavigationContext.tsx","../src/provider/InsforgeProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useUser.ts","../src/hooks/usePublicAuthConfig.ts"],"names":["useContext","useState","useEffect"],"mappings":"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","file":"hooks.js","sourcesContent":["import { createContext, useContext, ReactNode } from 'react';\nimport type { NavigationAdapter } from './types';\n\nconst NavigationContext = createContext<NavigationAdapter | null>(null);\n\nexport interface NavigationProviderProps {\n adapter: NavigationAdapter;\n children: ReactNode;\n}\n\n/**\n * Navigation Provider\n * Injects navigation adapter into the component tree\n */\nexport function NavigationProvider({ adapter, children }: NavigationProviderProps) {\n return <NavigationContext.Provider value={adapter}>{children}</NavigationContext.Provider>;\n}\n\n/**\n * Hook to access navigation adapter\n * @throws Error if used outside NavigationProvider\n */\nexport function useNavigationAdapter(): NavigationAdapter {\n const adapter = useContext(NavigationContext);\n\n if (!adapter) {\n return {\n useSearchParams: () => new URLSearchParams(),\n Link: ({ href, children }) => <a href={href}>{children}</a>,\n };\n }\n\n return adapter;\n}\n","import { useContext, useEffect, useState, useMemo, type ReactNode } from 'react';\nimport type { InsforgeUser, OAuthProvider } from '../types';\nimport { NavigationProvider, BrowserNavigationAdapter } from '../navigation';\nimport { InsforgeManager, type InsforgeManagerState } from '../core/InsforgeManager';\nimport { InsforgeContext, type InsforgeContextValue } from '../contexts';\n\nexport interface InsforgeProviderProps {\n children: ReactNode;\n baseUrl: string;\n /**\n * URL to redirect to after successful sign in (when token is detected in URL)\n * @default '/'\n */\n afterSignInUrl?: string;\n onAuthChange?: (user: InsforgeUser | null) => void;\n onSignIn?: (authToken: string) => Promise<void>;\n onSignOut?: () => Promise<void>;\n}\n\n/**\n * Unified Insforge Provider - manages authentication state and configuration\n *\n * Uses singleton InsforgeManager to manage state across packages.\n * Context only subscribes to Manager and triggers React re-renders.\n *\n * @example\n * ```tsx\n * // Basic usage (React/Vite)\n * import { InsforgeProvider } from '@insforge/react';\n *\n * export default function App() {\n * return (\n * <InsforgeProvider\n * baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}\n * >\n * {children}\n * </InsforgeProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With cookie sync (Next.js optimization)\n * <InsforgeProvider\n * baseUrl={baseUrl}\n * onSignIn={async (authToken) => {\n * await signIn(authToken);\n * }}\n * onSignOut={async () => {\n * await signOut();\n * }}\n * >\n * {children}\n * </InsforgeProvider>\n * ```\n */\nexport function InsforgeProviderCore({\n children,\n baseUrl,\n afterSignInUrl = '/',\n onAuthChange,\n onSignIn,\n onSignOut,\n}: InsforgeProviderProps) {\n // Get singleton Manager instance\n const manager = useMemo(\n () =>\n InsforgeManager.getInstance({\n baseUrl,\n afterSignInUrl,\n onAuthChange,\n onSignIn,\n onSignOut,\n }),\n [baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut]\n );\n\n // Subscribe to Manager state\n const [state, setState] = useState<InsforgeManagerState>(() => manager.getState());\n\n useEffect(() => {\n const unsubscribe = manager.subscribe((newState) => {\n setState(newState);\n });\n\n void manager.initialize();\n\n return unsubscribe;\n }, [manager]);\n\n // Handle OAuth callback\n useEffect(() => {\n if (typeof window !== 'undefined') {\n manager.handleOAuthCallback(state.isLoaded, state.user);\n }\n }, [manager, state.isLoaded, state.user]);\n\n // Create stable method references that delegate to manager\n const contextValue = useMemo<InsforgeContextValue>(\n () => ({\n // State from Manager\n user: state.user,\n isLoaded: state.isLoaded,\n isSignedIn: state.isSignedIn,\n\n // Methods delegated to Manager\n setUser: (user: InsforgeUser | null) => manager.setUser(user),\n signIn: (email: string, password: string) => manager.signIn(email, password),\n signUp: (email: string, password: string) => manager.signUp(email, password),\n signOut: () => manager.signOut(),\n updateUser: (data: Partial<InsforgeUser>) => manager.updateUser(data),\n reloadAuth: () => manager.reloadAuth(),\n sendVerificationEmail: (email: string) => manager.sendVerificationEmail(email),\n sendResetPasswordEmail: (email: string) => manager.sendResetPasswordEmail(email),\n resetPassword: (token: string, newPassword: string) =>\n manager.resetPassword(token, newPassword),\n verifyEmail: (otp: string, email?: string) => manager.verifyEmail(otp, email),\n exchangeResetPasswordToken: (email: string, code: string) =>\n manager.exchangeResetPasswordToken(email, code),\n loginWithOAuth: (provider: OAuthProvider, redirectTo: string) =>\n manager.loginWithOAuth(provider, redirectTo),\n getPublicAuthConfig: () => manager.getPublicAuthConfig(),\n\n // Config\n baseUrl: manager.getConfig().baseUrl,\n afterSignInUrl: manager.getConfig().afterSignInUrl || '/',\n }),\n [state, manager]\n );\n\n return <InsforgeContext.Provider value={contextValue}>{children}</InsforgeContext.Provider>;\n}\n\nexport function InsforgeProvider(props: InsforgeProviderProps) {\n return (\n <NavigationProvider adapter={BrowserNavigationAdapter}>\n <InsforgeProviderCore {...props} />\n </NavigationProvider>\n );\n}\n\n/**\n * Hook to access Insforge context\n *\n * Works seamlessly across packages thanks to singleton Manager.\n * Context instance is guaranteed to be consistent.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isSignedIn, signOut } = useInsforge();\n *\n * if (!isSignedIn) return <SignIn />;\n *\n * return (\n * <div>\n * <p>Welcome {user.email}</p>\n * <button onClick={signOut}>Sign Out</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInsforge(): InsforgeContextValue {\n const context = useContext(InsforgeContext);\n\n if (!context) {\n return {\n user: null,\n isLoaded: false,\n isSignedIn: false,\n setUser: () => {},\n signIn: () => Promise.resolve({ error: 'SSR mode' }),\n signUp: () => Promise.resolve({ error: 'SSR mode' }),\n signOut: () => Promise.resolve(),\n updateUser: () => Promise.resolve({ error: 'SSR mode' }),\n reloadAuth: () => Promise.resolve({ success: false, error: 'SSR mode' }),\n sendVerificationEmail: () => Promise.resolve(null),\n sendResetPasswordEmail: () => Promise.resolve(null),\n resetPassword: () => Promise.resolve(null),\n verifyEmail: () => Promise.resolve(null),\n exchangeResetPasswordToken: () => Promise.resolve({ error: { message: 'SSR mode' } }),\n loginWithOAuth: () => Promise.resolve(),\n getPublicAuthConfig: () => Promise.resolve(null),\n baseUrl: '',\n afterSignInUrl: '/',\n };\n }\n\n return context;\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access authentication methods\n *\n * @returns Object containing:\n * - `signIn`: Function to sign in with email and password\n * - `signUp`: Function to sign up with email and password\n * - `signOut`: Function to sign out the current user\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `isSignedIn`: Boolean indicating if user is currently signed in\n *\n * @example\n * ```tsx\n * function LoginForm() {\n * const { signIn, signUp, signOut, isLoaded, isSignedIn } = useAuth();\n *\n * async function handleLogin(email: string, password: string) {\n * try {\n * await signIn(email, password);\n * // User is now signed in\n * } catch (error) {\n * console.error('Sign in failed:', error);\n * }\n * }\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <form onSubmit={(e) => { e.preventDefault(); handleLogin(email, password); }}>\n * {/* form fields *\\/}\n * </form>\n * );\n * }\n * ```\n */\nexport function useAuth() {\n const { signIn, signUp, signOut, isLoaded, isSignedIn } = useInsforge();\n return { signIn, signUp, signOut, isLoaded, isSignedIn };\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access current user data\n *\n * @returns Object containing:\n * - `user`: Current user object (InsforgeUser | null)\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `updateUser`: Function to update user profile data (returns { error: string } | null)\n * - `setUser`: Internal function to manually set user state\n *\n * @example\n * ```tsx\n * function UserProfile() {\n * const { user, isLoaded, updateUser } = useUser();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n * if (!user) return <div>Not signed in</div>;\n *\n * async function handleUpdate(name: string) {\n * const result = await updateUser({ name });\n * if (result?.error) {\n * console.error(result.error);\n * } else {\n * console.log('User updated successfully');\n * }\n * }\n *\n * return (\n * <div>\n * <p>Email: {user.email}</p>\n * {user.name && <p>Name: {user.name}</p>}\n * {user.avatarUrl && <img src={user.avatarUrl} alt=\"Avatar\" />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useUser() {\n const { user, isLoaded, updateUser, setUser } = useInsforge();\n return { user, isLoaded, updateUser, setUser };\n}\n","import { useState, useEffect } from 'react';\nimport type { GetPublicAuthConfigResponse } from '@insforge/shared-schemas';\nimport { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to get all public authentication configuration (OAuth + Email) from Insforge backend\n *\n * **IMPORTANT: This hook should ONLY be used in SignIn and SignUp components.**\n *\n * This hook lazily fetches all public authentication configuration from the backend\n * only when the component mounts. Using it in other components will cause unnecessary\n * API calls on every page load.\n *\n * @returns Object containing OAuth providers, email auth config, and loading state\n * - `authConfig`: Email authentication configuration object with password rules\n * - `isLoaded`: Boolean indicating if the config has been fetched\n *\n * @example\n * ```tsx\n * // ✅ Correct usage - only in SignIn/SignUp components\n * function SignUp() {\n * const { authConfig, isLoaded } = usePublicAuthConfig();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * <p>OAuth providers: {authConfig?.oauthProviders.length}</p>\n * <p>Password min length: {authConfig?.passwordMinLength}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @requires Must be used within InsforgeProvider\n */\nexport function usePublicAuthConfig(): {\n authConfig: GetPublicAuthConfigResponse | null;\n isLoaded: boolean;\n} {\n const { getPublicAuthConfig } = useInsforge();\n const [authConfig, setAuthConfig] = useState<GetPublicAuthConfigResponse | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n async function fetchConfig() {\n const result = await getPublicAuthConfig();\n if (result) {\n setAuthConfig(result);\n } else {\n console.error('[usePublicAuthConfig] Failed to get public auth config');\n setAuthConfig(null);\n }\n setIsLoaded(true);\n }\n\n void fetchConfig();\n }, [getPublicAuthConfig]);\n\n return { authConfig, isLoaded };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/navigation/NavigationContext.tsx","../src/provider/InsforgeProvider.tsx","../src/hooks/useAuth.ts","../src/hooks/useUser.ts","../src/hooks/usePublicAuthConfig.ts"],"names":["useContext","useState","useEffect"],"mappings":"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","file":"hooks.js","sourcesContent":["import { createContext, useContext, ReactNode } from 'react';\nimport type { NavigationAdapter } from './types';\n\nconst NavigationContext = createContext<NavigationAdapter | null>(null);\n\nexport interface NavigationProviderProps {\n adapter: NavigationAdapter;\n children: ReactNode;\n}\n\n/**\n * Navigation Provider\n * Injects navigation adapter into the component tree\n */\nexport function NavigationProvider({ adapter, children }: NavigationProviderProps) {\n return <NavigationContext.Provider value={adapter}>{children}</NavigationContext.Provider>;\n}\n\n/**\n * Hook to access navigation adapter\n * @throws Error if used outside NavigationProvider\n */\nexport function useNavigationAdapter(): NavigationAdapter {\n const adapter = useContext(NavigationContext);\n\n if (!adapter) {\n return {\n useSearchParams: () => new URLSearchParams(),\n Link: ({ href, children }) => <a href={href}>{children}</a>,\n };\n }\n\n return adapter;\n}\n","import { useContext, useEffect, useState, useMemo, type ReactNode } from 'react';\nimport type { InsforgeUser, OAuthProvider } from '../types';\nimport { NavigationProvider, BrowserNavigationAdapter } from '../navigation';\nimport { InsforgeManager, type InsforgeManagerState } from '../core/InsforgeManager';\nimport { InsforgeContext, type InsforgeContextValue } from '../contexts';\n\nexport interface InsforgeProviderProps {\n children: ReactNode;\n baseUrl: string;\n /**\n * URL to redirect to after successful sign in (when token is detected in URL)\n * @default '/'\n */\n afterSignInUrl?: string;\n onAuthChange?: (user: InsforgeUser | null) => void;\n onSignIn?: (authToken: string) => Promise<void>;\n onSignOut?: () => Promise<void>;\n}\n\n/**\n * Unified Insforge Provider - manages authentication state and configuration\n *\n * Uses singleton InsforgeManager to manage state across packages.\n * Context only subscribes to Manager and triggers React re-renders.\n *\n * @example\n * ```tsx\n * // Basic usage (React/Vite)\n * import { InsforgeProvider } from '@insforge/react';\n *\n * export default function App() {\n * return (\n * <InsforgeProvider\n * baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}\n * >\n * {children}\n * </InsforgeProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With cookie sync (Next.js optimization)\n * <InsforgeProvider\n * baseUrl={baseUrl}\n * onSignIn={async (authToken) => {\n * await signIn(authToken);\n * }}\n * onSignOut={async () => {\n * await signOut();\n * }}\n * >\n * {children}\n * </InsforgeProvider>\n * ```\n */\nexport function InsforgeProviderCore({\n children,\n baseUrl,\n afterSignInUrl = '/',\n onAuthChange,\n onSignIn,\n onSignOut,\n}: InsforgeProviderProps) {\n // Get singleton Manager instance\n const manager = useMemo(\n () =>\n InsforgeManager.getInstance({\n baseUrl,\n afterSignInUrl,\n onAuthChange,\n onSignIn,\n onSignOut,\n }),\n [baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut]\n );\n\n // Subscribe to Manager state\n const [state, setState] = useState<InsforgeManagerState>(() => manager.getState());\n\n useEffect(() => {\n const unsubscribe = manager.subscribe((newState) => {\n setState(newState);\n });\n\n // Initialize auth state (only runs once due to isLoaded check in Manager)\n void manager.initialize();\n\n return () => {\n unsubscribe();\n };\n }, [manager]);\n\n // Handle auth redirect after successful authentication\n useEffect(() => {\n if (typeof window !== 'undefined') {\n manager.handleAuthRedirect(state.isLoaded, state.user);\n }\n }, [manager, state.isLoaded, state.user]);\n\n // Create stable method references that delegate to manager\n const contextValue = useMemo<InsforgeContextValue>(\n () => ({\n // State from Manager\n user: state.user,\n isLoaded: state.isLoaded,\n isSignedIn: state.isSignedIn,\n\n // Methods delegated to Manager\n setUser: (user: InsforgeUser | null) => manager.setUser(user),\n signIn: (email: string, password: string) => manager.signIn(email, password),\n signUp: (email: string, password: string) => manager.signUp(email, password),\n signOut: () => manager.signOut(),\n updateUser: (data: Partial<InsforgeUser>) => manager.updateUser(data),\n reloadAuth: () => manager.reloadAuth(),\n sendVerificationEmail: (email: string) => manager.sendVerificationEmail(email),\n sendResetPasswordEmail: (email: string) => manager.sendResetPasswordEmail(email),\n resetPassword: (token: string, newPassword: string) =>\n manager.resetPassword(token, newPassword),\n verifyEmail: (otp: string, email?: string) => manager.verifyEmail(otp, email),\n exchangeResetPasswordToken: (email: string, code: string) =>\n manager.exchangeResetPasswordToken(email, code),\n loginWithOAuth: (provider: OAuthProvider, redirectTo: string) =>\n manager.loginWithOAuth(provider, redirectTo),\n getPublicAuthConfig: () => manager.getPublicAuthConfig(),\n\n // Config\n baseUrl: manager.getConfig().baseUrl,\n afterSignInUrl: manager.getConfig().afterSignInUrl || '/',\n }),\n [state, manager]\n );\n\n return <InsforgeContext.Provider value={contextValue}>{children}</InsforgeContext.Provider>;\n}\n\nexport function InsforgeProvider(props: InsforgeProviderProps) {\n return (\n <NavigationProvider adapter={BrowserNavigationAdapter}>\n <InsforgeProviderCore {...props} />\n </NavigationProvider>\n );\n}\n\n/**\n * Hook to access Insforge context\n *\n * Works seamlessly across packages thanks to singleton Manager.\n * Context instance is guaranteed to be consistent.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { user, isSignedIn, signOut } = useInsforge();\n *\n * if (!isSignedIn) return <SignIn />;\n *\n * return (\n * <div>\n * <p>Welcome {user.email}</p>\n * <button onClick={signOut}>Sign Out</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInsforge(): InsforgeContextValue {\n const context = useContext(InsforgeContext);\n\n if (!context) {\n return {\n user: null,\n isLoaded: false,\n isSignedIn: false,\n setUser: () => {},\n signIn: () => Promise.resolve({ error: 'SSR mode' }),\n signUp: () => Promise.resolve({ error: 'SSR mode' }),\n signOut: () => Promise.resolve(),\n updateUser: () => Promise.resolve({ error: 'SSR mode' }),\n reloadAuth: () => Promise.resolve({ success: false, error: 'SSR mode' }),\n sendVerificationEmail: () => Promise.resolve(null),\n sendResetPasswordEmail: () => Promise.resolve(null),\n resetPassword: () => Promise.resolve(null),\n verifyEmail: () => Promise.resolve(null),\n exchangeResetPasswordToken: () => Promise.resolve({ error: { message: 'SSR mode' } }),\n loginWithOAuth: () => Promise.resolve(),\n getPublicAuthConfig: () => Promise.resolve(null),\n baseUrl: '',\n afterSignInUrl: '/',\n };\n }\n\n return context;\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access authentication methods\n *\n * @returns Object containing:\n * - `signIn`: Function to sign in with email and password\n * - `signUp`: Function to sign up with email and password\n * - `signOut`: Function to sign out the current user\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `isSignedIn`: Boolean indicating if user is currently signed in\n *\n * @example\n * ```tsx\n * function LoginForm() {\n * const { signIn, signUp, signOut, isLoaded, isSignedIn } = useAuth();\n *\n * async function handleLogin(email: string, password: string) {\n * try {\n * await signIn(email, password);\n * // User is now signed in\n * } catch (error) {\n * console.error('Sign in failed:', error);\n * }\n * }\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <form onSubmit={(e) => { e.preventDefault(); handleLogin(email, password); }}>\n * {/* form fields *\\/}\n * </form>\n * );\n * }\n * ```\n */\nexport function useAuth() {\n const { signIn, signUp, signOut, isLoaded, isSignedIn } = useInsforge();\n return { signIn, signUp, signOut, isLoaded, isSignedIn };\n}\n","import { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to access current user data\n *\n * @returns Object containing:\n * - `user`: Current user object (InsforgeUser | null)\n * - `isLoaded`: Boolean indicating if auth state has been loaded\n * - `updateUser`: Function to update user profile data (returns { error: string } | null)\n * - `setUser`: Internal function to manually set user state\n *\n * @example\n * ```tsx\n * function UserProfile() {\n * const { user, isLoaded, updateUser } = useUser();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n * if (!user) return <div>Not signed in</div>;\n *\n * async function handleUpdate(name: string) {\n * const result = await updateUser({ name });\n * if (result?.error) {\n * console.error(result.error);\n * } else {\n * console.log('User updated successfully');\n * }\n * }\n *\n * return (\n * <div>\n * <p>Email: {user.email}</p>\n * {user.name && <p>Name: {user.name}</p>}\n * {user.avatarUrl && <img src={user.avatarUrl} alt=\"Avatar\" />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useUser() {\n const { user, isLoaded, updateUser, setUser } = useInsforge();\n return { user, isLoaded, updateUser, setUser };\n}\n","import { useState, useEffect } from 'react';\nimport type { GetPublicAuthConfigResponse } from '@insforge/shared-schemas';\nimport { useInsforge } from '../provider/InsforgeProvider';\n\n/**\n * Hook to get all public authentication configuration (OAuth + Email) from Insforge backend\n *\n * **IMPORTANT: This hook should ONLY be used in SignIn and SignUp components.**\n *\n * This hook lazily fetches all public authentication configuration from the backend\n * only when the component mounts. Using it in other components will cause unnecessary\n * API calls on every page load.\n *\n * @returns Object containing OAuth providers, email auth config, and loading state\n * - `authConfig`: Email authentication configuration object with password rules\n * - `isLoaded`: Boolean indicating if the config has been fetched\n *\n * @example\n * ```tsx\n * // ✅ Correct usage - only in SignIn/SignUp components\n * function SignUp() {\n * const { authConfig, isLoaded } = usePublicAuthConfig();\n *\n * if (!isLoaded) return <div>Loading...</div>;\n *\n * return (\n * <div>\n * <p>OAuth providers: {authConfig?.oauthProviders.length}</p>\n * <p>Password min length: {authConfig?.passwordMinLength}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @requires Must be used within InsforgeProvider\n */\nexport function usePublicAuthConfig(): {\n authConfig: GetPublicAuthConfigResponse | null;\n isLoaded: boolean;\n} {\n const { getPublicAuthConfig } = useInsforge();\n const [authConfig, setAuthConfig] = useState<GetPublicAuthConfigResponse | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n async function fetchConfig() {\n const result = await getPublicAuthConfig();\n if (result) {\n setAuthConfig(result);\n } else {\n console.error('[usePublicAuthConfig] Failed to get public auth config');\n setAuthConfig(null);\n }\n setIsLoaded(true);\n }\n\n void fetchConfig();\n }, [getPublicAuthConfig]);\n\n return { authConfig, isLoaded };\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -71,6 +71,7 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
71
71
|
// State storage
|
|
72
72
|
user = null;
|
|
73
73
|
isLoaded = false;
|
|
74
|
+
isInitializing = false;
|
|
74
75
|
sdk;
|
|
75
76
|
listeners = /* @__PURE__ */ new Set();
|
|
76
77
|
// Config
|
|
@@ -81,6 +82,11 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
81
82
|
constructor(config) {
|
|
82
83
|
this.config = config;
|
|
83
84
|
this.sdk = sdk.createClient({ baseUrl: config.baseUrl });
|
|
85
|
+
const session = this.sdk.auth.getCurrentSession();
|
|
86
|
+
if (!session.data?.session?.accessToken) {
|
|
87
|
+
this.isLoaded = true;
|
|
88
|
+
this.user = null;
|
|
89
|
+
}
|
|
84
90
|
}
|
|
85
91
|
// Public access method (Singleton core)
|
|
86
92
|
static getInstance(config) {
|
|
@@ -104,8 +110,17 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
104
110
|
}
|
|
105
111
|
// Public initialization method
|
|
106
112
|
async initialize() {
|
|
107
|
-
if (
|
|
113
|
+
if (this.isLoaded) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (this.isInitializing) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.isInitializing = true;
|
|
120
|
+
try {
|
|
108
121
|
await this.loadAuthState();
|
|
122
|
+
} finally {
|
|
123
|
+
this.isInitializing = false;
|
|
109
124
|
}
|
|
110
125
|
}
|
|
111
126
|
// Get current state
|
|
@@ -211,6 +226,7 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
211
226
|
avatarUrl: profile?.avatarUrl || ""
|
|
212
227
|
};
|
|
213
228
|
this.user = userData;
|
|
229
|
+
this.notifyListeners();
|
|
214
230
|
if (this.config.onAuthChange) {
|
|
215
231
|
this.config.onAuthChange(userData);
|
|
216
232
|
}
|
|
@@ -223,7 +239,6 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
223
239
|
}
|
|
224
240
|
}
|
|
225
241
|
}
|
|
226
|
-
this.notifyListeners();
|
|
227
242
|
} else if (fallbackUser) {
|
|
228
243
|
const userData = {
|
|
229
244
|
id: fallbackUser.id || "",
|
|
@@ -232,10 +247,10 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
232
247
|
avatarUrl: ""
|
|
233
248
|
};
|
|
234
249
|
this.user = userData;
|
|
250
|
+
this.notifyListeners();
|
|
235
251
|
if (this.config.onAuthChange) {
|
|
236
252
|
this.config.onAuthChange(userData);
|
|
237
253
|
}
|
|
238
|
-
this.notifyListeners();
|
|
239
254
|
}
|
|
240
255
|
}
|
|
241
256
|
// Business methods
|
|
@@ -414,22 +429,22 @@ var InsforgeManager = class _InsforgeManager {
|
|
|
414
429
|
getSDK() {
|
|
415
430
|
return this.sdk;
|
|
416
431
|
}
|
|
417
|
-
// Handle
|
|
418
|
-
|
|
432
|
+
// Handle auth redirect after successful authentication
|
|
433
|
+
// Works for all auth sources: OAuth providers, cloud hosting sign-in, email verification
|
|
434
|
+
handleAuthRedirect(isLoaded, user) {
|
|
419
435
|
if (!isLoaded || this.hasProcessedCallbackRef) {
|
|
420
436
|
return false;
|
|
421
437
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
this.hasProcessedCallbackRef
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
return true;
|
|
438
|
+
if (user && this.config.afterSignInUrl) {
|
|
439
|
+
const currentPath = window.location.pathname + window.location.search;
|
|
440
|
+
const targetPath = this.config.afterSignInUrl;
|
|
441
|
+
if (currentPath !== targetPath && !this.hasProcessedCallbackRef) {
|
|
442
|
+
this.hasProcessedCallbackRef = true;
|
|
443
|
+
setTimeout(() => {
|
|
444
|
+
window.location.href = targetPath;
|
|
445
|
+
}, 100);
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
433
448
|
}
|
|
434
449
|
return false;
|
|
435
450
|
}
|
|
@@ -466,11 +481,13 @@ function InsforgeProviderCore({
|
|
|
466
481
|
setState(newState);
|
|
467
482
|
});
|
|
468
483
|
void manager.initialize();
|
|
469
|
-
return
|
|
484
|
+
return () => {
|
|
485
|
+
unsubscribe();
|
|
486
|
+
};
|
|
470
487
|
}, [manager]);
|
|
471
488
|
react.useEffect(() => {
|
|
472
489
|
if (typeof window !== "undefined") {
|
|
473
|
-
manager.
|
|
490
|
+
manager.handleAuthRedirect(state.isLoaded, state.user);
|
|
474
491
|
}
|
|
475
492
|
}, [manager, state.isLoaded, state.user]);
|
|
476
493
|
const contextValue = react.useMemo(
|