@umituz/react-native-auth 3.1.8 → 3.1.9
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 +11 -0
- package/src/presentation/hooks/useAuth.ts +26 -12
- package/src/presentation/stores/authStore.ts +84 -31
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-auth",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.9",
|
|
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
|
@@ -183,8 +183,19 @@ export {
|
|
|
183
183
|
initializeAuthListener,
|
|
184
184
|
resetAuthListener,
|
|
185
185
|
selectIsAuthenticated,
|
|
186
|
+
selectUserId,
|
|
187
|
+
selectIsAnonymous,
|
|
188
|
+
selectUserType,
|
|
189
|
+
selectIsAuthReady,
|
|
190
|
+
getUserId,
|
|
191
|
+
getUserType,
|
|
192
|
+
getIsAuthenticated,
|
|
193
|
+
getIsGuest,
|
|
194
|
+
getIsAnonymous,
|
|
186
195
|
} from './presentation/stores/authStore';
|
|
187
196
|
|
|
197
|
+
export type { UserType } from './presentation/stores/authStore';
|
|
198
|
+
|
|
188
199
|
// =============================================================================
|
|
189
200
|
// PRESENTATION LAYER - Utilities
|
|
190
201
|
// =============================================================================
|
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Uses centralized Zustand store for auth state.
|
|
6
6
|
* Single source of truth - no duplicate subscriptions.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* const { user, isAuthenticated, signIn, signUp, signOut } = useAuth();
|
|
11
|
-
* ```
|
|
12
7
|
*/
|
|
13
8
|
|
|
14
9
|
import { useCallback } from "react";
|
|
15
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
useAuthStore,
|
|
12
|
+
selectIsAuthenticated,
|
|
13
|
+
selectUserId,
|
|
14
|
+
selectUserType,
|
|
15
|
+
selectIsAnonymous,
|
|
16
|
+
selectIsAuthReady,
|
|
17
|
+
type UserType,
|
|
18
|
+
} from "../stores/authStore";
|
|
16
19
|
import {
|
|
17
20
|
useSignInMutation,
|
|
18
21
|
useSignUpMutation,
|
|
@@ -24,11 +27,19 @@ import type { AuthUser } from "../../domain/entities/AuthUser";
|
|
|
24
27
|
export interface UseAuthResult {
|
|
25
28
|
/** Current authenticated user */
|
|
26
29
|
user: AuthUser | null;
|
|
30
|
+
/** Current user ID (uid) */
|
|
31
|
+
userId: string | null;
|
|
32
|
+
/** Current user type */
|
|
33
|
+
userType: UserType;
|
|
27
34
|
/** Whether auth state is loading */
|
|
28
35
|
loading: boolean;
|
|
36
|
+
/** Whether auth is ready (initialized and not loading) */
|
|
37
|
+
isAuthReady: boolean;
|
|
29
38
|
/** Whether user is in guest mode */
|
|
30
39
|
isGuest: boolean;
|
|
31
|
-
/** Whether user is
|
|
40
|
+
/** Whether user is anonymous */
|
|
41
|
+
isAnonymous: boolean;
|
|
42
|
+
/** Whether user is authenticated (not guest, not anonymous) */
|
|
32
43
|
isAuthenticated: boolean;
|
|
33
44
|
/** Current error message */
|
|
34
45
|
error: string | null;
|
|
@@ -49,11 +60,6 @@ export interface UseAuthResult {
|
|
|
49
60
|
*
|
|
50
61
|
* Uses centralized Zustand store - all components share the same state.
|
|
51
62
|
* Must call initializeAuthListener() once in app root.
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```typescript
|
|
55
|
-
* const { user, isAuthenticated, signIn, signUp, signOut } = useAuth();
|
|
56
|
-
* ```
|
|
57
63
|
*/
|
|
58
64
|
export function useAuth(): UseAuthResult {
|
|
59
65
|
// State from store
|
|
@@ -62,6 +68,10 @@ export function useAuth(): UseAuthResult {
|
|
|
62
68
|
const isGuest = useAuthStore((state) => state.isGuest);
|
|
63
69
|
const error = useAuthStore((state) => state.error);
|
|
64
70
|
const isAuthenticated = useAuthStore(selectIsAuthenticated);
|
|
71
|
+
const userId = useAuthStore(selectUserId);
|
|
72
|
+
const userType = useAuthStore(selectUserType);
|
|
73
|
+
const isAnonymous = useAuthStore(selectIsAnonymous);
|
|
74
|
+
const isAuthReady = useAuthStore(selectIsAuthReady);
|
|
65
75
|
|
|
66
76
|
// Actions from store
|
|
67
77
|
const setLoading = useAuthStore((state) => state.setLoading);
|
|
@@ -137,8 +147,12 @@ export function useAuth(): UseAuthResult {
|
|
|
137
147
|
|
|
138
148
|
return {
|
|
139
149
|
user,
|
|
150
|
+
userId,
|
|
151
|
+
userType,
|
|
140
152
|
loading,
|
|
153
|
+
isAuthReady,
|
|
141
154
|
isGuest,
|
|
155
|
+
isAnonymous,
|
|
142
156
|
isAuthenticated,
|
|
143
157
|
error,
|
|
144
158
|
signUp,
|
|
@@ -4,18 +4,6 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Single source of truth for auth state across the app.
|
|
6
6
|
* Firebase auth changes are synced via initializeAuthListener().
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* // Initialize once in app root
|
|
11
|
-
* useEffect(() => {
|
|
12
|
-
* const unsubscribe = initializeAuthListener();
|
|
13
|
-
* return unsubscribe;
|
|
14
|
-
* }, []);
|
|
15
|
-
*
|
|
16
|
-
* // Use anywhere
|
|
17
|
-
* const { user, isAuthenticated, signIn, signOut } = useAuthStore();
|
|
18
|
-
* ```
|
|
19
7
|
*/
|
|
20
8
|
|
|
21
9
|
import { createStore } from "@umituz/react-native-storage";
|
|
@@ -25,6 +13,13 @@ import type { AuthUser } from "../../domain/entities/AuthUser";
|
|
|
25
13
|
import { mapToAuthUser } from "../../infrastructure/utils/UserMapper";
|
|
26
14
|
import { getAuthService } from "../../infrastructure/services/AuthService";
|
|
27
15
|
|
|
16
|
+
declare const __DEV__: boolean;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* User type classification
|
|
20
|
+
*/
|
|
21
|
+
export type UserType = "authenticated" | "anonymous" | "none";
|
|
22
|
+
|
|
28
23
|
// =============================================================================
|
|
29
24
|
// STATE TYPES
|
|
30
25
|
// =============================================================================
|
|
@@ -82,7 +77,6 @@ export const useAuthStore = createStore<AuthState, AuthActions>({
|
|
|
82
77
|
persist: true,
|
|
83
78
|
version: 1,
|
|
84
79
|
partialize: (state) => ({
|
|
85
|
-
// Only persist these fields (not functions, not firebaseUser)
|
|
86
80
|
isGuest: state.isGuest,
|
|
87
81
|
initialized: state.initialized,
|
|
88
82
|
}),
|
|
@@ -93,12 +87,9 @@ export const useAuthStore = createStore<AuthState, AuthActions>({
|
|
|
93
87
|
let user: AuthUser | null = null;
|
|
94
88
|
|
|
95
89
|
if (firebaseUser) {
|
|
96
|
-
// Non-anonymous users always get mapped
|
|
97
90
|
if (!firebaseUser.isAnonymous) {
|
|
98
91
|
user = mapToAuthUser(firebaseUser);
|
|
99
|
-
}
|
|
100
|
-
// Anonymous users only if not in guest mode
|
|
101
|
-
else if (!isGuest) {
|
|
92
|
+
} else if (!isGuest) {
|
|
102
93
|
user = mapToAuthUser(firebaseUser);
|
|
103
94
|
}
|
|
104
95
|
}
|
|
@@ -115,7 +106,6 @@ export const useAuthStore = createStore<AuthState, AuthActions>({
|
|
|
115
106
|
setIsGuest: (isGuest) => {
|
|
116
107
|
const { firebaseUser } = get();
|
|
117
108
|
|
|
118
|
-
// Recalculate user when guest mode changes
|
|
119
109
|
let user: AuthUser | null = null;
|
|
120
110
|
if (firebaseUser) {
|
|
121
111
|
if (!firebaseUser.isAnonymous) {
|
|
@@ -140,6 +130,13 @@ export const useAuthStore = createStore<AuthState, AuthActions>({
|
|
|
140
130
|
// SELECTORS
|
|
141
131
|
// =============================================================================
|
|
142
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Get current user ID
|
|
135
|
+
*/
|
|
136
|
+
export const selectUserId = (state: AuthState): string | null => {
|
|
137
|
+
return state.firebaseUser?.uid ?? state.user?.uid ?? null;
|
|
138
|
+
};
|
|
139
|
+
|
|
143
140
|
/**
|
|
144
141
|
* Check if user is authenticated (not guest, not anonymous)
|
|
145
142
|
*/
|
|
@@ -147,6 +144,73 @@ export const selectIsAuthenticated = (state: AuthState): boolean => {
|
|
|
147
144
|
return !!state.user && !state.isGuest && !state.user.isAnonymous;
|
|
148
145
|
};
|
|
149
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Check if user is anonymous
|
|
149
|
+
*/
|
|
150
|
+
export const selectIsAnonymous = (state: AuthState): boolean => {
|
|
151
|
+
return state.firebaseUser?.isAnonymous ?? state.user?.isAnonymous ?? false;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get current user type
|
|
156
|
+
*/
|
|
157
|
+
export const selectUserType = (state: AuthState): UserType => {
|
|
158
|
+
if (!state.firebaseUser && !state.user) {
|
|
159
|
+
return "none";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const isAnonymous =
|
|
163
|
+
state.firebaseUser?.isAnonymous ?? state.user?.isAnonymous ?? false;
|
|
164
|
+
|
|
165
|
+
return isAnonymous ? "anonymous" : "authenticated";
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Check if auth is ready (initialized and not loading)
|
|
170
|
+
*/
|
|
171
|
+
export const selectIsAuthReady = (state: AuthState): boolean => {
|
|
172
|
+
return state.initialized && !state.loading;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// =============================================================================
|
|
176
|
+
// NON-HOOK GETTERS
|
|
177
|
+
// =============================================================================
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get user ID without hook
|
|
181
|
+
*/
|
|
182
|
+
export function getUserId(): string | null {
|
|
183
|
+
return selectUserId(useAuthStore.getState());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get user type without hook
|
|
188
|
+
*/
|
|
189
|
+
export function getUserType(): UserType {
|
|
190
|
+
return selectUserType(useAuthStore.getState());
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Check if authenticated without hook
|
|
195
|
+
*/
|
|
196
|
+
export function getIsAuthenticated(): boolean {
|
|
197
|
+
return selectIsAuthenticated(useAuthStore.getState());
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if guest without hook
|
|
202
|
+
*/
|
|
203
|
+
export function getIsGuest(): boolean {
|
|
204
|
+
return useAuthStore.getState().isGuest;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Check if anonymous without hook
|
|
209
|
+
*/
|
|
210
|
+
export function getIsAnonymous(): boolean {
|
|
211
|
+
return selectIsAnonymous(useAuthStore.getState());
|
|
212
|
+
}
|
|
213
|
+
|
|
150
214
|
// =============================================================================
|
|
151
215
|
// LISTENER
|
|
152
216
|
// =============================================================================
|
|
@@ -156,17 +220,8 @@ let listenerInitialized = false;
|
|
|
156
220
|
/**
|
|
157
221
|
* Initialize Firebase auth listener
|
|
158
222
|
* Call once in app root, returns unsubscribe function
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* ```typescript
|
|
162
|
-
* useEffect(() => {
|
|
163
|
-
* const unsubscribe = initializeAuthListener();
|
|
164
|
-
* return unsubscribe;
|
|
165
|
-
* }, []);
|
|
166
|
-
* ```
|
|
167
223
|
*/
|
|
168
224
|
export function initializeAuthListener(): () => void {
|
|
169
|
-
// Prevent multiple initializations
|
|
170
225
|
if (listenerInitialized) {
|
|
171
226
|
return () => {};
|
|
172
227
|
}
|
|
@@ -180,7 +235,6 @@ export function initializeAuthListener(): () => void {
|
|
|
180
235
|
return () => {};
|
|
181
236
|
}
|
|
182
237
|
|
|
183
|
-
// Sync initial guest mode from service
|
|
184
238
|
const service = getAuthService();
|
|
185
239
|
if (service) {
|
|
186
240
|
const isGuest = service.getIsGuestMode();
|
|
@@ -191,16 +245,15 @@ export function initializeAuthListener(): () => void {
|
|
|
191
245
|
|
|
192
246
|
listenerInitialized = true;
|
|
193
247
|
|
|
194
|
-
// Subscribe to auth state changes
|
|
195
248
|
const unsubscribe = onAuthStateChanged(auth, (user) => {
|
|
196
|
-
if (__DEV__) {
|
|
249
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
250
|
+
// eslint-disable-next-line no-console
|
|
197
251
|
console.log("[authStore] Auth state changed:", user?.uid ?? "null");
|
|
198
252
|
}
|
|
199
253
|
|
|
200
254
|
store.setFirebaseUser(user);
|
|
201
255
|
store.setInitialized(true);
|
|
202
256
|
|
|
203
|
-
// Reset guest mode when real user signs in
|
|
204
257
|
if (user && !user.isAnonymous && store.isGuest) {
|
|
205
258
|
store.setIsGuest(false);
|
|
206
259
|
}
|