@chem-po/firebase-native 0.0.17 → 0.0.19

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.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/adapter/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAQjB,MAAM,eAAe,CAAA;AAiBtB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAwN1C,eAAO,MAAM,sBAAsB,GACjC,MAAM,IAAI,EACV,mBAAmB,OAAO,KACzB,WAAW,CAAC,gBAAgB,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAkCxE,CAAA"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/adapter/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAQjB,MAAM,eAAe,CAAA;AAiBtB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAkY1C,eAAO,MAAM,sBAAsB,GACjC,MAAM,IAAI,EACV,mBAAmB,OAAO,KACzB,WAAW,CAAC,gBAAgB,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAyDzE,CAAA"}
@@ -6,4 +6,5 @@ export * from './db';
6
6
  export * from './hooks';
7
7
  export * from './storage';
8
8
  export * from './types';
9
+ export * from './utils/validation';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,MAAM,CAAA;AACpB,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,MAAM,CAAA;AACpB,cAAc,SAAS,CAAA;AACvB,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AACvB,cAAc,oBAAoB,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { BaseAuthProvider } from '@chem-po/core';
2
+ interface ValidationResult {
3
+ isValid: boolean;
4
+ errors: string[];
5
+ warnings: string[];
6
+ }
7
+ /**
8
+ * Validates Firebase authentication configuration to help identify common setup issues
9
+ */
10
+ export declare const validateAuthConfiguration: (providers: BaseAuthProvider[]) => ValidationResult;
11
+ /**
12
+ * Logs validation results with appropriate console methods
13
+ */
14
+ export declare const logValidationResults: (result: ValidationResult, packageName?: string) => void;
15
+ /**
16
+ * Validates and logs Firebase auth configuration
17
+ * Call this during development to identify setup issues early
18
+ */
19
+ export declare const validateAndLogAuthConfig: (providers: BaseAuthProvider[]) => ValidationResult;
20
+ export {};
21
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAsB,MAAM,eAAe,CAAA;AAEpE,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,GAAI,WAAW,gBAAgB,EAAE,KAAG,gBAyCzE,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,gBAAgB,EACxB,oBAAwC,SAezC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,WAAW,gBAAgB,EAAE,qBAIrE,CAAA"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@chem-po/firebase-native",
3
3
  "author": "Elan Canfield",
4
4
  "license": "MIT",
5
- "version": "0.0.17",
5
+ "version": "0.0.19",
6
6
  "main": "lib/commonjs/index.js",
7
7
  "types": "lib/typescript/index.d.ts",
8
8
  "source": "src/index.ts",
@@ -43,9 +43,9 @@
43
43
  "react-native-paper": "^5.14.3",
44
44
  "react-native-svg": "15.11.2",
45
45
  "zustand": "^4.3.3",
