@umituz/react-native-firebase 1.13.105 → 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.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/src/auth/infrastructure/config/FirebaseAuthClient.ts +13 -7
  3. package/src/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +0 -2
  4. package/src/auth/infrastructure/services/account-deletion.service.ts +23 -12
  5. package/src/auth/infrastructure/services/anonymous-auth.service.ts +1 -9
  6. package/src/auth/infrastructure/services/apple-auth.service.ts +5 -17
  7. package/src/auth/infrastructure/services/auth-guard.service.ts +2 -1
  8. package/src/auth/infrastructure/services/crypto.util.ts +17 -0
  9. package/src/auth/infrastructure/services/firestore-utils.service.ts +0 -2
  10. package/src/auth/infrastructure/services/password.service.ts +4 -3
  11. package/src/auth/infrastructure/services/reauthentication.service.ts +23 -17
  12. package/src/auth/infrastructure/stores/auth.store.ts +2 -4
  13. package/src/auth/presentation/hooks/useAnonymousAuth.ts +0 -2
  14. package/src/auth/presentation/hooks/useSocialAuth.ts +6 -2
  15. package/src/auth/presentation/hooks/utils/auth-state-change.handler.ts +0 -2
  16. package/src/domain/errors/FirebaseError.ts +3 -3
  17. package/src/firestore/infrastructure/config/FirestoreClient.ts +1 -2
  18. package/src/firestore/infrastructure/config/initializers/FirebaseFirestoreInitializer.ts +1 -5
  19. package/src/firestore/infrastructure/middleware/QueryDeduplicationMiddleware.ts +1 -1
  20. package/src/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +0 -2
  21. package/src/firestore/infrastructure/repositories/BasePaginatedRepository.ts +2 -2
  22. package/src/firestore/infrastructure/repositories/BaseRepository.ts +3 -3
  23. package/src/firestore/infrastructure/services/RequestLoggerService.ts +2 -2
  24. package/src/firestore/utils/dateUtils.ts +2 -2
  25. package/src/firestore/utils/firestore-helper.ts +0 -2
  26. package/src/global.d.ts +5 -0
  27. package/src/infrastructure/config/FirebaseClient.ts +1 -4
  28. package/src/infrastructure/config/FirebaseConfigLoader.ts +2 -2
  29. package/src/infrastructure/config/initializers/FirebaseAppInitializer.ts +5 -3
  30. package/src/infrastructure/config/orchestrators/FirebaseInitializationOrchestrator.ts +0 -2
  31. package/src/infrastructure/config/services/FirebaseServiceInitializer.ts +0 -2
  32. package/src/init/createFirebaseInitModule.ts +2 -4
  33. package/src/storage/deleter.ts +7 -12
  34. package/src/storage/storage-instance.ts +11 -0
  35. package/src/storage/uploader.ts +1 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-firebase",
3
- "version": "1.13.105",
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: any) {
32
- if (__DEV__) console.error('[FirebaseAuth] Init error:', error.message);
33
- this.initializationError = error.message;
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
- reset(): void { this.auth = null; this.initializationError = null; }
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.initialize() ? null : "Not initialized";
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: any) {
36
- if (error.code === "auth/requires-recent-login" && (options.autoReauthenticate || options.password || options.googleIdToken)) {
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: { code: error.code || "auth/failed", message: error.message, requiresReauth: error.code === "auth/requires-recent-login" }
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, error?: any };
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: any) {
65
- return { success: false, error: { code: err.code || "auth/post-reauth-failed", message: err.message, requiresReauth: false } };
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: any) {
77
- return { success: false, error: { code: error.code || "auth/failed", message: error.message, requiresReauth: error.code === "auth/requires-recent-login" } };
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 && !currentUser.isAnonymous) {
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),
@@ -10,8 +10,8 @@ import {
10
10
  type UserCredential,
11
11
  } from "firebase/auth";
12
12
  import * as AppleAuthentication from "expo-apple-authentication";
13
- import * as Crypto from "expo-crypto";
14
13
  import { Platform } from "react-native";
14
+ import { generateNonce, hashNonce } from "./crypto.util";
15
15
 
16
16
  export interface AppleAuthResult {
17
17
  success: boolean;
@@ -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
  }
@@ -40,11 +41,8 @@ export class AppleAuthService {
40
41
  };
41
42
  }
42
43
 
43
- const nonce = await this.generateNonce();
44
- const hashedNonce = await Crypto.digestStringAsync(
45
- Crypto.CryptoDigestAlgorithm.SHA256,
46
- nonce,
47
- );
44
+ const nonce = await generateNonce();
45
+ const hashedNonce = await hashNonce(nonce);
48
46
 
