@onairos/react-native 3.0.30 → 3.0.34

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 (31) hide show
  1. package/README.md +2 -0
  2. package/lib/commonjs/components/OnairosButton.js +12 -23
  3. package/lib/commonjs/components/OnairosButton.js.map +1 -1
  4. package/lib/commonjs/components/onboarding/OAuthWebView.js +104 -28
  5. package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/services/platformAuthService.js +48 -6
  8. package/lib/commonjs/services/platformAuthService.js.map +1 -1
  9. package/lib/module/components/OnairosButton.js +12 -23
  10. package/lib/module/components/OnairosButton.js.map +1 -1
  11. package/lib/module/components/onboarding/OAuthWebView.js +106 -30
  12. package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
  13. package/lib/module/index.js.map +1 -1
  14. package/lib/module/services/platformAuthService.js +48 -6
  15. package/lib/module/services/platformAuthService.js.map +1 -1
  16. package/lib/typescript/components/OnairosButton.d.ts +1 -1
  17. package/lib/typescript/components/OnairosButton.d.ts.map +1 -1
  18. package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
  19. package/lib/typescript/index.d.ts +2 -2
  20. package/lib/typescript/index.d.ts.map +1 -1
  21. package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
  22. package/lib/typescript/types/index.d.ts +8 -6
  23. package/lib/typescript/types/index.d.ts.map +1 -1
  24. package/lib/typescript/utils/onairosApi.d.ts +1 -1
  25. package/lib/typescript/utils/onairosApi.d.ts.map +1 -1
  26. package/package.json +3 -3
  27. package/src/components/OnairosButton.tsx +17 -29
  28. package/src/components/onboarding/OAuthWebView.tsx +97 -26
  29. package/src/index.ts +1 -1
  30. package/src/services/platformAuthService.ts +45 -5
  31. package/src/types/index.ts +9 -7