46
- "@chem-po/react": "0.0.17",
47
- "@chem-po/core": "0.0.17",
48
- "@chem-po/react-native": "0.0.17"
46
+ "@chem-po/core": "0.0.19",
47
+ "@chem-po/react": "0.0.19",
48
+ "@chem-po/react-native": "0.0.19"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@babel/core": "^7.26.0",
@@ -27,17 +27,46 @@ import {
27
27
  import { GoogleSignin } from '@react-native-google-signin/google-signin'
28
28
  import { Auth, User } from '../types/auth'
29
29
 
30
+ const isDebug = (
31
+ typeof process !== 'undefined' &&
32
+ process.env?.EXPO_PUBLIC_DEBUG === 'true'
33
+ ) || false
34
+
35
+ const debugLog = (message: string, data?: any) => {
36
+ if (isDebug) {
37
+ console.log(`[FirebaseAuth Debug] ${message}`, data || '')
38
+ }
39
+ }
40
+
30
41
  const providerInitialized: Record<string, boolean> = {}
31
42
 
32
43
  const getUserWithRole = async <UserData extends BaseUserData>(
33
44
  user: FirebaseAuthTypes.User
34
45
  ): Promise<WithMultiFactorVerified<UserData>> => {
35
- const { claims } = await getIdTokenResult(user)
36
- return {
37
- ...(user as any),
38
- role: claims.role ?? ('user' as BaseUserRole),
39
- multiFactorVerified: !!user.multiFactor?.enrolledFactors.length
40
- } as WithMultiFactorVerified<UserData>
46
+ debugLog('Getting user with role', { uid: user.uid, email: user.email })
47
+
48
+ try {
49
+ const { claims } = await getIdTokenResult(user)
50
+ debugLog('Retrieved ID token claims', { role: claims.role, customClaims: Object.keys(claims) })
51
+
52
+ const userWithRole = {
53
+ ...(user as any),
54
+ role: claims.role ?? ('user' as BaseUserRole),
55
+ multiFactorVerified: !!user.multiFactor?.enrolledFactors.length
56
+ } as WithMultiFactorVerified<UserData>
57
+
58
+ debugLog('User with role created', {
59
+ uid: userWithRole.uid,
60
+ role: userWithRole.role,
61
+ multiFactorVerified: userWithRole.multiFactorVerified,
62
+ enrolledFactorsCount: user.multiFactor?.enrolledFactors.length || 0
63
+ })
64
+
65
+ return userWithRole
66
+ } catch (error) {
67
+ debugLog('Error getting user with role', error)
68
+ throw error
69
+ }
41
70
  }
42
71
 
43
72
  const toEnrollmentFactor = (hint: FirebaseAuthTypes.MultiFactorInfo): EnrollmentFactor => {
@@ -89,30 +118,52 @@ const sendMultiFactorCode = async (
89
118
  factor: EnrollmentFactor,
90
119
  resolver: FirebaseAuthTypes.MultiFactorResolver
91
120
  ): Promise<MultiFactorVerification> => {
121
+ debugLog('Sending multi-factor code', { factorType: factor.type, factorUid: factor.uid })
122
+
92
123
  const sessionId = resolver.session
93
124
  // const verificationId = await new PhoneAuthProvider(auth).verifyPhoneNumber(phoneSignInFactor, sessionId)
94
125
  if (factor.type === 'phone') {
95
- const verificationId = await auth.verifyPhoneNumberWithMultiFactorInfo(
96
- toFirebaseFactor(factor),
97
- sessionId
98
- )
99
- return {
100
- verificationId,
101
- factor,
102
- resolver,
126
+ try {
127
+ const verificationId = await auth.verifyPhoneNumberWithMultiFactorInfo(
128
+ toFirebaseFactor(factor),
129
+ sessionId
130
+ )
131
+ debugLog('Multi-factor code sent successfully', { verificationId: verificationId.substring(0, 10) + '...' })
132
+ return {
133
+ verificationId,
134
+ factor,
135
+ resolver,
136
+ }
137
+ } catch (error) {
138
+ debugLog('Error sending multi-factor code', error)
139
+ throw error
103
140
  }
104
141
  }
105
142
  throw new Error(`Unsupported factor type: ${factor.type ?? 'Missing factor type'}`)
106
143
  }
107
144
 
108
145
  const getEnrolledFactors = async (auth: Auth, error: any): Promise<EnrollmentFactorsResult> => {
109
- const resolver = getMultiFactorResolver(auth, error)
110
- if (resolver.hints.length === 0) {
111
- throw new Error('No multi-factor verification methods found, please enroll one on the website')
112
- }
113
- return {
114
- enrollmentFactors: resolver.hints.map(toEnrollmentFactor),
115
- multiFactorResolver: resolver,
146
+ debugLog('Getting enrolled factors from error', { errorCode: error?.code })
147
+
148
+ try {
149
+ const resolver = getMultiFactorResolver(auth, error)
150
+ debugLog('Multi-factor resolver created', { hintsCount: resolver.hints.length })
151
+
152
+ if (resolver.hints.length === 0) {
153
+ debugLog('No enrolled factors found')
154
+ throw new Error('No multi-factor verification methods found, please enroll one on the website')
155
+ }
156
+
157
+ const enrollmentFactors = resolver.hints.map(toEnrollmentFactor)
158
+ debugLog('Enrollment factors mapped', { factors: enrollmentFactors.map(f => ({ type: f.type, uid: f.uid })) })
159
+
160
+ return {
161
+ enrollmentFactors,
162
+ multiFactorResolver: resolver,
163
+ }
164
+ } catch (error) {
165
+ debugLog('Error getting enrolled factors', error)
166
+ throw error
116
167
  }
117
168
  }
118
169
 
@@ -120,75 +171,163 @@ const verifyMultiFactor = async (
120
171
  verification: MultiFactorVerification,
121
172
  code: string
122
173
  ): Promise<LoginResult<User>> => {
123
- const credential = await PhoneAuthProvider.credential(verification.verificationId, code)
124
- const assertion = PhoneMultiFactorGenerator.assertion(credential)
125
- const resolver = (verification as any).resolver
126
- if (!resolver) throw new Error('Internal error signing in with two factor: resolver not found')
127
- const userCredential = await resolver.resolveSignIn(assertion)
128
- const user = userCredential.user
129
- if (!user) throw new Error('No user found')
130
- return { user: await getUserWithRole(user) }
174
+ debugLog('Verifying multi-factor code', {
175
+ factorType: verification.factor.type,
176
+ codeLength: code.length
177
+ })
178
+
179
+ try {
180
+ const credential = await PhoneAuthProvider.credential(verification.verificationId, code)
181
+ debugLog('Phone credential created')
182
+
183
+ const assertion = PhoneMultiFactorGenerator.assertion(credential)
184
+ debugLog('Multi-factor assertion created')
185
+
186
+ const resolver = (verification as any).resolver
187
+ if (!resolver) {
188
+ debugLog('Multi-factor resolver not found')
189
+ throw new Error('Internal error signing in with two factor: resolver not found')
190
+ }
191
+
192
+ const userCredential = await resolver.resolveSignIn(assertion)
193
+ debugLog('Multi-factor sign-in resolved', { uid: userCredential.user?.uid })
194
+
195
+ const user = userCredential.user
196
+ if (!user) {
197
+ debugLog('No user found after multi-factor resolution')
198
+ throw new Error('No user found')
199
+ }
200
+
201
+ const userWithRole = await getUserWithRole(user)
202
+ debugLog('Multi-factor verification completed successfully')
203
+
204
+ return { user: userWithRole }
205
+ } catch (error) {
206
+ debugLog('Error verifying multi-factor', error)
207
+ throw error
208
+ }
131
209
  }
132
210
 
133
211
  const handleSignInError = async (error: any): Promise<LoginResult<User>> => {
212
+ debugLog('Handling sign-in error', { code: error?.code, message: error?.message })
213
+
134
214
  if (error.code === 'auth/multi-factor-auth-required') {
215
+ debugLog('Multi-factor authentication required')
135
216
  return { requestArgs: error }
136
217
  }
218
+
219
+ debugLog('Re-throwing sign-in error')
137
220
  throw error
138
221
  }
139
222
 
140
223
  const initializeProvider = async (provider: BaseAuthProvider) => {
141
- if (providerInitialized[provider.name]) return
224
+ debugLog('Initializing provider', { name: provider.name, alreadyInitialized: providerInitialized[provider.name] })
225
+
226
+ if (providerInitialized[provider.name]) {
227
+ debugLog('Provider already initialized, skipping')
228
+ return
229
+ }
230
+
142
231
  switch (provider.name) {
143
232
  case 'google':
233
+ debugLog('Initializing Google provider', { webClientId: !!(provider as GoogleAuthProvider).webClientId })
234
+
144
235
  if (!(provider as GoogleAuthProvider).webClientId) {
236
+ debugLog('Google web client ID missing')
145
237
  throw new Error(
146
- 'Google web client ID is required when using Google Auth. Refer to react native firebase docs for more information.'
238
+ 'Google web client ID is required when using Google Auth. ' +
239
+ 'Get your webClientId from Firebase Console > Authentication > Sign-in method > Google > Web SDK configuration. ' +
240
+ 'Then provide it in your GoogleAuthProvider: { name: "google", webClientId: "YOUR_CLIENT_ID" }'
147
241
  )
148
242
  }
149
- await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true })
150
- GoogleSignin.configure({
151
- webClientId: (provider as any).webClientId,
152
- })
243
+
244
+ try {
245
+ await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true })
246
+ debugLog('Google Play Services available')
247
+
248
+ GoogleSignin.configure({
249
+ webClientId: (provider as any).webClientId,
250
+ })
251
+ debugLog('Google Sign-In configured successfully')
252
+ } catch (error) {
253
+ debugLog('Error initializing Google provider', error)
254
+ if (error instanceof Error && error.message.includes('UNAVAILABLE')) {
255
+ throw new Error(
256
+ 'Google Play Services is not available or needs to be updated. ' +
257
+ 'Please ensure Google Play Services is installed and up to date on this device.'
258
+ )
259
+ }
260
+ throw error
261
+ }
153
262
  break
154
263
  case 'email':
264
+ debugLog('Email provider initialization (no special setup required)')
155
265
  // Native SDK doesn't need special initialization
156
266
  break
157
267
  default:
268
+ debugLog('Unsupported provider', { name: provider.name })
158
269
  throw new Error(`Unsupported provider: ${provider.name}`)
159
270
  }
160
271
 
161
272
  providerInitialized[provider.name] = true
273
+ debugLog('Provider initialization completed', { name: provider.name })
162
274
  }
