@insforge/react 1.1.1 → 1.1.2-dev.2

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
@@ -1,10 +1,10 @@
1
1
  export { ConditionalProps, ForgotPassword, ForgotPasswordProps, Protect, ProtectProps, ResetPassword, ResetPasswordProps, SignIn, SignInButton, SignInButtonProps, SignInProps, SignOutButton, SignOutButtonProps, SignUp, SignUpButton, SignUpButtonProps, SignUpProps, SignedIn, SignedOut, UserButton, UserButtonProps, UserProfileModal, UserProfileModalProps, VerifyEmail, VerifyEmailProps } from './components.cjs';
2
2
  export { ForgotPasswordForm, ForgotPasswordFormProps, ResetPasswordForm, ResetPasswordFormProps, SignInForm, SignInFormProps, SignUpForm, SignUpFormProps, VerifyEmailStatus, VerifyEmailStatusProps } from './forms.cjs';
3
- export { AuthBranding, AuthContainer, AuthContainerProps, AuthDivider, AuthDividerProps, AuthEmailVerificationStep, AuthEmailVerificationStepProps, AuthErrorBanner, AuthErrorBannerProps, AuthFormField, AuthFormFieldProps, AuthHeader, AuthHeaderProps, AuthLink, AuthLinkProps, AuthOAuthButton, AuthOAuthButtonProps, AuthOAuthProviders, AuthOAuthProvidersProps, AuthPasswordField, AuthPasswordFieldProps, AuthPasswordStrengthIndicator, AuthPasswordStrengthIndicatorProps, AuthResetPasswordVerificationStep, AuthResetPasswordVerificationStepProps, AuthSubmitButton, AuthSubmitButtonProps, AuthVerificationCodeInput, AuthVerificationCodeInputProps } from './atoms.cjs';
3
+ export { AuthBranding, AuthContainer, AuthContainerProps, AuthDivider, AuthDividerProps, AuthEmailVerificationStep, AuthErrorBanner, AuthErrorBannerProps, AuthFormField, AuthFormFieldProps, AuthHeader, AuthHeaderProps, AuthLink, AuthLinkProps, AuthOAuthButton, AuthOAuthButtonProps, AuthOAuthProviders, AuthOAuthProvidersProps, AuthPasswordField, AuthPasswordFieldProps, AuthPasswordStrengthIndicator, AuthPasswordStrengthIndicatorProps, AuthResetPasswordVerificationStep, AuthSubmitButton, AuthSubmitButtonProps, AuthVerificationCodeInput, AuthVerificationCodeInputProps } from './atoms.cjs';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import { ReactNode } from 'react';
6
6
  import { InsforgeUser, InsforgeContextValue, OAuthProvider } from '@insforge/shared';
7
- export { InsforgeContextValue, InsforgeUser, OAuthProvider } from '@insforge/shared';
7
+ export { InsforgeAuthConfig, InsforgeAuthMethods, InsforgeAuthState, InsforgeContextValue, InsforgeUser, OAuthProvider } from '@insforge/shared';
8
8
  import { InsForgeClient } from '@insforge/sdk';
9
9
  export { useAuth, usePublicAuthConfig, useUser } from './hooks.cjs';
10
10
  export { checkPasswordStrength, createPasswordSchema, emailSchema, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword } from './lib.cjs';
