@umituz/react-native-firebase 1.13.116 → 1.13.117

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 (40) hide show
  1. package/package.json +1 -1
  2. package/src/auth/domain/errors/FirebaseAuthError.ts +0 -4
  3. package/src/auth/index.ts +0 -14
  4. package/src/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +2 -23
  5. package/src/auth/infrastructure/services/apple-auth.types.ts +16 -4
  6. package/src/auth/infrastructure/services/auth-utils.service.ts +54 -46
  7. package/src/auth/infrastructure/services/google-auth.types.ts +18 -11
  8. package/src/auth/infrastructure/services/reauthentication.types.ts +16 -14
  9. package/src/auth/infrastructure/stores/auth.store.ts +1 -10
  10. package/src/auth/presentation/hooks/useAnonymousAuth.ts +1 -25
  11. package/src/domain/errors/FirebaseError.ts +0 -4
  12. package/src/firestore/domain/errors/FirebaseFirestoreError.ts +0 -8
  13. package/src/firestore/infrastructure/config/FirestoreClient.ts +0 -2
  14. package/src/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +0 -13
  15. package/src/firestore/infrastructure/repositories/BaseRepository.ts +5 -5
  16. package/src/firestore/infrastructure/services/RequestLoggerService.ts +2 -24
  17. package/src/firestore/types/pagination.types.ts +0 -8
  18. package/src/firestore/utils/firestore-helper.ts +10 -14
  19. package/src/firestore/utils/quota-error-detector.util.ts +27 -16
  20. package/src/index.ts +0 -10
  21. package/src/infrastructure/config/FirebaseClient.ts +0 -9
  22. package/src/infrastructure/config/FirebaseConfigLoader.ts +33 -2
  23. package/src/infrastructure/config/orchestrators/FirebaseInitializationOrchestrator.ts +0 -21
  24. package/src/infrastructure/config/services/FirebaseServiceInitializer.ts +2 -18
  25. package/src/init/createFirebaseInitModule.ts +0 -1
  26. package/src/storage/deleter.ts +2 -35
  27. package/src/storage/uploader.ts +0 -34
  28. package/src/auth/README.md +0 -339
  29. package/src/auth/domain/README.md +0 -264
  30. package/src/auth/infrastructure/stores/README.md +0 -407
  31. package/src/auth/presentation/hooks/README.md +0 -442
  32. package/src/firestore/README.md +0 -566
  33. package/src/firestore/__tests__/BaseRepository.test.ts +0 -132
  34. package/src/firestore/__tests__/QueryDeduplicationMiddleware.test.ts +0 -147
  35. package/src/firestore/__tests__/mocks/react-native-firebase.ts +0 -23
  36. package/src/firestore/__tests__/setup.ts +0 -45
  37. package/src/firestore/utils/path-resolver/README.md +0 -277
  38. package/src/firestore/utils/quota-error-detector/README.md +0 -355
  39. package/src/storage/README.md +0 -493
  40. package/src/storage/uploader/README.md +0 -409
