@umituz/react-native-firebase 1.2.0 → 1.2.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/LICENSE +11 -0
- package/README.md +20 -14
- package/package.json +6 -29
- package/src/application/ports/IFirebaseClient.ts +8 -14
- package/src/domain/errors/FirebaseError.ts +7 -44
- package/src/domain/value-objects/FirebaseConfig.ts +0 -10
- package/src/index.ts +10 -52
- package/src/infrastructure/config/FirebaseClient.ts +27 -64
- package/src/infrastructure/config/FirebaseConfigLoader.ts +72 -0
- package/src/infrastructure/config/initializers/FirebaseAppInitializer.ts +11 -0
- package/src/infrastructure/config/validators/FirebaseConfigValidator.ts +11 -0
- package/src/infrastructure/config/initializers/FirebaseAuthInitializer.ts +0 -68
- package/src/infrastructure/config/initializers/FirebaseFirestoreInitializer.ts +0 -54
- package/src/infrastructure/services/analytics/FirebaseAnalyticsService.ts +0 -206
- package/src/infrastructure/services/crashlytics/FirebaseCrashlyticsService.ts +0 -170
- package/src/infrastructure/services/performance/PerformanceTracker.ts +0 -63
- package/src/presentation/decorators/ErrorTrackingDecorator.ts +0 -50
- package/src/presentation/decorators/PerformanceDecorator.ts +0 -77
- package/src/presentation/decorators/TrackingDecorator.ts +0 -79
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firebase Auth Initializer
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Initialize Firebase Auth instance
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { initializeAuth, getAuth } from 'firebase/auth';
|
|
8
|
-
import type { Auth } from 'firebase/auth';
|
|
9
|
-
import { Platform } from 'react-native';
|
|
10
|
-
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
11
|
-
import type { FirebaseApp } from 'firebase/app';
|
|
12
|
-
import type { FirebaseConfig } from '../../../domain/value-objects/FirebaseConfig';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Initializes Firebase Auth
|
|
16
|
-
*/
|
|
17
|
-
export class FirebaseAuthInitializer {
|
|
18
|
-
/**
|
|
19
|
-
* Initialize Firebase Auth with platform-specific persistence
|
|
20
|
-
*/
|
|
21
|
-
static initialize(app: FirebaseApp, config: FirebaseConfig): Auth {
|
|
22
|
-
try {
|
|
23
|
-
if (Platform.OS === 'web') {
|
|
24
|
-
return getAuth(app);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Try React Native persistence
|
|
28
|
-
return this.initializeWithPersistence(app, config);
|
|
29
|
-
} catch (error: any) {
|
|
30
|
-
// If already initialized, get existing instance
|
|
31
|
-
if (error.code === 'auth/already-initialized') {
|
|
32
|
-
return getAuth(app);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/* eslint-disable-next-line no-console */
|
|
36
|
-
if (__DEV__) console.warn('Firebase Auth initialization error:', error);
|
|
37
|
-
return getAuth(app);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private static initializeWithPersistence(
|
|
42
|
-
app: FirebaseApp,
|
|
43
|
-
config: FirebaseConfig
|
|
44
|
-
): Auth {
|
|
45
|
-
try {
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
47
|
-
const authModule = require('firebase/auth');
|
|
48
|
-
const getReactNativePersistence = authModule.getReactNativePersistence;
|
|
49
|
-
|
|
50
|
-
if (!getReactNativePersistence) {
|
|
51
|
-
return getAuth(app);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const storage = config.authStorage || {
|
|
55
|
-
getItem: (key: string) => AsyncStorage.getItem(key),
|
|
56
|
-
setItem: (key: string, value: string) => AsyncStorage.setItem(key, value),
|
|
57
|
-
removeItem: (key: string) => AsyncStorage.removeItem(key),
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
return initializeAuth(app, {
|
|
61
|
-
persistence: getReactNativePersistence(storage),
|
|
62
|
-
});
|
|
63
|
-
} catch {
|
|
64
|
-
return getAuth(app);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firebase Firestore Initializer
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Initialize Firestore instance
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
getFirestore,
|
|
9
|
-
initializeFirestore,
|
|
10
|
-
persistentLocalCache,
|
|
11
|
-
} from 'firebase/firestore';
|
|
12
|
-
import type { Firestore } from 'firebase/firestore';
|
|
13
|
-
import { Platform } from 'react-native';
|
|
14
|
-
import type { FirebaseApp } from 'firebase/app';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Initializes Firestore
|
|
18
|
-
*/
|
|
19
|
-
export class FirebaseFirestoreInitializer {
|
|
20
|
-
/**
|
|
21
|
-
* Initialize Firestore with platform-specific cache configuration
|
|
22
|
-
*/
|
|
23
|
-
static initialize(app: FirebaseApp): Firestore {
|
|
24
|
-
if (Platform.OS === 'web') {
|
|
25
|
-
return this.initializeForWeb(app);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// React Native: Use default persistence
|
|
29
|
-
return getFirestore(app);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private static initializeForWeb(app: FirebaseApp): Firestore {
|
|
33
|
-
try {
|
|
34
|
-
return initializeFirestore(app, {
|
|
35
|
-
localCache: persistentLocalCache(),
|
|
36
|
-
});
|
|
37
|
-
} catch (error: any) {
|
|
38
|
-
// If already initialized, get existing instance
|
|
39
|
-
if (error.code === 'failed-precondition') {
|
|
40
|
-
/* eslint-disable-next-line no-console */
|
|
41
|
-
if (__DEV__)
|
|
42
|
-
console.warn(
|
|
43
|
-
'Firestore already initialized, using existing instance'
|
|
44
|
-
);
|
|
45
|
-
return getFirestore(app);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/* eslint-disable-next-line no-console */
|
|
49
|
-
if (__DEV__) console.warn('Firestore initialization error:', error);
|
|
50
|
-
return getFirestore(app);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firebase Analytics Service
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Handle Firebase Analytics tracking
|
|
5
|
-
* Platform-agnostic interface with platform-specific implementations
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { Platform } from 'react-native';
|
|
9
|
-
import { getFirebaseApp } from '../../config/FirebaseClient';
|
|
10
|
-
|
|
11
|
-
// Web implementation
|
|
12
|
-
let webAnalytics: any = null;
|
|
13
|
-
if (Platform.OS === 'web') {
|
|
14
|
-
try {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
-
const { getAnalytics, logEvent, setUserId, setUserProperties, Analytics } = require('firebase/analytics');
|
|
17
|
-
webAnalytics = { getAnalytics, logEvent, setUserId, setUserProperties, Analytics };
|
|
18
|
-
} catch {
|
|
19
|
-
// Firebase Analytics not available
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Native implementation
|
|
24
|
-
let nativeAnalytics: any = null;
|
|
25
|
-
if (Platform.OS !== 'web') {
|
|
26
|
-
try {
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
28
|
-
require('@react-native-firebase/app');
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
30
|
-
const analytics = require('@react-native-firebase/analytics');
|
|
31
|
-
nativeAnalytics = analytics;
|
|
32
|
-
} catch {
|
|
33
|
-
// @react-native-firebase/analytics not available
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface IAnalyticsService {
|
|
38
|
-
init(userId?: string): Promise<void>;
|
|
39
|
-
logEvent(eventName: string, params?: Record<string, string | number | boolean | null>): Promise<void>;
|
|
40
|
-
setUserProperty(key: string, value: string): Promise<void>;
|
|
41
|
-
setUserProperties(properties: Record<string, string>): Promise<void>;
|
|
42
|
-
clearUserData(): Promise<void>;
|
|
43
|
-
getCurrentUserId(): string | null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
class FirebaseAnalyticsService implements IAnalyticsService {
|
|
47
|
-
private isInitialized = false;
|
|
48
|
-
private userId: string | null = null;
|
|
49
|
-
private userProperties: Record<string, string> = {};
|
|
50
|
-
private analytics: any = null;
|
|
51
|
-
|
|
52
|
-
async init(userId?: string): Promise<void> {
|
|
53
|
-
try {
|
|
54
|
-
if (Platform.OS === 'web') {
|
|
55
|
-
await this.initWeb(userId);
|
|
56
|
-
} else {
|
|
57
|
-
await this.initNative(userId);
|
|
58
|
-
}
|
|
59
|
-
} catch (_error) {
|
|
60
|
-
// Analytics is non-critical, fail silently
|
|
61
|
-
this.isInitialized = true;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private async initWeb(userId?: string): Promise<void> {
|
|
66
|
-
if (!webAnalytics) {
|
|
67
|
-
this.isInitialized = true;
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
const app = getFirebaseApp();
|
|
73
|
-
if (!this.analytics) {
|
|
74
|
-
this.analytics = webAnalytics.getAnalytics(app);
|
|
75
|
-
}
|
|
76
|
-
} catch {
|
|
77
|
-
this.isInitialized = true;
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (userId) {
|
|
82
|
-
this.userId = userId;
|
|
83
|
-
await webAnalytics.setUserId(this.analytics, userId);
|
|
84
|
-
await this.setUserProperty('user_type', 'authenticated');
|
|
85
|
-
} else {
|
|
86
|
-
await this.setUserProperty('user_type', 'guest');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this.isInitialized = true;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private async initNative(userId?: string): Promise<void> {
|
|
93
|
-
if (!nativeAnalytics) {
|
|
94
|
-
this.isInitialized = true;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
this.analytics = nativeAnalytics.getAnalytics();
|
|
100
|
-
|
|
101
|
-
if (userId) {
|
|
102
|
-
this.userId = userId;
|
|
103
|
-
await nativeAnalytics.setUserId(this.analytics, userId);
|
|
104
|
-
await this.setUserProperty('user_type', 'authenticated');
|
|
105
|
-
} else {
|
|
106
|
-
await this.setUserProperty('user_type', 'guest');
|
|
107
|
-
}
|
|
108
|
-
} catch {
|
|
109
|
-
// Silent fail
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
this.isInitialized = true;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async logEvent(
|
|
116
|
-
eventName: string,
|
|
117
|
-
params?: Record<string, string | number | boolean | null>
|
|
118
|
-
): Promise<void> {
|
|
119
|
-
try {
|
|
120
|
-
if (!this.analytics) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (Platform.OS === 'web' && webAnalytics) {
|
|
125
|
-
await webAnalytics.logEvent(this.analytics, eventName, params);
|
|
126
|
-
} else if (Platform.OS !== 'web' && nativeAnalytics) {
|
|
127
|
-
await nativeAnalytics.logEvent(this.analytics, eventName, params);
|
|
128
|
-
}
|
|
129
|
-
} catch (_error) {
|
|
130
|
-
// Silent fail
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async setUserProperty(key: string, value: string): Promise<void> {
|
|
135
|
-
try {
|
|
136
|
-
if (!this.analytics) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
this.userProperties[key] = value;
|
|
141
|
-
|
|
142
|
-
if (Platform.OS === 'web' && webAnalytics) {
|
|
143
|
-
await webAnalytics.setUserProperties(this.analytics, { [key]: value });
|
|
144
|
-
} else if (Platform.OS !== 'web' && nativeAnalytics) {
|
|
145
|
-
await nativeAnalytics.setUserProperties(this.analytics, { [key]: value });
|
|
146
|
-
}
|
|
147
|
-
} catch (_error) {
|
|
148
|
-
// Silent fail
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async setUserProperties(properties: Record<string, string>): Promise<void> {
|
|
153
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
154
|
-
await this.setUserProperty(key, value);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async clearUserData(): Promise<void> {
|
|
159
|
-
try {
|
|
160
|
-
if (!this.analytics) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (Platform.OS === 'web' && webAnalytics) {
|
|
165
|
-
await webAnalytics.setUserId(this.analytics, '');
|
|
166
|
-
await webAnalytics.setUserProperties(this.analytics, {});
|
|
167
|
-
} else if (Platform.OS !== 'web' && nativeAnalytics) {
|
|
168
|
-
await nativeAnalytics.setUserId(this.analytics, '');
|
|
169
|
-
await nativeAnalytics.setUserProperties(this.analytics, {});
|
|
170
|
-
if (nativeAnalytics.resetAnalyticsData) {
|
|
171
|
-
await nativeAnalytics.resetAnalyticsData(this.analytics);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
this.userId = null;
|
|
176
|
-
this.userProperties = {};
|
|
177
|
-
this.isInitialized = false;
|
|
178
|
-
} catch (_error) {
|
|
179
|
-
// Silent fail
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
getCurrentUserId(): string | null {
|
|
184
|
-
return this.userId;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Log screen view
|
|
189
|
-
*/
|
|
190
|
-
async logScreenView(params: {
|
|
191
|
-
screen_name: string;
|
|
192
|
-
screen_class?: string;
|
|
193
|
-
}): Promise<void> {
|
|
194
|
-
try {
|
|
195
|
-
await this.logEvent('screen_view', {
|
|
196
|
-
screen_name: params.screen_name,
|
|
197
|
-
screen_class: params.screen_class || params.screen_name,
|
|
198
|
-
});
|
|
199
|
-
} catch (_error) {
|
|
200
|
-
// Silent fail
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export const firebaseAnalyticsService = new FirebaseAnalyticsService();
|
|
206
|
-
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firebase Crashlytics Service
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Handle Firebase Crashlytics error tracking
|
|
5
|
-
* Platform-agnostic interface with platform-specific implementations
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { Platform } from 'react-native';
|
|
9
|
-
import { firebaseAnalyticsService } from '../analytics/FirebaseAnalyticsService';
|
|
10
|
-
|
|
11
|
-
// Native implementation
|
|
12
|
-
let nativeCrashlytics: any = null;
|
|
13
|
-
if (Platform.OS !== 'web') {
|
|
14
|
-
try {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
-
require('@react-native-firebase/app');
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
18
|
-
const crashlytics = require('@react-native-firebase/crashlytics');
|
|
19
|
-
nativeCrashlytics = crashlytics;
|
|
20
|
-
} catch {
|
|
21
|
-
// @react-native-firebase/crashlytics not available
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ICrashlyticsService {
|
|
26
|
-
init(userId?: string): Promise<void>;
|
|
27
|
-
logError(error: Error, context?: string): Promise<void>;
|
|
28
|
-
log(message: string): Promise<void>;
|
|
29
|
-
setAttribute(key: string, value: string): Promise<void>;
|
|
30
|
-
setAttributes(attributes: Record<string, string>): Promise<void>;
|
|
31
|
-
clearUserData(): Promise<void>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
class FirebaseCrashlyticsService implements ICrashlyticsService {
|
|
35
|
-
private isInitialized = false;
|
|
36
|
-
private userId: string | null = null;
|
|
37
|
-
private attributes: Record<string, string> = {};
|
|
38
|
-
private crashlytics: any = null;
|
|
39
|
-
|
|
40
|
-
async init(userId?: string): Promise<void> {
|
|
41
|
-
try {
|
|
42
|
-
if (Platform.OS === 'web') {
|
|
43
|
-
// Crashlytics only works on native platforms
|
|
44
|
-
this.isInitialized = true;
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!nativeCrashlytics) {
|
|
49
|
-
this.isInitialized = true;
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
this.crashlytics = nativeCrashlytics.getCrashlytics();
|
|
54
|
-
|
|
55
|
-
if (userId) {
|
|
56
|
-
this.userId = userId;
|
|
57
|
-
await nativeCrashlytics.setUserId(this.crashlytics, userId);
|
|
58
|
-
await this.setAttribute('user_type', 'authenticated');
|
|
59
|
-
} else {
|
|
60
|
-
await this.setAttribute('user_type', 'guest');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this.isInitialized = true;
|
|
64
|
-
} catch (_error) {
|
|
65
|
-
// Crashlytics is non-critical, fail silently
|
|
66
|
-
this.isInitialized = true;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async logError(error: Error, context?: string): Promise<void> {
|
|
71
|
-
try {
|
|
72
|
-
if (Platform.OS === 'web') {
|
|
73
|
-
// On web, just log to console and analytics
|
|
74
|
-
/* eslint-disable-next-line no-console */
|
|
75
|
-
if (__DEV__) console.error(`[Crashlytics] Error${context ? ` in ${context}` : ''}:`, error);
|
|
76
|
-
|
|
77
|
-
await firebaseAnalyticsService.logEvent('error_occurred', {
|
|
78
|
-
error_name: error.name,
|
|
79
|
-
error_message: error.message.substring(0, 100),
|
|
80
|
-
error_context: context || 'unknown',
|
|
81
|
-
error_type: 'generic',
|
|
82
|
-
});
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!this.crashlytics || !nativeCrashlytics) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/* eslint-disable-next-line no-console */
|
|
91
|
-
if (__DEV__) {
|
|
92
|
-
console.error(`[Crashlytics] Error${context ? ` in ${context}` : ''}:`, error);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (context) {
|
|
96
|
-
await nativeCrashlytics.crashlytics().log(`Context: ${context}`);
|
|
97
|
-
}
|
|
98
|
-
await nativeCrashlytics.crashlytics().log(`Error: ${error.name} - ${error.message}`);
|
|
99
|
-
await nativeCrashlytics.recordError(this.crashlytics, error);
|
|
100
|
-
|
|
101
|
-
// Also log to Analytics
|
|
102
|
-
await firebaseAnalyticsService.logEvent('error_occurred', {
|
|
103
|
-
error_name: error.name,
|
|
104
|
-
error_message: error.message.substring(0, 100),
|
|
105
|
-
error_context: context || 'unknown',
|
|
106
|
-
error_type: 'generic',
|
|
107
|
-
});
|
|
108
|
-
} catch (_error) {
|
|
109
|
-
// Silent fail
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async log(message: string): Promise<void> {
|
|
114
|
-
try {
|
|
115
|
-
if (Platform.OS === 'web') {
|
|
116
|
-
/* eslint-disable-next-line no-console */
|
|
117
|
-
if (__DEV__) console.log(`[Crashlytics] ${message}`);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (!this.crashlytics || !nativeCrashlytics) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
await nativeCrashlytics.crashlytics().log(message);
|
|
126
|
-
} catch (_error) {
|
|
127
|
-
// Silent fail
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async setAttribute(key: string, value: string): Promise<void> {
|
|
132
|
-
try {
|
|
133
|
-
this.attributes[key] = value;
|
|
134
|
-
|
|
135
|
-
if (Platform.OS === 'web' || !this.crashlytics || !nativeCrashlytics) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
await nativeCrashlytics.setAttributes(this.crashlytics, { [key]: value });
|
|
140
|
-
} catch (_error) {
|
|
141
|
-
// Silent fail
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async setAttributes(attributes: Record<string, string>): Promise<void> {
|
|
146
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
147
|
-
await this.setAttribute(key, value);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async clearUserData(): Promise<void> {
|
|
152
|
-
try {
|
|
153
|
-
if (Platform.OS === 'web' || !this.crashlytics || !nativeCrashlytics) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
await nativeCrashlytics.crashlytics().setUserId('');
|
|
158
|
-
await nativeCrashlytics.crashlytics().setAttributes({});
|
|
159
|
-
|
|
160
|
-
this.userId = null;
|
|
161
|
-
this.attributes = {};
|
|
162
|
-
this.isInitialized = false;
|
|
163
|
-
} catch (_error) {
|
|
164
|
-
// Silent fail
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export const firebaseCrashlyticsService = new FirebaseCrashlyticsService();
|
|
170
|
-
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performance Tracker
|
|
3
|
-
*
|
|
4
|
-
* Single Responsibility: Track method execution time and log to Firebase Analytics
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { firebaseAnalyticsService } from '../analytics/FirebaseAnalyticsService';
|
|
8
|
-
|
|
9
|
-
interface PerformanceMetric {
|
|
10
|
-
operation: string;
|
|
11
|
-
duration_ms: number;
|
|
12
|
-
success: boolean;
|
|
13
|
-
metadata?: Record<string, string | number | boolean>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
class PerformanceTracker {
|
|
17
|
-
private activeTimings: Map<string, number> = new Map();
|
|
18
|
-
|
|
19
|
-
start(operationId: string): void {
|
|
20
|
-
this.activeTimings.set(operationId, Date.now());
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async end(
|
|
24
|
-
operationId: string,
|
|
25
|
-
metadata?: Record<string, string | number | boolean>
|
|
26
|
-
): Promise<void> {
|
|
27
|
-
const startTime = this.activeTimings.get(operationId);
|
|
28
|
-
if (!startTime) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const duration = Date.now() - startTime;
|
|
33
|
-
this.activeTimings.delete(operationId);
|
|
34
|
-
|
|
35
|
-
await firebaseAnalyticsService.logEvent('performance_metric', {
|
|
36
|
-
operation: operationId,
|
|
37
|
-
duration_ms: duration,
|
|
38
|
-
...metadata,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async track<T>(
|
|
43
|
-
operationId: string,
|
|
44
|
-
operation: () => Promise<T>
|
|
45
|
-
): Promise<T> {
|
|
46
|
-
this.start(operationId);
|
|
47
|
-
try {
|
|
48
|
-
const result = await operation();
|
|
49
|
-
await this.end(operationId, { success: true });
|
|
50
|
-
return result;
|
|
51
|
-
} catch (error) {
|
|
52
|
-
await this.end(operationId, {
|
|
53
|
-
success: false,
|
|
54
|
-
error_message: error instanceof Error ? error.message : 'Unknown error',
|
|
55
|
-
});
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export const performanceTracker = new PerformanceTracker();
|
|
62
|
-
export { PerformanceTracker };
|
|
63
|
-
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Tracking Decorator
|
|
3
|
-
*
|
|
4
|
-
* DDD Pattern: Decorator for automatic error logging to Firebase Crashlytics
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { firebaseCrashlyticsService } from '../../infrastructure/services/crashlytics/FirebaseCrashlyticsService';
|
|
8
|
-
|
|
9
|
-
export function TrackErrors(
|
|
10
|
-
serviceName: string,
|
|
11
|
-
errorType: 'database' | 'network' | 'auth' | 'cache' | 'generic' = 'generic'
|
|
12
|
-
) {
|
|
13
|
-
return function (
|
|
14
|
-
_target: unknown,
|
|
15
|
-
propertyKey: string,
|
|
16
|
-
descriptor: PropertyDescriptor
|
|
17
|
-
) {
|
|
18
|
-
const originalMethod = descriptor.value;
|
|
19
|
-
|
|
20
|
-
descriptor.value = async function (...args: unknown[]) {
|
|
21
|
-
try {
|
|
22
|
-
return await originalMethod.apply(this, args);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
const errorObj = error instanceof Error ? error : new Error('Unknown error');
|
|
25
|
-
const context = `${serviceName}.${propertyKey}`;
|
|
26
|
-
|
|
27
|
-
await firebaseCrashlyticsService.logError(errorObj, context);
|
|
28
|
-
|
|
29
|
-
throw error;
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
return descriptor;
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function trackErrors<T>(
|
|
38
|
-
serviceName: string,
|
|
39
|
-
operation: () => Promise<T>,
|
|
40
|
-
errorType: 'database' | 'network' | 'auth' | 'cache' | 'generic' = 'generic'
|
|
41
|
-
): Promise<T> {
|
|
42
|
-
try {
|
|
43
|
-
return await operation();
|
|
44
|
-
} catch (error) {
|
|
45
|
-
const errorObj = error instanceof Error ? error : new Error('Unknown error');
|
|
46
|
-
await firebaseCrashlyticsService.logError(errorObj, serviceName);
|
|
47
|
-
throw error;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performance Decorator
|
|
3
|
-
*
|
|
4
|
-
* DDD Pattern: Decorator for automatic performance tracking
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { performanceTracker } from '../../infrastructure/services/performance/PerformanceTracker';
|
|
8
|
-
import { firebaseCrashlyticsService } from '../../infrastructure/services/crashlytics/FirebaseCrashlyticsService';
|
|
9
|
-
|
|
10
|
-
export function TrackPerformance(operationName?: string) {
|
|
11
|
-
return function (
|
|
12
|
-
target: any,
|
|
13
|
-
propertyKey: string,
|
|
14
|
-
descriptor: PropertyDescriptor
|
|
15
|
-
) {
|
|
16
|
-
const originalMethod = descriptor.value;
|
|
17
|
-
const operation = operationName || `${target?.constructor?.name || 'Unknown'}.${propertyKey}`;
|
|
18
|
-
|
|
19
|
-
descriptor.value = async function (...args: unknown[]) {
|
|
20
|
-
const trackingId = `${operation}_${Date.now()}`;
|
|
21
|
-
return await performanceTracker.track(trackingId, async () => {
|
|
22
|
-
return await originalMethod.apply(this, args);
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
return descriptor;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function TrackOperation(
|
|
31
|
-
operationName: string,
|
|
32
|
-
errorType: 'database' | 'network' | 'auth' | 'cache' | 'generic' = 'generic'
|
|
33
|
-
) {
|
|
34
|
-
return function (
|
|
35
|
-
_target: unknown,
|
|
36
|
-
propertyKey: string,
|
|
37
|
-
descriptor: PropertyDescriptor
|
|
38
|
-
) {
|
|
39
|
-
const originalMethod = descriptor.value;
|
|
40
|
-
|
|
41
|
-
descriptor.value = async function (...args: unknown[]) {
|
|
42
|
-
const trackingId = `${operationName}_${Date.now()}`;
|
|
43
|
-
const startTime = Date.now();
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
performanceTracker.start(trackingId);
|
|
47
|
-
const result = await originalMethod.apply(this, args);
|
|
48
|
-
|
|
49
|
-
await performanceTracker.end(trackingId, {
|
|
50
|
-
operation: operationName,
|
|
51
|
-
method: propertyKey,
|
|
52
|
-
success: true,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return result;
|
|
56
|
-
} catch (error) {
|
|
57
|
-
await performanceTracker.end(trackingId, {
|
|
58
|
-
operation: operationName,
|
|
59
|
-
method: propertyKey,
|
|
60
|
-
success: false,
|
|
61
|
-
duration_ms: Date.now() - startTime,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const errorObj = error instanceof Error ? error : new Error('Unknown error');
|
|
65
|
-
await firebaseCrashlyticsService.logError(
|
|
66
|
-
errorObj,
|
|
67
|
-
`${operationName}.${propertyKey}`
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
return descriptor;
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|