@umituz/react-native-auth 1.3.2 → 1.4.0
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/README.md +19 -8
- package/package.json +3 -2
- package/src/domain/value-objects/AuthConfig.ts +9 -1
- package/src/infrastructure/services/AuthService.ts +23 -0
- package/src/presentation/components/AuthContainer.tsx +3 -0
- package/src/presentation/components/AuthDivider.tsx +3 -0
- package/src/presentation/components/AuthErrorDisplay.tsx +3 -0
- package/src/presentation/components/AuthFormCard.tsx +3 -0
- package/src/presentation/components/AuthGradientBackground.tsx +3 -0
- package/src/presentation/components/AuthHeader.tsx +3 -0
- package/src/presentation/components/AuthLegalLinks.tsx +3 -0
- package/src/presentation/components/AuthLink.tsx +3 -0
- package/src/presentation/hooks/useAuth.ts +66 -45
- package/src/presentation/utils/getAuthErrorMessage.ts +3 -0
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ npm install @umituz/react-native-auth
|
|
|
15
15
|
- `firebase` >= 11.0.0
|
|
16
16
|
- `react` >= 18.2.0
|
|
17
17
|
- `react-native` >= 0.74.0
|
|
18
|
+
- `@umituz/react-native-firebase-auth` >= 1.0.0 (for Firebase Auth initialization)
|
|
18
19
|
|
|
19
20
|
## Features
|
|
20
21
|
|
|
@@ -46,9 +47,10 @@ Initialize the service early in your app (e.g., in `App.tsx`):
|
|
|
46
47
|
|
|
47
48
|
```typescript
|
|
48
49
|
import { initializeAuthService } from '@umituz/react-native-auth';
|
|
49
|
-
import { getFirebaseAuth } from '@umituz/react-native-firebase';
|
|
50
|
+
import { getFirebaseAuth } from '@umituz/react-native-firebase-auth';
|
|
50
51
|
|
|
51
|
-
// Initialize Firebase first (using @umituz/react-native-firebase)
|
|
52
|
+
// Initialize Firebase App first (using @umituz/react-native-firebase)
|
|
53
|
+
// Then initialize Firebase Auth (using @umituz/react-native-firebase-auth)
|
|
52
54
|
const auth = getFirebaseAuth();
|
|
53
55
|
|
|
54
56
|
// Initialize auth service
|
|
@@ -189,15 +191,16 @@ await authService.setGuestMode();
|
|
|
189
191
|
3. **Guest Mode**: Use guest mode for offline-first apps that don't require authentication
|
|
190
192
|
4. **User Callbacks**: Use `onUserCreated` and `onSignOut` callbacks for app-specific logic
|
|
191
193
|
|
|
192
|
-
## Integration with
|
|
194
|
+
## Integration with Firebase Packages
|
|
193
195
|
|
|
194
|
-
This package works seamlessly with
|
|
196
|
+
This package works seamlessly with Firebase initialization packages:
|
|
195
197
|
|
|
196
198
|
```typescript
|
|
197
|
-
import { initializeFirebase
|
|
199
|
+
import { initializeFirebase } from '@umituz/react-native-firebase';
|
|
200
|
+
import { initializeFirebaseAuth, getFirebaseAuth } from '@umituz/react-native-firebase-auth';
|
|
198
201
|
import { initializeAuthService } from '@umituz/react-native-auth';
|
|
199
202
|
|
|
200
|
-
// Initialize Firebase
|
|
203
|
+
// 1. Initialize Firebase App
|
|
201
204
|
const config = {
|
|
202
205
|
apiKey: 'your-api-key',
|
|
203
206
|
authDomain: 'your-project.firebaseapp.com',
|
|
@@ -205,11 +208,19 @@ const config = {
|
|
|
205
208
|
};
|
|
206
209
|
initializeFirebase(config);
|
|
207
210
|
|
|
208
|
-
// Initialize Auth
|
|
211
|
+
// 2. Initialize Firebase Auth
|
|
212
|
+
initializeFirebaseAuth();
|
|
213
|
+
|
|
214
|
+
// 3. Initialize Auth Service (business logic)
|
|
209
215
|
const auth = getFirebaseAuth();
|
|
210
|
-
initializeAuthService(auth
|
|
216
|
+
initializeAuthService(auth, {
|
|
217
|
+
minPasswordLength: 6,
|
|
218
|
+
// ... other config
|
|
219
|
+
});
|
|
211
220
|
```
|
|
212
221
|
|
|
222
|
+
**Note:** This package is provider-agnostic. While it currently uses Firebase Auth, it can be easily adapted to work with Supabase or other authentication providers in the future.
|
|
223
|
+
|
|
213
224
|
## License
|
|
214
225
|
|
|
215
226
|
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-auth",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Authentication service for React Native apps - Secure, type-safe, and production-ready. Provider-agnostic design supports Firebase Auth and can be adapted for Supabase or other providers.",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"firebase": ">=11.0.0",
|
|
35
35
|
"react": ">=18.2.0",
|
|
36
36
|
"react-native": ">=0.74.0",
|
|
37
|
+
"@umituz/react-native-firebase-auth": ">=1.1.0",
|
|
37
38
|
"@react-navigation/stack": "^6.0.0",
|
|
38
39
|
"@react-navigation/native": "^6.0.0",
|
|
39
40
|
"@umituz/react-native-design-system": "*",
|
|
@@ -20,9 +20,17 @@ export interface AuthConfig {
|
|
|
20
20
|
onUserUpdated?: (user: any) => Promise<void> | void;
|
|
21
21
|
/** Callback for sign out cleanup */
|
|
22
22
|
onSignOut?: () => Promise<void> | void;
|
|
23
|
+
/** Callback for analytics logging on sign in */
|
|
24
|
+
onSignIn?: (method: string) => Promise<void> | void;
|
|
25
|
+
/** Callback for analytics logging on guest mode */
|
|
26
|
+
onGuestModeEnabled?: () => Promise<void> | void;
|
|
27
|
+
/** Callback for analytics initialization when user authenticates */
|
|
28
|
+
onAnalyticsInit?: (userId: string) => Promise<void> | void;
|
|
29
|
+
/** Callback for analytics initialization when guest mode enabled */
|
|
30
|
+
onAnalyticsInitGuest?: () => Promise<void> | void;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
|
-
export const DEFAULT_AUTH_CONFIG: Required<Omit<AuthConfig, 'onUserCreated' | 'onUserUpdated' | 'onSignOut'>> = {
|
|
33
|
+
export const DEFAULT_AUTH_CONFIG: Required<Omit<AuthConfig, 'onUserCreated' | 'onUserUpdated' | 'onSignOut' | 'onSignIn' | 'onGuestModeEnabled' | 'onAnalyticsInit' | 'onAnalyticsInitGuest'>> = {
|
|
26
34
|
minPasswordLength: 6,
|
|
27
35
|
requireUppercase: false,
|
|
28
36
|
requireLowercase: false,
|
|
@@ -204,6 +204,7 @@ export class AuthService implements IAuthService {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
// Call user created callback if provided
|
|
207
|
+
// User state is managed by Firebase Auth's onAuthStateChanged
|
|
207
208
|
if (this.config.onUserCreated) {
|
|
208
209
|
try {
|
|
209
210
|
await this.config.onUserCreated(userCredential.user);
|
|
@@ -245,6 +246,17 @@ export class AuthService implements IAuthService {
|
|
|
245
246
|
);
|
|
246
247
|
|
|
247
248
|
this.isGuestMode = false;
|
|
249
|
+
|
|
250
|
+
// Call analytics callback if provided
|
|
251
|
+
// User state is managed by Firebase Auth's onAuthStateChanged
|
|
252
|
+
if (this.config.onSignIn) {
|
|
253
|
+
try {
|
|
254
|
+
await this.config.onSignIn("email");
|
|
255
|
+
} catch (callbackError) {
|
|
256
|
+
// Don't fail signin if analytics callback fails
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
248
260
|
return userCredential.user;
|
|
249
261
|
} catch (error: any) {
|
|
250
262
|
throw mapFirebaseAuthError(error);
|
|
@@ -267,6 +279,7 @@ export class AuthService implements IAuthService {
|
|
|
267
279
|
this.isGuestMode = false;
|
|
268
280
|
|
|
269
281
|
// Call sign out callback if provided
|
|
282
|
+
// User state is managed by Firebase Auth's onAuthStateChanged
|
|
270
283
|
if (this.config.onSignOut) {
|
|
271
284
|
try {
|
|
272
285
|
await this.config.onSignOut();
|
|
@@ -295,6 +308,16 @@ export class AuthService implements IAuthService {
|
|
|
295
308
|
}
|
|
296
309
|
|
|
297
310
|
this.isGuestMode = true;
|
|
311
|
+
|
|
312
|
+
// Call analytics callback if provided
|
|
313
|
+
// Guest mode state is managed by useAuth hook
|
|
314
|
+
if (this.config.onGuestModeEnabled) {
|
|
315
|
+
try {
|
|
316
|
+
await this.config.onGuestModeEnabled();
|
|
317
|
+
} catch (callbackError) {
|
|
318
|
+
// Don't fail guest mode if analytics callback fails
|
|
319
|
+
}
|
|
320
|
+
}
|
|
298
321
|
}
|
|
299
322
|
|
|
300
323
|
/**
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useAuth Hook
|
|
3
3
|
* React hook for authentication state management
|
|
4
|
+
*
|
|
5
|
+
* Uses Firebase Auth's built-in state management via useFirebaseAuth hook.
|
|
6
|
+
* Adds app-specific state (guest mode, error handling) on top of Firebase Auth.
|
|
4
7
|
*/
|
|
5
8
|
|
|
6
|
-
import { useEffect,
|
|
9
|
+
import { useEffect, useRef, useCallback, useState } from "react";
|
|
7
10
|
import type { User } from "firebase/auth";
|
|
8
11
|
import { getAuthService } from "../../infrastructure/services/AuthService";
|
|
9
|
-
import {
|
|
12
|
+
import { useFirebaseAuth } from "@umituz/react-native-firebase-auth";
|
|
10
13
|
|
|
11
14
|
export interface UseAuthResult {
|
|
12
15
|
/** Current authenticated user */
|
|
@@ -27,58 +30,62 @@ export interface UseAuthResult {
|
|
|
27
30
|
signOut: () => Promise<void>;
|
|
28
31
|
/** Continue as guest function */
|
|
29
32
|
continueAsGuest: () => Promise<void>;
|
|
33
|
+
/** Set error manually (for form validation, etc.) */
|
|
34
|
+
setError: (error: string | null) => void;
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
/**
|
|
33
38
|
* Hook for authentication state management
|
|
34
39
|
*
|
|
40
|
+
* Uses Firebase Auth's built-in state management and adds app-specific features:
|
|
41
|
+
* - Guest mode support
|
|
42
|
+
* - Error handling
|
|
43
|
+
* - Loading states
|
|
44
|
+
*
|
|
35
45
|
* @example
|
|
36
46
|
* ```typescript
|
|
37
47
|
* const { user, isAuthenticated, signIn, signUp, signOut } = useAuth();
|
|
38
48
|
* ```
|
|
39
49
|
*/
|
|
40
50
|
export function useAuth(): UseAuthResult {
|
|
41
|
-
|
|
42
|
-
const
|
|
51
|
+
// Use Firebase Auth's built-in state management
|
|
52
|
+
const { user: firebaseUser, loading: firebaseLoading } = useFirebaseAuth();
|
|
53
|
+
|
|
54
|
+
// App-specific state
|
|
43
55
|
const [isGuest, setIsGuest] = useState(false);
|
|
44
56
|
const [error, setError] = useState<string | null>(null);
|
|
57
|
+
const [loading, setLoading] = useState(false);
|
|
58
|
+
const prevAuthState = useRef({ isAuthenticated: false, isGuest: false });
|
|
59
|
+
|
|
60
|
+
// Sync Firebase Auth user with guest mode
|
|
61
|
+
const user = isGuest ? null : firebaseUser;
|
|
62
|
+
const isAuthenticated = !!user && !isGuest;
|
|
45
63
|
|
|
64
|
+
// Handle analytics initialization (if callbacks are provided in config)
|
|
46
65
|
useEffect(() => {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
setUser(null);
|
|
51
|
-
setIsGuest(false);
|
|
52
|
-
setLoading(false);
|
|
53
|
-
return () => {};
|
|
54
|
-
}
|
|
66
|
+
const authChanged =
|
|
67
|
+
prevAuthState.current.isAuthenticated !== isAuthenticated ||
|
|
68
|
+
prevAuthState.current.isGuest !== isGuest;
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
setUser(currentUser);
|
|
59
|
-
setIsGuest(service.getIsGuestMode());
|
|
60
|
-
setLoading(false);
|
|
61
|
-
});
|
|
70
|
+
// Analytics initialization is handled by AuthService callbacks (onAnalyticsInit, onAnalyticsInitGuest)
|
|
71
|
+
// This effect is kept for backward compatibility but analytics should be configured via AuthConfig
|
|
62
72
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
setIsGuest(service.getIsGuestMode());
|
|
67
|
-
setLoading(false);
|
|
73
|
+
// Update previous state
|
|
74
|
+
prevAuthState.current = { isAuthenticated, isGuest };
|
|
75
|
+
}, [isAuthenticated, isGuest]);
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
} catch (error) {
|
|
73
|
-
// Auth service error
|
|
74
|
-
setUser(null);
|
|
77
|
+
// Reset guest mode when user signs in
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (firebaseUser && isGuest) {
|
|
75
80
|
setIsGuest(false);
|
|
76
|
-
setLoading(false);
|
|
77
|
-
return () => {};
|
|
78
81
|
}
|
|
79
|
-
}, []);
|
|
82
|
+
}, [firebaseUser, isGuest]);
|
|
80
83
|
|
|
81
|
-
const signUp = useCallback(async (
|
|
84
|
+
const signUp = useCallback(async (
|
|
85
|
+
email: string,
|
|
86
|
+
password: string,
|
|
87
|
+
displayName?: string
|
|
88
|
+
) => {
|
|
82
89
|
const service = getAuthService();
|
|
83
90
|
if (!service) {
|
|
84
91
|
const err = "Auth service is not initialized";
|
|
@@ -86,13 +93,16 @@ export function useAuth(): UseAuthResult {
|
|
|
86
93
|
throw new Error(err);
|
|
87
94
|
}
|
|
88
95
|
try {
|
|
96
|
+
setLoading(true);
|
|
89
97
|
setError(null);
|
|
90
98
|
await service.signUp({ email, password, displayName });
|
|
91
|
-
//
|
|
99
|
+
// User state is updated by Firebase Auth's onAuthStateChanged
|
|
92
100
|
} catch (err: any) {
|
|
93
101
|
const errorMessage = err.message || "Sign up failed";
|
|
94
102
|
setError(errorMessage);
|
|
95
103
|
throw err;
|
|
104
|
+
} finally {
|
|
105
|
+
setLoading(false);
|
|
96
106
|
}
|
|
97
107
|
}, []);
|
|
98
108
|
|
|
@@ -104,13 +114,16 @@ export function useAuth(): UseAuthResult {
|
|
|
104
114
|
throw new Error(err);
|
|
105
115
|
}
|
|
106
116
|
try {
|
|
117
|
+
setLoading(true);
|
|
107
118
|
setError(null);
|
|
108
119
|
await service.signIn({ email, password });
|
|
109
|
-
//
|
|
120
|
+
// User state is updated by Firebase Auth's onAuthStateChanged
|
|
110
121
|
} catch (err: any) {
|
|
111
|
-
const errorMessage = err.message || "
|
|
122
|
+
const errorMessage = err.message || "Failed to sign in";
|
|
112
123
|
setError(errorMessage);
|
|
113
124
|
throw err;
|
|
125
|
+
} finally {
|
|
126
|
+
setLoading(false);
|
|
114
127
|
}
|
|
115
128
|
}, []);
|
|
116
129
|
|
|
@@ -119,9 +132,13 @@ export function useAuth(): UseAuthResult {
|
|
|
119
132
|
if (!service) {
|
|
120
133
|
return;
|
|
121
134
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
try {
|
|
136
|
+
setLoading(true);
|
|
137
|
+
await service.signOut();
|
|
138
|
+
// User state is updated by Firebase Auth's onAuthStateChanged
|
|
139
|
+
} finally {
|
|
140
|
+
setLoading(false);
|
|
141
|
+
}
|
|
125
142
|
}, []);
|
|
126
143
|
|
|
127
144
|
const continueAsGuest = useCallback(async () => {
|
|
@@ -130,21 +147,25 @@ export function useAuth(): UseAuthResult {
|
|
|
130
147
|
setIsGuest(true);
|
|
131
148
|
return;
|
|
132
149
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
try {
|
|
151
|
+
setLoading(true);
|
|
152
|
+
await service.setGuestMode();
|
|
153
|
+
setIsGuest(true);
|
|
154
|
+
} finally {
|
|
155
|
+
setLoading(false);
|
|
156
|
+
}
|
|
136
157
|
}, []);
|
|
137
158
|
|
|
138
159
|
return {
|
|
139
160
|
user,
|
|
140
|
-
loading,
|
|
161
|
+
loading: loading || firebaseLoading,
|
|
141
162
|
isGuest,
|
|
142
|
-
isAuthenticated
|
|
163
|
+
isAuthenticated,
|
|
143
164
|
error,
|
|
144
165
|
signUp,
|
|
145
166
|
signIn,
|
|
146
167
|
signOut,
|
|
147
168
|
continueAsGuest,
|
|
169
|
+
setError,
|
|
148
170
|
};
|
|
149
171
|
}
|
|
150
|
-
|