@umituz/react-native-firebase 2.4.97 → 2.5.1
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/domains/auth/domain/value-objects/FirebaseAuthConfig.ts +1 -1
- package/src/domains/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +5 -41
- package/src/domains/firestore/index.ts +0 -58
- package/src/domains/firestore/infrastructure/config/initializers/FirebaseFirestoreInitializer.ts +4 -255
- package/src/domains/firestore/infrastructure/repositories/BasePaginatedRepository.ts +1 -7
- package/src/domains/firestore/infrastructure/repositories/BaseQueryRepository.ts +8 -34
- package/src/domains/firestore/infrastructure/repositories/BaseRepository.ts +9 -48
- package/src/domains/firestore/presentation/hooks/index.ts +0 -10
- package/src/index.ts +1 -1
- package/src/shared/infrastructure/config/clients/FirebaseClientSingleton.ts +1 -1
- package/src/shared/infrastructure/config/services/FirebaseInitializationService.ts +1 -1
- package/src/shared/infrastructure/config/state/FirebaseClientState.ts +1 -1
- package/src/domains/firestore/domain/constants/QuotaLimits.ts +0 -101
- package/src/domains/firestore/domain/entities/QuotaMetrics.ts +0 -26
- package/src/domains/firestore/domain/entities/RequestLog.ts +0 -28
- package/src/domains/firestore/domain/services/QuotaCalculator.ts +0 -71
- package/src/domains/firestore/infrastructure/middleware/QueryDeduplicationMiddleware.ts +0 -312
- package/src/domains/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +0 -95
- package/src/domains/firestore/infrastructure/services/RequestLoggerService.ts +0 -165
- package/src/domains/firestore/presentation/hooks/useSmartFirestoreSnapshot.ts +0 -361
- package/src/domains/firestore/presentation/query-keys/createFirestoreKeys.ts +0 -32
- package/src/domains/firestore/presentation/query-keys/index.ts +0 -1
- package/src/domains/firestore/utils/deduplication/pending-query-manager.util.ts +0 -119
- package/src/domains/firestore/utils/deduplication/query-key-generator.util.ts +0 -34
- package/src/domains/firestore/utils/deduplication/timer-manager.util.ts +0 -83
- package/src/shared/infrastructure/config/initializers/FirebaseAppInitializer.ts +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-firebase",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
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",
|
|
@@ -21,7 +21,7 @@ export interface FirebaseAuthConfig {
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Auth state persistence type
|
|
24
|
-
* - 'local': Persist across
|
|
24
|
+
* - 'local': Persist across app restarts (default)
|
|
25
25
|
* - 'session': Persist only for current session
|
|
26
26
|
* - 'none': No persistence
|
|
27
27
|
*/
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firebase Auth Initializer
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Initialize Firebase Auth instance
|
|
5
|
-
* Platform-agnostic: Works on all platforms (Web, iOS, Android)
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
import {
|
|
9
2
|
initializeAuth,
|
|
10
3
|
getAuth,
|
|
11
4
|
// @ts-expect-error: getReactNativePersistence exists in the React Native bundle but missing from type definitions
|
|
12
|
-
// See: https://github.com/firebase/firebase-js-sdk/issues/9316
|
|
13
5
|
getReactNativePersistence,
|
|
14
6
|
} from 'firebase/auth';
|
|
15
7
|
import type { Auth } from 'firebase/auth';
|
|
@@ -17,40 +9,8 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
17
9
|
import type { FirebaseApp } from 'firebase/app';
|
|
18
10
|
import type { FirebaseAuthConfig } from '../../../domain/value-objects/FirebaseAuthConfig';
|
|
19
11
|
|
|
20
|
-
/**
|
|
21
|
-
* Initializes Firebase Auth
|
|
22
|
-
* Platform-agnostic: Works on all platforms (Web, iOS, Android)
|
|
23
|
-
*/
|
|
24
12
|
export class FirebaseAuthInitializer {
|
|
25
|
-
/**
|
|
26
|
-
* Initialize Firebase Auth with persistence support
|
|
27
|
-
*/
|
|
28
13
|
static initialize(app: FirebaseApp, config?: FirebaseAuthConfig): Auth | null {
|
|
29
|
-
try {
|
|
30
|
-
const auth = this.initializeWithPersistence(app, config);
|
|
31
|
-
return auth;
|
|
32
|
-
} catch (error: unknown) {
|
|
33
|
-
return this.handleInitializationError(error, app);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private static handleInitializationError(error: unknown, app: FirebaseApp): Auth | null {
|
|
38
|
-
// Any initialization error: try to get existing auth instance
|
|
39
|
-
return this.getExistingAuth(app);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
private static getExistingAuth(app: FirebaseApp): Auth | null {
|
|
43
|
-
try {
|
|
44
|
-
return getAuth(app);
|
|
45
|
-
} catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private static initializeWithPersistence(
|
|
51
|
-
app: FirebaseApp,
|
|
52
|
-
config?: FirebaseAuthConfig
|
|
53
|
-
): Auth | null {
|
|
54
14
|
try {
|
|
55
15
|
const storage = config?.authStorage || {
|
|
56
16
|
getItem: (key: string) => AsyncStorage.getItem(key),
|
|
@@ -62,7 +22,11 @@ export class FirebaseAuthInitializer {
|
|
|
62
22
|
persistence: getReactNativePersistence(storage),
|
|
63
23
|
});
|
|
64
24
|
} catch {
|
|
65
|
-
|
|
25
|
+
try {
|
|
26
|
+
return getAuth(app);
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
66
30
|
}
|
|
67
31
|
}
|
|
68
32
|
}
|
|
@@ -59,61 +59,6 @@ export type {
|
|
|
59
59
|
} from './types/pagination.types';
|
|
60
60
|
export { EMPTY_PAGINATED_RESULT } from './types/pagination.types';
|
|
61
61
|
|
|
62
|
-
// Domain Constants
|
|
63
|
-
export {
|
|
64
|
-
FREE_TIER_LIMITS,
|
|
65
|
-
QUOTA_THRESHOLDS,
|
|
66
|
-
calculateQuotaUsage,
|
|
67
|
-
isQuotaThresholdReached,
|
|
68
|
-
getRemainingQuota,
|
|
69
|
-
} from './domain/constants/QuotaLimits';
|
|
70
|
-
|
|
71
|
-
// Domain Entities
|
|
72
|
-
export type {
|
|
73
|
-
QuotaMetrics,
|
|
74
|
-
QuotaLimits,
|
|
75
|
-
QuotaStatus,
|
|
76
|
-
} from './domain/entities/QuotaMetrics';
|
|
77
|
-
export type {
|
|
78
|
-
RequestLog,
|
|
79
|
-
RequestStats,
|
|
80
|
-
RequestType,
|
|
81
|
-
} from './domain/entities/RequestLog';
|
|
82
|
-
|
|
83
|
-
// Domain Services
|
|
84
|
-
export { QuotaCalculator } from './domain/services/QuotaCalculator';
|
|
85
|
-
|
|
86
|
-
// Quota Error Detection
|
|
87
|
-
export {
|
|
88
|
-
isQuotaError,
|
|
89
|
-
isRetryableError,
|
|
90
|
-
} from '../../shared/domain/utils/error-handlers/error-checkers';
|
|
91
|
-
export {
|
|
92
|
-
getQuotaErrorMessage,
|
|
93
|
-
} from '../../shared/domain/utils/error-handlers/error-messages';
|
|
94
|
-
|
|
95
|
-
// Middleware
|
|
96
|
-
export {
|
|
97
|
-
QueryDeduplicationMiddleware,
|
|
98
|
-
queryDeduplicationMiddleware,
|
|
99
|
-
syncDeduplicationWithQuota,
|
|
100
|
-
useDeduplicationWithQuota,
|
|
101
|
-
} from './infrastructure/middleware/QueryDeduplicationMiddleware';
|
|
102
|
-
export type {
|
|
103
|
-
QueryDeduplicationConfig,
|
|
104
|
-
DeduplicationStatistics,
|
|
105
|
-
} from './infrastructure/middleware/QueryDeduplicationMiddleware';
|
|
106
|
-
export {
|
|
107
|
-
QuotaTrackingMiddleware,
|
|
108
|
-
quotaTrackingMiddleware,
|
|
109
|
-
} from './infrastructure/middleware/QuotaTrackingMiddleware';
|
|
110
|
-
|
|
111
|
-
// Services
|
|
112
|
-
export {
|
|
113
|
-
RequestLoggerService,
|
|
114
|
-
requestLoggerService,
|
|
115
|
-
} from './infrastructure/services/RequestLoggerService';
|
|
116
|
-
|
|
117
62
|
// Firestore Helper Utilities
|
|
118
63
|
export {
|
|
119
64
|
withFirestore,
|
|
@@ -150,13 +95,10 @@ export {
|
|
|
150
95
|
export { useFirestoreQuery } from './presentation/hooks/useFirestoreQuery';
|
|
151
96
|
export { useFirestoreMutation } from './presentation/hooks/useFirestoreMutation';
|
|
152
97
|
export { useFirestoreSnapshot } from './presentation/hooks/useFirestoreSnapshot';
|
|
153
|
-
export { useSmartFirestoreSnapshot, useSmartListenerControl } from './presentation/hooks/useSmartFirestoreSnapshot';
|
|
154
|
-
export { createFirestoreKeys } from './presentation/query-keys/createFirestoreKeys';
|
|
155
98
|
|
|
156
99
|
export type { UseFirestoreQueryOptions } from './presentation/hooks/useFirestoreQuery';
|
|
157
100
|
export type { UseFirestoreMutationOptions } from './presentation/hooks/useFirestoreMutation';
|
|
158
101
|
export type { UseFirestoreSnapshotOptions } from './presentation/hooks/useFirestoreSnapshot';
|
|
159
|
-
export type { UseSmartFirestoreSnapshotOptions, BackgroundStrategy } from './presentation/hooks/useSmartFirestoreSnapshot';
|
|
160
102
|
|
|
161
103
|
// Firebase types are available from the 'firebase' package directly
|
|
162
104
|
// Import them in your app: import { Timestamp } from 'firebase/firestore';
|
package/src/domains/firestore/infrastructure/config/initializers/FirebaseFirestoreInitializer.ts
CHANGED
|
@@ -1,264 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
* Firebase Firestore Initializer (Enhanced)
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Initialize Firestore instance with optimal caching
|
|
5
|
-
*
|
|
6
|
-
* OPTIMIZATIONS:
|
|
7
|
-
* - Web: Persistent IndexedDB cache (survives restarts) with configurable size
|
|
8
|
-
* - React Native: Memory cache (platform limitation)
|
|
9
|
-
* - Configurable cache size limits (10 MB default for persistent cache)
|
|
10
|
-
* - Platform-aware cache strategy
|
|
11
|
-
*
|
|
12
|
-
* COST SAVINGS: ~90% reduction in network reads through persistent caching
|
|
13
|
-
*
|
|
14
|
-
* NOTE: As of Firebase v10+, cacheSizeBytes must be specified within the cache
|
|
15
|
-
* configuration object (e.g., persistentLocalCache({ cacheSizeBytes })) rather than
|
|
16
|
-
* as a separate Firestore setting. Memory cache doesn't support custom sizes.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
getFirestore,
|
|
21
|
-
initializeFirestore,
|
|
22
|
-
memoryLocalCache,
|
|
23
|
-
persistentLocalCache,
|
|
24
|
-
type FirestoreSettings,
|
|
25
|
-
} from 'firebase/firestore';
|
|
1
|
+
import { getFirestore, initializeFirestore, memoryLocalCache } from 'firebase/firestore';
|
|
26
2
|
import type { Firestore } from 'firebase/firestore';
|
|
27
3
|
import type { FirebaseApp } from 'firebase/app';
|
|
28
4
|
|
|
29
|
-
/**
|
|
30
|
-
* Cache configuration options
|
|
31
|
-
*/
|
|
32
|
-
export interface FirestoreCacheConfig {
|
|
33
|
-
/** Cache size in bytes (default: 10 MB) */
|
|
34
|
-
cacheSizeBytes?: number;
|
|
35
|
-
/** Enable persistent cache for web (default: true) */
|
|
36
|
-
enablePersistentCache?: boolean;
|
|
37
|
-
/** Force memory-only cache (useful for testing) */
|
|
38
|
-
forceMemoryCache?: boolean;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Default cache configuration
|
|
43
|
-
* Optimized for cost savings while maintaining performance
|
|
44
|
-
*/
|
|
45
|
-
const DEFAULT_CACHE_CONFIG: Required<FirestoreCacheConfig> = {
|
|
46
|
-
cacheSizeBytes: 10 * 1024 * 1024, // 10 MB
|
|
47
|
-
enablePersistentCache: true,
|
|
48
|
-
forceMemoryCache: false,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Platform detection utilities
|
|
53
|
-
*/
|
|
54
|
-
const Platform = {
|
|
55
|
-
isWeb(): boolean {
|
|
56
|
-
return typeof window !== 'undefined' && typeof window.indexedDB !== 'undefined';
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
isReactNative(): boolean {
|
|
60
|
-
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
isNode(): boolean {
|
|
64
|
-
return typeof process !== 'undefined' && process.versions?.node !== undefined;
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Creates persistent cache configuration for web platforms
|
|
70
|
-
* Uses IndexedDB to cache data across browser sessions
|
|
71
|
-
*/
|
|
72
|
-
function createPersistentCacheConfig(config: Required<FirestoreCacheConfig>): FirestoreSettings {
|
|
73
|
-
try {
|
|
74
|
-
// Create persistent cache with IndexedDB
|
|
75
|
-
// Note: cacheSizeBytes must be specified inside the cache object, not as a separate setting
|
|
76
|
-
const cacheConfig = persistentLocalCache({
|
|
77
|
-
cacheSizeBytes: config.cacheSizeBytes,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
localCache: cacheConfig,
|
|
82
|
-
};
|
|
83
|
-
} catch (error) {
|
|
84
|
-
// If persistent cache fails, fall back to memory cache
|
|
85
|
-
if (__DEV__) {
|
|
86
|
-
console.warn('[Firestore] Persistent cache failed, using memory cache:', error);
|
|
87
|
-
}
|
|
88
|
-
return createMemoryCacheConfig(config);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Creates optimized memory cache configuration for React Native
|
|
94
|
-
* Uses memory cache for platforms without IndexedDB support
|
|
95
|
-
*/
|
|
96
|
-
function createMemoryCacheConfig(config: Required<FirestoreCacheConfig>): FirestoreSettings {
|
|
97
|
-
// Memory cache - doesn't support cacheSizeBytes parameter
|
|
98
|
-
// Note: memoryLocalCache() doesn't accept any parameters
|
|
99
|
-
const cacheConfig = memoryLocalCache();
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
localCache: cacheConfig,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Initializes Firestore with optimal caching strategy based on platform
|
|
108
|
-
*
|
|
109
|
-
* @param app - Firebase app instance
|
|
110
|
-
* @param config - Cache configuration options
|
|
111
|
-
* @returns Firestore instance
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```typescript
|
|
115
|
-
* // Default configuration (recommended)
|
|
116
|
-
* const db = FirebaseFirestoreInitializer.initialize(app);
|
|
117
|
-
*
|
|
118
|
-
* // Custom cache size (20 MB)
|
|
119
|
-
* const db = FirebaseFirestoreInitializer.initialize(app, {
|
|
120
|
-
* cacheSizeBytes: 20 * 1024 * 1024,
|
|
121
|
-
* });
|
|
122
|
-
*
|
|
123
|
-
* // Force memory cache (testing)
|
|
124
|
-
* const db = FirebaseFirestoreInitializer.initialize(app, {
|
|
125
|
-
* forceMemoryCache: true,
|
|
126
|
-
* });
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
5
|
export class FirebaseFirestoreInitializer {
|
|
130
|
-
|
|
131
|
-
* Initialize Firestore with platform-optimized caching
|
|
132
|
-
*
|
|
133
|
-
* Platform Strategy:
|
|
134
|
-
* - Web: Persistent IndexedDB cache (survives restarts, 90% cost savings)
|
|
135
|
-
* - React Native: Memory cache
|
|
136
|
-
* - Node.js: Memory cache for server-side rendering
|
|
137
|
-
*/
|
|
138
|
-
static initialize(
|
|
139
|
-
app: FirebaseApp,
|
|
140
|
-
config: FirestoreCacheConfig = {}
|
|
141
|
-
): Firestore {
|
|
142
|
-
const finalConfig = { ...DEFAULT_CACHE_CONFIG, ...config };
|
|
143
|
-
|
|
6
|
+
static initialize(app: FirebaseApp): Firestore {
|
|
144
7
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
return initializeFirestore(app, createPersistentCacheConfig(finalConfig));
|
|
149
|
-
} catch (error) {
|
|
150
|
-
// IndexedDB may be disabled in private browsing mode
|
|
151
|
-
// Fall back to memory cache
|
|
152
|
-
if (__DEV__) {
|
|
153
|
-
console.warn('[Firestore] Persistent cache failed, using memory cache:', error);
|
|
154
|
-
}
|
|
155
|
-
return initializeFirestore(app, createMemoryCacheConfig(finalConfig));
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// React Native with memory cache
|
|
160
|
-
// Note: React Native doesn't support IndexedDB, use memory cache
|
|
161
|
-
if (Platform.isReactNative()) {
|
|
162
|
-
return initializeFirestore(app, createMemoryCacheConfig(finalConfig));
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Node.js / Server-side with memory cache
|
|
166
|
-
if (Platform.isNode()) {
|
|
167
|
-
return initializeFirestore(app, createMemoryCacheConfig(finalConfig));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Fallback: Try persistent cache, fall back to memory
|
|
171
|
-
return initializeFirestore(app, createPersistentCacheConfig(finalConfig));
|
|
172
|
-
} catch (error) {
|
|
173
|
-
// If initialization fails, get existing instance
|
|
174
|
-
// This handles cases where Firestore is already initialized
|
|
175
|
-
if (__DEV__) {
|
|
176
|
-
console.warn('[Firestore] Initialization failed, getting existing instance:', error);
|
|
177
|
-
}
|
|
8
|
+
return initializeFirestore(app, { localCache: memoryLocalCache() });
|
|
9
|
+
} catch {
|
|
178
10
|
return getFirestore(app);
|
|
179
11
|
}
|
|
180
12
|
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Initialize Firestore with memory-only cache
|
|
184
|
-
* Useful for testing or sensitive data that shouldn't be persisted
|
|
185
|
-
*/
|
|
186
|
-
static initializeWithMemoryCache(
|
|
187
|
-
app: FirebaseApp,
|
|
188
|
-
config: Omit<FirestoreCacheConfig, 'enablePersistentCache' | 'forceMemoryCache'> = {}
|
|
189
|
-
): Firestore {
|
|
190
|
-
return this.initialize(app, {
|
|
191
|
-
...config,
|
|
192
|
-
forceMemoryCache: true,
|
|
193
|
-
enablePersistentCache: false,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Check if persistent cache is available on current platform
|
|
199
|
-
*/
|
|
200
|
-
static isPersistentCacheAvailable(): boolean {
|
|
201
|
-
return Platform.isWeb() && typeof window.indexedDB !== 'undefined';
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Get current cache size in bytes
|
|
206
|
-
* Note: This is an estimate, actual size may vary
|
|
207
|
-
*/
|
|
208
|
-
static getEstimatedCacheSize(config: FirestoreCacheConfig = {}): number {
|
|
209
|
-
return config.cacheSizeBytes ?? DEFAULT_CACHE_CONFIG.cacheSizeBytes;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Clear all Firestore caches (useful for logout or data reset)
|
|
214
|
-
* WARNING: This will clear all cached data and force re-fetch
|
|
215
|
-
*/
|
|
216
|
-
static async clearPersistentCache(app: FirebaseApp): Promise<void> {
|
|
217
|
-
try {
|
|
218
|
-
const db = getFirestore(app);
|
|
219
|
-
await (db as any).clearPersistentCache();
|
|
220
|
-
if (__DEV__) {
|
|
221
|
-
console.log('[Firestore] Persistent cache cleared');
|
|
222
|
-
}
|
|
223
|
-
} catch (error) {
|
|
224
|
-
if (__DEV__) {
|
|
225
|
-
console.warn('[Firestore] Failed to clear persistent cache:', error);
|
|
226
|
-
}
|
|
227
|
-
throw error;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Cache statistics interface
|
|
234
|
-
*/
|
|
235
|
-
export interface CacheStatistics {
|
|
236
|
-
/** Platform type */
|
|
237
|
-
platform: 'web' | 'react-native' | 'node' | 'unknown';
|
|
238
|
-
/** Persistent cache available */
|
|
239
|
-
persistentCacheAvailable: boolean;
|
|
240
|
-
/** Current cache size limit */
|
|
241
|
-
cacheSizeBytes: number;
|
|
242
|
-
/** Estimated cache usage percentage */
|
|
243
|
-
estimatedCacheUsage: number;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Get cache statistics for monitoring and debugging
|
|
248
|
-
*/
|
|
249
|
-
export function getCacheStatistics(): CacheStatistics {
|
|
250
|
-
const platform = Platform.isWeb()
|
|
251
|
-
? 'web'
|
|
252
|
-
: Platform.isReactNative()
|
|
253
|
-
? 'react-native'
|
|
254
|
-
: Platform.isNode()
|
|
255
|
-
? 'node'
|
|
256
|
-
: 'unknown';
|
|
257
|
-
|
|
258
|
-
return {
|
|
259
|
-
platform,
|
|
260
|
-
persistentCacheAvailable: FirebaseFirestoreInitializer.isPersistentCacheAvailable(),
|
|
261
|
-
cacheSizeBytes: FirebaseFirestoreInitializer.getEstimatedCacheSize(),
|
|
262
|
-
estimatedCacheUsage: 0, // Firestore doesn't expose actual cache size
|
|
263
|
-
};
|
|
264
13
|
}
|
|
@@ -43,11 +43,9 @@ export abstract class BasePaginatedRepository extends BaseQueryRepository {
|
|
|
43
43
|
|
|
44
44
|
const collectionRef = collection(db, collectionName);
|
|
45
45
|
let q: import("firebase/firestore").Query<DocumentData>;
|
|
46
|
-
let cursorKey = 'start';
|
|
47
46
|
|
|
48
47
|
// Handle cursor-based pagination
|
|
49
48
|
if (helper.hasCursor(params) && params?.cursor) {
|
|
50
|
-
cursorKey = params.cursor;
|
|
51
49
|
|
|
52
50
|
// FIX: Validate cursor and throw error instead of silent failure
|
|
53
51
|
validateCursorOrThrow(params.cursor);
|
|
@@ -77,17 +75,13 @@ export abstract class BasePaginatedRepository extends BaseQueryRepository {
|
|
|
77
75
|
);
|
|
78
76
|
}
|
|
79
77
|
|
|
80
|
-
// Generate a unique key for deduplication (after cursor is resolved)
|
|
81
|
-
const uniqueKey = `${collectionName}_list_${orderByField}_${orderDirection}_${fetchLimit}_${cursorKey}`;
|
|
82
|
-
|
|
83
78
|
return this.executeQuery(
|
|
84
79
|
collectionName,
|
|
85
80
|
async () => {
|
|
86
81
|
const snapshot = await getDocs(q);
|
|
87
82
|
return snapshot.docs;
|
|
88
83
|
},
|
|
89
|
-
false
|
|
90
|
-
uniqueKey
|
|
84
|
+
false
|
|
91
85
|
);
|
|
92
86
|
}
|
|
93
87
|
|
|
@@ -1,44 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
* Base Repository - Query Operations
|
|
3
|
-
*
|
|
4
|
-
* Provides query and tracking operations for Firestore repositories.
|
|
5
|
-
* Extends BaseRepository with query-specific functionality.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { queryDeduplicationMiddleware } from "../middleware/QueryDeduplicationMiddleware";
|
|
9
|
-
import { BaseRepository } from "./BaseRepository";
|
|
1
|
+
import { BaseRepository } from './BaseRepository';
|
|
10
2
|
|
|
11
3
|
export abstract class BaseQueryRepository extends BaseRepository {
|
|
12
|
-
/**
|
|
13
|
-
* Execute query with deduplication and quota tracking
|
|
14
|
-
* Prevents duplicate queries and tracks quota usage
|
|
15
|
-
*/
|
|
16
4
|
protected async executeQuery<T>(
|
|
17
5
|
collection: string,
|
|
18
6
|
queryFn: () => Promise<T>,
|
|
19
|
-
cached: boolean = false
|
|
20
|
-
uniqueKey?: string
|
|
7
|
+
cached: boolean = false
|
|
21
8
|
): Promise<T> {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const queryKey = {
|
|
25
|
-
collection,
|
|
26
|
-
filters: safeKey,
|
|
27
|
-
limit: undefined,
|
|
28
|
-
orderBy: undefined,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
return queryDeduplicationMiddleware.deduplicate(queryKey, async () => {
|
|
32
|
-
const result = await queryFn();
|
|
9
|
+
const result = await queryFn();
|
|
33
10
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.trackRead(collection, count, cached);
|
|
39
|
-
}
|
|
11
|
+
if (!cached) {
|
|
12
|
+
const count = Array.isArray(result) ? result.length : 1;
|
|
13
|
+
this.trackRead(collection, count, cached);
|
|
14
|
+
}
|
|
40
15
|
|
|
41
|
-
|
|
42
|
-
});
|
|
16
|
+
return result;
|
|
43
17
|
}
|
|
44
18
|
}
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Firestore, CollectionReference, DocumentReference, DocumentData } from 'firebase/firestore';
|
|
12
12
|
import { getFirestore, collection, doc } from 'firebase/firestore';
|
|
13
|
-
import { isQuotaError as checkQuotaError } from '../../../../shared/domain/utils/error-handlers/error-checkers';
|
|
14
|
-
import { ERROR_MESSAGES } from '../../../../shared/domain/utils/error-handlers/error-messages';
|
|
15
|
-
import { quotaTrackingMiddleware } from '../middleware/QuotaTrackingMiddleware';
|
|
16
13
|
|
|
17
14
|
enum RepositoryState {
|
|
18
15
|
ACTIVE = 'active',
|
|
@@ -49,11 +46,11 @@ export abstract class BaseRepository implements IPathResolver {
|
|
|
49
46
|
*/
|
|
50
47
|
protected getDbOrThrow(): Firestore {
|
|
51
48
|
if (this.state === RepositoryState.DESTROYED) {
|
|
52
|
-
throw new Error(
|
|
49
|
+
throw new Error('Repository is destroyed');
|
|
53
50
|
}
|
|
54
51
|
const db = getFirestore();
|
|
55
52
|
if (!db) {
|
|
56
|
-
throw new Error(
|
|
53
|
+
throw new Error('Firestore is not initialized');
|
|
57
54
|
}
|
|
58
55
|
return db;
|
|
59
56
|
}
|
|
@@ -107,55 +104,19 @@ export abstract class BaseRepository implements IPathResolver {
|
|
|
107
104
|
protected async executeOperation<T>(
|
|
108
105
|
operation: () => Promise<T>
|
|
109
106
|
): Promise<T> {
|
|
110
|
-
|
|
111
|
-
return await operation();
|
|
112
|
-
} catch (error) {
|
|
113
|
-
if (checkQuotaError(error)) {
|
|
114
|
-
throw new Error(ERROR_MESSAGES.FIRESTORE.QUOTA_EXCEEDED);
|
|
115
|
-
}
|
|
116
|
-
throw error;
|
|
117
|
-
}
|
|
107
|
+
return await operation();
|
|
118
108
|
}
|
|
119
109
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
*
|
|
123
|
-
* @param collection - Collection name
|
|
124
|
-
* @param count - Number of documents read
|
|
125
|
-
* @param cached - Whether the result is from cache
|
|
126
|
-
*/
|
|
127
|
-
protected trackRead(
|
|
128
|
-
collection: string,
|
|
129
|
-
count: number = 1,
|
|
130
|
-
cached: boolean = false,
|
|
131
|
-
): void {
|
|
132
|
-
quotaTrackingMiddleware.trackRead(collection, count, cached);
|
|
110
|
+
protected trackRead(_collection: string, _count: number = 1, _cached: boolean = false): void {
|
|
111
|
+
// Quota tracking removed - use Firebase console for monitoring
|
|
133
112
|
}
|
|
134
113
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
*
|
|
138
|
-
* @param collection - Collection name
|
|
139
|
-
* @param count - Number of documents written
|
|
140
|
-
*/
|
|
141
|
-
protected trackWrite(
|
|
142
|
-
collection: string,
|
|
143
|
-
count: number = 1,
|
|
144
|
-
): void {
|
|
145
|
-
quotaTrackingMiddleware.trackWrite(collection, count);
|
|
114
|
+
protected trackWrite(_collection: string, _count: number = 1): void {
|
|
115
|
+
// Quota tracking removed - use Firebase console for monitoring
|
|
146
116
|
}
|
|
147
117
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
*
|
|
151
|
-
* @param collection - Collection name
|
|
152
|
-
* @param count - Number of documents deleted
|
|
153
|
-
*/
|
|
154
|
-
protected trackDelete(
|
|
155
|
-
collection: string,
|
|
156
|
-
count: number = 1,
|
|
157
|
-
): void {
|
|
158
|
-
quotaTrackingMiddleware.trackDelete(collection, count);
|
|
118
|
+
protected trackDelete(_collection: string, _count: number = 1): void {
|
|
119
|
+
// Quota tracking removed - use Firebase console for monitoring
|
|
159
120
|
}
|
|
160
121
|
|
|
161
122
|
/**
|
|
@@ -12,13 +12,3 @@ export {
|
|
|
12
12
|
useFirestoreSnapshot,
|
|
13
13
|
type UseFirestoreSnapshotOptions,
|
|
14
14
|
} from './useFirestoreSnapshot';
|
|
15
|
-
|
|
16
|
-
export {
|
|
17
|
-
useSmartFirestoreSnapshot,
|
|
18
|
-
useSmartListenerControl,
|
|
19
|
-
} from './useSmartFirestoreSnapshot';
|
|
20
|
-
|
|
21
|
-
export type {
|
|
22
|
-
UseSmartFirestoreSnapshotOptions,
|
|
23
|
-
BackgroundStrategy,
|
|
24
|
-
} from './useSmartFirestoreSnapshot';
|
package/src/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type {
|
|
|
32
32
|
ServiceInitializationResult,
|
|
33
33
|
} from "./shared/infrastructure/config/services/FirebaseInitializationService";
|
|
34
34
|
|
|
35
|
-
export type { FirebaseApp } from
|
|
35
|
+
export type { FirebaseApp } from 'firebase/app';
|
|
36
36
|
|
|
37
37
|
// Type Guards
|
|
38
38
|
export {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { FirebaseConfig } from '../../../domain/value-objects/FirebaseConfig';
|
|
7
7
|
import type { IFirebaseClient } from '../../../../application/ports/IFirebaseClient';
|
|
8
|
-
import type { FirebaseApp } from '
|
|
8
|
+
import type { FirebaseApp } from 'firebase/app';
|
|
9
9
|
import { FirebaseClientState } from '../state/FirebaseClientState';
|
|
10
10
|
import { FirebaseInitializationOrchestrator } from '../orchestrators/FirebaseInitializationOrchestrator';
|
|
11
11
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { FirebaseConfig } from '../../../domain/value-objects/FirebaseConfig';
|
|
7
|
-
import type { FirebaseApp } from '
|
|
7
|
+
import type { FirebaseApp } from 'firebase/app';
|
|
8
8
|
import { FirebaseClientSingleton } from '../clients/FirebaseClientSingleton';
|
|
9
9
|
import { loadFirebaseConfig } from '../FirebaseConfigLoader';
|
|
10
10
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Uses generic ClientStateManager for shared functionality
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { FirebaseApp } from '
|
|
9
|
+
import type { FirebaseApp } from 'firebase/app';
|
|
10
10
|
import { ClientStateManager } from '../base/ClientStateManager';
|
|
11
11
|
|
|
12
12
|
export class FirebaseClientState extends ClientStateManager<FirebaseApp> {
|