@onairos/react-native 3.0.70 → 3.0.72

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 (47) 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 +66 -0
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/services/apiKeyService.js +325 -0
  12. package/lib/commonjs/services/apiKeyService.js.map +1 -0
  13. package/lib/commonjs/services/platformAuthService.js +104 -113
  14. package/lib/commonjs/services/platformAuthService.js.map +1 -1
  15. package/lib/module/components/Onairos.js +297 -158
  16. package/lib/module/components/Onairos.js.map +1 -1
  17. package/lib/module/components/OnairosButton.js +1 -1
  18. package/lib/module/components/OnairosButton.js.map +1 -1
  19. package/lib/module/components/UniversalOnboarding.js +6 -6
  20. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  21. package/lib/module/components/onboarding/OAuthWebView.js +188 -52
  22. package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
  23. package/lib/module/index.js +4 -1
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/module/services/apiKeyService.js +310 -0
  26. package/lib/module/services/apiKeyService.js.map +1 -0
  27. package/lib/module/services/platformAuthService.js +104 -113
  28. package/lib/module/services/platformAuthService.js.map +1 -1
  29. package/lib/typescript/components/Onairos.d.ts +6 -5
  30. package/lib/typescript/components/Onairos.d.ts.map +1 -1
  31. package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
  32. package/lib/typescript/index.d.ts +3 -2
  33. package/lib/typescript/index.d.ts.map +1 -1
  34. package/lib/typescript/services/apiKeyService.d.ts +48 -0
  35. package/lib/typescript/services/apiKeyService.d.ts.map +1 -0
  36. package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
  37. package/lib/typescript/types.d.ts +36 -3
  38. package/lib/typescript/types.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/Onairos.tsx +336 -184
  41. package/src/components/OnairosButton.tsx +1 -1
  42. package/src/components/UniversalOnboarding.tsx +6 -6
  43. package/src/components/onboarding/OAuthWebView.tsx +236 -71
  44. package/src/index.ts +19 -0
  45. package/src/services/apiKeyService.ts +325 -0
  46. package/src/services/platformAuthService.ts +111 -130
  47. package/src/types.ts +40 -3
@@ -32,6 +32,8 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
32
32
  }) => {
33
33
  const [isLoading, setIsLoading] = useState(true);
34
34
  const [error, setError] = useState<string | null>(null);
35
+ const [errorMessage, setErrorMessage] = useState<string>('');
36
+ const [isRetryable, setIsRetryable] = useState(true);
35
37
  const [retryCount, setRetryCount] = useState(0);
36
38
  const webViewRef = useRef<WebView>(null);
37
39
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -74,91 +76,140 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
74
76
  };
75
77
  }, []);
76
78
 
