@umituz/react-native-firebase 1.13.148 → 1.13.150

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.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/src/auth/infrastructure/services/apple-auth.service.ts +10 -2
  3. package/src/auth/infrastructure/services/google-auth.service.ts +10 -2
  4. package/src/auth/infrastructure/services/reauthentication.service.ts +5 -1
  5. package/src/auth/presentation/hooks/shared/auth-hooks.util.ts +60 -0
  6. package/src/auth/presentation/hooks/shared/hook-utils.util.ts +14 -216
  7. package/src/auth/presentation/hooks/shared/safe-state-hooks.util.ts +76 -0
  8. package/src/auth/presentation/hooks/shared/state-hooks.util.ts +97 -0
  9. package/src/domain/utils/async-executor.util.ts +16 -169
  10. package/src/domain/utils/error-handler.util.ts +18 -170
  11. package/src/domain/utils/error-handlers/error-checkers.ts +120 -0
  12. package/src/domain/utils/error-handlers/error-converters.ts +48 -0
  13. package/src/domain/utils/error-handlers/error-messages.ts +18 -0
  14. package/src/domain/utils/executors/advanced-executors.util.ts +59 -0
  15. package/src/domain/utils/executors/basic-executors.util.ts +56 -0
  16. package/src/domain/utils/executors/batch-executors.util.ts +42 -0
  17. package/src/domain/utils/executors/error-converters.util.ts +45 -0
  18. package/src/domain/utils/result/result-creators.ts +49 -0
  19. package/src/domain/utils/result/result-helpers.ts +60 -0
  20. package/src/domain/utils/result/result-types.ts +40 -0
  21. package/src/domain/utils/result.util.ts +28 -127
  22. package/src/domain/utils/validation.util.ts +38 -209
  23. package/src/domain/utils/validators/composite.validator.ts +24 -0
  24. package/src/domain/utils/validators/firebase.validator.ts +45 -0
  25. package/src/domain/utils/validators/generic.validator.ts +59 -0
  26. package/src/domain/utils/validators/string.validator.ts +25 -0
  27. package/src/domain/utils/validators/url.validator.ts +36 -0
  28. package/src/domain/utils/validators/user-input.validator.ts +54 -0
  29. package/src/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +10 -3
  30. package/src/firestore/utils/deduplication/timer-manager.util.ts +2 -2
  31. package/src/firestore/utils/pagination.helper.ts +3 -1
  32. package/src/infrastructure/config/FirebaseClient.ts +28 -189
  33. package/src/infrastructure/config/clients/FirebaseClientSingleton.ts +82 -0
  34. package/src/infrastructure/config/services/FirebaseInitializationService.ts +115 -0
  35. package/src/init/createFirebaseInitModule.ts +9 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-firebase",
3
- "version": "1.13.148",
3
+ "version": "1.13.150",
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",
@@ -75,10 +75,18 @@ export class AppleAuthService {
75
75
  });
76
76
 
77
77
  const userCredential = await signInWithCredential(auth, credential);
78
+
79
+ // Check if user is new by comparing metadata timestamps
80
+ // Convert to timestamps for reliable comparison (string comparison can be unreliable)
81
+ const creationTime = userCredential.user.metadata.creationTime;
82
+ const lastSignInTime = userCredential.user.metadata.lastSignInTime;
83
+ const isNewUser = creationTime && lastSignInTime
84
+ ? new Date(creationTime).getTime() === new Date(lastSignInTime).getTime()
85
+ : false;
86
+
78
87
  return {
79
88
  userCredential,
80
- isNewUser: userCredential.user.metadata.creationTime ===
81
- userCredential.user.metadata.lastSignInTime
89
+ isNewUser
82
90
  };
83
91
  });
84
92
 