49
47
  const appleCredential = await AppleAuthentication.signInAsync({
50
48
  requestedScopes: [
@@ -86,16 +84,6 @@ export class AppleAuthService {
86
84
  }
87
85
  }
88
86
 
89
- private async generateNonce(length: number = 32): Promise<string> {
90
- const randomBytes = await Crypto.getRandomBytesAsync(length);
91
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
92
- let result = "";
93
- for (let i = 0; i < randomBytes.length; i++) {
94
- const byte = randomBytes[i];
95
- if (byte !== undefined) result += chars.charAt(byte % chars.length);
96
- }
97
- return result;
98
- }
99
87
  }
100
88
 
101
89
  export const appleAuthService = new AppleAuthService();
@@ -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
  }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Crypto Utilities
3
+ * Shared cryptographic helpers for auth services
4
+ */
5
+
6
+ import * as Crypto from "expo-crypto";
7
+
8
+ const NONCE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
9
+
10
+ export async function generateNonce(length: number = 32): Promise<string> {
11
+ const bytes = await Crypto.getRandomBytesAsync(length);
12
+ return Array.from(bytes).map(b => NONCE_CHARS.charAt(b % NONCE_CHARS.length)).join("");
13
+ }
14
+
15
+ export async function hashNonce(nonce: string): Promise<string> {
16
+ return Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce);
17
+ }
@@ -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: any) {
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: error.code || 'auth/password-update-failed',
32
- message: error.message || 'Failed to update password',
32
+ code: err.code || 'auth/password-update-failed',
33
+ message: err.message || 'Failed to update password',
33
34
  },
34
35
  };
35
36
  }
@@ -11,8 +11,8 @@ import {
11
11
  type User,
12
12
  } from "firebase/auth";
13
13
  import * as AppleAuthentication from "expo-apple-authentication";
14
- import * as Crypto from "expo-crypto";
15
14
  import { Platform } from "react-native";
15
+ import { generateNonce, hashNonce } from "./crypto.util";
16
16
  import type {
17
17
  ReauthenticationResult,
18
18
  AuthProviderType,
@@ -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: any) {
43
- return { success: false, error: { code: error.code || "auth/failed", message: error.message } };
50
+ } catch (error: unknown) {
51
+ const err = toAuthError(error);
52
+ return { success: false, error: err };
44
53
  }
45
54
  }
46
55
 
@@ -49,17 +58,12 @@ 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: any) {
53
- return { success: false, error: { code: error.code || "auth/failed", message: error.message } };
61
+ } catch (error: unknown) {
62
+ const err = toAuthError(error);
63
+ return { success: false, error: err };
54
64
  }
55
65
  }
56
66
 
57
- async function generateNonce(len: number = 32): Promise<string> {
58
- const bytes = await Crypto.getRandomBytesAsync(len);
59
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
60
- return Array.from(bytes).map(b => chars.charAt(b % chars.length)).join("");
61
- }
62
-
63
67
  export async function getAppleReauthCredential(): Promise<ReauthCredentialResult> {
64
68
  if (Platform.OS !== "ios") return { success: false, error: { code: "auth/ios-only", message: "iOS only" } };
65
69
  try {
@@ -67,7 +71,7 @@ export async function getAppleReauthCredential(): Promise<ReauthCredentialResult
67
71
  return { success: false, error: { code: "auth/unavailable", message: "Unavailable" } };
68
72
 
69
73
  const nonce = await generateNonce();
70
- const hashed = await Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce);
74
+ const hashed = await hashNonce(nonce);
71
75
  const apple = await AppleAuthentication.signInAsync({
72
76
  requestedScopes: [AppleAuthentication.AppleAuthenticationScope.FULL_NAME, AppleAuthentication.AppleAuthenticationScope.EMAIL],
73
77
  nonce: hashed,
@@ -75,9 +79,10 @@ export async function getAppleReauthCredential(): Promise<ReauthCredentialResult
75
79
 
76
80
  if (!apple.identityToken) return { success: false, error: { code: "auth/no-token", message: "No token" } };
77
81
  return { success: true, credential: new OAuthProvider("apple.com").credential({ idToken: apple.identityToken, rawNonce: nonce }) };
78
- } catch (error: any) {
79
- const code = error.message?.includes("ERR_CANCELED") ? "auth/cancelled" : "auth/failed";
80
- return { success: false, error: { code, message: error.message } };
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 } };
81
86
  }
82
87
  }
83
88
 
@@ -87,7 +92,8 @@ export async function reauthenticateWithApple(user: User): Promise<Reauthenticat
87
92
  try {
88
93
  await reauthenticateWithCredential(user, res.credential);
89
94
  return { success: true };
90
- } catch (error: any) {
91
- return { success: false, error: { code: error.code || "auth/failed", message: error.message } };
95
+ } catch (error: unknown) {
96
+ const err = toAuthError(error);
97
+ return { success: false, error: err };
92
98
  }
