rn-swiftauth-sdk 1.0.0

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 (59) hide show
  1. package/README.md +574 -0
  2. package/dist/components/AuthScreen.d.ts +14 -0
  3. package/dist/components/AuthScreen.js +75 -0
  4. package/dist/components/LoginForm.d.ts +7 -0
  5. package/dist/components/LoginForm.js +180 -0
  6. package/dist/components/PasswordInput.d.ts +8 -0
  7. package/dist/components/PasswordInput.js +70 -0
  8. package/dist/components/SignUpForm.d.ts +8 -0
  9. package/dist/components/SignUpForm.js +198 -0
  10. package/dist/components/index.d.ts +3 -0
  11. package/dist/components/index.js +19 -0
  12. package/dist/core/AuthContext.d.ts +3 -0
  13. package/dist/core/AuthContext.js +10 -0
  14. package/dist/core/AuthProvider.d.ts +8 -0
  15. package/dist/core/AuthProvider.js +350 -0
  16. package/dist/core/index.d.ts +2 -0
  17. package/dist/core/index.js +18 -0
  18. package/dist/errors/errorMapper.d.ts +2 -0
  19. package/dist/errors/errorMapper.js +124 -0
  20. package/dist/errors/index.d.ts +1 -0
  21. package/dist/errors/index.js +17 -0
  22. package/dist/hooks/index.d.ts +1 -0
  23. package/dist/hooks/index.js +17 -0
  24. package/dist/hooks/useAuth.d.ts +2 -0
  25. package/dist/hooks/useAuth.js +13 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.js +27 -0
  28. package/dist/types/auth.types.d.ts +29 -0
  29. package/dist/types/auth.types.js +11 -0
  30. package/dist/types/config.types.d.ts +21 -0
  31. package/dist/types/config.types.js +12 -0
  32. package/dist/types/error.types.d.ts +23 -0
  33. package/dist/types/error.types.js +26 -0
  34. package/dist/types/index.d.ts +4 -0
  35. package/dist/types/index.js +21 -0
  36. package/dist/types/ui.types.d.ts +20 -0
  37. package/dist/types/ui.types.js +2 -0
  38. package/dist/utils/validation.d.ts +3 -0
  39. package/dist/utils/validation.js +29 -0
  40. package/package.json +62 -0
  41. package/src/components/AuthScreen.tsx +87 -0
  42. package/src/components/LoginForm.tsx +246 -0
  43. package/src/components/PasswordInput.tsx +56 -0
  44. package/src/components/SignUpForm.tsx +293 -0
  45. package/src/components/index.ts +3 -0
  46. package/src/core/AuthContext.tsx +6 -0
  47. package/src/core/AuthProvider.tsx +362 -0
  48. package/src/core/index.ts +2 -0
  49. package/src/errors/errorMapper.ts +139 -0
  50. package/src/errors/index.ts +1 -0
  51. package/src/hooks/index.ts +1 -0
  52. package/src/hooks/useAuth.ts +13 -0
  53. package/src/index.ts +12 -0
  54. package/src/types/auth.types.ts +43 -0
  55. package/src/types/config.types.ts +46 -0
  56. package/src/types/error.types.ts +31 -0
  57. package/src/types/index.ts +5 -0
  58. package/src/types/ui.types.ts +26 -0
  59. package/src/utils/validation.ts +20 -0
