@insforge/react 0.2.5 → 0.2.6

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/router.d.mts CHANGED
@@ -13,14 +13,13 @@ interface GetInsforgeRoutesConfig {
13
13
  */
14
14
  builtInAuth?: boolean;
15
15
  /**
16
- * Custom paths for auth routes
16
+ * Custom paths for auth redirect routes
17
17
  * @default {
18
18
  * signIn: '/sign-in',
19
19
  * signUp: '/sign-up',
20
20
  * verifyEmail: '/verify-email',
21
21
  * forgotPassword: '/forgot-password',
22
- * resetPassword: '/reset-password',
23
- * callback: '/auth/callback'
22
+ * resetPassword: '/reset-password'
24
23
  * }
25
24
  */
26
25
  paths?: {
@@ -29,73 +28,58 @@ interface GetInsforgeRoutesConfig {
29
28
  verifyEmail?: string;
30
29
  forgotPassword?: string;
31
30
  resetPassword?: string;
32
- callback?: string;
33
31
  };
34
32
  }
35
33
  /**
36
- * Generates Insforge authentication routes for React Router.
34
+ * Generates Insforge authentication redirect routes for React Router.
37
35
  *
38
- * Returns an array of RouteObjects that can be spread into your router configuration.
39
- * Supports all Insforge auth pages: sign-in, sign-up, verify-email, forgot-password, reset-password.
36
+ * Returns redirect routes for sign-in, sign-up, etc. that redirect to your deployed Insforge auth pages.
37
+ *
38
+ * ⚠️ **Important**: You must manually create the `/auth/callback` route in your router
39
+ * to handle authentication callbacks. See documentation for details.
40
40
  *
41
41
  * @param config - Configuration for Insforge routes
42
- * @returns Array of RouteObject for React Router
42
+ * @returns Array of RouteObject for React Router (redirect routes only)
43
43
  *
44
44
  * @example
45
45
  * ```tsx
46
46
  * import { createBrowserRouter } from 'react-router-dom';
47
- * import { getInsforgeRoutes } from '@insforge/react';
47
+ * import { getInsforgeRoutes } from '@insforge/react/router';
48
+ * import { InsforgeCallback } from '@insforge/react';
48
49
  *
49
50
  * const router = createBrowserRouter([
50
51
  * {
51
52
  * path: '/',
52
- * element: <Home />
53
+ * element: <Layout />,
54
+ * children: [
55
+ * { index: true, element: <Home /> },
56
+ * // ✅ Required: Manually create callback route
57
+ * { path: 'auth/callback', element: <AuthCallback /> },
58
+ * { path: 'dashboard', element: <Dashboard /> }
59
+ * ]
53
60
  * },
54
- * // Add all Insforge auth routes (sign-in, sign-up, verify-email, etc.)
61
+ * // Add redirect routes (sign-in, sign-up, etc.)
55
62
  * ...getInsforgeRoutes({
56
63
  * baseUrl: 'https://your-backend.com',
57
64
  * builtInAuth: true
58
- * }),
59
- * {
60
- * path: '/dashboard',
61
- * element: <Dashboard />
62
- * }
65
+ * })
63
66
  * ]);
64
- * ```
65
67
  *
66
- * @example
67
- * ```tsx
68
- * // Don't use built-in auth, use your own components instead
69
- * import { SignIn, SignUp } from '@insforge/react';
70
- *
71
- * const router = createBrowserRouter([
72
- * // Only add callback route
73
- * ...getInsforgeRoutes({
74
- * baseUrl: 'https://your-backend.com',
75
- * builtInAuth: false
76
- * }),
77
- * // Your own auth components
78
- * {
79
- * path: '/sign-in',
80
- * element: <SignIn />
81
- * },
82
- * {
83
- * path: '/sign-up',
84
- * element: <SignUp />
85
- * }
86
- * ]);
68
+ * // src/pages/AuthCallback.tsx
69
+ * function AuthCallback() {
70
+ * return <InsforgeCallback redirectTo="/dashboard" />;
71
+ * }
87
72
  * ```
88
73
  *
89
74
  * @example
90
75
  * ```tsx
91
- * // Custom paths
76
+ * // Custom paths for redirect routes
92
77
  * ...getInsforgeRoutes({
93
78
  * baseUrl: 'https://your-backend.com',
94
79
  * builtInAuth: true,
95
80
  * paths: {
96
81
  * signIn: '/login',
97
- * signUp: '/register',
98
- * callback: '/callback'
82
+ * signUp: '/register'
99
83
  * }
100
84
  * })
101
85
  * ```
package/dist/router.d.ts CHANGED
@@ -13,14 +13,13 @@ interface GetInsforgeRoutesConfig {
13
13
  */
14
14
  builtInAuth?: boolean;
15
15
  /**
16
- * Custom paths for auth routes
16
+ * Custom paths for auth redirect routes
17
17
  * @default {
18
18
  * signIn: '/sign-in',
19
19
  * signUp: '/sign-up',
20
20
  * verifyEmail: '/verify-email',
21
21
  * forgotPassword: '/forgot-password',
22
- * resetPassword: '/reset-password',
23
- * callback: '/auth/callback'
22
+ * resetPassword: '/reset-password'
24
23
  * }
25
24
  */
26
25
  paths?: {
@@ -29,73 +28,58 @@ interface GetInsforgeRoutesConfig {
29
28
  verifyEmail?: string;
30
29
  forgotPassword?: string;
31
30
  resetPassword?: string;
32
- callback?: string;
33
31
  };
34
32
  }
35
33
  /**
36
- * Generates Insforge authentication routes for React Router.
34
+ * Generates Insforge authentication redirect routes for React Router.
37
35
  *
38
- * Returns an array of RouteObjects that can be spread into your router configuration.
39
- * Supports all Insforge auth pages: sign-in, sign-up, verify-email, forgot-password, reset-password.
36
+ * Returns redirect routes for sign-in, sign-up, etc. that redirect to your deployed Insforge auth pages.
37
+ *
38
+ * ⚠️ **Important**: You must manually create the `/auth/callback` route in your router
39
+ * to handle authentication callbacks. See documentation for details.
40
40
  *
41
41
  * @param config - Configuration for Insforge routes
42
- * @returns Array of RouteObject for React Router
42
+ * @returns Array of RouteObject for React Router (redirect routes only)
43
43
  *
44
44
  * @example
45
45
  * ```tsx
46
46
  * import { createBrowserRouter } from 'react-router-dom';
47
- * import { getInsforgeRoutes } from '@insforge/react';
47
+ * import { getInsforgeRoutes } from '@insforge/react/router';
48
+ * import { InsforgeCallback } from '@insforge/react';
48
49
  *
49
50
  * const router = createBrowserRouter([
50
51
  * {
51
52
  * path: '/',
52
- * element: <Home />
53
+ * element: <Layout />,
54
+ * children: [
55
+ * { index: true, element: <Home /> },
56
+ * // ✅ Required: Manually create callback route
57
+ * { path: 'auth/callback', element: <AuthCallback /> },
58
+ * { path: 'dashboard', element: <Dashboard /> }
59
+ * ]
53
60
  * },
54
- * // Add all Insforge auth routes (sign-in, sign-up, verify-email, etc.)
61
+ * // Add redirect routes (sign-in, sign-up, etc.)
55
62
  * ...getInsforgeRoutes({
56
63
  * baseUrl: 'https://your-backend.com',
57
64
  * builtInAuth: true
58
- * }),
59
- * {
60
- * path: '/dashboard',
61
- * element: <Dashboard />
62
- * }
65
+ * })
63
66
  * ]);
64
- * ```
65
67
  *
66
- * @example
67
- * ```tsx
68
- * // Don't use built-in auth, use your own components instead
69
- * import { SignIn, SignUp } from '@insforge/react';
70
- *
71
- * const router = createBrowserRouter([
72
- * // Only add callback route
73
- * ...getInsforgeRoutes({
74
- * baseUrl: 'https://your-backend.com',
75
- * builtInAuth: false
76
- * }),
77
- * // Your own auth components
78
- * {
79
- * path: '/sign-in',
80
- * element: <SignIn />
81
- * },
82
- * {
83
- * path: '/sign-up',
84
- * element: <SignUp />
85
- * }
86
- * ]);
68
+ * // src/pages/AuthCallback.tsx
69
+ * function AuthCallback() {
70
+ * return <InsforgeCallback redirectTo="/dashboard" />;
71
+ * }
87
72
  * ```
88
73
  *
89
74
  * @example
90
75
  * ```tsx
91
- * // Custom paths
76
+ * // Custom paths for redirect routes
92
77
  * ...getInsforgeRoutes({
93
78
  * baseUrl: 'https://your-backend.com',
94
79
  * builtInAuth: true,
95
80
  * paths: {
96
81
  * signIn: '/login',
97
- * signUp: '/register',
98
- * callback: '/callback'
82
+ * signUp: '/register'
99
83
  * }
100
84
  * })
101
85
  * ```
package/dist/router.js CHANGED
@@ -1,106 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var react = require('react');
4
- require('@insforge/sdk');
5
4
  var jsxRuntime = require('react/jsx-runtime');
6
5
 
7
- var InsforgeContext = react.createContext(
8
- void 0
9
- );
10
- function useInsforge() {
11
- const context = react.useContext(InsforgeContext);
12
- if (!context) {
13
- throw new Error("useInsforge must be used within InsforgeProvider");
14
- }
15
- return context;
16
- }
17
- function InsforgeCallback({
18
- redirectTo,
19
- onSuccess,
20
- onError,
21
- loadingComponent,
22
- onRedirect
23
- }) {
24
- const isProcessingRef = react.useRef(false);
25
- const { handleAuthCallback } = useInsforge();
26
- react.useEffect(() => {
27
- const processCallback = async () => {
28
- if (isProcessingRef.current) return;
29
- isProcessingRef.current = true;
30
- const searchParams = new URLSearchParams(window.location.search);
31
- const error = searchParams.get("error");
32
- if (error) {
33
- if (onError) {
34
- onError(error);
35
- } else {
36
- const errorUrl = "/?error=" + encodeURIComponent(error);
37
- if (onRedirect) {
38
- onRedirect(errorUrl);
39
- } else {
40
- window.location.href = errorUrl;
41
- }
42
- }
43
- return;
44
- }
45
- const accessToken = searchParams.get("access_token") || searchParams.get("auth_token");
46
- const userId = searchParams.get("user_id");
47
- const email = searchParams.get("email");
48
- const name = searchParams.get("name");
49
- if (!accessToken) {
50
- const errorMsg = "no_token";
51
- if (onError) {
52
- onError(errorMsg);
53
- } else {
54
- const errorUrl = "/?error=" + encodeURIComponent(errorMsg);
55
- if (onRedirect) {
56
- onRedirect(errorUrl);
57
- } else {
58
- window.location.href = errorUrl;
59
- }
60
- }
61
- return;
62
- }
63
- const result = await handleAuthCallback({
64
- accessToken,
65
- userId: userId || void 0,
66
- email: email || void 0,
67
- name: name || void 0
68
- });
69
- if (!result.success) {
70
- const errorMsg = result.error || "authentication_failed";
71
- if (onError) {
72
- onError(errorMsg);
73
- } else {
74
- const errorUrl = "/?error=" + encodeURIComponent(errorMsg);
75
- if (onRedirect) {
76
- onRedirect(errorUrl);
77
- } else {
78
- window.location.href = errorUrl;
79
- }
80
- }
81
- return;
82
- }
83
- window.history.replaceState({}, "", window.location.pathname);
84
- if (onSuccess) {
85
- onSuccess();
86
- }
87
- const destination = redirectTo || sessionStorage.getItem("auth_destination") || sessionStorage.getItem("oauth_final_destination") || "/";
88
- sessionStorage.removeItem("auth_destination");
89
- sessionStorage.removeItem("oauth_final_destination");
90
- if (onRedirect) {
91
- onRedirect(destination);
92
- } else {
93
- window.location.href = destination;
94
- }
95
- };
96
- processCallback();
97
- }, [handleAuthCallback, redirectTo, onSuccess, onError, onRedirect]);
98
- const defaultLoading = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
99
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold mb-4", children: "Completing authentication..." }),
100
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto" })
101
- ] }) });
102
- return loadingComponent || defaultLoading;
103
- }
104
6
  function RedirectToAuth({ baseUrl, path }) {
105
7
  react.useEffect(() => {
106
8
  const callbackUrl = `${window.location.origin}/auth/callback`;
@@ -121,16 +23,9 @@ function getInsforgeRoutes(config) {
121
23
  signUp = "/sign-up",
122
24
  verifyEmail = "/verify-email",
123
25
  forgotPassword = "/forgot-password",
124
- resetPassword = "/reset-password",
125
- callback = "/auth/callback"
26
+ resetPassword = "/reset-password"
126
27
  } = paths;
127
- const routes = [
128
- // Always include callback route
129
- {
130
- path: callback,
131
- element: /* @__PURE__ */ jsxRuntime.jsx(InsforgeCallback, {})
132
- }
133
- ];
28
+ const routes = [];
134
29
  if (builtInAuth) {
135
30
  routes.push(
136
31
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider/InsforgeProvider.tsx","../src/components/InsforgeCallback.tsx","../src/router/getInsforgeRoutes.tsx"],"names":["createContext","useContext","useRef","useEffect","jsx","jsxs"],"mappings":"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","file":"router.js","sourcesContent":["\"use client\";\r\n\r\nimport {\r\n createContext,\r\n useContext,\r\n useEffect,\r\n useState,\r\n useCallback,\r\n useRef,\r\n type ReactNode,\r\n} from \"react\";\r\nimport { createClient } from \"@insforge/sdk\";\r\nimport type { InsforgeUser } from \"../types\";\r\nimport { GetPublicAuthConfigResponse } from \"@insforge/shared-schemas\";\r\n\r\ninterface InsforgeContextValue {\r\n // Auth state\r\n user: InsforgeUser | null;\r\n isLoaded: boolean;\r\n isSignedIn: boolean;\r\n\r\n // Auth methods\r\n setUser: (user: InsforgeUser | null) => void;\r\n signIn: (\r\n email: string,\r\n password: string\r\n ) => Promise<\r\n | {\r\n user?: { id: string; email: string; name: string };\r\n accessToken: string | null;\r\n }\r\n | { error: string }\r\n >;\r\n signUp: (\r\n email: string,\r\n password: string\r\n ) => Promise<\r\n | {\r\n user?: { id: string; email: string; name: string };\r\n accessToken: string | null;\r\n }\r\n | { error: string }\r\n >;\r\n signOut: () => Promise<void>;\r\n updateUser: (data: Partial<InsforgeUser>) => Promise<void>;\r\n reloadAuth: () => Promise<{ success: boolean; error?: string }>;\r\n \r\n // Callback handling for OAuth and email/password redirects\r\n handleAuthCallback: (params: {\r\n accessToken: string;\r\n userId?: string;\r\n email?: string;\r\n name?: string;\r\n }) => Promise<{ success: boolean; error?: string }>;\r\n\r\n // Email verification methods\r\n sendPasswordResetCode: (\r\n email: string\r\n ) => Promise<{ success: boolean; message: string } | null>;\r\n resetPassword: (\r\n token: string,\r\n newPassword: string\r\n ) => Promise<{ message: string; redirectTo?: string } | null>;\r\n verifyEmail: (\r\n token: string\r\n ) => Promise<{ accessToken: string; user?: any } | null>;\r\n\r\n // Public auth config\r\n getPublicAuthConfig: () => Promise<GetPublicAuthConfigResponse | null>;\r\n // Base config\r\n baseUrl: string;\r\n}\r\n\r\nconst InsforgeContext = createContext<InsforgeContextValue | undefined>(\r\n undefined\r\n);\r\n\r\nexport interface InsforgeProviderProps {\r\n children: ReactNode;\r\n baseUrl: string;\r\n onAuthChange?: (user: InsforgeUser | null) => void;\r\n // Optional: custom token sync functions (e.g., for Next.js cookie sync)\r\n syncTokenToCookie?: (token: string) => Promise<boolean>;\r\n clearCookie?: () => Promise<void>;\r\n}\r\n\r\n/**\r\n * Unified Insforge Provider - manages authentication state and configuration\r\n *\r\n * Manages user authentication state and provides all necessary context to child components.\r\n * Works with any React framework (Next.js, Vite, Remix, etc.).\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage (React/Vite)\r\n * import { InsforgeProvider } from '@insforge/react';\r\n *\r\n * export default function App() {\r\n * return (\r\n * <InsforgeProvider baseUrl={process.env.VITE_INSFORGE_BASE_URL}>\r\n * {children}\r\n * </InsforgeProvider>\r\n * );\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```tsx\r\n * // With cookie sync (Next.js optimization)\r\n * <InsforgeProvider\r\n * baseUrl={baseUrl}\r\n * syncTokenToCookie={async (token) => {\r\n * await fetch('/api/auth', {\r\n * method: 'POST',\r\n * body: JSON.stringify({ token })\r\n * });\r\n * return true;\r\n * }}\r\n * clearCookie={async () => {\r\n * await fetch('/api/auth', { method: 'DELETE' });\r\n * }}\r\n * >\r\n * {children}\r\n * </InsforgeProvider>\r\n * ```\r\n */\r\nexport function InsforgeProvider({\r\n children,\r\n baseUrl,\r\n onAuthChange,\r\n syncTokenToCookie,\r\n clearCookie,\r\n}: InsforgeProviderProps) {\r\n // Auth state\r\n const [user, setUser] = useState<InsforgeUser | null>(null);\r\n const [isLoaded, setIsLoaded] = useState(false);\r\n\r\n const refreshIntervalRef = useRef<NodeJS.Timeout | null>(null);\r\n\r\n // Initialize SDK client with lazy initialization - only runs once\r\n const [insforge] = useState(() => createClient({ baseUrl }));\r\n\r\n // Load auth state - returns explicit success/error status\r\n const loadAuthState = useCallback(async (): Promise<{\r\n success: boolean;\r\n error?: string;\r\n }> => {\r\n try {\r\n // Use SDK's getCurrentSession() to check for existing session\r\n const sessionResult = insforge.auth.getCurrentSession();\r\n const session = sessionResult.data?.session;\r\n const token = session?.accessToken || null;\r\n\r\n if (!token) {\r\n // No token, user is not authenticated\r\n setUser(null);\r\n if (onAuthChange) {\r\n onAuthChange(null);\r\n }\r\n setIsLoaded(true);\r\n return { success: false, error: \"no_session\" };\r\n }\r\n\r\n const userResult = await insforge.auth.getCurrentUser();\r\n\r\n if (userResult.data) {\r\n // Token is valid, update user state with fresh data\r\n const profile = userResult.data.profile;\r\n const userData: InsforgeUser = {\r\n id: userResult.data.user.id,\r\n email: userResult.data.user.email,\r\n name: (profile?.nickname as string | undefined) || \"\",\r\n avatarUrl: (profile?.avatarUrl as string | undefined) || \"\",\r\n };\r\n\r\n setUser(userData);\r\n\r\n if (onAuthChange) {\r\n onAuthChange(userData);\r\n }\r\n setIsLoaded(true);\r\n return { success: true };\r\n } else {\r\n // Token invalid or expired\r\n await insforge.auth.signOut();\r\n\r\n // Clear cookie if function provided\r\n if (clearCookie) {\r\n try {\r\n await clearCookie();\r\n } catch (error) {\r\n // Ignore errors\r\n }\r\n }\r\n\r\n setUser(null);\r\n if (onAuthChange) {\r\n onAuthChange(null);\r\n }\r\n setIsLoaded(true);\r\n return { success: false, error: \"invalid_token\" };\r\n }\r\n } catch (error) {\r\n // Token validation failed\r\n console.error(\"[InsforgeProvider] Token validation failed:\", error);\r\n\r\n await insforge.auth.signOut();\r\n\r\n // Clear cookie if function provided\r\n if (clearCookie) {\r\n try {\r\n await clearCookie();\r\n } catch (error) {\r\n // Ignore errors\r\n }\r\n }\r\n\r\n setUser(null);\r\n if (onAuthChange) {\r\n onAuthChange(null);\r\n }\r\n setIsLoaded(true);\r\n\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : \"authentication_failed\",\r\n };\r\n }\r\n }, [insforge, onAuthChange, syncTokenToCookie, clearCookie]);\r\n\r\n useEffect(() => {\r\n // Run loadAuthState only once on mount\r\n loadAuthState();\r\n\r\n return () => {\r\n if (refreshIntervalRef.current) {\r\n clearInterval(refreshIntervalRef.current);\r\n }\r\n };\r\n }, []); // Empty deps - run only on mount\r\n\r\n const getPublicAuthConfig = useCallback(async () => {\r\n try {\r\n const result = await insforge.auth.getPublicAuthConfig();\r\n if (result.data) {\r\n return result.data;\r\n } else {\r\n console.error('[InsforgeProvider] Failed to get public auth config:', result.error);\r\n return null;\r\n }\r\n } catch (error) {\r\n console.error(\r\n \"[InsforgeProvider] Failed to get public auth config:\",\r\n error\r\n );\r\n return null;\r\n }\r\n }, [insforge]);\r\n\r\n /**\r\n * Helper function to handle successful authentication\r\n */\r\n const handleAuthSuccess = useCallback(\r\n async (\r\n authToken: string,\r\n fallbackUser?: { id?: string; email?: string; name?: string }\r\n ) => {\r\n const userResult = await insforge.auth.getCurrentUser();\r\n\r\n if (userResult.data) {\r\n const profile = userResult.data.profile;\r\n const userData: InsforgeUser = {\r\n id: userResult.data.user.id,\r\n email: userResult.data.user.email,\r\n name: (profile?.nickname as string | undefined) || \"\",\r\n avatarUrl: (profile?.avatarUrl as string | undefined) || \"\",\r\n };\r\n\r\n setUser(userData);\r\n\r\n if (onAuthChange) {\r\n onAuthChange(userData);\r\n }\r\n\r\n // Try to sync token to cookie if function provided\r\n if (syncTokenToCookie) {\r\n try {\r\n await syncTokenToCookie(authToken);\r\n } catch (error) {\r\n // Cookie sync failed - that's okay\r\n }\r\n }\r\n } else if (fallbackUser) {\r\n // Fallback to basic user data if getCurrentUser fails\r\n const userData: InsforgeUser = {\r\n id: fallbackUser.id || \"\",\r\n email: fallbackUser.email || \"\",\r\n name: fallbackUser.name || \"\",\r\n avatarUrl: \"\",\r\n };\r\n\r\n setUser(userData);\r\n\r\n if (onAuthChange) {\r\n onAuthChange(userData);\r\n }\r\n }\r\n },\r\n [insforge, onAuthChange, syncTokenToCookie]\r\n );\r\n\r\n /**\r\n * Handle authentication callback from OAuth or email/password redirects\r\n * This is specifically for callback pages - saves token and verifies authentication\r\n */\r\n const handleAuthCallback = useCallback(\r\n async (params: {\r\n accessToken: string;\r\n userId?: string;\r\n email?: string;\r\n name?: string;\r\n }): Promise<{ success: boolean; error?: string }> => {\r\n try {\r\n // Save the token to localStorage using SDK's setSession\r\n await insforge.auth.setSession({\r\n accessToken: params.accessToken,\r\n user: {\r\n id: params.userId || '',\r\n email: params.email || '',\r\n name: params.name || '',\r\n emailVerified: false,\r\n createdAt: new Date().toISOString(),\r\n updatedAt: new Date().toISOString(),\r\n },\r\n });\r\n\r\n // Now verify the token and get full user data\r\n const userResult = await insforge.auth.getCurrentUser();\r\n\r\n if (!userResult.data) {\r\n // Token is invalid\r\n await insforge.auth.signOut();\r\n \r\n if (clearCookie) {\r\n try {\r\n await clearCookie();\r\n } catch (error) {\r\n // Ignore errors\r\n }\r\n }\r\n\r\n return { success: false, error: 'invalid_token' };\r\n }\r\n\r\n // Update user state with full profile data\r\n const profile = userResult.data.profile;\r\n const userData: InsforgeUser = {\r\n id: userResult.data.user.id,\r\n email: userResult.data.user.email,\r\n name: (profile?.nickname as string | undefined) || params.name || '',\r\n avatarUrl: (profile?.avatarUrl as string | undefined) || '',\r\n };\r\n\r\n setUser(userData);\r\n\r\n if (onAuthChange) {\r\n onAuthChange(userData);\r\n }\r\n\r\n // Sync token to cookie if function provided\r\n if (syncTokenToCookie) {\r\n try {\r\n await syncTokenToCookie(params.accessToken);\r\n } catch (error) {\r\n // Cookie sync failed - that's okay, continue\r\n }\r\n }\r\n\r\n return { success: true };\r\n } catch (error) {\r\n // Authentication failed\r\n console.error('[InsforgeProvider] Auth callback failed:', error);\r\n\r\n await insforge.auth.signOut();\r\n\r\n if (clearCookie) {\r\n try {\r\n await clearCookie();\r\n } catch (error) {\r\n // Ignore errors\r\n }\r\n }\r\n\r\n setUser(null);\r\n if (onAuthChange) {\r\n onAuthChange(null);\r\n }\r\n\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'authentication_failed',\r\n };\r\n }\r\n },\r\n [insforge, onAuthChange, syncTokenToCookie, clearCookie]\r\n );\r\n\r\n const signIn = useCallback(\r\n async (email: string, password: string) => {\r\n const sdkResult = await insforge.auth.signInWithPassword({\r\n email,\r\n password,\r\n });\r\n\r\n if (sdkResult.data) {\r\n await handleAuthSuccess(\r\n sdkResult.data.accessToken || \"\",\r\n sdkResult.data.user\r\n ? {\r\n id: sdkResult.data.user.id,\r\n email: sdkResult.data.user.email,\r\n name: sdkResult.data.user.name,\r\n }\r\n : undefined\r\n );\r\n return sdkResult.data;\r\n } else {\r\n const errorMessage =\r\n sdkResult.error?.message || \"Invalid email or password\";\r\n return { error: errorMessage };\r\n }\r\n },\r\n [insforge, handleAuthSuccess]\r\n );\r\n\r\n const signUp = useCallback(\r\n async (email: string, password: string) => {\r\n const sdkResult = await insforge.auth.signUp({ email, password });\r\n\r\n if (sdkResult.data) {\r\n await handleAuthSuccess(\r\n sdkResult.data.accessToken || \"\",\r\n sdkResult.data.user\r\n ? {\r\n id: sdkResult.data.user.id,\r\n email: sdkResult.data.user.email,\r\n name: sdkResult.data.user.name,\r\n }\r\n : undefined\r\n );\r\n return sdkResult.data;\r\n } else {\r\n const errorMessage = sdkResult.error?.message || \"Sign up failed\";\r\n return { error: errorMessage };\r\n }\r\n },\r\n [insforge, handleAuthSuccess]\r\n );\r\n\r\n const signOut = useCallback(async () => {\r\n await insforge.auth.signOut();\r\n\r\n // Clear cookie if function provided\r\n if (clearCookie) {\r\n try {\r\n await clearCookie();\r\n } catch (error) {\r\n // Ignore errors\r\n }\r\n }\r\n\r\n // Clear refresh interval if exists\r\n if (refreshIntervalRef.current) {\r\n clearInterval(refreshIntervalRef.current);\r\n }\r\n\r\n setUser(null);\r\n if (onAuthChange) {\r\n onAuthChange(null);\r\n }\r\n }, [insforge, onAuthChange, clearCookie]);\r\n\r\n const updateUser = useCallback(\r\n async (data: Partial<InsforgeUser>) => {\r\n if (!user) throw new Error(\"No user signed in\");\r\n\r\n const profileUpdate: Record<string, any> = {\r\n nickname: data.name,\r\n avatarUrl: data.avatarUrl,\r\n };\r\n\r\n const result = await insforge.auth.setProfile(profileUpdate);\r\n\r\n if (result.data) {\r\n const userResult = await insforge.auth.getCurrentUser();\r\n if (userResult.data) {\r\n const profile = userResult.data.profile;\r\n const updatedUser: InsforgeUser = {\r\n id: userResult.data.user.id,\r\n email: userResult.data.user.email,\r\n name: (profile?.nickname as string | undefined) || \"\",\r\n avatarUrl: (profile?.avatarUrl as string | undefined) || \"\",\r\n };\r\n setUser(updatedUser);\r\n if (onAuthChange) {\r\n onAuthChange(updatedUser);\r\n }\r\n }\r\n }\r\n },\r\n [user, onAuthChange, insforge]\r\n );\r\n\r\n const sendPasswordResetCode = useCallback(\r\n async (email: string) => {\r\n const sdkResult = await insforge.auth.sendPasswordResetCode({ email });\r\n return sdkResult.data;\r\n },\r\n [insforge]\r\n );\r\n\r\n const resetPassword = useCallback(\r\n async (token: string, newPassword: string) => {\r\n const sdkResult = await insforge.auth.resetPassword({\r\n newPassword,\r\n otp: token,\r\n });\r\n return sdkResult.data;\r\n },\r\n [insforge]\r\n );\r\n\r\n const verifyEmail = useCallback(\r\n async (token: string) => {\r\n const sdkResult = await insforge.auth.verifyEmail({ otp: token });\r\n return sdkResult.data;\r\n },\r\n [insforge]\r\n );\r\n\r\n return (\r\n <InsforgeContext.Provider\r\n value={{\r\n user,\r\n isLoaded,\r\n isSignedIn: !!user,\r\n setUser,\r\n signIn,\r\n signUp,\r\n signOut,\r\n updateUser,\r\n reloadAuth: loadAuthState,\r\n handleAuthCallback,\r\n baseUrl,\r\n sendPasswordResetCode,\r\n resetPassword,\r\n verifyEmail,\r\n getPublicAuthConfig,\r\n }}\r\n >\r\n {children}\r\n </InsforgeContext.Provider>\r\n );\r\n}\r\n\r\n/**\r\n * Hook to access Insforge context\r\n *\r\n * @example\r\n * ```tsx\r\n * function MyComponent() {\r\n * const { user, isSignedIn, signOut } = useInsforge();\r\n *\r\n * if (!isSignedIn) return <SignIn />;\r\n *\r\n * return (\r\n * <div>\r\n * <p>Welcome {user.email}</p>\r\n * <button onClick={signOut}>Sign Out</button>\r\n * </div>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function useInsforge(): InsforgeContextValue {\r\n const context = useContext(InsforgeContext);\r\n if (!context) {\r\n throw new Error(\"useInsforge must be used within InsforgeProvider\");\r\n }\r\n return context;\r\n}\r\n","'use client';\r\n\r\nimport { useEffect, useRef, type ReactNode } from 'react';\r\nimport { useInsforge } from '../provider/InsforgeProvider';\r\n\r\nexport interface InsforgeCallbackProps {\r\n /**\r\n * Redirect destination after successful authentication\r\n */\r\n redirectTo?: string;\r\n \r\n /**\r\n * Callback fired on successful authentication\r\n */\r\n onSuccess?: () => void;\r\n \r\n /**\r\n * Callback fired on authentication error\r\n */\r\n onError?: (error: string) => void;\r\n \r\n /**\r\n * Custom loading component\r\n */\r\n loadingComponent?: ReactNode;\r\n \r\n /**\r\n * Custom redirect handler (default: window.location)\r\n */\r\n onRedirect?: (url: string) => void;\r\n}\r\n\r\n/**\r\n * InsforgeCallback - Handles OAuth and email/password authentication callbacks\r\n * \r\n * Place this component on your `/auth/callback` page.\r\n * \r\n * @example\r\n * ```tsx\r\n * // Minimal usage\r\n * export default function CallbackPage() {\r\n * return <InsforgeCallback />;\r\n * }\r\n * ```\r\n * \r\n * @example\r\n * ```tsx\r\n * // With Next.js router\r\n * import { useRouter } from 'next/navigation';\r\n * \r\n * export default function CallbackPage() {\r\n * const router = useRouter();\r\n * return (\r\n * <InsforgeCallback\r\n * redirectTo=\"/dashboard\"\r\n * onRedirect={(url) => router.push(url)}\r\n * />\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function InsforgeCallback({\r\n redirectTo,\r\n onSuccess,\r\n onError,\r\n loadingComponent,\r\n onRedirect,\r\n}: InsforgeCallbackProps) {\r\n const isProcessingRef = useRef(false);\r\n const { handleAuthCallback } = useInsforge();\r\n\r\n useEffect(() => {\r\n const processCallback = async () => {\r\n // Prevent double-processing\r\n if (isProcessingRef.current) return;\r\n isProcessingRef.current = true;\r\n\r\n // Get search params\r\n const searchParams = new URLSearchParams(window.location.search);\r\n\r\n // Check for error from backend\r\n const error = searchParams.get('error');\r\n if (error) {\r\n if (onError) {\r\n onError(error);\r\n } else {\r\n const errorUrl = '/?error=' + encodeURIComponent(error);\r\n if (onRedirect) {\r\n onRedirect(errorUrl);\r\n } else {\r\n window.location.href = errorUrl;\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Extract token parameters from URL\r\n // Supports both OAuth callbacks (access_token) and email/password redirects (auth_token)\r\n const accessToken = searchParams.get('access_token') || searchParams.get('auth_token');\r\n const userId = searchParams.get('user_id');\r\n const email = searchParams.get('email');\r\n const name = searchParams.get('name');\r\n\r\n if (!accessToken) {\r\n // No token found in URL\r\n const errorMsg = 'no_token';\r\n if (onError) {\r\n onError(errorMsg);\r\n } else {\r\n const errorUrl = '/?error=' + encodeURIComponent(errorMsg);\r\n if (onRedirect) {\r\n onRedirect(errorUrl);\r\n } else {\r\n window.location.href = errorUrl;\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Handle the callback: save token, verify, and update state\r\n const result = await handleAuthCallback({\r\n accessToken,\r\n userId: userId || undefined,\r\n email: email || undefined,\r\n name: name || undefined,\r\n });\r\n\r\n if (!result.success) {\r\n const errorMsg = result.error || 'authentication_failed';\r\n if (onError) {\r\n onError(errorMsg);\r\n } else {\r\n const errorUrl = '/?error=' + encodeURIComponent(errorMsg);\r\n if (onRedirect) {\r\n onRedirect(errorUrl);\r\n } else {\r\n window.location.href = errorUrl;\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Authentication successful!\r\n // Clean URL\r\n window.history.replaceState({}, '', window.location.pathname);\r\n\r\n // Fire success callback\r\n if (onSuccess) {\r\n onSuccess();\r\n }\r\n\r\n // Get destination and redirect\r\n const destination = \r\n redirectTo || \r\n sessionStorage.getItem('auth_destination') || \r\n sessionStorage.getItem('oauth_final_destination') || \r\n '/';\r\n \r\n sessionStorage.removeItem('auth_destination');\r\n sessionStorage.removeItem('oauth_final_destination');\r\n\r\n if (onRedirect) {\r\n onRedirect(destination);\r\n } else {\r\n window.location.href = destination;\r\n }\r\n };\r\n\r\n processCallback();\r\n }, [handleAuthCallback, redirectTo, onSuccess, onError, onRedirect]); // Include all dependencies\r\n\r\n const defaultLoading = (\r\n <div className=\"flex items-center justify-center min-h-screen\">\r\n <div className=\"text-center\">\r\n <h2 className=\"text-2xl font-semibold mb-4\">Completing authentication...</h2>\r\n <div className=\"animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto\"></div>\r\n </div>\r\n </div>\r\n );\r\n\r\n return loadingComponent || defaultLoading;\r\n}\r\n\r\n","'use client';\r\n\r\nimport { useEffect } from 'react';\r\nimport type { RouteObject } from 'react-router-dom';\r\nimport { InsforgeCallback } from '../components/InsforgeCallback';\r\n\r\ninterface GetInsforgeRoutesConfig {\r\n /**\r\n * Base URL of your Insforge backend\r\n */\r\n baseUrl: string;\r\n \r\n /**\r\n * Whether to use built-in auth (deployed Insforge Auth)\r\n * When true: redirects to baseUrl/auth/* pages\r\n * When false: no redirect routes are added (use your own components)\r\n * @default true\r\n */\r\n builtInAuth?: boolean;\r\n \r\n /**\r\n * Custom paths for auth routes\r\n * @default {\r\n * signIn: '/sign-in',\r\n * signUp: '/sign-up',\r\n * verifyEmail: '/verify-email',\r\n * forgotPassword: '/forgot-password',\r\n * resetPassword: '/reset-password',\r\n * callback: '/auth/callback'\r\n * }\r\n */\r\n paths?: {\r\n signIn?: string;\r\n signUp?: string;\r\n verifyEmail?: string;\r\n forgotPassword?: string;\r\n resetPassword?: string;\r\n callback?: string;\r\n };\r\n}\r\n\r\n/**\r\n * Helper component for redirecting to external auth\r\n */\r\nfunction RedirectToAuth({ baseUrl, path }: { baseUrl: string; path: string }) {\r\n useEffect(() => {\r\n const callbackUrl = `${window.location.origin}/auth/callback`;\r\n const authUrl = new URL(path, baseUrl);\r\n authUrl.searchParams.set('redirect', callbackUrl);\r\n window.location.replace(authUrl.toString());\r\n }, [baseUrl, path]);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Generates Insforge authentication routes for React Router.\r\n * \r\n * Returns an array of RouteObjects that can be spread into your router configuration.\r\n * Supports all Insforge auth pages: sign-in, sign-up, verify-email, forgot-password, reset-password.\r\n * \r\n * @param config - Configuration for Insforge routes\r\n * @returns Array of RouteObject for React Router\r\n * \r\n * @example\r\n * ```tsx\r\n * import { createBrowserRouter } from 'react-router-dom';\r\n * import { getInsforgeRoutes } from '@insforge/react';\r\n * \r\n * const router = createBrowserRouter([\r\n * {\r\n * path: '/',\r\n * element: <Home />\r\n * },\r\n * // Add all Insforge auth routes (sign-in, sign-up, verify-email, etc.)\r\n * ...getInsforgeRoutes({\r\n * baseUrl: 'https://your-backend.com',\r\n * builtInAuth: true\r\n * }),\r\n * {\r\n * path: '/dashboard',\r\n * element: <Dashboard />\r\n * }\r\n * ]);\r\n * ```\r\n * \r\n * @example\r\n * ```tsx\r\n * // Don't use built-in auth, use your own components instead\r\n * import { SignIn, SignUp } from '@insforge/react';\r\n * \r\n * const router = createBrowserRouter([\r\n * // Only add callback route\r\n * ...getInsforgeRoutes({\r\n * baseUrl: 'https://your-backend.com',\r\n * builtInAuth: false\r\n * }),\r\n * // Your own auth components\r\n * {\r\n * path: '/sign-in',\r\n * element: <SignIn />\r\n * },\r\n * {\r\n * path: '/sign-up',\r\n * element: <SignUp />\r\n * }\r\n * ]);\r\n * ```\r\n * \r\n * @example\r\n * ```tsx\r\n * // Custom paths\r\n * ...getInsforgeRoutes({\r\n * baseUrl: 'https://your-backend.com',\r\n * builtInAuth: true,\r\n * paths: {\r\n * signIn: '/login',\r\n * signUp: '/register',\r\n * callback: '/callback'\r\n * }\r\n * })\r\n * ```\r\n */\r\nexport function getInsforgeRoutes(config: GetInsforgeRoutesConfig): RouteObject[] {\r\n const {\r\n baseUrl,\r\n builtInAuth = true,\r\n paths = {},\r\n } = config;\r\n\r\n const {\r\n signIn = '/sign-in',\r\n signUp = '/sign-up',\r\n verifyEmail = '/verify-email',\r\n forgotPassword = '/forgot-password',\r\n resetPassword = '/reset-password',\r\n callback = '/auth/callback',\r\n } = paths;\r\n\r\n const routes: RouteObject[] = [\r\n // Always include callback route\r\n {\r\n path: callback,\r\n element: <InsforgeCallback />,\r\n },\r\n ];\r\n\r\n // Only add redirect routes if using built-in auth\r\n if (builtInAuth) {\r\n routes.push(\r\n {\r\n path: signIn,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/sign-in\" />,\r\n },\r\n {\r\n path: signUp,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/sign-up\" />,\r\n },\r\n {\r\n path: verifyEmail,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/verify-email\" />,\r\n },\r\n {\r\n path: forgotPassword,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/forgot-password\" />,\r\n },\r\n {\r\n path: resetPassword,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/reset-password\" />,\r\n }\r\n );\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n"]}
1
+ {"version":3,"sources":["../src/router/getInsforgeRoutes.tsx"],"names":["useEffect","jsx"],"mappings":";;;;;AAyCA,SAAS,cAAA,CAAe,EAAE,OAAA,EAAS,IAAA,EAAK,EAAsC;AAC5E,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,WAAA,GAAc,CAAA,EAAG,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,cAAA,CAAA;AAC7C,IAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AACrC,IAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,WAAW,CAAA;AAChD,IAAA,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,OAAA,CAAQ,QAAA,EAAU,CAAA;AAAA,EAC5C,CAAA,EAAG,CAAC,OAAA,EAAS,IAAI,CAAC,CAAA;AAElB,EAAA,OAAO,IAAA;AACT;AAwDO,SAAS,kBAAkB,MAAA,EAAgD;AAChF,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,WAAA,GAAc,IAAA;AAAA,IACd,QAAQ;AAAC,GACX,GAAI,MAAA;AAEJ,EAAA,MAAM;AAAA,IACJ,MAAA,GAAS,UAAA;AAAA,IACT,MAAA,GAAS,UAAA;AAAA,IACT,WAAA,GAAc,eAAA;AAAA,IACd,cAAA,GAAiB,kBAAA;AAAA,IACjB,aAAA,GAAgB;AAAA,GAClB,GAAI,KAAA;AAEJ,EAAA,MAAM,SAAwB,EAAC;AAG/B,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAA,CAAO,IAAA;AAAA,MACL;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,OAAA,kBAASC,cAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAkB,MAAK,eAAA,EAAgB;AAAA,OAClE;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAA;AAAA,QACN,OAAA,kBAASA,cAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAkB,MAAK,eAAA,EAAgB;AAAA,OAClE;AAAA,MACA;AAAA,QACE,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,kBAASA,cAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAkB,MAAK,oBAAA,EAAqB;AAAA,OACvE;AAAA,MACA;AAAA,QACE,IAAA,EAAM,cAAA;AAAA,QACN,OAAA,kBAASA,cAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAkB,MAAK,uBAAA,EAAwB;AAAA,OAC1E;AAAA,MACA;AAAA,QACE,IAAA,EAAM,aAAA;AAAA,QACN,OAAA,kBAASA,cAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAkB,MAAK,sBAAA,EAAuB;AAAA;AACzE,KACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT","file":"router.js","sourcesContent":["'use client';\r\n\r\nimport { useEffect } from 'react';\r\nimport type { RouteObject } from 'react-router-dom';\r\n\r\ninterface GetInsforgeRoutesConfig {\r\n /**\r\n * Base URL of your Insforge backend\r\n */\r\n baseUrl: string;\r\n \r\n /**\r\n * Whether to use built-in auth (deployed Insforge Auth)\r\n * When true: redirects to baseUrl/auth/* pages\r\n * When false: no redirect routes are added (use your own components)\r\n * @default true\r\n */\r\n builtInAuth?: boolean;\r\n \r\n /**\r\n * Custom paths for auth redirect routes\r\n * @default {\r\n * signIn: '/sign-in',\r\n * signUp: '/sign-up',\r\n * verifyEmail: '/verify-email',\r\n * forgotPassword: '/forgot-password',\r\n * resetPassword: '/reset-password'\r\n * }\r\n */\r\n paths?: {\r\n signIn?: string;\r\n signUp?: string;\r\n verifyEmail?: string;\r\n forgotPassword?: string;\r\n resetPassword?: string;\r\n };\r\n}\r\n\r\n/**\r\n * Helper component for redirecting to external auth\r\n */\r\nfunction RedirectToAuth({ baseUrl, path }: { baseUrl: string; path: string }) {\r\n useEffect(() => {\r\n const callbackUrl = `${window.location.origin}/auth/callback`;\r\n const authUrl = new URL(path, baseUrl);\r\n authUrl.searchParams.set('redirect', callbackUrl);\r\n window.location.replace(authUrl.toString());\r\n }, [baseUrl, path]);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Generates Insforge authentication redirect routes for React Router.\r\n * \r\n * Returns redirect routes for sign-in, sign-up, etc. that redirect to your deployed Insforge auth pages.\r\n * \r\n * ⚠️ **Important**: You must manually create the `/auth/callback` route in your router\r\n * to handle authentication callbacks. See documentation for details.\r\n * \r\n * @param config - Configuration for Insforge routes\r\n * @returns Array of RouteObject for React Router (redirect routes only)\r\n * \r\n * @example\r\n * ```tsx\r\n * import { createBrowserRouter } from 'react-router-dom';\r\n * import { getInsforgeRoutes } from '@insforge/react/router';\r\n * import { InsforgeCallback } from '@insforge/react';\r\n * \r\n * const router = createBrowserRouter([\r\n * {\r\n * path: '/',\r\n * element: <Layout />,\r\n * children: [\r\n * { index: true, element: <Home /> },\r\n * // ✅ Required: Manually create callback route\r\n * { path: 'auth/callback', element: <AuthCallback /> },\r\n * { path: 'dashboard', element: <Dashboard /> }\r\n * ]\r\n * },\r\n * // Add redirect routes (sign-in, sign-up, etc.)\r\n * ...getInsforgeRoutes({\r\n * baseUrl: 'https://your-backend.com',\r\n * builtInAuth: true\r\n * })\r\n * ]);\r\n * \r\n * // src/pages/AuthCallback.tsx\r\n * function AuthCallback() {\r\n * return <InsforgeCallback redirectTo=\"/dashboard\" />;\r\n * }\r\n * ```\r\n * \r\n * @example\r\n * ```tsx\r\n * // Custom paths for redirect routes\r\n * ...getInsforgeRoutes({\r\n * baseUrl: 'https://your-backend.com',\r\n * builtInAuth: true,\r\n * paths: {\r\n * signIn: '/login',\r\n * signUp: '/register'\r\n * }\r\n * })\r\n * ```\r\n */\r\nexport function getInsforgeRoutes(config: GetInsforgeRoutesConfig): RouteObject[] {\r\n const {\r\n baseUrl,\r\n builtInAuth = true,\r\n paths = {},\r\n } = config;\r\n\r\n const {\r\n signIn = '/sign-in',\r\n signUp = '/sign-up',\r\n verifyEmail = '/verify-email',\r\n forgotPassword = '/forgot-password',\r\n resetPassword = '/reset-password',\r\n } = paths;\r\n\r\n const routes: RouteObject[] = [];\r\n\r\n // Only add redirect routes if using built-in auth\r\n if (builtInAuth) {\r\n routes.push(\r\n {\r\n path: signIn,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/sign-in\" />,\r\n },\r\n {\r\n path: signUp,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/sign-up\" />,\r\n },\r\n {\r\n path: verifyEmail,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/verify-email\" />,\r\n },\r\n {\r\n path: forgotPassword,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/forgot-password\" />,\r\n },\r\n {\r\n path: resetPassword,\r\n element: <RedirectToAuth baseUrl={baseUrl} path=\"/auth/reset-password\" />,\r\n }\r\n );\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n"]}
package/dist/router.mjs CHANGED
@@ -1,104 +1,6 @@
1
- import { createContext, useEffect, useRef, useContext } from 'react';
2
- import '@insforge/sdk';
3
- import { jsx, jsxs } from 'react/jsx-runtime';
1
+ import { useEffect } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
4
3
 
