@umituz/react-native-firebase 1.13.2 → 1.13.4

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 (44) hide show
  1. package/package.json +10 -2
  2. package/src/auth/domain/entities/AnonymousUser.ts +44 -0
  3. package/src/auth/domain/errors/FirebaseAuthError.ts +18 -0
  4. package/src/auth/domain/value-objects/FirebaseAuthConfig.ts +45 -0
  5. package/src/auth/index.ts +146 -0
  6. package/src/auth/infrastructure/config/FirebaseAuthClient.ts +210 -0
  7. package/src/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +148 -0
  8. package/src/auth/infrastructure/services/account-deletion.service.ts +250 -0
  9. package/src/auth/infrastructure/services/anonymous-auth.service.ts +135 -0
  10. package/src/auth/infrastructure/services/apple-auth.service.ts +146 -0
  11. package/src/auth/infrastructure/services/auth-guard.service.ts +97 -0
  12. package/src/auth/infrastructure/services/auth-utils.service.ts +168 -0
  13. package/src/auth/infrastructure/services/firestore-utils.service.ts +155 -0
  14. package/src/auth/infrastructure/services/google-auth.service.ts +100 -0
  15. package/src/auth/infrastructure/services/reauthentication.service.ts +216 -0
  16. package/src/auth/presentation/hooks/useAnonymousAuth.ts +201 -0
  17. package/src/auth/presentation/hooks/useFirebaseAuth.ts +84 -0
  18. package/src/auth/presentation/hooks/useSocialAuth.ts +162 -0
  19. package/src/firestore/__tests__/BaseRepository.test.ts +133 -0
  20. package/src/firestore/__tests__/QueryDeduplicationMiddleware.test.ts +147 -0
  21. package/src/firestore/__tests__/mocks/react-native-firebase.ts +23 -0
  22. package/src/firestore/__tests__/setup.ts +36 -0
  23. package/src/firestore/domain/constants/QuotaLimits.ts +97 -0
  24. package/src/firestore/domain/entities/QuotaMetrics.ts +28 -0
  25. package/src/firestore/domain/entities/RequestLog.ts +30 -0
  26. package/src/firestore/domain/errors/FirebaseFirestoreError.ts +52 -0
  27. package/src/firestore/domain/services/QuotaCalculator.ts +70 -0
  28. package/src/firestore/index.ts +174 -0
  29. package/src/firestore/infrastructure/config/FirestoreClient.ts +181 -0
  30. package/src/firestore/infrastructure/config/initializers/FirebaseFirestoreInitializer.ts +46 -0
  31. package/src/firestore/infrastructure/middleware/QueryDeduplicationMiddleware.ts +153 -0
  32. package/src/firestore/infrastructure/middleware/QuotaTrackingMiddleware.ts +165 -0
  33. package/src/firestore/infrastructure/repositories/BasePaginatedRepository.ts +90 -0
  34. package/src/firestore/infrastructure/repositories/BaseQueryRepository.ts +80 -0
  35. package/src/firestore/infrastructure/repositories/BaseRepository.ts +147 -0
  36. package/src/firestore/infrastructure/services/QuotaMonitorService.ts +108 -0
  37. package/src/firestore/infrastructure/services/RequestLoggerService.ts +139 -0
  38. package/src/firestore/types/pagination.types.ts +60 -0
  39. package/src/firestore/utils/dateUtils.ts +31 -0
  40. package/src/firestore/utils/document-mapper.helper.ts +145 -0
  41. package/src/firestore/utils/pagination.helper.ts +93 -0
  42. package/src/firestore/utils/query-builder.ts +188 -0
  43. package/src/firestore/utils/quota-error-detector.util.ts +100 -0
  44. package/src/index.ts +16 -0
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Tests for QueryDeduplicationMiddleware
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
6
+ import { QueryDeduplicationMiddleware } from '../infrastructure/middleware/QueryDeduplicationMiddleware';
7
+
8
+ describe('QueryDeduplicationMiddleware', () => {
9
+ let middleware: QueryDeduplicationMiddleware;
10
+
11
+ beforeEach(() => {
12
+ middleware = new QueryDeduplicationMiddleware();
13
+ jest.useFakeTimers();
14
+ });
15
+
16
+ afterEach(() => {
17
+ middleware.destroy();
18
+ jest.useRealTimers();
19
+ });
20
+
21
+ describe('deduplicate', () => {
22
+ it('should execute query immediately if not pending', async () => {
23
+ const queryFn = jest.fn().mockResolvedValue('result');
24
+ const queryKey = {
25
+ collection: 'test',
26
+ filters: 'field == value',
27
+ limit: 10,
28
+ orderBy: 'createdAt',
29
+ };
30
+
31
+ const result = await middleware.deduplicate(queryKey, queryFn);
32
+ expect(result).toBe('result');
33
+ expect(queryFn).toHaveBeenCalledTimes(1);
34
+ });
35
+
36
+ it('should deduplicate identical queries within window', async () => {
37
+ const queryFn = jest.fn().mockResolvedValue('result');
38
+ const queryKey = {
39
+ collection: 'test',
40
+ filters: 'field == value',
41
+ limit: 10,
42
+ orderBy: 'createdAt',
43
+ };
44
+
45
+ const promise1 = middleware.deduplicate(queryKey, queryFn);
46
+ const promise2 = middleware.deduplicate(queryKey, queryFn);
47
+
48
+ const [result1, result2] = await Promise.all([promise1, promise2]);
49
+ expect(result1).toBe('result');
50
+ expect(result2).toBe('result');
51
+ expect(queryFn).toHaveBeenCalledTimes(1);
52
+ });
53
+
54
+ it('should execute new query after deduplication window', async () => {
55
+ const queryFn = jest.fn().mockResolvedValue('result');
56
+ const queryKey = {
57
+ collection: 'test',
58
+ filters: 'field == value',
59
+ limit: 10,
60
+ orderBy: 'createdAt',
61
+ };
62
+
63
+ await middleware.deduplicate(queryKey, queryFn);
64
+ expect(queryFn).toHaveBeenCalledTimes(1);
65
+
66
+ // Advance time beyond deduplication window
67
+ jest.advanceTimersByTime(1100);
68
+
69
+ await middleware.deduplicate(queryKey, queryFn);
70
+ expect(queryFn).toHaveBeenCalledTimes(2);
71
+ });
72
+
73
+ it('should handle different query keys separately', async () => {
74
+ const queryFn = jest.fn().mockResolvedValue('result');
75
+ const queryKey1 = {
76
+ collection: 'test1',
77
+ filters: 'field == value',
78
+ limit: 10,
79
+ orderBy: 'createdAt',
80
+ };
81
+ const queryKey2 = {
82
+ collection: 'test2',
83
+ filters: 'field == value',
84
+ limit: 10,
85
+ orderBy: 'createdAt',
86
+ };
87
+
88
+ await middleware.deduplicate(queryKey1, queryFn);
89
+ await middleware.deduplicate(queryKey2, queryFn);
90
+
91
+ expect(queryFn).toHaveBeenCalledTimes(2);
92
+ });
93
+ });
94
+
95
+ describe('cleanup', () => {
96
+ it('should clean up expired queries automatically', async () => {
97
+ const queryFn = jest.fn().mockResolvedValue('result');
98
+ const queryKey = {
99
+ collection: 'test',
100
+ filters: 'field == value',
101
+ limit: 10,
102
+ orderBy: 'createdAt',
103
+ };
104
+
105
+ await middleware.deduplicate(queryKey, queryFn);
106
+ expect(middleware.getPendingCount()).toBe(0);
107
+
108
+ // Advance time to trigger cleanup
109
+ jest.advanceTimersByTime(6000);
110
+ expect(middleware.getPendingCount()).toBe(0);
111
+ });
112
+ });
113
+
114
+ describe('clear', () => {
115
+ it('should clear all pending queries', async () => {
116
+ const queryFn = jest.fn(() => new Promise(() => {})); // Never resolves
117
+ const queryKey = {
118
+ collection: 'test',
119
+ filters: 'field == value',
120
+ limit: 10,
121
+ orderBy: 'createdAt',
122
+ };
123
+
124
+ middleware.deduplicate(queryKey, queryFn);
125
+ expect(middleware.getPendingCount()).toBe(1);
126
+
127
+ middleware.clear();
128
+ expect(middleware.getPendingCount()).toBe(0);
129
+ });
130
+ });
131
+
132
+ describe('destroy', () => {
133
+ it('should cleanup resources and clear queries', () => {
134
+ const queryKey = {
135
+ collection: 'test',
136
+ filters: 'field == value',
137
+ limit: 10,
138
+ orderBy: 'createdAt',
139
+ };
140
+
141
+ middleware.deduplicate(queryKey, () => Promise.resolve('result'));
142
+ middleware.destroy();
143
+
144
+ expect(middleware.getPendingCount()).toBe(0);
145
+ });
146
+ });
147
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Mock for @umituz/react-native-firebase
3
+ */
4
+
5
+ export class FirebaseError extends Error {
6
+ code: string;
7
+ originalError?: unknown;
8
+
9
+ constructor(message: string, code?: string, originalError?: unknown) {
10
+ super(message);
11
+ this.name = 'FirebaseError';
12
+ this.code = code || 'UNKNOWN';
13
+ this.originalError = originalError;
14
+ }
15
+ }
16
+
17
+ export function getFirebaseApp(): any {
18
+ return null;
19
+ }
20
+
21
+ export function initializeFirebase(): any {
22
+ return null;
23
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Jest setup file
3
+ */
4
+
5
+ // Mock __DEV__ for tests
6
+ export {};
7
+
8
+ declare global {
9
+ var __DEV__: boolean | undefined;
10
+ }
11
+
12
+ if (typeof (global as any).__DEV__ === 'undefined') {
13
+ (global as any).__DEV__ = true;
14
+ }
15
+
16
+ // Mock console methods to avoid noise in tests
17
+ const originalConsole = { ...console };
18
+
19
+ beforeEach(() => {
20
+ // Restore console methods before each test
21
+ Object.assign(console, originalConsole);
22
+ });
23
+
24
+ // Set up global test utilities
25
+ global.mockFirestore = () => ({
26
+ collection: jest.fn(),
27
+ doc: jest.fn(),
28
+ runTransaction: jest.fn(),
29
+ batch: jest.fn(),
30
+ });
31
+
32
+ global.mockFirebaseError = (code: string, message: string) => {
33
+ const error = new Error(message) as any;
34
+ error.code = code;
35
+ return error;
36
+ };
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Quota Limit Constants
3
+ * Domain layer - Default Firestore quota limits
4
+ *
5
+ * General-purpose constants for any app using Firestore
6
+ * Based on Firestore free tier and pricing documentation
7
+ */
8
+
9
+ /**
10
+ * Firestore free tier daily limits
11
+ * https://firebase.google.com/docs/firestore/quotas
12
+ */
13
+ export const FREE_TIER_LIMITS = {
14
+ /**
15
+ * Daily read operations (documents)
16
+ * Free tier: 50,000 reads/day
17
+ */
18
+ DAILY_READS: 50_000,
19
+
20
+ /**
21
+ * Daily write operations (documents)
22
+ * Free tier: 20,000 writes/day
23
+ */
24
+ DAILY_WRITES: 20_000,
25
+
26
+ /**
27
+ * Daily delete operations (documents)
28
+ * Free tier: 20,000 deletes/day
29
+ */
30
+ DAILY_DELETES: 20_000,
31
+
32
+ /**
33
+ * Stored data (GB)
34
+ * Free tier: 1 GB
35
+ */
36
+ STORAGE_GB: 1,
37
+ } as const;
38
+
39
+ /**
40
+ * Quota warning thresholds (percentage of limit)
41
+ * Apps can use these to show warnings before hitting limits
42
+ */
43
+ export const QUOTA_THRESHOLDS = {
44
+ /**
45
+ * Warning threshold (80% of limit)
46
+ * Show warning to user
47
+ */
48
+ WARNING: 0.8,
49
+
50
+ /**
51
+ * Critical threshold (95% of limit)
52
+ * Show critical alert, consider disabling features
53
+ */
54
+ CRITICAL: 0.95,
55
+
56
+ /**
57
+ * Emergency threshold (98% of limit)
58
+ * Disable non-essential features
59
+ */
60
+ EMERGENCY: 0.98,
61
+ } as const;
62
+
63
+ /**
64
+ * Calculate quota usage percentage
65
+ * @param current - Current usage count
66
+ * @param limit - Total limit
67
+ * @returns Percentage (0-1)
68
+ */
69
+ export function calculateQuotaUsage(current: number, limit: number): number {
70
+ return Math.min(1, current / limit);
71
+ }
72
+
73
+ /**
74
+ * Check if quota threshold is reached
75
+ * @param current - Current usage count
76
+ * @param limit - Total limit
77
+ * @param threshold - Threshold to check (0-1)
78
+ * @returns true if threshold is reached
79
+ */
80
+ export function isQuotaThresholdReached(
81
+ current: number,
82
+ limit: number,
83
+ threshold: number,
84
+ ): boolean {
85
+ const usage = calculateQuotaUsage(current, limit);
86
+ return usage >= threshold;
87
+ }
88
+
89
+ /**
90
+ * Get remaining quota
91
+ * @param current - Current usage count
92
+ * @param limit - Total limit
93
+ * @returns Remaining quota count
94
+ */
95
+ export function getRemainingQuota(current: number, limit: number): number {
96
+ return Math.max(0, limit - current);
97
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Quota Metrics Entity
3
+ * Domain entity for tracking Firestore quota usage
4
+ */
5
+
6
+ export interface QuotaMetrics {
7
+ readCount: number;
8
+ writeCount: number;
9
+ deleteCount: number;
10
+ timestamp: number;
11
+ }
12
+
13
+ export interface QuotaLimits {
14
+ dailyReadLimit: number;
15
+ dailyWriteLimit: number;
16
+ dailyDeleteLimit: number;
17
+ }
18
+
19
+ export interface QuotaStatus {
20
+ metrics: QuotaMetrics;
21
+ limits: QuotaLimits;
22
+ readPercentage: number;
23
+ writePercentage: number;
24
+ deletePercentage: number;
25
+ isNearLimit: boolean;
26
+ isOverLimit: boolean;
27
+ }
28
+
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Request Log Entity
3
+ * Domain entity for tracking Firestore requests
4
+ */
5
+
6
+ export type RequestType = 'read' | 'write' | 'delete' | 'listener';
7
+
8
+ export interface RequestLog {
9
+ id: string;
10
+ type: RequestType;
11
+ collection: string;
12
+ documentId?: string;
13
+ timestamp: number;
14
+ duration?: number;
15
+ success: boolean;
16
+ error?: string;
17
+ cached: boolean;
18
+ }
19
+
20
+ export interface RequestStats {
21
+ totalRequests: number;
22
+ readRequests: number;
23
+ writeRequests: number;
24
+ deleteRequests: number;
25
+ listenerRequests: number;
26
+ cachedRequests: number;
27
+ failedRequests: number;
28
+ averageDuration: number;
29
+ }
30
+
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Firebase Firestore Domain Errors
3
+ *
4
+ * Domain-Driven Design: Error types for Firestore operations
5
+ */
6
+
7
+ import { FirebaseError } from '../../../domain/errors/FirebaseError';
8
+
9
+ /**
10
+ * Firestore Error
11
+ * Thrown when Firestore operations fail
12
+ */
13
+ export class FirebaseFirestoreError extends FirebaseError {
14
+ constructor(message: string, originalError?: unknown) {
15
+ super(message, 'FIRESTORE_ERROR', originalError);
16
+ this.name = 'FirebaseFirestoreError';
17
+ Object.setPrototypeOf(this, FirebaseFirestoreError.prototype);
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Firestore Initialization Error
23
+ * Thrown when Firestore fails to initialize
24
+ */
25
+ export class FirebaseFirestoreInitializationError extends FirebaseFirestoreError {
26
+ constructor(message: string, originalError?: unknown) {
27
+ super(message, originalError);
28
+ this.name = 'FirebaseFirestoreInitializationError';
29
+ Object.setPrototypeOf(this, FirebaseFirestoreInitializationError.prototype);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Firestore Quota Error
35
+ * Thrown when Firebase quota limits are exceeded
36
+ *
37
+ * Firebase quota limits:
38
+ * - Free tier: 50K reads/day, 20K writes/day, 20K deletes/day
39
+ * - Blaze plan: Pay as you go, higher limits
40
+ *
41
+ * This error is NOT retryable - quota won't increase by retrying
42
+ */
43
+ export class FirebaseFirestoreQuotaError extends FirebaseFirestoreError {
44
+ constructor(message: string, originalError?: unknown) {
45
+ super(message, originalError);
46
+ this.name = 'FirebaseFirestoreQuotaError';
47
+ (this as any).isQuotaError = true;
48
+ (this as any).code = 'resource-exhausted';
49
+ Object.setPrototypeOf(this, FirebaseFirestoreQuotaError.prototype);
50
+ }
51
+ }
52
+
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Quota Calculator Service
3
+ * Domain service for calculating quota usage and status
4
+ */
5
+
6
+ import type { QuotaMetrics, QuotaLimits, QuotaStatus } from '../entities/QuotaMetrics';
7
+ import { FREE_TIER_LIMITS } from '../constants/QuotaLimits';
8
+
9
+ /**
10
+ * Default quota limits (Firebase Spark Plan)
11
+ * Can be overridden via configuration
12
+ */
13
+ const DEFAULT_QUOTA_LIMITS: QuotaLimits = {
14
+ dailyReadLimit: FREE_TIER_LIMITS.DAILY_READS,
15
+ dailyWriteLimit: FREE_TIER_LIMITS.DAILY_WRITES,
16
+ dailyDeleteLimit: FREE_TIER_LIMITS.DAILY_DELETES,
17
+ };
18
+
19
+ export class QuotaCalculator {
20
+ /**
21
+ * Calculate quota status from metrics and limits
22
+ */
23
+ static calculateStatus(
24
+ metrics: QuotaMetrics,
25
+ limits: QuotaLimits = DEFAULT_QUOTA_LIMITS,
26
+ ): QuotaStatus {
27
+ const readPercentage = (metrics.readCount / limits.dailyReadLimit) * 100;
28
+ const writePercentage = (metrics.writeCount / limits.dailyWriteLimit) * 100;
29
+ const deletePercentage = (metrics.deleteCount / limits.dailyDeleteLimit) * 100;
30
+
31
+ const isNearLimit =
32
+ readPercentage >= 80 ||
33
+ writePercentage >= 80 ||
34
+ deletePercentage >= 80;
35
+
36
+ const isOverLimit =
37
+ readPercentage >= 100 ||
38
+ writePercentage >= 100 ||
39
+ deletePercentage >= 100;
40
+
41
+ return {
42
+ metrics,
43
+ limits,
44
+ readPercentage,
45
+ writePercentage,
46
+ deletePercentage,
47
+ isNearLimit,
48
+ isOverLimit,
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Get default quota limits
54
+ */
55
+ static getDefaultLimits(): QuotaLimits {
56
+ return { ...DEFAULT_QUOTA_LIMITS };
57
+ }
58
+
59
+ /**
60
+ * Check if metrics are within limits
61
+ */
62
+ static isWithinLimits(
63
+ metrics: QuotaMetrics,
64
+ limits: QuotaLimits = DEFAULT_QUOTA_LIMITS,
65
+ ): boolean {
66
+ const status = this.calculateStatus(metrics, limits);
67
+ return !status.isOverLimit;
68
+ }
69
+ }
70
+
@@ -0,0 +1,174 @@
1
+ /**
2
+ * React Native Firestore Module
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
+ */
16
+
17
+ // =============================================================================
18
+ // DOMAIN LAYER - Errors
19
+ // =============================================================================
20
+
21
+ export {
22
+ FirebaseFirestoreError,
23
+ FirebaseFirestoreInitializationError,
24
+ FirebaseFirestoreQuotaError,
25
+ } from './domain/errors/FirebaseFirestoreError';
26
+
27
+ // =============================================================================
28
+ // INFRASTRUCTURE LAYER - Firestore Client
29
+ // =============================================================================
30
+
31
+ export {
32
+ initializeFirestore,
33
+ getFirestore,
34
+ isFirestoreInitialized,
35
+ getFirestoreInitializationError,
36
+ resetFirestoreClient,
37
+ firestoreClient,
38
+ } from './infrastructure/config/FirestoreClient';
39
+
40
+ export type { Firestore } from './infrastructure/config/FirestoreClient';
41
+
42
+ // =============================================================================
43
+ // INFRASTRUCTURE LAYER - BaseRepository
44
+ // =============================================================================
45
+
46
+ export { BaseRepository } from './infrastructure/repositories/BaseRepository';
47
+ export { BaseQueryRepository } from './infrastructure/repositories/BaseQueryRepository';
48
+ export { BasePaginatedRepository } from './infrastructure/repositories/BasePaginatedRepository';
49
+
50
+ // =============================================================================
51
+ // UTILS - Date Utilities
52
+ // =============================================================================
53
+
54
+ export {
55
+ isoToTimestamp,
56
+ timestampToISO,
57
+ timestampToDate,
58
+ getCurrentISOString,
59
+ } from './utils/dateUtils';
60
+
61
+ // =============================================================================
62
+ // UTILS - Query Builder
63
+ // =============================================================================
64
+
65
+ export {
66
+ buildQuery,
67
+ createInFilter,
68
+ createEqualFilter,
69
+ } from './utils/query-builder';
70
+
71
+ export type {
72
+ QueryBuilderOptions,
73
+ FieldFilter,
74
+ } from './utils/query-builder';
75
+
76
+ // =============================================================================
77
+ // UTILS - Pagination
78
+ // =============================================================================
79
+
80
+ export {
81
+ PaginationHelper,
82
+ createPaginationHelper,
83
+ } from './utils/pagination.helper';
84
+
85
+ export type {
86
+ PaginatedResult,
87
+ PaginationParams,
88
+ } from './types/pagination.types';
89
+
90
+ export { EMPTY_PAGINATED_RESULT } from './types/pagination.types';
91
+
92
+ // =============================================================================
93
+ // UTILS - Document Mapper
94
+ // =============================================================================
95
+
96
+ export {
97
+ DocumentMapperHelper,
98
+ createDocumentMapper,
99
+ } from './utils/document-mapper.helper';
100
+
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
+ // =============================================================================
112
+ // DOMAIN LAYER - Constants
113
+ // =============================================================================
114
+
115
+ export {
116
+ FREE_TIER_LIMITS,
117
+ QUOTA_THRESHOLDS,
118
+ calculateQuotaUsage,
119
+ isQuotaThresholdReached,
120
+ getRemainingQuota,
121
+ } from './domain/constants/QuotaLimits';
122
+
123
+ // =============================================================================
124
+ // DOMAIN LAYER - Entities
125
+ // =============================================================================
126
+
127
+ export type {
128
+ QuotaMetrics,
129
+ QuotaLimits,
130
+ QuotaStatus,
131
+ } from './domain/entities/QuotaMetrics';
132
+
133
+ export type {
134
+ RequestLog,
135
+ RequestStats,
136
+ RequestType,
137
+ } from './domain/entities/RequestLog';
138
+
139
+ // =============================================================================
140
+ // DOMAIN LAYER - Services
141
+ // =============================================================================
142
+
143
+ export { QuotaCalculator } from './domain/services/QuotaCalculator';
144
+
145
+ // =============================================================================
146
+ // INFRASTRUCTURE LAYER - Middleware
147
+ // =============================================================================
148
+
149
+ export {
150
+ QueryDeduplicationMiddleware,
151
+ queryDeduplicationMiddleware,
152
+ } from './infrastructure/middleware/QueryDeduplicationMiddleware';
153
+
154
+ export {
155
+ QuotaTrackingMiddleware,
156
+ quotaTrackingMiddleware,
157
+ } from './infrastructure/middleware/QuotaTrackingMiddleware';
158
+
159
+ // =============================================================================
160
+ // INFRASTRUCTURE LAYER - Services
161
+ // =============================================================================
162
+
163
+ export {
164
+ QuotaMonitorService,
165
+ quotaMonitorService,
166
+ } from './infrastructure/services/QuotaMonitorService';
167
+
168
+ export {
169
+ RequestLoggerService,
170
+ requestLoggerService,
171
+ } from './infrastructure/services/RequestLoggerService';
172
+
173
+ // Re-export Firestore types for convenience
174
+ export type { Timestamp } from 'firebase/firestore';