@@ -0,0 +1,139 @@
1
+ import { FirebaseError } from 'firebase/app';
2
+ import { AuthError, AuthErrorCode } from '../types';
3
+
4
+ export const mapFirebaseError = (error: any): AuthError => {
5
+ // Default fallback
6
+ const fallbackError: AuthError = {
7
+ code: AuthErrorCode.UNKNOWN,
8
+ message: 'An unexpected error occurred',
9
+ originalError: error,
10
+ };
11
+
12
+ // If it's not a Firebase error, return generic
13
+ if (!error || typeof error.code !== 'string') {
14
+ return {
15
+ ...fallbackError,
16
+ message: error?.message || fallbackError.message
17
+ };
18
+ }
19
+
20
+ const fbError = error as FirebaseError;
21
+
22
+ switch (fbError.code) {
23
+ // Email/Password Errors
24
+ case 'auth/invalid-email':
25
+ case 'auth/user-not-found':
26
+ case 'auth/wrong-password':
27
+ case 'auth/invalid-credential':
28
+ return {
29
+ code: AuthErrorCode.INVALID_CREDENTIALS,
30
+ message: 'Invalid email or password.',
31
+ originalError: error
32
+ };
33
+
34
+ case 'auth/email-already-in-use':
35
+ return {
36
+ code: AuthErrorCode.EMAIL_ALREADY_IN_USE,
37
+ message: 'This email is already registered.',
38
+ originalError: error
39
+ };
40
+
41
+ case 'auth/weak-password':
42
+ return {
43
+ code: AuthErrorCode.WEAK_PASSWORD,
44
+ message: 'Password is too weak. Please use a stronger password.',
45
+ originalError: error
46
+ };
47
+
48
+ case 'auth/network-request-failed':
49
+ return {
50
+ code: AuthErrorCode.NETWORK_ERROR,
51
+ message: 'Network error. Please check your connection.',
52
+ originalError: error
53
+ };
54
+
55
+ // Google Sign-In Errors
56
+ case 'auth/popup-closed-by-user':
57
+ case 'auth/cancelled-popup-request':
58
+ return {
59
+ code: AuthErrorCode.UNKNOWN,
60
+ message: 'Sign-in was cancelled.',
61
+ originalError: error
62
+ };
63
+
64
+ case 'auth/account-exists-with-different-credential':
65
+ return {
66
+ code: AuthErrorCode.EMAIL_ALREADY_IN_USE,
67
+ message: 'An account already exists with this email using a different sign-in method.',
68
+ originalError: error
69
+ };
70
+
71
+ case 'auth/invalid-credential':
72
+ return {
73
+ code: AuthErrorCode.INVALID_CREDENTIALS,
74
+ message: 'The credential received is invalid. Please try again.',
75
+ originalError: error
76
+ };
77
+
78
+ case 'auth/operation-not-allowed':
79
+ return {
80
+ code: AuthErrorCode.UNKNOWN,
81
+ message: 'This sign-in method is not enabled. Please contact support.',
82
+ originalError: error
83
+ };
84
+
85
+ case 'auth/user-disabled':
86
+ return {
87
+ code: AuthErrorCode.INVALID_CREDENTIALS,
88
+ message: 'This account has been disabled.',
89
+ originalError: error
90
+ };
91
+
92
+ // Apple Sign-In Errors
93
+ case 'auth/invalid-verification-code':
94
+ case 'auth/invalid-verification-id':
95
+ return {
96
+ code: AuthErrorCode.INVALID_CREDENTIALS,
97
+ message: 'The verification code is invalid. Please try again.',
98
+ originalError: error
99
+ };
100
+
101
+ // Token Expiration
102
+ case 'auth/id-token-expired':
103
+ case 'auth/user-token-expired':
104
+ return {
105
+ code: AuthErrorCode.TOKEN_EXPIRED,
106
+ message: 'Your session has expired. Please sign in again.',
107
+ originalError: error
108
+ };
109
+
110
+ // OAuth-Specific Errors
111
+ case 'auth/unauthorized-domain':
112
+ return {
113
+ code: AuthErrorCode.UNKNOWN,
114
+ message: 'This domain is not authorized for OAuth operations.',
115
+ originalError: error
116
+ };
117
+
118
+ case 'auth/invalid-oauth-provider':
119
+ return {
120
+ code: AuthErrorCode.UNKNOWN,
121
+ message: 'The OAuth provider configuration is invalid.',
122
+ originalError: error
123
+ };
124
+
125
+ case 'auth/invalid-oauth-client-id':
126
+ return {
127
+ code: AuthErrorCode.UNKNOWN,
128
+ message: 'The OAuth client ID is invalid.',
129
+ originalError: error
130
+ };
131
+
132
+ default:
133
+ return {
134
+ code: AuthErrorCode.UNKNOWN,
135
+ message: fbError.message || 'An unknown error occurred.',
136
+ originalError: error
137
+ };
138
+ }
139
+ };
@@ -0,0 +1 @@
1
+ export * from './errorMapper';
@@ -0,0 +1 @@
1
+ export * from './useAuth';
@@ -0,0 +1,13 @@
1
+ import { useContext } from 'react';
2
+ import { AuthContext } from '../core/AuthContext';
3
+ import { AuthContextType } from '../types';
4
+
5
+ export const useAuth = (): AuthContextType => {
6
+ const context = useContext(AuthContext);
7
+
8
+ if (context === undefined) {
9
+ throw new Error('useAuth must be used within an AuthProvider');
10
+ }
11
+
12
+ return context;
13
+ };
package/src/index.ts ADDED
@@ -0,0 +1,12 @@
1
+ // src/index.ts
2
+
3
+ // We will uncomment these as we build them
4
+ export * from './core';
5
+ // export * from './providers';
6
+ export * from './components';
7
+ export * from './hooks';
8
+ export * from './errors';
9
+ export * from './types';
10
+
11
+ // Placeholder so the build doesn't fail right now
12
+ export const SDK_VERSION = "1.0.0";
@@ -0,0 +1,43 @@
1
+ // src/types/auth.types.ts
2
+ import { AuthError } from './error.types';
3
+ import { AuthConfig } from './config.types'; // Import config type
4
+
5
+ // The specific states requested in the task
6
+ export enum AuthStatus {
7
+ AUTHENTICATED = 'AUTHENTICATED',
8
+ UNAUTHENTICATED = 'UNAUTHENTICATED',
9
+ TOKEN_EXPIRED = 'TOKEN_EXPIRED',
10
+ LOADING = 'LOADING', // Helpful for UI spinners
11
+ }
12
+
13
+ export interface User {
14
+ uid: string;
15
+ email: string | null;
16
+ displayName: string | null;
17
+ photoURL: string | null;
18
+ emailVerified: boolean;
19
+ token?: string;
20
+ }
21
+
22
+ export interface AuthContextType {
23
+ user: User | null;
24
+ status: AuthStatus;
25
+
26
+ // ✅ NEW: Explicit loading state for easier UI handling
27
+ isLoading: boolean;
28
+
29
+ error: AuthError | null;
30
+
31
+ // ✅ NEW: Expose config so UI components can check feature flags (e.g. enableGoogle)
32
+ config: AuthConfig;
33
+
34
+ // Actions
35
+ signInWithEmail: (email: string, pass: string) => Promise<void>;
36
+ signUpWithEmail: (email: string, pass: string) => Promise<void>;
37
+ signInWithGoogle: () => Promise<void>;
38
+ signInWithApple: () => Promise<void>;
39
+ signOut: () => Promise<void>;
40
+
41
+ // Reset error state
42
+ clearError: () => void;
43
+ }
@@ -0,0 +1,46 @@
1
+ export interface AuthConfig {
2
+ // Firebase Configuration
3
+ apiKey: string;
4
+ authDomain: string;
5
+ projectId: string;
6
+ storageBucket?: string;
7
+ messagingSenderId?: string;
8
+ appId?: string;
9
+
10
+ // ✅ NEW: Allow developer to choose persistence strategy
11
+ // 'local' = Keep user logged in forever (Standard Mobile Behavior)
12
+ // 'memory' = Log user out when app closes (Banking App Behavior)
13
+ persistence?: 'local' | 'memory';
14
+
15
+ // Feature flags
16
+ enableGoogle?: boolean;
17
+ enableApple?: boolean;
18
+ enableEmail?: boolean;
19
+
20
+ // Google Sign-In Configuration
21
+ // Get this from Firebase Console > Authentication > Sign-in method > Google
22
+ googleWebClientId?: string;
23
+
24
+ // Optional: iOS Client ID (usually not needed, but available)
25
+ googleIOSClientId?: string;
26
+
27
+ ui?: {
28
+ enableGoogleAuth?: boolean; // Default: true
29
+ enableAppleAuth?: boolean; // Default: true
30
+ enableEmailAuth?: boolean; // Default: true
31
+ };
32
+
33
+ // ✅ NEW: Control the Password UI features
34
+ enablePasswordHints?: boolean; // Show the "8 chars, 1 number" checklist
35
+ }
36
+
37
+ export const DEFAULT_AUTH_CONFIG: Partial<AuthConfig> = {
38
+ persistence: 'local',
39
+ ui: {
40
+ enableGoogleAuth: true,
41
+ enableAppleAuth: true,
42
+ enableEmailAuth: true,
43
+ },
44
+
45
+ enablePasswordHints: true,
46
+ };
@@ -0,0 +1,31 @@
1
+ // src/types/error.types.ts
2
+
3
+ export enum AuthErrorCode {
4
+ INVALID_CREDENTIALS = 'auth/invalid-credentials',
5
+ USER_NOT_FOUND = 'auth/user-not-found',
6
+ EMAIL_ALREADY_IN_USE = 'auth/email-already-in-use',
7
+ WEAK_PASSWORD = 'auth/weak-password',
8
+ TOKEN_EXPIRED = 'auth/token-expired',
9
+ NETWORK_ERROR = 'auth/network-request-failed',
10
+ UNKNOWN = 'auth/unknown',
11
+ // Specific to SDK flow
12
+ CONFIG_ERROR = 'auth/configuration-error',
13
+ CANCELLED = 'auth/cancelled',
14
+
15
+ // Google Sign-In Errors
16
+ GOOGLE_SIGN_IN_CANCELLED = 'GOOGLE_SIGN_IN_CANCELLED',
17
+ GOOGLE_SIGN_IN_IN_PROGRESS = 'GOOGLE_SIGN_IN_IN_PROGRESS',
18
+ GOOGLE_PLAY_SERVICES_NOT_AVAILABLE = 'GOOGLE_PLAY_SERVICES_NOT_AVAILABLE',
19
+ GOOGLE_SIGN_IN_FAILED = 'GOOGLE_SIGN_IN_FAILED',
20
+
21
+ // Apple Sign-In Errors
22
+ APPLE_SIGN_IN_CANCELLED = 'APPLE_SIGN_IN_CANCELLED',
23
+ APPLE_SIGN_IN_FAILED = 'APPLE_SIGN_IN_FAILED',
24
+ APPLE_SIGN_IN_NOT_SUPPORTED = 'APPLE_SIGN_IN_NOT_SUPPORTED',
25
+ }
26
+
27
+ export interface AuthError {
28
+ code: AuthErrorCode;
29
+ message: string;
30
+ originalError?: any; // To store the raw Firebase error for debugging
31
+ }
@@ -0,0 +1,5 @@
1
+ // src/types/index.ts
2
+ export * from './auth.types';
3
+ export * from './config.types';
4
+ export * from './error.types';
5
+ export * from './ui.types';
@@ -0,0 +1,26 @@
1
+ import { ViewStyle, TextStyle } from 'react-native';
2
+
3
+ export interface AuthScreenStyles {
4
+ // ... existing styles (container, header, etc.)
5
+ container?: ViewStyle;
6
+ header?: ViewStyle;
7
+ footer?: ViewStyle;
8
+ title?: TextStyle;
9
+ subtitle?: TextStyle;
10
+ footerText?: TextStyle;
11
+ linkText?: TextStyle;
12
+ errorText?: TextStyle;
13
+ input?: TextStyle;
14
+ button?: ViewStyle;
15
+ buttonText?: TextStyle;
16
+ loadingIndicatorColor?: string;
17
+
18
+ // ✅ NEW: Password Specific Styles
19
+ inputContainer?: ViewStyle; // Wrapper for Input + Eye Button
20
+ eyeIcon?: TextStyle; // Style for the "Show/Hide" text
21
+
22
+ // Hint List Styles
23
+ hintContainer?: ViewStyle; // Wrapper for the list
24
+ hintText?: TextStyle; // The text of the requirement
25
+ hintTextMet?: TextStyle; // Style when requirement is met (e.g., green)
26
+ }
@@ -0,0 +1,20 @@
1
+ // src/utils/validation.ts
2
+
3
+ export const validateEmail = (email: string): string | null => {
4
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
5
+ if (!email) return "Email is required.";
6
+ if (!emailRegex.test(email)) return "Please enter a valid email address.";
7
+ return null;
8
+ };
9
+
10
+ export const validatePasswordLogin = (password: string): string | null => {
11
+ if (!password) return "Password is required.";
12
+ return null;
13
+ };
14
+
15
+ export const validatePasswordSignup = (password: string): string | null => {
16
+ if (!password) return "Password is required.";
17
+ if (password.length < 6) return "Password must be at least 6 characters.";
18
+ if (!/\d/.test(password)) return "Password must contain at least one number.";
19
+ return null;
20
+ };