@umituz/react-native-firebase 1.13.55 → 1.13.57

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-firebase",
3
- "version": "1.13.55",
3
+ "version": "1.13.57",
4
4
  "description": "Unified Firebase package for React Native apps - Auth and Firestore services using Firebase JS SDK (no native modules).",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -9,27 +9,9 @@ import { checkAuthState, verifyUserId } from "./auth-utils.service";
9
9
  declare const __DEV__: boolean;
10
10
 
11
11
  export interface FirestoreQueryOptions {
12
- /**
13
- * Skip query if user is anonymous/guest
14
- * Default: true (guest users don't have Firestore data)
15
- */
16
12
  readonly skipForGuest?: boolean;
17
-
18
- /**
19
- * Skip query if user is not authenticated
20
- * Default: true
21
- */
22
13
  readonly skipIfNotAuthenticated?: boolean;
23
-
24
- /**
25
- * Verify userId matches current user
26
- * Default: true
27
- */
28
14
  readonly verifyUserId?: boolean;
29
-
30
- /**
31
- * User ID to verify (required if verifyUserId is true)
32
- */
33
15
  readonly userId?: string;
34
16
  }
35
17
 
@@ -48,9 +30,25 @@ export interface FirestoreQueryResult {
48
30
  readonly isAuthenticated: boolean;
49
31
  }
50
32
 
33
+ /**
34
+ * Create query result helper
35
+ */
36
+ function createResult(
37
+ shouldSkip: boolean,
38
+ authState: ReturnType<typeof checkAuthState>,
39
+ reason?: FirestoreQuerySkipReason
40
+ ): FirestoreQueryResult {
41
+ return {
42
+ shouldSkip,
43
+ reason,
44
+ userId: authState.userId,
45
+ isAnonymous: authState.isAnonymous,
46
+ isAuthenticated: authState.isAuthenticated,
47
+ };
48
+ }
49
+
51
50
  /**
52
51
  * Check if Firestore query should be skipped
53
- * Centralized logic for all Firestore operations
54
52
  */