@@ -51,6 +51,15 @@ interface InsforgeProviderProps {
51
51
  * Uses singleton InsforgeManager to manage state across packages.
52
52
  * Context only subscribes to Manager and triggers React re-renders.
53
53
  *
54
+ * Architecture (pattern learned from Clerk):
55
+ * - InsforgeMethodsContext: Stable method references (NEVER change)
56
+ * - InsforgeAuthStateContext: Reactive auth state (changes on sign in/out)
57
+ * - InsforgeConfigContext: Static configuration values
58
+ * - InsforgeContext: Combined context for backward compatibility
59
+ *
60
+ * This architecture prevents useEffect re-runs when auth state changes,
61
+ * solving the "duplicate request" bug in components like VerifyEmail.
62
+ *
54
63
  * @example
55
64
  * ```tsx
56
65
  * // Basic usage (React/Vite)
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export { ConditionalProps, ForgotPassword, ForgotPasswordProps, Protect, ProtectProps, ResetPassword, ResetPasswordProps, SignIn, SignInButton, SignInButtonProps, SignInProps, SignOutButton, SignOutButtonProps, SignUp, SignUpButton, SignUpButtonProps, SignUpProps, SignedIn, SignedOut, UserButton, UserButtonProps, UserProfileModal, UserProfileModalProps, VerifyEmail, VerifyEmailProps } from './components.js';
2
2
  export { ForgotPasswordForm, ForgotPasswordFormProps, ResetPasswordForm, ResetPasswordFormProps, SignInForm, SignInFormProps, SignUpForm, SignUpFormProps, VerifyEmailStatus, VerifyEmailStatusProps } from './forms.js';
3
- export { AuthBranding, AuthContainer, AuthContainerProps, AuthDivider, AuthDividerProps, AuthEmailVerificationStep, AuthEmailVerificationStepProps, AuthErrorBanner, AuthErrorBannerProps, AuthFormField, AuthFormFieldProps, AuthHeader, AuthHeaderProps, AuthLink, AuthLinkProps, AuthOAuthButton, AuthOAuthButtonProps, AuthOAuthProviders, AuthOAuthProvidersProps, AuthPasswordField, AuthPasswordFieldProps, AuthPasswordStrengthIndicator, AuthPasswordStrengthIndicatorProps, AuthResetPasswordVerificationStep, AuthResetPasswordVerificationStepProps, AuthSubmitButton, AuthSubmitButtonProps, AuthVerificationCodeInput, AuthVerificationCodeInputProps } from './atoms.js';
3
+ export { AuthBranding, AuthContainer, AuthContainerProps, AuthDivider, AuthDividerProps, AuthEmailVerificationStep, AuthErrorBanner, AuthErrorBannerProps, AuthFormField, AuthFormFieldProps, AuthHeader, AuthHeaderProps, AuthLink, AuthLinkProps, AuthOAuthButton, AuthOAuthButtonProps, AuthOAuthProviders, AuthOAuthProvidersProps, AuthPasswordField, AuthPasswordFieldProps, AuthPasswordStrengthIndicator, AuthPasswordStrengthIndicatorProps, AuthResetPasswordVerificationStep, AuthSubmitButton, AuthSubmitButtonProps, AuthVerificationCodeInput, AuthVerificationCodeInputProps } from './atoms.js';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import { ReactNode } from 'react';
6
6
  import { InsforgeUser, InsforgeContextValue, OAuthProvider } from '@insforge/shared';
7
- export { InsforgeContextValue, InsforgeUser, OAuthProvider } from '@insforge/shared';
7
+ export { InsforgeAuthConfig, InsforgeAuthMethods, InsforgeAuthState, InsforgeContextValue, InsforgeUser, OAuthProvider } from '@insforge/shared';
8
8
  import { InsForgeClient } from '@insforge/sdk';
9
9
  export { useAuth, usePublicAuthConfig, useUser } from './hooks.js';
10
10
  export { checkPasswordStrength, createPasswordSchema, emailSchema, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword } from './lib.js';
@@ -51,6 +51,15 @@ interface InsforgeProviderProps {
51
51
  * Uses singleton InsforgeManager to manage state across packages.
52
52
  * Context only subscribes to Manager and triggers React re-renders.
53
53
  *
54
+ * Architecture (pattern learned from Clerk):
55
+ * - InsforgeMethodsContext: Stable method references (NEVER change)
56
+ * - InsforgeAuthStateContext: Reactive auth state (changes on sign in/out)
57
+ * - InsforgeConfigContext: Static configuration values
58
+ * - InsforgeContext: Combined context for backward compatibility
59
+ *
60
+ * This architecture prevents useEffect re-runs when auth state changes,
61
+ * solving the "duplicate request" bug in components like VerifyEmail.
62
+ *
54
63
  * @example
55
64
  * ```tsx
56
65
  * // Basic usage (React/Vite)
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
15
15
  import * as React2 from 'react';
16
16
  import { createContext, forwardRef, useContext, useState, useMemo, useEffect, useRef, useCallback, isValidElement, cloneElement } from 'react';
17
17
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
18
- import { InsforgeContext } from '@insforge/shared/react';
18
+ import { InsforgeMethodsContext, InsforgeConfigContext, InsforgeAuthStateContext, InsforgeContext } from '@insforge/shared/react';
19
19
  import { AlertTriangle, Check, EyeOff, Eye, Loader2, CircleCheck, X, User, LogOut } from 'lucide-react';
20
20
  import { z } from 'zod';
21
21
  import { createPortal } from 'react-dom';
@@ -545,8 +545,8 @@ var InsforgeManager = class _InsforgeManager {
545
545
  this.listeners.forEach((listener) => listener(state));
546
546
  }
547
547
  // Load auth state
548
- // This loads the FULL user data from SDK (including complete profile)
549
- // Called after hydration to get complete user information beyond what's in cookies
548
+ // Gets session and user data from getCurrentSession()
549
+ // Called after hydration to restore authentication state
550
550
  async loadAuthState() {
551
551
  try {
552
552
  const {
@@ -570,30 +570,18 @@ var InsforgeManager = class _InsforgeManager {
570
570
  }
571
571
  }
572
572
  }
573
- const userResult = await this.sdk.auth.getCurrentUser();
574
- if (userResult.data) {
575
- const userData = {
576
- id: userResult.data.user.id,
577
- email: userResult.data.user.email,
578
- profile: userResult.data.user.profile
579
- };
580
- this.user = userData;
581
- if (this.config.onAuthChange) {
582
- this.config.onAuthChange(userData);
583
- }
584
- this.isLoaded = true;
585
- this.notifyListeners();
586
- return { success: true };
587
- } else {
588
- this.user = null;
589
- if (this.config.onAuthChange) {
590
- this.config.onAuthChange(null);
591
- }
592
- this.isLoaded = true;
593
- this.notifyListeners();
594
- const errorMessage = userResult.error?.message ?? "failed_to_get_user";
595
- return { success: false, error: errorMessage };
573
+ const userData = {
574
+ id: session.user.id,
575
+ email: session.user.email,
576
+ profile: session.user.profile
577
+ };
578
+ this.user = userData;
579
+ if (this.config.onAuthChange) {
580
+ this.config.onAuthChange(userData);
596
581
  }
582
+ this.isLoaded = true;
583
+ this.notifyListeners();
584
+ return { success: true };
597
585
  } catch (error) {
598
586
  this.user = null;
599
587
  if (this.config.onAuthChange) {
@@ -650,8 +638,12 @@ var InsforgeManager = class _InsforgeManager {
650
638
  };
651
639
  }
652
640
  }
653
- async signUp(email, password) {
654
- const sdkResult = await this.sdk.auth.signUp({ email, password });
641
+ async signUp(email, password, options) {
642
+ const sdkResult = await this.sdk.auth.signUp({
643
+ email,
644
+ password,
645
+ options
646
+ });
655
647
  if (sdkResult.data) {
656
648
  if (sdkResult.data.requireEmailVerification) {
657
649
  return sdkResult.data;
@@ -723,8 +715,11 @@ var InsforgeManager = class _InsforgeManager {
723
715
  async reloadAuth() {
724
716
  return await this.loadAuthState();
725
717
  }
726
- async sendVerificationEmail(email) {
727
- const sdkResult = await this.sdk.auth.sendVerificationEmail({ email });
718
+ async resendVerificationEmail(email, options) {
719
+ const sdkResult = await this.sdk.auth.resendVerificationEmail({
720
+ email,
721
+ options
722
+ });
728
723
  return sdkResult.data;
729
724
  }
730
725
  async sendResetPasswordEmail(email) {
@@ -2191,34 +2186,54 @@ function InsforgeProviderCore({
2191
2186
  unsubscribe();
2192
2187
  };
2193
2188
  }, [manager]);
2194
- const contextValue = useMemo(
2189
+ const stableMethods = useMemo(
2195
2190
  () => ({
2196
- // State from Manager
2197
- user: state.user,
2198
- userId: state.userId,
2199
- isLoaded: state.isLoaded,
2200
- isSignedIn: state.isSignedIn,
2201
- // Methods delegated to Manager
2202
2191
  setUser: (user) => manager.setUser(user),
2203
2192
  signIn: (email, password) => manager.signIn(email, password),
2204
- signUp: (email, password) => manager.signUp(email, password),
2193
+ signUp: (email, password, options) => manager.signUp(email, password, options),
2205
2194
  signOut: () => manager.signOut(),
2206
2195
  updateUser: (data) => manager.updateUser(data),
2207
2196
  reloadAuth: () => manager.reloadAuth(),
2208
- sendVerificationEmail: (email) => manager.sendVerificationEmail(email),
2197
+ resendVerificationEmail: (email, options) => manager.resendVerificationEmail(email, options),
2209
2198
  sendResetPasswordEmail: (email) => manager.sendResetPasswordEmail(email),
2210
2199
  resetPassword: (token2, newPassword) => manager.resetPassword(token2, newPassword),
2211
2200
  verifyEmail: (otp, email) => manager.verifyEmail(otp, email),
2212
2201
  exchangeResetPasswordToken: (email, code) => manager.exchangeResetPasswordToken(email, code),
2213
2202
  loginWithOAuth: (provider, redirectTo) => manager.loginWithOAuth(provider, redirectTo),
2214
- getPublicAuthConfig: () => manager.getPublicAuthConfig(),
2215
- // Config
2203
+ getPublicAuthConfig: () => manager.getPublicAuthConfig()
2204
+ }),
2205
+ [manager]
2206
+ // Only depends on manager (stable)
2207
+ );
2208
+ const stableConfig = useMemo(
2209
+ () => ({
2216
2210
  baseUrl: manager.getConfig().client.getHttpClient().baseUrl,
2217
2211
  afterSignInUrl: manager.getConfig().afterSignInUrl || "/"
2218
2212
  }),
2219
- [state, manager]
2213
+ [manager]
2214
+ // Only depends on manager (stable)
2215
+ );
2216
+ const authState = useMemo(
2217
+ () => ({
2218
+ user: state.user,
2219
+ userId: state.userId,
2220
+ isLoaded: state.isLoaded,
2221
+ isSignedIn: state.isSignedIn
2222
+ }),
2223
+ [state.user, state.userId, state.isLoaded, state.isSignedIn]
2224
+ );
2225
+ const contextValue = useMemo(
2226
+ () => ({
2227
+ // Reactive state
2228
+ ...authState,
2229
+ // Stable methods (references don't change!)
2230
+ ...stableMethods,
2231
+ // Stable config
2232
+ ...stableConfig
2233
+ }),
2234
+ [authState, stableMethods, stableConfig]
2220
2235
  );
2221
- return /* @__PURE__ */ jsx(InsforgeContext.Provider, { value: contextValue, children });
2236
+ return /* @__PURE__ */ jsx(InsforgeMethodsContext.Provider, { value: stableMethods, children: /* @__PURE__ */ jsx(InsforgeConfigContext.Provider, { value: stableConfig, children: /* @__PURE__ */ jsx(InsforgeAuthStateContext.Provider, { value: authState, children: /* @__PURE__ */ jsx(InsforgeContext.Provider, { value: contextValue, children }) }) }) });
2222
2237
  }
2223
2238
  function InsforgeProvider(props) {
2224
2239
  return /* @__PURE__ */ jsx(StyleProvider, { children: /* @__PURE__ */ jsx(NavigationProvider, { adapter: BrowserNavigationAdapter, children: /* @__PURE__ */ jsx(InsforgeProviderCore, { ...props }) }) });
@@ -2238,7 +2253,7 @@ function useInsforge() {
2238
2253
  signOut: () => Promise.resolve(),
2239
2254
  updateUser: () => Promise.resolve({ error: "SSR mode" }),
2240
2255
  reloadAuth: () => Promise.resolve({ success: false, error: "SSR mode" }),
2241
- sendVerificationEmail: () => Promise.resolve(null),
2256
+ resendVerificationEmail: () => Promise.resolve(null),
2242
2257
  sendResetPasswordEmail: () => Promise.resolve(null),
2243
2258
  resetPassword: () => Promise.resolve(null),
2244
2259
  verifyEmail: () => Promise.resolve({ error: "SSR mode" }),
@@ -3831,7 +3846,7 @@ function AuthEmailVerificationStep({
3831
3846
  onVerifyCode,
3832
3847
  emailSent = false
3833
3848
  }) {
3834
- const { sendVerificationEmail } = useInsforge();
3849
+ const { resendVerificationEmail } = useInsforge();
3835
3850
  const [resendDisabled, setResendDisabled] = useState(emailSent ? true : false);
3836
3851
  const [resendCountdown, setResendCountdown] = useState(emailSent ? 60 : 0);
3837
3852
  const [isSending, setIsSending] = useState(false);
@@ -3858,7 +3873,7 @@ function AuthEmailVerificationStep({
3858
3873
  setResendCountdown(60);
3859
3874
  setIsSending(true);
3860
3875
  try {
3861
- await sendVerificationEmail(email);
3876
+ await resendVerificationEmail(email);
3862
3877
  } catch {
3863
3878
  setResendDisabled(false);
3864
3879
  setResendCountdown(0);
@@ -4389,7 +4404,7 @@ function checkPasswordStrength(password) {
4389
4404
  }
4390
4405
  return { score, feedback };
4391
4406
  }
4392
- function SignUp({ onError, ...uiProps }) {
4407
+ function SignUp({ onError, emailRedirectTo, ...uiProps }) {
4393
4408
  const { signUp, verifyEmail, loginWithOAuth } = useInsforge();
4394
4409
  const { authConfig } = usePublicAuthConfig();
4395
4410
  const [email, setEmail] = useState("");
@@ -4431,7 +4446,7 @@ function SignUp({ onError, ...uiProps }) {
4431
4446
  return;
4432
4447
  }
4433
4448
  try {
4434
- const result = await signUp(emailValidation.data, password);
4449
+ const result = await signUp(emailValidation.data, password, { emailRedirectTo });
4435
4450
  if ("error" in result) {
4436
4451
  throw new Error(result.error);
4437
4452
  }