@@ -31,13 +31,10 @@ export function getDb(): Firestore | null {
31
31
  */
32
32
  export async function withFirestore<T>(
33
33
  operation: (db: Firestore) => Promise<FirestoreResult<T>>,
34
- logTag?: string
34
+ _logTag?: string
35
35
  ): Promise<FirestoreResult<T>> {
36
36
  const db = getDb();
37
37
  if (!db) {
38
- if (__DEV__ && logTag) {
39
- console.log(`[${logTag}] No Firestore instance`);
40
- }
41
38
  return NO_DB_ERROR as FirestoreResult<T>;
42
39
  }
43
40
  return operation(db);
@@ -48,13 +45,10 @@ export async function withFirestore<T>(
48
45
  */
49
46
  export async function withFirestoreVoid(
50
47
  operation: (db: Firestore) => Promise<void>,
51
- logTag?: string
48
+ _logTag?: string
52
49
  ): Promise<void> {
53
50
  const db = getDb();
54
51
  if (!db) {
55
- if (__DEV__ && logTag) {
56
- console.log(`[${logTag}] No Firestore instance`);
57
- }
58
52
  return;
59
53
  }
60
54
  return operation(db);
@@ -65,13 +59,10 @@ export async function withFirestoreVoid(
65
59
  */
66
60
  export async function withFirestoreBool(
67
61
  operation: (db: Firestore) => Promise<boolean>,
68
- logTag?: string
62
+ _logTag?: string
69
63
  ): Promise<boolean> {
70
64
  const db = getDb();
71
65
  if (!db) {
72
- if (__DEV__ && logTag) {
73
- console.log(`[${logTag}] No Firestore instance`);
74
- }
75
66
  return false;
76
67
  }
77
68
  return operation(db);
@@ -110,9 +101,14 @@ export async function runTransaction<T>(
110
101
  ): Promise<T> {
111
102
  const db = getDb();
112
103
  if (!db) {
113
- throw new Error("[runTransaction] Firestore not initialized");
104
+ throw new Error("[runTransaction] Firestore database is not initialized. Please ensure Firebase is properly initialized before running transactions.");
105
+ }
106
+ try {
107
+ return await fbRunTransaction(db, updateFunction);
108
+ } catch (error) {
109
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
110
+ throw new Error(`[runTransaction] Transaction failed: ${errorMessage}`);
114
111
  }
115
- return fbRunTransaction(db, updateFunction);
116
112
  }
117
113
 
118
114
  /**
@@ -16,24 +16,35 @@ const QUOTA_ERROR_MESSAGES = [
16
16
  'too many requests',
17
17
  ];
18
18
 
19
+ /**
20
+ * Type guard for error with code property
21
+ */
22
+ function hasCodeProperty(error: unknown): error is { code: string } {
23
+ return typeof error === 'object' && error !== null && 'code' in error && typeof (error as { code: unknown }).code === 'string';
24
+ }
25
+
26
+ /**
27
+ * Type guard for error with message property
28
+ */
29
+ function hasMessageProperty(error: unknown): error is { message: string } {
30
+ return typeof error === 'object' && error !== null && 'message' in error && typeof (error as { message: unknown }).message === 'string';
31
+ }
32
+
19
33
  /**
20
34
  * Check if error is a Firestore quota error
21
35
  */
22
36
  export function isQuotaError(error: unknown): boolean {
23
37
  if (!error || typeof error !== 'object') return false;
24
38
 
25
- const code = 'code' in error && typeof (error as Record<string, unknown>).code === 'string'
26
- ? (error as Record<string, unknown>).code as string
27
- : undefined;
28
- const message = 'message' in error && typeof (error as Record<string, unknown>).message === 'string'
29
- ? (error as Record<string, unknown>).message as string
30
- : undefined;
31
-
32
- if (code && QUOTA_ERROR_CODES.some((c) => code.includes(c))) {
33
- return true;
39
+ if (hasCodeProperty(error)) {
40
+ const code = error.code;
41
+ if (QUOTA_ERROR_CODES.some((c) => code.includes(c))) {
42
+ return true;
43
+ }
34
44
  }
35
45
 
36
- if (message) {
46
+ if (hasMessageProperty(error)) {
47
+ const message = error.message;
37
48
  const lowerMessage = message.toLowerCase();
38
49
  return QUOTA_ERROR_MESSAGES.some((m) => lowerMessage.includes(m));
39
50
  }
@@ -47,13 +58,13 @@ export function isQuotaError(error: unknown): boolean {
47
58
  export function isRetryableError(error: unknown): boolean {
48
59
  if (!error || typeof error !== 'object') return false;
49
60
 
50
- const code = 'code' in error && typeof (error as Record<string, unknown>).code === 'string'
51
- ? (error as Record<string, unknown>).code as string
52
- : undefined;
53
-
54
- const retryableCodes = ['unavailable', 'deadline-exceeded', 'aborted'];
61
+ if (hasCodeProperty(error)) {
62
+ const code = error.code;
63
+ const retryableCodes = ['unavailable', 'deadline-exceeded', 'aborted'];
64
+ return retryableCodes.some((c) => code.includes(c));
65
+ }
55
66
 
56
- return code ? retryableCodes.some((c) => code.includes(c)) : false;
67
+ return false;
57
68
  }
58
69
 
59
70
  /**
package/src/index.ts CHANGED
@@ -11,10 +11,6 @@
11
11
  * - @umituz/react-native-firebase/storage
12
12
  */
13
13
 
14
- if (__DEV__) {
15
- console.log("📍 [LIFECYCLE] @umituz/react-native-firebase/index.ts - START");
16
- }
17
-
18
14
  // Core Errors
19
15
  export {
20
16
  FirebaseError,
@@ -22,12 +18,6 @@ export {
22
18
  FirebaseConfigurationError,
23
19
  } from "./domain/errors/FirebaseError";
24
20
 
25
- if (__DEV__) {
26
- console.log(
27
- "📍 [LIFECYCLE] @umituz/react-native-firebase/index.ts - Core errors exported",
28
- );
29
- }
30
-
31
21
  // Core Types
32
22
  export type { FirebaseConfig } from "./domain/value-objects/FirebaseConfig";
33
23
  export type { IFirebaseClient } from "./application/ports/IFirebaseClient";
@@ -16,8 +16,6 @@
16
16
  * - Dependency Inversion: Depends on abstractions (interfaces), not concrete implementations
17
17
  */
18
18
 
19
- if (__DEV__) console.log("📍 [LIFECYCLE] FirebaseClient.ts - Module loading");
20
-
21
19
  import type { FirebaseConfig } from '../../domain/value-objects/FirebaseConfig';
22
20
  import type { IFirebaseClient } from '../../application/ports/IFirebaseClient';
23
21
  import type { FirebaseApp } from './initializers/FirebaseAppInitializer';
@@ -144,13 +142,6 @@ export async function initializeAllFirebaseServices(
144
142
 
145
143
  const { auth } = await FirebaseServiceInitializer.initializeServices(options);
146
144
 
147
- if (__DEV__) {
148
- console.log('[Firebase] All services initialized:', {
149
- app: !!app,
150
- auth: !!auth,
151
- });
152
- }
153
-
154
145
  return {
155
146
  app,
156
147
  auth,
@@ -62,6 +62,15 @@ function getExpoValue(key: ConfigKey, expoConfig: Record<string, string>): strin
62
62
  return expoConfig[mapping[key]] || '';
63
63
  }
64
64
 
65
+ /**
66
+ * Validate Firebase API key format
67
+ */
68
+ function validateApiKey(apiKey: string): boolean {
69
+ // Firebase API keys typically start with "AIza" followed by 35 characters
70
+ const apiKeyPattern = /^AIza[0-9A-Za-z_-]{35}$/;
71
+ return apiKeyPattern.test(apiKey);
72
+ }
73
+
65
74
  /**
66
75
  * Load Firebase configuration from Constants and environment variables
67
76
  */
@@ -76,11 +85,33 @@ export function loadFirebaseConfig(): FirebaseConfig | null {
76
85
  config[key] = expoValue || getEnvValue(key);
77
86
  }
78
87
 
79
- // Validate required fields
80
- if (!config.apiKey?.trim() || !config.authDomain?.trim() || !config.projectId?.trim()) {
88
+ // Validate required fields with proper checks
89
+ const apiKey = config.apiKey?.trim();
90
+ const authDomain = config.authDomain?.trim();
91
+ const projectId = config.projectId?.trim();
92
+
93
+ if (!apiKey || !authDomain || !projectId) {
94
+ if (__DEV__) {
95
+ console.error('[FirebaseConfigLoader] Missing required configuration fields');
96
+ }
97
+ return null;
98
+ }
99
+
100
+ // Validate API key format
101
+ if (!validateApiKey(apiKey)) {
102
+ if (__DEV__) {
103
+ console.error('[FirebaseConfigLoader] Invalid API key format');
104
+ }
81
105
  return null;
82
106
  }
83
107
 
108
+ // Validate authDomain format (should be like "projectId.firebaseapp.com")
109
+ if (!authDomain.includes('.firebaseapp.com') && !authDomain.includes('.web.app')) {
110
+ if (__DEV__) {
111
+ console.warn('[FirebaseConfigLoader] Unusual authDomain format, expected "projectId.firebaseapp.com" or similar');
112
+ }
113
+ }
114
+
84
115
  return config as FirebaseConfig;
85
116
  }
86
117
 
@@ -18,32 +18,18 @@ export class FirebaseInitializationOrchestrator {
18
18
  state: FirebaseClientState
19
19
  ): FirebaseApp | null {
20
20
  if (state.isInitialized()) {
21
- if (__DEV__) {
22
- console.log('[Firebase] Already initialized, returning existing instance');
23
- }
24
21
  return state.getApp();
25
22
  }
26
23
 
27
24
  if (state.getInitializationError()) {
28
- if (__DEV__) {
29
- console.log('[Firebase] Previous initialization failed, skipping retry');
30
- }
31
25
  return null;
32
26
  }
33
27
 
34
28
  try {
35
- if (__DEV__) {
36
- console.log('[Firebase] Initializing with projectId:', config.projectId);
37
- }
38
-
39
29
  FirebaseConfigValidator.validate(config);
40
30
  const app = FirebaseAppInitializer.initialize(config);
41
31
  state.setApp(app);
42
32
 
43
- if (__DEV__) {
44
- console.log('[Firebase] Successfully initialized');
45
- }
46
-
47
33
  return app;
48
34
  } catch (error) {
49
35
  const errorMessage =
@@ -67,16 +53,9 @@ export class FirebaseInitializationOrchestrator {
67
53
 
68
54
  const autoConfig = loadFirebaseConfig();
69
55
  if (autoConfig) {
70
- if (__DEV__) {
71
- console.log('[Firebase] Auto-initializing with environment config');
72
- }
73
56
  return this.initialize(autoConfig, state);
74
57
  }
75
58
 
76
- if (__DEV__) {
77
- console.log('[Firebase] No configuration found for auto-initialization');
78
- }
79
-
80
59
  return null;
81
60
  }
82
61
  }
@@ -22,31 +22,15 @@ export class FirebaseServiceInitializer {
22
22
  static async initializeServices(
23
23
  options?: ServiceInitializationOptions
24
24
  ): Promise<ServiceInitializationResult> {
25
- if (__DEV__) {
26
- console.log('[Firebase] Initializing auth service...');
27
- }
28
-
29
25
  let auth: unknown = null;
30
26
  if (options?.authInitializer) {
31
27
  try {
32
28
  auth = await options.authInitializer();
33
- if (__DEV__) {
34
- console.log('[Firebase] Auth initialized via callback');
35
- }
36
- } catch (error) {
37
- if (__DEV__) {
38
- console.warn(
39
- '[Firebase] Auth initialization failed:',
40
- error instanceof Error ? error.message : 'Unknown error'
41
- );
42
- }
29
+ } catch {
30
+ // Silently fail, auth initialization is optional
43
31
  }
44
32
  }
45
33
 
46
- if (__DEV__) {
47
- console.log('[Firebase] Auth service initialized:', !!auth);
48
- }
49
-
50
34
  return { auth };
51
35
  }
52
36
  }
@@ -52,7 +52,6 @@ export function createFirebaseInitModule(
52
52
  });
53
53
 
54
54
  if (__DEV__) {
55
- console.log('[createFirebaseInitModule] Firebase initialized');
56
55
  }
57
56
 
58
57
  return true;
@@ -32,8 +32,7 @@ function extractStoragePath(downloadUrl: string): string | null {
32
32
  }
33
33
 
34
34
  return decodeURIComponent(pathMatch[1]);
35
- } catch (error) {
36
- if (__DEV__) console.warn('[StorageDeleter] Failed to parse URL:', error);
35
+ } catch {
37
36
  return null;
38
37
  }
39
38
  }
@@ -45,18 +44,9 @@ function extractStoragePath(downloadUrl: string): string | null {
45
44
  export async function deleteStorageFile(
46
45
  downloadUrlOrPath: string
47
46
  ): Promise<DeleteResult> {
48
- if (__DEV__) {
49
- console.log("[StorageDeleter] Deleting", { url: downloadUrlOrPath });
50
- }
51
-
52
47
  const storagePath = extractStoragePath(downloadUrlOrPath);
53
48
 
54
49
  if (!storagePath) {
55
- if (__DEV__) {
56
- console.error("[StorageDeleter] Invalid URL", {
57
- url: downloadUrlOrPath,
58
- });
59
- }
60
50
  return { success: false, storagePath: downloadUrlOrPath };
61
51
  }
62
52
 
@@ -69,20 +59,8 @@ export async function deleteStorageFile(
69
59
  const storageRef = ref(storage, storagePath);
70
60
  await deleteObject(storageRef);
71
61
 
72
- if (__DEV__) {
73
- console.log("[StorageDeleter] Deleted successfully", {
74
- storagePath,
75
- });
76
- }
77
-
78
62
  return { success: true, storagePath };
79
- } catch (error) {
80
- if (__DEV__) {
81
- console.error("[StorageDeleter] Delete failed", {
82
- storagePath,
83
- error,
84
- });
85
- }
63
+ } catch {
86
64
  return { success: false, storagePath };
87
65
  }
88
66
  }
@@ -97,10 +75,6 @@ export async function deleteStorageFile(
97
75
  export async function deleteStorageFiles(
98
76
  urlsOrPaths: string[]
99
77
  ): Promise<BatchDeleteResult> {
100
- if (__DEV__) {
101
- console.log("[StorageDeleter] Batch delete", { count: urlsOrPaths.length });
102
- }
103
-
104
78
  const storage = getStorageInstance();
105
79
  if (!storage) {
106
80
  return {
@@ -131,12 +105,5 @@ export async function deleteStorageFiles(
131
105
  }
132
106
  });
133
107
 
134
- if (__DEV__) {
135
- console.log("[StorageDeleter] Batch delete complete", {
136
- successful: successful.length,
137
- failed: failed.length,
138
- });
139
- }
140
-
141
108
  return { successful, failed };
142
109
  }
@@ -20,9 +20,6 @@ export function getMimeType(base64: string): string {
20
20
  if (base64.startsWith("data:image/png")) return "image/png";
21
21
  if (base64.startsWith("data:image/webp")) return "image/webp";
22
22
  if (base64.startsWith("data:image/gif")) return "image/gif";
23
- if (__DEV__) {
24
- console.warn("[StorageUploader] Could not detect MIME type from base64 prefix, falling back to image/jpeg");
25
- }
26
23
  return "image/jpeg";
27
24
  }
28
25
 
@@ -47,13 +44,6 @@ export async function uploadBase64Image(
47
44
  const mimeType = options?.mimeType ?? getMimeType(base64);
48
45
  const dataUrl = ensureDataUrl(base64, mimeType);
49
46
 
50
- if (__DEV__) {
51
- console.log("[StorageUploader] Starting base64 upload", {
52
- storagePath,
53
- mimeType,
54
- });
55
- }
56
-
57
47
  const storage = getStorageInstance();
58
48
  if (!storage) {
59
49
  throw new Error("Firebase Storage not initialized");
@@ -71,13 +61,6 @@ export async function uploadBase64Image(
71
61
  await uploadBytes(storageRef, blob, metadata);
72
62
  const downloadUrl = await getDownloadURL(storageRef);
73
63
 
74
- if (__DEV__) {
75
- console.log("[StorageUploader] Upload complete", {
76
- storagePath,
77
- downloadUrl,
78
- });
79
- }
80
-
81
64
  return {
82
65
  downloadUrl,
83
66
  storagePath,
@@ -92,13 +75,6 @@ export async function uploadFile(
92
75
  storagePath: string,
93
76
  options?: UploadOptions
94
77
  ): Promise<UploadResult> {
95
- if (__DEV__) {
96
- console.log("[StorageUploader] Starting file upload", {
97
- uri,
98
- storagePath,
99
- });
100
- }
101
-
102
78
  const storage = getStorageInstance();
103
79
  if (!storage) {
104
80
  throw new Error("Firebase Storage not initialized");
@@ -109,9 +85,6 @@ export async function uploadFile(
109
85
  const blob = await response.blob();
110
86
 
111
87
  const contentType = options?.mimeType ?? "image/jpeg";
112
- if (!options?.mimeType && __DEV__) {
113
- console.warn("[StorageUploader] No MIME type provided for file upload, falling back to image/jpeg");
114
- }
115
88
  const metadata: UploadMetadata = {
116
89
  contentType,
117
90
  customMetadata: options?.customMetadata,
@@ -120,13 +93,6 @@ export async function uploadFile(
120
93
  await uploadBytes(storageRef, blob, metadata);
121
94
  const downloadUrl = await getDownloadURL(storageRef);
122
95
 
123
- if (__DEV__) {
124
- console.log("[StorageUploader] Upload complete", {
125
- storagePath,
126
- downloadUrl,
127
- });
128
- }
129
-
130
96
  return {
131
97
  downloadUrl,
132
98
  storagePath,