163
275
 
164
276
  const handleInitialLogin = async (
165
277
  userCredential: FirebaseAuthTypes.UserCredential,
166
278
  twoFactorRequired: boolean
167
279
  ): Promise<LoginResult<User>> => {
280
+ debugLog('Handling initial login', {
281
+ uid: userCredential.user?.uid,
282
+ twoFactorRequired,
283
+ enrolledFactorsCount: userCredential.user?.multiFactor?.enrolledFactors.length || 0
284
+ })
285
+
168
286
  const user = userCredential.user
169
- if (!user) throw new Error('No user found')
287
+ if (!user) {
288
+ debugLog('No user found in credential')
289
+ throw new Error('No user found')
290
+ }
291
+
170
292
  if (twoFactorRequired) {
293
+ debugLog('Two-factor authentication is required but user has no enrolled factors')
171
294
  throw new Error(
172
295
  'This app requires two factor authentication, please enroll a factor on the website and try again'
173
296
  )
174
297
  }
175
- return { user: await getUserWithRole(user) }
298
+
299
+ const userWithRole = await getUserWithRole(user)
300
+ debugLog('Initial login completed successfully')
301
+
302
+ return { user: userWithRole }
176
303
  }
177
304
 
178
305
  const loginWithGoogle = async (
179
306
  auth: Auth,
180
307
  twoFactorRequired: boolean
181
308
  ): Promise<LoginResult<User>> => {
309
+ debugLog('Starting Google sign-in', { twoFactorRequired })
310
+
182
311
  try {
312
+ debugLog('Calling GoogleSignin.signIn()')
183
313
  const signInResult = await GoogleSignin.signIn()
314
+ debugLog('Google sign-in result received', { hasIdToken: !!signInResult.data?.idToken })
315
+
184
316
  const idToken = signInResult.data?.idToken
185
317
  if (!idToken) {
318
+ debugLog('No ID token found in Google sign-in result')
186
319
  throw new Error('No ID token found')
187
320
  }
321
+
322
+ debugLog('Creating Google credential')
188
323
  const googleCredential = GoogleAuthProvider.credential(idToken)
324
+
325
+ debugLog('Signing in with Google credential')
189
326
  const userCredential = await signInWithCredential(auth, googleCredential)
327
+
190
328
  return await handleInitialLogin(userCredential, twoFactorRequired)
191
329
  } catch (error) {
330
+ debugLog('Error in Google sign-in', error)
192
331
  return await handleSignInError(error)
193
332
  }
194
333
  }
