@umituz/react-native-firebase 1.13.2 → 1.13.3

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@umituz/react-native-firebase",
3
- "version": "1.13.2",
4
- "description": "Unified Firebase package for React Native apps - Centralized initialization and core services (Analytics, Crashlytics).",
3
+ "version": "1.13.3",
4
+ "description": "Unified Firebase package for React Native apps - Centralized initialization and core services (Auth, Analytics, Crashlytics).",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "scripts": {
@@ -15,6 +15,8 @@
15
15
  "react-native",
16
16
  "firebase",
17
17
  "firebase-core",
18
+ "auth",
19
+ "authentication",
18
20
  "analytics",
19
21
  "crashlytics",
20
22
  "ddd",
@@ -30,6 +32,7 @@
30
32
  "@react-native-firebase/analytics": ">=18.0.0",
31
33
  "@react-native-firebase/app": ">=18.0.0",
32
34
  "@react-native-firebase/crashlytics": ">=18.0.0",
35
+ "expo-apple-authentication": ">=6.0.0",
33
36
  "firebase": ">=10.0.0",
34
37
  "react": ">=18.2.0",
35
38
  "react-native": ">=0.74.0"
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Anonymous User Entity
3
+ * Represents a Firebase Anonymous Auth user
4
+ */
5
+
6
+ import type { User } from "firebase/auth";
7
+
8
+ export interface AnonymousUser {
9
+ readonly uid: string;
10
+ readonly isAnonymous: boolean;
11
+ readonly createdAt?: number;
12
+ }
13
+
14
+ /**
15
+ * Check if a Firebase User is anonymous
16
+ */
17
+ export function isAnonymousUser(user: User | null | undefined): user is User & { isAnonymous: true } {
18
+ return user?.isAnonymous === true;
19
+ }
20
+
21
+ /**
22
+ * Convert Firebase User to AnonymousUser entity
23
+ */
24
+ export function toAnonymousUser(user: User): AnonymousUser {
25
+ return {
26
+ uid: user.uid,
27
+ isAnonymous: user.isAnonymous,
28
+ createdAt: Date.now(),
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Validate AnonymousUser entity
34
+ */
35
+ export function isValidAnonymousUser(user: unknown): user is AnonymousUser {
36
+ return (
37
+ typeof user === 'object' &&
38
+ user !== null &&
39
+ 'uid' in user &&
40
+ typeof user.uid === 'string' &&
41
+ 'isAnonymous' in user &&
42
+ typeof user.isAnonymous === 'boolean'
43
+ );
44
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Firebase Auth Error Classes
3
+ * Custom error types for Firebase Auth operations
4
+ */
5
+
6
+ export class FirebaseAuthError extends Error {
7
+ constructor(message: string) {
8
+ super(message);
9
+ this.name = 'FirebaseAuthError';
10
+ }
11
+ }
12
+
13
+ export class FirebaseAuthInitializationError extends FirebaseAuthError {
14
+ constructor(message: string) {
15
+ super(message);
16
+ this.name = 'FirebaseAuthInitializationError';
17
+ }
18
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Firebase Auth Configuration Value Object
3
+ * Configuration options for Firebase Auth initialization
4
+ */
5
+
6
+ /**
7
+ * Storage interface for auth persistence
8
+ */
9
+ export interface AuthStorage {
10
+ getItem: (key: string) => Promise<string | null>;
11
+ setItem: (key: string, value: string) => Promise<void>;
12
+ removeItem: (key: string) => Promise<void>;
13
+ }
14
+
15
+ export interface FirebaseAuthConfig {
16
+ /**
17
+ * Enable persistence (store user session across app restarts)
18
+ * Default: true
19
+ */
20
+ persistence?: boolean;
21
+
22
+ /**
23
+ * Auth state persistence type
24
+ * - 'local': Persist across browser/app restarts (default)
25
+ * - 'session': Persist only for current session
26
+ * - 'none': No persistence
27
+ */
28
+ persistenceType?: 'local' | 'session' | 'none';
29
+
30
+ /**
31
+ * Custom storage key prefix for auth state
32
+ */
33
+ storageKeyPrefix?: string;
34
+
35
+ /**
36
+ * Enable debug logging
37
+ */
38
+ debug?: boolean;
39
+
40
+ /**
41
+ * Custom auth storage implementation
42
+ * Default: Uses AsyncStorage
43
+ */
44
+ authStorage?: AuthStorage;
45
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Firebase Auth Module
3
+ * Domain-Driven Design (DDD) Architecture
4
+ */
5
+
6
+ // =============================================================================
7
+ // DOMAIN LAYER - Business Logic
8
+ // =============================================================================
9
+
10
+ export {
11
+ FirebaseAuthError,
12
+ FirebaseAuthInitializationError,
13
+ } from './domain/errors/FirebaseAuthError';
14
+
15
+ export type { FirebaseAuthConfig } from './domain/value-objects/FirebaseAuthConfig';
16
+
17
+ // Anonymous User Entity
18
+ export {
19
+ isAnonymousUser,
20
+ toAnonymousUser,
21
+ isValidAnonymousUser,
22
+ } from './domain/entities/AnonymousUser';
23
+ export type { AnonymousUser } from './domain/entities/AnonymousUser';
24
+
25
+ // =============================================================================
26
+ // INFRASTRUCTURE LAYER - Implementation
27
+ // =============================================================================
28
+
29
+ export {
30
+ getFirebaseAuth,
31
+ isFirebaseAuthInitialized,
32
+ getFirebaseAuthInitializationError,
33
+ resetFirebaseAuthClient,
34
+ firebaseAuthClient,
35
+ initializeFirebaseAuth,
36
+ } from './infrastructure/config/FirebaseAuthClient';
37
+
38
+ export type {
39
+ Auth,
40
+ } from './infrastructure/config/FirebaseAuthClient';
41
+
42
+ // Auth Utilities
43
+ export {
44
+ checkAuthState,
45
+ isAuthenticated,
46
+ isGuest,
47
+ getCurrentUserId,
48
+ getCurrentUser,
49
+ getCurrentUserIdFromGlobal,
50
+ getCurrentUserFromGlobal,
51
+ isCurrentUserAuthenticated,
52
+ isCurrentUserGuest,
53
+ verifyUserId,
54
+ getSafeUserId,
55
+ isValidUser,
56
+ } from './infrastructure/services/auth-utils.service';
57
+
58
+ export type {
59
+ AuthCheckResult,
60
+ } from './infrastructure/services/auth-utils.service';
61
+
62
+ // Auth Guard
63
+ export {
64
+ AuthGuardService,
65
+ authGuardService,
66
+ } from './infrastructure/services/auth-guard.service';
67
+
68
+ // Anonymous Auth Service
69
+ export {
70
+ AnonymousAuthService,
71
+ anonymousAuthService,
72
+ } from './infrastructure/services/anonymous-auth.service';
73
+
74
+ export type {
75
+ AnonymousAuthResult,
76
+ AnonymousAuthServiceInterface,
77
+ } from './infrastructure/services/anonymous-auth.service';
78
+
79
+ // Firestore Utilities
80
+ export {
81
+ shouldSkipFirestoreQuery,
82
+ createFirestoreQueryOptions,
83
+ } from './infrastructure/services/firestore-utils.service';
84
+
85
+ export type {
86
+ FirestoreQueryOptions,
87
+ FirestoreQueryResult,
88
+ FirestoreQuerySkipReason,
89
+ } from './infrastructure/services/firestore-utils.service';
90
+
91
+ // Account Deletion
92
+ export {
93
+ deleteCurrentUser,
94
+ deleteUserAccount,
95
+ } from './infrastructure/services/account-deletion.service';
96
+
97
+ export type { AccountDeletionResult, AccountDeletionOptions } from './infrastructure/services/account-deletion.service';
98
+
99
+ // Reauthentication Service
100
+ export {
101
+ getUserAuthProvider,
102
+ reauthenticateWithGoogle,
103
+ reauthenticateWithApple,
104
+ getAppleReauthCredential,
105
+ } from './infrastructure/services/reauthentication.service';
106
+
107
+ export type {
108
+ ReauthenticationResult,
109
+ AuthProviderType,
110
+ } from './infrastructure/services/reauthentication.service';
111
+
112
+ // =============================================================================
113
+ // INFRASTRUCTURE LAYER - Social Auth Services
114
+ // =============================================================================
115
+
116
+ export {
117
+ GoogleAuthService,
118
+ googleAuthService,
119
+ } from './infrastructure/services/google-auth.service';
120
+ export type {
121
+ GoogleAuthConfig,
122
+ GoogleAuthResult,
123
+ } from './infrastructure/services/google-auth.service';
124
+
125
+ export {
126
+ AppleAuthService,
127
+ appleAuthService,
128
+ } from './infrastructure/services/apple-auth.service';
129
+ export type { AppleAuthResult } from './infrastructure/services/apple-auth.service';
130
+
131
+ // =============================================================================
132
+ // PRESENTATION LAYER - Hooks
133
+ // =============================================================================
134
+
135
+ export { useFirebaseAuth } from './presentation/hooks/useFirebaseAuth';
136
+ export type { UseFirebaseAuthResult } from './presentation/hooks/useFirebaseAuth';
137
+
138
+ export { useAnonymousAuth } from './presentation/hooks/useAnonymousAuth';
139
+ export type { UseAnonymousAuthResult } from './presentation/hooks/useAnonymousAuth';
140
+
141
+ export { useSocialAuth } from './presentation/hooks/useSocialAuth';
142
+ export type {
143
+ SocialAuthConfig,
144
+ SocialAuthResult,
145
+ UseSocialAuthResult,
146
+ } from './presentation/hooks/useSocialAuth';
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Firebase Auth Client - Infrastructure Layer
3
+ *
4
+ * Domain-Driven Design: Infrastructure implementation of Firebase Auth client
5
+ * Singleton pattern for managing Firebase Auth instance
6
+ *
7
+ * IMPORTANT: This package requires Firebase App to be initialized first.
8
+ * Use @umituz/react-native-firebase to initialize Firebase App.
9
+ *
10
+ * SOLID Principles:
11
+ * - Single Responsibility: Only manages Auth initialization
12
+ * - Open/Closed: Extensible through configuration, closed for modification
13
+ * - Dependency Inversion: Depends on Firebase App from @umituz/react-native-firebase
14
+ */
15
+
16
+ import type { Auth } from 'firebase/auth';
17
+ import { getFirebaseApp } from '../../../infrastructure/config/FirebaseClient';
18
+ import { FirebaseAuthInitializationError } from '../../domain/errors/FirebaseAuthError';
19
+ import { FirebaseAuthInitializer } from './initializers/FirebaseAuthInitializer';
20
+ import type { FirebaseAuthConfig } from '../../domain/value-objects/FirebaseAuthConfig';
21
+
22
+ declare const __DEV__: boolean;
23
+
24
+ /**
25
+ * Firebase Auth Client Singleton
26
+ * Manages Firebase Auth initialization
27
+ */
28
+ class FirebaseAuthClientSingleton {
29
+ private static instance: FirebaseAuthClientSingleton | null = null;
30
+ private auth: Auth | null = null;
31
+ private initializationError: string | null = null;
32
+
33
+ private constructor() {
34
+ // Private constructor to enforce singleton pattern
35
+ }
36
+
37
+ /**
38
+ * Get singleton instance
39
+ */
40
+ static getInstance(): FirebaseAuthClientSingleton {
41
+ if (!FirebaseAuthClientSingleton.instance) {
42
+ FirebaseAuthClientSingleton.instance = new FirebaseAuthClientSingleton();
43
+ }
44
+ return FirebaseAuthClientSingleton.instance;
45
+ }
46
+
47
+ /**
48
+ * Initialize Firebase Auth
49
+ * Requires Firebase App to be initialized first via @umituz/react-native-firebase
50
+ *
51
+ * @param config - Optional Firebase Auth configuration
52
+ * @returns Firebase Auth instance or null if initialization fails
53
+ */
54
+ initialize(config?: FirebaseAuthConfig): Auth | null {
55
+ // Return existing instance if already initialized
56
+ if (this.auth) {
57
+ if (__DEV__) {
58
+ console.log('[FirebaseAuth] Already initialized, returning existing instance');
59
+ }
60
+ return this.auth;
61
+ }
62
+
63
+ // Don't retry if initialization already failed
64
+ if (this.initializationError) {
65
+ if (__DEV__) {
66
+ console.warn('[FirebaseAuth] Previous initialization failed:', this.initializationError);
67
+ }
68
+ return null;
69
+ }
70
+
71
+ try {
72
+ // Get Firebase App instance (must be initialized first)
73
+ const app = getFirebaseApp();
74
+
75
+ // Return null if Firebase App is not available (offline mode)
76
+ if (!app) {
77
+ if (__DEV__) {
78
+ console.log('[FirebaseAuth] Firebase App not available - skipping Auth initialization');
79
+ }
80
+ // Don't set initializationError - this is normal offline mode
81
+ return null;
82
+ }
83
+
84
+ if (__DEV__) {
85
+ console.log('[FirebaseAuth] Initializing Firebase Auth...');
86
+ }
87
+
88
+ // Initialize Auth
89
+ this.auth = FirebaseAuthInitializer.initialize(app, config);
90
+
91
+ if (this.auth) {
92
+ if (__DEV__) {
93
+ console.log('[FirebaseAuth] ✅ Successfully initialized');
94
+ }
95
+ } else {
96
+ if (__DEV__) {
97
+ console.warn('[FirebaseAuth] ⚠️ Initialization returned null');
98
+ }
99
+ }
100
+
101
+ return this.auth;
102
+ } catch (error) {
103
+ // Only set error if it's a real initialization failure, not just missing config
104
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
105
+ if (__DEV__) {
106
+ console.error('[FirebaseAuth] ❌ Initialization error:', errorMessage);
107
+ }
108
+ if (!errorMessage.includes('not initialized') && !errorMessage.includes('not available')) {
109
+ this.initializationError = errorMessage;
110
+ }
111
+ return null;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Get the Firebase Auth instance
117
+ * Auto-initializes if Firebase App is available
118
+ * Returns null if config is not available (offline mode - no error)
119
+ * @returns Firebase Auth instance or null if not initialized
120
+ */
121
+ getAuth(): Auth | null {
122
+ // Auto-initialize if not already initialized
123
+ if (!this.auth && !this.initializationError) {
124
+ try {
125
+ // Try to get Firebase App (will auto-initialize if config is available)
126
+ const app = getFirebaseApp();
127
+ if (app) {
128
+ this.initialize();
129
+ }
130
+ } catch {
131
+ // Firebase App not available, return null (offline mode)
132
+ return null;
133
+ }
134
+ }
135
+
136
+ // Return null if not initialized (offline mode - no error)
137
+ return this.auth || null;
138
+ }
139
+
140
+ /**
141
+ * Check if Auth is initialized
142
+ */
143
+ isInitialized(): boolean {
144
+ return this.auth !== null;
145
+ }
146
+
147
+ /**
148
+ * Get initialization error if any
149
+ */
150
+ getInitializationError(): string | null {
151
+ return this.initializationError;
152
+ }
153
+
154
+ /**
155
+ * Reset the Auth client instance
156
+ * Useful for testing
157
+ */
158
+ reset(): void {
159
+ this.auth = null;
160
+ this.initializationError = null;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Singleton instance
166
+ */
167
+ export const firebaseAuthClient = FirebaseAuthClientSingleton.getInstance();
168
+
169
+ export function initializeFirebaseAuth(
170
+ config?: FirebaseAuthConfig
171
+ ): Auth | null {
172
+ return firebaseAuthClient.initialize(config);
173
+ }
174
+
175
+ /**
176
+ * Get Firebase Auth instance
177
+ * Auto-initializes if Firebase App is available
178
+ * Returns null if config is not available (offline mode - no error)
179
+ * @returns Firebase Auth instance or null if not initialized
180
+ */
181
+ export function getFirebaseAuth(): Auth | null {
182
+ return firebaseAuthClient.getAuth();
183
+ }
184
+
185
+ /**
186
+ * Check if Firebase Auth is initialized
187
+ */
188
+ export function isFirebaseAuthInitialized(): boolean {
189
+ return firebaseAuthClient.isInitialized();
190
+ }
191
+
192
+ /**
193
+ * Get initialization error if any
194
+ */
195
+ export function getFirebaseAuthInitializationError(): string | null {
196
+ return firebaseAuthClient.getInitializationError();
197
+ }
198
+
199
+ /**
200
+ * Reset Firebase Auth client instance
201
+ * Useful for testing
202
+ */
203
+ export function resetFirebaseAuthClient(): void {
204
+ firebaseAuthClient.reset();
205
+ }
206
+
207
+ // Export types
208
+ export type { Auth } from 'firebase/auth';
209
+ export type { FirebaseAuthConfig } from '../../domain/value-objects/FirebaseAuthConfig';
210
+
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Firebase Auth Initializer
3
+ *
4
+ * Single Responsibility: Initialize Firebase Auth instance
5
+ * Platform-agnostic: Works on all platforms (Web, iOS, Android)
6
+ */
7
+
8
+ import { initializeAuth, getAuth } from 'firebase/auth';
9
+ import type { Auth } from 'firebase/auth';
10
+ import AsyncStorage from '@react-native-async-storage/async-storage';
11
+ import type { FirebaseApp } from 'firebase/app';
12
+ import type { FirebaseAuthConfig } from '../../../domain/value-objects/FirebaseAuthConfig';
13
+ import {
14
+ trackPackageError,
15
+ addPackageBreadcrumb,
16
+ trackPackageWarning,
17
+ } from '@umituz/react-native-sentry';
18
+
19
+ declare const __DEV__: boolean;
20
+
21
+ /**
22
+ * Initializes Firebase Auth
23
+ * Platform-agnostic: Works on all platforms (Web, iOS, Android)
24
+ */
25
+ export class FirebaseAuthInitializer {
26
+ /**
27
+ * Initialize Firebase Auth with persistence support
28
+ */
29
+ static initialize(app: FirebaseApp, config?: FirebaseAuthConfig): Auth | null {
30
+ addPackageBreadcrumb('firebase-auth', 'Initializing Firebase Auth');
31
+
32
+ try {
33
+ // Try React Native persistence first (works on all platforms)
34
+ const auth = this.initializeWithPersistence(app, config);
35
+
36
+ if (auth) {
37
+ addPackageBreadcrumb('firebase-auth', 'Successfully initialized with persistence');
38
+ }
39
+
40
+ return auth;
41
+ } catch (error: any) {
42
+ // If already initialized or persistence fails, get existing instance
43
+ if (error.code === 'auth/already-initialized') {
44
+ trackPackageWarning(
45
+ 'firebase-auth',
46
+ 'Auth already initialized, returning existing instance',
47
+ { errorCode: error.code }
48
+ );
49
+
50
+ try {
51
+ return getAuth(app);
52
+ } catch (getAuthError) {
53
+ const errorObj = getAuthError instanceof Error ? getAuthError : new Error(String(getAuthError));
54
+ trackPackageError(errorObj, {
55
+ packageName: 'firebase-auth',
56
+ operation: 'getAuth-after-already-initialized',
57
+ });
58
+
59
+ if (__DEV__) {
60
+ console.warn('Firebase Auth: Failed to get existing auth instance:', getAuthError);
61
+ }
62
+ return null;
63
+ }
64
+ }
65
+
66
+ const errorObj = error instanceof Error ? error : new Error(String(error));
67
+ trackPackageError(errorObj, {
68
+ packageName: 'firebase-auth',
69
+ operation: 'initialize',
70
+ errorCode: error.code,
71
+ });
72
+
73
+ if (__DEV__) {
74
+ console.warn('Firebase Auth initialization error:', error);
75
+ }
76
+
77
+ // Try to get auth instance as fallback
78
+ try {
79
+ return getAuth(app);
80
+ } catch (getAuthError) {
81
+ const fallbackError = getAuthError instanceof Error ? getAuthError : new Error(String(getAuthError));
82
+ trackPackageError(fallbackError, {
83
+ packageName: 'firebase-auth',
84
+ operation: 'getAuth-fallback',
85
+ });
86
+
87
+ if (__DEV__) {
88
+ console.warn('Firebase Auth: Failed to get auth instance after initialization error:', getAuthError);
89
+ }
90
+ return null;
91
+ }
92
+ }
93
+ }
94
+
95
+ private static initializeWithPersistence(
96
+ app: FirebaseApp,
97
+ config?: FirebaseAuthConfig
98
+ ): Auth | null {
99
+ try {
100
+ const authModule = require('firebase/auth');
101
+ const getReactNativePersistence = authModule.getReactNativePersistence;
102
+
103
+ if (!getReactNativePersistence) {
104
+ trackPackageWarning(
105
+ 'firebase-auth',
106
+ 'getReactNativePersistence not available, using default persistence'
107
+ );
108
+
109
+ if (__DEV__) {
110
+ console.log('Firebase Auth: getReactNativePersistence not available, using default persistence');
111
+ }
112
+ try {
113
+ return getAuth(app);
114
+ } catch {
115
+ return null;
116
+ }
117
+ }
118
+
119
+ const storage = config?.authStorage || {
120
+ getItem: (key: string) => AsyncStorage.getItem(key),
121
+ setItem: (key: string, value: string) => AsyncStorage.setItem(key, value),
122
+ removeItem: (key: string) => AsyncStorage.removeItem(key),
123
+ };
124
+
125
+ addPackageBreadcrumb('firebase-auth', 'Initializing with AsyncStorage persistence');
126
+
127
+ return initializeAuth(app, {
128
+ persistence: getReactNativePersistence(storage),
129
+ });
130
+ } catch (error) {
131
+ const errorObj = error instanceof Error ? error : new Error(String(error));
132
+ trackPackageError(errorObj, {
133
+ packageName: 'firebase-auth',
134
+ operation: 'initializeWithPersistence',
135
+ });
136
+
137
+ if (__DEV__) {
138
+ console.warn('Firebase Auth: Persistence initialization failed:', error);
139
+ }
140
+ try {
141
+ return getAuth(app);
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+ }
147
+ }
148
+