@umituz/react-native-firebase 1.13.140 → 1.13.142
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 -1
- package/src/auth/infrastructure/config/FirebaseAuthClient.ts +11 -2
- package/src/auth/infrastructure/services/account-deletion.service.ts +40 -20
- package/src/auth/infrastructure/services/anonymous-auth.service.ts +7 -11
- package/src/auth/infrastructure/services/apple-auth.service.ts +44 -18
- package/src/auth/infrastructure/services/base/base-auth.service.ts +9 -40
- package/src/auth/infrastructure/services/firestore-utils.service.ts +2 -2
- package/src/auth/infrastructure/services/google-auth.service.ts +27 -23
- package/src/auth/infrastructure/services/password.service.ts +6 -21
- package/src/auth/infrastructure/services/reauthentication.service.ts +19 -29
- package/src/auth/presentation/hooks/shared/hook-utils.util.ts +222 -0
- package/src/auth/presentation/hooks/useSocialAuth.ts +10 -1
- package/src/domain/utils/async-executor.util.ts +176 -0
- package/src/domain/utils/credential.util.ts +102 -0
- package/src/domain/utils/index.ts +101 -0
- package/src/domain/utils/result.util.ts +129 -0
- package/src/domain/utils/service-config.util.ts +99 -0
- package/src/domain/utils/validation.util.ts +78 -0
- package/src/firestore/infrastructure/middleware/QueryDeduplicationMiddleware.ts +3 -5
- package/src/firestore/infrastructure/repositories/BaseQueryRepository.ts +3 -3
- package/src/firestore/utils/dateUtils.ts +21 -5
- package/src/firestore/utils/deduplication/pending-query-manager.util.ts +3 -7
- package/src/firestore/utils/deduplication/query-key-generator.util.ts +12 -3
- package/src/firestore/utils/deduplication/timer-manager.util.ts +8 -2
- package/src/infrastructure/config/FirebaseClient.ts +36 -4
- package/src/init/createFirebaseInitModule.ts +18 -3
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.142",
|
|
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",
|
|
@@ -52,8 +52,17 @@ class FirebaseAuthClientSingleton extends ServiceClientSingleton<Auth, FirebaseA
|
|
|
52
52
|
getAuth(): Auth | null {
|
|
53
53
|
// Attempt initialization if not already initialized
|
|
54
54
|
if (!this.isInitialized() && !this.getInitializationError()) {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
try {
|
|
56
|
+
const app = getFirebaseApp();
|
|
57
|
+
if (app) {
|
|
58
|
+
this.initialize();
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
// Silently handle auto-initialization errors
|
|
62
|
+
// The error will be stored in state for later retrieval
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : 'Auto-initialization failed';
|
|
64
|
+
this.setError(errorMessage);
|
|
65
|
+
}
|
|
57
66
|
}
|
|
58
67
|
return this.getInstance();
|
|
59
68
|
}
|
|
@@ -11,10 +11,14 @@ import {
|
|
|
11
11
|
reauthenticateWithPassword,
|
|
12
12
|
reauthenticateWithGoogle,
|
|
13
13
|
} from "./reauthentication.service";
|
|
14
|
-
import {
|
|
15
|
-
import type {
|
|
14
|
+
import { successResult, type Result } from "../../../domain/utils";
|
|
15
|
+
import type { AccountDeletionOptions } from "./reauthentication.types";
|
|
16
16
|
|
|
17
|
-
export
|
|
17
|
+
export interface AccountDeletionResult extends Result<void> {
|
|
18
|
+
requiresReauth?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type { AccountDeletionOptions } from "./reauthentication.types";
|
|
18
22
|
|
|
19
23
|
export async function deleteCurrentUser(
|
|
20
24
|
options: AccountDeletionOptions = { autoReauthenticate: true }
|
|
@@ -25,29 +29,36 @@ export async function deleteCurrentUser(
|
|
|
25
29
|
if (!auth || !user) {
|
|
26
30
|
return {
|
|
27
31
|
success: false,
|
|
28
|
-
error: { code: "auth/not-ready", message: "Auth not ready"
|
|
32
|
+
error: { code: "auth/not-ready", message: "Auth not ready" },
|
|
33
|
+
requiresReauth: false
|
|
29
34
|
};
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
if (user.isAnonymous) {
|
|
33
38
|
return {
|
|
34
39
|
success: false,
|
|
35
|
-
error: { code: "auth/anonymous", message: "Cannot delete anonymous"
|
|
40
|
+
error: { code: "auth/anonymous", message: "Cannot delete anonymous" },
|
|
41
|
+
requiresReauth: false
|
|
36
42
|
};
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
try {
|
|
40
46
|
await deleteUser(user);
|
|
41
|
-
return
|
|
47
|
+
return successResult();
|
|
42
48
|
} catch (error: unknown) {
|
|
43
|
-
const authErr =
|
|
44
|
-
|
|
49
|
+
const authErr = error instanceof Error ? (error as { code?: string; message?: string }) : null;
|
|
50
|
+
const code = authErr?.code ?? "auth/failed";
|
|
51
|
+
const message = authErr?.message ?? "Account deletion failed";
|
|
52
|
+
|
|
53
|
+
if (code === "auth/requires-recent-login" && (options.autoReauthenticate || options.password || options.googleIdToken)) {
|
|
45
54
|
const reauth = await attemptReauth(user, options);
|
|
46
55
|
if (reauth) return reauth;
|
|
47
56
|
}
|
|
57
|
+
|
|
48
58
|
return {
|
|
49
59
|
success: false,
|
|
50
|
-
error: {
|
|
60
|
+
error: { code, message },
|
|
61
|
+
requiresReauth: code === "auth/requires-recent-login"
|
|
51
62
|
};
|
|
52
63
|
}
|
|
53
64
|
}
|
|
@@ -62,7 +73,8 @@ async function attemptReauth(user: User, options: AccountDeletionOptions): Promi
|
|
|
62
73
|
if (!options.googleIdToken) {
|
|
63
74
|
return {
|
|
64
75
|
success: false,
|
|
65
|
-
error: { code: "auth/google-reauth", message: "Google reauth required"
|
|
76
|
+
error: { code: "auth/google-reauth", message: "Google reauth required" },
|
|
77
|
+
requiresReauth: true
|
|
66
78
|
};
|
|
67
79
|
}
|
|
68
80
|
res = await reauthenticateWithGoogle(user, options.googleIdToken);
|
|
@@ -70,7 +82,8 @@ async function attemptReauth(user: User, options: AccountDeletionOptions): Promi
|
|
|
70
82
|
if (!options.password) {
|
|
71
83
|
return {
|
|
72
84
|
success: false,
|
|
73
|
-
error: { code: "auth/password-reauth", message: "Password required"
|
|
85
|
+
error: { code: "auth/password-reauth", message: "Password required" },
|
|
86
|
+
requiresReauth: true
|
|
74
87
|
};
|
|
75
88
|
}
|
|
76
89
|
res = await reauthenticateWithPassword(user, options.password);
|
|
@@ -81,10 +94,14 @@ async function attemptReauth(user: User, options: AccountDeletionOptions): Promi
|
|
|
81
94
|
if (res.success) {
|
|
82
95
|
try {
|
|
83
96
|
await deleteUser(user);
|
|
84
|
-
return
|
|
97
|
+
return successResult();
|
|
85
98
|
} catch (err: unknown) {
|
|
86
|
-
const authErr =
|
|
87
|
-
return {
|
|
99
|
+
const authErr = err instanceof Error ? (err as { code?: string; message?: string }) : null;
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
error: { code: authErr?.code ?? "auth/failed", message: authErr?.message ?? "Deletion failed" },
|
|
103
|
+
requiresReauth: false
|
|
104
|
+
};
|
|
88
105
|
}
|
|
89
106
|
}
|
|
90
107
|
|
|
@@ -93,8 +110,8 @@ async function attemptReauth(user: User, options: AccountDeletionOptions): Promi
|
|
|
93
110
|
error: {
|
|
94
111
|
code: res.error?.code || "auth/reauth-failed",
|
|
95
112
|
message: res.error?.message || "Reauth failed",
|
|
96
|
-
|
|
97
|
-
|
|
113
|
+
},
|
|
114
|
+
requiresReauth: true
|
|
98
115
|
};
|
|
99
116
|
}
|
|
100
117
|
|
|
@@ -102,18 +119,21 @@ export async function deleteUserAccount(user: User | null): Promise<AccountDelet
|
|
|
102
119
|
if (!user || user.isAnonymous) {
|
|
103
120
|
return {
|
|
104
121
|
success: false,
|
|
105
|
-
error: { code: "auth/invalid", message: "Invalid user"
|
|
122
|
+
error: { code: "auth/invalid", message: "Invalid user" },
|
|
123
|
+
requiresReauth: false
|
|
106
124
|
};
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
try {
|
|
110
128
|
await deleteUser(user);
|
|
111
|
-
return
|
|
129
|
+
return successResult();
|
|
112
130
|
} catch (error: unknown) {
|
|
113
|
-
const authErr =
|
|
131
|
+
const authErr = error instanceof Error ? (error as { code?: string; message?: string }) : null;
|
|
132
|
+
const code = authErr?.code ?? "auth/failed";
|
|
114
133
|
return {
|
|
115
134
|
success: false,
|
|
116
|
-
error: {
|
|
135
|
+
error: { code, message: authErr?.message ?? "Deletion failed" },
|
|
136
|
+
requiresReauth: code === "auth/requires-recent-login"
|
|
117
137
|
};
|
|
118
138
|
}
|
|
119
139
|
}
|
|
@@ -34,17 +34,13 @@ export class AnonymousAuthService implements AnonymousAuthServiceInterface {
|
|
|
34
34
|
throw new Error("A non-anonymous user is already signed in. Sign out first before creating an anonymous session.");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
45
|
-
} catch (error) {
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
37
|
+
const userCredential = await signInAnonymously(auth);
|
|
38
|
+
const anonymousUser = toAnonymousUser(userCredential.user);
|
|
39
|
+
return {
|
|
40
|
+
user: userCredential.user,
|
|
41
|
+
anonymousUser,
|
|
42
|
+
wasAlreadySignedIn: false,
|
|
43
|
+
};
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
46
|
|
|
@@ -13,10 +13,9 @@ import { Platform } from "react-native";
|
|
|
13
13
|
import { generateNonce, hashNonce } from "./crypto.util";
|
|
14
14
|
import type { AppleAuthResult } from "./apple-auth.types";
|
|
15
15
|
import {
|
|
16
|
-
createSuccessResult,
|
|
17
|
-
createFailureResult,
|
|
18
16
|
isCancellationError,
|
|
19
17
|
} from "./base/base-auth.service";
|
|
18
|
+
import { executeAuthOperation, type Result } from "../../../domain/utils";
|
|
20
19
|
|
|
21
20
|
export class AppleAuthService {
|
|
22
21
|
async isAvailable(): Promise<boolean> {
|
|
@@ -28,17 +27,32 @@ export class AppleAuthService {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
|
|
30
|
+
private convertToAppleAuthResult(result: Result<{ userCredential: any; isNewUser: boolean }>): AppleAuthResult {
|
|
31
|
+
if (result.success && result.data) {
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
userCredential: result.data.userCredential,
|
|
35
|
+
isNewUser: result.data.isNewUser,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: result.error?.message ?? "Apple sign-in failed",
|
|
41
|
+
code: result.error?.code,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
async signIn(auth: Auth): Promise<AppleAuthResult> {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
46
|
+
const isAvailable = await this.isAvailable();
|
|
47
|
+
if (!isAvailable) {
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
error: "Apple Sign-In is not available on this device",
|
|
51
|
+
code: "unavailable"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
41
54
|
|
|
55
|
+
const result = await executeAuthOperation(async () => {
|
|
42
56
|
const nonce = await generateNonce();
|
|
43
57
|
const hashedNonce = await hashNonce(nonce);
|
|
44
58
|
|
|
@@ -51,11 +65,7 @@ export class AppleAuthService {
|
|
|
51
65
|
});
|
|
52
66
|
|
|
53
67
|
if (!appleCredential.identityToken) {
|
|
54
|
-
|
|
55
|
-
success: false,
|
|
56
|
-
error: "No identity token received",
|
|
57
|
-
code: "no_token"
|
|
58
|
-
};
|
|
68
|
+
throw new Error("No identity token received");
|
|
59
69
|
}
|
|
60
70
|
|
|
61
71
|
const provider = new OAuthProvider("apple.com");
|
|
@@ -65,7 +75,22 @@ export class AppleAuthService {
|
|
|
65
75
|
});
|
|
66
76
|
|
|
67
77
|
const userCredential = await signInWithCredential(auth, credential);
|
|
68
|
-
return
|
|
78
|
+
return {
|
|
79
|
+
userCredential,
|
|
80
|
+
isNewUser: userCredential.user.metadata.creationTime ===
|
|
81
|
+
userCredential.user.metadata.lastSignInTime
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return this.convertToAppleAuthResult(result);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Sign in with error handling for cancellation
|
|
90
|
+
*/
|
|
91
|
+
async signInWithCancellationHandling(auth: Auth): Promise<AppleAuthResult> {
|
|
92
|
+
try {
|
|
93
|
+
return await this.signIn(auth);
|
|
69
94
|
} catch (error) {
|
|
70
95
|
if (isCancellationError(error)) {
|
|
71
96
|
return {
|
|
@@ -75,7 +100,8 @@ export class AppleAuthService {
|
|
|
75
100
|
};
|
|
76
101
|
}
|
|
77
102
|
|
|
78
|
-
|
|
103
|
+
// Re-throw for executeAuthOperation to handle
|
|
104
|
+
throw error;
|
|
79
105
|
}
|
|
80
106
|
}
|
|
81
107
|
|
|
@@ -6,39 +6,20 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { UserCredential } from 'firebase/auth';
|
|
9
|
-
import {
|
|
9
|
+
import { authErrorConverter, type Result } from '../../../../domain/utils';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Authentication result with user credential
|
|
13
13
|
*/
|
|
14
|
-
export interface
|
|
15
|
-
readonly success: boolean;
|
|
16
|
-
readonly error?: string;
|
|
17
|
-
readonly code?: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Successful authentication result
|
|
22
|
-
*/
|
|
23
|
-
export interface AuthSuccessResult extends BaseAuthResult {
|
|
24
|
-
readonly success: true;
|
|
14
|
+
export interface AuthSuccessData {
|
|
25
15
|
readonly userCredential: UserCredential;
|
|
26
16
|
readonly isNewUser: boolean;
|
|
27
17
|
}
|
|
28
18
|
|
|
29
19
|
/**
|
|
30
|
-
*
|
|
31
|
-
*/
|
|
32
|
-
export interface AuthFailureResult extends BaseAuthResult {
|
|
33
|
-
readonly success: false;
|
|
34
|
-
readonly error: string;
|
|
35
|
-
readonly code: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Combined auth result type
|
|
20
|
+
* Auth result type that extends the base Result
|
|
40
21
|
*/
|
|
41
|
-
export type AuthResult =
|
|
22
|
+
export type AuthResult = Result<AuthSuccessData>;
|
|
42
23
|
|
|
43
24
|
/**
|
|
44
25
|
* Check if user is new based on metadata
|
|
@@ -50,17 +31,6 @@ export function checkIsNewUser(userCredential: UserCredential): boolean {
|
|
|
50
31
|
);
|
|
51
32
|
}
|
|
52
33
|
|
|
53
|
-
/**
|
|
54
|
-
* Extract error information from unknown error
|
|
55
|
-
*/
|
|
56
|
-
export function extractAuthError(error: unknown): { code: string; message: string } {
|
|
57
|
-
const errorInfo = toAuthErrorInfo(error);
|
|
58
|
-
return {
|
|
59
|
-
code: errorInfo.code,
|
|
60
|
-
message: errorInfo.message,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
34
|
/**
|
|
65
35
|
* Check if error is a cancellation error
|
|
66
36
|
*/
|
|
@@ -74,19 +44,18 @@ export function isCancellationError(error: unknown): boolean {
|
|
|
74
44
|
/**
|
|
75
45
|
* Create failure result from error
|
|
76
46
|
*/
|
|
77
|
-
export function createFailureResult(error: unknown):
|
|
78
|
-
const
|
|
47
|
+
export function createFailureResult(error: unknown): { success: false; error: { code: string; message: string } } {
|
|
48
|
+
const errorInfo = authErrorConverter(error);
|
|
79
49
|
return {
|
|
80
50
|
success: false,
|
|
81
|
-
error:
|
|
82
|
-
code,
|
|
51
|
+
error: errorInfo,
|
|
83
52
|
};
|
|
84
53
|
}
|
|
85
54
|
|
|
86
55
|
/**
|
|
87
56
|
* Create success result from user credential
|
|
88
57
|
*/
|
|
89
|
-
export function createSuccessResult(userCredential: UserCredential):
|
|
58
|
+
export function createSuccessResult(userCredential: UserCredential): { success: true; userCredential: UserCredential; isNewUser: boolean } {
|
|
90
59
|
return {
|
|
91
60
|
success: true,
|
|
92
61
|
userCredential,
|
|
@@ -55,7 +55,7 @@ export function shouldSkipFirestoreQuery(
|
|
|
55
55
|
const {
|
|
56
56
|
skipForGuest = true,
|
|
57
57
|
skipIfNotAuthenticated = true,
|
|
58
|
-
verifyUserId:
|
|
58
|
+
verifyUserId: shouldVerifyUserId = true,
|
|
59
59
|
userId,
|
|
60
60
|
} = options;
|
|
61
61
|
|
|
@@ -80,7 +80,7 @@ export function shouldSkipFirestoreQuery(
|
|
|
80
80
|
return createResult(true, authState, "is_guest");
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
if (
|
|
83
|
+
if (shouldVerifyUserId && userId && !verifyUserId(auth, userId)) {
|
|
84
84
|
return createResult(true, authState, "user_id_mismatch");
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -9,46 +9,50 @@ import {
|
|
|
9
9
|
type Auth,
|
|
10
10
|
} from "firebase/auth";
|
|
11
11
|
import type { GoogleAuthConfig, GoogleAuthResult } from "./google-auth.types";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
createFailureResult,
|
|
15
|
-
} from "./base/base-auth.service";
|
|
12
|
+
import { executeAuthOperation, type Result } from "../../../domain/utils";
|
|
13
|
+
import { ConfigurableService } from "../../../domain/utils/service-config.util";
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
16
|
* Google Auth Service
|
|
19
17
|
* Provides Google Sign-In functionality for Firebase
|
|
20
18
|
*/
|
|
21
|
-
export class GoogleAuthService {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
configure(config: GoogleAuthConfig): void {
|
|
25
|
-
this.config = config;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
isConfigured(): boolean {
|
|
19
|
+
export class GoogleAuthService extends ConfigurableService<GoogleAuthConfig> {
|
|
20
|
+
protected isValidConfig(config: GoogleAuthConfig): boolean {
|
|
29
21
|
return (
|
|
30
|
-
|
|
31
|
-
(!!
|
|
32
|
-
!!this.config.iosClientId ||
|
|
33
|
-
!!this.config.androidClientId)
|
|
22
|
+
config !== null &&
|
|
23
|
+
(!!config.webClientId || !!config.iosClientId || !!config.androidClientId)
|
|
34
24
|
);
|
|
35
25
|
}
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
private convertToGoogleAuthResult(result: Result<{ userCredential: any; isNewUser: boolean }>): GoogleAuthResult {
|
|
28
|
+
if (result.success && result.data) {
|
|
29
|
+
return {
|
|
30
|
+
success: true,
|
|
31
|
+
userCredential: result.data.userCredential,
|
|
32
|
+
isNewUser: result.data.isNewUser,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
error: result.error?.message ?? "Google sign-in failed",
|
|
38
|
+
code: result.error?.code,
|
|
39
|
+
};
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
async signInWithIdToken(
|
|
42
43
|
auth: Auth,
|
|
43
44
|
idToken: string,
|
|
44
45
|
): Promise<GoogleAuthResult> {
|
|
45
|
-
|
|
46
|
+
const result = await executeAuthOperation(async () => {
|
|
46
47
|
const credential = GoogleAuthProvider.credential(idToken);
|
|
47
48
|
const userCredential = await signInWithCredential(auth, credential);
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
return {
|
|
50
|
+
userCredential,
|
|
51
|
+
isNewUser: userCredential.user.metadata.creationTime ===
|
|
52
|
+
userCredential.user.metadata.lastSignInTime
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
return this.convertToGoogleAuthResult(result);
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
|
|
@@ -4,35 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { updatePassword, type User } from 'firebase/auth';
|
|
7
|
-
import {
|
|
7
|
+
import { executeAuthOperation, type Result } from '../../../domain/utils';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Result of a password update operation
|
|
11
|
+
* @deprecated Use Result<void> instead
|
|
11
12
|
*/
|
|
12
|
-
export
|
|
13
|
-
success: boolean;
|
|
14
|
-
error?: {
|
|
15
|
-
code: string;
|
|
16
|
-
message: string;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
13
|
+
export type PasswordUpdateResult = Result<void>;
|
|
19
14
|
|
|
20
15
|
/**
|
|
21
16
|
* Update the current user's password
|
|
22
17
|
* Note: Requires recent authentication. Re-authenticate before calling if needed.
|
|
23
18
|
*/
|
|
24
|
-
export async function updateUserPassword(user: User, newPassword: string): Promise<
|
|
25
|
-
|
|
19
|
+
export async function updateUserPassword(user: User, newPassword: string): Promise<Result<void>> {
|
|
20
|
+
return executeAuthOperation(async () => {
|
|
26
21
|
await updatePassword(user, newPassword);
|
|
27
|
-
|
|
28
|
-
} catch (error: unknown) {
|
|
29
|
-
const errorInfo = toAuthErrorInfo(error);
|
|
30
|
-
return {
|
|
31
|
-
success: false,
|
|
32
|
-
error: {
|
|
33
|
-
code: errorInfo.code,
|
|
34
|
-
message: errorInfo.message,
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
22
|
+
});
|
|
38
23
|
}
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
import * as AppleAuthentication from "expo-apple-authentication";
|
|
14
14
|
import { Platform } from "react-native";
|
|
15
15
|
import { generateNonce, hashNonce } from "./crypto.util";
|
|
16
|
-
import {
|
|
16
|
+
import { executeOperation, failureResultFrom } from "../../../domain/utils";
|
|
17
|
+
import { isCancelledError } from "../../../domain/utils/error-handler.util";
|
|
17
18
|
import type {
|
|
18
19
|
ReauthenticationResult,
|
|
19
20
|
AuthProviderType,
|
|
@@ -37,30 +38,20 @@ export function getUserAuthProvider(user: User): AuthProviderType {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export async function reauthenticateWithGoogle(user: User, idToken: string): Promise<ReauthenticationResult> {
|
|
40
|
-
|
|
41
|
+
return executeOperation(async () => {
|
|
41
42
|
await reauthenticateWithCredential(user, GoogleAuthProvider.credential(idToken));
|
|
42
|
-
|
|
43
|
-
} catch (error: unknown) {
|
|
44
|
-
const err = toAuthErrorInfo(error);
|
|
45
|
-
return { success: false, error: err };
|
|
46
|
-
}
|
|
43
|
+
});
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
export async function reauthenticateWithPassword(user: User, pass: string): Promise<ReauthenticationResult> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
error: { code: "auth/no-email", message: "User has no email" }
|
|
54
|
-
};
|
|
47
|
+
const email = user.email;
|
|
48
|
+
if (!email) {
|
|
49
|
+
return failureResultFrom("auth/no-email", "User has no email");
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
|
|
58
|
-
await reauthenticateWithCredential(user, EmailAuthProvider.credential(
|
|
59
|
-
|
|
60
|
-
} catch (error: unknown) {
|
|
61
|
-
const err = toAuthErrorInfo(error);
|
|
62
|
-
return { success: false, error: err };
|
|
63
|
-
}
|
|
52
|
+
return executeOperation(async () => {
|
|
53
|
+
await reauthenticateWithCredential(user, EmailAuthProvider.credential(email, pass));
|
|
54
|
+
});
|
|
64
55
|
}
|
|
65
56
|
|
|
66
57
|
export async function getAppleReauthCredential(): Promise<ReauthCredentialResult> {
|
|
@@ -107,8 +98,8 @@ export async function getAppleReauthCredential(): Promise<ReauthCredentialResult
|
|
|
107
98
|
credential
|
|
108
99
|
};
|
|
109
100
|
} catch (error: unknown) {
|
|
110
|
-
const err =
|
|
111
|
-
const code = isCancelledError(err) ? "auth/cancelled" :
|
|
101
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
102
|
+
const code = isCancelledError({ code: '', message: err.message }) ? "auth/cancelled" : "auth/failed";
|
|
112
103
|
return {
|
|
113
104
|
success: false,
|
|
114
105
|
error: { code, message: err.message }
|
|
@@ -118,13 +109,12 @@ export async function getAppleReauthCredential(): Promise<ReauthCredentialResult
|
|
|
118
109
|
|
|
119
110
|
export async function reauthenticateWithApple(user: User): Promise<ReauthenticationResult> {
|
|
120
111
|
const res = await getAppleReauthCredential();
|
|
121
|
-
if (!res.success || !res.credential)
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
await reauthenticateWithCredential(user, res.credential);
|
|
125
|
-
return { success: true };
|
|
126
|
-
} catch (error: unknown) {
|
|
127
|
-
const err = toAuthErrorInfo(error);
|
|
128
|
-
return { success: false, error: err };
|
|
112
|
+
if (!res.success || !res.credential) {
|
|
113
|
+
return { success: false, error: res.error ?? { code: "auth/failed", message: "Failed to get credential" } };
|
|
129
114
|
}
|
|
115
|
+
|
|
116
|
+
const credential = res.credential;
|
|
117
|
+
return executeOperation(async () => {
|
|
118
|
+
await reauthenticateWithCredential(user, credential);
|
|
119
|
+
});
|
|
130
120
|
}
|