@umituz/react-native-auth 3.2.16 → 3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-auth",
3
- "version": "3.2.16",
3
+ "version": "3.4.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",
package/src/index.ts CHANGED
@@ -93,6 +93,15 @@ export {
93
93
  configureUserDocumentService,
94
94
  } from './infrastructure/services/UserDocumentService';
95
95
 
96
+ // Unified Auth Initialization (RECOMMENDED)
97
+ export {
98
+ initializeAuth,
99
+ isAuthInitialized,
100
+ resetAuthInitialization,
101
+ } from './infrastructure/services/initializeAuth';
102
+
103
+ export type { InitializeAuthOptions } from './infrastructure/services/initializeAuth';
104
+
96
105
  export type {
97
106
  UserDocumentConfig,
98
107
  UserDocumentExtras,
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Unified Auth Initialization
3
+ * Single function to initialize all auth services
4
+ *
5
+ * Combines:
6
+ * - AuthService (email/password auth)
7
+ * - Auth Listener (state management)
8
+ * - User Document Service (Firestore)
9
+ * - Anonymous-to-authenticated conversion detection
10
+ */
11
+
12
+ import type { Auth, User } from "firebase/auth";
13
+ import { getFirebaseAuth } from "@umituz/react-native-firebase";
14
+ import { initializeAuthService } from "./AuthService";
15
+ import { configureUserDocumentService, ensureUserDocument } from "./UserDocumentService";
16
+ import type { UserDocumentConfig } from "./UserDocumentService";
17
+ import { initializeAuthListener } from "../../presentation/stores/initializeAuthListener";
18
+ import type { AuthConfig } from "../../domain/value-objects/AuthConfig";
19
+
20
+ /**
21
+ * Unified auth initialization options
22
+ */
23
+ export interface InitializeAuthOptions {
24
+ /** User document collection name (default: "users") */
25
+ userCollection?: string;
26
+
27
+ /** Additional fields to store with user documents */
28
+ extraFields?: Record<string, unknown>;
29
+
30
+ /** Callback to collect device/app info for user documents */
31
+ collectExtras?: () => Promise<Record<string, unknown>>;
32
+
33
+ /** Enable auto anonymous sign-in (default: true) */
34
+ autoAnonymousSignIn?: boolean;
35
+
36
+ /**
37
+ * Callback when user converts from anonymous to authenticated
38
+ * Use this to migrate user data (e.g., call Cloud Function)
39
+ *
40
+ * @param anonymousUserId - The previous anonymous user ID
41
+ * @param authenticatedUserId - The new authenticated user ID
42
+ */
43
+ onUserConverted?: (
44
+ anonymousUserId: string,
45
+ authenticatedUserId: string
46
+ ) => void | Promise<void>;
47
+
48
+ /**
49
+ * Callback when auth state changes (after user document is ensured)
50
+ * Called for every auth state change including initial load
51
+ */
52
+ onAuthStateChange?: (user: User | null) => void | Promise<void>;
53
+
54
+ /** Auth configuration (password rules, etc.) */
55
+ authConfig?: Partial<AuthConfig>;
56
+ }
57
+
58
+ let isInitialized = false;
59
+
60
+ // Track previous user for conversion detection
61
+ let previousUserId: string | null = null;
62
+ let wasAnonymous = false;
63
+
64
+ /**
65
+ * Initialize all auth services with a single call
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * import { initializeAuth } from '@umituz/react-native-auth';
70
+ * import { migrateUserData } from '@domains/migration';
71
+ *
72
+ * await initializeAuth({
73
+ * userCollection: 'users',
74
+ * autoAnonymousSignIn: true,
75
+ * onUserConverted: async (anonymousId, authId) => {
76
+ * await migrateUserData(anonymousId, authId);
77
+ * },
78
+ * });
79
+ * ```
80
+ */
81
+ export async function initializeAuth(
82
+ options: InitializeAuthOptions = {}
83
+ ): Promise<{ success: boolean; auth: Auth | null }> {
84
+ if (isInitialized) {
85
+ const auth = getFirebaseAuth();
86
+ return { success: true, auth };
87
+ }
88
+
89
+ const {
90
+ userCollection = "users",
91
+ extraFields,
92
+ collectExtras,
93
+ autoAnonymousSignIn = true,
94
+ onUserConverted,
95
+ onAuthStateChange,
96
+ authConfig,
97
+ } = options;
98
+
99
+ // 1. Configure user document service
100
+ const userDocConfig: UserDocumentConfig = {
101
+ collectionName: userCollection,
102
+ };
103
+ if (extraFields) userDocConfig.extraFields = extraFields;
104
+ if (collectExtras) userDocConfig.collectExtras = collectExtras;
105
+
106
+ configureUserDocumentService(userDocConfig);
107
+
108
+ // 2. Get Firebase Auth
109
+ const auth = getFirebaseAuth();
110
+ if (!auth) {
111
+ return { success: false, auth: null };
112
+ }
113
+
114
+ // 3. Initialize AuthService (for email/password auth)
115
+ try {
116
+ await initializeAuthService(auth, authConfig);
117
+ } catch {
118
+ // AuthService initialization failed, but we can continue
119
+ // Email/password auth won't work, but social/anonymous will
120
+ }
121
+
122
+ // 4. Initialize Auth Listener (for state management)
123
+ initializeAuthListener({
124
+ autoAnonymousSignIn,
125
+ onAuthStateChange: async (user) => {
126
+ if (!user) {
127
+ // User signed out
128
+ previousUserId = null;
129
+ wasAnonymous = false;
130
+ onAuthStateChange?.(null);
131
+ return;
132
+ }
133
+
134
+ const currentUserId = user.uid;
135
+ const isCurrentlyAnonymous = user.isAnonymous ?? false;
136
+
137
+ // Detect anonymous-to-authenticated conversion
138
+ if (
139
+ previousUserId &&
140
+ previousUserId !== currentUserId &&
141
+ wasAnonymous &&
142
+ !isCurrentlyAnonymous &&
143
+ onUserConverted
144
+ ) {
145
+ try {
146
+ await onUserConverted(previousUserId, currentUserId);
147
+ } catch {
148
+ // Migration failed but don't block user flow
149
+ }
150
+ }
151
+
152
+ // Create/update user document in Firestore
153
+ await ensureUserDocument(user);
154
+
155
+ // Update tracking state
156
+ previousUserId = currentUserId;
157
+ wasAnonymous = isCurrentlyAnonymous;
158
+
159
+ // Call app's custom callback
160
+ onAuthStateChange?.(user);
161
+ },
162
+ });
163
+
164
+ isInitialized = true;
165
+ return { success: true, auth };
166
+ }
167
+
168
+ /**
169
+ * Check if auth is initialized
170
+ */
171
+ export function isAuthInitialized(): boolean {
172
+ return isInitialized;
173
+ }
174
+
175
+ /**
176
+ * Reset auth initialization state (for testing)
177
+ */
178
+ export function resetAuthInitialization(): void {
179
+ isInitialized = false;
180
+ previousUserId = null;
181
+ wasAnonymous = false;
182
+ }