5
- var InsforgeContext = createContext(
6
- void 0
7
- );
8
- function useInsforge() {
9
- const context = useContext(InsforgeContext);
10
- if (!context) {
11
- throw new Error("useInsforge must be used within InsforgeProvider");
12
- }
13
- return context;
14
- }
15
- function InsforgeCallback({
16
- redirectTo,
17
- onSuccess,
18
- onError,
19
- loadingComponent,
20
- onRedirect
21
- }) {
22
- const isProcessingRef = useRef(false);
23
- const { handleAuthCallback } = useInsforge();
24
- useEffect(() => {
25
- const processCallback = async () => {
26
- if (isProcessingRef.current) return;
27
- isProcessingRef.current = true;
28
- const searchParams = new URLSearchParams(window.location.search);
29
- const error = searchParams.get("error");
30
- if (error) {
31
- if (onError) {
32
- onError(error);
33
- } else {
34
- const errorUrl = "/?error=" + encodeURIComponent(error);
35
- if (onRedirect) {
36
- onRedirect(errorUrl);
37
- } else {
38
- window.location.href = errorUrl;
39
- }
40
- }
41
- return;
42
- }
43
- const accessToken = searchParams.get("access_token") || searchParams.get("auth_token");
44
- const userId = searchParams.get("user_id");
45
- const email = searchParams.get("email");
46
- const name = searchParams.get("name");
47
- if (!accessToken) {
48
- const errorMsg = "no_token";
49
- if (onError) {
50
- onError(errorMsg);
51
- } else {
52
- const errorUrl = "/?error=" + encodeURIComponent(errorMsg);
53
- if (onRedirect) {
54
- onRedirect(errorUrl);
55
- } else {
56
- window.location.href = errorUrl;
57
- }
58
- }
59
- return;
60
- }
61
- const result = await handleAuthCallback({
62
- accessToken,
63
- userId: userId || void 0,
64
- email: email || void 0,
65
- name: name || void 0
66
- });
67
- if (!result.success) {
68
- const errorMsg = result.error || "authentication_failed";
69
- if (onError) {
70
- onError(errorMsg);
71
- } else {
72
- const errorUrl = "/?error=" + encodeURIComponent(errorMsg);
73
- if (onRedirect) {
74
- onRedirect(errorUrl);
75
- } else {
76
- window.location.href = errorUrl;
77
- }
78
- }
79
- return;
80
- }
81
- window.history.replaceState({}, "", window.location.pathname);
82
- if (onSuccess) {
83
- onSuccess();
84
- }
85
- const destination = redirectTo || sessionStorage.getItem("auth_destination") || sessionStorage.getItem("oauth_final_destination") || "/";
86
- sessionStorage.removeItem("auth_destination");
87
- sessionStorage.removeItem("oauth_final_destination");
88
- if (onRedirect) {
89
- onRedirect(destination);
90
- } else {
91
- window.location.href = destination;
92
- }
93
- };
94
- processCallback();
95
- }, [handleAuthCallback, redirectTo, onSuccess, onError, onRedirect]);
96
- const defaultLoading = /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
97
- /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold mb-4", children: "Completing authentication..." }),
98
- /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto" })
99
- ] }) });
100
- return loadingComponent || defaultLoading;
101
- }
102
4
  function RedirectToAuth({ baseUrl, path }) {
103
5
  useEffect(() => {
104
6
  const callbackUrl = `${window.location.origin}/auth/callback`;
@@ -119,16 +21,9 @@ function getInsforgeRoutes(config) {
119
21
  signUp = "/sign-up",
120
22
  verifyEmail = "/verify-email",
121
23
  forgotPassword = "/forgot-password",
122
- resetPassword = "/reset-password",
123
- callback = "/auth/callback"
24
+ resetPassword = "/reset-password"
124
25
  } = paths;
125
- const routes = [
126
- // Always include callback route
127
- {
128
- path: callback,
129
- element: /* @__PURE__ */ jsx(InsforgeCallback, {})
130
- }
131
- ];
26
+ const routes = [];
132
27
  if (builtInAuth) {
133
28
  routes.push(
134
29
  {