@umituz/react-native-firebase 2.6.0 → 2.6.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.
Files changed (39) hide show
  1. package/package.json +1 -1
  2. package/src/application/auth/index.ts +42 -0
  3. package/src/application/auth/ports/AuthPort.ts +164 -0
  4. package/src/application/auth/use-cases/SignInUseCase.ts +253 -0
  5. package/src/application/auth/use-cases/SignOutUseCase.ts +288 -0
  6. package/src/application/auth/use-cases/index.ts +26 -0
  7. package/src/domains/account-deletion/domain/index.ts +15 -0
  8. package/src/domains/account-deletion/domain/services/UserValidationService.ts +295 -0
  9. package/src/domains/account-deletion/index.ts +43 -6
  10. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor.ts +230 -0
  11. package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler.ts +174 -0
  12. package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository.ts +266 -0
  13. package/src/domains/account-deletion/infrastructure/services/AccountDeletionTypes.ts +33 -0
  14. package/src/domains/account-deletion/infrastructure/services/account-deletion.service.ts +39 -227
  15. package/src/domains/auth/domain.ts +16 -0
  16. package/src/domains/auth/index.ts +7 -148
  17. package/src/domains/auth/infrastructure.ts +156 -0
  18. package/src/domains/auth/presentation/hooks/GoogleOAuthHookService.ts +247 -0
  19. package/src/domains/auth/presentation/hooks/useGoogleOAuth.ts +49 -103
  20. package/src/domains/auth/presentation.ts +25 -0
  21. package/src/domains/firestore/domain/entities/Collection.ts +288 -0
  22. package/src/domains/firestore/domain/entities/Document.ts +233 -0
  23. package/src/domains/firestore/domain/index.ts +30 -0
  24. package/src/domains/firestore/domain/services/QueryService.ts +182 -0
  25. package/src/domains/firestore/domain/services/QueryServiceAnalysis.ts +169 -0
  26. package/src/domains/firestore/domain/services/QueryServiceHelpers.ts +151 -0
  27. package/src/domains/firestore/domain/value-objects/QueryOptions.ts +191 -0
  28. package/src/domains/firestore/domain/value-objects/QueryOptions.ts.bak +320 -0
  29. package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization.ts +207 -0
  30. package/src/domains/firestore/domain/value-objects/QueryOptionsValidation.ts +182 -0
  31. package/src/domains/firestore/domain/value-objects/WhereClause.ts +299 -0
  32. package/src/domains/firestore/domain/value-objects/WhereClauseFactory.ts +207 -0
  33. package/src/domains/firestore/index.ts +9 -6
  34. package/src/index.ts +25 -0
  35. package/src/shared/domain/utils/error-handlers/error-messages.ts +11 -0
  36. package/src/shared/infrastructure/base/ErrorHandler.ts +189 -0
  37. package/src/shared/infrastructure/base/ServiceBase.ts +220 -0
  38. package/src/shared/infrastructure/base/TypedGuard.ts +131 -0
  39. package/src/shared/infrastructure/base/index.ts +34 -0
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Sign Out Use Case
3
+ * Single Responsibility: Handle user sign out operations
4
+ *
5
+ * Application use case for user sign out.
6
+ * Ensures proper cleanup and state management.
7
+ *
8
+ * Max lines: 150 (enforced for maintainability)
9
+ */
10
+
11
+ import type { User } from 'firebase/auth';
12
+ import type { Result } from '../../../shared/domain/utils';
13
+ import type { IAuthPort } from '../ports/AuthPort';
14
+
15
+ /**
16
+ * Sign out use case result
17
+ */
18
+ export interface SignOutUseCaseResult extends Result<void> {
19
+ readonly wasSignedIn: boolean;
20
+ }
21
+
22
+ /**
23
+ * Sign out use case options
24
+ */
25
+ export interface SignOutOptions {
26
+ /** Clear local data */
27
+ readonly clearLocalData?: boolean;
28
+ /** Navigate to sign in screen */
29
+ readonly navigateToSignIn?: boolean;
30
+ /** Show confirmation dialog */
31
+ readonly showConfirmation?: boolean;
32
+ }
33
+
34
+ /**
35
+ * Sign out use case
36
+ * Handles user sign out with proper cleanup
37
+ */
38
+ export class SignOutUseCase {
39
+ private readonly authPort: IAuthPort;
40
+
41
+ constructor(authPort: IAuthPort) {
42
+ this.authPort = authPort;
43
+ }
44
+
45
+ /**
46
+ * Execute sign out use case
47
+ * Signs out user and performs cleanup
48
+ */
49
+ async execute(options: SignOutOptions = {}): Promise<SignOutUseCaseResult> {
50
+ const wasSignedIn = this.authPort.isAuthenticated();
51
+
52
+ // Check if user is signed in
53
+ if (!wasSignedIn) {
54
+ return {
55
+ success: true,
56
+ wasSignedIn: false,
57
+ };
58
+ }
59
+
60
+ // Sign out from auth
61
+ const result = await this.authPort.signOut();
62
+
63
+ if (!result.success) {
64
+ return {
65
+ success: false,
66
+ error: result.error,
67
+ wasSignedIn,
68
+ };
69
+ }
70
+
71
+ // Perform cleanup
72
+ await this.performCleanup(options);
73
+
74
+ return {
75
+ success: true,
76
+ wasSignedIn,
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Perform cleanup after sign out
82
+ */
83
+ private async performCleanup(options: SignOutOptions): Promise<void> {
84
+ // Clear local data if requested
85
+ if (options.clearLocalData) {
86
+ await this.clearLocalData();
87
+ }
88
+
89
+ // Additional cleanup can be added here
90
+ // For example: clear cache, reset state, etc.
91
+ }
92
+
93
+ /**
94
+ * Clear local data
95
+ * Override in subclass for custom cleanup
96
+ */
97
+ protected async clearLocalData(): Promise<void> {
98
+ // Default implementation does nothing
99
+ // Subclass can override for custom cleanup
100
+ if (__DEV__) {
101
+ console.log('[SignOutUseCase] Clearing local data');
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Check if user is signed in
107
+ */
108
+ isSignedIn(): boolean {
109
+ return this.authPort.isAuthenticated();
110
+ }
111
+
112
+ /**
113
+ * Get current user
114
+ */
115
+ getCurrentUser(): User | null {
116
+ return this.authPort.getCurrentUser();
117
+ }
118
+
119
+ /**
120
+ * Get current user ID
121
+ */
122
+ getCurrentUserId(): string | null {
123
+ return this.authPort.getCurrentUserId();
124
+ }
125
+
126
+ /**
127
+ * Check if user is anonymous
128
+ */
129
+ isAnonymous(): boolean {
130
+ return this.authPort.isAnonymous();
131
+ }
132
+
133
+ /**
134
+ * Confirm sign out
135
+ * Useful for showing confirmation dialog
136
+ */
137
+ async confirmSignOut(): Promise<boolean> {
138
+ // Default implementation always returns true
139
+ // Override in subclass to show confirmation dialog
140
+ return true;
141
+ }
142
+
143
+ /**
144
+ * Validate can sign out
145
+ * Check if sign out is allowed
146
+ */
147
+ async canSignOut(): Promise<Result<void>> {
148
+ if (!this.isSignedIn()) {
149
+ return {
150
+ success: false,
151
+ error: {
152
+ code: 'auth/not-signed-in',
153
+ message: 'No user is currently signed in',
154
+ },
155
+ };
156
+ }
157
+
158
+ // Additional checks can be added here
159
+ // For example: check for unsaved changes, active operations, etc.
160
+
161
+ return { success: true };
162
+ }
163
+
164
+ /**
165
+ * Sign out with confirmation
166
+ * Shows confirmation dialog before signing out
167
+ */
168
+ async signOutWithConfirmation(): Promise<SignOutUseCaseResult> {
169
+ const confirmed = await this.confirmSignOut();
170
+
171
+ if (!confirmed) {
172
+ return {
173
+ success: false,
174
+ error: {
175
+ code: 'auth/sign-out-cancelled',
176
+ message: 'Sign out was cancelled',
177
+ },
178
+ wasSignedIn: this.isSignedIn(),
179
+ };
180
+ }
181
+
182
+ return this.execute();
183
+ }
184
+
185
+ /**
186
+ * Sign out and navigate
187
+ * Signs out and navigates to sign in screen
188
+ */
189
+ async signOutAndNavigate(): Promise<SignOutUseCaseResult> {
190
+ return this.execute({
191
+ clearLocalData: true,
192
+ navigateToSignIn: true,
193
+ });
194
+ }
195
+
196
+ /**
197
+ * Force sign out
198
+ * Signs out even if there are errors
199
+ */
200
+ async forceSignOut(): Promise<void> {
201
+ try {
202
+ await this.execute({
203
+ clearLocalData: true,
204
+ });
205
+ } catch (error) {
206
+ // Ignore errors during force sign out
207
+ if (__DEV__) {
208
+ console.error('[SignOutUseCase] Force sign out error:', error);
209
+ }
210
+ }
211
+
212
+ // Ensure local data is cleared
213
+ await this.clearLocalData();
214
+ }
215
+
216
+ /**
217
+ * Get sign out statistics
218
+ */
219
+ getSignOutStats(): {
220
+ readonly isSignedIn: boolean;
221
+ readonly isAnonymous: boolean;
222
+ readonly hasUserId: boolean;
223
+ } {
224
+ return {
225
+ isSignedIn: this.isSignedIn(),
226
+ isAnonymous: this.isAnonymous(),
227
+ hasUserId: this.getCurrentUserId() !== null,
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Create sign out options
233
+ */
234
+ createOptions(options: Partial<SignOutOptions> = {}): SignOutOptions {
235
+ return {
236
+ clearLocalData: false,
237
+ navigateToSignIn: false,
238
+ showConfirmation: false,
239
+ ...options,
240
+ };
241
+ }
242
+
243
+ /**
244
+ * Quick sign out helper
245
+ */
246
+ async quickSignOut(): Promise<SignOutUseCaseResult> {
247
+ return this.execute();
248
+ }
249
+
250
+ /**
251
+ * Check if confirmation should be shown
252
+ */
253
+ shouldShowConfirmation(): boolean {
254
+ // Default: show confirmation for authenticated users
255
+ return this.isSignedIn() && !this.isAnonymous();
256
+ }
257
+
258
+ /**
259
+ * Get user-friendly sign out message
260
+ */
261
+ getSignOutMessage(): string {
262
+ if (!this.isSignedIn()) {
263
+ return 'You are not signed in';
264
+ }
265
+
266
+ if (this.isAnonymous()) {
267
+ return 'Sign out from guest session?';
268
+ }
269
+
270
+ return 'Are you sure you want to sign out?';
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Factory function to create sign out use case
276
+ */
277
+ export function createSignOutUseCase(authPort: IAuthPort): SignOutUseCase {
278
+ return new SignOutUseCase(authPort);
279
+ }
280
+
281
+ /**
282
+ * Factory function to create sign out use case with default auth port
283
+ */
284
+ export async function createDefaultSignOutUseCase(): Promise<SignOutUseCase> {
285
+ const { createAuthPort } = await import('../ports/AuthPort');
286
+ const authPort = createAuthPort();
287
+ return createSignOutUseCase(authPort);
288
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Auth Use Cases
3
+ * Application layer use cases for authentication
4
+ */
5
+
6
+ export type {
7
+ SignInUseCaseResult,
8
+ SignInOptions,
9
+ } from './SignInUseCase';
10
+
11
+ export {
12
+ SignInUseCase,
13
+ createSignInUseCase,
14
+ createDefaultSignInUseCase,
15
+ } from './SignInUseCase';
16
+
17
+ export type {
18
+ SignOutUseCaseResult,
19
+ SignOutOptions,
20
+ } from './SignOutUseCase';
21
+
22
+ export {
23
+ SignOutUseCase,
24
+ createSignOutUseCase,
25
+ createDefaultSignOutUseCase,
26
+ } from './SignOutUseCase';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Account Deletion Domain Layer
3
+ * Domain-Driven Design (DDD) - Domain Exports
4
+ *
5
+ * Pure domain logic without infrastructure concerns.
6
+ * Exports domain services for account deletion operations.
7
+ */
8
+
9
+ // Domain Services
10
+ export {
11
+ UserValidationService,
12
+ createUserValidationService,
13
+ userValidationService,
14
+ } from './services/UserValidationService';
15
+ export type { UserValidationResult } from './services/UserValidationService';
@@ -0,0 +1,295 @@
1
+ /**
2
+ * User Validation Service
3
+ * Single Responsibility: Validate user state for account operations
4
+ *
5
+ * Domain service that encapsulates user validation logic.
6
+ * Moves business logic from infrastructure to domain layer.
7
+ *
8
+ * Max lines: 150 (enforced for maintainability)
9
+ */
10
+
11
+ import type { Auth, User } from 'firebase/auth';
12
+ import type { Result } from '../../../../shared/domain/utils';
13
+ import { successResult, failureResultFrom } from '../../../../shared/domain/utils';
14
+
15
+ /**
16
+ * User validation result
17
+ */
18
+ export interface UserValidationResult {
19
+ readonly valid: boolean;
20
+ readonly error?: { code: string; message: string };
21
+ readonly userId?: string;
22
+ }
23
+
24
+ /**
25
+ * User validation service
26
+ * Provides user validation functionality for account operations
27
+ */
28
+ export class UserValidationService {
29
+ /**
30
+ * Validate user is ready for deletion
31
+ * Checks user exists, not anonymous, and has required provider
32
+ */
33
+ validateForDeletion(user: User | null): Result<{ userId: string; provider: string }> {
34
+ if (!user) {
35
+ return failureResultFrom('auth/not-ready', 'No authenticated user');
36
+ }
37
+
38
+ if (user.isAnonymous) {
39
+ return failureResultFrom('auth/anonymous', 'Cannot delete anonymous account');
40
+ }
41
+
42
+ const provider = this.getUserAuthProvider(user);
43
+ if (!provider) {
44
+ return failureResultFrom('auth/unsupported', 'Unsupported auth provider');
45
+ }
46
+
47
+ return successResult({
48
+ userId: user.uid,
49
+ provider,
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Validate user hasn't changed during operation
55
+ * Critical for preventing race conditions
56
+ */
57
+ validateUserUnchanged(auth: Auth | null, originalUserId: string): Result<void> {
58
+ if (!auth) {
59
+ return failureResultFrom('auth/not-ready', 'Auth not initialized');
60
+ }
61
+
62
+ const currentUserId = auth.currentUser?.uid;
63
+
64
+ if (!currentUserId) {
65
+ return failureResultFrom('auth/user-signed-out', 'User signed out during operation');
66
+ }
67
+
68
+ if (currentUserId !== originalUserId) {
69
+ return failureResultFrom('auth/user-changed', 'User changed during operation');
70
+ }
71
+
72
+ return successResult();
73
+ }
74
+
75
+ /**
76
+ * Validate user credentials are present
77
+ */
78
+ validateCredentials(
79
+ user: User,
80
+ options: {
81
+ password?: string;
82
+ googleIdToken?: string;
83
+ }
84
+ ): Result<void> {
85
+ const provider = this.getUserAuthProvider(user);
86
+
87
+ if (provider === 'password' && !options.password) {
88
+ return failureResultFrom('auth/password-required', 'Password required for reauthentication');
89
+ }
90
+
91
+ if (provider === 'google.com' && !options.googleIdToken) {
92
+ return failureResultFrom('auth/google-token-required', 'Google ID token required for reauthentication');
93
+ }
94
+
95
+ return successResult();
96
+ }
97
+
98
+ /**
99
+ * Get user's auth provider
100
+ * Returns provider ID or null if unknown
101
+ */
102
+ getUserAuthProvider(user: User): string | null {
103
+ if (!user.providerData || user.providerData.length === 0) {
104
+ return null;
105
+ }
106
+
107
+ // Check all providers
108
+ for (const userInfo of user.providerData) {
109
+ if (userInfo.providerId) {
110
+ return userInfo.providerId;
111
+ }
112
+ }
113
+
114
+ return null;
115
+ }
116
+
117
+ /**
118
+ * Check if user has specific provider
119
+ */
120
+ hasProvider(user: User, providerId: string): boolean {
121
+ if (!user.providerData || user.providerData.length === 0) {
122
+ return false;
123
+ }
124
+
125
+ return user.providerData.some(
126
+ userInfo => userInfo.providerId === providerId
127
+ );
128
+ }
129
+
130
+ /**
131
+ * Check if user is email/password user
132
+ */
133
+ isEmailPasswordUser(user: User): boolean {
134
+ return this.hasProvider(user, 'password');
135
+ }
136
+
137
+ /**
138
+ * Check if user is Google user
139
+ */
140
+ isGoogleUser(user: User): boolean {
141
+ return this.hasProvider(user, 'google.com');
142
+ }
143
+
144
+ /**
145
+ * Check if user is Apple user
146
+ */
147
+ isAppleUser(user: User): boolean {
148
+ return this.hasProvider(user, 'apple.com');
149
+ }
150
+
151
+ /**
152
+ * Check if user requires reauthentication
153
+ * Based on provider and operation type
154
+ */
155
+ requiresReauthentication(user: User, operation: 'delete' | 'update'): boolean {
156
+ // Email/password users always need recent auth
157
+ if (this.isEmailPasswordUser(user)) {
158
+ return true;
159
+ }
160
+
161
+ // Social providers may require recent auth for sensitive operations
162
+ if (operation === 'delete') {
163
+ return true;
164
+ }
165
+
166
+ return false;
167
+ }
168
+
169
+ /**
170
+ * Validate user email
171
+ */
172
+ validateEmail(user: User): Result<void> {
173
+ const email = user.email;
174
+
175
+ if (!email) {
176
+ return failureResultFrom('auth/no-email', 'User has no email');
177
+ }
178
+
179
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
180
+ if (!emailRegex.test(email)) {
181
+ return failureResultFrom('auth/invalid-email', 'Invalid email format');
182
+ }
183
+
184
+ return successResult();
185
+ }
186
+
187
+ /**
188
+ * Validate user is verified (if applicable)
189
+ */
190
+ validateVerified(user: User, requireVerification: boolean = false): Result<void> {
191
+ if (requireVerification && !user.emailVerified) {
192
+ return failureResultFrom('auth/unverified', 'Email not verified');
193
+ }
194
+
195
+ return successResult();
196
+ }
197
+
198
+ /**
199
+ * Get user metadata
200
+ */
201
+ getUserMetadata(user: User): {
202
+ readonly createdAt: number | null;
203
+ readonly lastSignInAt: number | null;
204
+ } {
205
+ return {
206
+ createdAt: user.metadata.creationTime ? new Date(user.metadata.creationTime).getTime() : null,
207
+ lastSignInAt: user.metadata.lastSignInTime ? new Date(user.metadata.lastSignInTime).getTime() : null,
208
+ };
209
+ }
210
+
211
+ /**
212
+ * Check if account is new (created recently)
213
+ */
214
+ isAccountNew(user: User, maxAgeMs: number = 24 * 60 * 60 * 1000): boolean {
215
+ const metadata = this.getUserMetadata(user);
216
+ if (!metadata.createdAt) return false;
217
+
218
+ const age = Date.now() - metadata.createdAt;
219
+ return age <= maxAgeMs;
220
+ }
221
+
222
+ /**
223
+ * Check if user recently signed in
224
+ */
225
+ isRecentSignIn(user: User, maxAgeMs: number = 5 * 60 * 1000): boolean {
226
+ const metadata = this.getUserMetadata(user);
227
+ if (!metadata.lastSignInAt) return false;
228
+
229
+ const timeSinceSignIn = Date.now() - metadata.lastSignInAt;
230
+ return timeSinceSignIn <= maxAgeMs;
231
+ }
232
+
233
+ /**
234
+ * Validate user can perform operation
235
+ * Comprehensive check combining multiple validations
236
+ */
237
+ validateCanPerformOperation(
238
+ user: User | null,
239
+ operation: 'delete' | 'update',
240
+ options: {
241
+ requireVerified?: boolean;
242
+ maxSignInAge?: number;
243
+ password?: string;
244
+ googleIdToken?: string;
245
+ } = {}
246
+ ): Result<{ userId: string; provider: string }> {
247
+ // Validate user ready for operation
248
+ const deletionValidation = this.validateForDeletion(user);
249
+ if (!deletionValidation.success) {
250
+ return deletionValidation;
251
+ }
252
+
253
+ const userId = deletionValidation.data!.userId;
254
+ const provider = deletionValidation.data!.provider;
255
+
256
+ // Validate email
257
+ if (user) {
258
+ const emailValidation = this.validateEmail(user);
259
+ if (!emailValidation.success) {
260
+ return emailValidation;
261
+ }
262
+
263
+ // Validate verification status
264
+ const verifiedValidation = this.validateVerified(user, options.requireVerified);
265
+ if (!verifiedValidation.success) {
266
+ return verifiedValidation;
267
+ }
268
+
269
+ // Check if recent sign-in required
270
+ if (options.maxSignInAge && !this.isRecentSignIn(user, options.maxSignInAge)) {
271
+ return failureResultFrom('auth/stale-session', 'Session too old, please sign in again');
272
+ }
273
+
274
+ // Validate credentials
275
+ const credentialsValidation = this.validateCredentials(user, options);
276
+ if (!credentialsValidation.success) {
277
+ return credentialsValidation;
278
+ }
279
+ }
280
+
281
+ return successResult({ userId, provider });
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Factory function to create user validation service
287
+ */
288
+ export function createUserValidationService(): UserValidationService {
289
+ return new UserValidationService();
290
+ }
291
+
292
+ /**
293
+ * Default instance for convenience
294
+ */
295
+ export const userValidationService = createUserValidationService();
@@ -1,16 +1,24 @@
1
1
  /**
2
2
  * Account Deletion Domain
3
3
  * Handles Firebase account deletion with reauthentication
4
+ *
5
+ * Domain-Driven Design (DDD) Architecture
4
6
  */
5
7
 
8
+ // =============================================================================
9
+ // DOMAIN LAYER - Business Logic
10
+ // =============================================================================
11
+
6
12
  export {
7
- deleteCurrentUser,
8
- deleteUserAccount,
9
- } from './infrastructure/services/account-deletion.service';
13
+ UserValidationService,
14
+ createUserValidationService,
15
+ userValidationService,
16
+ } from './domain';
17
+ export type { UserValidationResult } from './domain';
10
18
 
11
- export type {
12
- AccountDeletionResult,
13
- } from './infrastructure/services/account-deletion.service';
19
+ // =============================================================================
20
+ // APPLICATION LAYER - Use Cases & Ports
21
+ // =============================================================================
14
22
 
15
23
  export type {
16
24
  AccountDeletionOptions,
@@ -19,6 +27,35 @@ export type {
19
27
  ReauthCredentialResult,
20
28
  } from './application/ports/reauthentication.types';
21
29
 
30
+ // =============================================================================
31
+ // INFRASTRUCTURE LAYER - Implementation
32
+ // =============================================================================
33
+
34
+ // Main Service (Refactored)
35
+ export {
36
+ deleteCurrentUser,
37
+ deleteUserAccount,
38
+ isDeletionInProgress,
39
+ } from './infrastructure/services/account-deletion.service';
40
+
41
+ export type {
42
+ AccountDeletionResult,
43
+ } from './infrastructure/services/account-deletion.service';
44
+
45
+ // Deletion Components
46
+ export {
47
+ AccountDeletionRepository,
48
+ createAccountDeletionRepository,
49
+ accountDeletionRepository,
50
+ } from './infrastructure/services/AccountDeletionRepository';
51
+
52
+ export {
53
+ AccountDeletionExecutor,
54
+ createAccountDeletionExecutor,
55
+ accountDeletionExecutor,
56
+ } from './infrastructure/services/AccountDeletionExecutor';
57
+
58
+ // Reauthentication Service
22
59
  export {
23
60
  getUserAuthProvider,
24
61
  reauthenticateWithPassword,