@umituz/react-native-firebase 1.3.1 → 1.5.0
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/LICENSE +0 -0
- package/README.md +0 -0
- package/lib/application/ports/IFirebaseClient.d.ts +37 -0
- package/lib/application/ports/IFirebaseClient.d.ts.map +1 -0
- package/lib/application/ports/IFirebaseClient.js +8 -0
- package/lib/application/ports/IFirebaseClient.js.map +1 -0
- package/lib/domain/errors/FirebaseError.d.ts +28 -0
- package/lib/domain/errors/FirebaseError.d.ts.map +1 -0
- package/lib/domain/errors/FirebaseError.js +46 -0
- package/lib/domain/errors/FirebaseError.js.map +1 -0
- package/lib/domain/value-objects/FirebaseConfig.d.ts +36 -0
- package/lib/domain/value-objects/FirebaseConfig.d.ts.map +1 -0
- package/lib/domain/value-objects/FirebaseConfig.js +8 -0
- package/lib/domain/value-objects/FirebaseConfig.js.map +1 -0
- package/lib/index.d.ts +26 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +29 -0
- package/lib/index.js.map +1 -0
- package/lib/infrastructure/config/FirebaseClient.d.ts +145 -0
- package/lib/infrastructure/config/FirebaseClient.d.ts.map +1 -0
- package/lib/infrastructure/config/FirebaseClient.js +335 -0
- package/lib/infrastructure/config/FirebaseClient.js.map +1 -0
- package/lib/infrastructure/config/FirebaseConfigLoader.d.ts +16 -0
- package/lib/infrastructure/config/FirebaseConfigLoader.d.ts.map +1 -0
- package/lib/infrastructure/config/FirebaseConfigLoader.js +131 -0
- package/lib/infrastructure/config/FirebaseConfigLoader.js.map +1 -0
- package/lib/infrastructure/config/initializers/FirebaseAppInitializer.d.ts +17 -0
- package/lib/infrastructure/config/initializers/FirebaseAppInitializer.d.ts.map +1 -0
- package/lib/infrastructure/config/initializers/FirebaseAppInitializer.js +83 -0
- package/lib/infrastructure/config/initializers/FirebaseAppInitializer.js.map +1 -0
- package/lib/infrastructure/config/validators/FirebaseConfigValidator.d.ts +18 -0
- package/lib/infrastructure/config/validators/FirebaseConfigValidator.d.ts.map +1 -0
- package/lib/infrastructure/config/validators/FirebaseConfigValidator.js +62 -0
- package/lib/infrastructure/config/validators/FirebaseConfigValidator.js.map +1 -0
- package/package.json +19 -4
- package/src/application/ports/IFirebaseClient.ts +4 -3
- package/src/domain/errors/FirebaseError.ts +0 -0
- package/src/domain/value-objects/FirebaseConfig.ts +0 -0
- package/src/index.ts +0 -0
- package/src/infrastructure/config/FirebaseClient.ts +222 -92
- package/src/infrastructure/config/FirebaseConfigLoader.ts +140 -45
- package/src/infrastructure/config/initializers/FirebaseAppInitializer.ts +67 -27
- package/src/infrastructure/config/validators/FirebaseConfigValidator.ts +58 -25
|
@@ -10,56 +10,151 @@
|
|
|
10
10
|
|
|
11
11
|
import type { FirebaseConfig } from '../../domain/value-objects/FirebaseConfig';
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Configuration source interface
|
|
15
|
+
*/
|
|
16
|
+
interface ConfigSource {
|
|
17
|
+
getApiKey(): string;
|
|
18
|
+
getAuthDomain(): string;
|
|
19
|
+
getProjectId(): string;
|
|
20
|
+
getStorageBucket(): string;
|
|
21
|
+
getMessagingSenderId(): string;
|
|
22
|
+
getAppId(): string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Expo Constants configuration source
|
|
27
|
+
*/
|
|
28
|
+
class ExpoConfigSource implements ConfigSource {
|
|
29
|
+
private extra: any;
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
let Constants: any;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
Constants = require('expo-constants');
|
|
36
|
+
} catch {
|
|
37
|
+
// expo-constants not available
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const expoConfig = Constants?.expoConfig || Constants?.default?.expoConfig;
|
|
41
|
+
this.extra = expoConfig?.extra || {};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getApiKey(): string {
|
|
45
|
+
return this.extra?.firebaseApiKey || '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getAuthDomain(): string {
|
|
49
|
+
return this.extra?.firebaseAuthDomain || '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getProjectId(): string {
|
|
53
|
+
return this.extra?.firebaseProjectId || '';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getStorageBucket(): string {
|
|
57
|
+
return this.extra?.firebaseStorageBucket || '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getMessagingSenderId(): string {
|
|
61
|
+
return this.extra?.firebaseMessagingSenderId || '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getAppId(): string {
|
|
65
|
+
return this.extra?.firebaseAppId || '';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Environment variables configuration source
|
|
71
|
+
*/
|
|
72
|
+
class EnvironmentConfigSource implements ConfigSource {
|
|
73
|
+
getApiKey(): string {
|
|
74
|
+
return process.env.EXPO_PUBLIC_FIREBASE_API_KEY ||
|
|
75
|
+
process.env.FIREBASE_API_KEY ||
|
|
76
|
+
'';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getAuthDomain(): string {
|
|
80
|
+
return process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN ||
|
|
81
|
+
process.env.FIREBASE_AUTH_DOMAIN ||
|
|
82
|
+
'';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getProjectId(): string {
|
|
86
|
+
return process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID ||
|
|
87
|
+
process.env.FIREBASE_PROJECT_ID ||
|
|
88
|
+
'';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getStorageBucket(): string {
|
|
92
|
+
return process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET ||
|
|
93
|
+
process.env.FIREBASE_STORAGE_BUCKET ||
|
|
94
|
+
'';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getMessagingSenderId(): string {
|
|
98
|
+
return process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID ||
|
|
99
|
+
process.env.FIREBASE_MESSAGING_SENDER_ID ||
|
|
100
|
+
'';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getAppId(): string {
|
|
104
|
+
return process.env.EXPO_PUBLIC_FIREBASE_APP_ID ||
|
|
105
|
+
process.env.FIREBASE_APP_ID ||
|
|
106
|
+
'';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Configuration aggregator
|
|
112
|
+
*/
|
|
113
|
+
class ConfigAggregator {
|
|
114
|
+
private sources: ConfigSource[];
|
|
115
|
+
|
|
116
|
+
constructor() {
|
|
117
|
+
this.sources = [
|
|
118
|
+
new ExpoConfigSource(),
|
|
119
|
+
new EnvironmentConfigSource(),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get configuration value from first available source
|
|
125
|
+
*/
|
|
126
|
+
private getValue(getter: (source: ConfigSource) => string): string {
|
|
127
|
+
for (const source of this.sources) {
|
|
128
|
+
const value = getter(source);
|
|
129
|
+
if (value && value.trim() !== '') {
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Build Firebase configuration from all sources
|
|
138
|
+
*/
|
|
139
|
+
buildConfig(): Partial<FirebaseConfig> {
|
|
140
|
+
return {
|
|
141
|
+
apiKey: this.getValue(source => source.getApiKey()),
|
|
142
|
+
authDomain: this.getValue(source => source.getAuthDomain()),
|
|
143
|
+
projectId: this.getValue(source => source.getProjectId()),
|
|
144
|
+
storageBucket: this.getValue(source => source.getStorageBucket()),
|
|
145
|
+
messagingSenderId: this.getValue(source => source.getMessagingSenderId()),
|
|
146
|
+
appId: this.getValue(source => source.getAppId()),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
13
151
|
/**
|
|
14
152
|
* Load Firebase configuration from Constants and environment variables
|
|
15
153
|
* Returns null if no valid configuration is found
|
|
16
154
|
*/
|
|
17
155
|
export function loadFirebaseConfig(): FirebaseConfig | null {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// Try to load expo-constants (optional dependency)
|
|
21
|
-
try {
|
|
22
|
-
Constants = require('expo-constants');
|
|
23
|
-
} catch {
|
|
24
|
-
// expo-constants not available, skip
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Try both Constants.expoConfig and Constants.default.expoConfig
|
|
28
|
-
const expoConfig = Constants?.expoConfig || Constants?.default?.expoConfig;
|
|
29
|
-
const extra = expoConfig?.extra;
|
|
30
|
-
|
|
31
|
-
const config: Partial<FirebaseConfig> = {
|
|
32
|
-
apiKey:
|
|
33
|
-
extra?.firebaseApiKey ||
|
|
34
|
-
process.env.EXPO_PUBLIC_FIREBASE_API_KEY ||
|
|
35
|
-
process.env.FIREBASE_API_KEY ||
|
|
36
|
-
'',
|
|
37
|
-
authDomain:
|
|
38
|
-
extra?.firebaseAuthDomain ||
|
|
39
|
-
process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN ||
|
|
40
|
-
process.env.FIREBASE_AUTH_DOMAIN ||
|
|
41
|
-
'',
|
|
42
|
-
projectId:
|
|
43
|
-
extra?.firebaseProjectId ||
|
|
44
|
-
process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID ||
|
|
45
|
-
process.env.FIREBASE_PROJECT_ID ||
|
|
46
|
-
'',
|
|
47
|
-
storageBucket:
|
|
48
|
-
extra?.firebaseStorageBucket ||
|
|
49
|
-
process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET ||
|
|
50
|
-
process.env.FIREBASE_STORAGE_BUCKET ||
|
|
51
|
-
'',
|
|
52
|
-
messagingSenderId:
|
|
53
|
-
extra?.firebaseMessagingSenderId ||
|
|
54
|
-
process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID ||
|
|
55
|
-
process.env.FIREBASE_MESSAGING_SENDER_ID ||
|
|
56
|
-
'',
|
|
57
|
-
appId:
|
|
58
|
-
extra?.firebaseAppId ||
|
|
59
|
-
process.env.EXPO_PUBLIC_FIREBASE_APP_ID ||
|
|
60
|
-
process.env.FIREBASE_APP_ID ||
|
|
61
|
-
'',
|
|
62
|
-
};
|
|
156
|
+
const aggregator = new ConfigAggregator();
|
|
157
|
+
const config = aggregator.buildConfig();
|
|
63
158
|
|
|
64
159
|
// Only return config if required fields are present and not empty
|
|
65
160
|
if (
|
|
@@ -4,34 +4,67 @@
|
|
|
4
4
|
* Single Responsibility: Initialize Firebase App instance
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { initializeApp, getApps, FirebaseApp } from 'firebase/app';
|
|
8
7
|
import type { FirebaseConfig } from '../../../domain/value-objects/FirebaseConfig';
|
|
9
8
|
import { FirebaseInitializationError } from '../../../domain/errors/FirebaseError';
|
|
10
9
|
|
|
10
|
+
export type FirebaseApp = any;
|
|
11
|
+
|
|
12
|
+
declare const initializeApp: any;
|
|
13
|
+
declare const getApps: any;
|
|
14
|
+
|
|
11
15
|
/**
|
|
12
|
-
*
|
|
16
|
+
* Firebase configuration mapper
|
|
13
17
|
*/
|
|
14
|
-
|
|
18
|
+
class FirebaseConfigMapper {
|
|
15
19
|
/**
|
|
16
|
-
*
|
|
20
|
+
* Map domain config to Firebase SDK config
|
|
17
21
|
*/
|
|
18
|
-
static
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
static toFirebaseConfig(config: FirebaseConfig): Record<string, any> {
|
|
23
|
+
return {
|
|
24
|
+
apiKey: config.apiKey,
|
|
25
|
+
authDomain: config.authDomain,
|
|
26
|
+
projectId: config.projectId,
|
|
27
|
+
storageBucket: config.storageBucket,
|
|
28
|
+
messagingSenderId: config.messagingSenderId,
|
|
29
|
+
appId: config.appId,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Firebase App manager
|
|
36
|
+
*/
|
|
37
|
+
class FirebaseAppManager {
|
|
38
|
+
/**
|
|
39
|
+
* Check if Firebase App is already initialized
|
|
40
|
+
*/
|
|
41
|
+
static isInitialized(): boolean {
|
|
42
|
+
try {
|
|
43
|
+
const existingApps = getApps();
|
|
44
|
+
return existingApps.length > 0;
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
23
47
|
}
|
|
48
|
+
}
|
|
24
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Get existing Firebase App instance
|
|
52
|
+
*/
|
|
53
|
+
static getExistingApp(): FirebaseApp | null {
|
|
25
54
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
appId: config.appId,
|
|
33
|
-
};
|
|
55
|
+
const existingApps = getApps();
|
|
56
|
+
return existingApps.length > 0 ? existingApps[0] : null;
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
34
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Create new Firebase App instance
|
|
64
|
+
*/
|
|
65
|
+
static createApp(config: FirebaseConfig): FirebaseApp {
|
|
66
|
+
try {
|
|
67
|
+
const firebaseConfig = FirebaseConfigMapper.toFirebaseConfig(config);
|
|
35
68
|
return initializeApp(firebaseConfig);
|
|
36
69
|
} catch (error) {
|
|
37
70
|
throw new FirebaseInitializationError(
|
|
@@ -44,14 +77,21 @@ export class FirebaseAppInitializer {
|
|
|
44
77
|
}
|
|
45
78
|
}
|
|
46
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Initializes Firebase App
|
|
82
|
+
*/
|
|
83
|
+
export class FirebaseAppInitializer {
|
|
84
|
+
/**
|
|
85
|
+
* Initialize or get existing Firebase App
|
|
86
|
+
*/
|
|
87
|
+
static initialize(config: FirebaseConfig): FirebaseApp {
|
|
88
|
+
// Return existing app if already initialized
|
|
89
|
+
const existingApp = FirebaseAppManager.getExistingApp();
|
|
90
|
+
if (existingApp) {
|
|
91
|
+
return existingApp;
|
|
92
|
+
}
|
|
47
93
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
94
|
+
// Create new app
|
|
95
|
+
return FirebaseAppManager.createApp(config);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -8,43 +8,76 @@ import type { FirebaseConfig } from '../../../domain/value-objects/FirebaseConfi
|
|
|
8
8
|
import { FirebaseConfigurationError } from '../../../domain/errors/FirebaseError';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Validation rule interface
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
interface ValidationRule {
|
|
14
|
+
validate(config: FirebaseConfig): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Required field validation rule
|
|
19
|
+
*/
|
|
20
|
+
class RequiredFieldRule implements ValidationRule {
|
|
21
|
+
constructor(
|
|
22
|
+
private fieldName: string,
|
|
23
|
+
private getter: (config: FirebaseConfig) => string | undefined
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
validate(config: FirebaseConfig): void {
|
|
27
|
+
const value = this.getter(config);
|
|
28
|
+
|
|
29
|
+
if (!value || typeof value !== 'string') {
|
|
20
30
|
throw new FirebaseConfigurationError(
|
|
21
|
-
|
|
31
|
+
`Firebase ${this.fieldName} is required and must be a string`
|
|
22
32
|
);
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
if (
|
|
26
|
-
throw new FirebaseConfigurationError(
|
|
27
|
-
'Firebase Auth Domain is required and must be a string'
|
|
28
|
-
);
|
|
35
|
+
if (value.trim().length === 0) {
|
|
36
|
+
throw new FirebaseConfigurationError(`Firebase ${this.fieldName} cannot be empty`);
|
|
29
37
|
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
30
40
|
|
|
31
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Placeholder validation rule
|
|
43
|
+
*/
|
|
44
|
+
class PlaceholderRule implements ValidationRule {
|
|
45
|
+
constructor(
|
|
46
|
+
private fieldName: string,
|
|
47
|
+
private getter: (config: FirebaseConfig) => string | undefined,
|
|
48
|
+
private placeholder: string
|
|
49
|
+
) {}
|
|
50
|
+
|
|
51
|
+
validate(config: FirebaseConfig): void {
|
|
52
|
+
const value = this.getter(config);
|
|
53
|
+
|
|
54
|
+
if (value && value.includes(this.placeholder)) {
|
|
32
55
|
throw new FirebaseConfigurationError(
|
|
33
|
-
|
|
56
|
+
`Please replace placeholder values with actual Firebase credentials for ${this.fieldName}`
|
|
34
57
|
);
|
|
35
58
|
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
36
61
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Firebase Configuration Validator
|
|
64
|
+
*/
|
|
65
|
+
export class FirebaseConfigValidator {
|
|
66
|
+
private static rules: ValidationRule[] = [
|
|
67
|
+
new RequiredFieldRule('API Key', config => config.apiKey),
|
|
68
|
+
new RequiredFieldRule('Auth Domain', config => config.authDomain),
|
|
69
|
+
new RequiredFieldRule('Project ID', config => config.projectId),
|
|
70
|
+
new PlaceholderRule('API Key', config => config.apiKey, 'your_firebase_api_key'),
|
|
71
|
+
new PlaceholderRule('Project ID', config => config.projectId, 'your-project-id'),
|
|
72
|
+
];
|
|
40
73
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
);
|
|
74
|
+
/**
|
|
75
|
+
* Validate Firebase configuration
|
|
76
|
+
* @throws {FirebaseConfigurationError} If configuration is invalid
|
|
77
|
+
*/
|
|
78
|
+
static validate(config: FirebaseConfig): void {
|
|
79
|
+
for (const rule of this.rules) {
|
|
80
|
+
rule.validate(config);
|
|
48
81
|
}
|
|
49
82
|
}
|
|
50
83
|
}
|