rn-swiftauth-sdk 1.0.0 → 1.0.2
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 +213 -363
- package/contributors.md +9 -0
- package/dist/components/LoginForm.js +19 -11
- package/dist/components/SignUpForm.js +17 -16
- package/dist/core/AuthProvider.js +45 -75
- package/dist/types/auth.types.d.ts +11 -3
- package/dist/types/auth.types.js +0 -1
- package/dist/types/error.types.d.ts +10 -1
- package/dist/types/error.types.js +16 -1
- package/package.json +4 -3
- package/src/components/LoginForm.tsx +21 -12
- package/src/components/SignUpForm.tsx +20 -31
- package/src/core/AuthProvider.tsx +67 -116
- package/src/types/auth.types.ts +20 -17
- package/src/types/error.types.ts +20 -1
package/contributors.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# 👥 Contributors
|
|
2
|
+
|
|
3
|
+
A huge thank you to the team who built the SwiftAuth SDK!
|
|
4
|
+
|
|
5
|
+
* 🛡️ **[@allcodez](https://github.com/allcodez)**
|
|
6
|
+
* 🎨 **[@Peliah](https://github.com/Peliah)**
|
|
7
|
+
* 🚀 **[@ukemeikot](https://github.com/ukemeikot)**
|
|
8
|
+
|
|
9
|
+
Interested in contributing? Pull requests are welcome!
|
|
@@ -40,13 +40,12 @@ const useAuth_1 = require("../hooks/useAuth");
|
|
|
40
40
|
const PasswordInput_1 = require("./PasswordInput");
|
|
41
41
|
const validation_1 = require("../utils/validation");
|
|
42
42
|
const LoginForm = ({ styles: userStyles }) => {
|
|
43
|
-
const { signInWithEmail, signInWithGoogle, signInWithApple, isLoading,
|
|
44
|
-
error, config // ✅ We need this to check if social buttons are enabled
|
|
45
|
-
} = (0, useAuth_1.useAuth)();
|
|
43
|
+
const { signInWithEmail, signInWithGoogle, signInWithApple, isLoading, error, config } = (0, useAuth_1.useAuth)();
|
|
46
44
|
const [email, setEmail] = (0, react_1.useState)('');
|
|
47
45
|
const [password, setPassword] = (0, react_1.useState)('');
|
|
48
|
-
// ✅ Validation Error State
|
|
49
46
|
const [validationErrors, setValidationErrors] = (0, react_1.useState)({});
|
|
47
|
+
//Check if form is filled to enable button
|
|
48
|
+
const isFormFilled = email.length > 0 && password.length > 0;
|
|
50
49
|
const handleLogin = async () => {
|
|
51
50
|
// 1. Reset previous errors
|
|
52
51
|
setValidationErrors({});
|
|
@@ -58,14 +57,17 @@ const LoginForm = ({ styles: userStyles }) => {
|
|
|
58
57
|
email: emailErr || undefined,
|
|
59
58
|
password: passErr || undefined
|
|
60
59
|
});
|
|
61
|
-
return; //
|
|
60
|
+
return; //Stop if invalid
|
|
62
61
|
}
|
|
63
62
|
// 3. Attempt Login
|
|
64
63
|
try {
|
|
65
|
-
|
|
64
|
+
//UPDATED: Clean Object Syntax
|
|
65
|
+
await signInWithEmail({ email, password });
|
|
66
66
|
}
|
|
67
67
|
catch (e) {
|
|
68
68
|
// Auth errors handled by global state
|
|
69
|
+
// DX: Log it for the developer (Optional but helpful for debugging)
|
|
70
|
+
console.log('Login failed:', e);
|
|
69
71
|
}
|
|
70
72
|
};
|
|
71
73
|
const handleGoogleSignIn = async () => {
|
|
@@ -89,7 +91,7 @@ const LoginForm = ({ styles: userStyles }) => {
|
|
|
89
91
|
react_1.default.createElement(react_native_1.TextInput, { style: [
|
|
90
92
|
defaultStyles.input,
|
|
91
93
|
userStyles?.input,
|
|
92
|
-
validationErrors.email ? { borderColor: 'red' } : {}
|
|
94
|
+
validationErrors.email ? { borderColor: 'red' } : {}
|
|
93
95
|
], placeholder: "Email", value: email, onChangeText: (text) => {
|
|
94
96
|
setEmail(text);
|
|
95
97
|
if (validationErrors.email)
|
|
@@ -104,9 +106,12 @@ const LoginForm = ({ styles: userStyles }) => {
|
|
|
104
106
|
validationErrors.password && (react_1.default.createElement(react_native_1.Text, { style: defaultStyles.validationText }, validationErrors.password)),
|
|
105
107
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
|
|
106
108
|
defaultStyles.button,
|
|
107
|
-
|
|
109
|
+
// Disable style if loading OR form is incomplete
|
|
110
|
+
(isLoading || !isFormFilled) && defaultStyles.buttonDisabled,
|
|
108
111
|
userStyles?.button
|
|
109
|
-
], onPress: handleLogin,
|
|
112
|
+
], onPress: handleLogin,
|
|
113
|
+
// Disable interaction if loading OR form is incomplete
|
|
114
|
+
disabled: isLoading || !isFormFilled }, isLoading ? (react_1.default.createElement(react_native_1.ActivityIndicator, { color: userStyles?.loadingIndicatorColor || "#fff" })) : (react_1.default.createElement(react_native_1.Text, { style: [defaultStyles.buttonText, userStyles?.buttonText] }, "Sign In"))),
|
|
110
115
|
(config.enableGoogle || config.enableApple) && !isLoading && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
111
116
|
react_1.default.createElement(react_native_1.View, { style: defaultStyles.dividerContainer },
|
|
112
117
|
react_1.default.createElement(react_native_1.View, { style: defaultStyles.divider }),
|
|
@@ -130,7 +135,7 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
130
135
|
backgroundColor: '#f5f5f5',
|
|
131
136
|
padding: 15,
|
|
132
137
|
borderRadius: 8,
|
|
133
|
-
marginBottom: 8,
|
|
138
|
+
marginBottom: 8,
|
|
134
139
|
borderWidth: 1,
|
|
135
140
|
borderColor: '#e0e0e0',
|
|
136
141
|
fontSize: 16,
|
|
@@ -142,7 +147,10 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
142
147
|
alignItems: 'center',
|
|
143
148
|
marginTop: 8,
|
|
144
149
|
},
|
|
145
|
-
buttonDisabled: {
|
|
150
|
+
buttonDisabled: {
|
|
151
|
+
backgroundColor: '#a0cfff',
|
|
152
|
+
opacity: 0.7
|
|
153
|
+
},
|
|
146
154
|
buttonText: { color: '#fff', fontWeight: '600', fontSize: 16 },
|
|
147
155
|
errorText: { color: 'red', marginBottom: 12, fontSize: 14, textAlign: 'center' },
|
|
148
156
|
validationText: { color: 'red', fontSize: 12, marginBottom: 10, marginLeft: 4, marginTop: -4 },
|
|
@@ -40,22 +40,20 @@ const useAuth_1 = require("../hooks/useAuth");
|
|
|
40
40
|
const PasswordInput_1 = require("./PasswordInput");
|
|
41
41
|
const validation_1 = require("../utils/validation");
|
|
42
42
|
const SignUpForm = ({ styles: userStyles, showHints = true }) => {
|
|
43
|
-
const { signUpWithEmail, signInWithGoogle, signInWithApple, isLoading,
|
|
44
|
-
error, config // ✅ Use config for conditional rendering
|
|
45
|
-
} = (0, useAuth_1.useAuth)();
|
|
43
|
+
const { signUpWithEmail, signInWithGoogle, signInWithApple, isLoading, error, config } = (0, useAuth_1.useAuth)();
|
|
46
44
|
const [email, setEmail] = (0, react_1.useState)('');
|
|
47
45
|
const [password, setPassword] = (0, react_1.useState)('');
|
|
48
46
|
const [confirmPassword, setConfirmPassword] = (0, react_1.useState)('');
|
|
49
|
-
// ✅ Proper Validation State
|
|
50
47
|
const [validationErrors, setValidationErrors] = (0, react_1.useState)({});
|
|
51
|
-
//
|
|
48
|
+
// 1. Smart Button Logic: Check if all fields have content
|
|
49
|
+
const isFormFilled = email.length > 0 && password.length > 0 && confirmPassword.length > 0;
|
|
50
|
+
// Password Requirements Logic
|
|
52
51
|
const requirements = [
|
|
53
52
|
{ label: "At least 6 characters", met: password.length >= 6 },
|
|
54
53
|
{ label: "Contains a number", met: /\d/.test(password) },
|
|
55
54
|
{ label: "Passwords match", met: password.length > 0 && password === confirmPassword }
|
|
56
55
|
];
|
|
57
56
|
const handleSignUp = async () => {
|
|
58
|
-
// 1. Reset Errors
|
|
59
57
|
setValidationErrors({});
|
|
60
58
|
// 2. Validate Inputs
|
|
61
59
|
const emailErr = (0, validation_1.validateEmail)(email);
|
|
@@ -64,7 +62,6 @@ const SignUpForm = ({ styles: userStyles, showHints = true }) => {
|
|
|
64
62
|
if (password !== confirmPassword) {
|
|
65
63
|
confirmErr = "Passwords do not match.";
|
|
66
64
|
}
|
|
67
|
-
// 3. Check if any errors exist
|
|
68
65
|
if (emailErr || passErr || confirmErr) {
|
|
69
66
|
setValidationErrors({
|
|
70
67
|
email: emailErr || undefined,
|
|
@@ -73,12 +70,12 @@ const SignUpForm = ({ styles: userStyles, showHints = true }) => {
|
|
|
73
70
|
});
|
|
74
71
|
return;
|
|
75
72
|
}
|
|
76
|
-
// 4. Attempt Sign Up
|
|
77
73
|
try {
|
|
78
|
-
|
|
74
|
+
// ✅ UPDATED: New Object Syntax
|
|
75
|
+
await signUpWithEmail({ email, password });
|
|
79
76
|
}
|
|
80
77
|
catch (e) {
|
|
81
|
-
|
|
78
|
+
console.error('Sign Up Failed:', e);
|
|
82
79
|
}
|
|
83
80
|
};
|
|
84
81
|
const handleGoogleSignIn = async () => {
|
|
@@ -130,9 +127,12 @@ const SignUpForm = ({ styles: userStyles, showHints = true }) => {
|
|
|
130
127
|
] }, req.label)))))),
|
|
131
128
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
|
|
132
129
|
defaultStyles.button,
|
|
133
|
-
|
|
130
|
+
// Disable style if loading OR form incomplete
|
|
131
|
+
(isLoading || !isFormFilled) && defaultStyles.buttonDisabled,
|
|
134
132
|
userStyles?.button
|
|
135
|
-
], onPress: handleSignUp,
|
|
133
|
+
], onPress: handleSignUp,
|
|
134
|
+
// Disable interaction if loading OR form incomplete
|
|
135
|
+
disabled: isLoading || !isFormFilled }, isLoading ? (react_1.default.createElement(react_native_1.ActivityIndicator, { color: userStyles?.loadingIndicatorColor || "#fff" })) : (react_1.default.createElement(react_native_1.Text, { style: [defaultStyles.buttonText, userStyles?.buttonText] }, "Create Account"))),
|
|
136
136
|
(config.enableGoogle || config.enableApple) && !isLoading && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
137
137
|
react_1.default.createElement(react_native_1.View, { style: defaultStyles.dividerContainer },
|
|
138
138
|
react_1.default.createElement(react_native_1.View, { style: defaultStyles.divider }),
|
|
@@ -150,7 +150,7 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
150
150
|
backgroundColor: '#f5f5f5',
|
|
151
151
|
padding: 15,
|
|
152
152
|
borderRadius: 8,
|
|
153
|
-
marginBottom: 8,
|
|
153
|
+
marginBottom: 8,
|
|
154
154
|
borderWidth: 1,
|
|
155
155
|
borderColor: '#e0e0e0',
|
|
156
156
|
fontSize: 16,
|
|
@@ -162,11 +162,13 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
162
162
|
alignItems: 'center',
|
|
163
163
|
marginTop: 8,
|
|
164
164
|
},
|
|
165
|
-
buttonDisabled: {
|
|
165
|
+
buttonDisabled: {
|
|
166
|
+
backgroundColor: '#9ce4ae',
|
|
167
|
+
opacity: 0.7
|
|
168
|
+
},
|
|
166
169
|
buttonText: { color: '#fff', fontWeight: '600', fontSize: 16 },
|
|
167
170
|
globalError: { color: 'red', marginBottom: 12, fontSize: 14, textAlign: 'center' },
|
|
168
171
|
validationText: { color: 'red', fontSize: 12, marginBottom: 10, marginLeft: 4, marginTop: -4 },
|
|
169
|
-
// OAuth Styles
|
|
170
172
|
dividerContainer: {
|
|
171
173
|
flexDirection: 'row',
|
|
172
174
|
alignItems: 'center',
|
|
@@ -190,7 +192,6 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
190
192
|
googleButtonText: { color: '#000', fontSize: 16, fontWeight: '500' },
|
|
191
193
|
appleButton: { backgroundColor: '#000' },
|
|
192
194
|
appleButtonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
|
|
193
|
-
// Password Hint Styles
|
|
194
195
|
hintContainer: { marginBottom: 15, paddingLeft: 5 },
|
|
195
196
|
hintRow: { flexDirection: 'row', alignItems: 'center', marginBottom: 4 },
|
|
196
197
|
hintText: { color: '#666', fontSize: 12 },
|
|
@@ -40,33 +40,26 @@ exports.AuthProvider = void 0;
|
|
|
40
40
|
const react_1 = __importStar(require("react"));
|
|
41
41
|
const react_native_1 = require("react-native");
|
|
42
42
|
const app_1 = require("firebase/app");
|
|
43
|
-
|
|
44
|
-
const auth_1 = require("firebase/auth");
|
|
45
|
-
// The Hack: Import for getReactNativePersistence
|
|
46
|
-
const firebaseAuth = __importStar(require("firebase/auth"));
|
|
47
|
-
// @ts-ignore
|
|
48
|
-
const getReactNativePersistence = firebaseAuth.getReactNativePersistence;
|
|
43
|
+
const FirebaseAuth = __importStar(require("firebase/auth"));
|
|
49
44
|
const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
|
|
50
|
-
// PROPER GOOGLE SIGN-IN
|
|
51
45
|
const google_signin_1 = require("@react-native-google-signin/google-signin");
|
|
52
|
-
// Apple Sign-In (Expo)
|
|
53
46
|
const AppleAuthentication = __importStar(require("expo-apple-authentication"));
|
|
54
47
|
const Crypto = __importStar(require("expo-crypto"));
|
|
55
48
|
const errors_1 = require("../errors");
|
|
56
49
|
const AuthContext_1 = require("./AuthContext");
|
|
57
50
|
const types_1 = require("../types");
|
|
51
|
+
const getReactNativePersistence = FirebaseAuth.getReactNativePersistence;
|
|
58
52
|
const AuthProvider = ({ config, children }) => {
|
|
59
53
|
const [user, setUser] = (0, react_1.useState)(null);
|
|
60
54
|
const [status, setStatus] = (0, react_1.useState)(types_1.AuthStatus.LOADING);
|
|
61
55
|
const [error, setError] = (0, react_1.useState)(null);
|
|
62
56
|
const [firebaseAuthInstance, setFirebaseAuthInstance] = (0, react_1.useState)(null);
|
|
63
|
-
// ✅ NEW: Explicit loading state for initial app load vs action loading
|
|
64
57
|
const [isDataLoading, setIsDataLoading] = (0, react_1.useState)(true);
|
|
58
|
+
// --- INITIALIZATION ---
|
|
65
59
|
(0, react_1.useEffect)(() => {
|
|
66
60
|
let app;
|
|
67
61
|
let auth;
|
|
68
62
|
if (!(0, app_1.getApps)().length) {
|
|
69
|
-
// 1. Initialize App
|
|
70
63
|
app = (0, app_1.initializeApp)({
|
|
71
64
|
apiKey: config.apiKey,
|
|
72
65
|
authDomain: config.authDomain,
|
|
@@ -75,39 +68,35 @@ const AuthProvider = ({ config, children }) => {
|
|
|
75
68
|
messagingSenderId: config.messagingSenderId,
|
|
76
69
|
appId: config.appId,
|
|
77
70
|
});
|
|
78
|
-
// 2. Select Persistence Strategy
|
|
79
71
|
const selectedPersistence = config.persistence === 'memory'
|
|
80
|
-
?
|
|
72
|
+
? FirebaseAuth.inMemoryPersistence
|
|
81
73
|
: getReactNativePersistence(async_storage_1.default);
|
|
82
|
-
|
|
83
|
-
auth = (0, auth_1.initializeAuth)(app, {
|
|
74
|
+
auth = FirebaseAuth.initializeAuth(app, {
|
|
84
75
|
persistence: selectedPersistence
|
|
85
76
|
});
|
|
86
77
|
}
|
|
87
78
|
else {
|
|
88
79
|
app = (0, app_1.getApp)();
|
|
89
|
-
auth =
|
|
80
|
+
auth = FirebaseAuth.getAuth(app);
|
|
90
81
|
}
|
|
91
82
|
setFirebaseAuthInstance(auth);
|
|
92
|
-
// 4. Configure Google Sign-In if enabled
|
|
93
83
|
if (config.enableGoogle && config.googleWebClientId) {
|
|
94
84
|
try {
|
|
95
85
|
google_signin_1.GoogleSignin.configure({
|
|
96
86
|
webClientId: config.googleWebClientId,
|
|
97
87
|
offlineAccess: true,
|
|
98
|
-
iosClientId: config.googleIOSClientId,
|
|
88
|
+
iosClientId: config.googleIOSClientId,
|
|
99
89
|
});
|
|
100
|
-
console.log('
|
|
90
|
+
console.log('Google Sign-In configured successfully');
|
|
101
91
|
}
|
|
102
92
|
catch (err) {
|
|
103
|
-
console.error('
|
|
93
|
+
console.error('Google Sign-In configuration failed:', err);
|
|
104
94
|
}
|
|
105
95
|
}
|
|
106
|
-
const unsubscribe =
|
|
96
|
+
const unsubscribe = FirebaseAuth.onAuthStateChanged(auth, async (fbUser) => {
|
|
107
97
|
try {
|
|
108
98
|
if (fbUser) {
|
|
109
99
|
try {
|
|
110
|
-
// Force token refresh to ensure validity on load
|
|
111
100
|
const token = await fbUser.getIdToken(true);
|
|
112
101
|
setUser({
|
|
113
102
|
uid: fbUser.uid,
|
|
@@ -121,7 +110,8 @@ const AuthProvider = ({ config, children }) => {
|
|
|
121
110
|
}
|
|
122
111
|
catch (tokenError) {
|
|
123
112
|
console.error('Token retrieval error:', tokenError);
|
|
124
|
-
if (tokenError.code ===
|
|
113
|
+
if (tokenError.code === types_1.ProviderErrorCodes.USER_TOKEN_EXPIRED ||
|
|
114
|
+
tokenError.code === types_1.ProviderErrorCodes.NULL_USER) {
|
|
125
115
|
setStatus(types_1.AuthStatus.TOKEN_EXPIRED);
|
|
126
116
|
}
|
|
127
117
|
else {
|
|
@@ -140,60 +130,48 @@ const AuthProvider = ({ config, children }) => {
|
|
|
140
130
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
141
131
|
}
|
|
142
132
|
finally {
|
|
143
|
-
// ✅ Stop initial loading spinner once Firebase has checked storage
|
|
144
133
|
setIsDataLoading(false);
|
|
145
134
|
}
|
|
146
|
-
}, (err) => {
|
|
147
|
-
console.error("Auth State Error:", err);
|
|
148
|
-
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
149
|
-
setIsDataLoading(false);
|
|
150
135
|
});
|
|
151
136
|
return () => unsubscribe();
|
|
152
137
|
}, [config]);
|
|
153
|
-
//
|
|
154
|
-
const signInWithEmail = async (email,
|
|
138
|
+
// --- ACTIONS ---
|
|
139
|
+
const signInWithEmail = async ({ email, password }) => {
|
|
155
140
|
if (!firebaseAuthInstance)
|
|
156
141
|
return;
|
|
157
142
|
try {
|
|
158
143
|
setError(null);
|
|
159
144
|
setStatus(types_1.AuthStatus.LOADING);
|
|
160
|
-
await
|
|
145
|
+
await FirebaseAuth.signInWithEmailAndPassword(firebaseAuthInstance, email, password);
|
|
161
146
|
}
|
|
162
147
|
catch (err) {
|
|
163
|
-
const
|
|
164
|
-
setError(
|
|
148
|
+
const mapped = (0, errors_1.mapFirebaseError)(err);
|
|
149
|
+
setError({ ...mapped, originalError: err });
|
|
165
150
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
166
|
-
throw
|
|
151
|
+
throw err;
|
|
167
152
|
}
|
|
168
153
|
};
|
|
169
|
-
|
|
170
|
-
const signUpWithEmail = async (email, pass) => {
|
|
154
|
+
const signUpWithEmail = async ({ email, password }) => {
|
|
171
155
|
if (!firebaseAuthInstance)
|
|
172
156
|
return;
|
|
173
157
|
try {
|
|
174
158
|
setError(null);
|
|
175
159
|
setStatus(types_1.AuthStatus.LOADING);
|
|
176
|
-
await
|
|
160
|
+
await FirebaseAuth.createUserWithEmailAndPassword(firebaseAuthInstance, email, password);
|
|
177
161
|
}
|
|
178
162
|
catch (err) {
|
|
179
|
-
const
|
|
180
|
-
setError(
|
|
163
|
+
const mapped = (0, errors_1.mapFirebaseError)(err);
|
|
164
|
+
setError({ ...mapped, originalError: err });
|
|
181
165
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
182
|
-
throw
|
|
166
|
+
throw err;
|
|
183
167
|
}
|
|
184
168
|
};
|
|
185
|
-
// PROPER GOOGLE SIGN-IN using @react-native-google-signin/google-signin
|
|
186
169
|
const signInWithGoogle = async () => {
|
|
187
|
-
if (!firebaseAuthInstance)
|
|
170
|
+
if (!firebaseAuthInstance)
|
|
188
171
|
throw new Error('Firebase not initialized');
|
|
189
|
-
}
|
|
190
172
|
if (!config.enableGoogle || !config.googleWebClientId) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
message: 'Google Sign-In is not enabled or configured. Please add googleWebClientId to your AuthConfig.',
|
|
194
|
-
};
|
|
195
|
-
setError(configError);
|
|
196
|
-
throw configError;
|
|
173
|
+
setError({ code: types_1.AuthErrorCode.CONFIG_ERROR, message: 'Google Auth not configured. Missing googleWebClientId.' });
|
|
174
|
+
return;
|
|
197
175
|
}
|
|
198
176
|
try {
|
|
199
177
|
setError(null);
|
|
@@ -201,34 +179,32 @@ const AuthProvider = ({ config, children }) => {
|
|
|
201
179
|
await google_signin_1.GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
|
|
202
180
|
const userInfo = await google_signin_1.GoogleSignin.signIn();
|
|
203
181
|
const idToken = userInfo.data?.idToken;
|
|
204
|
-
if (!idToken)
|
|
182
|
+
if (!idToken)
|
|
205
183
|
throw new Error('No ID token received from Google Sign-In');
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
console.log('✅ Google Sign-In successful');
|
|
184
|
+
const credential = FirebaseAuth.GoogleAuthProvider.credential(idToken);
|
|
185
|
+
await FirebaseAuth.signInWithCredential(firebaseAuthInstance, credential);
|
|
186
|
+
console.log('Google Sign-In successful');
|
|
210
187
|
}
|
|
211
188
|
catch (err) {
|
|
212
|
-
console.error('
|
|
189
|
+
console.error('Google Sign-In Error:', err);
|
|
213
190
|
let mappedError;
|
|
214
|
-
if (err.code ===
|
|
191
|
+
if (err.code === types_1.ProviderErrorCodes.GOOGLE_CANCELLED) {
|
|
215
192
|
mappedError = {
|
|
216
193
|
code: types_1.AuthErrorCode.GOOGLE_SIGN_IN_CANCELLED,
|
|
217
194
|
message: 'Google Sign-In was cancelled',
|
|
218
195
|
originalError: err
|
|
219
196
|
};
|
|
220
|
-
// Reset status if cancelled, don't leave it loading
|
|
221
197
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
222
198
|
return;
|
|
223
199
|
}
|
|
224
|
-
else if (err.code ===
|
|
200
|
+
else if (err.code === types_1.ProviderErrorCodes.GOOGLE_IN_PROGRESS) {
|
|
225
201
|
mappedError = {
|
|
226
202
|
code: types_1.AuthErrorCode.GOOGLE_SIGN_IN_IN_PROGRESS,
|
|
227
203
|
message: 'Google Sign-In is already in progress',
|
|
228
204
|
originalError: err
|
|
229
205
|
};
|
|
230
206
|
}
|
|
231
|
-
else if (err.code ===
|
|
207
|
+
else if (err.code === types_1.ProviderErrorCodes.GOOGLE_PLAY_UNAVAILABLE) {
|
|
232
208
|
mappedError = {
|
|
233
209
|
code: types_1.AuthErrorCode.GOOGLE_PLAY_SERVICES_NOT_AVAILABLE,
|
|
234
210
|
message: 'Google Play Services are not available. Please update Google Play Services.',
|
|
@@ -238,16 +214,14 @@ const AuthProvider = ({ config, children }) => {
|
|
|
238
214
|
else {
|
|
239
215
|
mappedError = (0, errors_1.mapFirebaseError)(err);
|
|
240
216
|
}
|
|
241
|
-
setError(mappedError);
|
|
217
|
+
setError({ ...mappedError, originalError: err });
|
|
242
218
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
243
219
|
throw mappedError;
|
|
244
220
|
}
|
|
245
221
|
};
|
|
246
|
-
// Apple Sign-In using expo-apple-authentication
|
|
247
222
|
const signInWithApple = async () => {
|
|
248
|
-
if (!firebaseAuthInstance)
|
|
223
|
+
if (!firebaseAuthInstance)
|
|
249
224
|
throw new Error('Firebase not initialized');
|
|
250
|
-
}
|
|
251
225
|
if (react_native_1.Platform.OS !== 'ios') {
|
|
252
226
|
const platformError = {
|
|
253
227
|
code: types_1.AuthErrorCode.APPLE_SIGN_IN_NOT_SUPPORTED,
|
|
@@ -278,20 +252,19 @@ const AuthProvider = ({ config, children }) => {
|
|
|
278
252
|
nonce: hashedNonce,
|
|
279
253
|
});
|
|
280
254
|
const { identityToken } = appleCredential;
|
|
281
|
-
if (!identityToken)
|
|
255
|
+
if (!identityToken)
|
|
282
256
|
throw new Error('No identity token received from Apple');
|
|
283
|
-
|
|
284
|
-
const provider = new auth_1.OAuthProvider('apple.com');
|
|
257
|
+
const provider = new FirebaseAuth.OAuthProvider('apple.com');
|
|
285
258
|
const credential = provider.credential({
|
|
286
259
|
idToken: identityToken,
|
|
287
260
|
rawNonce: nonce,
|
|
288
261
|
});
|
|
289
|
-
await
|
|
290
|
-
console.log('
|
|
262
|
+
await FirebaseAuth.signInWithCredential(firebaseAuthInstance, credential);
|
|
263
|
+
console.log('Apple Sign-In successful');
|
|
291
264
|
}
|
|
292
265
|
catch (err) {
|
|
293
|
-
console.error('
|
|
294
|
-
if (err.code ===
|
|
266
|
+
console.error('Apple Sign-In Error:', err);
|
|
267
|
+
if (err.code === types_1.ProviderErrorCodes.APPLE_CANCELLED) {
|
|
295
268
|
const cancelError = {
|
|
296
269
|
code: types_1.AuthErrorCode.APPLE_SIGN_IN_CANCELLED,
|
|
297
270
|
message: 'Apple Sign-In was cancelled',
|
|
@@ -302,12 +275,11 @@ const AuthProvider = ({ config, children }) => {
|
|
|
302
275
|
return;
|
|
303
276
|
}
|
|
304
277
|
const mappedError = (0, errors_1.mapFirebaseError)(err);
|
|
305
|
-
setError(mappedError);
|
|
278
|
+
setError({ ...mappedError, originalError: err });
|
|
306
279
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
307
280
|
throw mappedError;
|
|
308
281
|
}
|
|
309
282
|
};
|
|
310
|
-
// Sign Out
|
|
311
283
|
const signOut = async () => {
|
|
312
284
|
try {
|
|
313
285
|
if (firebaseAuthInstance) {
|
|
@@ -321,10 +293,10 @@ const AuthProvider = ({ config, children }) => {
|
|
|
321
293
|
console.log('Google sign-out skipped or failed:', googleSignOutError);
|
|
322
294
|
}
|
|
323
295
|
}
|
|
324
|
-
console.log('
|
|
296
|
+
console.log('Sign out successful');
|
|
325
297
|
}
|
|
326
298
|
catch (err) {
|
|
327
|
-
console.error('
|
|
299
|
+
console.error('Sign out error:', err);
|
|
328
300
|
setUser(null);
|
|
329
301
|
setStatus(types_1.AuthStatus.UNAUTHENTICATED);
|
|
330
302
|
}
|
|
@@ -333,10 +305,8 @@ const AuthProvider = ({ config, children }) => {
|
|
|
333
305
|
const value = (0, react_1.useMemo)(() => ({
|
|
334
306
|
user,
|
|
335
307
|
status,
|
|
336
|
-
// ✅ NEW: Combine internal loading with AuthStatus
|
|
337
308
|
isLoading: isDataLoading || status === types_1.AuthStatus.LOADING,
|
|
338
309
|
error,
|
|
339
|
-
// ✅ NEW: Expose config for UI to read
|
|
340
310
|
config,
|
|
341
311
|
signInWithEmail,
|
|
342
312
|
signUpWithEmail,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AuthError } from './error.types';
|
|
2
1
|
import { AuthConfig } from './config.types';
|
|
2
|
+
import { AuthError } from './error.types';
|
|
3
3
|
export declare enum AuthStatus {
|
|
4
4
|
AUTHENTICATED = "AUTHENTICATED",
|
|
5
5
|
UNAUTHENTICATED = "UNAUTHENTICATED",
|
|
@@ -14,14 +14,22 @@ export interface User {
|
|
|
14
14
|
emailVerified: boolean;
|
|
15
15
|
token?: string;
|
|
16
16
|
}
|
|
17
|
+
export interface EmailSignInOptions {
|
|
18
|
+
email: string;
|
|
19
|
+
password: string;
|
|
20
|
+
}
|
|
21
|
+
export interface EmailSignUpOptions {
|
|
22
|
+
email: string;
|
|
23
|
+
password: string;
|
|
24
|
+
}
|
|
17
25
|
export interface AuthContextType {
|
|
18
26
|
user: User | null;
|
|
19
27
|
status: AuthStatus;
|
|
20
28
|
isLoading: boolean;
|
|
21
29
|
error: AuthError | null;
|
|
22
30
|
config: AuthConfig;
|
|
23
|
-
signInWithEmail: (
|
|
24
|
-
signUpWithEmail: (
|
|
31
|
+
signInWithEmail: (options: EmailSignInOptions) => Promise<void>;
|
|
32
|
+
signUpWithEmail: (options: EmailSignUpOptions) => Promise<void>;
|
|
25
33
|
signInWithGoogle: () => Promise<void>;
|
|
26
34
|
signInWithApple: () => Promise<void>;
|
|
27
35
|
signOut: () => Promise<void>;
|
package/dist/types/auth.types.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
export declare enum ProviderErrorCodes {
|
|
2
|
+
USER_TOKEN_EXPIRED = "auth/user-token-expired",
|
|
3
|
+
NULL_USER = "auth/null-user",
|
|
4
|
+
GOOGLE_CANCELLED = "SIGN_IN_CANCELLED",
|
|
5
|
+
GOOGLE_IN_PROGRESS = "IN_PROGRESS",
|
|
6
|
+
GOOGLE_PLAY_UNAVAILABLE = "PLAY_SERVICES_NOT_AVAILABLE",
|
|
7
|
+
APPLE_CANCELLED = "ERR_REQUEST_CANCELED",
|
|
8
|
+
APPLE_NOT_SUPPORTED = "APPLE_SIGN_IN_NOT_SUPPORTED"
|
|
9
|
+
}
|
|
1
10
|
export declare enum AuthErrorCode {
|
|
2
11
|
INVALID_CREDENTIALS = "auth/invalid-credentials",
|
|
3
12
|
USER_NOT_FOUND = "auth/user-not-found",
|
|
@@ -17,7 +26,7 @@ export declare enum AuthErrorCode {
|
|
|
17
26
|
APPLE_SIGN_IN_NOT_SUPPORTED = "APPLE_SIGN_IN_NOT_SUPPORTED"
|
|
18
27
|
}
|
|
19
28
|
export interface AuthError {
|
|
20
|
-
code: AuthErrorCode;
|
|
29
|
+
code: string | ProviderErrorCodes | AuthErrorCode;
|
|
21
30
|
message: string;
|
|
22
31
|
originalError?: any;
|
|
23
32
|
}
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// src/types/error.types.ts
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.AuthErrorCode = void 0;
|
|
4
|
+
exports.AuthErrorCode = exports.ProviderErrorCodes = void 0;
|
|
5
|
+
// ✅ 1. Define Known Error Codes (Source of Truth)
|
|
6
|
+
var ProviderErrorCodes;
|
|
7
|
+
(function (ProviderErrorCodes) {
|
|
8
|
+
// Firebase specific
|
|
9
|
+
ProviderErrorCodes["USER_TOKEN_EXPIRED"] = "auth/user-token-expired";
|
|
10
|
+
ProviderErrorCodes["NULL_USER"] = "auth/null-user";
|
|
11
|
+
// Google specific
|
|
12
|
+
ProviderErrorCodes["GOOGLE_CANCELLED"] = "SIGN_IN_CANCELLED";
|
|
13
|
+
ProviderErrorCodes["GOOGLE_IN_PROGRESS"] = "IN_PROGRESS";
|
|
14
|
+
ProviderErrorCodes["GOOGLE_PLAY_UNAVAILABLE"] = "PLAY_SERVICES_NOT_AVAILABLE";
|
|
15
|
+
// Apple specific
|
|
16
|
+
ProviderErrorCodes["APPLE_CANCELLED"] = "ERR_REQUEST_CANCELED";
|
|
17
|
+
ProviderErrorCodes["APPLE_NOT_SUPPORTED"] = "APPLE_SIGN_IN_NOT_SUPPORTED";
|
|
18
|
+
})(ProviderErrorCodes || (exports.ProviderErrorCodes = ProviderErrorCodes = {}));
|
|
19
|
+
// Legacy error codes used in mapping (Keep this for backward compatibility if needed)
|
|
5
20
|
var AuthErrorCode;
|
|
6
21
|
(function (AuthErrorCode) {
|
|
7
22
|
AuthErrorCode["INVALID_CREDENTIALS"] = "auth/invalid-credentials";
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rn-swiftauth-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
8
|
-
"src"
|
|
8
|
+
"src",
|
|
9
|
+
"CONTRIBUTORS.md"
|
|
9
10
|
],
|
|
10
11
|
"scripts": {
|
|
11
12
|
"build": "tsc",
|
|
@@ -59,4 +60,4 @@
|
|
|
59
60
|
"react-native-safe-area-context": "^5.6.2",
|
|
60
61
|
"typescript": "^5.0.0"
|
|
61
62
|
}
|
|
62
|
-
}
|
|
63
|
+
}
|