@@ -12,7 +12,7 @@ import {
12
12
  import { UniversalOnboarding } from './UniversalOnboarding';
13
13
  import { Overlay } from './Overlay';
14
14
  import { COLORS } from '../constants';
15
- import type { OnairosButtonProps } from '../types';
15
+ import type { OnairosButtonProps } from '../types/index';
16
16
  import { hasCredentials, getCredentials, deleteCredentials as clearCredentials } from '../utils/secureStorage';
17
17
  import { onairosApi } from '../api';
18
18
 
@@ -25,31 +25,26 @@ export interface OnairosButtonRef {
25
25
  * OnairosButton Component - A sign-in button similar to Google/Apple sign-in
26
26
  */
27
27
  export const OnairosButton = forwardRef<OnairosButtonRef, OnairosButtonProps>(({
28
+ AppName,
29
+ requestData,
28
30
  returnLink,
29
31
  prefillUrl,
30
- AppName,
31
32
  buttonType = 'normal',
32
- requestData,
33
33
  buttonWidth = 180,
34
34
  buttonHeight = 48,
35
35
  hasStroke = false,
36
36
  enabled = true,
37
37
  buttonForm = 'default',
38
+ auto = false,
38
39
  onRejection,
39
40
  onResolved,
40
41
  preCheck,
41
42
  color,
42
43
  swerv = false,
43
44
  debug = false,
44
- darkMode = false,
45
45
  preferredPlatform,
46
46
  testMode = false,
47
- autoFetch = false,
48
- inferenceData,
49
- textLayout,
50
- textColor: customTextColor,
51
- proofMode = false,
52
- webpageName,
47
+ darkMode = false,
53
48
  }, ref) => {
54
49
  const [showOnboarding, setShowOnboarding] = useState(false);
55
50
  const [showOverlay, setShowOverlay] = useState(false);
@@ -112,12 +107,8 @@ export const OnairosButton = forwardRef<OnairosButtonRef, OnairosButtonProps>(({
112
107
  setIsLoading(true);
113
108
 
114
109
  try {
115
- // If autoFetch is enabled, directly call the API with inferenceData
116
- if (autoFetch) {
117
- if (!inferenceData) {
118
- throw new Error('inferenceData is required when autoFetch is enabled');
119
- }
120
-
110
+ // If auto is enabled, make API call automatically and return result
111
+ if (auto) {
121
112
  try {
122
113
  // Check if credentials exist
123
114
  const hasStoredCreds = await hasCredentials();
@@ -129,27 +120,24 @@ export const OnairosButton = forwardRef<OnairosButtonRef, OnairosButtonProps>(({
129
120
  throw new Error('Invalid credentials');
130
121
  }
131
122
 
132
- // Call the API directly with inferenceData
133
- // Using a custom API call for inference
134
- const result = await fetch(`https://api.onairos.ai/inference`, {
123
+ // Call the API directly and return result
124
+ const result = await fetch(`https://api2.onairos.uk/api/inference`, {
135
125
  method: 'POST',
136
126
  headers: {
137
127
  'Content-Type': 'application/json',
138
128
  'Authorization': `Bearer ${credentials.userPin || ''}`
139
129
  },
140
130
  body: JSON.stringify({
141
- username: credentials.username,
142
- modelKey: credentials.userPin || '',
143
- data: inferenceData,
144
- requestData: requestData || {},
145
- proofMode: proofMode,
146
- webpageName: webpageName || AppName
147
- })
131
+ username: credentials.username,
132
+ modelKey: credentials.userPin || '',
133
+ requestData: requestData || {},
134
+ appName: AppName
135
+ })
148
136
  }).then(res => res.json());
149
137
 
150
138
  if (result && result.success) {
151
139
  if (onResolved) {
152
- onResolved(result.apiUrl || '', result.token || '', result.data || {});
140
+ onResolved(result.apiUrl || 'https://api2.onairos.uk', result.token || '', result.data || {});
153
141
  }
154
142
  setIsLoading(false);
155
143
  return;
@@ -160,8 +148,8 @@ export const OnairosButton = forwardRef<OnairosButtonRef, OnairosButtonProps>(({
160
148
  // No credentials, proceed with normal flow
161
149
  console.log('No credentials found, proceeding with normal flow');
162
150
  }
163
- } catch (autoFetchError) {
164
- console.error('AutoFetch error:', autoFetchError);
151
+ } catch (automaticError) {
152
+ console.error('Automatic API call error:', automaticError);
165
153
  // Fall back to normal flow on error
166
154
  }
167
155
  }
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useRef } from 'react';
2
2
  import {
3
3
  View,
4
4
  Text,
@@ -7,6 +7,7 @@ import {
7
7
  ActivityIndicator,
8
8
  SafeAreaView,
9
9
  Dimensions,
10
+ Linking,
10
11
  } from 'react-native';
11
12
  import { WebView } from 'react-native-webview';
12
13
  import Icon from 'react-native-vector-icons/MaterialIcons';
@@ -30,8 +31,10 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
30
31
  onComplete,
31
32
  }) => {
32
33
  const [isLoading, setIsLoading] = useState(true);
34
+ const [error, setError] = useState<string | null>(null);
35
+ const webViewRef = useRef<WebView>(null);
33
36
 
34
- console.log('Opening OAuth WebView with URL:', url); // Add logging
37
+ console.log('Opening OAuth WebView with URL:', url);
35
38
 
36
39
  const handleNavigationStateChange = (navState: any) => {
37
40
  console.log(`Navigation state changed for ${platform}:`, navState.url);
@@ -40,29 +43,11 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
40
43
  const isFinalRedirect = (
41
44
  navState.url.includes('onairos.uk/Home') ||
42
45
  navState.url.includes('onairos.uk/home') ||
43
- navState.url.includes('onairos.uk/success')
46
+ navState.url.includes('onairos.uk/success') ||
47
+ navState.url.startsWith('https://onairos.uk/Home')
44
48
  );
45
49
 
46
- // For YouTube specifically, we need to be more careful about when to close
47
- // Only close after the backend callback redirects to onairos.uk/Home
48
- if (platform === 'youtube') {
49
- // Only trigger success when we see the final redirect from the backend
50
- if (isFinalRedirect) {
51
- console.log('YouTube OAuth completed - backend callback finished and redirected to Home');
52
- onSuccess('success');
53
-
54
- // Close the OAuth window after a small delay to ensure redirect is processed
55
- setTimeout(() => {
56
- if (onComplete) {
57
- console.log('Closing YouTube OAuth window after callback completion');
58
- onComplete();
59
- }
60
- }, 500);
61
- }
62
- return; // Exit early for YouTube to avoid other triggers
63
- }
64
-
65
- // Platform-specific success patterns (for non-YouTube platforms)
50
+ // Platform-specific success patterns
66
51
  const platformSuccessPatterns: Record<string, RegExp[]> = {
67
52
  reddit: [
68
53
  /reddit\.com\/api\/v1\/authorize\?done=true/,
@@ -77,10 +62,14 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
77
62
  /linkedin\.com\/oauth\/complete/,
78
63
  /linkedin\.com\/uas\/oauth2\/authorization\/success/
79
64
  ],
80
- email: [/success/], // Generic success pattern for email
65
+ email: [/success/],
81
66
  instagram: [
82
67
  /instagram\.com\/oauth\/authorize\?done=true/,
83
68
  /instagram\.com\/oauth\/success/
69
+ ],
70
+ youtube: [
71
+ /accounts\.google\.com\/o\/oauth2\/approval/,
72
+ /youtube\.com\/oauth\/success/
84
73
  ]
85
74
  };
86
75
 
@@ -139,6 +128,20 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
139
128
 
140
129
  const handleLoadEnd = () => {
141
130
  setIsLoading(false);
131
+ setError(null);
132
+ };
133
+
134
+ const handleError = (syntheticEvent: any) => {
135
+ const { nativeEvent } = syntheticEvent;
136
+ console.error('WebView error:', nativeEvent);
137
+ setError('Failed to load OAuth page. Please try again.');
138
+ setIsLoading(false);
139
+ };
140
+
141
+ const handleOpenInBrowser = () => {
142
+ Linking.openURL(url).catch(err => {
143
+ console.error('Failed to open URL in browser:', err);
144
+ });
142
145
  };
143
146
 
144
147
  /**
@@ -181,6 +184,35 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
181
184
  }
182
185
  };
183
186
 
187
+ if (error) {
188
+ return (
189
+ <SafeAreaView style={styles.container}>
190
+ <View style={styles.header}>
191
+ <TouchableOpacity onPress={onClose} style={styles.closeButton}>
192
+ <Icon name="close" size={24} color="#000" />
193
+ </TouchableOpacity>
194
+ <View style={styles.titleContainer}>
195
+ <Icon
196
+ name={getPlatformIcon(platform)}
197
+ size={20}
198
+ color={getPlatformColor(platform)}
199
+ />
200
+ <Text style={styles.titleText}>{platform.charAt(0).toUpperCase() + platform.slice(1)} OAuth</Text>
201
+ </View>
202
+ </View>
203
+
204
+ <View style={styles.errorContainer}>
205
+ <Icon name="error-outline" size={48} color="#FF6B6B" />
206
+ <Text style={styles.errorTitle}>Connection Error</Text>
207
+ <Text style={styles.errorMessage}>{error}</Text>
208
+ <TouchableOpacity style={styles.retryButton} onPress={handleOpenInBrowser}>
209
+ <Text style={styles.retryButtonText}>Open in Browser</Text>
210
+ </TouchableOpacity>
211
+ </View>
212
+ </SafeAreaView>
213
+ );
214
+ }
215
+
184
216
  return (
185
217
  <SafeAreaView style={styles.container}>
186
218
  <View style={styles.header}>
@@ -195,17 +227,20 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
195
227
  />
196
228
  <Text style={styles.titleText}>{platform.charAt(0).toUpperCase() + platform.slice(1)} OAuth</Text>
197
229
  </View>
230
+ <TouchableOpacity onPress={handleOpenInBrowser} style={styles.browserButton}>
231
+ <Icon name="open-in-browser" size={20} color="#666" />
232
+ </TouchableOpacity>
198
233
  </View>
199
234
 
200
235
  <WebView
236
+ ref={webViewRef}
201
237
  source={{ uri: url }}
202
238
  onNavigationStateChange={handleNavigationStateChange}
203
239
  onLoadEnd={handleLoadEnd}
240
+ onError={handleError}
204
241
  style={styles.webView}
205
242
  javaScriptEnabled={true}
206
243
  domStorageEnabled={true}
207
- sharedCookiesEnabled={true}
208
- thirdPartyCookiesEnabled={true}
209
244
  userAgent="Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"
210
245
  />
211
246
 
@@ -251,6 +286,12 @@ const styles = StyleSheet.create({
251
286
  left: 16,
252
287
  zIndex: 10,
253
288
  },
289
+ browserButton: {
290
+ padding: 8,
291
+ position: 'absolute',
292
+ right: 16,
293
+ zIndex: 10,
294
+ },
254
295
  webView: {
255
296
  flex: 1,
256
297
  },
@@ -265,4 +306,34 @@ const styles = StyleSheet.create({
265
306
  fontSize: 16,
266
307
  color: '#666',
267
308
  },
309
+ errorContainer: {
310
+ flex: 1,
311
+ alignItems: 'center',
312
+ justifyContent: 'center',
313
+ padding: 20,
314
+ },
315
+ errorTitle: {
316
+ fontSize: 18,
317
+ fontWeight: '600',
318
+ color: '#333',
319
+ marginTop: 16,
320
+ marginBottom: 8,
321
+ },
322
+ errorMessage: {
323
+ fontSize: 14,
324
+ color: '#666',
325
+ textAlign: 'center',
326
+ marginBottom: 20,
327
+ },
328
+ retryButton: {
329
+ backgroundColor: COLORS.primary,
330
+ paddingHorizontal: 24,
331
+ paddingVertical: 12,
332
+ borderRadius: 8,
333
+ },
334
+ retryButtonText: {
335
+ color: '#fff',
336
+ fontSize: 16,
337
+ fontWeight: '600',
338
+ },
268
339
  });
package/src/index.ts CHANGED
@@ -118,7 +118,7 @@ interface OnairosComponent extends React.FC<any> {}
118
118
  // Define the public components for default export
119
119
  const components = {
120
120
  Onairos: Onairos as OnairosComponent,
121
- OnairosButton: OnairosButton as React.ComponentType<OnairosButtonProps>,
121
+ OnairosButton: OnairosButton,
122
122
  OnairosOverlay: Overlay as OverlayComponent,
123
123
  UniversalOnboarding: UniversalOnboarding as React.ComponentType<UniversalOnboardingProps>,
124
124
  PortalHost: PortalHost,
@@ -166,13 +166,53 @@ export const initiateNativeAuth = async (platform: string): Promise<boolean> =>
166
166
  try {
167
167
  // Currently only YouTube (Google Sign-In) is supported
168
168
  if (platform === 'youtube') {
169
- // This is a placeholder for the actual implementation
170
- // In a real implementation, you would import and use the Google Sign-In SDK
171
169
  console.log('Initiating native Google Sign-In for YouTube');
172
170
 
173
- // Simulate a successful authentication
174
- // In a real implementation, this would be the result of the Google Sign-In flow
175
- return true;
171
+ try {
172
+ // Import Google Sign-In dynamically to avoid errors if not installed
173
+ const { GoogleSignin, statusCodes } = require('@react-native-google-signin/google-signin');
174
+
175
+ // Configure Google Sign-In
176
+ await GoogleSignin.configure({
177
+ scopes: ['https://www.googleapis.com/auth/youtube.readonly'],
178
+ webClientId: 'YOUR_WEB_CLIENT_ID', // Replace with your actual web client ID
179
+ offlineAccess: true,
180
+ hostedDomain: '',
181
+ forceCodeForRefreshToken: true,
182
+ });
183
+
184
+ // Check if device supports Google Play Services
185
+ await GoogleSignin.hasPlayServices();
186
+
187
+ // Sign in
188
+ const userInfo = await GoogleSignin.signIn();
189
+ console.log('Google Sign-In successful:', userInfo);
190
+
191
+ // Get access token
192
+ const tokens = await GoogleSignin.getTokens();
193
+ console.log('Google tokens:', tokens);
194
+
195
+ // Here you would typically send the tokens to your backend
196
+ // to associate the YouTube account with the user
197
+
198
+ return true;
199
+ } catch (error: any) {
200
+ console.error('Google Sign-In error:', error);
201
+
202
+ const { statusCodes: StatusCodes } = require('@react-native-google-signin/google-signin');
203
+
204
+ if (error.code === StatusCodes.SIGN_IN_CANCELLED) {
205
+ console.log('User cancelled the sign-in flow');
206
+ } else if (error.code === StatusCodes.IN_PROGRESS) {
207
+ console.log('Sign-in is in progress already');
208
+ } else if (error.code === StatusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
209
+ console.log('Play services not available or outdated');
210
+ } else {
211
+ console.log('Some other error happened');
212
+ }
213
+
214
+ return false;
215
+ }
176
216
  }
177
217
 
178
218
  throw new Error(`Native authentication not supported for ${platform}`);
@@ -5,30 +5,32 @@ export interface DataTier {
5
5
  }
6
6
 
7
7
  export interface OnairosButtonProps {
8
- returnLink?: string;
9
- prefillUrl?: string;
10
- AppName?: string;
11
- buttonType?: 'normal' | 'pill';
12
- requestData?: {
8
+ AppName: string;
9
+ requestData: {
13
10
  [key: string]: {
14
11
  type: string;
15
12
  descriptions: string;
16
13
  reward: string;
17
14
  };
18
15
  };
16
+ returnLink?: string;
17
+ prefillUrl?: string;
18
+ buttonType?: 'normal' | 'pill';
19
19
  buttonWidth?: number | string;
20
20
  buttonHeight?: number;
21
21
  hasStroke?: boolean;
22
22
  enabled?: boolean;
23
- buttonForm?: 'default' | 'login' | 'signup';
23
+ buttonForm?: 'default' | 'login' | 'signup' | 'connect';
24
+ auto?: boolean; // If true, makes API call automatically and returns result
24
25
  onRejection?: (error?: string) => void;
25
- onResolved?: (apiUrl: string, token: string, userData: any) => void;
26
+ onResolved?: (apiUrl: string, token: string, userData: any) => void; // Required when auto is false
26
27
  preCheck?: () => Promise<boolean>;
27
28
  color?: string;
28
29
  swerv?: boolean;
29
30
  debug?: boolean;
30
31
  preferredPlatform?: string;
31
32
  testMode?: boolean;
33
+ darkMode?: boolean;
32
34
  }
33
35
 
34
36
  export interface UniversalOnboardingProps {