@umituz/react-native-firebase 1.13.106 → 1.13.107
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 +1 -1
- package/src/auth/infrastructure/config/FirebaseAuthClient.ts +13 -7
- package/src/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +0 -2
- package/src/auth/infrastructure/services/account-deletion.service.ts +23 -12
- package/src/auth/infrastructure/services/anonymous-auth.service.ts +1 -9
- package/src/auth/infrastructure/services/apple-auth.service.ts +2 -1
- package/src/auth/infrastructure/services/auth-guard.service.ts +2 -1
- package/src/auth/infrastructure/services/firestore-utils.service.ts +0 -2
- package/src/auth/infrastructure/services/password.service.ts +4 -3
- package/src/auth/infrastructure/services/reauthentication.service.ts +21 -9
- package/src/auth/infrastructure/stores/auth.store.ts +2 -4
- package/src/auth/presentation/hooks/useAnonymousAuth.ts +0 -2
- package/src/auth/presentation/hooks/useSocialAuth.ts +6 -2
- package/src/auth/presentation/hooks/utils/auth-state-change.handler.ts +0 -2
- package/src/domain/errors/FirebaseError.ts +3 -3
- package/src/firestore/infrastructure/config/FirestoreClient.ts +1 -2
- package/src/firestore/infrastructure/config/initializers/FirebaseFirestoreInitializer.ts +1 -5
- package/src/firestore/infrastructure/middleware/QueryDeduplicationMiddleware.ts +1 -1
- package/src/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +0 -2
- package/src/firestore/infrastructure/repositories/BasePaginatedRepository.ts +2 -2
- package/src/firestore/infrastructure/repositories/BaseRepository.ts +3 -3
- package/src/firestore/infrastructure/services/RequestLoggerService.ts +2 -2
- package/src/firestore/utils/firestore-helper.ts +0 -2
- package/src/global.d.ts +5 -0
- package/src/infrastructure/config/FirebaseClient.ts +1 -4
- package/src/infrastructure/config/FirebaseConfigLoader.ts +2 -2
- package/src/infrastructure/config/initializers/FirebaseAppInitializer.ts +5 -3
- package/src/infrastructure/config/orchestrators/FirebaseInitializationOrchestrator.ts +0 -2
- package/src/infrastructure/config/services/FirebaseServiceInitializer.ts +0 -2
- package/src/init/createFirebaseInitModule.ts +2 -4
- package/src/storage/deleter.ts +5 -5
- package/src/storage/uploader.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-firebase",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.107",
|
|
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",
|
|
@@ -7,8 +7,6 @@ import { getFirebaseApp } from '../../../infrastructure/config/FirebaseClient';
|
|
|
7
7
|
import { FirebaseAuthInitializer } from './initializers/FirebaseAuthInitializer';
|
|
8
8
|
import type { FirebaseAuthConfig } from '../../domain/value-objects/FirebaseAuthConfig';
|
|
9
9
|
|
|
10
|
-
declare const __DEV__: boolean;
|
|
11
|
-
|
|
12
10
|
class FirebaseAuthClientSingleton {
|
|
13
11
|
private static instance: FirebaseAuthClientSingleton | null = null;
|
|
14
12
|
private auth: Auth | null = null;
|
|
@@ -28,9 +26,10 @@ class FirebaseAuthClientSingleton {
|
|
|
28
26
|
if (!app) return null;
|
|
29
27
|
this.auth = FirebaseAuthInitializer.initialize(app, config);
|
|
30
28
|
return this.auth;
|
|
31
|
-
} catch (error:
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
} catch (error: unknown) {
|
|
30
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
31
|
+
if (__DEV__) console.error('[FirebaseAuth] Init error:', message);
|
|
32
|
+
this.initializationError = message;
|
|
34
33
|
return null;
|
|
35
34
|
}
|
|
36
35
|
}
|
|
@@ -40,14 +39,21 @@ class FirebaseAuthClientSingleton {
|
|
|
40
39
|
return this.auth;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
getInitializationError(): string | null {
|
|
43
|
+
return this.initializationError;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
reset(): void {
|
|
47
|
+
this.auth = null;
|
|
48
|
+
this.initializationError = null;
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
export const firebaseAuthClient = FirebaseAuthClientSingleton.getInstance();
|
|
47
53
|
export const initializeFirebaseAuth = (c?: FirebaseAuthConfig) => firebaseAuthClient.initialize(c);
|
|
48
54
|
export const getFirebaseAuth = () => firebaseAuthClient.getAuth();
|
|
49
55
|
export const isFirebaseAuthInitialized = () => firebaseAuthClient.getAuth() !== null;
|
|
50
|
-
export const getFirebaseAuthInitializationError = () => firebaseAuthClient.
|
|
56
|
+
export const getFirebaseAuthInitializationError = () => firebaseAuthClient.getInitializationError();
|
|
51
57
|
export const resetFirebaseAuthClient = () => firebaseAuthClient.reset();
|
|
52
58
|
|
|
53
59
|
export type { Auth } from 'firebase/auth';
|
|
@@ -17,8 +17,6 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
17
17
|
import type { FirebaseApp } from 'firebase/app';
|
|
18
18
|
import type { FirebaseAuthConfig } from '../../../domain/value-objects/FirebaseAuthConfig';
|
|
19
19
|
|
|
20
|
-
declare const __DEV__: boolean;
|
|
21
|
-
|
|
22
20
|
/**
|
|
23
21
|
* Initializes Firebase Auth
|
|
24
22
|
* Platform-agnostic: Works on all platforms (Web, iOS, Android)
|
|
@@ -14,15 +14,23 @@ import type { AccountDeletionResult, AccountDeletionOptions } from "./reauthenti
|
|
|
14
14
|
|
|
15
15
|
export type { AccountDeletionResult, AccountDeletionOptions } from "./reauthentication.types";
|
|
16
16
|
|
|
17
|
+
function toAuthError(error: unknown): { code: string; message: string } {
|
|
18
|
+
const err = error as { code?: string; message?: string };
|
|
19
|
+
return {
|
|
20
|
+
code: err.code || "auth/failed",
|
|
21
|
+
message: err.message || "Unknown error",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
export async function deleteCurrentUser(
|
|
18
26
|
options: AccountDeletionOptions = { autoReauthenticate: true }
|
|
19
27
|
): Promise<AccountDeletionResult> {
|
|
20
28
|
const auth = getFirebaseAuth();
|
|
21
29
|
const user = auth?.currentUser;
|
|
22
30
|
|
|
23
|
-
if (!auth || !user) return {
|
|
24
|
-
success: false,
|
|
25
|
-
error: { code: "auth/not-ready", message: "Auth not ready", requiresReauth: false }
|
|
31
|
+
if (!auth || !user) return {
|
|
32
|
+
success: false,
|
|
33
|
+
error: { code: "auth/not-ready", message: "Auth not ready", requiresReauth: false }
|
|
26
34
|
};
|
|
27
35
|
if (user.isAnonymous) return {
|
|
28
36
|
success: false,
|
|
@@ -32,21 +40,22 @@ export async function deleteCurrentUser(
|
|
|
32
40
|
try {
|
|
33
41
|
await deleteUser(user);
|
|
34
42
|
return { success: true };
|
|
35
|
-
} catch (error:
|
|
36
|
-
|
|
43
|
+
} catch (error: unknown) {
|
|
44
|
+
const authErr = toAuthError(error);
|
|
45
|
+
if (authErr.code === "auth/requires-recent-login" && (options.autoReauthenticate || options.password || options.googleIdToken)) {
|
|
37
46
|
const reauth = await attemptReauth(user, options);
|
|
38
47
|
if (reauth) return reauth;
|
|
39
48
|
}
|
|
40
49
|
return {
|
|
41
50
|
success: false,
|
|
42
|
-
error: {
|
|
51
|
+
error: { ...authErr, requiresReauth: authErr.code === "auth/requires-recent-login" }
|
|
43
52
|
};
|
|
44
53
|
}
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
async function attemptReauth(user: User, options: AccountDeletionOptions): Promise<AccountDeletionResult | null> {
|
|
48
57
|
const provider = getUserAuthProvider(user);
|
|
49
|
-
let res: { success: boolean
|
|
58
|
+
let res: { success: boolean; error?: { code?: string; message?: string } };
|
|
50
59
|
|
|
51
60
|
if (provider === "apple.com") res = await reauthenticateWithApple(user);
|
|
52
61
|
else if (provider === "google.com") {
|
|
@@ -61,11 +70,12 @@ async function attemptReauth(user: User, options: AccountDeletionOptions): Promi
|
|
|
61
70
|
try {
|
|
62
71
|
await deleteUser(user);
|
|
63
72
|
return { success: true };
|
|
64
|
-
} catch (err:
|
|
65
|
-
|
|
73
|
+
} catch (err: unknown) {
|
|
74
|
+
const authErr = toAuthError(err);
|
|
75
|
+
return { success: false, error: { ...authErr, requiresReauth: false } };
|
|
66
76
|
}
|
|
67
77
|
}
|
|
68
|
-
return { success: false, error: { code: res.error?.code || "auth/reauth-failed", message: res.error?.message, requiresReauth: true } };
|
|
78
|
+
return { success: false, error: { code: res.error?.code || "auth/reauth-failed", message: res.error?.message || "Reauth failed", requiresReauth: true } };
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
export async function deleteUserAccount(user: User): Promise<AccountDeletionResult> {
|
|
@@ -73,7 +83,8 @@ export async function deleteUserAccount(user: User): Promise<AccountDeletionResu
|
|
|
73
83
|
try {
|
|
74
84
|
await deleteUser(user);
|
|
75
85
|
return { success: true };
|
|
76
|
-
} catch (error:
|
|
77
|
-
|
|
86
|
+
} catch (error: unknown) {
|
|
87
|
+
const authErr = toAuthError(error);
|
|
88
|
+
return { success: false, error: { ...authErr, requiresReauth: authErr.code === "auth/requires-recent-login" } };
|
|
78
89
|
}
|
|
79
90
|
}
|
|
@@ -22,15 +22,7 @@ export class AnonymousAuthService implements AnonymousAuthServiceInterface {
|
|
|
22
22
|
|
|
23
23
|
const currentUser = auth.currentUser;
|
|
24
24
|
|
|
25
|
-
if (currentUser
|
|
26
|
-
return {
|
|
27
|
-
user: currentUser,
|
|
28
|
-
anonymousUser: toAnonymousUser(currentUser),
|
|
29
|
-
wasAlreadySignedIn: true,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (currentUser && currentUser.isAnonymous) {
|
|
25
|
+
if (currentUser) {
|
|
34
26
|
return {
|
|
35
27
|
user: currentUser,
|
|
36
28
|
anonymousUser: toAnonymousUser(currentUser),
|
|
@@ -25,7 +25,8 @@ export class AppleAuthService {
|
|
|
25
25
|
if (Platform.OS !== "ios") return false;
|
|
26
26
|
try {
|
|
27
27
|
return await AppleAuthentication.isAvailableAsync();
|
|
28
|
-
} catch {
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (__DEV__) console.warn('[AppleAuth] isAvailable check failed:', error);
|
|
29
30
|
return false;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -52,7 +52,8 @@ export class AuthGuardService {
|
|
|
52
52
|
async getAuthenticatedUserId(): Promise<string | null> {
|
|
53
53
|
try {
|
|
54
54
|
return await this.requireAuthenticatedUser();
|
|
55
|
-
} catch {
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (__DEV__) console.warn('[AuthGuard] getAuthenticatedUserId:', error);
|
|
56
57
|
return null;
|
|
57
58
|
}
|
|
58
59
|
}
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
import type { Auth } from "firebase/auth";
|
|
7
7
|
import { checkAuthState, verifyUserId } from "./auth-utils.service";
|
|
8
8
|
|
|
9
|
-
declare const __DEV__: boolean;
|
|
10
|
-
|
|
11
9
|
export interface FirestoreQueryOptions {
|
|
12
10
|
readonly skipForGuest?: boolean;
|
|
13
11
|
readonly skipIfNotAuthenticated?: boolean;
|
|
@@ -24,12 +24,13 @@ export async function updateUserPassword(user: User, newPassword: string): Promi
|
|
|
24
24
|
try {
|
|
25
25
|
await updatePassword(user, newPassword);
|
|
26
26
|
return { success: true };
|
|
27
|
-
} catch (error:
|
|
27
|
+
} catch (error: unknown) {
|
|
28
|
+
const err = error as { code?: string; message?: string };
|
|
28
29
|
return {
|
|
29
30
|
success: false,
|
|
30
31
|
error: {
|
|
31
|
-
code:
|
|
32
|
-
message:
|
|
32
|
+
code: err.code || 'auth/password-update-failed',
|
|
33
|
+
message: err.message || 'Failed to update password',
|
|
33
34
|
},
|
|
34
35
|
};
|
|
35
36
|
}
|
|
@@ -25,6 +25,14 @@ export type {
|
|
|
25
25
|
ReauthCredentialResult
|
|
26
26
|
} from "./reauthentication.types";
|
|
27
27
|
|
|
28
|
+
function toAuthError(error: unknown): { code: string; message: string } {
|
|
29
|
+
const err = error as { code?: string; message?: string };
|
|
30
|
+
return {
|
|
31
|
+
code: err.code || "auth/failed",
|
|
32
|
+
message: err.message || "Unknown error",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
export function getUserAuthProvider(user: User): AuthProviderType {
|
|
29
37
|
if (user.isAnonymous) return "anonymous";
|
|
30
38
|
const data = user.providerData;
|
|
@@ -39,8 +47,9 @@ export async function reauthenticateWithGoogle(user: User, idToken: string): Pro
|
|
|
39
47
|
try {
|
|
40
48
|
await reauthenticateWithCredential(user, GoogleAuthProvider.credential(idToken));
|
|
41
49
|
return { success: true };
|
|
42
|
-
} catch (error:
|
|
43
|
-
|
|
50
|
+
} catch (error: unknown) {
|
|
51
|
+
const err = toAuthError(error);
|
|
52
|
+
return { success: false, error: err };
|
|
44
53
|
}
|
|
45
54
|
}
|
|
46
55
|
|
|
@@ -49,8 +58,9 @@ export async function reauthenticateWithPassword(user: User, pass: string): Prom
|
|
|
49
58
|
try {
|
|
50
59
|
await reauthenticateWithCredential(user, EmailAuthProvider.credential(user.email, pass));
|
|
51
60
|
return { success: true };
|
|
52
|
-
} catch (error:
|
|
53
|
-
|
|
61
|
+
} catch (error: unknown) {
|
|
62
|
+
const err = toAuthError(error);
|
|
63
|
+
return { success: false, error: err };
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
66
|
|
|
@@ -69,9 +79,10 @@ export async function getAppleReauthCredential(): Promise<ReauthCredentialResult
|
|
|
69
79
|
|
|
70
80
|
if (!apple.identityToken) return { success: false, error: { code: "auth/no-token", message: "No token" } };
|
|
71
81
|
return { success: true, credential: new OAuthProvider("apple.com").credential({ idToken: apple.identityToken, rawNonce: nonce }) };
|
|
72
|
-
} catch (error:
|
|
73
|
-
const
|
|
74
|
-
|
|
82
|
+
} catch (error: unknown) {
|
|
83
|
+
const err = toAuthError(error);
|
|
84
|
+
const code = err.message.includes("ERR_CANCELED") ? "auth/cancelled" : err.code;
|
|
85
|
+
return { success: false, error: { code, message: err.message } };
|
|
75
86
|
}
|
|
76
87
|
}
|
|
77
88
|
|
|
@@ -81,7 +92,8 @@ export async function reauthenticateWithApple(user: User): Promise<Reauthenticat
|
|
|
81
92
|
try {
|
|
82
93
|
await reauthenticateWithCredential(user, res.credential);
|
|
83
94
|
return { success: true };
|
|
84
|
-
} catch (error:
|
|
85
|
-
|
|
95
|
+
} catch (error: unknown) {
|
|
96
|
+
const err = toAuthError(error);
|
|
97
|
+
return { success: false, error: err };
|
|
86
98
|
}
|
|
87
99
|
}
|
|
@@ -10,8 +10,6 @@
|
|
|
10
10
|
import { createStore, type SetState, type GetState } from "@umituz/react-native-design-system";
|
|
11
11
|
import { onAuthStateChanged, type User, type Auth } from "firebase/auth";
|
|
12
12
|
|
|
13
|
-
declare const __DEV__: boolean;
|
|
14
|
-
|
|
15
13
|
interface AuthState {
|
|
16
14
|
user: User | null;
|
|
17
15
|
loading: boolean;
|
|
@@ -52,7 +50,7 @@ export const useFirebaseAuthStore = createStore<AuthState, AuthActions>({
|
|
|
52
50
|
|
|
53
51
|
try {
|
|
54
52
|
unsubscribe = onAuthStateChanged(auth, (currentUser: User | null) => {
|
|
55
|
-
if (
|
|
53
|
+
if (__DEV__) {
|
|
56
54
|
console.log(
|
|
57
55
|
"[FirebaseAuthStore] Auth state changed:",
|
|
58
56
|
currentUser?.uid || "null"
|
|
@@ -71,7 +69,7 @@ export const useFirebaseAuthStore = createStore<AuthState, AuthActions>({
|
|
|
71
69
|
// On error, release the mutex so retry is possible
|
|
72
70
|
setupInProgress = false;
|
|
73
71
|
set({ listenerSetup: false });
|
|
74
|
-
if (
|
|
72
|
+
if (__DEV__) {
|
|
75
73
|
console.error("[FirebaseAuthStore] Failed to setup listener:", error);
|
|
76
74
|
}
|
|
77
75
|
}
|
|
@@ -9,8 +9,6 @@ import type { AuthCheckResult } from "../../infrastructure/services/auth-utils.s
|
|
|
9
9
|
import { anonymousAuthService, type AnonymousAuthResult } from "../../infrastructure/services/anonymous-auth.service";
|
|
10
10
|
import { createAuthStateChangeHandler, userToAuthCheckResult } from "./utils/auth-state-change.handler";
|
|
11
11
|
|
|
12
|
-
declare const __DEV__: boolean;
|
|
13
|
-
|
|
14
12
|
export interface UseAnonymousAuthResult extends AuthCheckResult {
|
|
15
13
|
/**
|
|
16
14
|
* Sign in anonymously
|
|
@@ -79,8 +79,10 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
|
|
|
79
79
|
|
|
80
80
|
setGoogleLoading(true);
|
|
81
81
|
try {
|
|
82
|
+
const auth = getFirebaseAuth();
|
|
83
|
+
if (!auth) return { success: false, error: "Firebase Auth not initialized" };
|
|
82
84
|
return await signInWrapper(() =>
|
|
83
|
-
googleAuthService.signInWithIdToken(
|
|
85
|
+
googleAuthService.signInWithIdToken(auth, idToken)
|
|
84
86
|
);
|
|
85
87
|
} catch (error) {
|
|
86
88
|
return {
|
|
@@ -101,8 +103,10 @@ export function useSocialAuth(config?: SocialAuthConfig): UseSocialAuthResult {
|
|
|
101
103
|
|
|
102
104
|
setAppleLoading(true);
|
|
103
105
|
try {
|
|
106
|
+
const auth = getFirebaseAuth();
|
|
107
|
+
if (!auth) return { success: false, error: "Firebase Auth not initialized" };
|
|
104
108
|
return await signInWrapper(() =>
|
|
105
|
-
appleAuthService.signIn(
|
|
109
|
+
appleAuthService.signIn(auth)
|
|
106
110
|
);
|
|
107
111
|
} catch (error) {
|
|
108
112
|
return {
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
import type { User } from 'firebase/auth';
|
|
7
7
|
import type { AuthCheckResult } from '../../../infrastructure/services/auth-utils.service';
|
|
8
8
|
|
|
9
|
-
declare const __DEV__: boolean;
|
|
10
|
-
|
|
11
9
|
/**
|
|
12
10
|
* Convert Firebase User to AuthCheckResult
|
|
13
11
|
* @param user - Firebase user or null
|
|
@@ -12,7 +12,7 @@ if (__DEV__) {
|
|
|
12
12
|
* Base Firebase error class
|
|
13
13
|
*/
|
|
14
14
|
export class FirebaseError extends Error {
|
|
15
|
-
constructor(message: string, public code?: string, public cause?:
|
|
15
|
+
constructor(message: string, public code?: string, public cause?: unknown) {
|
|
16
16
|
super(message);
|
|
17
17
|
this.name = 'FirebaseError';
|
|
18
18
|
Object.setPrototypeOf(this, FirebaseError.prototype);
|
|
@@ -23,7 +23,7 @@ export class FirebaseError extends Error {
|
|
|
23
23
|
* Initialization specific error
|
|
24
24
|
*/
|
|
25
25
|
export class FirebaseInitializationError extends FirebaseError {
|
|
26
|
-
constructor(message: string, cause?:
|
|
26
|
+
constructor(message: string, cause?: unknown) {
|
|
27
27
|
super(message, 'INITIALIZATION_ERROR', cause);
|
|
28
28
|
this.name = 'FirebaseInitializationError';
|
|
29
29
|
Object.setPrototypeOf(this, FirebaseInitializationError.prototype);
|
|
@@ -34,7 +34,7 @@ export class FirebaseInitializationError extends FirebaseError {
|
|
|
34
34
|
* Configuration specific error
|
|
35
35
|
*/
|
|
36
36
|
export class FirebaseConfigurationError extends FirebaseError {
|
|
37
|
-
constructor(message: string, cause?:
|
|
37
|
+
constructor(message: string, cause?: unknown) {
|
|
38
38
|
super(message, 'CONFIGURATION_ERROR', cause);
|
|
39
39
|
this.name = 'FirebaseConfigurationError';
|
|
40
40
|
Object.setPrototypeOf(this, FirebaseConfigurationError.prototype);
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
* Use @umituz/react-native-firebase to initialize Firebase App.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("📍 [LIFECYCLE] FirestoreClient.ts - Module loading");
|
|
11
|
+
if (__DEV__) console.log("📍 [LIFECYCLE] FirestoreClient.ts - Module loading");
|
|
13
12
|
|
|
14
13
|
import type { Firestore } from 'firebase/firestore';
|
|
15
14
|
import { getFirebaseApp } from '../../../infrastructure/config/FirebaseClient';
|
|
@@ -33,12 +33,8 @@ export class FirebaseFirestoreInitializer {
|
|
|
33
33
|
return initializeFirestore(app, {
|
|
34
34
|
localCache: memoryLocalCache(),
|
|
35
35
|
});
|
|
36
|
-
} catch (error:
|
|
36
|
+
} catch (error: unknown) {
|
|
37
37
|
// If already initialized, get existing instance
|
|
38
|
-
if (error.code === 'failed-precondition') {
|
|
39
|
-
return getFirestore(app);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
38
|
return getFirestore(app);
|
|
43
39
|
}
|
|
44
40
|
}
|
|
@@ -19,7 +19,7 @@ export class QueryDeduplicationMiddleware {
|
|
|
19
19
|
private pendingQueries = new Map<string, PendingQuery>();
|
|
20
20
|
private readonly DEDUPLICATION_WINDOW_MS = 1000; // 1 second
|
|
21
21
|
private readonly CLEANUP_INTERVAL_MS = 5000; // 5 seconds
|
|
22
|
-
private cleanupTimer:
|
|
22
|
+
private cleanupTimer: ReturnType<typeof setInterval> | null = null;
|
|
23
23
|
|
|
24
24
|
constructor() {
|
|
25
25
|
this.startCleanupTimer();
|
|
@@ -42,8 +42,8 @@ export abstract class BasePaginatedRepository extends BaseQueryRepository {
|
|
|
42
42
|
limit(fetchLimit),
|
|
43
43
|
);
|
|
44
44
|
|
|
45
|
-
if (helper.hasCursor(params)) {
|
|
46
|
-
const cursorDoc = await getDoc(doc(db, collectionName, params
|
|
45
|
+
if (helper.hasCursor(params) && params?.cursor) {
|
|
46
|
+
const cursorDoc = await getDoc(doc(db, collectionName, params.cursor));
|
|
47
47
|
if (cursorDoc.exists()) {
|
|
48
48
|
q = query(
|
|
49
49
|
collectionRef,
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
* It provides a consistent interface for Firestore operations.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("📍 [LIFECYCLE] BaseRepository.ts - Module loading");
|
|
17
|
+
if (__DEV__) console.log("📍 [LIFECYCLE] BaseRepository.ts - Module loading");
|
|
19
18
|
|
|
20
19
|
import type { Firestore } from "firebase/firestore";
|
|
21
20
|
import { getFirestore } from "../config/FirestoreClient";
|
|
@@ -71,7 +70,8 @@ export class BaseRepository {
|
|
|
71
70
|
try {
|
|
72
71
|
const db = getFirestore();
|
|
73
72
|
return db !== null;
|
|
74
|
-
} catch {
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (__DEV__) console.warn('[BaseRepository] isDbInitialized check failed:', error);
|
|
75
75
|
return false;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -74,8 +74,8 @@ export class RequestLoggerService {
|
|
|
74
74
|
const failedRequests = this.logs.filter((l) => !l.success).length;
|
|
75
75
|
|
|
76
76
|
const durations = this.logs
|
|
77
|
-
.
|
|
78
|
-
.
|
|
77
|
+
.map((l) => l.duration)
|
|
78
|
+
.filter((d): d is number => d !== undefined);
|
|
79
79
|
const averageDuration =
|
|
80
80
|
durations.length > 0
|
|
81
81
|
? durations.reduce((sum, d) => sum + d, 0) / durations.length
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* Firestore Helper - Centralized Firestore access utilities
|
|
3
3
|
* Provides common patterns for Firestore operations with error handling
|
|
4
4
|
*/
|
|
5
|
-
declare const __DEV__: boolean;
|
|
6
|
-
|
|
7
5
|
import { getFirestore } from "../infrastructure/config/FirestoreClient";
|
|
8
6
|
import type { Firestore } from "../infrastructure/config/FirestoreClient";
|
|
9
7
|
|
package/src/global.d.ts
ADDED
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
* - Dependency Inversion: Depends on abstractions (interfaces), not concrete implementations
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("📍 [LIFECYCLE] FirebaseClient.ts - Module loading");
|
|
19
|
+
if (__DEV__) console.log("📍 [LIFECYCLE] FirebaseClient.ts - Module loading");
|
|
21
20
|
|
|
22
21
|
import type { FirebaseConfig } from '../../domain/value-objects/FirebaseConfig';
|
|
23
22
|
import type { IFirebaseClient } from '../../application/ports/IFirebaseClient';
|
|
@@ -33,8 +32,6 @@ import { loadFirebaseConfig } from './FirebaseConfigLoader';
|
|
|
33
32
|
|
|
34
33
|
export type { FirebaseApp, AuthInitializer, ServiceInitializationOptions };
|
|
35
34
|
|
|
36
|
-
declare const __DEV__: boolean;
|
|
37
|
-
|
|
38
35
|
/**
|
|
39
36
|
* Service initialization result interface
|
|
40
37
|
*/
|
|
@@ -37,11 +37,11 @@ function getEnvValue(key: ConfigKey): string {
|
|
|
37
37
|
*/
|
|
38
38
|
function loadExpoConfig(): Record<string, string> {
|
|
39
39
|
try {
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
40
|
const Constants = require('expo-constants');
|
|
42
41
|
const expoConfig = Constants?.expoConfig || Constants?.default?.expoConfig;
|
|
43
42
|
return expoConfig?.extra || {};
|
|
44
|
-
} catch {
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (__DEV__) console.warn('[FirebaseConfigLoader] expo-constants not available:', error);
|
|
45
45
|
return {};
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -21,7 +21,7 @@ class FirebaseConfigMapper {
|
|
|
21
21
|
/**
|
|
22
22
|
* Map domain config to Firebase SDK config
|
|
23
23
|
*/
|
|
24
|
-
static toFirebaseConfig(config: FirebaseConfig): Record<string,
|
|
24
|
+
static toFirebaseConfig(config: FirebaseConfig): Record<string, string | undefined> {
|
|
25
25
|
return {
|
|
26
26
|
apiKey: config.apiKey,
|
|
27
27
|
authDomain: config.authDomain,
|
|
@@ -44,7 +44,8 @@ class FirebaseAppManager {
|
|
|
44
44
|
try {
|
|
45
45
|
const existingApps = getApps();
|
|
46
46
|
return existingApps.length > 0;
|
|
47
|
-
} catch {
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (__DEV__) console.warn('[FirebaseAppManager] isInitialized check failed:', error);
|
|
48
49
|
return false;
|
|
49
50
|
}
|
|
50
51
|
}
|
|
@@ -56,7 +57,8 @@ class FirebaseAppManager {
|
|
|
56
57
|
try {
|
|
57
58
|
const existingApps = getApps();
|
|
58
59
|
return existingApps.length > 0 ? existingApps[0] ?? null : null;
|
|
59
|
-
} catch {
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (__DEV__) console.warn('[FirebaseAppManager] getExistingApp failed:', error);
|
|
60
62
|
return null;
|
|
61
63
|
}
|
|
62
64
|
}
|
|
@@ -12,8 +12,6 @@ import { FirebaseAppInitializer } from '../initializers/FirebaseAppInitializer';
|
|
|
12
12
|
import { loadFirebaseConfig } from '../FirebaseConfigLoader';
|
|
13
13
|
import type { FirebaseClientState } from '../state/FirebaseClientState';
|
|
14
14
|
|
|
15
|
-
declare const __DEV__: boolean;
|
|
16
|
-
|
|
17
15
|
export class FirebaseInitializationOrchestrator {
|
|
18
16
|
static initialize(
|
|
19
17
|
config: FirebaseConfig,
|
|
@@ -7,8 +7,6 @@ import type { InitModule } from '@umituz/react-native-design-system';
|
|
|
7
7
|
import { initializeAllFirebaseServices } from '../infrastructure/config/FirebaseClient';
|
|
8
8
|
import { initializeFirebaseAuth } from '../auth/infrastructure/config/FirebaseAuthClient';
|
|
9
9
|
|
|
10
|
-
declare const __DEV__: boolean;
|
|
11
|
-
|
|
12
10
|
export interface FirebaseInitModuleConfig {
|
|
13
11
|
/**
|
|
14
12
|
* Custom auth initializer function
|
|
@@ -53,13 +51,13 @@ export function createFirebaseInitModule(
|
|
|
53
51
|
authInitializer: authInitializer ?? (() => initializeFirebaseAuth()),
|
|
54
52
|
});
|
|
55
53
|
|
|
56
|
-
if (
|
|
54
|
+
if (__DEV__) {
|
|
57
55
|
console.log('[createFirebaseInitModule] Firebase initialized');
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
return true;
|
|
61
59
|
} catch (error) {
|
|
62
|
-
if (
|
|
60
|
+
if (__DEV__) {
|
|
63
61
|
console.error('[createFirebaseInitModule] Error:', error);
|
|
64
62
|
}
|
|
65
63
|
// Return false to indicate failure, let the app initializer handle it
|
package/src/storage/deleter.ts
CHANGED
|
@@ -7,8 +7,6 @@ import { ref, deleteObject } from "firebase/storage";
|
|
|
7
7
|
import { getStorageInstance } from "./storage-instance";
|
|
8
8
|
import type { DeleteResult } from "./types";
|
|
9
9
|
|
|
10
|
-
declare const __DEV__: boolean;
|
|
11
|
-
|
|
12
10
|
/**
|
|
13
11
|
* Batch delete result interface
|
|
14
12
|
*/
|
|
@@ -34,7 +32,8 @@ function extractStoragePath(downloadUrl: string): string | null {
|
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
return decodeURIComponent(pathMatch[1]);
|
|
37
|
-
} catch {
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (__DEV__) console.warn('[StorageDeleter] Failed to parse URL:', error);
|
|
38
37
|
return null;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
@@ -125,9 +124,10 @@ export async function deleteStorageFiles(
|
|
|
125
124
|
successful.push(result.value.storagePath);
|
|
126
125
|
} else {
|
|
127
126
|
const errorMessage = result.status === "rejected"
|
|
128
|
-
? String(
|
|
127
|
+
? String(result.reason instanceof Error ? result.reason.message : "Unknown error")
|
|
129
128
|
: "Delete operation failed";
|
|
130
|
-
|
|
129
|
+
const path = urlsOrPaths[index] ?? "unknown";
|
|
130
|
+
failed.push({ path, error: errorMessage });
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
133
|
|
package/src/storage/uploader.ts
CHANGED