@@ -46,10 +46,18 @@ export class GoogleAuthService extends ConfigurableService<GoogleAuthConfig> {
46
46
  const result = await executeAuthOperation(async () => {
47
47
  const credential = GoogleAuthProvider.credential(idToken);
48
48
  const userCredential = await signInWithCredential(auth, credential);
49
+
50
+ // Check if user is new by comparing metadata timestamps
51
+ // Convert to timestamps for reliable comparison (string comparison can be unreliable)
52
+ const creationTime = userCredential.user.metadata.creationTime;
53
+ const lastSignInTime = userCredential.user.metadata.lastSignInTime;
54
+ const isNewUser = creationTime && lastSignInTime
55
+ ? new Date(creationTime).getTime() === new Date(lastSignInTime).getTime()
56
+ : false;
57
+
49
58
  return {
50
59
  userCredential,
51
- isNewUser: userCredential.user.metadata.creationTime ===
52
- userCredential.user.metadata.lastSignInTime
60
+ isNewUser
53
61
  };
54
62
  });
55
63
  return this.convertToGoogleAuthResult(result);
@@ -99,7 +99,11 @@ export async function getAppleReauthCredential(): Promise<ReauthCredentialResult
99
99
  };
100
100
  } catch (error: unknown) {
101
101
  const err = error instanceof Error ? error : new Error(String(error));
102
- const code = isCancelledError({ code: '', message: err.message }) ? "auth/cancelled" : "auth/failed";
102
+ const errorInfo = {
103
+ code: (err as { code?: string }).code ?? '',
104
+ message: err.message
105
+ };
106
+ const code = isCancelledError(errorInfo) ? "auth/cancelled" : "auth/failed";
103
107
  return {
104
108
  success: false,
105
109
  error: { code, message: err.message }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Auth-Specific Hooks
3
+ * React hooks for Firebase Auth state management
4
+ */
5
+
6
+ import { useRef, useEffect, useCallback } from 'react';
7
+ import { onAuthStateChanged, type Auth, type User } from 'firebase/auth';
8
+
9
+ /**
10
+ * Create an auth state handler
11
+ */
12
+ export function createAuthStateHandler(
13
+ setState: (user: User | null) => void,
14
+ setLoading: (loading: boolean) => void,
15
+ setError: (error: Error | null) => void
16
+ ): (user: User | null) => void {
17
+ return (user: User | null) => {
18
+ try {
19
+ setState(user);
20
+ setError(null);
21
+ } catch (err) {
22
+ const error = err instanceof Error ? err : new Error('Auth state update failed');
23
+ setError(error);
24
+ } finally {
25
+ setLoading(false);
26
+ }
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Hook for managing auth listener lifecycle
32
+ */
33
+ export function useAuthListener(
34
+ auth: Auth | null,
35
+ onAuthStateChange: (user: User | null) => void
36
+ ): void {
37
+ const unsubscribeRef = useRef<(() => void) | null>(null);
38
+
39
+ useEffect(() => {
40
+ // Cleanup previous listener
41
+ if (unsubscribeRef.current) {
42
+ unsubscribeRef.current();
43
+ unsubscribeRef.current = null;
44
+ }
45
+
46
+ if (!auth) {
47
+ onAuthStateChange(null);
48
+ return;
49
+ }
50
+
51
+ unsubscribeRef.current = onAuthStateChanged(auth, onAuthStateChange);
52
+
53
+ return () => {
54
+ if (unsubscribeRef.current) {
55
+ unsubscribeRef.current();
56
+ unsubscribeRef.current = null;
57
+ }
58
+ };
59
+ }, [auth, onAuthStateChange]);
60
+ }
@@ -1,222 +1,20 @@
1
1
  /**
2
2
  * Shared Hook Utilities
3
- * Common utilities and patterns for React hooks
4
- * Reduces code duplication across presentation hooks
3
+ * Re-exports all hook utilities for backward compatibility
4
+ * @deprecated Import from specific files instead
5
5
  */
6
6
 
7
- import { useState, useCallback, useRef, useEffect } from 'react';
8
- import { onAuthStateChanged, type Auth, type User } from 'firebase/auth';
7
+ // State Management Hooks
8
+ export type { HookState, HookStateActions } from './state-hooks.util';
9
+ export { useHookState, useAsyncOperation } from './state-hooks.util';
9
10
 
10
- /**
11
- * Hook state management result
12
- */
13
- export interface HookState<T> {
14
- value: T;
15
- loading: boolean;
16
- error: Error | null;
17
- }
18
-
19
- /**
20
- * Hook state actions
21
- */
22
- export interface HookStateActions<T> {
23
- setValue: (value: T) => void;
24
- setLoading: (loading: boolean) => void;
25
- setError: (error: Error | null) => void;
26
- clearError: () => void;
27
- reset: () => void;
28
- }
29
-
30
- /**
31
- * Create a stateful hook with loading and error handling
32
- */
33
- export function useHookState<T>(
34
- initialValue: T
35
- ): [HookState<T>, HookStateActions<T>] {
36
- const [value, setValue] = useState<T>(initialValue);
37
- const [loading, setLoading] = useState<boolean>(false);
38
- const [error, setError] = useState<Error | null>(null);
39
-
40
- const clearError = useCallback(() => {
41
- setError(null);
42
- }, []);
43
-
44
- const reset = useCallback(() => {
45
- setValue(initialValue);
46
- setLoading(false);
47
- setError(null);
48
- }, [initialValue]);
49
-
50
- const state: HookState<T> = { value, loading, error };
51
- const actions: HookStateActions<T> = {
52
- setValue,
53
- setLoading,
54
- setError,
55
- clearError,
56
- reset,
57
- };
58
-
59
- return [state, actions];
60
- }
61
-
62
- /**
63
- * Hook for managing cleanup callbacks
64
- */
65
- export function useCleanup(
66
- cleanupFn: () => void,
67
- deps: React.DependencyList = []
68
- ): void {
69
- useEffect(() => {
70
- return () => {
71
- cleanupFn();
72
- };
73
- }, deps);
74
- }
75
-
76
- /**
77
- * Hook for managing async operation state
78
- */
79
- export function useAsyncOperation<T = void>() {
80
- const [loading, setLoading] = useState<boolean>(false);
81
- const [error, setError] = useState<Error | null>(null);
82
- const operationRef = useRef<Promise<T> | null>(null);
83
-
84
- const execute = useCallback(async (operation: () => Promise<T>): Promise<T> => {
85
- setLoading(true);
86
- setError(null);
87
-
88
- try {
89
- const promise = operation();
90
- operationRef.current = promise;
91
- const result = await promise;
92
- return result;
93
- } catch (err) {
94
- const error = err instanceof Error ? err : new Error(String(err));
95
- setError(error);
96
- throw error;
97
- } finally {
98
- setLoading(false);
99
- operationRef.current = null;
100
- }
101
- }, []);
102
-
103
- const clearError = useCallback(() => {
104
- setError(null);
105
- }, []);
106
-
107
- return {
108
- loading,
109
- error,
110
- execute,
111
- clearError,
112
- };
113
- }
114
-
115
- /**
116
- * Hook for debounced value updates
117
- */
118
- export function useDebouncedValue<T>(value: T, delayMs: number): T {
119
- const [debouncedValue, setDebouncedValue] = useState<T>(value);
120
-
121
- useEffect(() => {
122
- const handler = setTimeout(() => {
123
- setDebouncedValue(value);
124
- }, delayMs);
125
-
126
- return () => {
127
- clearTimeout(handler);
128
- };
129
- }, [value, delayMs]);
130
-
131
- return debouncedValue;
132
- }
133
-
134
- /**
135
- * Hook for tracking mounted state
136
- */
137
- export function useIsMounted(): () => boolean {
138
- const isMountedRef = useRef<boolean>(true);
139
-
140
- useEffect(() => {
141
- isMountedRef.current = true;
142
- return () => {
143
- isMountedRef.current = false;
144
- };
145
- }, []);
146
-
147
- return useCallback(() => isMountedRef.current, []);
148
- }
149
-
150
- /**
151
- * Hook for safe state updates (only if mounted)
152
- */
153
- export function useSafeState<T>(
154
- initialValue: T
155
- ): [T, (value: T | ((prev: T) => T)) => void] {
156
- const isMounted = useIsMounted();
157
- const [state, setState] = useState<T>(initialValue);
158
-
159
- const setSafeState = useCallback(
160
- (value: T | ((prev: T) => T)) => {
161
- if (isMounted()) {
162
- setState(value);
163
- }
164
- },
165
- [isMounted]
166
- );
167
-
168
- return [state, setSafeState];
169
- }
170
-
171
- /**
172
- * Create an auth state handler
173
- */
174
- export function createAuthStateHandler(
175
- setState: (user: User | null) => void,
176
- setLoading: (loading: boolean) => void,
177
- setError: (error: Error | null) => void
178
- ): (user: User | null) => void {
179
- return (user: User | null) => {
180
- try {
181
- setState(user);
182
- setError(null);
183
- } catch (err) {
184
- const error = err instanceof Error ? err : new Error('Auth state update failed');
185
- setError(error);
186
- } finally {
187
- setLoading(false);
188
- }
189
- };
190
- }
191
-
192
- /**
193
- * Hook for managing auth listener lifecycle
194
- */
195
- export function useAuthListener(
196
- auth: Auth | null,
197
- onAuthStateChange: (user: User | null) => void
198
- ): void {
199
- const unsubscribeRef = useRef<(() => void) | null>(null);
200
-
201
- useEffect(() => {
202
- // Cleanup previous listener
203
- if (unsubscribeRef.current) {
204
- unsubscribeRef.current();
205
- unsubscribeRef.current = null;
206
- }
207
-
208
- if (!auth) {
209
- onAuthStateChange(null);
210
- return;
211
- }
212
-
213
- unsubscribeRef.current = onAuthStateChanged(auth, onAuthStateChange);
11
+ // Safe State Hooks
12
+ export {
13
+ useIsMounted,
14
+ useSafeState,
15
+ useDebouncedValue,
16
+ useCleanup,
17
+ } from './safe-state-hooks.util';
214
18
 
215
- return () => {
216
- if (unsubscribeRef.current) {
217
- unsubscribeRef.current();
218
- unsubscribeRef.current = null;
219
- }
220
- };
221
- }, [auth, onAuthStateChange]);
222
- }
19
+ // Auth Hooks
20
+ export { createAuthStateHandler, useAuthListener } from './auth-hooks.util';
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Safe State Hooks
3
+ * React hooks for safe state management and mounted state tracking
4
+ */
5
+
6
+ import { useState, useCallback, useRef, useEffect } from 'react';
7
+
8
+ /**
9
+ * Hook for tracking mounted state
10
+ */
11
+ export function useIsMounted(): () => boolean {
12
+ const isMountedRef = useRef<boolean>(true);
13
+
14
+ useEffect(() => {
15
+ isMountedRef.current = true;
16
+ return () => {
17
+ isMountedRef.current = false;
18
+ };
19
+ }, []);
20
+
21
+ return useCallback(() => isMountedRef.current, []);
22
+ }
23
+
24
+ /**
25
+ * Hook for safe state updates (only if mounted)
26
+ */
27
+ export function useSafeState<T>(
28
+ initialValue: T
29
+ ): [T, (value: T | ((prev: T) => T)) => void] {
30
+ const isMounted = useIsMounted();
31
+ const [state, setState] = useState<T>(initialValue);
32
+
33
+ const setSafeState = useCallback(
34
+ (value: T | ((prev: T) => T)) => {
35
+ if (isMounted()) {
36
+ setState(value);
37
+ }
38
+ },
39
+ [isMounted]
40
+ );
41
+
42
+ return [state, setSafeState];
43
+ }
44
+
45
+ /**
46
+ * Hook for debounced value updates
47
+ */
48
+ export function useDebouncedValue<T>(value: T, delayMs: number): T {
49
+ const [debouncedValue, setDebouncedValue] = useState<T>(value);
50
+
51
+ useEffect(() => {
52
+ const handler = setTimeout(() => {
53
+ setDebouncedValue(value);
54
+ }, delayMs);
55
+
56
+ return () => {
57
+ clearTimeout(handler);
58
+ };
59
+ }, [value, delayMs]);
60
+
61
+ return debouncedValue;
62
+ }
63
+
64
+ /**
65
+ * Hook for managing cleanup callbacks
66
+ */
67
+ export function useCleanup(
68
+ cleanupFn: () => void,
69
+ deps: React.DependencyList = []
70
+ ): void {
71
+ useEffect(() => {
72
+ return () => {
73
+ cleanupFn();
74
+ };
75
+ }, deps);
76
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * State Management Hooks
3
+ * React hooks for managing component state with loading and error handling
4
+ */
5
+
6
+ import { useState, useCallback, useRef } from 'react';
7
+
8
+ /**
9
+ * Hook state management result
10
+ */
11
+ export interface HookState<T> {
12
+ value: T;
13
+ loading: boolean;
14
+ error: Error | null;
15
+ }
16
+
17
+ /**
18
+ * Hook state actions
19
+ */
20
+ export interface HookStateActions<T> {
21
+ setValue: (value: T) => void;
22
+ setLoading: (loading: boolean) => void;
23
+ setError: (error: Error | null) => void;
24
+ clearError: () => void;
25
+ reset: () => void;
26
+ }
27
+
28
+ /**
29
+ * Create a stateful hook with loading and error handling
30
+ */
31
+ export function useHookState<T>(
32
+ initialValue: T
33
+ ): [HookState<T>, HookStateActions<T>] {
34
+ const [value, setValue] = useState<T>(initialValue);
35
+ const [loading, setLoading] = useState<boolean>(false);
36
+ const [error, setError] = useState<Error | null>(null);
37
+
38
+ const clearError = useCallback(() => {
39
+ setError(null);
40
+ }, []);
41
+
42
+ const reset = useCallback(() => {
43
+ setValue(initialValue);
44
+ setLoading(false);
45
+ setError(null);
46
+ }, [initialValue]);
47
+
48
+ const state: HookState<T> = { value, loading, error };
49
+ const actions: HookStateActions<T> = {
50
+ setValue,
51
+ setLoading,
52
+ setError,
53
+ clearError,
54
+ reset,
55
+ };
56
+
57
+ return [state, actions];
58
+ }
59
+
60
+ /**
61
+ * Hook for managing async operation state
62
+ */
63
+ export function useAsyncOperation<T = void>() {
64
+ const [loading, setLoading] = useState<boolean>(false);
65
+ const [error, setError] = useState<Error | null>(null);
66
+ const operationRef = useRef<Promise<T> | null>(null);
67
+
68
+ const execute = useCallback(async (operation: () => Promise<T>): Promise<T> => {
69
+ setLoading(true);
70
+ setError(null);
71
+
72
+ try {
73
+ const promise = operation();
74
+ operationRef.current = promise;
75
+ const result = await promise;
76
+ return result;
77
+ } catch (err) {
78
+ const error = err instanceof Error ? err : new Error(String(err));
79
+ setError(error);
80
+ throw error;
81
+ } finally {
82
+ setLoading(false);
83
+ operationRef.current = null;
84
+ }
85
+ }, []);
86
+
87
+ const clearError = useCallback(() => {
88
+ setError(null);
89
+ }, []);
90
+
91
+ return {
92
+ loading,
93
+ error,
94
+ execute,
95
+ clearError,
96
+ };
97
+ }