55
53
  export function shouldSkipFirestoreQuery(
56
54
  auth: Auth | null,
@@ -64,79 +62,30 @@ export function shouldSkipFirestoreQuery(
64
62
  } = options;
65
63
 
66
64
  try {
67
- // No auth available
68
65
  if (!auth) {
69
- return {
70
- shouldSkip: true,
71
- reason: "no_auth",
72
- userId: null,
73
- isAnonymous: false,
74
- isAuthenticated: false,
75
- };
66
+ return createResult(true, checkAuthState(null), "no_auth");
76
67
  }
77
68
 
78
- // Check auth state
79
69
  const authState = checkAuthState(auth);
80
70
 
81
- // Not authenticated
82
- if (!authState.isAuthenticated) {
83
- if (skipIfNotAuthenticated) {
84
- return {
85
- shouldSkip: true,
86
- reason: "not_authenticated",
87
- userId: null,
88
- isAnonymous: false,
89
- isAuthenticated: false,
90
- };
91
- }
71
+ if (!authState.isAuthenticated && skipIfNotAuthenticated) {
72
+ return createResult(true, authState, "not_authenticated");
92
73
  }
93
74
 
94
- // Anonymous user
95
- if (authState.isAnonymous) {
96
- if (skipForGuest) {
97
- return {
98
- shouldSkip: true,
99
- reason: "is_guest",
100
- userId: authState.userId,
101
- isAnonymous: true,
102
- isAuthenticated: false,
103
- };
104
- }
75
+ if (authState.isAnonymous && skipForGuest) {
76
+ return createResult(true, authState, "is_guest");
105
77
  }
106
78
 
107
- // Verify userId if provided
108
- if (shouldVerify && userId) {
109
- if (!verifyUserId(auth, userId)) {
110
- return {
111
- shouldSkip: true,
112
- reason: "user_id_mismatch",
113
- userId: authState.userId,
114
- isAnonymous: authState.isAnonymous,
115
- isAuthenticated: authState.isAuthenticated,
116
- };
117
- }
79
+ if (shouldVerify && userId && !verifyUserId(auth, userId)) {
80
+ return createResult(true, authState, "user_id_mismatch");
118
81
  }
119
82
 
120
- // Don't skip
121
- return {
122
- shouldSkip: false,
123
- userId: authState.userId,
124
- isAnonymous: authState.isAnonymous,
125
- isAuthenticated: authState.isAuthenticated,
126
- };
83
+ return createResult(false, authState);
127
84
  } catch (error) {
128
- if (typeof __DEV__ !== "undefined" && __DEV__) {
129
- // eslint-disable-next-line no-console
130
- console.error("[FirestoreUtils] Error checking if query should be skipped", error);
85
+ if (__DEV__) {
86
+ console.error("[FirestoreUtils] Error checking query", error);
131
87
  }
132
-
133
- return {
134
- shouldSkip: true,
135
- reason: "invalid_options",
136
- userId: null,
137
- isAnonymous: false,
138
- isAuthenticated: false,
139
- };
88
+ return createResult(true, checkAuthState(null), "invalid_options");
140
89
  }
141
90
  }
142
91
 
@@ -1,9 +1,6 @@
1
1
  /**
2
2
  * useSocialAuth Hook
3
3
  * Provides Google and Apple Sign-In functionality
4
- *
5
- * Note: This hook handles the Firebase authentication part.
6
- * The OAuth flow (expo-auth-session for Google) should be set up in the consuming app.
7
4
  */
8
5
 
9
6
  import { useState, useCallback, useEffect } from "react";
@@ -14,54 +11,45 @@ import {
14
11
  } from "../../infrastructure/services/google-auth.service";
15
12
  import { appleAuthService } from "../../infrastructure/services/apple-auth.service";
16
13
 
17
- /**
18
- * Social auth configuration
19
- */
20
14
  export interface SocialAuthConfig {
21
15
  google?: GoogleAuthConfig;
22
16
  apple?: { enabled: boolean };
23
17
  }
24
18
 
25
- /**
26
- * Social auth result
27
- */
28
19
  export interface SocialAuthResult {
29
20
  success: boolean;
30
21
  isNewUser?: boolean;
31
22
  error?: string;
32
23
  }
33
24
 
34
- /**
35
- * Hook result
36
- */
37
25
  export interface UseSocialAuthResult {
38
- /** Sign in with Google using ID token (call after OAuth flow) */
39
26
  signInWithGoogleToken: (idToken: string) => Promise<SocialAuthResult>;
40
- /** Sign in with Apple (handles full flow) */
41
27
  signInWithApple: () => Promise<SocialAuthResult>;
42
- /** Whether Google is loading */
43
28
  googleLoading: boolean;
44
- /** Whether Apple is loading */
45
29
  appleLoading: boolean;
46
- /** Whether Google is configured */
47
30
  googleConfigured: boolean;
48
- /** Whether Apple is available */
49
31
  appleAvailable: boolean;
50
32
  }
51
33
 
52
34
  /**
53
- * Hook for social authentication
54
- *
55
- * Usage:
56
- * 1. For Google: Set up expo-auth-session in your app, get idToken, then call signInWithGoogleToken
57
- * 2. For Apple: Just call signInWithApple (handles complete flow)
35
+ * Common sign-in wrapper
58
36
  */
37
+ async function signInWrapper(
38
+ signInFn: () => Promise<{ success: boolean; isNewUser?: boolean; error?: string }>
39
+ ): Promise<SocialAuthResult> {
40
+ const auth = getFirebaseAuth();
41
+ if (!auth) {
42
+ return { success: false, error: "Firebase Auth not initialized" };
43
+ }
44
+
45
+ return signInFn();
46
+ }
47
+
59
48
  export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
60
49
  const [googleLoading, setGoogleLoading] = useState(false);
61
50
  const [appleLoading, setAppleLoading] = useState(false);
62
51
  const [appleAvailable, setAppleAvailable] = useState(false);
63
52
 
64
- // Configure Google Auth
65
53
  const googleConfig = config?.google;
66
54
  const googleConfigured = !!(
67
55
  googleConfig?.webClientId ||
@@ -69,14 +57,12 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
69
57
  googleConfig?.androidClientId
70
58
  );
71
59
 
72
- // Configure Google service on mount
73
60
  useEffect(() => {
74
61
  if (googleConfig) {
75
62
  googleAuthService.configure(googleConfig);
76
63
  }
77
64
  }, [googleConfig]);
78
65
 
79
- // Check Apple availability on mount
80
66
  useEffect(() => {
81
67
  const checkApple = async () => {
82
68
  const available = await appleAuthService.isAvailable();
@@ -85,7 +71,6 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
85
71
  checkApple();
86
72
  }, [config?.apple?.enabled]);
87
73
 
88
- // Sign in with Google using ID token
89
74
  const signInWithGoogleToken = useCallback(
90
75
  async (idToken: string): Promise<SocialAuthResult> => {
91
76
  if (!googleConfigured) {
@@ -94,21 +79,9 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
94
79
 
95
80
  setGoogleLoading(true);
96
81
  try {
97
- const auth = getFirebaseAuth();
98
- if (!auth) {
99
- return { success: false, error: "Firebase Auth not initialized" };
100
- }
101
-
102
- const signInResult = await googleAuthService.signInWithIdToken(
103
- auth,
104
- idToken,
82
+ return await signInWrapper(() =>
83
+ googleAuthService.signInWithIdToken(getFirebaseAuth()!, idToken)
105
84
  );
106
-
107
- return {
108
- success: signInResult.success,
109
- isNewUser: signInResult.isNewUser,
110
- error: signInResult.error,
111
- };
112
85
  } catch (error) {
113
86
  return {
114
87
  success: false,
@@ -118,10 +91,9 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
118
91
  setGoogleLoading(false);
119
92
  }
120
93
  },
121
- [googleConfigured],
94
+ [googleConfigured]
122
95
  );
123
96
 
124
- // Sign in with Apple
125
97
  const signInWithApple = useCallback(async (): Promise<SocialAuthResult> => {
126
98
  if (!appleAvailable) {
127
99
  return { success: false, error: "Apple Sign-In is not available" };
@@ -129,18 +101,9 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
129
101
 
130
102
  setAppleLoading(true);
131
103
  try {
132
- const auth = getFirebaseAuth();
133
- if (!auth) {
134
- return { success: false, error: "Firebase Auth not initialized" };
135
- }
136
-
137
- const result = await appleAuthService.signIn(auth);
138
-
139
- return {
140
- success: result.success,
141
- isNewUser: result.isNewUser,
142
- error: result.error,
143
- };
104
+ return await signInWrapper(() =>
105
+ appleAuthService.signIn(getFirebaseAuth()!)
106
+ );
144
107
  } catch (error) {
145
108
  return {
146
109
  success: false,
@@ -3,20 +3,14 @@
3
3
  * Domain-Driven Design (DDD) Architecture
4
4
  */
5
5
 
6
- // =============================================================================
7
- // DOMAIN LAYER - Errors
8
- // =============================================================================
9
-
6
+ // Domain Errors
10
7
  export {
11
8
  FirebaseFirestoreError,
12
9
  FirebaseFirestoreInitializationError,
13
10
  FirebaseFirestoreQuotaError,
14
11
  } from './domain/errors/FirebaseFirestoreError';
15
12
 
16
- // =============================================================================
17
- // INFRASTRUCTURE LAYER - Firestore Client
18
- // =============================================================================
19
-
13
+ // Firestore Client
20
14
  export {
21
15
  initializeFirestore,
22
16
  getFirestore,
@@ -25,21 +19,14 @@ export {
25
19
  resetFirestoreClient,
26
20
  firestoreClient,
27
21
  } from './infrastructure/config/FirestoreClient';
28
-
29
22
  export type { Firestore } from './infrastructure/config/FirestoreClient';
30
23
 
31
- // =============================================================================
32
- // INFRASTRUCTURE LAYER - BaseRepository
33
- // =============================================================================
34
-
24
+ // Repositories
35
25
  export { BaseRepository } from './infrastructure/repositories/BaseRepository';
36
26
  export { BaseQueryRepository } from './infrastructure/repositories/BaseQueryRepository';
37
27
  export { BasePaginatedRepository } from './infrastructure/repositories/BasePaginatedRepository';
38
28
 
39
- // =============================================================================
40
- // UTILS - Date Utilities
41
- // =============================================================================
42
-
29
+ // Date Utilities
43
30
  export {
44
31
  isoToTimestamp,
45
32
  timestampToISO,
@@ -47,56 +34,38 @@ export {
47
34
  getCurrentISOString,
48
35
  } from './utils/dateUtils';
49
36
 
50
- // =============================================================================
51
- // UTILS - Query Builder
52
- // =============================================================================
53
-
37
+ // Query Builder
54
38
  export {
55
39
  buildQuery,
56
40
  createInFilter,
57
41
  createEqualFilter,
58
42
  } from './utils/query-builder';
59
-
60
43
  export type {
61
44
  QueryBuilderOptions,
62
45
  FieldFilter,
63
46
  } from './utils/query-builder';
64
47
 
65
- // =============================================================================
66
- // UTILS - Pagination
67
- // =============================================================================
68
-
48
+ // Pagination
69
49
  export {
70
50
  PaginationHelper,
71
51
  createPaginationHelper,
72
52
  } from './utils/pagination.helper';
73
-
74
53
  export type {
75
54
  PaginatedResult,
76
55
  PaginationParams,
77
56
  } from './types/pagination.types';
78
-
79
57
  export { EMPTY_PAGINATED_RESULT } from './types/pagination.types';
80
58
 
81
- // =============================================================================
82
- // UTILS - Document Mapper
83
- // =============================================================================
84
-
59
+ // Document Mapper
85
60
  export {
86
61
  DocumentMapperHelper,
87
62
  createDocumentMapper,
88
63
  } from './utils/document-mapper.helper';
89
64
 
90
- // =============================================================================
91
- // UTILS - Path Resolver
92
- // =============================================================================
93
-
65
+ // Path Resolver
94
66
  export { FirestorePathResolver } from './utils/path-resolver';
95
67
 
96
- // =============================================================================
97
- // DOMAIN LAYER - Constants
98
- // =============================================================================
99
-
68
+ // Domain Constants
100
69
  export {
101
70
  FREE_TIER_LIMITS,
102
71
  QUOTA_THRESHOLDS,
@@ -105,60 +74,43 @@ export {
105
74
  getRemainingQuota,
106
75
  } from './domain/constants/QuotaLimits';
107
76
 
108
- // =============================================================================
109
- // DOMAIN LAYER - Entities
110
- // =============================================================================
111
-
77
+ // Domain Entities
112
78
  export type {
113
79
  QuotaMetrics,
114
80
  QuotaLimits,
115
81
  QuotaStatus,
116
82
  } from './domain/entities/QuotaMetrics';
117
-
118
83
  export type {
119
84
  RequestLog,
120
85
  RequestStats,
121
86
  RequestType,
122
87
  } from './domain/entities/RequestLog';
123
88
 
124
- // =============================================================================
125
- // DOMAIN LAYER - Services
126
- // =============================================================================
127
-
89
+ // Domain Services
128
90
  export { QuotaCalculator } from './domain/services/QuotaCalculator';
129
91
 
130
- // =============================================================================
131
- // UTILS - Quota Error Detection
132
- // =============================================================================
133
-
92
+ // Quota Error Detection
134
93
  export {
135
94
  isQuotaError,
136
95
  isRetryableError,
137
96
  getQuotaErrorMessage,
138
97
  } from './utils/quota-error-detector.util';
139
98
 
140
- // =============================================================================
141
- // INFRASTRUCTURE LAYER - Middleware
142
- // =============================================================================
143
-
99
+ // Middleware
144
100
  export {
145
101
  QueryDeduplicationMiddleware,
146
102
  queryDeduplicationMiddleware,
147
103
  } from './infrastructure/middleware/QueryDeduplicationMiddleware';
148
-
149
104
  export {
150
105
  QuotaTrackingMiddleware,
151
106
  quotaTrackingMiddleware,
152
107
  } from './infrastructure/middleware/QuotaTrackingMiddleware';
153
108
 
154
- // =============================================================================
155
- // INFRASTRUCTURE LAYER - Services
156
- // =============================================================================
157
-
109
+ // Services
158
110
  export {
159
111
  RequestLoggerService,
160
112
  requestLoggerService,
161
113
  } from './infrastructure/services/RequestLoggerService';
162
114
 
163
- // Re-export Firestore types for convenience
115
+ // Re-export Firestore types
164
116
  export type { Timestamp } from 'firebase/firestore';
@@ -4,168 +4,81 @@
4
4
  * Automatically loads Firebase configuration from:
5
5
  * 1. expo-constants (Constants.expoConfig?.extra)
6
6
  * 2. Environment variables (process.env)
7
- *
8
- * This allows zero-configuration Firebase initialization.
9
7
  */
10
8
 
11
9
  import type { FirebaseConfig } from '../../domain/value-objects/FirebaseConfig';
12
10
 
13
- /**
14
- * Configuration source interface
15
- */
16
- interface ConfigSource {
17
- getApiKey(): string;
18
- getAuthDomain(): string;
19
- getProjectId(): string;
20
- getStorageBucket(): string;
21
- getMessagingSenderId(): string;
22
- getAppId(): string;
23
- }
11
+ type ConfigKey = 'apiKey' | 'authDomain' | 'projectId' | 'storageBucket' | 'messagingSenderId' | 'appId';
12
+
13
+ const EXPO_PREFIX = 'EXPO_PUBLIC_';
14
+ const ENV_KEYS: Record<ConfigKey, string[]> = {
15
+ apiKey: ['FIREBASE_API_KEY'],
16
+ authDomain: ['FIREBASE_AUTH_DOMAIN'],
17
+ projectId: ['FIREBASE_PROJECT_ID'],
18
+ storageBucket: ['FIREBASE_STORAGE_BUCKET'],
19
+ messagingSenderId: ['FIREBASE_MESSAGING_SENDER_ID'],
20
+ appId: ['FIREBASE_APP_ID'],
21
+ };
24
22
 
25
23
  /**
26
- * Expo Constants configuration source
24
+ * Get environment variable value
27
25
  */
28
- class ExpoConfigSource implements ConfigSource {
29
- private extra: any;
30
-
31
- constructor() {
32
- let Constants: any;
33
-
34
- try {
35
- Constants = require('expo-constants');
36
- } catch {
37
- // expo-constants not available
38
- }
39
-
40
- const expoConfig = Constants?.expoConfig || Constants?.default?.expoConfig;
41
- this.extra = expoConfig?.extra || {};
42
- }
43
-
44
- getApiKey(): string {
45
- return this.extra?.firebaseApiKey || '';
46
- }
47
-
48
- getAuthDomain(): string {
49
- return this.extra?.firebaseAuthDomain || '';
50
- }
51
-
52
- getProjectId(): string {
53
- return this.extra?.firebaseProjectId || '';
54
- }
55
-
56
- getStorageBucket(): string {
57
- return this.extra?.firebaseStorageBucket || '';
58
- }
59
-
60
- getMessagingSenderId(): string {
61
- return this.extra?.firebaseMessagingSenderId || '';
62
- }
63
-
64
- getAppId(): string {
65
- return this.extra?.firebaseAppId || '';
26
+ function getEnvValue(key: ConfigKey): string {
27
+ const keys = ENV_KEYS[key];
28
+ for (const envKey of keys) {
29
+ const value = process.env[`${EXPO_PREFIX}${envKey}`] || process.env[envKey];
30
+ if (value?.trim()) return value;
66
31
  }
32
+ return '';
67
33
  }
68
34
 
69
35
  /**
70
- * Environment variables configuration source
36
+ * Load configuration from expo-constants
71
37
  */
72
- class EnvironmentConfigSource implements ConfigSource {
73
- getApiKey(): string {
74
- return process.env.EXPO_PUBLIC_FIREBASE_API_KEY ||
75
- process.env.FIREBASE_API_KEY ||
76
- '';
77
- }
78
-
79
- getAuthDomain(): string {
80
- return process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN ||
81
- process.env.FIREBASE_AUTH_DOMAIN ||
82
- '';
83
- }
84
-
85
- getProjectId(): string {
86
- return process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID ||
87
- process.env.FIREBASE_PROJECT_ID ||
88
- '';
89
- }
90
-
91
- getStorageBucket(): string {
92
- return process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET ||
93
- process.env.FIREBASE_STORAGE_BUCKET ||
94
- '';
95
- }
96
-
97
- getMessagingSenderId(): string {
98
- return process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID ||
99
- process.env.FIREBASE_MESSAGING_SENDER_ID ||
100
- '';
101
- }
102
-
103
- getAppId(): string {
104
- return process.env.EXPO_PUBLIC_FIREBASE_APP_ID ||
105
- process.env.FIREBASE_APP_ID ||
106
- '';
38
+ function loadExpoConfig(): Record<string, string> {
39
+ try {
40
+ const Constants = require('expo-constants');
41
+ const expoConfig = Constants?.expoConfig || Constants?.default?.expoConfig;
42
+ return expoConfig?.extra || {};
43
+ } catch {
44
+ return {};
107
45
  }
108
46
  }
109
47
 
110
48
  /**
111
- * Configuration aggregator
49
+ * Get config value from expo constants
112
50
  */
113
- class ConfigAggregator {
114
- private sources: ConfigSource[];
115
-
116
- constructor() {
117
- this.sources = [
118
- new ExpoConfigSource(),
119
- new EnvironmentConfigSource(),
120
- ];
121
- }
122
-
123
- /**
124
- * Get configuration value from first available source
125
- */
126
- private getValue(getter: (source: ConfigSource) => string): string {
127
- for (const source of this.sources) {
128
- const value = getter(source);
129
- if (value && value.trim() !== '') {
130
- return value;
131
- }
132
- }
133
- return '';
134
- }
135
-
136
- /**
137
- * Build Firebase configuration from all sources
138
- */
139
- buildConfig(): Partial<FirebaseConfig> {
140
- return {
141
- apiKey: this.getValue(source => source.getApiKey()),
142
- authDomain: this.getValue(source => source.getAuthDomain()),
143
- projectId: this.getValue(source => source.getProjectId()),
144
- storageBucket: this.getValue(source => source.getStorageBucket()),
145
- messagingSenderId: this.getValue(source => source.getMessagingSenderId()),
146
- appId: this.getValue(source => source.getAppId()),
147
- };
148
- }
51
+ function getExpoValue(key: ConfigKey, expoConfig: Record<string, string>): string {
52
+ const mapping: Record<ConfigKey, string> = {
53
+ apiKey: 'firebaseApiKey',
54
+ authDomain: 'firebaseAuthDomain',
55
+ projectId: 'firebaseProjectId',
56
+ storageBucket: 'firebaseStorageBucket',
57
+ messagingSenderId: 'firebaseMessagingSenderId',
58
+ appId: 'firebaseAppId',
59
+ };
60
+ return expoConfig[mapping[key]] || '';
149
61
  }
150
62
 
151
63
  /**
152
64
  * Load Firebase configuration from Constants and environment variables
153
- * Returns null if no valid configuration is found
154
65
  */
155
66
  export function loadFirebaseConfig(): FirebaseConfig | null {
156
- const aggregator = new ConfigAggregator();
157
- const config = aggregator.buildConfig();
67
+ const expoConfig = loadExpoConfig();
68
+
69
+ const config: Partial<Record<ConfigKey, string>> = {};
70
+ const keys: ConfigKey[] = ['apiKey', 'authDomain', 'projectId', 'storageBucket', 'messagingSenderId', 'appId'];
71
+
72
+ for (const key of keys) {
73
+ const expoValue = getExpoValue(key, expoConfig);
74
+ config[key] = expoValue || getEnvValue(key);
75
+ }
158
76
 
159
- // Only return config if required fields are present and not empty
160
- if (
161
- config.apiKey &&
162
- config.projectId &&
163
- config.apiKey.trim() !== '' &&
164
- config.projectId.trim() !== ''
165
- ) {
166
- return config as FirebaseConfig;
77
+ // Validate required fields
78
+ if (!config.apiKey?.trim() || !config.projectId?.trim()) {
79
+ return null;
167
80
  }
168
81
 
169
- return null;
82
+ return config as FirebaseConfig;
170
83
  }
171
84