@@ -199,11 +338,21 @@ const getLoginWithPassword =
199
338
  provider: BaseAuthProvider,
200
339
  { email, password }: { email: string; password: string }
201
340
  ): Promise<LoginResult<User>> => {
341
+ debugLog('Starting email/password sign-in', {
342
+ provider: provider.name,
343
+ email,
344
+ twoFactorRequired
345
+ })
346
+
202
347
  await initializeProvider(provider)
203
348
  try {
349
+ debugLog('Calling signInWithEmailAndPassword')
204
350
  const userCredential = await signInWithEmailAndPassword(auth, email, password)
351
+ debugLog('Email/password sign-in successful', { uid: userCredential.user?.uid })
352
+
205
353
  return await handleInitialLogin(userCredential, twoFactorRequired)
206
354
  } catch (error) {
355
+ debugLog('Error in email/password sign-in', error)
207
356
  return await handleSignInError(error)
208
357
  }
209
358
  }
@@ -211,11 +360,14 @@ const getLoginWithPassword =
211
360
  const getLoginWithPopup =
212
361
  (auth: Auth, twoFactorRequired: boolean) =>
213
362
  async (provider: BaseAuthProvider): Promise<LoginResult<User>> => {
363
+ debugLog('Starting popup sign-in', { provider: provider.name, twoFactorRequired })
364
+
214
365
  await initializeProvider(provider)
215
366
  switch (provider.name) {
216
367
  case 'google':
217
368
  return loginWithGoogle(auth, twoFactorRequired)
218
369
  default:
370
+ debugLog('Unsupported popup provider', { name: provider.name })
219
371
  throw new Error(`Unsupported provider: ${provider.name}`)
220
372
  }
221
373
  }
