@umituz/react-native-firebase 1.13.40 → 1.13.42
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 -5
- package/src/auth/infrastructure/config/initializers/FirebaseAuthInitializer.ts +8 -38
- package/src/auth/infrastructure/services/anonymous-auth.service.ts +3 -103
- package/src/auth/infrastructure/services/apple-auth.service.ts +7 -88
- package/src/auth/infrastructure/services/google-auth.service.ts +3 -36
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.42",
|
|
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",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"url": "https://github.com/umituz/react-native-firebase"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@umituz/react-native-sentry": "*",
|
|
36
35
|
"@umituz/react-native-storage": "*",
|
|
37
36
|
"expo-apple-authentication": ">=6.0.0",
|
|
38
37
|
"expo-crypto": ">=13.0.0",
|
|
@@ -42,11 +41,8 @@
|
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
45
|
-
"@sentry/react-native": "^7.8.0",
|
|
46
|
-
"@sentry/types": "^10.32.1",
|
|
47
44
|
"@types/jest": "^30.0.0",
|
|
48
45
|
"@types/react": "~19.1.10",
|
|
49
|
-
"@umituz/react-native-sentry": "*",
|
|
50
46
|
"@umituz/react-native-storage": "*",
|
|
51
47
|
"expo-apple-authentication": "^8.0.8",
|
|
52
48
|
"expo-crypto": "^15.0.8",
|
|
@@ -16,10 +16,6 @@ import type { Auth } from 'firebase/auth';
|
|
|
16
16
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
17
17
|
import type { FirebaseApp } from 'firebase/app';
|
|
18
18
|
import type { FirebaseAuthConfig } from '../../../domain/value-objects/FirebaseAuthConfig';
|
|
19
|
-
import {
|
|
20
|
-
trackPackageError,
|
|
21
|
-
addPackageBreadcrumb,
|
|
22
|
-
trackPackageWarning,
|
|
23
19
|
|
|
24
20
|
declare const __DEV__: boolean;
|
|
25
21
|
|
|
@@ -32,13 +28,13 @@ export class FirebaseAuthInitializer {
|
|
|
32
28
|
* Initialize Firebase Auth with persistence support
|
|
33
29
|
*/
|
|
34
30
|
static initialize(app: FirebaseApp, config?: FirebaseAuthConfig): Auth | null {
|
|
35
|
-
|
|
31
|
+
if (__DEV__) console.log('[Firebase Auth] Initializing...');
|
|
36
32
|
|
|
37
33
|
try {
|
|
38
34
|
const auth = this.initializeWithPersistence(app, config);
|
|
39
35
|
|
|
40
|
-
if (auth) {
|
|
41
|
-
|
|
36
|
+
if (auth && __DEV__) {
|
|
37
|
+
console.log('[Firebase Auth] Successfully initialized');
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
return auth;
|
|
@@ -48,26 +44,15 @@ export class FirebaseAuthInitializer {
|
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
private static handleInitializationError(error: unknown, app: FirebaseApp): Auth | null {
|
|
51
|
-
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
52
47
|
const errorCode = (error as { code?: string })?.code;
|
|
53
48
|
|
|
54
49
|
if (errorCode === 'auth/already-initialized') {
|
|
55
|
-
|
|
56
|
-
'firebase-auth',
|
|
57
|
-
'Auth already initialized, returning existing instance',
|
|
58
|
-
{ errorCode }
|
|
59
|
-
);
|
|
50
|
+
if (__DEV__) console.log('[Firebase Auth] Already initialized, returning existing instance');
|
|
60
51
|
return this.getExistingAuth(app);
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
trackPackageError(errorObj, {
|
|
64
|
-
packageName: 'firebase-auth',
|
|
65
|
-
operation: 'initialize',
|
|
66
|
-
errorCode,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
54
|
if (__DEV__) {
|
|
70
|
-
console.warn('Firebase Auth
|
|
55
|
+
console.warn('[Firebase Auth] Initialization error:', error);
|
|
71
56
|
}
|
|
72
57
|
|
|
73
58
|
return this.getExistingAuth(app);
|
|
@@ -77,17 +62,8 @@ export class FirebaseAuthInitializer {
|
|
|
77
62
|
try {
|
|
78
63
|
return getAuth(app);
|
|
79
64
|
} catch (getAuthError) {
|
|
80
|
-
const errorObj = getAuthError instanceof Error
|
|
81
|
-
? getAuthError
|
|
82
|
-
: new Error(String(getAuthError));
|
|
83
|
-
|
|
84
|
-
trackPackageError(errorObj, {
|
|
85
|
-
packageName: 'firebase-auth',
|
|
86
|
-
operation: 'getAuth-fallback',
|
|
87
|
-
});
|
|
88
|
-
|
|
89
65
|
if (__DEV__) {
|
|
90
|
-
console.warn('Firebase Auth
|
|
66
|
+
console.warn('[Firebase Auth] Failed to get auth instance:', getAuthError);
|
|
91
67
|
}
|
|
92
68
|
return null;
|
|
93
69
|
}
|
|
@@ -104,20 +80,14 @@ export class FirebaseAuthInitializer {
|
|
|
104
80
|
removeItem: (key: string) => AsyncStorage.removeItem(key),
|
|
105
81
|
};
|
|
106
82
|
|
|
107
|
-
|
|
83
|
+
if (__DEV__) console.log('[Firebase Auth] Initializing with AsyncStorage persistence');
|
|
108
84
|
|
|
109
85
|
return initializeAuth(app, {
|
|
110
86
|
persistence: getReactNativePersistence(storage),
|
|
111
87
|
});
|
|
112
88
|
} catch (error) {
|
|
113
|
-
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
114
|
-
trackPackageError(errorObj, {
|
|
115
|
-
packageName: 'firebase-auth',
|
|
116
|
-
operation: 'initializeWithPersistence',
|
|
117
|
-
});
|
|
118
|
-
|
|
119
89
|
if (__DEV__) {
|
|
120
|
-
console.warn('Firebase Auth
|
|
90
|
+
console.warn('[Firebase Auth] Persistence initialization failed:', error);
|
|
121
91
|
}
|
|
122
92
|
|
|
123
93
|
return this.getExistingAuth(app);
|
|
@@ -6,11 +6,6 @@
|
|
|
6
6
|
import { signInAnonymously, type Auth, type User } from "firebase/auth";
|
|
7
7
|
import { toAnonymousUser, type AnonymousUser } from "../../domain/entities/AnonymousUser";
|
|
8
8
|
import { checkAuthState } from "./auth-utils.service";
|
|
9
|
-
import {
|
|
10
|
-
trackPackageError,
|
|
11
|
-
addPackageBreadcrumb,
|
|
12
|
-
|
|
13
|
-
declare const __DEV__: boolean;
|
|
14
9
|
|
|
15
10
|
export interface AnonymousAuthResult {
|
|
16
11
|
readonly user: User;
|
|
@@ -18,36 +13,13 @@ export interface AnonymousAuthResult {
|
|
|
18
13
|
readonly wasAlreadySignedIn: boolean;
|
|
19
14
|
}
|
|
20
15
|
|
|
21
|
-
export
|
|
22
|
-
signInAnonymously(auth: Auth): Promise<AnonymousAuthResult>;
|
|
23
|
-
getCurrentAnonymousUser(auth: Auth | null): User | null;
|
|
24
|
-
isCurrentUserAnonymous(auth: Auth | null): boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Anonymous Auth Service
|
|
29
|
-
* Handles anonymous authentication operations
|
|
30
|
-
*/
|
|
31
|
-
export class AnonymousAuthService implements AnonymousAuthServiceInterface {
|
|
32
|
-
/**
|
|
33
|
-
* Sign in anonymously
|
|
34
|
-
* IMPORTANT: Only signs in if NO user exists (preserves email/password sessions)
|
|
35
|
-
*/
|
|
16
|
+
export class AnonymousAuthService {
|
|
36
17
|
async signInAnonymously(auth: Auth): Promise<AnonymousAuthResult> {
|
|
37
|
-
if (!auth)
|
|
38
|
-
throw new Error("Firebase Auth instance is required");
|
|
39
|
-
}
|
|
18
|
+
if (!auth) throw new Error("Firebase Auth instance is required");
|
|
40
19
|
|
|
41
20
|
const currentUser = auth.currentUser;
|
|
42
21
|
|
|
43
|
-
// If user is already signed in with email/password, preserve that session
|
|
44
22
|
if (currentUser && !currentUser.isAnonymous) {
|
|
45
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
46
|
-
// eslint-disable-next-line no-console
|
|
47
|
-
console.log("[AnonymousAuthService] User already signed in with email/password, skipping anonymous auth");
|
|
48
|
-
}
|
|
49
|
-
// Return a "fake" anonymous result to maintain API compatibility
|
|
50
|
-
// The actual user is NOT anonymous
|
|
51
23
|
return {
|
|
52
24
|
user: currentUser,
|
|
53
25
|
anonymousUser: toAnonymousUser(currentUser),
|
|
@@ -55,12 +27,7 @@ export class AnonymousAuthService implements AnonymousAuthServiceInterface {
|
|
|
55
27
|
};
|
|
56
28
|
}
|
|
57
29
|
|
|
58
|
-
// If already signed in anonymously, return existing user
|
|
59
30
|
if (currentUser && currentUser.isAnonymous) {
|
|
60
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
61
|
-
// eslint-disable-next-line no-console
|
|
62
|
-
console.log("[AnonymousAuthService] User already signed in anonymously");
|
|
63
|
-
}
|
|
64
31
|
return {
|
|
65
32
|
user: currentUser,
|
|
66
33
|
anonymousUser: toAnonymousUser(currentUser),
|
|
@@ -68,86 +35,19 @@ export class AnonymousAuthService implements AnonymousAuthServiceInterface {
|
|
|
68
35
|
};
|
|
69
36
|
}
|
|
70
37
|
|
|
71
|
-
// No user exists, sign in anonymously
|
|
72
|
-
addPackageBreadcrumb("firebase-auth", "Starting anonymous sign-in");
|
|
73
|
-
|
|
74
38
|
try {
|
|
75
39
|
const userCredential = await signInAnonymously(auth);
|
|
76
40
|
const anonymousUser = toAnonymousUser(userCredential.user);
|
|
77
|
-
|
|
78
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
79
|
-
// eslint-disable-next-line no-console
|
|
80
|
-
console.log("[AnonymousAuthService] Successfully signed in anonymously", { uid: anonymousUser.uid });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
addPackageBreadcrumb("firebase-auth", "Anonymous sign-in successful", {
|
|
84
|
-
userId: anonymousUser.uid,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
41
|
return {
|
|
88
42
|
user: userCredential.user,
|
|
89
43
|
anonymousUser,
|
|
90
44
|
wasAlreadySignedIn: false,
|
|
91
45
|
};
|
|
92
46
|
} catch (error) {
|
|
93
|
-
if (
|
|
94
|
-
// eslint-disable-next-line no-console
|
|
95
|
-
console.error("[AnonymousAuthService] Failed to sign in anonymously", error);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
trackPackageError(
|
|
99
|
-
error instanceof Error ? error : new Error("Anonymous sign-in failed"),
|
|
100
|
-
{
|
|
101
|
-
packageName: "firebase-auth",
|
|
102
|
-
operation: "anonymous-sign-in",
|
|
103
|
-
}
|
|
104
|
-
);
|
|
105
|
-
|
|
47
|
+
if (__DEV__) console.error("[AnonymousAuthService] Failed", error);
|
|
106
48
|
throw error;
|
|
107
49
|
}
|
|
108
50
|
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get current anonymous user
|
|
112
|
-
*/
|
|
113
|
-
getCurrentAnonymousUser(auth: Auth | null): User | null {
|
|
114
|
-
if (!auth) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const state = checkAuthState(auth);
|
|
120
|
-
if (state.isAnonymous && state.currentUser) {
|
|
121
|
-
return state.currentUser;
|
|
122
|
-
}
|
|
123
|
-
return null;
|
|
124
|
-
} catch (error) {
|
|
125
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
126
|
-
// eslint-disable-next-line no-console
|
|
127
|
-
console.error("[AnonymousAuthService] Error getting current anonymous user", error);
|
|
128
|
-
}
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Check if current user is anonymous
|
|
135
|
-
*/
|
|
136
|
-
isCurrentUserAnonymous(auth: Auth | null): boolean {
|
|
137
|
-
if (!auth) {
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
return checkAuthState(auth).isAnonymous;
|
|
143
|
-
} catch (error) {
|
|
144
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
145
|
-
// eslint-disable-next-line no-console
|
|
146
|
-
console.error("[AnonymousAuthService] Error checking if user is anonymous", error);
|
|
147
|
-
}
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
51
|
}
|
|
152
52
|
|
|
153
53
|
export const anonymousAuthService = new AnonymousAuthService();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Apple Auth Service
|
|
3
3
|
* Handles Apple Sign-In with Firebase Authentication
|
|
4
|
-
* Uses expo-apple-authentication for native Apple Sign-In
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
6
|
import {
|
|
@@ -13,13 +12,7 @@ import {
|
|
|
13
12
|
import * as AppleAuthentication from "expo-apple-authentication";
|
|
14
13
|
import * as Crypto from "expo-crypto";
|
|
15
14
|
import { Platform } from "react-native";
|
|
16
|
-
import {
|
|
17
|
-
trackPackageError,
|
|
18
|
-
addPackageBreadcrumb,
|
|
19
15
|
|
|
20
|
-
/**
|
|
21
|
-
* Apple Auth result
|
|
22
|
-
*/
|
|
23
16
|
export interface AppleAuthResult {
|
|
24
17
|
success: boolean;
|
|
25
18
|
userCredential?: UserCredential;
|
|
@@ -27,20 +20,9 @@ export interface AppleAuthResult {
|
|
|
27
20
|
isNewUser?: boolean;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
/**
|
|
31
|
-
* Apple Auth Service
|
|
32
|
-
* Provides Apple Sign-In functionality for Firebase (iOS only)
|
|
33
|
-
*/
|
|
34
23
|
export class AppleAuthService {
|
|
35
|
-
/**
|
|
36
|
-
* Check if Apple Sign-In is available
|
|
37
|
-
* Only available on iOS 13+
|
|
38
|
-
*/
|
|
39
24
|
async isAvailable(): Promise<boolean> {
|
|
40
|
-
if (Platform.OS !== "ios")
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
25
|
+
if (Platform.OS !== "ios") return false;
|
|
44
26
|
try {
|
|
45
27
|
return await AppleAuthentication.isAvailableAsync();
|
|
46
28
|
} catch {
|
|
@@ -48,36 +30,22 @@ export class AppleAuthService {
|
|
|
48
30
|
}
|
|
49
31
|
}
|
|
50
32
|
|
|
51
|
-
/**
|
|
52
|
-
* Sign in with Apple
|
|
53
|
-
* Handles the complete Apple Sign-In flow
|
|
54
|
-
*/
|
|
55
33
|
async signIn(auth: Auth): Promise<AppleAuthResult> {
|
|
56
|
-
addPackageBreadcrumb("firebase-auth", "Apple Sign-In started");
|
|
57
|
-
|
|
58
34
|
try {
|
|
59
|
-
// Check availability
|
|
60
35
|
const isAvailable = await this.isAvailable();
|
|
61
36
|
if (!isAvailable) {
|
|
62
|
-
addPackageBreadcrumb("firebase-auth", "Apple Sign-In not available", {
|
|
63
|
-
platform: Platform.OS,
|
|
64
|
-
});
|
|
65
37
|
return {
|
|
66
38
|
success: false,
|
|
67
39
|
error: "Apple Sign-In is not available on this device",
|
|
68
40
|
};
|
|
69
41
|
}
|
|
70
42
|
|
|
71
|
-
// Generate nonce for security
|
|
72
43
|
const nonce = await this.generateNonce();
|
|
73
44
|
const hashedNonce = await Crypto.digestStringAsync(
|
|
74
45
|
Crypto.CryptoDigestAlgorithm.SHA256,
|
|
75
46
|
nonce,
|
|
76
47
|
);
|
|
77
48
|
|
|
78
|
-
addPackageBreadcrumb("firebase-auth", "Requesting Apple credentials");
|
|
79
|
-
|
|
80
|
-
// Request Apple Sign-In
|
|
81
49
|
const appleCredential = await AppleAuthentication.signInAsync({
|
|
82
50
|
requestedScopes: [
|
|
83
51
|
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
|
|
@@ -86,69 +54,31 @@ export class AppleAuthService {
|
|
|
86
54
|
nonce: hashedNonce,
|
|
87
55
|
});
|
|
88
56
|
|
|
89
|
-
// Check for identity token
|
|
90
57
|
if (!appleCredential.identityToken) {
|
|
91
|
-
|
|
92
|
-
trackPackageError(error, {
|
|
93
|
-
packageName: "firebase-auth",
|
|
94
|
-
operation: "apple-sign-in",
|
|
95
|
-
});
|
|
96
|
-
return {
|
|
97
|
-
success: false,
|
|
98
|
-
error: "No identity token received from Apple",
|
|
99
|
-
};
|
|
58
|
+
return { success: false, error: "No identity token received" };
|
|
100
59
|
}
|
|
101
60
|
|
|
102
|
-
addPackageBreadcrumb("firebase-auth", "Creating Firebase credential");
|
|
103
|
-
|
|
104
|
-
// Create Firebase credential
|
|
105
61
|
const provider = new OAuthProvider("apple.com");
|
|
106
62
|
const credential = provider.credential({
|
|
107
63
|
idToken: appleCredential.identityToken,
|
|
108
64
|
rawNonce: nonce,
|
|
109
65
|
});
|
|
110
66
|
|
|
111
|
-
// Sign in to Firebase
|
|
112
67
|
const userCredential = await signInWithCredential(auth, credential);
|
|
113
|
-
|
|
114
|
-
// Check if this is a new user
|
|
115
68
|
const isNewUser =
|
|
116
69
|
userCredential.user.metadata.creationTime ===
|
|
117
70
|
userCredential.user.metadata.lastSignInTime;
|
|
118
71
|
|
|
119
|
-
addPackageBreadcrumb("firebase-auth", "Apple Sign-In successful", {
|
|
120
|
-
isNewUser,
|
|
121
|
-
userId: userCredential.user.uid,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
72
|
return {
|
|
125
73
|
success: true,
|
|
126
74
|
userCredential,
|
|
127
75
|
isNewUser,
|
|
128
76
|
};
|
|
129
77
|
} catch (error) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
error instanceof Error &&
|
|
133
|
-
error.message.includes("ERR_CANCELED")
|
|
134
|
-
) {
|
|
135
|
-
addPackageBreadcrumb("firebase-auth", "Apple Sign-In cancelled by user");
|
|
136
|
-
return {
|
|
137
|
-
success: false,
|
|
138
|
-
error: "Apple Sign-In was cancelled",
|
|
139
|
-
};
|
|
78
|
+
if (error instanceof Error && error.message.includes("ERR_CANCELED")) {
|
|
79
|
+
return { success: false, error: "Apple Sign-In was cancelled" };
|
|
140
80
|
}
|
|
141
|
-
|
|
142
|
-
// Track error in Sentry
|
|
143
|
-
trackPackageError(
|
|
144
|
-
error instanceof Error ? error : new Error("Apple sign-in failed"),
|
|
145
|
-
{
|
|
146
|
-
packageName: "firebase-auth",
|
|
147
|
-
operation: "apple-sign-in",
|
|
148
|
-
platform: Platform.OS,
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
|
|
81
|
+
if (__DEV__) console.error('[Firebase Auth] Apple Sign-In failed:', error);
|
|
152
82
|
return {
|
|
153
83
|
success: false,
|
|
154
84
|
error: error instanceof Error ? error.message : "Apple sign-in failed",
|
|
@@ -156,27 +86,16 @@ export class AppleAuthService {
|
|
|
156
86
|
}
|
|
157
87
|
}
|
|
158
88
|
|
|
159
|
-
/**
|
|
160
|
-
* Generate a random nonce for Apple Sign-In security
|
|
161
|
-
*/
|
|
162
89
|
private async generateNonce(length: number = 32): Promise<string> {
|
|
163
90
|
const randomBytes = await Crypto.getRandomBytesAsync(length);
|
|
164
|
-
const chars =
|
|
165
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
91
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
166
92
|
let result = "";
|
|
167
|
-
|
|
168
93
|
for (let i = 0; i < randomBytes.length; i++) {
|
|
169
94
|
const byte = randomBytes[i];
|
|
170
|
-
if (byte !== undefined)
|
|
171
|
-
result += chars.charAt(byte % chars.length);
|
|
172
|
-
}
|
|
95
|
+
if (byte !== undefined) result += chars.charAt(byte % chars.length);
|
|
173
96
|
}
|
|
174
|
-
|
|
175
97
|
return result;
|
|
176
98
|
}
|
|
177
99
|
}
|
|
178
100
|
|
|
179
|
-
/**
|
|
180
|
-
* Singleton instance
|
|
181
|
-
*/
|
|
182
101
|
export const appleAuthService = new AppleAuthService();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Google Auth Service
|
|
3
3
|
* Handles Google Sign-In with Firebase Authentication
|
|
4
|
-
* Uses expo-auth-session for OAuth flow
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
6
|
import {
|
|
@@ -10,9 +9,6 @@ import {
|
|
|
10
9
|
type Auth,
|
|
11
10
|
type UserCredential,
|
|
12
11
|
} from "firebase/auth";
|
|
13
|
-
import {
|
|
14
|
-
trackPackageError,
|
|
15
|
-
addPackageBreadcrumb,
|
|
16
12
|
|
|
17
13
|
/**
|
|
18
14
|
* Google Auth configuration
|
|
@@ -40,16 +36,10 @@ export interface GoogleAuthResult {
|
|
|
40
36
|
export class GoogleAuthService {
|
|
41
37
|
private config: GoogleAuthConfig | null = null;
|
|
42
38
|
|
|
43
|
-
/**
|
|
44
|
-
* Configure Google Auth with client IDs
|
|
45
|
-
*/
|
|
46
39
|
configure(config: GoogleAuthConfig): void {
|
|
47
40
|
this.config = config;
|
|
48
41
|
}
|
|
49
42
|
|
|
50
|
-
/**
|
|
51
|
-
* Check if Google Auth is configured
|
|
52
|
-
*/
|
|
53
43
|
isConfigured(): boolean {
|
|
54
44
|
return (
|
|
55
45
|
this.config !== null &&
|
|
@@ -59,51 +49,31 @@ export class GoogleAuthService {
|
|
|
59
49
|
);
|
|
60
50
|
}
|
|
61
51
|
|
|
62
|
-
/**
|
|
63
|
-
* Get the current configuration
|
|
64
|
-
*/
|
|
65
52
|
getConfig(): GoogleAuthConfig | null {
|
|
66
53
|
return this.config;
|
|
67
54
|
}
|
|
68
55
|
|
|
69
|
-
/**
|
|
70
|
-
* Sign in with Google ID token
|
|
71
|
-
* Called after successful Google OAuth flow
|
|
72
|
-
*/
|
|
73
56
|
async signInWithIdToken(
|
|
74
57
|
auth: Auth,
|
|
75
58
|
idToken: string,
|
|
76
59
|
): Promise<GoogleAuthResult> {
|
|
77
|
-
addPackageBreadcrumb("firebase-auth", "Google Sign-In with ID token");
|
|
78
|
-
|
|
79
60
|
try {
|
|
80
61
|
const credential = GoogleAuthProvider.credential(idToken);
|
|
81
62
|
const userCredential = await signInWithCredential(auth, credential);
|
|
82
63
|
|
|
83
|
-
// Check if this is a new user
|
|
84
64
|
const isNewUser =
|
|
85
65
|
userCredential.user.metadata.creationTime ===
|
|
86
66
|
userCredential.user.metadata.lastSignInTime;
|
|
87
67
|
|
|
88
|
-
addPackageBreadcrumb("firebase-auth", "Google Sign-In successful", {
|
|
89
|
-
isNewUser,
|
|
90
|
-
userId: userCredential.user.uid,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
68
|
return {
|
|
94
69
|
success: true,
|
|
95
70
|
userCredential,
|
|
96
71
|
isNewUser,
|
|
97
72
|
};
|
|
98
73
|
} catch (error) {
|
|
99
|
-
|
|
100
|
-
error
|
|
101
|
-
|
|
102
|
-
packageName: "firebase-auth",
|
|
103
|
-
operation: "google-sign-in",
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
|
|
74
|
+
if (__DEV__) {
|
|
75
|
+
console.error('[Firebase Auth] Google Sign-In failed:', error);
|
|
76
|
+
}
|
|
107
77
|
return {
|
|
108
78
|
success: false,
|
|
109
79
|
error: error instanceof Error ? error.message : "Google sign-in failed",
|
|
@@ -112,7 +82,4 @@ export class GoogleAuthService {
|
|
|
112
82
|
}
|
|
113
83
|
}
|
|
114
84
|
|
|
115
|
-
/**
|
|
116
|
-
* Singleton instance
|
|
117
|
-
*/
|
|
118
85
|
export const googleAuthService = new GoogleAuthService();
|