@onairos/react-native 3.0.71 โ†’ 3.0.73

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 (65) hide show
  1. package/lib/commonjs/components/Onairos.js +294 -155
  2. package/lib/commonjs/components/Onairos.js.map +1 -1
  3. package/lib/commonjs/components/OnairosButton.js +1 -1
  4. package/lib/commonjs/components/OnairosButton.js.map +1 -1
  5. package/lib/commonjs/components/UniversalOnboarding.js +6 -6
  6. package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
  7. package/lib/commonjs/components/onboarding/OAuthWebView.js +188 -52
  8. package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
  9. package/lib/commonjs/index.js +25 -440
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/services/apiKeyService.js +404 -0
  12. package/lib/commonjs/services/apiKeyService.js.map +1 -0
  13. package/lib/commonjs/services/platformAuthService.js +318 -113
  14. package/lib/commonjs/services/platformAuthService.js.map +1 -1
  15. package/lib/commonjs/types/index.js +4 -0
  16. package/lib/commonjs/types.js +12 -0
  17. package/lib/commonjs/types.js.map +1 -1
  18. package/lib/commonjs/utils/programmaticFlow.js +117 -0
  19. package/lib/commonjs/utils/programmaticFlow.js.map +1 -0
  20. package/lib/module/components/Onairos.js +297 -158
  21. package/lib/module/components/Onairos.js.map +1 -1
  22. package/lib/module/components/OnairosButton.js +1 -1
  23. package/lib/module/components/OnairosButton.js.map +1 -1
  24. package/lib/module/components/UniversalOnboarding.js +6 -6
  25. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  26. package/lib/module/components/onboarding/OAuthWebView.js +188 -52
  27. package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
  28. package/lib/module/index.js +17 -61
  29. package/lib/module/index.js.map +1 -1
  30. package/lib/module/services/apiKeyService.js +389 -0
  31. package/lib/module/services/apiKeyService.js.map +1 -0
  32. package/lib/module/services/platformAuthService.js +311 -111
  33. package/lib/module/services/platformAuthService.js.map +1 -1
  34. package/lib/module/types/index.js +1 -1
  35. package/lib/module/types.js +8 -0
  36. package/lib/module/types.js.map +1 -1
  37. package/lib/module/utils/programmaticFlow.js +111 -0
  38. package/lib/module/utils/programmaticFlow.js.map +1 -0
  39. package/lib/typescript/components/Onairos.d.ts +2 -29
  40. package/lib/typescript/components/Onairos.d.ts.map +1 -1
  41. package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
  42. package/lib/typescript/index.d.ts +10 -39
  43. package/lib/typescript/index.d.ts.map +1 -1
  44. package/lib/typescript/services/apiKeyService.d.ts +66 -0
  45. package/lib/typescript/services/apiKeyService.d.ts.map +1 -0
  46. package/lib/typescript/services/platformAuthService.d.ts +26 -0
  47. package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
  48. package/lib/typescript/types/index.d.ts +144 -78
  49. package/lib/typescript/types/index.d.ts.map +1 -1
  50. package/lib/typescript/types.d.ts +92 -3
  51. package/lib/typescript/types.d.ts.map +1 -1
  52. package/lib/typescript/utils/programmaticFlow.d.ts +23 -0
  53. package/lib/typescript/utils/programmaticFlow.d.ts.map +1 -0
  54. package/package.json +1 -1
  55. package/src/components/Onairos.tsx +330 -207
  56. package/src/components/OnairosButton.tsx +1 -1
  57. package/src/components/UniversalOnboarding.tsx +6 -6
  58. package/src/components/onboarding/OAuthWebView.tsx +236 -71
  59. package/src/index.ts +25 -115
  60. package/src/services/apiKeyService.ts +401 -0
  61. package/src/services/platformAuthService.ts +363 -126
  62. package/src/types/index.d.ts +110 -0
  63. package/src/types/index.ts +148 -74
  64. package/src/types.ts +99 -3
  65. package/src/utils/programmaticFlow.ts +113 -0
@@ -1,29 +1,62 @@
1
1
  import { Platform, Linking } from 'react-native';
2
2
  import AsyncStorage from '@react-native-async-storage/async-storage';
