react-native-nitro-auth 0.5.4 → 0.5.6
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/README.md +82 -47
- package/android/proguard-rules.pro +7 -1
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/cpp/JniOnLoad.cpp +3 -1
- package/android/src/main/cpp/PlatformAuth+Android.cpp +271 -78
- package/android/src/main/java/com/auth/AuthAdapter.kt +293 -238
- package/android/src/main/java/com/auth/GoogleSignInActivity.kt +9 -5
- package/android/src/main/java/com/auth/NitroAuthModule.kt +8 -1
- package/cpp/HybridAuth.cpp +79 -64
- package/cpp/HybridAuth.hpp +9 -7
- package/cpp/JSONSerializer.hpp +3 -0
- package/ios/AuthAdapter.swift +226 -79
- package/ios/PlatformAuth+iOS.mm +10 -3
- package/lib/commonjs/Auth.web.js +50 -10
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/index.js +23 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +30 -12
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/service.js +36 -9
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js +65 -13
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/ui/social-button.js +19 -14
- package/lib/commonjs/ui/social-button.js.map +1 -1
- package/lib/commonjs/ui/social-button.web.js +16 -10
- package/lib/commonjs/ui/social-button.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +22 -25
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/commonjs/utils/auth-error.js +37 -0
- package/lib/commonjs/utils/auth-error.js.map +1 -0
- package/lib/commonjs/utils/logger.js +1 -0
- package/lib/commonjs/utils/logger.js.map +1 -1
- package/lib/module/Auth.web.js +50 -10
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/global.d.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +2 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/service.js +36 -9
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js +65 -13
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/ui/social-button.js +19 -14
- package/lib/module/ui/social-button.js.map +1 -1
- package/lib/module/ui/social-button.web.js +16 -10
- package/lib/module/ui/social-button.web.js.map +1 -1
- package/lib/module/use-auth.js +22 -25
- package/lib/module/use-auth.js.map +1 -1
- package/lib/module/utils/auth-error.js +30 -0
- package/lib/module/utils/auth-error.js.map +1 -0
- package/lib/module/utils/logger.js +1 -0
- package/lib/module/utils/logger.js.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +5 -1
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +2 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts +2 -18
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts +2 -1
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/auth-error.d.ts +16 -0
- package/lib/typescript/commonjs/utils/auth-error.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/logger.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +5 -1
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +2 -1
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts +2 -18
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts +2 -1
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/utils/auth-error.d.ts +16 -0
- package/lib/typescript/module/utils/auth-error.d.ts.map +1 -0
- package/lib/typescript/module/utils/logger.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroAuthOnLoad.cpp +22 -17
- package/nitrogen/generated/android/NitroAuthOnLoad.hpp +13 -4
- package/package.json +8 -10
- package/src/Auth.web.ts +77 -11
- package/src/global.d.ts +0 -11
- package/src/index.ts +5 -0
- package/src/index.web.ts +6 -1
- package/src/service.ts +37 -9
- package/src/service.web.ts +84 -15
- package/src/ui/social-button.tsx +21 -9
- package/src/ui/social-button.web.tsx +17 -4
- package/src/use-auth.ts +29 -67
- package/src/utils/auth-error.ts +49 -0
- package/src/utils/logger.ts +1 -0
package/src/service.web.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Auth,
|
|
3
|
+
AuthProvider,
|
|
4
|
+
AuthTokens,
|
|
5
|
+
LoginOptions,
|
|
6
|
+
AuthUser,
|
|
7
|
+
} from "./Auth.nitro";
|
|
1
8
|
import { AuthModule } from "./Auth.web";
|
|
9
|
+
import { AuthError } from "./utils/auth-error";
|
|
2
10
|
|
|
3
|
-
export const AuthService = {
|
|
4
|
-
...AuthModule,
|
|
5
|
-
|
|
11
|
+
export const AuthService: Auth = {
|
|
6
12
|
get name() {
|
|
7
13
|
return AuthModule.name;
|
|
8
14
|
},
|
|
@@ -19,16 +25,79 @@ export const AuthService = {
|
|
|
19
25
|
return AuthModule.hasPlayServices;
|
|
20
26
|
},
|
|
21
27
|
|
|
22
|
-
login:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
async login(provider: AuthProvider, options?: LoginOptions) {
|
|
29
|
+
try {
|
|
30
|
+
await AuthModule.login(provider, options);
|
|
31
|
+
return;
|
|
32
|
+
} catch (e) {
|
|
33
|
+
throw AuthError.from(e);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
async requestScopes(scopes: string[]) {
|
|
38
|
+
try {
|
|
39
|
+
await AuthModule.requestScopes(scopes);
|
|
40
|
+
return;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
throw AuthError.from(e);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
async revokeScopes(scopes: string[]) {
|
|
47
|
+
try {
|
|
48
|
+
await AuthModule.revokeScopes(scopes);
|
|
49
|
+
return;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
throw AuthError.from(e);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
async getAccessToken() {
|
|
56
|
+
try {
|
|
57
|
+
return await AuthModule.getAccessToken();
|
|
58
|
+
} catch (e) {
|
|
59
|
+
throw AuthError.from(e);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
async refreshToken() {
|
|
64
|
+
try {
|
|
65
|
+
return await AuthModule.refreshToken();
|
|
66
|
+
} catch (e) {
|
|
67
|
+
throw AuthError.from(e);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
logout() {
|
|
72
|
+
AuthModule.logout();
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
async silentRestore() {
|
|
76
|
+
try {
|
|
77
|
+
await AuthModule.silentRestore();
|
|
78
|
+
return;
|
|
79
|
+
} catch (e) {
|
|
80
|
+
throw AuthError.from(e);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
onAuthStateChanged(callback: (user: AuthUser | undefined) => void) {
|
|
85
|
+
return AuthModule.onAuthStateChanged(callback);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
onTokensRefreshed(callback: (tokens: AuthTokens) => void) {
|
|
89
|
+
return AuthModule.onTokensRefreshed(callback);
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
setLoggingEnabled(enabled: boolean) {
|
|
93
|
+
AuthModule.setLoggingEnabled(enabled);
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
dispose() {
|
|
97
|
+
AuthModule.dispose();
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
equals(other: Parameters<Auth["equals"]>[0]): boolean {
|
|
101
|
+
return AuthModule.equals(other);
|
|
102
|
+
},
|
|
34
103
|
};
|
package/src/ui/social-button.tsx
CHANGED
|
@@ -7,8 +7,9 @@ import {
|
|
|
7
7
|
View,
|
|
8
8
|
ActivityIndicator,
|
|
9
9
|
} from "react-native";
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
10
|
+
import { AuthService } from "../service";
|
|
11
|
+
import { logger } from "../utils/logger";
|
|
12
|
+
import type { AuthProvider, AuthUser } from "../Auth.nitro";
|
|
12
13
|
|
|
13
14
|
export type SocialButtonVariant = "primary" | "outline" | "white" | "black";
|
|
14
15
|
|
|
@@ -56,8 +57,7 @@ const getTextColor = (variant: SocialButtonVariant): string =>
|
|
|
56
57
|
variant === "white" || variant === "outline" ? "#000000" : "#FFFFFF";
|
|
57
58
|
|
|
58
59
|
async function performLogin(provider: AuthProvider): Promise<void> {
|
|
59
|
-
|
|
60
|
-
await auth.login(provider);
|
|
60
|
+
await AuthService.login(provider);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export const SocialButton = ({
|
|
@@ -83,12 +83,16 @@ export const SocialButton = ({
|
|
|
83
83
|
setLoading(true);
|
|
84
84
|
try {
|
|
85
85
|
await performLogin(provider);
|
|
86
|
-
const user =
|
|
86
|
+
const user = AuthService.currentUser;
|
|
87
87
|
if (user) {
|
|
88
88
|
onSuccess?.(user);
|
|
89
89
|
}
|
|
90
90
|
} catch (error) {
|
|
91
|
-
onError
|
|
91
|
+
if (onError) {
|
|
92
|
+
onError(error);
|
|
93
|
+
} else if (__DEV__) {
|
|
94
|
+
logger.error("SocialButton unhandled error:", error);
|
|
95
|
+
}
|
|
92
96
|
} finally {
|
|
93
97
|
setLoading(false);
|
|
94
98
|
}
|
|
@@ -126,19 +130,21 @@ export const SocialButton = ({
|
|
|
126
130
|
<>
|
|
127
131
|
{provider === "google" && variant !== "primary" && (
|
|
128
132
|
<View style={styles.iconPlaceholder}>
|
|
129
|
-
<Text style={
|
|
133
|
+
<Text style={styles.iconText}>G</Text>
|
|
130
134
|
</View>
|
|
131
135
|
)}
|
|
132
136
|
{provider === "apple" && variant !== "primary" && (
|
|
133
137
|
<View style={styles.iconPlaceholder}>
|
|
134
|
-
<Text
|
|
138
|
+
<Text
|
|
139
|
+
style={[styles.iconText, { color: getTextColor(variant) }]}
|
|
140
|
+
>
|
|
135
141
|
|
|
136
142
|
</Text>
|
|
137
143
|
</View>
|
|
138
144
|
)}
|
|
139
145
|
{provider === "microsoft" && variant !== "primary" && (
|
|
140
146
|
<View style={styles.iconPlaceholder}>
|
|
141
|
-
<Text style={
|
|
147
|
+
<Text style={styles.microsoftIconText}>⊞</Text>
|
|
142
148
|
</View>
|
|
143
149
|
)}
|
|
144
150
|
<Text
|
|
@@ -179,4 +185,10 @@ const styles = StyleSheet.create({
|
|
|
179
185
|
fontSize: 16,
|
|
180
186
|
fontWeight: "600",
|
|
181
187
|
},
|
|
188
|
+
iconText: {
|
|
189
|
+
fontSize: 18,
|
|
190
|
+
},
|
|
191
|
+
microsoftIconText: {
|
|
192
|
+
fontSize: 16,
|
|
193
|
+
},
|
|
182
194
|
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ActivityIndicator,
|
|
9
9
|
} from "react-native";
|
|
10
10
|
import { AuthModule } from "../Auth.web";
|
|
11
|
+
import { logger } from "../utils/logger";
|
|
11
12
|
import type { AuthProvider, AuthUser } from "../Auth.nitro";
|
|
12
13
|
|
|
13
14
|
export type SocialButtonVariant = "primary" | "outline" | "white" | "black";
|
|
@@ -87,7 +88,11 @@ export const SocialButton = ({
|
|
|
87
88
|
onSuccess?.(user);
|
|
88
89
|
}
|
|
89
90
|
} catch (error) {
|
|
90
|
-
onError
|
|
91
|
+
if (onError) {
|
|
92
|
+
onError(error);
|
|
93
|
+
} else if (process.env.NODE_ENV !== "production") {
|
|
94
|
+
logger.error("SocialButton unhandled error:", error);
|
|
95
|
+
}
|
|
91
96
|
} finally {
|
|
92
97
|
setLoading(false);
|
|
93
98
|
}
|
|
@@ -125,19 +130,21 @@ export const SocialButton = ({
|
|
|
125
130
|
<>
|
|
126
131
|
{provider === "google" && variant !== "primary" && (
|
|
127
132
|
<View style={styles.iconPlaceholder}>
|
|
128
|
-
<Text style={
|
|
133
|
+
<Text style={styles.iconText}>G</Text>
|
|
129
134
|
</View>
|
|
130
135
|
)}
|
|
131
136
|
{provider === "apple" && variant !== "primary" && (
|
|
132
137
|
<View style={styles.iconPlaceholder}>
|
|
133
|
-
<Text
|
|
138
|
+
<Text
|
|
139
|
+
style={[styles.iconText, { color: getTextColor(variant) }]}
|
|
140
|
+
>
|
|
134
141
|
|
|
135
142
|
</Text>
|
|
136
143
|
</View>
|
|
137
144
|
)}
|
|
138
145
|
{provider === "microsoft" && variant !== "primary" && (
|
|
139
146
|
<View style={styles.iconPlaceholder}>
|
|
140
|
-
<Text style={
|
|
147
|
+
<Text style={styles.microsoftIconText}>⊞</Text>
|
|
141
148
|
</View>
|
|
142
149
|
)}
|
|
143
150
|
<Text
|
|
@@ -178,4 +185,10 @@ const styles = StyleSheet.create({
|
|
|
178
185
|
fontSize: 16,
|
|
179
186
|
fontWeight: "600",
|
|
180
187
|
},
|
|
188
|
+
iconText: {
|
|
189
|
+
fontSize: 18,
|
|
190
|
+
},
|
|
191
|
+
microsoftIconText: {
|
|
192
|
+
fontSize: 16,
|
|
193
|
+
},
|
|
181
194
|
});
|
package/src/use-auth.ts
CHANGED
|
@@ -6,38 +6,25 @@ import type {
|
|
|
6
6
|
AuthTokens,
|
|
7
7
|
} from "./Auth.nitro";
|
|
8
8
|
import { AuthService } from "./service";
|
|
9
|
+
import { AuthError } from "./utils/auth-error";
|
|
9
10
|
|
|
10
11
|
type AuthState = {
|
|
11
12
|
user: AuthUser | undefined;
|
|
12
13
|
scopes: string[];
|
|
13
14
|
loading: boolean;
|
|
14
|
-
error:
|
|
15
|
+
error: AuthError | undefined;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const areScopesEqual = (left: string[], right: string[]): boolean => {
|
|
18
|
-
if (left.length !== right.length)
|
|
19
|
-
|
|
19
|
+
if (left.length !== right.length) return false;
|
|
20
|
+
const sortedLeft = [...left].sort();
|
|
21
|
+
const sortedRight = [...right].sort();
|
|
22
|
+
for (let i = 0; i < sortedLeft.length; i += 1) {
|
|
23
|
+
if (sortedLeft[i] !== sortedRight[i]) return false;
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
for (let index = 0; index < left.length; index += 1) {
|
|
23
|
-
if (left[index] !== right[index]) {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
25
|
return true;
|
|
29
26
|
};
|
|
30
27
|
|
|
31
|
-
class AuthHookError extends Error {
|
|
32
|
-
public readonly underlyingError?: string;
|
|
33
|
-
|
|
34
|
-
constructor(message: string, underlyingError?: string) {
|
|
35
|
-
super(message);
|
|
36
|
-
this.name = "AuthHookError";
|
|
37
|
-
this.underlyingError = underlyingError;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
28
|
export type UseAuthReturn = AuthState & {
|
|
42
29
|
hasPlayServices: boolean;
|
|
43
30
|
login: (provider: AuthProvider, options?: LoginOptions) => Promise<void>;
|
|
@@ -58,7 +45,7 @@ export function useAuth(): UseAuthReturn {
|
|
|
58
45
|
});
|
|
59
46
|
|
|
60
47
|
const syncStateFromService = useCallback(
|
|
61
|
-
(nextLoading: boolean, nextError:
|
|
48
|
+
(nextLoading: boolean, nextError: AuthError | undefined) => {
|
|
62
49
|
const nextUser = AuthService.currentUser;
|
|
63
50
|
const nextScopes = AuthService.grantedScopes;
|
|
64
51
|
setState((prev) => {
|
|
@@ -70,7 +57,6 @@ export function useAuth(): UseAuthReturn {
|
|
|
70
57
|
) {
|
|
71
58
|
return prev;
|
|
72
59
|
}
|
|
73
|
-
|
|
74
60
|
return {
|
|
75
61
|
user: nextUser,
|
|
76
62
|
scopes: nextScopes,
|
|
@@ -89,12 +75,8 @@ export function useAuth(): UseAuthReturn {
|
|
|
89
75
|
await AuthService.login(provider, options);
|
|
90
76
|
syncStateFromService(false, undefined);
|
|
91
77
|
} catch (e) {
|
|
92
|
-
const error =
|
|
93
|
-
setState((prev) => ({
|
|
94
|
-
...prev,
|
|
95
|
-
loading: false,
|
|
96
|
-
error,
|
|
97
|
-
}));
|
|
78
|
+
const error = AuthError.from(e);
|
|
79
|
+
setState((prev) => ({ ...prev, loading: false, error }));
|
|
98
80
|
throw error;
|
|
99
81
|
}
|
|
100
82
|
},
|
|
@@ -103,12 +85,7 @@ export function useAuth(): UseAuthReturn {
|
|
|
103
85
|
|
|
104
86
|
const logout = useCallback(() => {
|
|
105
87
|
AuthService.logout();
|
|
106
|
-
setState({
|
|
107
|
-
user: undefined,
|
|
108
|
-
scopes: [],
|
|
109
|
-
loading: false,
|
|
110
|
-
error: undefined,
|
|
111
|
-
});
|
|
88
|
+
setState({ user: undefined, scopes: [], loading: false, error: undefined });
|
|
112
89
|
}, []);
|
|
113
90
|
|
|
114
91
|
const requestScopes = useCallback(
|
|
@@ -118,12 +95,8 @@ export function useAuth(): UseAuthReturn {
|
|
|
118
95
|
await AuthService.requestScopes(newScopes);
|
|
119
96
|
syncStateFromService(false, undefined);
|
|
120
97
|
} catch (e) {
|
|
121
|
-
const error =
|
|
122
|
-
setState((prev) => ({
|
|
123
|
-
...prev,
|
|
124
|
-
loading: false,
|
|
125
|
-
error,
|
|
126
|
-
}));
|
|
98
|
+
const error = AuthError.from(e);
|
|
99
|
+
setState((prev) => ({ ...prev, loading: false, error }));
|
|
127
100
|
throw error;
|
|
128
101
|
}
|
|
129
102
|
},
|
|
@@ -137,12 +110,8 @@ export function useAuth(): UseAuthReturn {
|
|
|
137
110
|
await AuthService.revokeScopes(scopesToRevoke);
|
|
138
111
|
syncStateFromService(false, undefined);
|
|
139
112
|
} catch (e) {
|
|
140
|
-
const error =
|
|
141
|
-
setState((prev) => ({
|
|
142
|
-
...prev,
|
|
143
|
-
loading: false,
|
|
144
|
-
error,
|
|
145
|
-
}));
|
|
113
|
+
const error = AuthError.from(e);
|
|
114
|
+
setState((prev) => ({ ...prev, loading: false, error }));
|
|
146
115
|
throw error;
|
|
147
116
|
}
|
|
148
117
|
},
|
|
@@ -158,17 +127,9 @@ export function useAuth(): UseAuthReturn {
|
|
|
158
127
|
syncStateFromService(false, undefined);
|
|
159
128
|
return tokens;
|
|
160
129
|
} catch (e) {
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
AuthService.currentUser?.underlyingError,
|
|
165
|
-
);
|
|
166
|
-
setState((prev) => ({
|
|
167
|
-
...prev,
|
|
168
|
-
loading: false,
|
|
169
|
-
error: authError,
|
|
170
|
-
}));
|
|
171
|
-
throw authError;
|
|
130
|
+
const error = AuthError.from(e);
|
|
131
|
+
setState((prev) => ({ ...prev, loading: false, error }));
|
|
132
|
+
throw error;
|
|
172
133
|
}
|
|
173
134
|
}, [syncStateFromService]);
|
|
174
135
|
|
|
@@ -178,18 +139,14 @@ export function useAuth(): UseAuthReturn {
|
|
|
178
139
|
await AuthService.silentRestore();
|
|
179
140
|
syncStateFromService(false, undefined);
|
|
180
141
|
} catch (e) {
|
|
181
|
-
const error =
|
|
182
|
-
setState((prev) => ({
|
|
183
|
-
...prev,
|
|
184
|
-
loading: false,
|
|
185
|
-
error,
|
|
186
|
-
}));
|
|
142
|
+
const error = AuthError.from(e);
|
|
143
|
+
setState((prev) => ({ ...prev, loading: false, error }));
|
|
187
144
|
throw error;
|
|
188
145
|
}
|
|
189
146
|
}, [syncStateFromService]);
|
|
190
147
|
|
|
191
148
|
useEffect(() => {
|
|
192
|
-
const
|
|
149
|
+
const unsubscribeAuth = AuthService.onAuthStateChanged((currentUser) => {
|
|
193
150
|
const nextScopes = AuthService.grantedScopes;
|
|
194
151
|
setState((prev) => {
|
|
195
152
|
if (
|
|
@@ -199,7 +156,6 @@ export function useAuth(): UseAuthReturn {
|
|
|
199
156
|
) {
|
|
200
157
|
return prev;
|
|
201
158
|
}
|
|
202
|
-
|
|
203
159
|
return {
|
|
204
160
|
...prev,
|
|
205
161
|
user: currentUser,
|
|
@@ -208,8 +164,14 @@ export function useAuth(): UseAuthReturn {
|
|
|
208
164
|
};
|
|
209
165
|
});
|
|
210
166
|
});
|
|
211
|
-
|
|
212
|
-
|
|
167
|
+
const unsubscribeTokens = AuthService.onTokensRefreshed?.(() => {
|
|
168
|
+
syncStateFromService(false, undefined);
|
|
169
|
+
});
|
|
170
|
+
return () => {
|
|
171
|
+
unsubscribeAuth();
|
|
172
|
+
unsubscribeTokens?.();
|
|
173
|
+
};
|
|
174
|
+
}, [syncStateFromService]);
|
|
213
175
|
|
|
214
176
|
return useMemo(
|
|
215
177
|
() => ({
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AuthErrorCode } from "../Auth.nitro";
|
|
2
|
+
|
|
3
|
+
const AUTH_ERROR_CODES: ReadonlySet<string> = new Set<AuthErrorCode>([
|
|
4
|
+
"cancelled",
|
|
5
|
+
"timeout",
|
|
6
|
+
"popup_blocked",
|
|
7
|
+
"network_error",
|
|
8
|
+
"configuration_error",
|
|
9
|
+
"unsupported_provider",
|
|
10
|
+
"invalid_state",
|
|
11
|
+
"invalid_nonce",
|
|
12
|
+
"token_error",
|
|
13
|
+
"no_id_token",
|
|
14
|
+
"parse_error",
|
|
15
|
+
"refresh_failed",
|
|
16
|
+
"unknown",
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
export function isAuthErrorCode(value: string): value is AuthErrorCode {
|
|
20
|
+
return AUTH_ERROR_CODES.has(value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function toAuthErrorCode(raw: string): AuthErrorCode {
|
|
24
|
+
return isAuthErrorCode(raw) ? raw : "unknown";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Typed error thrown by all AuthService operations.
|
|
29
|
+
*
|
|
30
|
+
* - `code` — always a valid `AuthErrorCode`, safe to switch on
|
|
31
|
+
* - `underlyingMessage` — the raw platform message when it differs from `code`
|
|
32
|
+
*/
|
|
33
|
+
export class AuthError extends Error {
|
|
34
|
+
readonly code: AuthErrorCode;
|
|
35
|
+
readonly underlyingMessage: string | undefined;
|
|
36
|
+
|
|
37
|
+
constructor(raw: unknown) {
|
|
38
|
+
const message = raw instanceof Error ? raw.message : String(raw);
|
|
39
|
+
const code = toAuthErrorCode(message);
|
|
40
|
+
super(code);
|
|
41
|
+
this.name = "AuthError";
|
|
42
|
+
this.code = code;
|
|
43
|
+
this.underlyingMessage = code !== message ? message : undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static from(e: unknown): AuthError {
|
|
47
|
+
return e instanceof AuthError ? e : new AuthError(e);
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/utils/logger.ts
CHANGED