@@ -223,11 +375,21 @@ const getLoginWithPopup =
223
375
  const getLoginWithToken =
224
376
  (auth: Auth, twoFactorRequired: boolean) =>
225
377
  async (provider: BaseAuthProvider, token: string): Promise<LoginResult<User>> => {
378
+ debugLog('Starting token sign-in', {
379
+ provider: provider.name,
380
+ tokenLength: token.length,
381
+ twoFactorRequired
382
+ })
383
+
226
384
  await initializeProvider(provider)
227
385
  try {
386
+ debugLog('Calling signInWithCustomToken')
228
387
  const userCredential = await signInWithCustomToken(auth, token)
388
+ debugLog('Token sign-in successful', { uid: userCredential.user?.uid })
389
+
229
390
  return await handleInitialLogin(userCredential, twoFactorRequired)
230
391
  } catch (error) {
392
+ debugLog('Error in token sign-in', error)
231
393
  return await handleSignInError(error)
232
394
  }
233
395
  }
@@ -237,45 +399,76 @@ const resetPassword = async (
237
399
  provider: BaseAuthProvider,
238
400
  usernameOrEmail: string
239
401
  ): Promise<void> => {
402
+ debugLog('Starting password reset', { provider: provider.name, email: usernameOrEmail })
403
+
240
404
  await initializeProvider(provider)
241
- await sendPasswordResetEmail(auth, usernameOrEmail)
405
+ try {
406
+ await sendPasswordResetEmail(auth, usernameOrEmail)
407
+ debugLog('Password reset email sent successfully')
408
+ } catch (error) {
409
+ debugLog('Error sending password reset email', error)
410
+ throw error
411
+ }
242
412
  }