3
+ import type { PlatformAuthConfig } from '../types';
4
+ import { makeAuthenticatedRequest, getApiConfig } from './apiKeyService';
3
5
 
4
- // Define types for platform auth configuration
5
- interface PlatformAuthConfig {
6
- hasNativeSDK: boolean;
7
- nativeSDKPackage?: string;
8
- authEndpoint: string;
9
- color: string;
10
- clientId?: string;
11
- redirectUri?: string;
12
- scope?: string;
13
- responseType?: string;
14
- }
6
+ // ๐Ÿ”‘ CRITICAL: Initialize API key service for authentication
7
+ let isApiKeyInitialized = false;
8
+
9
+ /**
10
+ * Initialize the API key service with the admin key for testing
11
+ * This ensures all API requests include proper authentication headers
12
+ */
13
+ export const initializePlatformAuthService = async (): Promise<void> => {
14
+ if (isApiKeyInitialized) {
15
+ console.log('๐Ÿ”‘ API key service already initialized');
16
+ return;
17
+ }
18
+
19
+ try {
20
+ // Import the initialization function
21
+ const { initializeApiKey, ADMIN_API_KEY } = await import('./apiKeyService');
22
+
23
+ // Initialize with admin key for testing/development
24
+ await initializeApiKey({
25
+ apiKey: ADMIN_API_KEY, // 'OnairosIsAUnicorn2025'
26
+ environment: 'development',
27
+ enableLogging: true,
28
+ timeout: 30000,
29
+ });
30
+
31
+ isApiKeyInitialized = true;
32
+ console.log('โœ… Platform auth service initialized with admin key');
33
+ } catch (error) {
34
+ console.error('โŒ Failed to initialize platform auth service:', error);
35
+ throw error;
36
+ }
37
+ };
38
+
39
+ /**
40
+ * Ensure API key is initialized before making authenticated requests
41
+ */
42
+ const ensureApiKeyInitialized = async (): Promise<void> => {
43
+ if (!isApiKeyInitialized) {
44
+ console.log('๐Ÿ”‘ API key not initialized, initializing now...');
45
+ await initializePlatformAuthService();
46
+ }
47
+ };
15
48
 
16
49
  // Configuration for each platform's authentication
17
50
  let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
18
51
  instagram: {
19
52
  hasNativeSDK: false, // Instagram uses OAuth WebView flow
20
- authEndpoint: 'https://api2.onairos.uk/instagram/authorize',
53
+ authEndpoint: '/instagram/authorize',
21
54
  color: '#E1306C',
22
55
  },
23
56
  youtube: {
24
57
  hasNativeSDK: true, // Native Google Sign-In SDK enabled
25
58
  nativeSDKPackage: '@react-native-google-signin/google-signin',
26
- authEndpoint: 'https://api2.onairos.uk/youtube/authorize',
59
+ authEndpoint: '/youtube/authorize',
27
60
  color: '#FF0000',
28
61
  clientId: '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com',
29
62
  redirectUri: 'onairosevents://auth/callback',
@@ -32,17 +65,17 @@ let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
32
65
  },
33
66
  reddit: {
34
67
  hasNativeSDK: false,
35
- authEndpoint: 'https://api2.onairos.uk/reddit/authorize',
68
+ authEndpoint: '/reddit/authorize',
36
69
  color: '#FF4500',
37
70
  },
38
71
  pinterest: {
39
72
  hasNativeSDK: false,
40
- authEndpoint: 'https://api2.onairos.uk/pinterest/authorize',
73
+ authEndpoint: '/pinterest/authorize',
41
74
  color: '#E60023',
42
75
  },
43
76
  email: {
44
77
  hasNativeSDK: false,
45
- authEndpoint: 'https://api2.onairos.uk/gmail/authorize',
78
+ authEndpoint: '/gmail/authorize',
46
79
  color: '#4285F4',
47
80
  },
48
81
  };
