@umituz/react-native-firebase 1.13.161 → 1.13.163

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.161",
3
+ "version": "1.13.163",
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",
@@ -50,7 +50,11 @@ export async function deleteCurrentUser(
50
50
  const code = authErr?.code ?? "auth/failed";
51
51
  const message = authErr?.message ?? "Account deletion failed";
52
52
 
53
- if (code === "auth/requires-recent-login" && (options.autoReauthenticate || options.password || options.googleIdToken)) {
53
+ // Determine if we should attempt reauthentication
54
+ const hasCredentials = !!(options.password || options.googleIdToken);
55
+ const shouldReauth = options.autoReauthenticate === true || hasCredentials;
56
+
57
+ if (code === "auth/requires-recent-login" && shouldReauth) {
54
58
  const reauth = await attemptReauth(user, options);
55
59
  if (reauth) return reauth;
56
60
  }
@@ -93,7 +97,10 @@ async function attemptReauth(user: User, options: AccountDeletionOptions): Promi
93
97
 
94
98
  if (res.success) {
95
99
  try {
96
- await deleteUser(user);
100
+ // After reauthentication, get fresh user reference from auth
101
+ const auth = getFirebaseAuth();
102
+ const currentUser = auth?.currentUser || user;
103
+ await deleteUser(currentUser);
97
104
  return successResult();
98
105
  } catch (err: unknown) {
99
106
  const authErr = err instanceof Error ? (err as { code?: string; message?: string }) : null;
@@ -22,9 +22,10 @@ let AppleAuthentication: any = null;
22
22
  let isAppleAuthAvailable = false;
23
23
 
24
24
  try {
25
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
25
26
  AppleAuthentication = require("expo-apple-authentication");
26
27
  isAppleAuthAvailable = true;
27
- } catch (error) {
28
+ } catch {
28
29
  // expo-apple-authentication not available - this is fine if not using Apple auth
29
30
  console.info("expo-apple-authentication is not installed. Apple authentication will not be available.");
30
31
  }
@@ -6,7 +6,7 @@
6
6
  import { onIdTokenChanged, type User } from "firebase/auth";
7
7
  import { getFirebaseAuth } from "../config/FirebaseAuthClient";
8
8
  import type { Result } from "../../../domain/utils";
9
- import { successResult, failureResultFrom } from "../../../domain/utils";
9
+ import { failureResultFrom } from "../../../domain/utils";
10
10
 
11
11
  export interface AuthListenerConfig {
12
12
  /**
@@ -82,11 +82,17 @@ export async function signUpWithEmail(
82
82
  );
83
83
  }
84
84
 
85
- // Update display name if provided
85
+ // Update display name if provided (non-critical operation)
86
86
  if (credentials.displayName && userCredential.user) {
87
- await updateProfile(userCredential.user, {
88
- displayName: credentials.displayName.trim(),
89
- });
87
+ try {
88
+ await updateProfile(userCredential.user, {
89
+ displayName: credentials.displayName.trim(),
90
+ });
91
+ } catch (profileError) {
92
+ // Profile update failed but account was created successfully
93
+ // Log the error but don't fail the signup
94
+ console.warn("Profile update failed after account creation:", profileError);
95
+ }
90
96
  }
91
97
 
92
98
  return { success: true, data: userCredential.user };
@@ -8,13 +8,12 @@ import type { Auth } from "firebase/auth";
8
8
  import type { GoogleAuthResult } from "./google-auth.types";
9
9
  import { googleAuthService } from "./google-auth.service";
10
10
 
11
- // Conditional imports - these packages are optional
12
- let ExpoAuthSession: any = null;
11
+ // Conditional import - expo-web-browser is optional
13
12
  let ExpoWebBrowser: any = null;
14
13
  let isExpoAuthAvailable = false;
15
14
 
16
15
  try {
17
- ExpoAuthSession = require("expo-auth-session/providers/google");
16
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
18
17
  ExpoWebBrowser = require("expo-web-browser");
19
18
  isExpoAuthAvailable = true;
20
19
 
@@ -22,9 +21,9 @@ try {
22
21
  if (ExpoWebBrowser?.maybeCompleteAuthSession) {
23
22
  ExpoWebBrowser.maybeCompleteAuthSession();
24
23
  }
25
- } catch (error) {
26
- // expo-auth-session not available - this is fine if not using Google OAuth
27
- console.info("expo-auth-session is not installed. Google OAuth will not be available.");
24
+ } catch {
25
+ // 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.");
28
27
  }
29
28
 
30
29
  export interface GoogleOAuthConfig {
@@ -33,12 +32,6 @@ export interface GoogleOAuthConfig {
33
32
  androidClientId?: string;
34
33
  }
35
34
 
36
- export interface GoogleOAuthHookResult {
37
- request: any;
38
- response: any;
39
- promptAsync: (() => Promise<any>) | null;
40
- }
41
-
42
35
  const PLACEHOLDER_CLIENT_ID = "000000000000-placeholder.apps.googleusercontent.com";
43
36
 
44
37
  function validateGoogleConfig(config?: GoogleOAuthConfig): boolean {
@@ -69,41 +62,6 @@ export class GoogleOAuthService {
69
62
  return validateGoogleConfig(config);
70
63
  }
71
64
 
72
- /**
73
- * Create auth request hook
74
- * This mimics the behavior of expo-auth-session's useAuthRequest hook
75
- */
76
- createAuthRequest(config?: GoogleOAuthConfig): GoogleOAuthHookResult {
77
- if (!isExpoAuthAvailable || !ExpoAuthSession?.useAuthRequest) {
78
- return {
79
- request: null,
80
- response: null,
81
- promptAsync: null,
82
- };
83
- }
84
-
85
- try {
86
- const [request, response, promptAsync] = ExpoAuthSession.useAuthRequest({
87
- iosClientId: config?.iosClientId || PLACEHOLDER_CLIENT_ID,
88
- webClientId: config?.webClientId || PLACEHOLDER_CLIENT_ID,
89
- androidClientId: config?.androidClientId || PLACEHOLDER_CLIENT_ID,
90
- });
91
-
92
- return {
93
- request: request ?? null,
94
- response: response ?? null,
95
- promptAsync: promptAsync ?? null,
96
- };
97
- } catch (error) {
98
- console.error("Failed to create Google auth request:", error);
99
- return {
100
- request: null,
101
- response: null,
102
- promptAsync: null,
103
- };
104
- }
105
- }
106
-
107
65
  /**
108
66
  * Sign in with Google using OAuth flow
109
67
  */
@@ -9,6 +9,18 @@ import { googleOAuthService } from "../../infrastructure/services/google-oauth.s
9
9
  import { getFirebaseAuth } from "../../infrastructure/config/FirebaseAuthClient";
10
10
  import type { GoogleOAuthConfig } from "../../infrastructure/services/google-oauth.service";
11
11
 
12
+ // Conditional import for expo-auth-session
13
+ let ExpoAuthSession: any = null;
14
+ let isExpoAuthAvailable = false;
15
+
16
+ try {
17
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
18
+ ExpoAuthSession = require("expo-auth-session/providers/google");
19
+ isExpoAuthAvailable = true;
20
+ } catch {
21
+ // expo-auth-session not available - hook will return unavailable state
22
+ }
23
+
12
24
  export interface UseGoogleOAuthResult {
13
25
  signInWithGoogle: () => Promise<SocialAuthResult>;
14
26
  googleLoading: boolean;
@@ -23,6 +35,8 @@ export interface SocialAuthResult {
23
35
  error?: string;
24
36
  }
25
37
 
38
+ const PLACEHOLDER_CLIENT_ID = "000000000000-placeholder.apps.googleusercontent.com";
39
+
26
40
  /**
27
41
  * Hook for Google OAuth authentication
28
42
  * Requires expo-auth-session and expo-web-browser to be installed
@@ -34,9 +48,15 @@ export function useGoogleOAuth(config?: GoogleOAuthConfig): UseGoogleOAuthResult
34
48
  const googleAvailable = googleOAuthService.isAvailable();
35
49
  const googleConfigured = googleOAuthService.isConfigured(config);
36
50
 
37
- // Create auth request - this will return null values if expo-auth-session is not available
38
- const authRequest = googleOAuthService.createAuthRequest(config);
39
- const { request, response, promptAsync } = authRequest;
51
+ // Call the Hook directly (only valid in React component)
52
+ // If expo-auth-session is not available, these will be null
53
+ const [request, response, promptAsync] = isExpoAuthAvailable && ExpoAuthSession?.useAuthRequest
54
+ ? ExpoAuthSession.useAuthRequest({
55
+ iosClientId: config?.iosClientId || PLACEHOLDER_CLIENT_ID,
56
+ webClientId: config?.webClientId || PLACEHOLDER_CLIENT_ID,
57
+ androidClientId: config?.androidClientId || PLACEHOLDER_CLIENT_ID,
58
+ })
59
+ : [null, null, null];
40
60
 
41
61
  // Handle OAuth response
42
62
  useEffect(() => {
@@ -62,9 +62,6 @@ export {
62
62
  createDocumentMapper,
63
63
  } from './utils/document-mapper.helper';
64
64
 
65
- // Path Resolver
66
- export { FirestorePathResolver } from './utils/path-resolver';
67
-
68
65
  // Domain Constants
69
66
  export {
70
67
  FREE_TIER_LIMITS,
@@ -50,11 +50,11 @@ export abstract class BaseRepository {
50
50
  * @param userId User identifier
51
51
  * @returns CollectionReference or null if db not initialized
52
52
  */
53
- protected getUserCollection(userId: string): CollectionReference<DocumentData> | null {
53
+ protected getUserCollection = (userId: string): CollectionReference<DocumentData> | null => {
54
54
  const db = this.getDb();
55
55
  if (!db) return null;
56
56
  return collection(db, 'users', userId, this.collectionName);
57
- }
57
+ };
58
58
 
59
59
  /**
60
60
  * Get document reference
@@ -64,11 +64,11 @@ export abstract class BaseRepository {
64
64
  * @param documentId Document identifier
65
65
  * @returns DocumentReference or null if db not initialized
66
66
  */
67
- protected getDocRef(userId: string, documentId: string): DocumentReference<DocumentData> | null {
67
+ protected getDocRef = (userId: string, documentId: string): DocumentReference<DocumentData> | null => {
68
68
  const db = this.getDb();
69
69
  if (!db) return null;
70
70
  return doc(db, 'users', userId, this.collectionName, documentId);
71
- }
71
+ };
72
72
 
73
73
  /**
74
74
  * Check if Firestore is initialized
@@ -84,13 +84,11 @@ export abstract class BaseRepository {
84
84
 
85
85
  /**
86
86
  * Execute operation with error handling
87
- * @param collection - Collection name for tracking
88
87
  * @param operation - Operation to execute
89
88
  * @returns Operation result
90
89
  * @throws Error if operation fails
91
90
  */
92
91
  protected async executeOperation<T>(
93
- collection: string,
94
92
  operation: () => Promise<T>
95
93
  ): Promise<T> {
96
94
  if (this.state === RepositoryState.DESTROYED) {
@@ -111,27 +109,6 @@ export abstract class BaseRepository {
111
109
  }
112
110
  }
113
111
 
114
- /**
115
- * Track read operation
116
- */
117
- protected trackRead(_collection: string, _count: number = 1): void {
118
- // Quota tracking delegated to middleware
119
- }
120
-
121
- /**
122
- * Track write operation
123
- */
124
- protected trackWrite(_collection: string, _count: number = 1): void {
125
- // Quota tracking delegated to middleware
126
- }
127
-
128
- /**
129
- * Track delete operation
130
- */
131
- protected trackDelete(_collection: string, _count: number = 1): void {
132
- // Quota tracking delegated to middleware
133
- }
134
-
135
112
  /**
136
113
  * Destroy the repository
137
114
  * Prevents further operations
package/src/index.ts CHANGED
@@ -62,7 +62,6 @@ export {
62
62
  BaseRepository,
63
63
  BaseQueryRepository,
64
64
  BasePaginatedRepository,
65
- FirestorePathResolver,
66
65
  } from "./firestore";
67
66
  export * from "./firestore";
68
67
  export { Timestamp } from "firebase/firestore";
@@ -1,44 +0,0 @@
1
- import type { Firestore, CollectionReference, DocumentReference, DocumentData } from "firebase/firestore";
2
- import { collection, doc } from "firebase/firestore";
3
-
4
- /**
5
- * Resolves Firestore paths for user collections
6
- * Standard pattern: users/{userId}/{collectionName}
7
- *
8
- * Stateless design: db is passed to methods, not stored in constructor
9
- * This eliminates initialization timing issues and makes testing easier
10
- * This class is designed to be used across hundreds of apps.
11
- * All user data MUST be under users/{userId}/ for consistency.
12
- */
13
- export class FirestorePathResolver {
14
- constructor(
15
- private readonly collectionName: string,
16
- ) { }
17
-
18
- /**
19
- * Get collection reference for a user
20
- * Pattern: users/{userId}/{collectionName}
21
- *
22
- * @param db Firestore instance
23
- * @param userId User identifier
24
- * @returns CollectionReference or null if db not initialized
25
- */
26
- getUserCollection(db: Firestore | null, userId: string): CollectionReference<DocumentData> | null {
27
- if (!db) return null;
28
- return collection(db, "users", userId, this.collectionName);
29
- }
30
-
31
- /**
32
- * Get document reference for a specific item
33
- * Pattern: users/{userId}/{collectionName}/{documentId}
34
- *
35
- * @param db Firestore instance
36
- * @param userId User identifier
37
- * @param documentId Document identifier
38
- * @returns DocumentReference or null if db not initialized
39
- */
40
- getDocRef(db: Firestore | null, userId: string, documentId: string): DocumentReference<DocumentData> | null {
41
- if (!db) return null;
42
- return doc(db, "users", userId, this.collectionName, documentId);
43
- }
44
- }