@onairos/react-native 3.0.21 → 3.0.24

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 (30) hide show
  1. package/lib/commonjs/components/OnairosButton.js +62 -7
  2. package/lib/commonjs/components/OnairosButton.js.map +1 -1
  3. package/lib/commonjs/components/UniversalOnboarding.js +155 -7
  4. package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
  5. package/lib/commonjs/constants/index.js +2 -1
  6. package/lib/commonjs/constants/index.js.map +1 -1
  7. package/lib/commonjs/services/platformAuthService.js +180 -0
  8. package/lib/commonjs/services/platformAuthService.js.map +1 -0
  9. package/lib/module/components/OnairosButton.js +62 -7
  10. package/lib/module/components/OnairosButton.js.map +1 -1
  11. package/lib/module/components/UniversalOnboarding.js +156 -8
  12. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  13. package/lib/module/constants/index.js +2 -1
  14. package/lib/module/constants/index.js.map +1 -1
  15. package/lib/module/services/platformAuthService.js +167 -0
  16. package/lib/module/services/platformAuthService.js.map +1 -0
  17. package/lib/typescript/components/OnairosButton.d.ts.map +1 -1
  18. package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
  19. package/lib/typescript/constants/index.d.ts +1 -0
  20. package/lib/typescript/constants/index.d.ts.map +1 -1
  21. package/lib/typescript/services/platformAuthService.d.ts +38 -0
  22. package/lib/typescript/services/platformAuthService.d.ts.map +1 -0
  23. package/lib/typescript/types.d.ts +6 -0
  24. package/lib/typescript/types.d.ts.map +1 -1
  25. package/package.json +2 -1
  26. package/src/components/OnairosButton.tsx +365 -305
  27. package/src/components/UniversalOnboarding.tsx +153 -9
  28. package/src/constants/index.ts +1 -0
  29. package/src/services/platformAuthService.ts +175 -0
  30. package/src/types.ts +6 -0
@@ -14,13 +14,16 @@ import {
14
14
  ScrollView,
15
15
  Image,
16
16
  Switch,
17
+ Linking,
17
18
  } from 'react-native';
18
19
  import Icon from 'react-native-vector-icons/MaterialIcons';
19
20
  import { PlatformList } from './PlatformList';
20
21
  import { PinInput } from './PinInput';
21
22
  import { TrainingModal } from './TrainingModal';
23
+ import { OAuthWebView } from './onboarding/OAuthWebView';
22
24
  import { useConnections } from '../hooks/useConnections';
23
- import { COLORS } from '../constants';
25
+ import { COLORS, DEEP_LINK_CONFIG } from '../constants';
26
+ import { initiateOAuth, initiateNativeAuth, hasNativeSDK, isOAuthCallback } from '../services/platformAuthService';
24
27
  import type { UniversalOnboardingProps, ConnectionStatus } from '../types';
25
28
 
26
29
  const { height, width } = Dimensions.get('window');
@@ -37,7 +40,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
37
40
  test = false,
38
41
  preferredPlatform,
39
42
  }) => {
40
- const [step, setStep] = useState<'connect' | 'pin' | 'training'>('connect');
43
+ const [step, setStep] = useState<'connect' | 'pin' | 'training' | 'oauth'>('connect');
41
44
  const [connections, setConnections] = useState<ConnectionStatus>({});
42
45
  const [pin, setPin] = useState<string>('');
43
46
  const [selectedTier, setSelectedTier] = useState<'Small' | 'Medium' | 'Large'>('Medium');
@@ -47,6 +50,9 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
47
50
  }>({ progress: 0, eta: '' });
48
51
  const [slideAnim] = useState(new Animated.Value(height));
49
52
  const [platformToggles, setPlatformToggles] = useState<{[key: string]: boolean}>({});
53
+ const [oauthUrl, setOauthUrl] = useState<string>('');
54
+ const [currentPlatform, setCurrentPlatform] = useState<string>('');
55
+ const [username, setUsername] = useState<string>(`user_${Math.floor(Math.random() * 10000)}`);
50
56
 
51
57
  const platforms = [
52
58
  { id: 'instagram', name: 'Instagram', icon: require('../assets/images/instagram.png') },
@@ -73,6 +79,27 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
73
79
  bounciness: 0,
74
80
  }).start();
75
81
 