93
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 (typeof __DEV__ !== "undefined" && __DEV__) {
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 (typeof __DEV__ !== "undefined" && __DEV__) {
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(getFirebaseAuth()!, idToken)
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(getFirebaseAuth()!)
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?: any) {
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?: any) {
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?: any) {
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: any) {
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: any = null;
22
+ private cleanupTimer: ReturnType<typeof setInterval> | null = null;
23
23
 
24
24
  constructor() {
25
25
  this.startCleanupTimer();
@@ -3,8 +3,6 @@
3
3
  * Tracks Firestore operations for quota monitoring
4
4
  */
5
5
 
6
- declare const __DEV__: boolean;
7
-
8
6
  interface OperationInfo {
9
7
  type: 'read' | 'write' | 'delete';
10
8
  collection: string;
@@ -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!.cursor!));
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
- .filter((l) => l.duration !== undefined)
78
- .map((l) => l.duration!);
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
@@ -10,7 +10,7 @@ export function isoToTimestamp(isoString: string): Timestamp {
10
10
  /**
11
11
  * Convert Firestore Timestamp to ISO string
12
12
  */
13
- export function timestampToISO(timestamp: Timestamp): string {
13
+ export function timestampToISO(timestamp: Timestamp | null | undefined): string {
14
14
  if (!timestamp) return new Date().toISOString();
15
15
  return timestamp.toDate().toISOString();
16
16
  }
@@ -18,7 +18,7 @@ export function timestampToISO(timestamp: Timestamp): string {
18
18
  /**
19
19
  * Convert Firestore Timestamp to Date
20
20
  */
21
- export function timestampToDate(timestamp: Timestamp): Date {
21
+ export function timestampToDate(timestamp: Timestamp | null | undefined): Date {
22
22
  if (!timestamp) return new Date();
23
23
  return timestamp.toDate();
24
24
  }
@@ -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
 
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Global type declarations for React Native environment
3
+ */
4
+
5
+ declare const __DEV__: boolean;
@@ -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, any> {
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,
@@ -8,8 +8,6 @@
8
8
  * Single Responsibility: Only initializes Firebase Auth service
9
9
  */
10
10
 
11
- declare const __DEV__: boolean;
12
-
13
11
  export type AuthInitializer = () => unknown;
14
12
 
15
13
  export interface ServiceInitializationOptions {
@@ -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 (typeof __DEV__ !== 'undefined' && __DEV__) {
54
+ if (__DEV__) {
57
55
  console.log('[createFirebaseInitModule] Firebase initialized');
58
56
  }
59
57
 
60
58
  return true;
61
59
  } catch (error) {
62
- if (typeof __DEV__ !== 'undefined' && __DEV__) {
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
@@ -3,12 +3,10 @@
3
3
  * Handles single and batch deletion from Firebase Storage
4
4
  */
5
5
 
6
- import { getStorage, ref, deleteObject } from "firebase/storage";
7
- import { getFirebaseApp } from "../infrastructure/config/FirebaseClient";
6
+ import { ref, deleteObject } from "firebase/storage";
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,16 +32,12 @@ 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
  }
41
40
 
42
- function getStorageInstance() {
43
- const app = getFirebaseApp();
44
- return app ? getStorage(app) : null;
45
- }
46
-
47
41
  /**
48
42
  * Delete image from Firebase Storage
49
43
  * Accepts either a download URL or storage path
@@ -130,9 +124,10 @@ export async function deleteStorageFiles(
130
124
  successful.push(result.value.storagePath);
131
125
  } else {
132
126
  const errorMessage = result.status === "rejected"
133
- ? String((result.reason as any)?.message ?? "Unknown error")
127
+ ? String(result.reason instanceof Error ? result.reason.message : "Unknown error")
134
128
  : "Delete operation failed";
135
- failed.push({ path: urlsOrPaths[index]!, error: errorMessage });
129
+ const path = urlsOrPaths[index] ?? "unknown";
130
+ failed.push({ path, error: errorMessage });
136
131
  }
137
132
  });
138
133
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared Firebase Storage instance getter
3
+ */
4
+
5
+ import { getStorage } from "firebase/storage";
6
+ import { getFirebaseApp } from "../infrastructure/config/FirebaseClient";
7
+
8
+ export function getStorageInstance() {
9
+ const app = getFirebaseApp();
10
+ return app ? getStorage(app) : null;
11
+ }
@@ -4,17 +4,14 @@
4
4
  */
5
5
 
6
6
  import {
7
- getStorage,
8
7
  ref,
9
8
  uploadBytes,
10
9
  getDownloadURL,
11
10
  type UploadMetadata,
12
11
  } from "firebase/storage";
13
- import { getFirebaseApp } from "../infrastructure/config/FirebaseClient";
12
+ import { getStorageInstance } from "./storage-instance";
14
13
  import type { UploadResult, UploadOptions } from "./types";
15
14
 
16
- declare const __DEV__: boolean;
17
-
18
15
  /**
19
16
  * Extract MIME type from base64 data URL or return default
20
17
  */
@@ -35,11 +32,6 @@ function ensureDataUrl(base64: string, mimeType: string): string {
35
32
  return `data:${mimeType};base64,${base64}`;
36
33
  }
37
34
 
38
- function getStorageInstance() {
39
- const app = getFirebaseApp();
40
- return app ? getStorage(app) : null;
41
- }
42
-
43
35
  /**
44
36
  * Upload base64 image to Firebase Storage
45
37
  */