@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.
- package/README.md +2 -0
- package/lib/commonjs/components/OnairosButton.js +12 -23
- package/lib/commonjs/components/OnairosButton.js.map +1 -1
- package/lib/commonjs/components/onboarding/OAuthWebView.js +104 -28
- package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/platformAuthService.js +48 -6
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/module/components/OnairosButton.js +12 -23
- package/lib/module/components/OnairosButton.js.map +1 -1
- package/lib/module/components/onboarding/OAuthWebView.js +106 -30
- package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/platformAuthService.js +48 -6
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/typescript/components/OnairosButton.d.ts +1 -1
- package/lib/typescript/components/OnairosButton.d.ts.map +1 -1
- package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/lib/typescript/types/index.d.ts +8 -6
- package/lib/typescript/types/index.d.ts.map +1 -1
- package/lib/typescript/utils/onairosApi.d.ts +1 -1
- package/lib/typescript/utils/onairosApi.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/OnairosButton.tsx +17 -29
- package/src/components/onboarding/OAuthWebView.tsx +97 -26
- package/src/index.ts +1 -1
- package/src/services/platformAuthService.ts +45 -5
- 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
|
-
|
|
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
|
|
116
|
-
if (
|
|
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
|
|
133
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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 (
|
|
164
|
-
console.error('
|
|
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);
|
|
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
|
-
//
|
|
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/],
|
|
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
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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}`);
|
package/src/types/index.ts
CHANGED
|
@@ -5,30 +5,32 @@ export interface DataTier {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export interface OnairosButtonProps {
|
|
8
|
-
|
|
9
|
-
|
|
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 {
|