77
- const handleNavigationStateChange = (navState: any) => {
78
- console.log(`Navigation state changed for ${platform}:`, navState.url);
79
-
80
- // Don't process navigation changes while still loading the initial page
81
- if (isLoading) {
82
- return;
83
- }
84
-
85
- // Check for error states first
86
- if (navState.url.includes('error=') || navState.url.includes('access_denied')) {
87
- console.log('OAuth error detected:', navState.url);
88
- setError('Authentication was cancelled or failed. Please try again.');
79
+ const onNavigationStateChange = (navState: any) => {
80
+ const currentUrl = navState.url;
81
+ console.log('🌐 Navigation state changed:', {
82
+ url: currentUrl,
83
+ canGoBack: navState.canGoBack,
84
+ canGoForward: navState.canGoForward,
85
+ loading: navState.loading,
86
+ title: navState.title,
87
+ });
88
+
89
+ // Don't process if still loading
90
+ if (navState.loading) {
89
91
  return;
90
92
  }
91
-
92
- // Special handling for Onairos login page (existing account check)
93
- if (platform === 'onairos') {
94
- // Check if user successfully logged in to Onairos
95
- if (navState.url.includes('onairos.uk/Home') ||
96
- navState.url.includes('onairos.uk/dashboard') ||
97
- navState.url.includes('onairos.uk/profile')) {
98
- console.log('Onairos login successful - existing account detected');
93
+
94
+ // Check if this URL indicates OAuth completion
95
+ if (isOAuthComplete(currentUrl)) {
96
+ console.log('🎉 OAuth completion detected!');
97
+
98
+ // Extract the result
99
+ const result = extractOAuthResult(currentUrl);
100
+
101
+ if (result.success) {
102
+ console.log('✅ OAuth completed successfully:', result);
99
103
 
100
- // Clear timeout since login completed successfully
104
+ // Clear timeout
101
105
  if (timeoutRef.current) {
102
106
  clearTimeout(timeoutRef.current);
107
+ timeoutRef.current = null;
103
108
  }
104
109
 
105
- onSuccess('onairos_login_success');
106
- return;
107
- }
108
-
109
- // If still on login page, don't close
110
- if (navState.url.includes('onairos.uk/signin') ||
111
- navState.url.includes('onairos.uk/login')) {
112
- console.log('Still on Onairos login page, waiting for user to complete login');
113
- return;
110
+ // Call success callback
111
+ if (onSuccess && result.code) {
112
+ onSuccess(result.code);
113
+ }
114
+
115
+ // Close the WebView
116
+ if (onComplete) {
117
+ onComplete();
118
+ }
119
+ } else {
120
+ console.error('❌ OAuth failed:', result.error);
121
+
122
+ // Clear timeout
123
+ if (timeoutRef.current) {
124
+ clearTimeout(timeoutRef.current);
125
+ timeoutRef.current = null;
126
+ }
127
+
128
+ // Set error state
129
+ setError('OAuth authentication failed');
130
+ setErrorMessage(result.error || 'Authentication failed');
131
+ setIsRetryable(true);
114
132
  }
115
133
  }
116
134
 
117
- // For platform OAuth flows, only close when we get the FINAL redirect from Onairos backend
118
- // This happens AFTER the user has logged in and the backend has processed the OAuth callback
119
- const isFinalOAuthRedirect = (
120
- navState.url.includes('onairos.uk/Home') ||
121
- navState.url.includes('onairos.uk/home') ||
122
- navState.url.includes('onairos.uk/success') ||
123
- navState.url.includes('onairos.uk/dashboard') ||
124
- (navState.url.includes('onairos.uk') && navState.url.includes('complete'))
125
- );
126
-
127
- // Only close when we get the final redirect from Onairos backend
128
- if (isFinalOAuthRedirect) {
129
- console.log(`Final OAuth redirect detected for ${platform} - user has completed login`);
135
+ // Additional check for Gmail specific patterns
136
+ if (platform === 'email' || platform === 'gmail') {
137
+ const gmailPatterns = [
138
+ 'onairos.uk/Home',
139
+ 'onairos.uk/home',
140
+ 'https://onairos.uk/Home',
141
+ 'https://onairos.uk/home',
142
+ ];
130
143
 
131
- // Clear timeout since OAuth completed successfully
132
- if (timeoutRef.current) {
133
- clearTimeout(timeoutRef.current);
134
- }
135
-
136
- onSuccess('oauth_complete');
137
-
138
- // Close the OAuth window after a short delay
139
- setTimeout(() => {
140
- if (onComplete) {
141
- console.log('Calling onComplete to close OAuth window');
142
- onComplete();
144
+ for (const pattern of gmailPatterns) {
145
+ if (currentUrl.includes(pattern)) {
146
+ console.log('✅ Gmail OAuth success detected via home page redirect');
147
+
148
+ // Clear timeout
149
+ if (timeoutRef.current) {
150
+ clearTimeout(timeoutRef.current);
151
+ timeoutRef.current = null;
152
+ }
153
+
154
+ // Call success callback with Gmail-specific code
155
+ if (onSuccess) {
156
+ onSuccess('gmail_success');
157
+ }
158
+
159
+ // Close the WebView
160
+ if (onComplete) {
161
+ onComplete();
162
+ }
163
+
164
+ return;
165
+ }
143
166
  }
144
- }, 1500);
145
- return;
146
167
  }
147
168
 
148
- // Log intermediate steps but don't close the WebView
149
- if (navState.url.includes('/callback') || navState.url.includes('code=')) {
150
- console.log(`OAuth callback detected for ${platform}, but waiting for final redirect from Onairos backend`);
151
- // Don't close here - wait for the final redirect
152
- return;
153
- }
169
+ // Check for error URLs
170
+ const errorPatterns = [
171
+ 'error=',
172
+ 'error_description=',
173
+ 'access_denied',
174
+ 'user_cancelled',
175
+ 'cancelled',
176
+ 'denied',
177
+ ];
154
178
 
155
- // Log other navigation for debugging
156
- console.log(`${platform} OAuth navigation:`, navState.url);
179
+ for (const pattern of errorPatterns) {
180
+ if (currentUrl.includes(pattern)) {
181
+ console.log('❌ OAuth error detected in URL:', pattern);
182
+
183
+ // Clear timeout
184
+ if (timeoutRef.current) {
185
+ clearTimeout(timeoutRef.current);
186
+ timeoutRef.current = null;
187
+ }
188
+
189
+ // Parse error details
190
+ try {
191
+ const urlObj = new URL(currentUrl);
192
+ const params = new URLSearchParams(urlObj.search);
193
+ const errorDescription = params.get('error_description') || params.get('error') || 'Authentication failed';
194
+
195
+ setError('OAuth authentication failed');
196
+ setErrorMessage(errorDescription);
197
+ setIsRetryable(true);
198
+ } catch (parseError) {
199
+ setError('OAuth authentication failed');
200
+ setErrorMessage('Authentication failed');
201
+ setIsRetryable(true);
202
+ }
203
+
204
+ return;
205
+ }
206
+ }
157
207
  };
158
208
 
159
209
  const handleLoadEnd = () => {
160
210
  setIsLoading(false);
161
211
  setError(null);
212
+ setErrorMessage('');
162
213
  };
163
214
 
164
215
  const handleError = (syntheticEvent: any) => {
@@ -272,6 +323,8 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
272
323
  const handleRetry = () => {
273
324
  console.log('Manual retry requested');
274
325
  setError(null);
326
+ setErrorMessage('');
327
+ setIsRetryable(true);
275
328
  setIsLoading(true);
276
329
  setRetryCount(0);
277
330
 
@@ -320,6 +373,116 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
320
373
  }
321
374
  };
322
375
 
376
+ // Check if URL indicates OAuth completion
377
+ const isOAuthComplete = (url: string): boolean => {
378
+ // Gmail OAuth completion patterns
379
+ const gmailSuccessPatterns = [
380
+ 'https://onairos.uk/Home',
381
+ 'https://onairos.uk/home',
382
+ 'onairos.uk/Home',
383
+ 'onairos.uk/home',
384
+ process.env.APP_HOME_URL,
385
+ ].filter(Boolean);
386
+
387
+ // Check for success redirect patterns
388
+ for (const pattern of gmailSuccessPatterns) {
389
+ if (url.includes(pattern)) {
390
+ console.log('✅ OAuth success detected via redirect to:', pattern);
391
+ return true;
392
+ }
393
+ }
394
+
395
+ // Check for traditional OAuth callback patterns
396
+ const callbackPatterns = [
397
+ 'code=',
398
+ 'access_token=',
399
+ 'oauth_token=',
400
+ 'authorization_code=',
401
+ 'auth_code=',
402
+ 'token=',
403
+ 'callback',
404
+ 'success',
405
+ 'complete',
406
+ 'connected',
407
+ 'authorized',
408
+ ];
409
+
410
+ for (const pattern of callbackPatterns) {
411
+ if (url.includes(pattern)) {
412
+ console.log('✅ OAuth success detected via callback pattern:', pattern);
413
+ return true;
414
+ }
415
+ }
416
+
417
+ // Check for error patterns
418
+ const errorPatterns = [
419
+ 'error=',
420
+ 'error_description=',
421
+ 'oauth_error=',
422
+ 'auth_error=',
423
+ 'access_denied',
424
+ 'user_cancelled',
425
+ 'cancelled',
426
+ 'denied',
427
+ ];
428
+
429
+ for (const pattern of errorPatterns) {
430
+ if (url.includes(pattern)) {
431
+ console.log('❌ OAuth error detected via pattern:', pattern);
432
+ return false;
433
+ }
434
+ }
435
+
436
+ return false;
437
+ };
438
+
439
+ // Extract OAuth result from URL
440
+ const extractOAuthResult = (url: string): { success: boolean; code?: string; error?: string } => {
441
+ try {
442
+ const urlObj = new URL(url);
443
+ const params = new URLSearchParams(urlObj.search);
444
+
445
+ // Check for error first
446
+ const error = params.get('error') || params.get('error_description') || params.get('oauth_error');
447
+ if (error) {
448
+ return { success: false, error };
449
+ }
450
+
451
+ // Check for success indicators
452
+ const code = params.get('code') || params.get('authorization_code') || params.get('auth_code');
453
+ const accessToken = params.get('access_token') || params.get('oauth_token') || params.get('token');
454
+
455
+ if (code || accessToken) {
456
+ return { success: true, code: code || accessToken };
457
+ }
458
+
459
+ // Check for success redirect to home page (Gmail pattern)
460
+ const gmailSuccessPatterns = [
461
+ 'https://onairos.uk/Home',
462
+ 'https://onairos.uk/home',
463
+ 'onairos.uk/Home',
464
+ 'onairos.uk/home',
465
+ ];
466
+
467
+ for (const pattern of gmailSuccessPatterns) {
468
+ if (url.includes(pattern)) {
469
+ console.log('✅ Gmail OAuth success detected via home page redirect');
470
+ return { success: true, code: 'gmail_home_redirect' };
471
+ }
472
+ }
473
+
474
+ // If we reached here and isOAuthComplete returned true, assume success
475
+ if (isOAuthComplete(url)) {
476
+ return { success: true, code: 'oauth_complete' };
477
+ }
478
+
479
+ return { success: false, error: 'OAuth completion not detected' };
480
+ } catch (error) {
481
+ console.error('Error parsing OAuth URL:', error);
482
+ return { success: false, error: 'Invalid OAuth callback URL' };
483
+ }
484
+ };
485
+
323
486
  if (error) {
324
487
  return (
325
488
  <SafeAreaView style={styles.container}>
@@ -340,7 +503,7 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
340
503
  <View style={styles.errorContainer}>
341
504
  <Icon name="error-outline" size={48} color="#FF6B6B" />
342
505
  <Text style={styles.errorTitle}>Connection Error</Text>
343
- <Text style={styles.errorMessage}>{error}</Text>
506
+ <Text style={styles.errorMessage}>{errorMessage || error}</Text>
344
507
 
345
508
  {/* Help text based on error type */}
346
509
  {error.includes('internet') || error.includes('network') ? (
@@ -375,10 +538,12 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
375
538
  )}
376
539
 
377
540
  <View style={styles.buttonContainer}>
378
- <TouchableOpacity style={styles.retryButton} onPress={handleRetry}>
379
- <Icon name="refresh" size={20} color="#fff" style={styles.buttonIcon} />
380
- <Text style={styles.retryButtonText}>Retry</Text>
381
- </TouchableOpacity>
541
+ {isRetryable && (
542
+ <TouchableOpacity style={styles.retryButton} onPress={handleRetry}>
543
+ <Icon name="refresh" size={20} color="#fff" style={styles.buttonIcon} />
544
+ <Text style={styles.retryButtonText}>Retry</Text>
545
+ </TouchableOpacity>
546
+ )}
382
547
  <TouchableOpacity style={styles.browserButton} onPress={handleOpenInBrowser}>
383
548
  <Icon name="open-in-browser" size={20} color="#666" style={styles.buttonIcon} />
384
549
  <Text style={styles.browserButtonText}>Open in Browser</Text>
@@ -428,7 +593,7 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
428
593
  <WebView
429
594
  ref={webViewRef}
430
595
  source={{ uri: url }}
431
- onNavigationStateChange={handleNavigationStateChange}
596
+ onNavigationStateChange={onNavigationStateChange}
432
597
  onLoadEnd={handleLoadEnd}
433
598
  onError={handleError}
434
599
  onHttpError={(syntheticEvent) => {
package/src/index.ts CHANGED
@@ -14,11 +14,17 @@ export type {
14
14
  TrainingModalProps,
15
15
  OAuthWebViewProps,
16
16
  PlatformConfig,
17
+ PlatformAuthConfig,
17
18
  ApiResponse,
18
19
  CredentialsResult,
19
20
  OverlayProps,
20
21
  BiometricOptions,
21
22
  PinRequirements,
23
+ OnairosConfig,
24
+ ApiKeyConfig,
25
+ ApiKeyValidationResult,
26
+ TestModeOptions,
27
+ DataRequest,
22
28
  } from './types';
23
29
 
24
30
  export type { EmailVerificationModalProps } from './components/EmailVerificationModal';
@@ -80,8 +86,21 @@ export {
80
86
  verifyEmailCode,
81
87
  checkEmailVerificationStatus,
82
88
  disconnectPlatform,
89
+ initiateOAuth,
83
90
  } from './services/platformAuthService';
84
91
 
92
+ // API Key Service - Initialize SDK with API key
93
+ export {
94
+ initializeApiKey,
95
+ validateApiKey,
96
+ getApiConfig,
97
+ getApiKey,
98
+ isApiKeyInitialized,
99
+ resetApiKeyService,
100
+ getAuthHeaders,
101
+ makeAuthenticatedRequest,
102
+ } from './services/apiKeyService';
103
+
85
104
  // Export API and Services
86
105
  export { onairosApi } from './api';
87
106
  export { OAuthService } from './services/oauthService';