@insforge/react 0.4.5 → 0.4.7

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/index.d.cts CHANGED
@@ -8,7 +8,7 @@ import { InsforgeUser, OAuthProvider, OAuthProviderConfig } from './types.cjs';
8
8
  export { AuthConfig, EmailVerificationMethod } from './types.cjs';
9
9
  import { CreateSessionResponse, CreateUserResponse, ResetPasswordResponse, GetPublicAuthConfigResponse } from '@insforge/shared-schemas';
10
10
  export { useAuth, usePublicAuthConfig, useUser } from './hooks.cjs';
11
- export { checkPasswordStrength, createPasswordSchema, emailSchema, passwordSchema, validateEmail, validatePassword } from './lib.cjs';
11
+ export { checkPasswordStrength, createPasswordSchema, emailSchema, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword } from './lib.cjs';
12
12
  export { getInsforgeRoutes } from './router.cjs';
13
13
  import 'zod';
14
14
  import 'react-router-dom';
@@ -69,6 +69,11 @@ interface InsforgeContextValue {
69
69
  interface InsforgeProviderProps {
70
70
  children: ReactNode;
71
71
  baseUrl: string;
72
+ /**
73
+ * URL to redirect to after successful sign in (when token is detected in URL)
74
+ * @default '/'
75
+ */
76
+ afterSignInUrl?: string;
72
77
  onAuthChange?: (user: InsforgeUser | null) => void;
73
78
  onSignIn?: (authToken: string) => Promise<void>;
74
79
  onSignOut?: () => Promise<void>;
@@ -86,7 +91,10 @@ interface InsforgeProviderProps {
86
91
  *
87
92
  * export default function App() {
88
93
  * return (
89
- * <InsforgeProvider baseUrl={process.env.VITE_INSFORGE_BASE_URL}>
94
+ * <InsforgeProvider
95
+ * baseUrl={process.env.VITE_INSFORGE_BASE_URL}
96
+ * afterSignInUrl="/dashboard"
97
+ * >
90
98
  * {children}
91
99
  * </InsforgeProvider>
92
100
  * );
@@ -109,7 +117,7 @@ interface InsforgeProviderProps {
109
117
  * </InsforgeProvider>
110
118
  * ```
111
119
  */
112
- declare function InsforgeProvider({ children, baseUrl, onAuthChange, onSignIn, onSignOut, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
120
+ declare function InsforgeProvider({ children, baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
113
121
  /**
114
122
  * Hook to access Insforge context
115
123
  *
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ import { InsforgeUser, OAuthProvider, OAuthProviderConfig } from './types.js';
8
8
  export { AuthConfig, EmailVerificationMethod } from './types.js';
9
9
  import { CreateSessionResponse, CreateUserResponse, ResetPasswordResponse, GetPublicAuthConfigResponse } from '@insforge/shared-schemas';
10
10
  export { useAuth, usePublicAuthConfig, useUser } from './hooks.js';
11
- export { checkPasswordStrength, createPasswordSchema, emailSchema, passwordSchema, validateEmail, validatePassword } from './lib.js';
11
+ export { checkPasswordStrength, createPasswordSchema, emailSchema, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword } from './lib.js';
12
12
  export { getInsforgeRoutes } from './router.js';
13
13
  import 'zod';
14
14
  import 'react-router-dom';
@@ -69,6 +69,11 @@ interface InsforgeContextValue {
69
69
  interface InsforgeProviderProps {
70
70
  children: ReactNode;
71
71
  baseUrl: string;
72
+ /**
73
+ * URL to redirect to after successful sign in (when token is detected in URL)
74
+ * @default '/'
75
+ */
76
+ afterSignInUrl?: string;
72
77
  onAuthChange?: (user: InsforgeUser | null) => void;
73
78
  onSignIn?: (authToken: string) => Promise<void>;
74
79
  onSignOut?: () => Promise<void>;
@@ -86,7 +91,10 @@ interface InsforgeProviderProps {
86
91
  *
87
92
  * export default function App() {
88
93
  * return (
89
- * <InsforgeProvider baseUrl={process.env.VITE_INSFORGE_BASE_URL}>
94
+ * <InsforgeProvider
95
+ * baseUrl={process.env.VITE_INSFORGE_BASE_URL}
96
+ * afterSignInUrl="/dashboard"
97
+ * >
90
98
  * {children}
91
99
  * </InsforgeProvider>
92
100
  * );
@@ -109,7 +117,7 @@ interface InsforgeProviderProps {
109
117
  * </InsforgeProvider>
110
118
  * ```
111
119
  */
112
- declare function InsforgeProvider({ children, baseUrl, onAuthChange, onSignIn, onSignOut, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
120
+ declare function InsforgeProvider({ children, baseUrl, afterSignInUrl, onAuthChange, onSignIn, onSignOut, }: InsforgeProviderProps): react_jsx_runtime.JSX.Element;
113
121
  /**
114
122
  * Hook to access Insforge context
115
123
  *
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
12
12
  }
13
13
  }
14
14
 
15
- import { createContext, useState, useRef, useCallback, useEffect, useContext } from 'react';
15
+ import { createContext, useState, useRef, useCallback, useEffect, useContext, useMemo } from 'react';
16
16
  import { useSearchParams } from 'react-router-dom';
17
17
  import { createClient } from '@insforge/sdk';
18
18
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -23,6 +23,7 @@ var InsforgeContext = createContext(void 0);
23
23
  function InsforgeProvider({
24
24
  children,
25
25
  baseUrl,
26
+ afterSignInUrl = "/",
26
27
  onAuthChange,
27
28
  onSignIn,
28
29
  onSignOut
@@ -30,6 +31,7 @@ function InsforgeProvider({
30
31
  const [user, setUser] = useState(null);
31
32
  const [isLoaded, setIsLoaded] = useState(false);
32
33
  const refreshIntervalRef = useRef(null);
34
+ const hasProcessedCallbackRef = useRef(false);
33
35
  const [insforge] = useState(() => createClient({ baseUrl }));
34
36
  const loadAuthState = useCallback(async () => {
35
37
  try {
@@ -109,6 +111,22 @@ function InsforgeProvider({
109
111
  }
110
112
  };
111
113
  }, [loadAuthState]);
114
+ useEffect(() => {
115
+ if (!isLoaded || hasProcessedCallbackRef.current) {
116
+ return;
117
+ }
118
+ const searchParams = new URLSearchParams(window.location.search);
119
+ const accessToken = searchParams.get("access_token");
120
+ if (accessToken && !!user) {
121
+ hasProcessedCallbackRef.current = true;
122
+ const url = new URL(window.location.href);
123
+ url.search = "";
124
+ window.history.replaceState({}, "", url.toString());
125
+ setTimeout(() => {
126
+ window.location.href = afterSignInUrl;
127
+ }, 100);
128
+ }
129
+ }, [isLoaded, user, afterSignInUrl]);
112
130
  const getPublicAuthConfig = useCallback(async () => {
113
131
  try {
114
132
  const result = await insforge.auth.getPublicAuthConfig();
@@ -540,6 +558,28 @@ function createRequirements(config) {
540
558
  }
541
559
  return requirements;
542
560
  }
561
+
562
+ // src/lib/path-utils.ts
563
+ function resolveAuthPath(targetPath) {
564
+ if (typeof window === "undefined") {
565
+ return targetPath;
566
+ }
567
+ const currentPath = window.location.pathname;
568
+ if (currentPath.startsWith("/auth/")) {
569
+ if (targetPath.startsWith("/auth/")) {
570
+ return targetPath;
571
+ }
572
+ return `/auth${targetPath}`;
573
+ }
574
+ return targetPath;
575
+ }
576
+ function resolveAuthUrl(targetPath, searchParams) {
577
+ const resolvedPath = resolveAuthPath(targetPath);
578
+ if (!searchParams || searchParams.toString() === "") {
579
+ return resolvedPath;
580
+ }
581
+ return `${resolvedPath}?${searchParams.toString()}`;
582
+ }
543
583
  function AuthPasswordField({
544
584
  label,
545
585
  id,
@@ -552,6 +592,10 @@ function AuthPasswordField({
552
592
  }) {
553
593
  const [showPassword, setShowPassword] = useState(false);
554
594
  const [showStrength, setShowStrength] = useState(false);
595
+ const resolvedForgotPasswordHref = useMemo(
596
+ () => forgotPasswordLink ? resolveAuthPath(forgotPasswordLink.href) : void 0,
597
+ [forgotPasswordLink]
598
+ );
555
599
  const handleFocus = (e) => {
556
600
  if (showStrengthIndicator) {
557
601
  setShowStrength(true);
@@ -561,7 +605,7 @@ function AuthPasswordField({
561
605
  return /* @__PURE__ */ jsxs("div", { className: "if-passwordField if-internal-p5w9m7", children: [
562
606
  (label || forgotPasswordLink) && /* @__PURE__ */ jsxs("div", { className: "if-passwordField-labelRow", children: [
563
607
  /* @__PURE__ */ jsx("label", { htmlFor: id, className: "if-passwordField-label", children: label }),
564
- forgotPasswordLink && /* @__PURE__ */ jsx("a", { href: forgotPasswordLink.href, className: "if-passwordField-forgotLink", children: forgotPasswordLink.text || "Forget Password?" })
608
+ forgotPasswordLink && resolvedForgotPasswordHref && /* @__PURE__ */ jsx("a", { href: resolvedForgotPasswordHref, className: "if-passwordField-forgotLink", children: forgotPasswordLink.text || "Forget Password?" })
565
609
  ] }),
566
610
  /* @__PURE__ */ jsxs("div", { className: "if-passwordField-inputWrapper", children: [
567
611
  /* @__PURE__ */ jsx(
@@ -614,19 +658,7 @@ function AuthSubmitButton({
614
658
  }
615
659
  function AuthLink({ text, linkText, href }) {
616
660
  const [searchParams] = useSearchParams();
617
- const currentSearch = searchParams.toString();
618
- const finalHref = (() => {
619
- if (!currentSearch) {
620
- return href;
621
- }
622
- try {
623
- const url = new URL(href, window.location.origin);
624
- url.search = currentSearch;
625
- return url.pathname + url.search;
626
- } catch {
627
- return href;
628
- }
629
- })();
661
+ const finalHref = resolveAuthUrl(href, searchParams);
630
662
  return /* @__PURE__ */ jsxs("p", { className: "if-authLink if-internal-al5w9p", children: [
631
663
  text && /* @__PURE__ */ jsx("span", { className: "if-authLink-text", children: text }),
632
664
  text && " ",
@@ -1882,12 +1914,9 @@ function ForgotPassword({ onError, ...uiProps }) {
1882
1914
  const result = await resetPassword(resetToken, newPassword);
1883
1915
  if (result?.message) {
1884
1916
  setSuccess(true);
1885
- const signInUrl = new URL("/sign-in", window.location.origin);
1886
- searchParams.forEach((value, key) => {
1887
- signInUrl.searchParams.set(key, value);
1888
- });
1917
+ const signInUrl = resolveAuthUrl("/sign-in", searchParams);
1889
1918
  setTimeout(() => {
1890
- window.location.href = signInUrl.toString();
1919
+ window.location.href = signInUrl;
1891
1920
  }, 2e3);
1892
1921
  } else {
1893
1922
  const errorMessage = "Failed to reset password";
@@ -2305,23 +2334,24 @@ function Protect({
2305
2334
  onRedirect
2306
2335
  }) {
2307
2336
  const { isSignedIn, isLoaded, user } = useInsforge();
2337
+ const resolvedRedirectTo = useMemo(() => resolveAuthPath(redirectTo), [redirectTo]);
2308
2338
  useEffect(() => {
2309
2339
  if (isLoaded && !isSignedIn) {
2310
2340
  if (onRedirect) {
2311
- onRedirect(redirectTo);
2341
+ onRedirect(resolvedRedirectTo);
2312
2342
  } else {
2313
- window.location.href = redirectTo;
2343
+ window.location.href = resolvedRedirectTo;
2314
2344
  }
2315
2345
  } else if (isLoaded && isSignedIn && condition && user) {
2316
2346
  if (!condition(user)) {
2317
2347
  if (onRedirect) {
2318
- onRedirect(redirectTo);
2348
+ onRedirect(resolvedRedirectTo);
2319
2349
  } else {
2320
- window.location.href = redirectTo;
2350
+ window.location.href = resolvedRedirectTo;
2321
2351
  }
2322
2352
  }
2323
2353
  }
2324
- }, [isLoaded, isSignedIn, redirectTo, condition, user, onRedirect]);
2354
+ }, [isLoaded, isSignedIn, resolvedRedirectTo, condition, user, onRedirect]);
2325
2355
  if (!isLoaded) {
2326
2356
  return fallback || /* @__PURE__ */ jsx("div", { className: "insforge-loading", children: "Loading..." });
2327
2357
  }
@@ -2367,9 +2397,9 @@ function useUser() {
2367
2397
  }
2368
2398
  function RedirectToAuth({ baseUrl, path }) {
2369
2399
  useEffect(() => {
2370
- const callbackUrl = `${window.location.origin}/auth/callback`;
2400
+ const currentUrl = window.location.href;
2371
2401
  const authUrl = new URL(path, baseUrl);
2372
- authUrl.searchParams.set("redirect", callbackUrl);
2402
+ authUrl.searchParams.set("redirect", currentUrl);
2373
2403
  window.location.replace(authUrl.toString());
2374
2404
  }, [baseUrl, path]);
2375
2405
  return null;
@@ -2411,6 +2441,6 @@ function getInsforgeRoutes(config) {
2411
2441
  return routes;
2412
2442
  }
2413
2443
 
2414
- export { AuthBranding, AuthContainer, AuthDivider, AuthEmailVerificationStep, AuthErrorBanner, AuthFormField, AuthHeader, AuthLink, AuthOAuthButton, AuthOAuthProviders, AuthPasswordField, AuthPasswordStrengthIndicator, AuthResetPasswordVerificationStep, AuthSubmitButton, AuthVerificationCodeInput, ForgotPassword, ForgotPasswordForm, InsforgeProvider, OAUTH_PROVIDER_CONFIG, Protect, ResetPassword, ResetPasswordForm, SignIn, SignInForm, SignUp, SignUpForm, SignedIn, SignedOut, UserButton, VerifyEmail, VerifyEmailStatus, checkPasswordStrength, createPasswordSchema, emailSchema, getAllProviderConfigs, getInsforgeRoutes, getProviderConfig, passwordSchema, useAuth, useInsforge, usePublicAuthConfig, useUser, validateEmail, validatePassword };
2444
+ export { AuthBranding, AuthContainer, AuthDivider, AuthEmailVerificationStep, AuthErrorBanner, AuthFormField, AuthHeader, AuthLink, AuthOAuthButton, AuthOAuthProviders, AuthPasswordField, AuthPasswordStrengthIndicator, AuthResetPasswordVerificationStep, AuthSubmitButton, AuthVerificationCodeInput, ForgotPassword, ForgotPasswordForm, InsforgeProvider, OAUTH_PROVIDER_CONFIG, Protect, ResetPassword, ResetPasswordForm, SignIn, SignInForm, SignUp, SignUpForm, SignedIn, SignedOut, UserButton, VerifyEmail, VerifyEmailStatus, checkPasswordStrength, createPasswordSchema, emailSchema, getAllProviderConfigs, getInsforgeRoutes, getProviderConfig, passwordSchema, resolveAuthPath, resolveAuthUrl, useAuth, useInsforge, usePublicAuthConfig, useUser, validateEmail, validatePassword };
2415
2445
  //# sourceMappingURL=index.js.map
2416
2446
  //# sourceMappingURL=index.js.map