@umituz/react-native-firebase 1.13.1 → 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 +5 -2
- package/src/auth/domain/entities/AnonymousUser.ts +44 -0
- package/src/auth/domain/errors/FirebaseAuthError.ts +18 -0
- package/src/auth/domain/value-objects/FirebaseAuthConfig.ts +45 -0
- package/src/auth/index.ts +146 -0
- package/src/auth/infrastructure/config/FirebaseAuthClient.ts +210 -0
- package/src/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +148 -0
- package/src/auth/infrastructure/services/account-deletion.service.ts +250 -0
- package/src/auth/infrastructure/services/anonymous-auth.service.ts +135 -0
- package/src/auth/infrastructure/services/apple-auth.service.ts +146 -0
- package/src/auth/infrastructure/services/auth-guard.service.ts +97 -0
- package/src/auth/infrastructure/services/auth-utils.service.ts +168 -0
- package/src/auth/infrastructure/services/firestore-utils.service.ts +155 -0
- package/src/auth/infrastructure/services/google-auth.service.ts +100 -0
- package/src/auth/infrastructure/services/reauthentication.service.ts +216 -0
- package/src/auth/presentation/hooks/useAnonymousAuth.ts +201 -0
- package/src/auth/presentation/hooks/useFirebaseAuth.ts +84 -0
- package/src/auth/presentation/hooks/useSocialAuth.ts +162 -0
- package/src/index.ts +8 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-firebase",
|
|
3
|
-
"version": "1.13.
|
|
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
|
+
|