@umituz/react-native-auth 3.4.53 → 3.5.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-auth",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
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",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"url": "git+https://github.com/umituz/react-native-auth.git"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@umituz/react-native-design-system": "*",
|
|
36
35
|
"@umituz/react-native-firebase": "*",
|
|
37
36
|
"@umituz/react-native-localization": "*"
|
|
38
37
|
},
|
|
@@ -62,7 +61,7 @@
|
|
|
62
61
|
"@types/react": "~19.1.0",
|
|
63
62
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
64
63
|
"@typescript-eslint/parser": "^7.0.0",
|
|
65
|
-
"@umituz/react-native-design-system": "
|
|
64
|
+
"@umituz/react-native-design-system": "^2.8.34",
|
|
66
65
|
"@umituz/react-native-design-system-theme": "*",
|
|
67
66
|
"eslint": "^8.57.0",
|
|
68
67
|
"expo-apple-authentication": "^6.0.0",
|
|
@@ -9,8 +9,12 @@ import {
|
|
|
9
9
|
signOut as firebaseSignOut,
|
|
10
10
|
onAuthStateChanged,
|
|
11
11
|
updateProfile,
|
|
12
|
+
EmailAuthProvider,
|
|
13
|
+
linkWithCredential,
|
|
12
14
|
type Auth,
|
|
13
15
|
} from "firebase/auth";
|
|
16
|
+
|
|
17
|
+
declare const __DEV__: boolean;
|
|
14
18
|
import type {
|
|
15
19
|
IAuthProvider,
|
|
16
20
|
AuthCredentials,
|
|
@@ -72,11 +76,44 @@ export class FirebaseAuthProvider implements IAuthProvider {
|
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
try {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
const currentUser = this.auth.currentUser;
|
|
80
|
+
const isAnonymous = currentUser?.isAnonymous ?? false;
|
|
81
|
+
|
|
82
|
+
let userCredential;
|
|
83
|
+
|
|
84
|
+
// Convert anonymous user to permanent account
|
|
85
|
+
if (currentUser && isAnonymous) {
|
|
86
|
+
if (__DEV__) {
|
|
87
|
+
console.log("[FirebaseAuthProvider] Converting anonymous user to authenticated:", {
|
|
88
|
+
anonymousId: currentUser.uid.slice(0, 8),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const credential = EmailAuthProvider.credential(
|
|
93
|
+
credentials.email.trim(),
|
|
94
|
+
credentials.password
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
userCredential = await linkWithCredential(currentUser, credential);
|
|
98
|
+
|
|
99
|
+
if (__DEV__) {
|
|
100
|
+
console.log("[FirebaseAuthProvider] Anonymous user converted successfully:", {
|
|
101
|
+
userId: userCredential.user.uid.slice(0, 8),
|
|
102
|
+
sameUser: currentUser.uid === userCredential.user.uid,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
// Create new user
|
|
107
|
+
if (__DEV__) {
|
|
108
|
+
console.log("[FirebaseAuthProvider] Creating new user account");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
userCredential = await createUserWithEmailAndPassword(
|
|
112
|
+
this.auth,
|
|
113
|
+
credentials.email.trim(),
|
|
114
|
+
credentials.password
|
|
115
|
+
);
|
|
116
|
+
}
|
|
80
117
|
|
|
81
118
|
if (credentials.displayName && userCredential.user) {
|
|
82
119
|
try {
|
|
@@ -4,10 +4,12 @@
|
|
|
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
|
+
* IMPORTANT: user is ALWAYS set when firebaseUser exists (anonymous or not).
|
|
9
|
+
* The isAnonymous flag indicates the user type, not whether user is null.
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import { createStore } from "@umituz/react-native-design-system";
|
|
10
|
-
import type { AuthUser } from "../../domain/entities/AuthUser";
|
|
11
13
|
import { mapToAuthUser } from "../../infrastructure/utils/UserMapper";
|
|
12
14
|
import type { AuthState, AuthActions, UserType } from "../../types/auth-store.types";
|
|
13
15
|
import { initialAuthState } from "../../types/auth-store.types";
|
|
@@ -80,48 +82,56 @@ export const useAuthStore = createStore<AuthState, AuthActions>({
|
|
|
80
82
|
},
|
|
81
83
|
actions: (set, get) => ({
|
|
82
84
|
setFirebaseUser: (firebaseUser) => {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
85
|
+
const prevState = get();
|
|
86
|
+
const user = firebaseUser ? mapToAuthUser(firebaseUser) : null;
|
|
87
|
+
const isAnonymous = firebaseUser?.isAnonymous ?? false;
|
|
88
|
+
|
|
89
|
+
if (__DEV__) {
|
|
90
|
+
console.log("[AuthStore] setFirebaseUser:", {
|
|
91
|
+
uid: firebaseUser?.uid ?? null,
|
|
92
|
+
isAnonymous,
|
|
93
|
+
prevIsAnonymous: prevState.isAnonymous,
|
|
94
|
+
hasUser: !!user,
|
|
95
|
+
});
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
set({
|
|
96
|
-
firebaseUser,
|
|
97
|
-
user,
|
|
98
|
-
loading: false,
|
|
99
|
-
isAnonymous: firebaseUser?.isAnonymous ?? false,
|
|
100
|
-
});
|
|
98
|
+
set({ firebaseUser, user, loading: false, isAnonymous });
|
|
101
99
|
},
|
|
102
100
|
|
|
103
|
-
setLoading: (loading) =>
|
|
101
|
+
setLoading: (loading) => {
|
|
102
|
+
if (__DEV__) {
|
|
103
|
+
console.log("[AuthStore] setLoading:", loading);
|
|
104
|
+
}
|
|
105
|
+
set({ loading });
|
|
106
|
+
},
|
|
104
107
|
|
|
105
108
|
setIsAnonymous: (isAnonymous) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
let user: AuthUser | null = null;
|
|
109
|
-
if (firebaseUser) {
|
|
110
|
-
if (!firebaseUser.isAnonymous) {
|
|
111
|
-
user = mapToAuthUser(firebaseUser);
|
|
112
|
-
} else if (!isAnonymous) {
|
|
113
|
-
user = mapToAuthUser(firebaseUser);
|
|
114
|
-
}
|
|
109
|
+
if (__DEV__) {
|
|
110
|
+
console.log("[AuthStore] setIsAnonymous:", isAnonymous);
|
|
115
111
|
}
|
|
116
|
-
|
|
117
|
-
set({ isAnonymous, user });
|
|
112
|
+
set({ isAnonymous });
|
|
118
113
|
},
|
|
119
114
|
|
|
120
|
-
setError: (error) =>
|
|
115
|
+
setError: (error) => {
|
|
116
|
+
if (__DEV__ && error) {
|
|
117
|
+
console.log("[AuthStore] setError:", error);
|
|
118
|
+
}
|
|
119
|
+
set({ error });
|
|
120
|
+
},
|
|
121
121
|
|
|
122
|
-
setInitialized: (initialized) =>
|
|
122
|
+
setInitialized: (initialized) => {
|
|
123
|
+
if (__DEV__) {
|
|
124
|
+
console.log("[AuthStore] setInitialized:", initialized);
|
|
125
|
+
}
|
|
126
|
+
set({ initialized });
|
|
127
|
+
},
|
|
123
128
|
|
|
124
|
-
reset: () =>
|
|
129
|
+
reset: () => {
|
|
130
|
+
if (__DEV__) {
|
|
131
|
+
console.log("[AuthStore] reset");
|
|
132
|
+
}
|
|
133
|
+
set(initialAuthState);
|
|
134
|
+
},
|
|
125
135
|
}),
|
|
126
136
|
});
|
|
127
137
|
|
|
@@ -19,17 +19,23 @@ let listenerInitialized = false;
|
|
|
19
19
|
/**
|
|
20
20
|
* Initialize Firebase auth listener
|
|
21
21
|
* Call once in app root, returns unsubscribe function
|
|
22
|
-
*
|
|
23
|
-
* @param options - Configuration options
|
|
24
|
-
* @param options.autoAnonymousSignIn - Enable auto anonymous sign-in (default: true)
|
|
25
|
-
* @param options.onAuthStateChange - Callback when auth state changes
|
|
26
22
|
*/
|
|
27
23
|
export function initializeAuthListener(
|
|
28
24
|
options: AuthListenerOptions = {}
|
|
29
25
|
): () => void {
|
|
30
26
|
const { autoAnonymousSignIn = true, onAuthStateChange } = options;
|
|
31
27
|
|
|
28
|
+
if (__DEV__) {
|
|
29
|
+
console.log("[AuthListener] initializeAuthListener called:", {
|
|
30
|
+
autoAnonymousSignIn,
|
|
31
|
+
alreadyInitialized: listenerInitialized,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
32
35
|
if (listenerInitialized) {
|
|
36
|
+
if (__DEV__) {
|
|
37
|
+
console.log("[AuthListener] Already initialized, skipping");
|
|
38
|
+
}
|
|
33
39
|
return () => {};
|
|
34
40
|
}
|
|
35
41
|
|
|
@@ -37,6 +43,9 @@ export function initializeAuthListener(
|
|
|
37
43
|
const store = useAuthStore.getState();
|
|
38
44
|
|
|
39
45
|
if (!auth) {
|
|
46
|
+
if (__DEV__) {
|
|
47
|
+
console.log("[AuthListener] No Firebase auth, marking initialized");
|
|
48
|
+
}
|
|
40
49
|
store.setLoading(false);
|
|
41
50
|
store.setInitialized(true);
|
|
42
51
|
return () => {};
|
|
@@ -45,6 +54,9 @@ export function initializeAuthListener(
|
|
|
45
54
|
const service = getAuthService();
|
|
46
55
|
if (service) {
|
|
47
56
|
const isAnonymous = service.getIsAnonymousMode();
|
|
57
|
+
if (__DEV__) {
|
|
58
|
+
console.log("[AuthListener] Service isAnonymousMode:", isAnonymous);
|
|
59
|
+
}
|
|
48
60
|
if (isAnonymous) {
|
|
49
61
|
store.setIsAnonymous(true);
|
|
50
62
|
}
|
|
@@ -53,27 +65,28 @@ export function initializeAuthListener(
|
|
|
53
65
|
listenerInitialized = true;
|
|
54
66
|
|
|
55
67
|
const unsubscribe = onAuthStateChanged(auth, (user) => {
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
if (__DEV__) {
|
|
69
|
+
console.log("[AuthListener] onAuthStateChanged:", {
|
|
70
|
+
uid: user?.uid ?? null,
|
|
71
|
+
isAnonymous: user?.isAnonymous ?? null,
|
|
72
|
+
email: user?.email ?? null,
|
|
73
|
+
});
|
|
59
74
|
}
|
|
60
75
|
|
|
61
|
-
// Auto sign-in anonymously if no user and autoAnonymousSignIn is enabled
|
|
62
76
|
if (!user && autoAnonymousSignIn) {
|
|
77
|
+
if (__DEV__) {
|
|
78
|
+
console.log("[AuthListener] No user, auto signing in anonymously...");
|
|
79
|
+
}
|
|
63
80
|
void (async () => {
|
|
64
81
|
try {
|
|
65
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
66
|
-
// eslint-disable-next-line no-console
|
|
67
|
-
console.log("[authStore] Auto signing in anonymously...");
|
|
68
|
-
}
|
|
69
82
|
await anonymousAuthService.signInAnonymously(auth);
|
|
70
|
-
|
|
83
|
+
if (__DEV__) {
|
|
84
|
+
console.log("[AuthListener] Anonymous sign-in successful");
|
|
85
|
+
}
|
|
71
86
|
} catch (error) {
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
console.warn("[authStore] Auto anonymous sign-in failed:", error);
|
|
87
|
+
if (__DEV__) {
|
|
88
|
+
console.warn("[AuthListener] Anonymous sign-in failed:", error);
|
|
75
89
|
}
|
|
76
|
-
// Continue with null user if anonymous sign-in fails
|
|
77
90
|
store.setFirebaseUser(null);
|
|
78
91
|
store.setInitialized(true);
|
|
79
92
|
}
|
|
@@ -85,14 +98,19 @@ export function initializeAuthListener(
|
|
|
85
98
|
store.setInitialized(true);
|
|
86
99
|
|
|
87
100
|
if (user && !user.isAnonymous && store.isAnonymous) {
|
|
101
|
+
if (__DEV__) {
|
|
102
|
+
console.log("[AuthListener] User converted from anonymous, updating");
|
|
103
|
+
}
|
|
88
104
|
store.setIsAnonymous(false);
|
|
89
105
|
}
|
|
90
106
|
|
|
91
|
-
// Call optional callback
|
|
92
107
|
onAuthStateChange?.(user);
|
|
93
108
|
});
|
|
94
109
|
|
|
95
110
|
return () => {
|
|
111
|
+
if (__DEV__) {
|
|
112
|
+
console.log("[AuthListener] Unsubscribing");
|
|
113
|
+
}
|
|
96
114
|
unsubscribe();
|
|
97
115
|
listenerInitialized = false;
|
|
98
116
|
};
|