@umituz/react-native-firebase 2.4.43 → 2.4.45

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": "2.4.43",
3
+ "version": "2.4.45",
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",
@@ -35,12 +35,7 @@ export class FirebaseAuthInitializer {
35
35
  }
36
36
 
37
37
  private static handleInitializationError(error: unknown, app: FirebaseApp): Auth | null {
38
- const errorCode = (error as { code?: string })?.code;
39
-
40
- if (errorCode === 'auth/already-initialized') {
41
- return this.getExistingAuth(app);
42
- }
43
-
38
+ // Any initialization error: try to get existing auth instance
44
39
  return this.getExistingAuth(app);
45
40
  }
46
41
 
@@ -21,16 +21,24 @@ import { isNewUser as checkIsNewUser } from "../../domain/utils/user-metadata.ut
21
21
  import { convertToOAuthResult } from "./utils/auth-result-converter.util";
22
22
 
23
23
  // Conditional import - expo-apple-authentication is optional
24
- let AppleAuthentication: any = null;
24
+ interface AppleAuthModule {
25
+ isAvailableAsync: () => Promise<boolean>;
26
+ signInAsync: (options: {
27
+ requestedScopes: number[];
28
+ nonce: string;
29
+ }) => Promise<{ identityToken: string | null }>;
30
+ AppleAuthenticationScope: { FULL_NAME: number; EMAIL: number };
31
+ }
32
+
33
+ let AppleAuthentication: AppleAuthModule | null = null;
25
34
  let isAppleAuthAvailable = false;
26
35
 
27
36
  try {
28
37
  // eslint-disable-next-line @typescript-eslint/no-require-imports
29
- AppleAuthentication = require("expo-apple-authentication");
38
+ AppleAuthentication = require("expo-apple-authentication") as AppleAuthModule;
30
39
  isAppleAuthAvailable = true;
31
40
  } catch {
32
41
  // expo-apple-authentication not available - this is fine if not using Apple auth
33
- console.info("expo-apple-authentication is not installed. Apple authentication will not be available.");
34
42
  }
35
43
 