82
+ // Set up deep link listener for OAuth callbacks
83
+ // Using the subscription pattern for React Native's Linking API
84
+ const subscription = Linking.addListener('url', ({ url }) => {
85
+ if (isOAuthCallback(url)) {
86
+ handleOAuthCallback(url);
87
+ }
88
+ });
89
+
90
+ // Check for initial URL (app was opened via deep link)
91
+ Linking.getInitialURL().then(initialUrl => {
92
+ if (initialUrl && isOAuthCallback(initialUrl)) {
93
+ handleOAuthCallback(initialUrl);
94
+ }
95
+ });
96
+
97
+ // Return cleanup function
98
+ return () => {
99
+ // Remove event listener using the subscription
100
+ subscription.remove();
101
+ };
102
+
76
103
  // Initialize platform toggles
77
104
  const initialToggles: { [key: string]: boolean } = {};
78
105
  platforms.forEach((platform) => {
@@ -127,12 +154,116 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
127
154
  setConnections(status);
128
155
  }, [getConnectionStatus]);
129
156
 
130
- const togglePlatform = useCallback((platformId: string) => {
131
- setPlatformToggles(prev => ({
132
- ...prev,
133
- [platformId]: !prev[platformId]
134
- }));
135
- }, []);
157
+ const togglePlatform = useCallback(async (platformId: string) => {
158
+ // If toggling on, initiate the OAuth flow for the platform
159
+ if (!platformToggles[platformId]) {
160
+ try {
161
+ // Special case for Instagram which uses the existing flow
162
+ if (platformId === 'instagram') {
163
+ setPlatformToggles(prev => ({
164
+ ...prev,
165
+ [platformId]: !prev[platformId]
166
+ }));
167
+ return;
168
+ }
169
+
170
+ // Check if the platform has a native SDK
171
+ if (hasNativeSDK(platformId)) {
172
+ // Use native SDK authentication
173
+ setCurrentPlatform(platformId);
174
+ const success = await initiateNativeAuth(platformId);
175
+
176
+ if (success) {
177
+ // Update connections state
178
+ setConnections(prev => ({
179
+ ...prev,
180
+ [platformId]: { userName: username, connected: true }
181
+ }));
182
+
183
+ // Update platform toggles
184
+ setPlatformToggles(prev => ({
185
+ ...prev,
186
+ [platformId]: true
187
+ }));
188
+ }
189
+ return;
190
+ }
191
+
192
+ // For other platforms, use the web OAuth flow
193
+ setCurrentPlatform(platformId);
194
+ const oauthUrl = await initiateOAuth(platformId, username);
195
+
196
+ // If oauthUrl is null, it means we should use native SDK (which should have been caught above)
197
+ if (oauthUrl) {
198
+ setOauthUrl(oauthUrl);
199
+ setStep('oauth');
200
+ }
201
+ } catch (error) {
202
+ console.error(`Error initiating OAuth for ${platformId}:`, error);
203
+ // If there's an error, don't toggle the platform
204
+ return;
205
+ }
206
+ } else {
207
+ // If toggling off, just update the state
208
+ setPlatformToggles(prev => ({
209
+ ...prev,
210
+ [platformId]: !prev[platformId]
211
+ }));
212
+ }
213
+ }, [platformToggles, username]);
214
+
215
+ /**
216
+ * Handles OAuth callback URLs
217
+ */
218
+ const handleOAuthCallback = useCallback((url: string) => {
219
+ try {
220
+ // Extract the authorization code from the URL
221
+ const parsedUrl = new URL(url);
222
+ const code = parsedUrl.searchParams.get('code');
223
+ const platform = parsedUrl.searchParams.get('platform') || currentPlatform;
224
+
225
+ if (code && platform) {
226
+ // Update connections state
227
+ setConnections(prev => ({
228
+ ...prev,
229
+ [platform]: { userName: username, connected: true }
230
+ }));
231
+
232
+ // Update platform toggles
233
+ setPlatformToggles(prev => ({
234
+ ...prev,
235
+ [platform]: true
236
+ }));
237
+
238
+ // Return to the connect step
239
+ setStep('connect');
240
+ }
241
+ } catch (error) {
242
+ console.error('Error handling OAuth callback:', error);
243
+ }
244
+ }, [currentPlatform, username]);
245
+
246
+ /**
247
+ * Handles completion of the OAuth flow
248
+ */
249
+ const handleOAuthSuccess = useCallback((code: string) => {
250
+ if (currentPlatform) {
251
+ // Update connections state
252
+ setConnections(prev => ({
253
+ ...prev,
254
+ [currentPlatform]: { userName: username, connected: true }
255
+ }));
256
+
257
+ // Update platform toggles
258
+ setPlatformToggles(prev => ({
259
+ ...prev,
260
+ [currentPlatform]: true
261
+ }));
262
+
263
+ // Return to the connect step
264
+ setStep('connect');
265
+ }
266
+ }, [currentPlatform, username]);
136
267
 
