@umituz/react-native-auth 3.6.75 → 3.6.77

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.
@@ -22,11 +22,12 @@ export interface AuthTransitionResult {
22
22
  */
23
23
  export function useAuthTransitions(
24
24
  state: AuthTransitionState,
25
- onTransition?: (result: AuthTransitionResult) => void
25
+ onTransition?: (result: AuthTransitionResult) => (() => void) | void
26
26
  ): void {
27
27
  const prevIsAuthenticatedRef = useRef(state.isAuthenticated);
28
28
  const prevIsAnonymousRef = useRef(state.isAnonymous);
29
29
  const prevIsVisibleRef = useRef(state.isVisible);
30
+ const cleanupRef = useRef<(() => void) | null>(null);
30
31
 
31
32
  useEffect(() => {
32
33
  const justAuthenticated = !prevIsAuthenticatedRef.current && state.isAuthenticated;
@@ -41,11 +42,21 @@ export function useAuthTransitions(
41
42
  shouldClose,
42
43
  };
43
44
 
44
- onTransition?.(result);
45
+ // Call previous cleanup before running new transition
46
+ cleanupRef.current?.();
47
+
48
+ const cleanup = onTransition?.(result);
49
+ cleanupRef.current = cleanup ?? null;
45
50
 
46
51
  prevIsAuthenticatedRef.current = state.isAuthenticated;
47
52
  prevIsVisibleRef.current = state.isVisible;
48
53
  prevIsAnonymousRef.current = state.isAnonymous;
54
+
55
+ // Return cleanup function for useEffect
56
+ return () => {
57
+ cleanupRef.current?.();
58
+ cleanupRef.current = null;
59
+ };
49
60
  }, [state.isAuthenticated, state.isVisible, state.isAnonymous, onTransition]);
50
61
  }
51
62
 
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Shared Form Field Hook
3
+ * Provides reusable form field state management with automatic error clearing
4
+ */
5
+
6
+ import { useCallback, useState } from "react";
7
+
8
+ export interface UseFormFieldOptions {
9
+ clearLocalError?: () => void;
10
+ fieldsToClear?: string[];
11
+ }
12
+
13
+ export interface UseFormFieldResult {
14
+ value: string;
15
+ error: string | null;
16
+ setValue: (value: string) => void;
17
+ setError: (error: string | null) => void;
18
+ clearError: () => void;
19
+ handleChange: (text: string) => void;
20
+ }
21
+
22
+ /**
23
+ * Hook for managing a single form field with automatic error clearing
24
+ * @param initialValue - Initial field value
25
+ * @param setError - Function to set field error in parent state
26
+ * @param options - Additional options
27
+ * @returns Field state and handlers
28
+ */
29
+ export function useFormField(
30
+ initialValue: string,
31
+ setError: (error: string | null) => void,
32
+ options?: UseFormFieldOptions
33
+ ): UseFormFieldResult {
34
+ const [value, setValue] = useState(initialValue);
35
+ const [error, setLocalError] = useState<string | null>(null);
36
+
37
+ const clearError = useCallback(() => {
38
+ setLocalError(null);
39
+ setError(null);
40
+ options?.clearLocalError?.();
41
+ }, [setError, options]);
42
+
43
+ const handleChange = useCallback(
44
+ (text: string) => {
45
+ setValue(text);
46
+ if (error || options?.clearLocalError) {
47
+ clearError();
48
+ }
49
+ },
50
+ [error, options, clearError]
51
+ );
52
+
53
+ return {
54
+ value,
55
+ error,
56
+ setValue,
57
+ setError: setLocalError,
58
+ clearError,
59
+ handleChange,
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Hook for managing multiple form fields
65
+ * @param initialFields - Initial field values
66
+ * @param setFieldErrors - Function to set field errors in parent state
67
+ * @param options - Additional options
68
+ * @returns Field states and handlers
69
+ */
70
+ export function useFormFields<T extends Record<string, string>>(
71
+ initialFields: T,
72
+ setFieldErrors: ((errors: Partial<Record<string, string>> | ((prev: Partial<Record<string, string>>) => Partial<Record<string, string>>)) => void) | null,
73
+ options?: UseFormFieldOptions
74
+ ) {
75
+ type FieldKey = keyof T;
76
+
77
+ const [fields, setFields] = useState<T>(initialFields);
78
+
79
+ const updateField = useCallback(
80
+ (field: FieldKey, value: string) => {
81
+ setFields((prev) => ({ ...prev, [field]: value }));
82
+ // Note: setFieldErrors is handled externally by form hooks
83
+ options?.clearLocalError?.();
84
+ },
85
+ [options]
86
+ );
87
+
88
+ const resetFields = useCallback(() => {
89
+ setFields(initialFields);
90
+ }, [initialFields]);
91
+
92
+ return {
93
+ fields,
94
+ updateField,
95
+ resetFields,
96
+ };
97
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Password Validation Hook
3
+ * Provides reusable password validation logic with requirements tracking
4
+ */
5
+
6
+ import { useMemo } from "react";
7
+ import {
8
+ validatePasswordForRegister,
9
+ validatePasswordConfirmation,
10
+ type PasswordRequirements,
11
+ type ValidationResult,
12
+ } from "../../../infrastructure/utils/AuthValidation";
13
+ import type { PasswordConfig } from "../../../domain/value-objects/AuthConfig";
14
+
15
+ export interface UsePasswordValidationResult {
16
+ passwordRequirements: PasswordRequirements;
17
+ passwordsMatch: boolean;
18
+ isValid: boolean;
19
+ confirmationError: string | null;
20
+ }
21
+
22
+ export interface UsePasswordValidationOptions {
23
+ passwordConfig?: PasswordConfig;
24
+ }
25
+
26
+ /**
27
+ * Hook for password validation with requirements tracking
28
+ * @param password - Password value
29
+ * @param confirmPassword - Confirm password value
30
+ * @param options - Validation options
31
+ * @returns Password validation state
32
+ */
33
+ export function usePasswordValidation(
34
+ password: string,
35
+ confirmPassword: string,
36
+ options?: UsePasswordValidationOptions
37
+ ): UsePasswordValidationResult {
38
+ const config = options?.passwordConfig;
39
+
40
+ const passwordRequirements = useMemo((): PasswordRequirements => {
41
+ if (!password || !config) {
42
+ return { hasMinLength: false };
43
+ }
44
+ const result = validatePasswordForRegister(password, config);
45
+ return result.requirements;
46
+ }, [password, config]);
47
+
48
+ const passwordsMatch = useMemo(() => {
49
+ if (!password || !confirmPassword) {
50
+ return false;
51
+ }
52
+ return password === confirmPassword;
53
+ }, [password, confirmPassword]);
54
+
55
+ const confirmationError = useMemo(() => {
56
+ if (!confirmPassword) {
57
+ return null;
58
+ }
59
+ const result = validatePasswordConfirmation(password, confirmPassword);
60
+ return result.error ?? null;
61
+ }, [password, confirmPassword]);
62
+
63
+ const isValid = useMemo(() => {
64
+ return passwordRequirements.hasMinLength && passwordsMatch;
65
+ }, [passwordRequirements, passwordsMatch]);
66
+
67
+ return {
68
+ passwordRequirements,
69
+ passwordsMatch,
70
+ isValid,
71
+ confirmationError,
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Hook for login password validation (simpler, no requirements)
77
+ * @param password - Password value
78
+ * @returns Validation result
79
+ */
80
+ export function useLoginPasswordValidation(password: string): ValidationResult {
81
+ return useMemo(() => {
82
+ if (!password || password.length === 0) {
83
+ return { isValid: false, error: "auth.validation.passwordRequired" };
84
+ }
85
+ return { isValid: true };
86
+ }, [password]);
87
+ }
@@ -32,52 +32,29 @@ export function getAuthErrorLocalizationKey(error: unknown): string {
32
32
  };
33
33
 
34
34
  // Check error name for specific error types
35
- if (error.name === "AuthInvalidEmailError") {
36
- return "auth.errors.invalidEmail";
37
- }
38
- if (error.name === "AuthWeakPasswordError") {
39
- return "auth.errors.weakPassword";
40
- }
41
- if (error.name === "AuthUserNotFoundError") {
42
- return "auth.errors.userNotFound";
43
- }
44
- if (error.name === "AuthWrongPasswordError") {
45
- return "auth.errors.wrongPassword";
46
- }
47
- if (error.name === "AuthEmailAlreadyInUseError") {
48
- return "auth.errors.emailAlreadyInUse";
49
- }
50
- if (error.name === "AuthNetworkError") {
51
- return "auth.errors.networkError";
52
- }
53
- if (error.name === "AuthConfigurationError") {
54
- return "auth.errors.configurationError";
55
- }
56
- if (error.name === "AuthInitializationError") {
57
- return "auth.errors.authNotInitialized";
35
+ const errorNameMap: Record<string, string> = {
36
+ AuthInvalidEmailError: "auth.errors.invalidEmail",
37
+ AuthWeakPasswordError: "auth.errors.weakPassword",
38
+ AuthUserNotFoundError: "auth.errors.userNotFound",
39
+ AuthWrongPasswordError: "auth.errors.wrongPassword",
40
+ AuthEmailAlreadyInUseError: "auth.errors.emailAlreadyInUse",
41
+ AuthNetworkError: "auth.errors.networkError",
42
+ AuthConfigurationError: "auth.errors.configurationError",
43
+ AuthInitializationError: "auth.errors.authNotInitialized",
44
+ };
45
+
46
+ // First check by error name (most specific)
47
+ const mappedByName = errorNameMap[error.name];
48
+ if (mappedByName) {
49
+ return mappedByName;
58
50
  }
59
51
 
60
- // Use code if available
52
+ // Then check by error code
61
53
  if (code && errorCodeMap[code]) {
62
54
  return errorCodeMap[code];
63
55
  }
64
56
 
65
- // Check error message for specific patterns
66
- const message = error.message.toLowerCase();
67
- if (message.includes("too many requests")) {
68
- return "auth.errors.tooManyRequests";
69
- }
70
- if (message.includes("user account has been disabled") || message.includes("user disabled")) {
71
- return "auth.errors.userDisabled";
72
- }
73
- if (message.includes("not properly configured") || message.includes("configuration")) {
74
- return "auth.errors.configurationError";
75
- }
76
- if (message.includes("not enabled") || message.includes("operation not allowed")) {
77
- return "auth.errors.operationNotAllowed";
78
- }
79
-
80
- // Default to unknown error
57
+ // Default to unknown error - don't leak system information through error messages
81
58
  return "auth.errors.unknownError";
82
59
  }
83
60
 
@@ -20,34 +20,24 @@ export interface SocialAuthConfig {
20
20
  }
21
21
 
22
22
  /**
23
- * Hook for managing social auth loading states
23
+ * Hook for managing a single social auth provider's loading state
24
+ * @returns Loading state and handler creator
24
25
  */
25
26
  export function useSocialAuthLoading() {
26
27
  const [googleLoading, setGoogleLoading] = useState(false);
27
28
  const [appleLoading, setAppleLoading] = useState(false);
28
29
 
29
- const createGoogleHandler = useCallback(
30
- (handler: () => Promise<void>) => {
30
+ const createHandler = useCallback(
31
+ (setter: (loading: boolean) => void, signInHandler?: () => Promise<void>) => {
31
32
  return async () => {
32
- setGoogleLoading(true);
33
- try {
34
- await handler();
35
- } finally {
36
- setGoogleLoading(false);
33
+ if (!signInHandler) {
34
+ throw new Error("Sign-in handler not available");
37
35
  }
38
- };
39
- },
40
- []
41
- );
42
-
43
- const createAppleHandler = useCallback(
44
- (handler: () => Promise<void>) => {
45
- return async () => {
46
- setAppleLoading(true);
36
+ setter(true);
47
37
  try {
48
- await handler();
38
+ await signInHandler();
49
39
  } finally {
50
- setAppleLoading(false);
40
+ setter(false);
51
41
  }
52
42
  };
53
43
  },
@@ -59,8 +49,7 @@ export function useSocialAuthLoading() {
59
49
  appleLoading,
60
50
  setGoogleLoading,
61
51
  setAppleLoading,
62
- createGoogleHandler,
63
- createAppleHandler,
52
+ createHandler,
64
53
  };
65
54
  }
66
55
 
@@ -86,21 +75,15 @@ export function determineEnabledProviders(
86
75
  }
87
76
 
88
77
  /**
89
- * Create social auth handlers
78
+ * Select the appropriate sign-in handler from external and internal options
79
+ * @param externalHandler - External handler provided by parent
80
+ * @param internalHandler - Internal handler from auth hook
81
+ * @returns The selected handler or undefined
90
82
  */
91
- export function createSocialAuthHandlers(
92
- googleSignIn: (() => Promise<void>) | undefined,
93
- appleSignIn: (() => Promise<void>) | undefined,
94
- internalGoogleHandler: (() => Promise<void>) | undefined,
95
- internalAppleHandler: (() => Promise<void>) | undefined
96
- ): SocialAuthHandlers {
97
- const googleHandler = googleSignIn || internalGoogleHandler;
98
- const appleHandler = appleSignIn || internalAppleHandler;
99
-
100
- return {
101
- googleLoading: false,
102
- appleLoading: false,
103
- handleGoogleSignIn: googleHandler || (async () => {}),
104
- handleAppleSignIn: appleHandler || (async () => {}),
105
- };
83
+ export function selectSignInHandler(
84
+ externalHandler?: () => Promise<void>,
85
+ internalHandler?: () => Promise<void>
86
+ ): (() => Promise<void>) | undefined {
87
+ return externalHandler ?? internalHandler;
106
88
  }
89
+