36
44
  export class AppleAuthService {
@@ -67,6 +75,10 @@ export class AppleAuthService {
67
75
  }
68
76
 
69
77
  const result = await executeAuthOperation(async () => {
78
+ if (!AppleAuthentication) {
79
+ throw new Error("Apple authentication module not loaded");
80
+ }
81
+
70
82
  const nonce = await generateNonce();
71
83
  const hashedNonce = await hashNonce(nonce);
72
84
 
@@ -9,21 +9,21 @@ import type { GoogleAuthResult } from "./google-auth.types";
9
9
  import { googleAuthService } from "./google-auth.service";
10
10
 
11
11
  // Conditional import - expo-web-browser is optional
12
- let ExpoWebBrowser: any = null;
12
+ interface ExpoWebBrowserModule {
13
+ maybeCompleteAuthSession: () => { type: string };
14
+ }
15
+
16
+ let ExpoWebBrowser: ExpoWebBrowserModule | null = null;
13
17
  let isExpoAuthAvailable = false;
14
18
 
15
19
  try {
16
20
  // eslint-disable-next-line @typescript-eslint/no-require-imports
17
- ExpoWebBrowser = require("expo-web-browser");
21
+ ExpoWebBrowser = require("expo-web-browser") as ExpoWebBrowserModule;
18
22
  isExpoAuthAvailable = true;
19
23
 
20
- // Complete auth session if available
21
- if (ExpoWebBrowser?.maybeCompleteAuthSession) {
22
- ExpoWebBrowser.maybeCompleteAuthSession();
23
- }
24
+ ExpoWebBrowser.maybeCompleteAuthSession();
24
25
  } catch {
25
26
  // expo-web-browser not available - this is fine if not using Google OAuth
26
- console.info("expo-web-browser is not installed. Google OAuth will not be available.");
27
27
  }
28
28
 
29
29
  export interface GoogleOAuthConfig {
@@ -10,12 +10,25 @@ import { getFirebaseAuth } from "../../infrastructure/config/FirebaseAuthClient"
10
10
  import type { GoogleOAuthConfig } from "../../infrastructure/services/google-oauth.service";
11
11
 
12
12
  // Conditional import for expo-auth-session
13
- let ExpoAuthSession: any = null;
13
+ interface AuthSessionResponse {
14
+ type: string;
15
+ authentication?: { idToken?: string } | null;
16
+ }
17
+
18
+ interface ExpoAuthSessionModule {
19
+ useAuthRequest: (config: {
20
+ iosClientId: string;
21
+ webClientId: string;
22
+ androidClientId: string;
23
+ }) => [unknown, AuthSessionResponse | null, (() => Promise<AuthSessionResponse>) | null];
24
+ }
25
+
26
+ let ExpoAuthSession: ExpoAuthSessionModule | null = null;
14
27
  let isExpoAuthAvailable = false;
15
28
 
16
29
  try {
17
30
  // eslint-disable-next-line @typescript-eslint/no-require-imports
18
- ExpoAuthSession = require("expo-auth-session/providers/google");
31
+ ExpoAuthSession = require("expo-auth-session/providers/google") as ExpoAuthSessionModule;
19
32
  isExpoAuthAvailable = true;
20
33
  } catch {
21
34
  // expo-auth-session not available - hook will return unavailable state
@@ -50,7 +63,7 @@ export function useGoogleOAuth(config?: GoogleOAuthConfig): UseGoogleOAuthResult
50
63
 
51
64
  // Call the Hook directly (only valid in React component)
52
65
  // If expo-auth-session is not available, these will be null
53
- const [request, response, promptAsync] = isExpoAuthAvailable && ExpoAuthSession?.useAuthRequest
66
+ const [request, response, promptAsync] = isExpoAuthAvailable && ExpoAuthSession
54
67
  ? ExpoAuthSession.useAuthRequest({
55
68
  iosClientId: config?.iosClientId || PLACEHOLDER_CLIENT_ID,
56
69
  webClientId: config?.webClientId || PLACEHOLDER_CLIENT_ID,
@@ -82,12 +82,11 @@ export abstract class BasePaginatedRepository extends BaseQueryRepository {
82
82
 
83
83
  return this.executeQuery(
84
84
  collectionName,
85
- q,
86
85
  async () => {
87
86
  const snapshot = await getDocs(q);
88
87
  return snapshot.docs;
89
88
  },
90
- false, // Default to false as we don't know yet
89
+ false,
91
90
  uniqueKey
92
91
  );
93
92
  }
@@ -5,8 +5,6 @@
5
5
  * Extends BaseRepository with query-specific functionality.
6
6
  */
7
7
 
8
- import type { Query } from "firebase/firestore";
9
- import { quotaTrackingMiddleware } from "../middleware/QuotaTrackingMiddleware";
10
8
  import { queryDeduplicationMiddleware } from "../middleware/QueryDeduplicationMiddleware";
11
9
  import { BaseRepository } from "./BaseRepository";
12
10
 
@@ -14,72 +12,27 @@ export abstract class BaseQueryRepository extends BaseRepository {
14
12
  /**
15
13
  * Execute query with deduplication and quota tracking
16
14
  * Prevents duplicate queries and tracks quota usage
17
- *
18
- * @param collection - Collection name
19
- * @param query - Firestore query (kept for interface compatibility)
20
- * @param queryFn - Function to execute the query
21
- * @param cached - Whether the result is from cache
22
- * @param uniqueKey - Unique key for deduplication (critical for correct caching)
23
- * @returns Query result
24
15
  */
25
16
  protected async executeQuery<T>(
26
17
  collection: string,
27
- _query: Query,
28
18
  queryFn: () => Promise<T>,
29
19
  cached: boolean = false,
30
20
  uniqueKey?: string
31
21
  ): Promise<T> {
32
- // Use provided uniqueKey, or generate a stable key based on collection
33
- // IMPORTANT: Don't use Date.now() as it defeats deduplication!
34
22
  const safeKey = uniqueKey || `${collection}_query`;
35
23
 
36
24
  const queryKey = {
37
25
  collection,
38
- filters: safeKey, // Use the unique key as the filter identifier
26
+ filters: safeKey,
39
27
  limit: undefined,
40
28
  orderBy: undefined,
41
29
  };
42
30
 
43
31
  return queryDeduplicationMiddleware.deduplicate(queryKey, async () => {
44
- // Execute the query function
45
32
  const result = await queryFn();
46
-
47
- // Track the operation after successful execution
48
- // We calculate count based on result if possible, otherwise default to 1 (for list/count queries)
49
33
  const count = Array.isArray(result) ? result.length : 1;
50
-
51
34
  this.trackRead(collection, count, cached);
52
-
53
35
  return result;
54
36
  });
55
37
  }
56
-
57
- /**
58
- * Track read operation
59
- *
60
- * @param collection - Collection name
61
- * @param count - Number of documents read
62
- * @param cached - Whether the result is from cache
63
- */
64
- protected trackRead(
65
- collection: string,
66
- count: number = 1,
67
- cached: boolean = false,
68
- ): void {
69
- quotaTrackingMiddleware.trackRead(collection, count, cached);
70
- }
71
-
72
- protected trackWrite(
73
- collection: string,
74
- count: number = 1,
75
- ): void {
76
- quotaTrackingMiddleware.trackWrite(collection, count);
77
- }
78
-
79
- protected trackDelete(
80
- collection: string,
81
- count: number = 1,
82
- ): void {
83
- quotaTrackingMiddleware.trackDelete(collection, count);
84
- }
85
38
  }
package/src/index.ts CHANGED
@@ -34,21 +34,6 @@ export type {
34
34
 
35
35
  export type { FirebaseApp } from "./shared/infrastructure/config/initializers/FirebaseAppInitializer";
36
36
 
37
- import { FirebaseClientSingleton } from "./shared/infrastructure/config/clients/FirebaseClientSingleton";
38
-
39
- function getFirebaseClientSafe(): FirebaseClientSingleton | null {
40
- try {
41
- return FirebaseClientSingleton.getInstance();
42
- } catch {
43
- if (__DEV__) {
44
- console.warn('[Firebase] Could not create Firebase client singleton — Firebase may not be configured.');
45
- }
46
- return null;
47
- }
48
- }
49
-
50
- export const firebaseClient = getFirebaseClientSafe();
51
-
52
37
  // Type Guards
53
38
  export {
54
39
  isFirestoreError,