@umituz/react-native-firebase 1.13.121 → 1.13.122
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/auth/infrastructure/services/account-deletion.service.ts +4 -4
- package/src/auth/infrastructure/services/auth-utils.service.ts +2 -1
- package/src/auth/infrastructure/services/reauthentication.service.ts +15 -28
- package/src/domain/utils/error-handler.util.ts +90 -0
- package/src/domain/utils/id-generator.util.ts +50 -0
- package/src/domain/utils/validation.util.ts +133 -0
- package/src/firestore/infrastructure/middleware/QueryDeduplicationMiddleware.ts +26 -117
- package/src/firestore/infrastructure/services/RequestLoggerService.ts +2 -8
- package/src/firestore/utils/deduplication/index.ts +13 -0
- package/src/firestore/utils/deduplication/pending-query-manager.util.ts +93 -0
- package/src/firestore/utils/deduplication/query-key-generator.util.ts +41 -0
- package/src/firestore/utils/deduplication/timer-manager.util.ts +59 -0
- package/src/firestore/utils/document-mapper.helper.ts +45 -37
- package/src/firestore/utils/firestore-helper.ts +21 -85
- package/src/firestore/utils/mapper/base-mapper.util.ts +42 -0
- package/src/firestore/utils/mapper/enrichment-mapper.util.ts +82 -0
- package/src/firestore/utils/mapper/index.ts +8 -0
- package/src/firestore/utils/mapper/multi-enrichment-mapper.util.ts +39 -0
- package/src/firestore/utils/operation/operation-executor.util.ts +49 -0
- package/src/firestore/utils/query/filters.util.ts +75 -0
- package/src/firestore/utils/query/index.ts +10 -0
- package/src/firestore/utils/query/modifiers.util.ts +65 -0
- package/src/firestore/utils/query-builder.ts +7 -108
- package/src/firestore/utils/result/result.util.ts +45 -0
- package/src/firestore/utils/transaction/transaction.util.ts +45 -0
- package/src/index.ts +0 -1
- package/src/infrastructure/config/FirebaseConfigLoader.ts +9 -13
- package/src/storage/deleter/README.md +0 -370
- package/src/storage/deleter.ts +0 -109
- package/src/storage/index.ts +0 -8
- package/src/storage/storage-instance.ts +0 -11
- package/src/storage/types/README.md +0 -313
- package/src/storage/types.ts +0 -19
- package/src/storage/uploader.ts +0 -106
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Filters Utility
|
|
3
|
+
* Utilities for creating Firestore field filters
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
query,
|
|
8
|
+
where,
|
|
9
|
+
or,
|
|
10
|
+
type WhereFilterOp,
|
|
11
|
+
type Query,
|
|
12
|
+
} from "firebase/firestore";
|
|
13
|
+
|
|
14
|
+
export interface FieldFilter {
|
|
15
|
+
field: string;
|
|
16
|
+
operator: WhereFilterOp;
|
|
17
|
+
value: string | number | boolean | string[] | number[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MAX_IN_OPERATOR_VALUES = 10;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Apply field filter with 'in' operator and chunking support
|
|
24
|
+
*/
|
|
25
|
+
export function applyFieldFilter(q: Query, filter: FieldFilter): Query {
|
|
26
|
+
const { field, operator, value } = filter;
|
|
27
|
+
|
|
28
|
+
if (operator === "in" && Array.isArray(value)) {
|
|
29
|
+
if (value.length <= MAX_IN_OPERATOR_VALUES) {
|
|
30
|
+
return query(q, where(field, "in", value));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Split into chunks of 10 and use 'or' operator
|
|
34
|
+
const chunks: (string[] | number[])[] = [];
|
|
35
|
+
for (let i = 0; i < value.length; i += MAX_IN_OPERATOR_VALUES) {
|
|
36
|
+
chunks.push(value.slice(i, i + MAX_IN_OPERATOR_VALUES));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const orConditions = chunks.map((chunk) => where(field, "in", chunk));
|
|
40
|
+
return query(q, or(...orConditions));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return query(q, where(field, operator, value));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a field filter for 'in' operator
|
|
48
|
+
*/
|
|
49
|
+
export function createInFilter(
|
|
50
|
+
field: string,
|
|
51
|
+
values: string[] | number[],
|
|
52
|
+
): FieldFilter {
|
|
53
|
+
return { field, operator: "in", value: values };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create a field filter for equality
|
|
58
|
+
*/
|
|
59
|
+
export function createEqualFilter(
|
|
60
|
+
field: string,
|
|
61
|
+
value: string | number | boolean,
|
|
62
|
+
): FieldFilter {
|
|
63
|
+
return { field, operator: "==", value };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Create a field filter for custom operator
|
|
68
|
+
*/
|
|
69
|
+
export function createFieldFilter(
|
|
70
|
+
field: string,
|
|
71
|
+
operator: WhereFilterOp,
|
|
72
|
+
value: string | number | boolean | string[] | number[],
|
|
73
|
+
): FieldFilter {
|
|
74
|
+
return { field, operator, value };
|
|
75
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Utilities
|
|
3
|
+
* Utilities for building Firestore queries
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { applyFieldFilter, createInFilter, createEqualFilter, createFieldFilter } from './filters.util';
|
|
7
|
+
export type { FieldFilter } from './filters.util';
|
|
8
|
+
|
|
9
|
+
export { applyDateRange, applySort, applyCursor, applyLimit } from './modifiers.util';
|
|
10
|
+
export type { SortOptions, DateRangeOptions } from './modifiers.util';
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Modifiers Utility
|
|
3
|
+
* Utilities for applying query modifiers (sort, limit, cursor)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
query,
|
|
8
|
+
orderBy,
|
|
9
|
+
where,
|
|
10
|
+
limit as limitQuery,
|
|
11
|
+
startAfter,
|
|
12
|
+
type Query,
|
|
13
|
+
Timestamp,
|
|
14
|
+
} from "firebase/firestore";
|
|
15
|
+
|
|
16
|
+
export interface SortOptions {
|
|
17
|
+
field: string;
|
|
18
|
+
order?: "asc" | "desc";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface DateRangeOptions {
|
|
22
|
+
field: string;
|
|
23
|
+
startDate?: number;
|
|
24
|
+
endDate?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Apply date range filters to query
|
|
29
|
+
*/
|
|
30
|
+
export function applyDateRange(q: Query, dateRange: DateRangeOptions | undefined): Query {
|
|
31
|
+
if (!dateRange) return q;
|
|
32
|
+
|
|
33
|
+
if (dateRange.startDate) {
|
|
34
|
+
q = query(q, where(dateRange.field, ">=", Timestamp.fromMillis(dateRange.startDate)));
|
|
35
|
+
}
|
|
36
|
+
if (dateRange.endDate) {
|
|
37
|
+
q = query(q, where(dateRange.field, "<=", Timestamp.fromMillis(dateRange.endDate)));
|
|
38
|
+
}
|
|
39
|
+
return q;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Apply sorting to query
|
|
44
|
+
*/
|
|
45
|
+
export function applySort(q: Query, sort?: SortOptions): Query {
|
|
46
|
+
if (!sort) return q;
|
|
47
|
+
const sortOrder = sort.order || "desc";
|
|
48
|
+
return query(q, orderBy(sort.field, sortOrder));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Apply cursor for pagination
|
|
53
|
+
*/
|
|
54
|
+
export function applyCursor(q: Query, cursorValue?: number): Query {
|
|
55
|
+
if (cursorValue === undefined) return q;
|
|
56
|
+
return query(q, startAfter(Timestamp.fromMillis(cursorValue)));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Apply limit to query
|
|
61
|
+
*/
|
|
62
|
+
export function applyLimit(q: Query, limitValue?: number): Query {
|
|
63
|
+
if (limitValue === undefined) return q;
|
|
64
|
+
return query(q, limitQuery(limitValue));
|
|
65
|
+
}
|
|
@@ -5,106 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
collection,
|
|
8
|
-
query,
|
|
9
|
-
where,
|
|
10
|
-
orderBy,
|
|
11
|
-
limit as limitQuery,
|
|
12
|
-
startAfter,
|
|
13
|
-
or,
|
|
14
8
|
type Firestore,
|
|
15
9
|
type Query,
|
|
16
|
-
Timestamp,
|
|
17
|
-
type WhereFilterOp,
|
|
18
10
|
} from "firebase/firestore";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
field: string;
|
|
22
|
-
operator: WhereFilterOp;
|
|
23
|
-
value: string | number | boolean | string[] | number[];
|
|
24
|
-
}
|
|
11
|
+
import { applyFieldFilter, createInFilter, createEqualFilter, createFieldFilter, type FieldFilter } from "./query/filters.util";
|
|
12
|
+
import { applyDateRange, applySort, applyCursor, applyLimit, type SortOptions, type DateRangeOptions } from "./query/modifiers.util";
|
|
25
13
|
|
|
26
14
|
export interface QueryBuilderOptions {
|
|
27
15
|
collectionName: string;
|
|
28
16
|
baseFilters?: FieldFilter[];
|
|
29
|
-
dateRange?:
|
|
30
|
-
|
|
31
|
-
startDate?: number;
|
|
32
|
-
endDate?: number;
|
|
33
|
-
};
|
|
34
|
-
sort?: {
|
|
35
|
-
field: string;
|
|
36
|
-
order?: "asc" | "desc";
|
|
37
|
-
};
|
|
17
|
+
dateRange?: DateRangeOptions;
|
|
18
|
+
sort?: SortOptions;
|
|
38
19
|
limitValue?: number;
|
|
39
20
|
cursorValue?: number;
|
|
40
21
|
}
|
|
41
22
|
|
|
42
|
-
const MAX_IN_OPERATOR_VALUES = 10;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Apply date range filters to query
|
|
46
|
-
*/
|
|
47
|
-
function applyDateRange(q: Query, dateRange: QueryBuilderOptions['dateRange']): Query {
|
|
48
|
-
if (!dateRange) return q;
|
|
49
|
-
|
|
50
|
-
if (dateRange.startDate) {
|
|
51
|
-
q = query(q, where(dateRange.field, ">=", Timestamp.fromMillis(dateRange.startDate)));
|
|
52
|
-
}
|
|
53
|
-
if (dateRange.endDate) {
|
|
54
|
-
q = query(q, where(dateRange.field, "<=", Timestamp.fromMillis(dateRange.endDate)));
|
|
55
|
-
}
|
|
56
|
-
return q;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Apply sorting to query
|
|
61
|
-
*/
|
|
62
|
-
function applySort(q: Query, sort?: QueryBuilderOptions['sort']): Query {
|
|
63
|
-
if (!sort) return q;
|
|
64
|
-
const sortOrder = sort.order || "desc";
|
|
65
|
-
return query(q, orderBy(sort.field, sortOrder));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Apply cursor for pagination
|
|
70
|
-
*/
|
|
71
|
-
function applyCursor(q: Query, cursorValue?: number): Query {
|
|
72
|
-
if (cursorValue === undefined) return q;
|
|
73
|
-
return query(q, startAfter(Timestamp.fromMillis(cursorValue)));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Apply limit to query
|
|
78
|
-
*/
|
|
79
|
-
function applyLimit(q: Query, limitValue?: number): Query {
|
|
80
|
-
if (limitValue === undefined) return q;
|
|
81
|
-
return query(q, limitQuery(limitValue));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Apply field filter with 'in' operator and chunking support
|
|
86
|
-
*/
|
|
87
|
-
function applyFieldFilter(q: Query, filter: FieldFilter): Query {
|
|
88
|
-
const { field, operator, value } = filter;
|
|
89
|
-
|
|
90
|
-
if (operator === "in" && Array.isArray(value)) {
|
|
91
|
-
if (value.length <= MAX_IN_OPERATOR_VALUES) {
|
|
92
|
-
return query(q, where(field, "in", value));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Split into chunks of 10 and use 'or' operator
|
|
96
|
-
const chunks: (string[] | number[])[] = [];
|
|
97
|
-
for (let i = 0; i < value.length; i += MAX_IN_OPERATOR_VALUES) {
|
|
98
|
-
chunks.push(value.slice(i, i + MAX_IN_OPERATOR_VALUES));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const orConditions = chunks.map((chunk) => where(field, "in", chunk));
|
|
102
|
-
return query(q, or(...orConditions));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return query(q, where(field, operator, value));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
23
|
/**
|
|
109
24
|
* Build Firestore query with advanced filtering support
|
|
110
25
|
*/
|
|
@@ -138,22 +53,6 @@ export function buildQuery(
|
|
|
138
53
|
return q;
|
|
139
54
|
}
|
|
140
55
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
export function createInFilter(
|
|
145
|
-
field: string,
|
|
146
|
-
values: string[] | number[],
|
|
147
|
-
): FieldFilter {
|
|
148
|
-
return { field, operator: "in", value: values };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Create a field filter for equality
|
|
153
|
-
*/
|
|
154
|
-
export function createEqualFilter(
|
|
155
|
-
field: string,
|
|
156
|
-
value: string | number | boolean,
|
|
157
|
-
): FieldFilter {
|
|
158
|
-
return { field, operator: "==", value };
|
|
159
|
-
}
|
|
56
|
+
// Re-export filter utilities for convenience
|
|
57
|
+
export { createInFilter, createEqualFilter, createFieldFilter };
|
|
58
|
+
export type { FieldFilter, SortOptions, DateRangeOptions };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result Utility
|
|
3
|
+
* Utilities for creating Firestore result objects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface FirestoreResult<T> {
|
|
7
|
+
success: boolean;
|
|
8
|
+
data?: T;
|
|
9
|
+
error?: { message: string; code: string };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type NoDbResult = FirestoreResult<never>;
|
|
13
|
+
|
|
14
|
+
export const NO_DB_ERROR: NoDbResult = {
|
|
15
|
+
success: false,
|
|
16
|
+
error: { message: "No DB", code: "DB_ERR" },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create a standard error result
|
|
21
|
+
*/
|
|
22
|
+
export function createErrorResult<T>(message: string, code: string): FirestoreResult<T> {
|
|
23
|
+
return { success: false, error: { message, code } };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a standard success result
|
|
28
|
+
*/
|
|
29
|
+
export function createSuccessResult<T>(data?: T): FirestoreResult<T> {
|
|
30
|
+
return { success: true, data };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Check if result is successful
|
|
35
|
+
*/
|
|
36
|
+
export function isSuccess<T>(result: FirestoreResult<T>): result is FirestoreResult<T> & { success: true } {
|
|
37
|
+
return result.success;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Check if result is an error
|
|
42
|
+
*/
|
|
43
|
+
export function isError<T>(result: FirestoreResult<T>): result is FirestoreResult<T> & { success: false } {
|
|
44
|
+
return !result.success;
|
|
45
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction Utility
|
|
3
|
+
* Utilities for executing Firestore transactions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
runTransaction as fbRunTransaction,
|
|
8
|
+
serverTimestamp as fbServerTimestamp,
|
|
9
|
+
type Transaction,
|
|
10
|
+
} from "firebase/firestore";
|
|
11
|
+
import { getDb } from "../firestore-helper";
|
|
12
|
+
import type { Firestore } from "../../infrastructure/config/FirestoreClient";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Execute a transaction with automatic DB instance check.
|
|
16
|
+
* Wraps the Firebase runTransaction to ensure the DB is initialized.
|
|
17
|
+
*/
|
|
18
|
+
export async function runTransaction<T>(
|
|
19
|
+
updateFunction: (transaction: Transaction) => Promise<T>
|
|
20
|
+
): Promise<T> {
|
|
21
|
+
const db = getDb();
|
|
22
|
+
if (!db) {
|
|
23
|
+
throw new Error("[runTransaction] Firestore database is not initialized. Please ensure Firebase is properly initialized before running transactions.");
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return await fbRunTransaction(db as Firestore, updateFunction);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
29
|
+
const errorCode = error instanceof Error ? (error as { code?: string }).code : 'unknown';
|
|
30
|
+
|
|
31
|
+
if (__DEV__) {
|
|
32
|
+
console.error(`[runTransaction] Transaction failed (Code: ${errorCode}):`, errorMessage);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
throw new Error(`[runTransaction] Transaction failed: ${errorMessage} (Code: ${errorCode})`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the server timestamp (Sentinel value).
|
|
41
|
+
* Wraps Firebase serverTimestamp to avoid direct dependency.
|
|
42
|
+
*/
|
|
43
|
+
export function serverTimestamp() {
|
|
44
|
+
return fbServerTimestamp();
|
|
45
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { FirebaseConfig } from '../../domain/value-objects/FirebaseConfig';
|
|
10
|
+
import {
|
|
11
|
+
isValidString,
|
|
12
|
+
isValidFirebaseApiKey,
|
|
13
|
+
isValidFirebaseAuthDomain,
|
|
14
|
+
} from '../../domain/utils/validation.util';
|
|
10
15
|
|
|
11
16
|
type ConfigKey = 'apiKey' | 'authDomain' | 'projectId' | 'storageBucket' | 'messagingSenderId' | 'appId';
|
|
12
17
|
|
|
@@ -27,7 +32,7 @@ function getEnvValue(key: ConfigKey): string {
|
|
|
27
32
|
const keys = ENV_KEYS[key];
|
|
28
33
|
for (const envKey of keys) {
|
|
29
34
|
const value = process.env[`${EXPO_PREFIX}${envKey}`] || process.env[envKey];
|
|
30
|
-
if (value
|
|
35
|
+
if (isValidString(value)) return value;
|
|
31
36
|
}
|
|
32
37
|
return '';
|
|
33
38
|
}
|
|
@@ -62,15 +67,6 @@ function getExpoValue(key: ConfigKey, expoConfig: Record<string, string>): strin
|
|
|
62
67
|
return expoConfig[mapping[key]] || '';
|
|
63
68
|
}
|
|
64
69
|
|
|
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
|
-
|
|
74
70
|
/**
|
|
75
71
|
* Load Firebase configuration from Constants and environment variables
|
|
76
72
|
*/
|
|
@@ -90,7 +86,7 @@ export function loadFirebaseConfig(): FirebaseConfig | null {
|
|
|
90
86
|
const authDomain = config.authDomain?.trim();
|
|
91
87
|
const projectId = config.projectId?.trim();
|
|
92
88
|
|
|
93
|
-
if (!apiKey || !authDomain || !projectId) {
|
|
89
|
+
if (!isValidString(apiKey) || !isValidString(authDomain) || !isValidString(projectId)) {
|
|
94
90
|
if (__DEV__) {
|
|
95
91
|
console.error('[FirebaseConfigLoader] Missing required configuration fields');
|
|
96
92
|
}
|
|
@@ -98,7 +94,7 @@ export function loadFirebaseConfig(): FirebaseConfig | null {
|
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
// Validate API key format
|
|
101
|
-
if (!
|
|
97
|
+
if (!isValidFirebaseApiKey(apiKey)) {
|
|
102
98
|
if (__DEV__) {
|
|
103
99
|
console.error('[FirebaseConfigLoader] Invalid API key format');
|
|
104
100
|
}
|
|
@@ -106,7 +102,7 @@ export function loadFirebaseConfig(): FirebaseConfig | null {
|
|
|
106
102
|
}
|
|
107
103
|
|
|
108
104
|
// Validate authDomain format (should be like "projectId.firebaseapp.com")
|
|
109
|
-
if (!
|
|
105
|
+
if (!isValidFirebaseAuthDomain(authDomain)) {
|
|
110
106
|
if (__DEV__) {
|
|
111
107
|
console.warn('[FirebaseConfigLoader] Unusual authDomain format, expected "projectId.firebaseapp.com" or similar');
|
|
112
108
|
}
|