137
268
  const handlePinSubmit = useCallback(async (userPin: string) => {
138
269
  setPin(userPin);
@@ -294,7 +425,20 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
294
425
  });
295
426
  }}
296
427
  modelKey="onairosTrainingModel"
297
- username="demo_user"
428
+ username={username}
429
+ />
430
+ )}
431
+
432
+ {step === 'oauth' && oauthUrl && (
433
+ <OAuthWebView
434
+ url={oauthUrl}
435
+ platform={currentPlatform}
436
+ onClose={() => {
437
+ setStep('connect');
438
+ setOauthUrl('');
439
+ }}
440
+ onSuccess={handleOAuthSuccess}
441
+ onComplete={() => setStep('connect')}
298
442
  />
299
443
  )}
300
444
  </SafeAreaView>
@@ -79,4 +79,5 @@ export const PIN_REQUIREMENTS = {
79
79
  export const DEEP_LINK_CONFIG = {
80
80
  scheme: 'onairosanime',
81
81
  host: 'authenticate',
82
+ redirectUri: 'onairosanime://auth/',
82
83
  };
@@ -0,0 +1,175 @@
1
+ import { Platform, Linking } from 'react-native';
2
+ import { DEEP_LINK_CONFIG } from '../constants';
3
+
4
+ // Define types for platform auth configuration
5
+ interface PlatformAuthConfig {
6
+ hasNativeSDK: boolean;
7
+ nativeSDKPackage?: string;
8
+ authEndpoint: string;
9
+ color: string;
10
+ }
11
+
12
+ // Configuration for each platform's authentication
13
+ const PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
14
+ instagram: {
15
+ hasNativeSDK: false, // Instagram doesn't have a public OAuth SDK for React Native
16
+ authEndpoint: 'https://api2.onairos.uk/instagram/authorize',
17
+ color: '#E1306C',
18
+ },
19
+ youtube: {
20
+ hasNativeSDK: true, // YouTube uses Google Sign-In SDK
21
+ nativeSDKPackage: '@react-native-google-signin/google-signin',
22
+ authEndpoint: 'https://api2.onairos.uk/youtube/authorize',
23
+ color: '#FF0000',
24
+ },
25
+ reddit: {
26
+ hasNativeSDK: false,
27
+ authEndpoint: 'https://api2.onairos.uk/reddit/authorize',
28
+ color: '#FF4500',
29
+ },
30
+ pinterest: {
31
+ hasNativeSDK: false,
32
+ authEndpoint: 'https://api2.onairos.uk/pinterest/authorize',
33
+ color: '#E60023',
34
+ },
35
+ email: {
36
+ hasNativeSDK: false,
37
+ authEndpoint: 'https://api2.onairos.uk/email/authorize',
38
+ color: '#4285F4',
39
+ },
40
+ };
41
+
42
+ /**
43
+ * Checks if a native SDK is available for the given platform
44
+ */
45
+ export const hasNativeSDK = (platform: string): boolean => {
46
+ const config = PLATFORM_AUTH_CONFIG[platform];
47
+ return config?.hasNativeSDK || false;
48
+ };
49
+
50
+ /**
51
+ * Gets the auth endpoint URL for a platform
52
+ */
53
+ export const getAuthEndpoint = (platform: string): string => {
54
+ const config = PLATFORM_AUTH_CONFIG[platform];
55
+ return config?.authEndpoint || '';
56
+ };
57
+
58
+ /**
59
+ * Gets the color associated with a platform
60
+ */
61
+ export const getPlatformColor = (platform: string): string => {
62
+ const config = PLATFORM_AUTH_CONFIG[platform];
63
+ return config?.color || '#000000';
64
+ };
65
+
66
+ /**
67
+ * Initiates the OAuth flow for a platform
68
+ * @param platform The platform to authenticate with
69
+ * @param username The username to associate with the authentication
70
+ * @returns A Promise that resolves to the OAuth URL to open in a WebView or null if using native SDK
71
+ */
72
+ export const initiateOAuth = async (platform: string, username: string): Promise<string | null> => {
73
+ try {
74
+ // Check if the platform is supported
75
+ if (!PLATFORM_AUTH_CONFIG[platform]) {
76
+ throw new Error(`Unsupported platform: ${platform}`);
77
+ }
78
+
79
+ // Check if platform has a native SDK
80
+ if (PLATFORM_AUTH_CONFIG[platform].hasNativeSDK) {
81
+ // Return null to indicate that we should use the native SDK
82
+ return null;
83
+ }
84
+
85
+ // Prepare the request body
86
+ const jsonData = {
87
+ session: {
88
+ username: username || 'anonymous',
89
+ },
90
+ };
91
+
92
+ // Make the request to get the OAuth URL
93
+ const response = await fetch(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
94
+ method: 'POST',
95
+ headers: {
96
+ 'Content-Type': 'application/json',
97
+ },
98
+ body: JSON.stringify(jsonData),
99
+ });
100
+
101
+ // Parse the response
102
+ const data = await response.json();
103
+
104
+ // Check if the response contains the OAuth URL
105
+ if (platform === 'reddit' && data.redditURL) {
106
+ return data.redditURL;
107
+ } else if (platform === 'pinterest' && data.pinterestURL) {
108
+ return data.pinterestURL;
109
+ } else if (platform === 'youtube' && data.youtubeURL) {
110
+ return data.youtubeURL;
111
+ } else if (platform === 'email' && data.emailURL) {
112
+ return data.emailURL;
113
+ } else if (data.url) {
114
+ return data.url;
115
+ }
116
+
117
+ throw new Error(`No OAuth URL found in response for ${platform}`);
118
+ } catch (error) {
119
+ console.error(`Error initiating OAuth for ${platform}:`, error);
120
+ throw error;
121
+ }
122
+ };
123
+
124
+ /**
125
+ * Initiates the native SDK authentication flow for a platform
126
+ * @param platform The platform to authenticate with
127
+ * @returns A Promise that resolves to the authentication result
128
+ */
129
+ export const initiateNativeAuth = async (platform: string): Promise<boolean> => {
130
+ try {
131
+ // Currently only YouTube (Google Sign-In) is supported
132
+ if (platform === 'youtube') {
133
+ // This is a placeholder for the actual implementation
134
+ // In a real implementation, you would import and use the Google Sign-In SDK
135
+ console.log('Initiating native Google Sign-In for YouTube');
136
+
137
+ // Simulate a successful authentication
138
+ // In a real implementation, this would be the result of the Google Sign-In flow
139
+ return true;
140
+ }
141
+
142
+ throw new Error(`Native authentication not supported for ${platform}`);
143
+ } catch (error) {
144
+ console.error(`Error initiating native auth for ${platform}:`, error);
145
+ throw error;
146
+ }
147
+ };
148
+
149
+ /**
150
+ * Handles the OAuth callback
151
+ * @param url The callback URL
152
+ * @returns The authorization code extracted from the URL
153
+ */
154
+ export const handleOAuthCallback = (url: string): string | null => {
155
+ try {
156
+ // Parse the URL
157
+ const parsedUrl = new URL(url);
158
+
159
+ // Extract the authorization code
160
+ return parsedUrl.searchParams.get('code');
161
+ } catch (error) {
162
+ console.error('Error handling OAuth callback:', error);
163
+ return null;
164
+ }
165
+ };
166
+
167
+ /**
168
+ * Checks if a URL is an OAuth callback
169
+ * @param url The URL to check
170
+ * @returns True if the URL is an OAuth callback
171
+ */
172
+ export const isOAuthCallback = (url: string): boolean => {
173
+ // Check if the URL starts with our redirect URI
174
+ return url.startsWith('onairosanime://auth/');
175
+ };
package/src/types.ts CHANGED
@@ -54,6 +54,12 @@ export interface OnairosButtonProps {
54
54
  darkMode?: boolean;
55
55
  preferredPlatform?: string;
56
56
  testMode?: boolean;
57
+ autoFetch?: boolean;
58
+ inferenceData?: any;
59
+ textLayout?: 'left' | 'right' | 'center';
60
+ textColor?: string;
61
+ proofMode?: boolean;
62
+ webpageName?: string;
57
63
  }
58
64
 
59
65
  export interface PlatformListProps {