@umituz/react-native-firebase 1.13.22 → 1.13.23
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/firestore/domain/entities/QuotaMetrics.ts +26 -0
- package/src/firestore/domain/entities/RequestLog.ts +28 -0
- package/src/firestore/index.ts +10 -26
- package/src/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +103 -0
- package/src/firestore/utils/quota-error-detector.util.ts +59 -0
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.23",
|
|
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",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Metrics Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface QuotaMetrics {
|
|
6
|
+
readCount: number;
|
|
7
|
+
writeCount: number;
|
|
8
|
+
deleteCount: number;
|
|
9
|
+
lastResetDate: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface QuotaLimits {
|
|
13
|
+
dailyReadLimit: number;
|
|
14
|
+
dailyWriteLimit: number;
|
|
15
|
+
dailyDeleteLimit: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface QuotaStatus {
|
|
19
|
+
metrics: QuotaMetrics;
|
|
20
|
+
limits: QuotaLimits;
|
|
21
|
+
readPercentage: number;
|
|
22
|
+
writePercentage: number;
|
|
23
|
+
deletePercentage: number;
|
|
24
|
+
isNearLimit: boolean;
|
|
25
|
+
isOverLimit: boolean;
|
|
26
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Log Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type RequestType = 'read' | 'write' | 'delete' | 'listener';
|
|
6
|
+
|
|
7
|
+
export interface RequestLog {
|
|
8
|
+
id: string;
|
|
9
|
+
type: RequestType;
|
|
10
|
+
collection: string;
|
|
11
|
+
documentId?: string;
|
|
12
|
+
cached: boolean;
|
|
13
|
+
success: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
duration?: number;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RequestStats {
|
|
20
|
+
totalRequests: number;
|
|
21
|
+
readRequests: number;
|
|
22
|
+
writeRequests: number;
|
|
23
|
+
deleteRequests: number;
|
|
24
|
+
listenerRequests: number;
|
|
25
|
+
cachedRequests: number;
|
|
26
|
+
failedRequests: number;
|
|
27
|
+
averageDuration: number;
|
|
28
|
+
}
|
package/src/firestore/index.ts
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* React Native Firestore Module
|
|
3
3
|
* Domain-Driven Design (DDD) Architecture
|
|
4
|
-
*
|
|
5
|
-
* This is the SINGLE SOURCE OF TRUTH for all Firestore operations.
|
|
6
|
-
* ALL imports from the Firestore module MUST go through this file.
|
|
7
|
-
*
|
|
8
|
-
* Architecture:
|
|
9
|
-
* - domain: Errors, Constants, Entities, Services
|
|
10
|
-
* - infrastructure: Firestore client, BaseRepository, utilities
|
|
11
|
-
* - utils: Date utilities, timestamp conversion, query builders
|
|
12
|
-
*
|
|
13
|
-
* This module is designed to be used across hundreds of apps.
|
|
14
|
-
* It provides a consistent interface for Firestore operations.
|
|
15
4
|
*/
|
|
16
5
|
|
|
17
6
|
// =============================================================================
|
|
@@ -98,16 +87,6 @@ export {
|
|
|
98
87
|
createDocumentMapper,
|
|
99
88
|
} from './utils/document-mapper.helper';
|
|
100
89
|
|
|
101
|
-
// =============================================================================
|
|
102
|
-
// UTILS - Quota Error Detection
|
|
103
|
-
// =============================================================================
|
|
104
|
-
|
|
105
|
-
export {
|
|
106
|
-
isQuotaError,
|
|
107
|
-
isRetryableError,
|
|
108
|
-
getQuotaErrorMessage,
|
|
109
|
-
} from './utils/quota-error-detector.util';
|
|
110
|
-
|
|
111
90
|
// =============================================================================
|
|
112
91
|
// UTILS - Path Resolver
|
|
113
92
|
// =============================================================================
|
|
@@ -148,6 +127,16 @@ export type {
|
|
|
148
127
|
|
|
149
128
|
export { QuotaCalculator } from './domain/services/QuotaCalculator';
|
|
150
129
|
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// UTILS - Quota Error Detection
|
|
132
|
+
// =============================================================================
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
isQuotaError,
|
|
136
|
+
isRetryableError,
|
|
137
|
+
getQuotaErrorMessage,
|
|
138
|
+
} from './utils/quota-error-detector.util';
|
|
139
|
+
|
|
151
140
|
// =============================================================================
|
|
152
141
|
// INFRASTRUCTURE LAYER - Middleware
|
|
153
142
|
// =============================================================================
|
|
@@ -166,11 +155,6 @@ export {
|
|
|
166
155
|
// INFRASTRUCTURE LAYER - Services
|
|
167
156
|
// =============================================================================
|
|
168
157
|
|
|
169
|
-
export {
|
|
170
|
-
QuotaMonitorService,
|
|
171
|
-
quotaMonitorService,
|
|
172
|
-
} from './infrastructure/services/QuotaMonitorService';
|
|
173
|
-
|
|
174
158
|
export {
|
|
175
159
|
RequestLoggerService,
|
|
176
160
|
requestLoggerService,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Tracking Middleware
|
|
3
|
+
* Tracks Firestore operations for quota monitoring
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare const __DEV__: boolean;
|
|
7
|
+
|
|
8
|
+
interface OperationInfo {
|
|
9
|
+
type: 'read' | 'write' | 'delete';
|
|
10
|
+
collection: string;
|
|
11
|
+
count: number;
|
|
12
|
+
cached: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class QuotaTrackingMiddleware {
|
|
16
|
+
private readCount = 0;
|
|
17
|
+
private writeCount = 0;
|
|
18
|
+
private deleteCount = 0;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Track a Firestore operation
|
|
22
|
+
*/
|
|
23
|
+
async trackOperation<T>(
|
|
24
|
+
info: OperationInfo,
|
|
25
|
+
operation: () => Promise<T>
|
|
26
|
+
): Promise<T> {
|
|
27
|
+
const result = await operation();
|
|
28
|
+
|
|
29
|
+
switch (info.type) {
|
|
30
|
+
case 'read':
|
|
31
|
+
if (!info.cached) {
|
|
32
|
+
this.readCount += info.count;
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case 'write':
|
|
36
|
+
this.writeCount += info.count;
|
|
37
|
+
break;
|
|
38
|
+
case 'delete':
|
|
39
|
+
this.deleteCount += info.count;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (__DEV__) {
|
|
44
|
+
console.log(`[QuotaTracking] ${info.type}: ${info.collection} (${info.count})`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Track read operation
|
|
52
|
+
*/
|
|
53
|
+
trackRead(collection: string, count: number = 1, cached: boolean = false): void {
|
|
54
|
+
if (!cached) {
|
|
55
|
+
this.readCount += count;
|
|
56
|
+
}
|
|
57
|
+
if (__DEV__) {
|
|
58
|
+
console.log(`[QuotaTracking] read: ${collection} (${count})`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Track write operation
|
|
64
|
+
*/
|
|
65
|
+
trackWrite(collection: string, _documentId?: string, count: number = 1): void {
|
|
66
|
+
this.writeCount += count;
|
|
67
|
+
if (__DEV__) {
|
|
68
|
+
console.log(`[QuotaTracking] write: ${collection} (${count})`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Track delete operation
|
|
74
|
+
*/
|
|
75
|
+
trackDelete(collection: string, _documentId?: string, count: number = 1): void {
|
|
76
|
+
this.deleteCount += count;
|
|
77
|
+
if (__DEV__) {
|
|
78
|
+
console.log(`[QuotaTracking] delete: ${collection} (${count})`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get current counts
|
|
84
|
+
*/
|
|
85
|
+
getCounts(): { reads: number; writes: number; deletes: number } {
|
|
86
|
+
return {
|
|
87
|
+
reads: this.readCount,
|
|
88
|
+
writes: this.writeCount,
|
|
89
|
+
deletes: this.deleteCount,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Reset counts
|
|
95
|
+
*/
|
|
96
|
+
reset(): void {
|
|
97
|
+
this.readCount = 0;
|
|
98
|
+
this.writeCount = 0;
|
|
99
|
+
this.deleteCount = 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const quotaTrackingMiddleware = new QuotaTrackingMiddleware();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Error Detection Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const QUOTA_ERROR_CODES = [
|
|
6
|
+
'resource-exhausted',
|
|
7
|
+
'quota-exceeded',
|
|
8
|
+
'RESOURCE_EXHAUSTED',
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const QUOTA_ERROR_MESSAGES = [
|
|
12
|
+
'quota',
|
|
13
|
+
'exceeded',
|
|
14
|
+
'limit',
|
|
15
|
+
'too many requests',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Check if error is a Firestore quota error
|
|
20
|
+
*/
|
|
21
|
+
export function isQuotaError(error: unknown): boolean {
|
|
22
|
+
if (!error) return false;
|
|
23
|
+
|
|
24
|
+
const errorObj = error as Record<string, unknown>;
|
|
25
|
+
const code = errorObj.code as string | undefined;
|
|
26
|
+
const message = errorObj.message as string | undefined;
|
|
27
|
+
|
|
28
|
+
if (code && QUOTA_ERROR_CODES.some((c) => code.includes(c))) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (message) {
|
|
33
|
+
const lowerMessage = message.toLowerCase();
|
|
34
|
+
return QUOTA_ERROR_MESSAGES.some((m) => lowerMessage.includes(m));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Check if error is retryable
|
|
42
|
+
*/
|
|
43
|
+
export function isRetryableError(error: unknown): boolean {
|
|
44
|
+
if (!error) return false;
|
|
45
|
+
|
|
46
|
+
const errorObj = error as Record<string, unknown>;
|
|
47
|
+
const code = errorObj.code as string | undefined;
|
|
48
|
+
|
|
49
|
+
const retryableCodes = ['unavailable', 'deadline-exceeded', 'aborted'];
|
|
50
|
+
|
|
51
|
+
return code ? retryableCodes.some((c) => code.includes(c)) : false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get user-friendly quota error message
|
|
56
|
+
*/
|
|
57
|
+
export function getQuotaErrorMessage(): string {
|
|
58
|
+
return 'Daily quota exceeded. Please try again tomorrow or upgrade your plan.';
|
|
59
|
+
}
|