@umituz/react-native-auth 4.3.56 → 4.3.57
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/package.json +1 -1
- package/src/index.ts +18 -2
- package/src/infrastructure/repositories/AuthRepository.ts +0 -3
- package/src/infrastructure/services/AuthService.ts +2 -1
- package/src/infrastructure/utils/listener/anonymousSignInHandler.ts +2 -8
- package/src/presentation/README.md +0 -4
- package/src/presentation/components/LoginForm.tsx +2 -1
- package/src/presentation/components/PasswordStrengthIndicator.tsx +1 -1
- package/src/presentation/components/RegisterForm.tsx +3 -1
- package/src/presentation/hooks/README.md +0 -4
- package/src/presentation/hooks/registerForm/registerFormSubmit.ts +2 -2
- package/src/presentation/hooks/useAccountManagement.md +1 -1
- package/src/presentation/hooks/useAuth.ts +9 -20
- package/src/presentation/hooks/useLoginForm.ts +6 -5
- package/src/presentation/hooks/usePasswordPromptNavigation.ts +2 -1
- package/src/presentation/hooks/useProfileEdit.ts +2 -2
- package/src/presentation/stores/initializeAuthListener.ts +4 -2
- package/src/presentation/utils/form/usePasswordValidation.hook.ts +2 -2
- package/src/presentation/utils/form/validation/formValidators.ts +1 -1
- package/src/presentation/utils/passwordPromptCallback.ts +4 -0
- package/src/application/services/ValidationService.ts +0 -16
- package/src/infrastructure/utils/listener/listenerLifecycle.util.ts +0 -19
- package/src/init/index.ts +0 -6
- package/src/presentation/components/form/index.ts +0 -3
- package/src/presentation/hooks/useProfileUpdate.md +0 -299
- package/src/presentation/utils/form/formValidation.util.ts +0 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-auth",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.57",
|
|
4
4
|
"description": "Authentication service for React Native apps - Secure, type-safe, and production-ready. Provider-agnostic design with dependency injection, configurable validation, and comprehensive error handling.",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -103,13 +103,29 @@ export { useAuthStore } from './presentation/stores/authStore';
|
|
|
103
103
|
export { useAuthModalStore } from './presentation/stores/authModalStore';
|
|
104
104
|
export { initializeAuthListener, resetAuthListener, isAuthListenerInitialized } from './presentation/stores/initializeAuthListener';
|
|
105
105
|
export type { AuthState, AuthActions, UserType, AuthListenerOptions } from './types/auth-store.types';
|
|
106
|
-
export
|
|
106
|
+
export type { AuthModalMode } from './presentation/stores/auth.selectors';
|
|
107
|
+
export {
|
|
108
|
+
selectUser,
|
|
109
|
+
selectLoading,
|
|
110
|
+
selectError,
|
|
111
|
+
selectSetLoading,
|
|
112
|
+
selectSetError,
|
|
113
|
+
selectSetIsAnonymous,
|
|
114
|
+
selectShowAuthModal,
|
|
115
|
+
selectUserId,
|
|
116
|
+
selectIsAuthenticated,
|
|
117
|
+
selectHasFirebaseUser,
|
|
118
|
+
selectIsAnonymous,
|
|
119
|
+
selectUserType,
|
|
120
|
+
selectIsAuthReady,
|
|
121
|
+
selectFirebaseUserId,
|
|
122
|
+
} from './presentation/stores/auth.selectors';
|
|
107
123
|
|
|
108
124
|
// =============================================================================
|
|
109
125
|
// UTILITIES & INIT
|
|
110
126
|
// =============================================================================
|
|
111
127
|
|
|
112
128
|
export { getAuthErrorLocalizationKey, resolveErrorMessage } from './presentation/utils/getAuthErrorMessage';
|
|
113
|
-
export { createAuthInitModule } from './init';
|
|
129
|
+
export { createAuthInitModule } from './init/createAuthInitModule';
|
|
114
130
|
export type { AuthInitModuleConfig } from './init/createAuthInitModule';
|
|
115
131
|
|
|
@@ -109,9 +109,6 @@ export class AuthRepository implements IAuthRepository {
|
|
|
109
109
|
throw new AuthError("Failed to map user");
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// Ensure Firestore user document exists for existing users too
|
|
113
|
-
await ensureUserDocument(result.data, { signUpMethod: "email" });
|
|
114
|
-
|
|
115
112
|
return authUser;
|
|
116
113
|
}
|
|
117
114
|
|
|
@@ -83,7 +83,8 @@ export class AuthService {
|
|
|
83
83
|
const success = await this.anonymousModeService.clear(this.storageProvider);
|
|
84
84
|
if (!success) {
|
|
85
85
|
console.warn('[AuthService] Failed to clear anonymous mode from storage');
|
|
86
|
-
// Force clear in memory to maintain consistency
|
|
86
|
+
// Force clear in memory to maintain consistency and prevent stale state
|
|
87
|
+
// Storage clear failure shouldn't block auth flow, so we force update memory
|
|
87
88
|
this.anonymousModeService.setAnonymousMode(false);
|
|
88
89
|
}
|
|
89
90
|
}
|
|
@@ -12,7 +12,6 @@ const ANONYMOUS_RETRY_DELAY_MS = 1000;
|
|
|
12
12
|
const ANONYMOUS_SIGNIN_TIMEOUT_MS = 10000;
|
|
13
13
|
|
|
14
14
|
interface AnonymousSignInCallbacks {
|
|
15
|
-
onSignInStart: () => void;
|
|
16
15
|
onSignInSuccess: () => void;
|
|
17
16
|
onSignInFailure: (error: Error) => void;
|
|
18
17
|
}
|
|
@@ -31,7 +30,7 @@ interface AnonymousSignInOptions {
|
|
|
31
30
|
*/
|
|
32
31
|
async function attemptAnonymousSignIn(
|
|
33
32
|
auth: Auth,
|
|
34
|
-
callbacks: AnonymousSignInCallbacks,
|
|
33
|
+
callbacks: Omit<AnonymousSignInCallbacks, 'onSignInStart'>,
|
|
35
34
|
options: AnonymousSignInOptions = {}
|
|
36
35
|
): Promise<void> {
|
|
37
36
|
const {
|
|
@@ -40,8 +39,6 @@ async function attemptAnonymousSignIn(
|
|
|
40
39
|
timeout = ANONYMOUS_SIGNIN_TIMEOUT_MS,
|
|
41
40
|
} = options;
|
|
42
41
|
|
|
43
|
-
callbacks.onSignInStart();
|
|
44
|
-
|
|
45
42
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
46
43
|
|
|
47
44
|
try {
|
|
@@ -83,7 +80,7 @@ async function performAnonymousSignIn(
|
|
|
83
80
|
} catch (error) {
|
|
84
81
|
// If not last attempt, wait and retry
|
|
85
82
|
if (attempt < maxRetries - 1) {
|
|
86
|
-
await new Promise(resolve => setTimeout(
|
|
83
|
+
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
|
87
84
|
continue;
|
|
88
85
|
}
|
|
89
86
|
|
|
@@ -119,9 +116,6 @@ export function createAnonymousSignInHandler(
|
|
|
119
116
|
await attemptAnonymousSignIn(
|
|
120
117
|
auth,
|
|
121
118
|
{
|
|
122
|
-
onSignInStart: () => {
|
|
123
|
-
// Sign-in starting
|
|
124
|
-
},
|
|
125
119
|
onSignInSuccess: () => {
|
|
126
120
|
// Listener will be triggered again with the new user
|
|
127
121
|
},
|
|
@@ -27,7 +27,6 @@ React components, hooks, providers, stores, and navigation for authentication UI
|
|
|
27
27
|
**hooks/useAuth.ts** - Main auth hook
|
|
28
28
|
**hooks/useAuthRequired.ts** - Auth requirement checking
|
|
29
29
|
**hooks/useUserProfile.ts** - Profile data fetching
|
|
30
|
-
**hooks/useProfileUpdate.ts** - Profile updates
|
|
31
30
|
**hooks/useAccountManagement.ts** - Account operations
|
|
32
31
|
**hooks/useSocialLogin.ts** - Social auth management
|
|
33
32
|
**hooks/useAuthBottomSheet.ts** - Modal management
|
|
@@ -212,13 +211,11 @@ import { useUserProfile } from '@umituz/react-native-auth';
|
|
|
212
211
|
|
|
213
212
|
---
|
|
214
213
|
|
|
215
|
-
#### useProfileUpdate
|
|
216
214
|
|
|
217
215
|
**PURPOSE**: Profile update operations
|
|
218
216
|
|
|
219
217
|
**IMPORT PATH**:
|
|
220
218
|
```typescript
|
|
221
|
-
import { useProfileUpdate } from '@umituz/react-native-auth';
|
|
222
219
|
```
|
|
223
220
|
|
|
224
221
|
**RETURNS**:
|
|
@@ -238,7 +235,6 @@ import { useProfileUpdate } from '@umituz/react-native-auth';
|
|
|
238
235
|
- Ignore errors
|
|
239
236
|
- Update without user action
|
|
240
237
|
|
|
241
|
-
**Documentation**: `hooks/useProfileUpdate.md`
|
|
242
238
|
|
|
243
239
|
---
|
|
244
240
|
|
|
@@ -4,7 +4,8 @@ import { AtomicButton } from "@umituz/react-native-design-system/atoms";
|
|
|
4
4
|
import { useLoginForm } from "../hooks/useLoginForm";
|
|
5
5
|
import { AuthErrorDisplay } from "./AuthErrorDisplay";
|
|
6
6
|
import { AuthLink } from "./AuthLink";
|
|
7
|
-
import { FormEmailInput
|
|
7
|
+
import { FormEmailInput } from "./form/FormEmailInput";
|
|
8
|
+
import { FormPasswordInput } from "./form/FormPasswordInput";
|
|
8
9
|
|
|
9
10
|
export interface LoginFormTranslations {
|
|
10
11
|
email: string;
|
|
@@ -3,7 +3,7 @@ import { View, StyleSheet } from "react-native";
|
|
|
3
3
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
4
4
|
import { AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
5
5
|
import type { ColorVariant } from "@umituz/react-native-design-system/typography";
|
|
6
|
-
import type { PasswordRequirements } from "../../
|
|
6
|
+
import type { PasswordRequirements } from "../../infrastructure/utils/validation/types";
|
|
7
7
|
|
|
8
8
|
export interface PasswordStrengthTranslations {
|
|
9
9
|
minLength: string;
|
|
@@ -7,7 +7,9 @@ import { AuthLink } from "./AuthLink";
|
|
|
7
7
|
import { AuthLegalLinks, type AuthLegalLinksTranslations } from "./AuthLegalLinks";
|
|
8
8
|
import { PasswordStrengthIndicator, type PasswordStrengthTranslations } from "./PasswordStrengthIndicator";
|
|
9
9
|
import { PasswordMatchIndicator, type PasswordMatchTranslations } from "./PasswordMatchIndicator";
|
|
10
|
-
import { FormTextInput
|
|
10
|
+
import { FormTextInput } from "./form/FormTextInput";
|
|
11
|
+
import { FormEmailInput } from "./form/FormEmailInput";
|
|
12
|
+
import { FormPasswordInput } from "./form/FormPasswordInput";
|
|
11
13
|
|
|
12
14
|
export interface RegisterFormTranslations {
|
|
13
15
|
displayName: string;
|
|
@@ -127,7 +127,6 @@ import { useUserProfile } from '@umituz/react-native-auth';
|
|
|
127
127
|
|
|
128
128
|
---
|
|
129
129
|
|
|
130
|
-
### useProfileUpdate & useProfileEdit
|
|
131
130
|
|
|
132
131
|
**Purpose**: Profile update operations and form management
|
|
133
132
|
|
|
@@ -140,12 +139,10 @@ import { useUserProfile } from '@umituz/react-native-auth';
|
|
|
140
139
|
**Import Path**:
|
|
141
140
|
```typescript
|
|
142
141
|
import {
|
|
143
|
-
useProfileUpdate,
|
|
144
142
|
useProfileEdit
|
|
145
143
|
} from '@umituz/react-native-auth';
|
|
146
144
|
```
|
|
147
145
|
|
|
148
|
-
**File**: `useProfileUpdate.ts`
|
|
149
146
|
|
|
150
147
|
**Rules**:
|
|
151
148
|
- MUST validate before update
|
|
@@ -153,7 +150,6 @@ import {
|
|
|
153
150
|
- MUST show errors to user
|
|
154
151
|
- MUST not allow anonymous updates
|
|
155
152
|
|
|
156
|
-
**Documentation**: `useProfileUpdate.md`
|
|
157
153
|
|
|
158
154
|
---
|
|
159
155
|
|
|
@@ -8,8 +8,8 @@ import { alertService } from "@umituz/react-native-design-system/molecules";
|
|
|
8
8
|
import { DEFAULT_PASSWORD_CONFIG } from "../../../domain/value-objects/AuthConfig";
|
|
9
9
|
import {
|
|
10
10
|
validateRegisterForm,
|
|
11
|
-
|
|
12
|
-
} from "../../utils/form/formValidation.
|
|
11
|
+
} from "../../utils/form/validation/formValidators";
|
|
12
|
+
import { errorsToFieldErrors } from "../../utils/form/validation/formValidation.utils";
|
|
13
13
|
import type { FieldErrors, RegisterFormTranslations } from "./useRegisterForm.types";
|
|
14
14
|
import { sanitizeEmail, sanitizeName } from "../../../infrastructure/utils/validation/sanitization";
|
|
15
15
|
|
|
@@ -330,7 +330,7 @@ import { useAccountManagement } from '@umituz/react-native-auth';
|
|
|
330
330
|
|
|
331
331
|
- **`useAuth`** (`src/presentation/hooks/useAuth.ts`) - Authentication state
|
|
332
332
|
- **`useUserProfile`** (`src/presentation/hooks/useUserProfile.ts`) - Profile data
|
|
333
|
-
- **`
|
|
333
|
+
- **`useProfileEdit`** (`src/presentation/hooks/useProfileEdit.ts`) - Profile editing form
|
|
334
334
|
|
|
335
335
|
## Related Components
|
|
336
336
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* React hook for authentication state management
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useCallback
|
|
6
|
+
import { useCallback } from "react";
|
|
7
7
|
import { useAuthStore } from "../stores/authStore";
|
|
8
8
|
import {
|
|
9
9
|
selectUser,
|
|
@@ -62,23 +62,12 @@ export function useAuth(): UseAuthResult {
|
|
|
62
62
|
const signOutMutation = useSignOutMutation();
|
|
63
63
|
const anonymousModeMutation = useAnonymousModeMutation();
|
|
64
64
|
|
|
65
|
-
// Store mutateAsync in refs to avoid recreating callbacks on every render.
|
|
66
|
-
// useMutation returns a new object each render, but mutateAsync is stable.
|
|
67
|
-
const signUpMutateRef = useRef(signUpMutation.mutateAsync);
|
|
68
|
-
signUpMutateRef.current = signUpMutation.mutateAsync;
|
|
69
|
-
const signInMutateRef = useRef(signInMutation.mutateAsync);
|
|
70
|
-
signInMutateRef.current = signInMutation.mutateAsync;
|
|
71
|
-
const signOutMutateRef = useRef(signOutMutation.mutateAsync);
|
|
72
|
-
signOutMutateRef.current = signOutMutation.mutateAsync;
|
|
73
|
-
const anonymousMutateRef = useRef(anonymousModeMutation.mutateAsync);
|
|
74
|
-
anonymousMutateRef.current = anonymousModeMutation.mutateAsync;
|
|
75
|
-
|
|
76
65
|
const signUp = useCallback(
|
|
77
66
|
async (email: string, password: string, displayName?: string) => {
|
|
78
67
|
try {
|
|
79
68
|
setLoading(true);
|
|
80
69
|
setError(null);
|
|
81
|
-
await
|
|
70
|
+
await signUpMutation.mutateAsync({ email, password, displayName });
|
|
82
71
|
// isAnonymous is automatically derived from firebaseUser by the auth listener
|
|
83
72
|
} catch (err: unknown) {
|
|
84
73
|
setError(err instanceof Error ? err.message : "Sign up failed");
|
|
@@ -87,7 +76,7 @@ export function useAuth(): UseAuthResult {
|
|
|
87
76
|
setLoading(false);
|
|
88
77
|
}
|
|
89
78
|
},
|
|
90
|
-
[setLoading, setError]
|
|
79
|
+
[setLoading, setError, signUpMutation.mutateAsync]
|
|
91
80
|
);
|
|
92
81
|
|
|
93
82
|
const signIn = useCallback(
|
|
@@ -95,7 +84,7 @@ export function useAuth(): UseAuthResult {
|
|
|
95
84
|
try {
|
|
96
85
|
setLoading(true);
|
|
97
86
|
setError(null);
|
|
98
|
-
await
|
|
87
|
+
await signInMutation.mutateAsync({ email, password });
|
|
99
88
|
// isAnonymous is automatically derived from firebaseUser by the auth listener
|
|
100
89
|
} catch (err: unknown) {
|
|
101
90
|
setError(err instanceof Error ? err.message : "Sign in failed");
|
|
@@ -104,27 +93,27 @@ export function useAuth(): UseAuthResult {
|
|
|
104
93
|
setLoading(false);
|
|
105
94
|
}
|
|
106
95
|
},
|
|
107
|
-
[setLoading, setError]
|
|
96
|
+
[setLoading, setError, signInMutation.mutateAsync]
|
|
108
97
|
);
|
|
109
98
|
|
|
110
99
|
const signOut = useCallback(async () => {
|
|
111
100
|
try {
|
|
112
101
|
setLoading(true);
|
|
113
102
|
setError(null);
|
|
114
|
-
await
|
|
103
|
+
await signOutMutation.mutateAsync();
|
|
115
104
|
} catch (err: unknown) {
|
|
116
105
|
setError(err instanceof Error ? err.message : "Sign out failed");
|
|
117
106
|
throw err;
|
|
118
107
|
} finally {
|
|
119
108
|
setLoading(false);
|
|
120
109
|
}
|
|
121
|
-
}, [setLoading, setError]);
|
|
110
|
+
}, [setLoading, setError, signOutMutation.mutateAsync]);
|
|
122
111
|
|
|
123
112
|
const continueAnonymously = useCallback(async () => {
|
|
124
113
|
try {
|
|
125
114
|
setLoading(true);
|
|
126
115
|
setError(null);
|
|
127
|
-
await
|
|
116
|
+
await anonymousModeMutation.mutateAsync();
|
|
128
117
|
// isAnonymous is automatically derived from firebaseUser by the auth listener
|
|
129
118
|
} catch (err: unknown) {
|
|
130
119
|
setError(err instanceof Error ? err.message : "Failed to continue anonymously");
|
|
@@ -132,7 +121,7 @@ export function useAuth(): UseAuthResult {
|
|
|
132
121
|
} finally {
|
|
133
122
|
setLoading(false);
|
|
134
123
|
}
|
|
135
|
-
}, [setLoading, setError]);
|
|
124
|
+
}, [setLoading, setError, anonymousModeMutation.mutateAsync]);
|
|
136
125
|
|
|
137
126
|
return {
|
|
138
127
|
user, userId, userType, loading, isAuthReady, isAnonymous, isAuthenticated, hasFirebaseUser, error,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback } from "react";
|
|
2
2
|
import { useAuth } from "./useAuth";
|
|
3
|
-
import { validateLoginForm } from "../utils/form/
|
|
3
|
+
import { validateLoginForm } from "../utils/form/validation/formValidators";
|
|
4
4
|
import { alertService } from "@umituz/react-native-design-system/molecules";
|
|
5
5
|
import { useFormFields } from "../utils/form/useFormField.hook";
|
|
6
6
|
import { sanitizeEmail } from "../../infrastructure/utils/validation/sanitization";
|
|
@@ -79,10 +79,11 @@ export function useLoginForm(config?: UseLoginFormConfig): UseLoginFormResult {
|
|
|
79
79
|
);
|
|
80
80
|
|
|
81
81
|
if (!validation.isValid) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
// Collect errors first to avoid potential state update batching issues
|
|
83
|
+
const emailErrorMsg = validation.errors.find(e => e.field === "email")?.message || null;
|
|
84
|
+
const passwordErrorMsg = validation.errors.find(e => e.field === "password")?.message || null;
|
|
85
|
+
setEmailError(emailErrorMsg);
|
|
86
|
+
setPasswordError(passwordErrorMsg);
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
8
|
-
import { validateProfileForm } from "../utils/form/
|
|
8
|
+
import { validateProfileForm } from "../utils/form/validation/formValidators";
|
|
9
9
|
|
|
10
10
|
export interface ProfileEditFormState {
|
|
11
11
|
displayName: string;
|
|
@@ -63,7 +63,7 @@ export const useProfileEdit = (
|
|
|
63
63
|
displayName: formState.displayName,
|
|
64
64
|
email: formState.email,
|
|
65
65
|
},
|
|
66
|
-
|
|
66
|
+
key => key // Identity function for translation
|
|
67
67
|
);
|
|
68
68
|
|
|
69
69
|
return {
|
|
@@ -10,10 +10,12 @@ import type { AuthListenerOptions } from "../../types/auth-store.types";
|
|
|
10
10
|
import {
|
|
11
11
|
handleExistingInitialization,
|
|
12
12
|
handleInitializationInProgress,
|
|
13
|
+
} from "../../infrastructure/utils/listener/cleanupHandlers";
|
|
14
|
+
import { setupAuthListener } from "../../infrastructure/utils/listener/setupListener";
|
|
15
|
+
import {
|
|
13
16
|
handleNoFirebaseAuth,
|
|
14
|
-
setupAuthListener,
|
|
15
17
|
completeListenerSetup,
|
|
16
|
-
} from "../../infrastructure/utils/listener/
|
|
18
|
+
} from "../../infrastructure/utils/listener/initializationHandlers";
|
|
17
19
|
import {
|
|
18
20
|
startInitialization,
|
|
19
21
|
isListenerInitialized,
|
|
@@ -7,8 +7,8 @@ import { useMemo } from "react";
|
|
|
7
7
|
import {
|
|
8
8
|
validatePasswordForRegister,
|
|
9
9
|
validatePasswordConfirmation,
|
|
10
|
-
|
|
11
|
-
} from "../../../
|
|
10
|
+
} from "../../../infrastructure/utils/AuthValidation";
|
|
11
|
+
import type { PasswordRequirements } from "../../../infrastructure/utils/validation/types";
|
|
12
12
|
import type { PasswordConfig } from "../../../domain/value-objects/AuthConfig";
|
|
13
13
|
|
|
14
14
|
interface UsePasswordValidationResult {
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
validatePasswordForLogin,
|
|
9
9
|
validatePasswordForRegister,
|
|
10
10
|
validatePasswordConfirmation,
|
|
11
|
-
} from "../../../../
|
|
11
|
+
} from "../../../../infrastructure/utils/AuthValidation";
|
|
12
12
|
import type { PasswordConfig } from "../../../../domain/value-objects/AuthConfig";
|
|
13
13
|
import type {
|
|
14
14
|
FormValidationResult,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
let callback: ((value: string | null) => void) | null = null;
|
|
2
2
|
|
|
3
3
|
export const setPasswordPromptCallback = (cb: ((value: string | null) => void) | null): void => {
|
|
4
|
+
// Warn if overriding an existing callback (indicates potential bug)
|
|
5
|
+
if (callback && cb) {
|
|
6
|
+
console.warn('[passwordPromptCallback] Overriding existing callback - this may indicate a bug');
|
|
7
|
+
}
|
|
4
8
|
callback = cb;
|
|
5
9
|
};
|
|
6
10
|
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validation Service (Application Layer)
|
|
3
|
-
* Facade for validation functions to be used by presentation layer
|
|
4
|
-
* Follows DDD architecture - presentation imports from application, not infrastructure
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
validateEmail,
|
|
9
|
-
validatePasswordForLogin,
|
|
10
|
-
validatePasswordForRegister,
|
|
11
|
-
validatePasswordConfirmation,
|
|
12
|
-
} from "../../infrastructure/utils/AuthValidation";
|
|
13
|
-
|
|
14
|
-
export type {
|
|
15
|
-
PasswordRequirements,
|
|
16
|
-
} from "../../infrastructure/utils/validation/types";
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth Listener Lifecycle - Main Export
|
|
3
|
-
* Exports all listener lifecycle utilities from modular files
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Cleanup handlers
|
|
7
|
-
export {
|
|
8
|
-
handleExistingInitialization,
|
|
9
|
-
handleInitializationInProgress,
|
|
10
|
-
} from "./cleanupHandlers";
|
|
11
|
-
|
|
12
|
-
// Setup listener
|
|
13
|
-
export { setupAuthListener } from "./setupListener";
|
|
14
|
-
|
|
15
|
-
// Initialization handlers
|
|
16
|
-
export {
|
|
17
|
-
handleNoFirebaseAuth,
|
|
18
|
-
completeListenerSetup,
|
|
19
|
-
} from "./initializationHandlers";
|
package/src/init/index.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
# useProfileUpdate & useProfileEdit
|
|
2
|
-
|
|
3
|
-
Hooks for profile update operations and profile editing form management.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## useProfileUpdate
|
|
8
|
-
|
|
9
|
-
Hook for updating user profile information (display name, photo URL).
|
|
10
|
-
|
|
11
|
-
### Strategy
|
|
12
|
-
|
|
13
|
-
**Purpose**: Provides functionality to update user profile data in Firebase Auth and Firestore. Implementation provided by app using Firebase SDK.
|
|
14
|
-
|
|
15
|
-
**When to Use**:
|
|
16
|
-
- User profile editing screens
|
|
17
|
-
- Settings screens with profile updates
|
|
18
|
-
- Need to update display name or photo
|
|
19
|
-
- Profile modification operations
|
|
20
|
-
|
|
21
|
-
**Import Path**:
|
|
22
|
-
```typescript
|
|
23
|
-
import { useProfileUpdate } from '@umituz/react-native-auth';
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**Hook Location**: `src/presentation/hooks/useProfileUpdate.ts`
|
|
27
|
-
|
|
28
|
-
### Rules
|
|
29
|
-
|
|
30
|
-
**MUST**:
|
|
31
|
-
- Validate user is authenticated before updating
|
|
32
|
-
- Validate input data before calling update
|
|
33
|
-
- Handle loading state during update
|
|
34
|
-
- Display error messages on failure
|
|
35
|
-
- Update both Firebase Auth and Firestore
|
|
36
|
-
- Handle anonymous users appropriately
|
|
37
|
-
|
|
38
|
-
**MUST NOT**:
|
|
39
|
-
- Allow anonymous users to update profile
|
|
40
|
-
- Update profile without validation
|
|
41
|
-
- Expose sensitive error details
|
|
42
|
-
- Allow partial updates (all-or-nothing)
|
|
43
|
-
|
|
44
|
-
### Constraints
|
|
45
|
-
|
|
46
|
-
**PARAMETERS**:
|
|
47
|
-
- `displayName?: string` - New display name
|
|
48
|
-
- `photoURL?: string` - New profile photo URL
|
|
49
|
-
|
|
50
|
-
**OPERATION RULES**:
|
|
51
|
-
- Updates Firebase Auth user profile
|
|
52
|
-
- Updates Firestore user document
|
|
53
|
-
- Transactional (both or none)
|
|
54
|
-
- Auto-updates auth state
|
|
55
|
-
- Triggers profile listeners
|
|
56
|
-
|
|
57
|
-
**LIMITATIONS**:
|
|
58
|
-
- Cannot update email (use separate method)
|
|
59
|
-
- Cannot update password (use separate method)
|
|
60
|
-
- Anonymous users cannot update
|
|
61
|
-
- Requires authentication
|
|
62
|
-
|
|
63
|
-
**ERROR HANDLING**:
|
|
64
|
-
- Validation errors before API call
|
|
65
|
-
- Network errors during update
|
|
66
|
-
- Permission errors (user not authenticated)
|
|
67
|
-
- Firebase errors
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## useProfileEdit
|
|
72
|
-
|
|
73
|
-
Hook for managing profile editing form state and validation.
|
|
74
|
-
|
|
75
|
-
### Strategy
|
|
76
|
-
|
|
77
|
-
**Purpose**: Provides form state management for profile editing with validation and change tracking.
|
|
78
|
-
|
|
79
|
-
**When to Use**:
|
|
80
|
-
- Profile editing forms
|
|
81
|
-
- Settings screens with profile edits
|
|
82
|
-
- Need form validation for profile data
|
|
83
|
-
- Want to track form modifications
|
|
84
|
-
|
|
85
|
-
**Import Path**:
|
|
86
|
-
```typescript
|
|
87
|
-
import { useProfileEdit } from '@umituz/react-native-auth';
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Hook Location**: `src/presentation/hooks/useProfileUpdate.ts`
|
|
91
|
-
|
|
92
|
-
### Rules
|
|
93
|
-
|
|
94
|
-
**MUST**:
|
|
95
|
-
- Validate form before submission
|
|
96
|
-
- Show validation errors to user
|
|
97
|
-
- Track form modifications
|
|
98
|
-
- Handle email field as read-only
|
|
99
|
-
- Provide clear error messages
|
|
100
|
-
- Reset form after successful submission
|
|
101
|
-
|
|
102
|
-
**MUST NOT**:
|
|
103
|
-
- Allow invalid form submission
|
|
104
|
-
- Allow email modification (read-only)
|
|
105
|
-
- Submit unchanged data
|
|
106
|
-
- Clear form without confirmation if modified
|
|
107
|
-
|
|
108
|
-
### Constraints
|
|
109
|
-
|
|
110
|
-
**FORM FIELDS**:
|
|
111
|
-
- `displayName: string` - Editable
|
|
112
|
-
- `email: string` - Read-only
|
|
113
|
-
- `photoURL: string | null` - Editable
|
|
114
|
-
- `isModified: boolean` - Auto-calculated
|
|
115
|
-
|
|
116
|
-
**VALIDATION RULES**:
|
|
117
|
-
- Display name: Cannot be empty
|
|
118
|
-
- Email: Valid format (if provided)
|
|
119
|
-
- Photo URL: Valid URL format (if provided)
|
|
120
|
-
|
|
121
|
-
**RETURNED FUNCTIONS**:
|
|
122
|
-
- `setDisplayName: (value: string) => void`
|
|
123
|
-
- `setEmail: (value: string) => void`
|
|
124
|
-
- `setPhotoURL: (value: string | null) => void`
|
|
125
|
-
- `resetForm: (initial: Partial<ProfileEditFormState>) => void`
|
|
126
|
-
- `validateForm: () => { isValid: boolean; errors: string[] }`
|
|
127
|
-
|
|
128
|
-
**CHANGE TRACKING**:
|
|
129
|
-
- `isModified` automatically calculated
|
|
130
|
-
- Compares current vs initial values
|
|
131
|
-
- Triggers re-calculation on any change
|
|
132
|
-
- Used to enable/disable save button
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## Validation Strategy
|
|
137
|
-
|
|
138
|
-
### Strategy
|
|
139
|
-
|
|
140
|
-
**Purpose**: Ensure profile data meets requirements before submission.
|
|
141
|
-
|
|
142
|
-
**Rules**:
|
|
143
|
-
- MUST validate all fields before submission
|
|
144
|
-
- MUST show clear error messages
|
|
145
|
-
- MUST prevent invalid submissions
|
|
146
|
-
- MUST provide real-time validation feedback
|
|
147
|
-
|
|
148
|
-
**MUST NOT**:
|
|
149
|
-
- Allow empty display names
|
|
150
|
-
- Accept invalid email formats
|
|
151
|
-
- Submit with validation errors
|
|
152
|
-
- Hide validation errors
|
|
153
|
-
|
|
154
|
-
### Constraints
|
|
155
|
-
|
|
156
|
-
**DISPLAY NAME VALIDATION**:
|
|
157
|
-
- Required field
|
|
158
|
-
- Minimum length: 1 character
|
|
159
|
-
- Maximum length: 100 characters
|
|
160
|
-
- No special character restrictions
|
|
161
|
-
|
|
162
|
-
**EMAIL VALIDATION**:
|
|
163
|
-
- Valid email format required
|
|
164
|
-
- Read-only field (cannot change)
|
|
165
|
-
- Must match Firebase user email
|
|
166
|
-
- Used for display only
|
|
167
|
-
|
|
168
|
-
**PHOTO URL VALIDATION**:
|
|
169
|
-
- Optional field
|
|
170
|
-
- Must be valid URL if provided
|
|
171
|
-
- Supports HTTP, HTTPS URLs
|
|
172
|
-
- Can be cleared (set to null)
|
|
173
|
-
|
|
174
|
-
**VALIDATION TIMING**:
|
|
175
|
-
- Real-time validation on input
|
|
176
|
-
- Final validation on submit
|
|
177
|
-
- Clear errors on correction
|
|
178
|
-
- Error messages localized
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
## Anonymous User Handling
|
|
183
|
-
|
|
184
|
-
### Strategy
|
|
185
|
-
|
|
186
|
-
**Purpose**: Prevent profile updates from anonymous users.
|
|
187
|
-
|
|
188
|
-
**Rules**:
|
|
189
|
-
- MUST check user is not anonymous
|
|
190
|
-
- MUST hide profile edit for anonymous users
|
|
191
|
-
- MUST show upgrade prompt instead
|
|
192
|
-
- MUST NOT allow anonymous profile updates
|
|
193
|
-
|
|
194
|
-
**Constraints**:
|
|
195
|
-
- Anonymous users cannot update profile
|
|
196
|
-
- Show "Create account" prompt
|
|
197
|
-
- Guide to registration
|
|
198
|
-
- Preserve anonymous data during upgrade
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
## Error Handling
|
|
203
|
-
|
|
204
|
-
### Strategy
|
|
205
|
-
|
|
206
|
-
**Purpose**: Graceful handling of profile update failures.
|
|
207
|
-
|
|
208
|
-
**Rules**:
|
|
209
|
-
- MUST catch all errors during update
|
|
210
|
-
- MUST show user-friendly error messages
|
|
211
|
-
- MUST allow retry after failures
|
|
212
|
-
- MUST not lose form data on error
|
|
213
|
-
|
|
214
|
-
**MUST NOT**:
|
|
215
|
-
- Show raw error messages
|
|
216
|
-
- Crash on update failures
|
|
217
|
-
- Lose user input on errors
|
|
218
|
-
- Block retry attempts
|
|
219
|
-
|
|
220
|
-
### Constraints
|
|
221
|
-
|
|
222
|
-
**ERROR TYPES**:
|
|
223
|
-
- Validation errors: Before API call
|
|
224
|
-
- Network errors: During update
|
|
225
|
-
- Permission errors: Not authenticated
|
|
226
|
-
- Firebase errors: From service
|
|
227
|
-
|
|
228
|
-
**ERROR RECOVERY**:
|
|
229
|
-
- Keep form data on error
|
|
230
|
-
- Allow user to retry
|
|
231
|
-
- Clear errors on new input
|
|
232
|
-
- Show retry button
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
|
|
236
|
-
## Performance Optimization
|
|
237
|
-
|
|
238
|
-
### Strategy
|
|
239
|
-
|
|
240
|
-
**Purpose**: Efficient form state management and updates.
|
|
241
|
-
|
|
242
|
-
**Rules**:
|
|
243
|
-
- MUST minimize unnecessary re-renders
|
|
244
|
-
- MUST debounce validation if expensive
|
|
245
|
-
- MUST optimize form state updates
|
|
246
|
-
- MUST prevent excessive recalculations
|
|
247
|
-
|
|
248
|
-
**Constraints**:
|
|
249
|
-
- Form state in local component
|
|
250
|
-
- Efficient validation checks
|
|
251
|
-
- Minimal prop drilling
|
|
252
|
-
- Optimized re-render triggers
|
|
253
|
-
|
|
254
|
-
---
|
|
255
|
-
|
|
256
|
-
## Security Considerations
|
|
257
|
-
|
|
258
|
-
### Strategy
|
|
259
|
-
|
|
260
|
-
**Purpose**: Secure profile data updates.
|
|
261
|
-
|
|
262
|
-
**Rules**:
|
|
263
|
-
- MUST validate user owns profile
|
|
264
|
-
- MUST sanitize input data
|
|
265
|
-
- MUST use secure upload for photos
|
|
266
|
-
- MUST not expose sensitive data
|
|
267
|
-
|
|
268
|
-
**MUST NOT**:
|
|
269
|
-
- Allow cross-user profile updates
|
|
270
|
-
- Accept unvalidated photo URLs
|
|
271
|
-
- Expose user IDs in errors
|
|
272
|
-
- Log profile data with sensitive info
|
|
273
|
-
|
|
274
|
-
### Constraints
|
|
275
|
-
|
|
276
|
-
**PERMISSION CHECKS**:
|
|
277
|
-
- User can only update own profile
|
|
278
|
-
- Firebase security rules enforce
|
|
279
|
-
- Server-side validation required
|
|
280
|
-
- Token-based authentication
|
|
281
|
-
|
|
282
|
-
**DATA SANITIZATION**:
|
|
283
|
-
- Trim whitespace from names
|
|
284
|
-
- Validate URL formats
|
|
285
|
-
- Escape special characters
|
|
286
|
-
- Prevent XSS attacks
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## Related Hooks
|
|
291
|
-
|
|
292
|
-
- **`useAuth`** (`src/presentation/hooks/useAuth.ts`) - Authentication state
|
|
293
|
-
- **`useUserProfile`** (`src/presentation/hooks/useUserProfile.ts`) - Profile display data
|
|
294
|
-
- **`useAccountManagement`** (`src/presentation/hooks/useAccountManagement.md`) - Account operations
|
|
295
|
-
|
|
296
|
-
## Related Components
|
|
297
|
-
|
|
298
|
-
- **`ProfileSection`** (`src/presentation/components/ProfileComponents.md`) - Profile display
|
|
299
|
-
- **`EditProfileForm`** (`src/presentation/components/ProfileComponents.md`) - Profile editing UI
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Form Validation - Main Export
|
|
3
|
-
* Exports all form validation utilities
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Validators
|
|
7
|
-
export {
|
|
8
|
-
validateLoginForm,
|
|
9
|
-
validateRegisterForm,
|
|
10
|
-
validateProfileForm,
|
|
11
|
-
} from "./validation/formValidators";
|
|
12
|
-
|
|
13
|
-
// Utilities
|
|
14
|
-
export { errorsToFieldErrors } from "./validation/formValidation.utils";
|