@@ -123,34 +156,12 @@ export const initiateOAuth = async (platform: string, username: string, appName?
123
156
 
124
157
  console.log('๐Ÿ“ค Sending Instagram OAuth request:', jsonData);
125
158
 
126
- const controller = new AbortController();
127
- const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
128
-
129
- let response: Response;
130
- try {
131
- response = await fetch('https://api2.onairos.uk/instagram/authorize', {
132
- method: 'POST',
133
- headers: {
134
- 'Content-Type': 'application/json',
135
- 'User-Agent': 'OnairosReactNative/1.0',
136
- },
137
- body: JSON.stringify(jsonData),
138
- signal: controller.signal,
139
- });
140
- } catch (fetchError) {
141
- clearTimeout(timeoutId);
142
-
143
- if (fetchError.name === 'AbortError') {
144
- throw new Error(`Request timeout: Instagram OAuth server took too long to respond`);
145
- }
146
-
147
- throw new Error(`Network error: ${fetchError.message || 'Failed to connect to Instagram OAuth server'}`);
148
- }
149
-
150
- clearTimeout(timeoutId);
159
+ const response = await makeAuthenticatedRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
160
+ method: 'POST',
161
+ body: JSON.stringify(jsonData),
162
+ });
151
163
 
152
164
  console.log('๐Ÿ“ก Instagram OAuth response status:', response.status);
153
- console.log('๐Ÿ“ก Instagram OAuth response headers:', response.headers);
154
165
 
155
166
  if (!response.ok) {
156
167
  const errorText = await response.text();
@@ -187,35 +198,13 @@ export const initiateOAuth = async (platform: string, username: string, appName?
187
198
 
188
199
  console.log(`๐Ÿ“ค Sending ${platform} OAuth request:`, jsonData);
189
200
 
190
- // Make the request to get the OAuth URL with enhanced error handling
191
- const controller = new AbortController();
192
- const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
193
-
194
- let response: Response;
195
- try {
196
- response = await fetch(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
197
- method: 'POST',
198
- headers: {
199
- 'Content-Type': 'application/json',
200
- 'User-Agent': 'OnairosReactNative/1.0',
201
- },
202
- body: JSON.stringify(jsonData),
203
- signal: controller.signal,
204
- });
205
- } catch (fetchError) {
206
- clearTimeout(timeoutId);
207
-
208
- if (fetchError.name === 'AbortError') {
209
- throw new Error(`Request timeout: ${platform} OAuth server took too long to respond`);
210
- }
211
-
212
- throw new Error(`Network error: ${fetchError.message || 'Failed to connect to OAuth server'}`);
213
- }
214
-
215
- clearTimeout(timeoutId);
201
+ // Make the authenticated request to get the OAuth URL
202
+ const response = await makeAuthenticatedRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
203
+ method: 'POST',
204
+ body: JSON.stringify(jsonData),
205
+ });
216
206
 
217
207
  console.log(`๐Ÿ“ก ${platform} OAuth response status:`, response.status);
218
- console.log(`๐Ÿ“ก ${platform} OAuth response headers:`, response.headers);
219
208
 