243
413
 
244
414
  export const getFirebaseAuthAdapter = (
245
415
  auth: Auth,
246
416
  twoFactorRequired: boolean
247
- ): AuthAdapter<BaseAuthProvider, User, { email: string; password: string }> => ({
248
- twoFactorRequired,
249
- getCurrentUser: async () => {
250
- const user = auth.currentUser
251
- if (!user) return null
252
- return getUserWithRole(user)
253
- },
254
- loginWithPassword: getLoginWithPassword(auth, twoFactorRequired),
255
- loginWithPopup: getLoginWithPopup(auth, twoFactorRequired),
256
- loginWithToken: getLoginWithToken(auth, twoFactorRequired),
257
- resetPassword: (...args) => {
258
- return resetPassword(auth, ...args)
259
- },
260
- verifyMultiFactor,
261
- sendMultiFactorCode: (...args) => {
262
- return sendMultiFactorCode(auth, ...args)
263
- },
264
- getEnrolledFactors: (...args) => {
265
- return getEnrolledFactors(auth, ...args)
266
- },
267
- logout: async () => {
268
- await signOut(auth)
269
- },
270
- subscribeToUser: (callback) => {
271
- return onAuthStateChanged(auth, (user) => {
417
+ ): AuthAdapter<BaseAuthProvider, User, { email: string; password: string }> => {
418
+ debugLog('Creating Firebase Auth Adapter', { twoFactorRequired })
419
+
420
+ return {
421
+ twoFactorRequired,
422
+ getCurrentUser: async () => {
423
+ debugLog('Getting current user')
424
+ const user = auth.currentUser
272
425
  if (!user) {
273
- callback(null)
274
- return
426
+ debugLog('No current user found')
427
+ return null
428
+ }
429
+ debugLog('Current user found', { uid: user.uid, email: user.email })
430
+ return getUserWithRole(user)
431
+ },
432
+ loginWithPassword: getLoginWithPassword(auth, twoFactorRequired),
433
+ loginWithPopup: getLoginWithPopup(auth, twoFactorRequired),
434
+ loginWithToken: getLoginWithToken(auth, twoFactorRequired),
435
+ resetPassword: (...args) => {
436
+ return resetPassword(auth, ...args)
437
+ },
438
+ verifyMultiFactor,
439
+ sendMultiFactorCode: (...args) => {
440
+ return sendMultiFactorCode(auth, ...args)
441
+ },
442
+ getEnrolledFactors: (...args) => {
443
+ return getEnrolledFactors(auth, ...args)
444
+ },
445
+ logout: async () => {
446
+ debugLog('Starting logout')
447
+ try {
448
+ await signOut(auth)
449
+ debugLog('Logout completed successfully')
450
+ } catch (error) {
451
+ debugLog('Error during logout', error)
452
+ throw error
275
453
  }
276
- getUserWithRole(user).then((result) => {
277
- callback(result)
454
+ },
455
+ subscribeToUser: (callback) => {
456
+ debugLog('Setting up user subscription')
457
+ return onAuthStateChanged(auth, (user) => {
458
+ if (!user) {
459
+ debugLog('User state changed: signed out')
460
+ callback(null)
461
+ return
462
+ }
463
+ debugLog('User state changed: user signed in', { uid: user.uid, email: user.email })
464
+ getUserWithRole(user).then((result) => {
465
+ debugLog('User subscription callback completed', { uid: result.uid, role: result.role })
466
+ callback(result)
467
+ }).catch((error) => {
468
+ debugLog('Error in user subscription callback', error)
469
+ callback(null)
470
+ })
278
471
  })
279
- })
280
- },
281
- })
472
+ },
473
+ }
474
+ }
@@ -25,7 +25,7 @@ const GoogleLogin = ({ provider }: { provider: GoogleAuthProvider }) => {
25
25
  const { showError } = useToast()
26
26
 
27
27
  const handleSignIn = useCallback(() => {
28
- auth.loginWithPopup(provider).catch(error => {
28
+ return auth.loginWithPopup(provider).catch(error => {
29
29
  showError(error instanceof Error ? error.message : 'An unknown error occurred')
30
30
  })
31
31
  }, [auth, provider, showError])
package/src/index.ts CHANGED
@@ -6,3 +6,4 @@ export * from './db'
6
6
  export * from './hooks'
7
7
  export * from './storage'
8
8
  export * from './types'
9
+ export * from './utils/validation'
@@ -0,0 +1,85 @@
1
+ import { BaseAuthProvider, GoogleAuthProvider } from '@chem-po/core'
2
+
3
+ interface ValidationResult {
4
+ isValid: boolean
5
+ errors: string[]
6
+ warnings: string[]
7
+ }
8
+
9
+ /**
10
+ * Validates Firebase authentication configuration to help identify common setup issues
11
+ */
12
+ export const validateAuthConfiguration = (providers: BaseAuthProvider[]): ValidationResult => {
13
+ const errors: string[] = []
14
+ const warnings: string[] = []
15
+
16
+ // Check for Google provider configuration
17
+ const googleProvider = providers.find(p => p.name === 'google') as GoogleAuthProvider | undefined
18
+
19
+ if (googleProvider) {
20
+ if (!googleProvider.webClientId) {
21
+ errors.push(
22
+ 'Google provider is missing webClientId. ' +
23
+ 'Get this from Firebase Console > Authentication > Sign-in method > Google > Web SDK configuration',
24
+ )
25
+ } else if (!googleProvider.webClientId.includes('.apps.googleusercontent.com')) {
26
+ warnings.push(
27
+ 'Google webClientId format looks incorrect. Expected format: "xxx.apps.googleusercontent.com"',
28
+ )
29
+ }
30
+ }
31
+
32
+ // Check environment
33
+ if (typeof process === 'undefined') {
34
+ warnings.push('Process environment is not available - some features may not work as expected')
35
+ }
36
+
37
+ // Check for Firebase configuration files (platform-specific warnings)
38
+ const isExpo =
39
+ typeof process !== 'undefined' && process.env?.EXPO_PUBLIC_ENVIRONMENT !== undefined
40
+ if (!isExpo) {
41
+ warnings.push(
42
+ 'Ensure Firebase configuration files are present:\n' +
43
+ '- iOS: GoogleService-Info.plist in ios/ directory\n' +
44
+ '- Android: google-services.json in android/app/ directory',
45
+ )
46
+ }
47
+
48
+ return {
49
+ isValid: errors.length === 0,
50
+ errors,
51
+ warnings,
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Logs validation results with appropriate console methods
57
+ */
58
+ export const logValidationResults = (
59
+ result: ValidationResult,
60
+ packageName = '@chem-po/firebase-native',
61
+ ) => {
62
+ if (result.errors.length > 0) {
63
+ console.error(`[${packageName}] Configuration errors found:`)
64
+ result.errors.forEach(error => console.error(` ❌ ${error}`))
65
+ }
66
+
67
+ if (result.warnings.length > 0) {
68
+ console.warn(`[${packageName}] Configuration warnings:`)
69
+ result.warnings.forEach(warning => console.warn(` ⚠️ ${warning}`))
70
+ }
71
+
72
+ if (result.isValid && result.warnings.length === 0) {
73
+ console.log(`[${packageName}] ✅ Configuration validation passed`)
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Validates and logs Firebase auth configuration
79
+ * Call this during development to identify setup issues early
80
+ */
81
+ export const validateAndLogAuthConfig = (providers: BaseAuthProvider[]) => {
82
+ const result = validateAuthConfiguration(providers)
83
+ logValidationResults(result)
84
+ return result
85
+ }