220
209
  if (!response.ok) {
221
210
  const errorText = await response.text();
@@ -834,45 +823,83 @@ export const requestEmailVerification = async (email: string, testMode = false):
834
823
  success: boolean;
835
824
  message?: string;
836
825
  error?: string;
826
+ requestId?: string;
837
827
  }> => {
838
828
  try {
839
829
  console.log('๐Ÿ“ง Requesting email verification for:', email);
840
- console.log('๐Ÿ” Test mode:', testMode);
841
-
842
- // Use the correct endpoint: /email/verify
843
- const response = await fetch('https://api2.onairos.uk/email/verify', {
844
- method: 'POST',
845
- headers: {
846
- 'Content-Type': 'application/json',
847
- },
848
- body: JSON.stringify({ email }),
849
- });
830
+ console.log('๐Ÿงช Test mode:', testMode);
850
831
 
851
- const result = await response.json();
832
+ if (!email || !email.includes('@')) {
833
+ return {
834
+ success: false,
835
+ error: 'Valid email address is required',
836
+ };
837
+ }
852
838
 
853
- if (response.ok && result.success) {
854
- console.log('โœ… Email verification requested successfully');
839
+ // In test mode, always return success with mock request ID
840
+ if (testMode) {
841
+ console.log('๐Ÿงช Test mode: Always returning success with mock request ID');
842
+ const mockRequestId = 'test-request-' + Date.now();
855
843
 
856
- const message = testMode
857
- ? 'Verification code sent to your email (testing mode: any code accepted)'
858
- : result.message || 'Verification code sent to your email';
844
+ // Store request info for tracking
845
+ await AsyncStorage.setItem('email_verification_request_id', mockRequestId);
846
+ await AsyncStorage.setItem('email_verification_request_email', email);
859
847
 
860
848
  return {
861
849
  success: true,
862
- message,
850
+ message: 'Email verification sent successfully (test mode)',
851
+ requestId: mockRequestId,
863
852
  };
864
- } else {
865
- console.error('โŒ Email verification request failed:', result.error);
853
+ }
854
+
855
+ // Production mode: Make real API call with API key authentication
856
+ try {
857
+ // ๐Ÿ”‘ Ensure API key is initialized before making authenticated requests
858
+ await ensureApiKeyInitialized();
859
+
860
+ const response = await makeAuthenticatedRequest('/email/verification', {
861
+ method: 'POST',
862
+ body: JSON.stringify({
863
+ email,
864
+ action: 'request',
865
+ }),
866
+ });
867
+
868
+ const result = await response.json();
869
+ console.log('๐Ÿ“ก Email verification API response:', result);
870
+
871
+ if (response.ok && result.success) {
872
+ console.log('โœ… Email verification request sent');
873
+
874
+ // Store request info for tracking
875
+ const requestId = result.requestId || result.id || ('req-' + Date.now());
876
+ await AsyncStorage.setItem('email_verification_request_id', requestId);
877
+ await AsyncStorage.setItem('email_verification_request_email', email);
878
+
879
+ return {
880
+ success: true,
881
+ message: result.message || 'Email verification sent successfully',
882
+ requestId: requestId,
883
+ };
884
+ } else {
885
+ console.error('โŒ Email verification request failed:', result.error);
886
+ return {
887
+ success: false,
888
+ error: result.error || 'Failed to send verification email',
889
+ };
890
+ }
891
+ } catch (apiError) {
892
+ console.error('โŒ Email verification API call failed:', apiError);
866
893
  return {
867
894
  success: false,
868
- error: result.error || 'Failed to send verification code',
895
+ error: 'Network error while sending verification email',
869
896
  };
870
897
  }
871
898
  } catch (error) {
872
899
  console.error('โŒ Email verification request error:', error);
873
900
  return {
874
901
  success: false,
875
- error: error instanceof Error ? error.message : 'Network error',
902
+ error: error instanceof Error ? error.message : 'Unknown error',
876
903
  };
877
904
  }
878
905
  };
@@ -882,31 +909,57 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
882
909
  message?: string;
883
910
  error?: string;
884
911
  existingUser?: boolean;
912
+ jwtToken?: string;
885
913
  }> => {
886
914
  try {
887
915
  console.log('๐Ÿ” Verifying email code for:', email);
888
- console.log('๐Ÿ” Test mode:', testMode);
916
+ console.log('๐Ÿ”‘ Code length:', code.length);
917
+ console.log('๐Ÿงช Test mode:', testMode);
918
+
919
+ if (!email || !email.includes('@')) {
920
+ return {
921
+ success: false,
922
+ error: 'Valid email address is required',
923
+ };
924
+ }
889
925
 
890
- // In test mode, accept any code
926
+ if (!code || code.length < 4) {
927
+ return {
928
+ success: false,
929
+ error: 'Valid verification code is required',
930
+ };
931
+ }
932
+
933
+ // In test mode, always return success with mock JWT token
891
934
  if (testMode) {
892
- console.log('๐Ÿงช Test mode: All codes will pass through');
893
- // Simulate 30% chance of existing user in test mode
894
- const simulateExistingUser = Math.random() < 0.3;
935
+ console.log('๐Ÿงช Test mode: Always returning success with mock JWT token');
936
+ const mockToken = 'test-jwt-token-' + Date.now();
937
+
938
+ // Store mock token for API requests
939
+ await AsyncStorage.setItem('email_verification_token', mockToken);
940
+ await AsyncStorage.setItem('onairos_jwt_token', mockToken);
941
+ await AsyncStorage.setItem('email_verification_email', email);
942
+
895
943
  return {
896
944
  success: true,
897
- message: 'Email verified successfully (test mode: all codes accepted)',
898
- existingUser: simulateExistingUser,
945
+ message: 'Email verification successful (test mode)',
946
+ existingUser: false,
947
+ jwtToken: mockToken,
899
948
  };
900
949
  }
901
950
 
902
- // Production mode: Make real API call with proper validation
951
+ // Production mode: Make real API call with API key authentication
903
952
  try {
904
- const response = await fetch('https://api2.onairos.uk/email/verify/confirm', {
953
+ // ๐Ÿ”‘ Ensure API key is initialized before making authenticated requests
954
+ await ensureApiKeyInitialized();
955
+
956
+ const response = await makeAuthenticatedRequest('/email/verification', {
905
957
  method: 'POST',
906
- headers: {
907
- 'Content-Type': 'application/json',
908
- },
909
- body: JSON.stringify({ email, code }),
958
+ body: JSON.stringify({
959
+ email,
960
+ code,
961
+ action: 'verify',
962
+ }),
910
963
  });
911
964
 
912
965
  const result = await response.json();
@@ -914,23 +967,40 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
914
967
 
915
968
  if (response.ok && result.success) {
916
969
  console.log('โœ… Email verification successful');
970
+
971
+ // ๐ŸŽซ CRITICAL: Store JWT token from email verification response
972
+ const jwtToken = result.token || result.jwtToken || result.jwt || result.authToken;
973
+
974
+ if (jwtToken) {
975
+ console.log('๐ŸŽซ Storing JWT token from email verification response');
976
+ await AsyncStorage.setItem('email_verification_token', jwtToken);
977
+ await AsyncStorage.setItem('onairos_jwt_token', jwtToken);
978
+ await AsyncStorage.setItem('enoch_token', jwtToken);
979
+ await AsyncStorage.setItem('auth_token', jwtToken);
980
+ await AsyncStorage.setItem('email_verification_email', email);
981
+ await AsyncStorage.setItem('token_timestamp', Date.now().toString());
982
+ } else {
983
+ console.warn('โš ๏ธ No JWT token received from email verification API');
984
+ }
985
+
917
986
  return {
918
987
  success: true,
919
- message: result.message || 'Email verified successfully',
920
- existingUser: result.existingUser || false, // Backend should return this flag
988
+ message: result.message || 'Email verification successful',
989
+ existingUser: result.existingUser || false,
990
+ jwtToken: jwtToken,
921
991
  };
922
992
  } else {
923
993
  console.error('โŒ Email verification failed:', result.error);
924
994
  return {
925
995
  success: false,
926
- error: result.error || 'Invalid verification code',
996
+ error: result.error || 'Email verification failed',
927
997
  };
928
998
  }
929
999
  } catch (apiError) {
930
1000
  console.error('โŒ Email verification API call failed:', apiError);
931
1001
  return {
932
1002
  success: false,
933
- error: 'Network error during verification',
1003
+ error: 'Network error during email verification',
934
1004
  };
935
1005
  }
936
1006
  } catch (error) {
@@ -962,13 +1032,13 @@ export const checkEmailVerificationStatus = async (email: string, testMode = fal
962
1032
  };
963
1033
  }
964
1034
 
965
- // Production mode: Make real API call
1035
+ // Production mode: Make real API call with API key authentication
966
1036
  try {
967
- const response = await fetch(`https://api2.onairos.uk/email/verify/status/${encodeURIComponent(email)}`, {
1037
+ // ๐Ÿ”‘ Ensure API key is initialized before making authenticated requests
1038
+ await ensureApiKeyInitialized();
1039
+
1040
+ const response = await makeAuthenticatedRequest(`/email/verify/status/${encodeURIComponent(email)}`, {
968
1041
  method: 'GET',
969
- headers: {
970
- 'Content-Type': 'application/json',
971
- },
972
1042
  });
973
1043
 
974
1044
  const result = await response.json();
@@ -1014,41 +1084,208 @@ export const disconnectPlatform = async (platform: string, username: string): Pr
1014
1084
  error?: string;
1015
1085
  }> => {
1016
1086
  try {
1017
- console.log(`๐Ÿ”Œ Disconnecting ${platform} for user:`, username);
1087
+ console.log('๐Ÿ”Œ Disconnecting platform:', platform, 'for user:', username);
1088
+
1089
+ if (!platform || !username) {
1090
+ return {
1091
+ success: false,
1092
+ error: 'Platform and username are required',
1093
+ };
1094
+ }
1095
+
1096
+ // Make authenticated API call to disconnect platform
1097
+ const response = await makeAuthenticatedRequest('/revoke', {
1098
+ method: 'POST',
1099
+ body: JSON.stringify({
1100
+ platform,
1101
+ username,
1102
+ }),
1103
+ });
1104
+
1105
+ const result = await response.json();
1106
+ console.log('๐Ÿ“ก Platform disconnect API response:', result);
1107
+
1108
+ if (response.ok && result.success) {
1109
+ console.log('โœ… Platform disconnected successfully');
1110
+ return {
1111
+ success: true,
1112
+ message: result.message || 'Platform disconnected successfully',
1113
+ };
1114
+ } else {
1115
+ console.error('โŒ Platform disconnect failed:', result.error);
1116
+ return {
1117
+ success: false,
1118
+ error: result.error || 'Failed to disconnect platform',
1119
+ };
1120
+ }
1121
+ } catch (error) {
1122
+ console.error('โŒ Platform disconnect error:', error);
1123
+ return {
1124
+ success: false,
1125
+ error: error instanceof Error ? error.message : 'Platform disconnect failed',
1126
+ };
1127
+ }
1128
+ };
1129
+
1130
+ /**
1131
+ * ๐Ÿ” STORE PIN AFTER BIOMETRIC AUTHENTICATION
1132
+ * Send PIN separately to /store-pin/web endpoint after biometric Face ID verification
1133
+ */
1134
+ export const storePinAfterBiometric = async (username: string, pin: string, jwtToken?: string): Promise<{
1135
+ success: boolean;
1136
+ message?: string;
1137
+ error?: string;
1138
+ }> => {
1139
+ try {
1140
+ console.log('๐Ÿ” Storing PIN after biometric authentication for user:', username);
1141
+ console.log('๐Ÿ”‘ PIN length:', pin.length);
1142
+ console.log('๐ŸŽซ JWT token provided:', !!jwtToken);
1143
+
1144
+ if (!username || !pin) {
1145
+ return {
1146
+ success: false,
1147
+ error: 'Username and PIN are required',
1148
+ };
1149
+ }
1150
+
1151
+ if (pin.length < 4) {
1152
+ return {
1153
+ success: false,
1154
+ error: 'PIN must be at least 4 digits',
1155
+ };
1156
+ }
1157
+
1158
+ // Get JWT token from storage if not provided
1159
+ let authToken = jwtToken;
1160
+ if (!authToken) {
1161
+ authToken = await AsyncStorage.getItem('onairos_jwt_token') ||
1162
+ await AsyncStorage.getItem('enoch_token') ||
1163
+ await AsyncStorage.getItem('auth_token') ||
1164
+ await AsyncStorage.getItem('email_verification_token');
1165
+ }
1166
+
1167
+ if (!authToken) {
1168
+ console.warn('โš ๏ธ No JWT token available for PIN storage');
1169
+ return {
1170
+ success: false,
1171
+ error: 'No authentication token available',
1172
+ };
1173
+ }
1174
+
1175
+ console.log('๐Ÿ“ค Sending PIN to /store-pin/web endpoint');
1018
1176
 
1019
- const response = await fetch('https://api2.onairos.uk/revoke', {
1177
+ // Make authenticated request to store PIN
1178
+ const response = await makeAuthenticatedRequest('/store-pin/web', {
1020
1179
  method: 'POST',
1021
1180
  headers: {
1022
- 'Content-Type': 'application/json',
1181
+ 'Authorization': `Bearer ${authToken}`,
1023
1182
  },
1024
1183
  body: JSON.stringify({
1025
- Info: {
1026
- connection: platform.charAt(0).toUpperCase() + platform.slice(1), // Capitalize platform name
1027
- username: username,
1028
- },
1184
+ username,
1185
+ pin,
1029
1186
  }),
1030
1187
  });
1031
1188
 
1189
+ console.log('๐Ÿ“ก PIN storage response status:', response.status);
1190
+
1191
+ if (!response.ok) {
1192
+ const errorText = await response.text();
1193
+ console.error('โŒ PIN storage failed:', errorText);
1194
+ return {
1195
+ success: false,
1196
+ error: `PIN storage failed: ${response.status} - ${errorText}`,
1197
+ };
1198
+ }
1199
+
1032
1200
  const result = await response.json();
1201
+ console.log('๐Ÿ“ฅ PIN storage response:', result);
1033
1202
 
1034
- if (response.ok && result.success) {
1035
- console.log(`โœ… ${platform} disconnected successfully`);
1203
+ if (result.success) {
1204
+ console.log('โœ… PIN stored successfully after biometric authentication');
1205
+
1206
+ // Store PIN locally for future use
1207
+ await AsyncStorage.setItem('user_pin_stored', 'true');
1208
+ await AsyncStorage.setItem('pin_storage_timestamp', Date.now().toString());
1209
+
1036
1210
  return {
1037
1211
  success: true,
1038
- message: result.message || `${platform} disconnected successfully`,
1212
+ message: result.message || 'PIN stored successfully',
1039
1213
  };
1040
1214
  } else {
1041
- console.error(`โŒ ${platform} disconnection failed:`, result.error);
1215
+ console.error('โŒ PIN storage API returned error:', result.error);
1042
1216
  return {
1043
1217
  success: false,
1044
- error: result.error || `Failed to disconnect ${platform}`,
1218
+ error: result.error || 'PIN storage failed',
1045
1219
  };
1046
1220
  }
1047
1221
  } catch (error) {
1048
- console.error(`โŒ ${platform} disconnection error:`, error);
1222
+ console.error('โŒ Error storing PIN after biometric authentication:', error);
1049
1223
  return {
1050
1224
  success: false,
1051
- error: error instanceof Error ? error.message : 'Network error',
1225
+ error: error instanceof Error ? error.message : 'PIN storage failed',
1052
1226
  };
1053
1227
  }
1054
1228
  };
1229
+
1230
+ /**
1231
+ * ๐ŸŽซ GET STORED JWT TOKEN
1232
+ * Helper function to retrieve stored JWT token from email verification or other sources
1233
+ */
1234
+ export const getStoredJwtToken = async (): Promise<string | null> => {
1235
+ try {
1236
+ console.log('๐ŸŽซ Retrieving stored JWT token...');
1237
+
1238
+ // Try different storage keys in order of preference
1239
+ const tokenSources = [
1240
+ 'email_verification_token',
1241
+ 'onairos_jwt_token',
1242
+ 'enoch_token',
1243
+ 'auth_token',
1244
+ ];
1245
+
1246
+ for (const source of tokenSources) {
1247
+ const token = await AsyncStorage.getItem(source);
1248
+ if (token && token.length > 20) {
1249
+ console.log(`โœ… JWT token found in ${source}:`, token.substring(0, 20) + '...');
1250
+ return token;
1251
+ }
1252
+ }
1253
+
1254
+ console.warn('โš ๏ธ No JWT token found in storage');
1255
+ return null;
1256
+ } catch (error) {
1257
+ console.error('โŒ Error retrieving JWT token:', error);
1258
+ return null;
1259
+ }
1260
+ };
1261
+
1262
+ /**
1263
+ * ๐ŸŽซ CLEAR STORED TOKENS
1264
+ * Helper function to clear all stored tokens (useful for logout)
1265
+ */
1266
+ export const clearStoredTokens = async (): Promise<void> => {
1267
+ try {
1268
+ console.log('๐Ÿงน Clearing all stored tokens...');
1269
+
1270
+ const tokenKeys = [
1271
+ 'email_verification_token',
1272
+ 'onairos_jwt_token',
1273
+ 'enoch_token',
1274
+ 'auth_token',
1275
+ 'email_verification_email',
1276
+ 'email_verification_request_id',
1277
+ 'email_verification_request_email',
1278
+ 'token_timestamp',
1279
+ 'user_pin_stored',
1280
+ 'pin_storage_timestamp',
1281
+ ];
1282
+
1283
+ await Promise.all(
1284
+ tokenKeys.map(key => AsyncStorage.removeItem(key))
1285
+ );
1286
+
1287
+ console.log('โœ… All tokens cleared successfully');
1288
+ } catch (error) {
1289
+ console.error('โŒ Error clearing tokens:', error);
1290
+ }
1291
+ };