@onairos/react-native 3.0.71 → 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
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useImperativeHandle, useState, useCallback } from 'react';
1
+ import React, { forwardRef, useImperativeHandle, useState, useCallback, useEffect } from 'react';
2
2
  import {
3
3
  StyleSheet,
4
4
  View,
@@ -8,6 +8,7 @@ import {
8
8
  TextStyle,
9
9
  Platform,
10
10
  Image,
11
+ Alert,
11
12
  } from 'react-native';
12
13
  import { UniversalOnboarding } from './UniversalOnboarding';
13
14
  import { Overlay } from './Overlay';
@@ -15,7 +16,8 @@ import { COLORS } from '../constants';
15
16
  import { hasCredentials, getCredentials, deleteCredentials } from '../utils/secureStorage';
16
17
  import { onairosApi } from '../api';
17
18
  import { Portal } from '../utils/Portal';
18
- import { DataTier } from '../types';
19
+ import { DataTier, OnairosConfig } from '../types';
20
+ import { initializeApiKey, isApiKeyInitialized, getApiConfig } from '../services/apiKeyService';
19
21
 
20
22
  interface OnairosProps {
21
23
  returnLink?: string;
@@ -38,232 +40,354 @@ interface OnairosProps {
38
40
  darkMode?: boolean;
39
41
  preferredPlatform?: string;
40
42
  testMode?: boolean;
43
+ // API Key Configuration (REQUIRED)
44
+ apiKey: string;
45
+ environment?: 'production' | 'staging' | 'development';
46
+ enableLogging?: boolean;
47
+ timeout?: number;
48
+ retryAttempts?: number;
41
49
  }
42
50
 
43
- export interface OnairosRef {
44
- trigger: () => Promise<void>;
45
- reset: () => Promise<void>;
46
- }
51
+ export const Onairos = forwardRef<any, OnairosProps>((props, ref) => {
52
+ const {
53
+ returnLink,
54
+ prefillUrl,
55
+ AppName,
56
+ buttonType = 'normal',
57
+ requestData,
58
+ buttonWidth = 200,
59
+ buttonHeight = 48,
60
+ hasStroke = false,
61
+ enabled = true,
62
+ buttonForm = 'default',
63
+ onRejection,
64
+ onResolved,
65
+ preCheck,
66
+ color = COLORS.primary,
67
+ debug = false,
68
+ darkMode = false,
69
+ preferredPlatform,
70
+ testMode = false,
71
+ // API Key props
72
+ apiKey,
73
+ environment = 'production',
74
+ enableLogging = true,
75
+ timeout = 30000,
76
+ retryAttempts = 3,
77
+ } = props;
47
78
 
48
- export const Onairos = forwardRef<OnairosRef, OnairosProps>(({
49
- returnLink,
50
- prefillUrl,
51
- AppName,
52
- buttonType = 'normal',
53
- requestData,
54
- buttonWidth = 180,
55
- buttonHeight,
56
- hasStroke = false,
57
- enabled = true,
58
- buttonForm = 'default',
59
- onRejection,
60
- onResolved,
61
- preCheck,
62
- color,
63
- debug = false,
64
- darkMode = false,
65
- preferredPlatform,
66
- testMode = false,
67
- }, ref) => {
68
- const [showOnboarding, setShowOnboarding] = useState(false);
69
79
  const [showOverlay, setShowOverlay] = useState(false);
70
- const [storedCredentials, setStoredCredentials] = useState<any>(null);
71
- const [isLoading, setIsLoading] = useState(false);
72
- const [isPressed, setIsPressed] = useState(false);
80
+ const [isInitialized, setIsInitialized] = useState(false);
81
+ const [initializationError, setInitializationError] = useState<string | null>(null);
82
+ const [isInitializing, setIsInitializing] = useState(false);
73
83
 
74
- // Expose methods for external control
75
- useImperativeHandle(ref, () => ({
76
- trigger: async () => {
77
- await handlePress();
78
- },
79
- reset: async () => {
80
- await deleteCredentials();
81
- }
82
- }));
84
+ // Initialize API key when component mounts or API key changes
85
+ useEffect(() => {
86
+ let isMounted = true;
83
87
 
84
- // Compute button text based on buttonForm
85
- const getButtonText = () => {
86
- if (buttonForm === 'connect') {
87
- return 'Connect with Onairos';
88
- } else {
89
- return 'Sign in with Onairos';
90
- }
91
- };
88
+ const initializeApi = async () => {
89
+ // Skip if already initializing
90
+ if (isInitializing) return;
91
+
92
+ setIsInitializing(true);
93
+ setInitializationError(null);
92
94
 
93
- // Calculate background color based on props and state
94
- const getBackgroundColor = (): string => {
95
- if (!enabled) {
96
- return darkMode ? '#3A3A3A' : '#e0e0e0';
97
- }
98
-
99
- if (isPressed) {
100
- return color ?
101
- (typeof color === 'string' ? `${color}80` : color) :
102
- (darkMode ? '#32323280' : '#f5f5f580');
103
- }
104
-
105
- return color || (darkMode ? '#2A2A2A' : '#ffffff');
106
- };
95
+ try {
96
+ console.log('🚀 Onairos SDK: Starting API key initialization...');
97
+
98
+ if (!apiKey) {
99
+ throw new Error('API key is required. Please provide a valid API key from your Onairos dashboard.');
100
+ }
107
101
 
108
- // Calculate text color based on background luminance
109
- const getTextColor = (): string => {
110
- if (!enabled) {
111
- return darkMode ? '#777777' : '#AAAAAA';
112
- }
113
-
114
- if (darkMode) {
115
- return '#FFFFFF';
102
+ const config: OnairosConfig = {
103
+ apiKey,
104
+ environment,
105
+ enableLogging,
106
+ timeout,
107
+ retryAttempts,
108
+ };
109
+
110
+ // Initialize the API key service
111
+ await initializeApiKey(config);
112
+
113
+ if (isMounted) {
114
+ setIsInitialized(true);
115
+ setInitializationError(null);
116
+
117
+ if (enableLogging) {
118
+ console.log('✅ Onairos SDK: API key initialization completed successfully');
119
+ console.log('📊 Configuration:', {
120
+ environment,
121
+ enableLogging,
122
+ timeout,
123
+ retryAttempts,
124
+ apiKeyLength: apiKey.length,
125
+ });
126
+ }
127
+ }
128
+ } catch (error) {
129
+ const errorMessage = error instanceof Error ? error.message : 'Unknown initialization error';
130
+
131
+ console.error('❌ Onairos SDK: API key initialization failed:', errorMessage);
132
+
133
+ if (isMounted) {
134
+ setIsInitialized(false);
135
+ setInitializationError(errorMessage);
136
+
137
+ // Show developer-friendly error
138
+ if (enableLogging) {
139
+ console.group('🔧 API Key Troubleshooting Guide');
140
+ console.log('1. Check that your API key is correct and not expired');
141
+ console.log('2. Verify you have the right permissions for your use case');
142
+ console.log('3. Ensure your environment setting matches your API key');
143
+ console.log('4. Check your internet connection');
144
+ console.log('5. Visit https://dashboard.onairos.uk to manage your API keys');
145
+ console.groupEnd();
146
+ }
147
+
148
+ // Call rejection callback if provided
149
+ if (onRejection) {
150
+ onRejection(`SDK initialization failed: ${errorMessage}`);
151
+ }
152
+ }
153
+ } finally {
154
+ if (isMounted) {
155
+ setIsInitializing(false);
156
+ }
157
+ }
158
+ };
159
+
160
+ // Only initialize if we have an API key and aren't already initialized correctly
161
+ if (apiKey && (!isApiKeyInitialized() || getApiConfig()?.apiKey !== apiKey)) {
162
+ initializeApi();
116
163
  }
117
-
118
- const bgColor = getBackgroundColor();
119
- // Simple luminance check - in a real app, this would use a proper algorithm
120
- return bgColor === '#ffffff' || bgColor === '#f5f5f580' || bgColor.includes('#f') ? '#000000' : '#FFFFFF';
121
- };
122
164
 
123
- const handlePress = async () => {
124
- if (!enabled || isLoading) return;
125
-
126
- setIsLoading(true);
127
-
165
+ return () => {
166
+ isMounted = false;
167
+ };
168
+ }, [apiKey, environment, enableLogging, timeout, retryAttempts, onRejection]);
169
+
170
+ // Imperative methods
171
+ useImperativeHandle(ref, () => ({
172
+ openOverlay: handleShowOverlay,
173
+ closeOverlay: handleCloseOverlay,
174
+ isInitialized: () => isInitialized,
175
+ getApiConfig: () => getApiConfig(),
176
+ }));
177
+
178
+ const handleShowOverlay = useCallback(async () => {
128
179
  try {
180
+ // Check if SDK is initialized
181
+ if (!isInitialized) {
182
+ const errorMessage = initializationError || 'SDK not initialized. Please check your API key.';
183
+ console.error('❌ Cannot open overlay: SDK not initialized');
184
+
185
+ if (onRejection) {
186
+ onRejection(errorMessage);
187
+ } else {
188
+ Alert.alert(
189
+ 'SDK Error',
190
+ errorMessage,
191
+ [{ text: 'OK' }]
192
+ );
193
+ }
194
+ return;
195
+ }
196
+
197
+ // Run pre-check if provided
129
198
  if (preCheck) {
130
- const shouldProceed = await preCheck();
131
- if (!shouldProceed) {
132
- onRejection?.('Precheck validation failed');
133
- setIsLoading(false);
199
+ if (enableLogging) {
200
+ console.log('🔍 Running pre-check validation...');
201
+ }
202
+
203
+ try {
204
+ const preCheckPassed = await preCheck();
205
+ if (!preCheckPassed) {
206
+ if (enableLogging) {
207
+ console.log('⛔ Pre-check failed, aborting overlay');
208
+ }
209
+ return;
210
+ }
211
+
212
+ if (enableLogging) {
213
+ console.log('✅ Pre-check passed');
214
+ }
215
+ } catch (preCheckError) {
216
+ console.error('❌ Pre-check error:', preCheckError);
217
+ if (onRejection) {
218
+ onRejection(`Pre-check failed: ${preCheckError.message}`);
219
+ }
134
220
  return;
135
221
  }
136
222
  }
137
223
 
138
- // Check if credentials exist
139
- const hasStoredCreds = await hasCredentials();
224
+ // Check for existing credentials
225
+ if (enableLogging) {
226
+ console.log('🔍 Checking for existing credentials...');
227
+ }
140
228
 
141
- if (hasStoredCreds) {
142
- // If credentials exist, fetch them and verify
143
- const credentials = await getCredentials();
144
-
145
- if (!credentials || !credentials.username) {
146
- // Invalid credentials, clear and start fresh
147
- await deleteCredentials();
148
- setShowOnboarding(true);
149
- setIsLoading(false);
150
- return;
229
+ const hasExistingCredentials = await hasCredentials();
230
+
231
+ if (hasExistingCredentials) {
232
+ if (enableLogging) {
233
+ console.log('🔑 Existing credentials found, attempting automatic resolution...');
151
234
  }
152
235
 
153
236
  try {
154
- // Validate credentials with server
155
- const isValid = await onairosApi.validateCredentials(credentials.username);
237
+ const credentials = await getCredentials();
156
238
 
157
- if (!isValid) {
158
- // Clear invalid credentials
159
- await deleteCredentials();
160
- setShowOnboarding(true);
161
- setIsLoading(false);
239
+ if (credentials && onResolved) {
240
+ // For existing users, we can resolve immediately with cached data
241
+ const mockApiUrl = 'https://api2.onairos.uk/user/data';
242
+ const mockToken = 'existing_user_token';
243
+
244
+ if (enableLogging) {
245
+ console.log('✅ Resolving with existing credentials');
246
+ }
247
+
248
+ onResolved(mockApiUrl, mockToken, credentials);
162
249
  return;
163
250
  }
164
-
165
- // Store and display overlay with valid credentials
166
- setStoredCredentials(credentials);
167
- setShowOverlay(true);
168
- } catch (validationError) {
169
- console.warn('Validation error, proceeding to onboarding:', validationError);
170
- setShowOnboarding(true);
251
+ } catch (credentialsError) {
252
+ console.warn('⚠️ Failed to retrieve existing credentials:', credentialsError);
253
+ // Continue with normal flow
171
254
  }
172
- } else {
173
- // If no credentials, show onboarding
174
- setShowOnboarding(true);
175
255
  }
256
+
257
+ if (enableLogging) {
258
+ console.log('🎨 Opening Onairos overlay...');
259
+ }
260
+
261
+ setShowOverlay(true);
176
262
  } catch (error) {
177
- console.error('Error during button press flow:', error);
178
- // Fall back to onboarding on error
179
- setShowOnboarding(true);
180
- onRejection?.(error instanceof Error ? error.message : 'Unknown error');
181
- } finally {
182
- setIsLoading(false);
263
+ console.error('Error opening overlay:', error);
264
+ if (onRejection) {
265
+ onRejection(`Failed to open overlay: ${error.message}`);
266
+ }
183
267
  }
184
- };
268
+ }, [isInitialized, initializationError, preCheck, enableLogging, onRejection, onResolved]);
185
269
 
186
- const handleOnboardingComplete = useCallback((apiUrl: string, token: string, data: any) => {
187
- setShowOnboarding(false);
188
- if (onResolved) {
189
- onResolved(apiUrl, token, data);
270
+ const handleCloseOverlay = useCallback((result?: any) => {
271
+ if (enableLogging) {
272
+ console.log('🔽 Closing Onairos overlay');
273
+ }
274
+
275
+ setShowOverlay(false);
276
+
277
+ if (result && onResolved) {
278
+ onResolved(result.apiUrl, result.token, result.userData);
190
279
  }
191
- }, [onResolved]);
280
+ }, [enableLogging, onResolved]);
192
281
 
193
- const handleOverlayResolved = useCallback((apiUrl: string, token: string, data: any) => {
282
+ const handleOverlayRejection = useCallback((error?: string) => {
283
+ if (enableLogging) {
284
+ console.log('❌ Overlay rejected:', error);
285
+ }
286
+
194
287
  setShowOverlay(false);
195
- if (onResolved) {
196
- onResolved(apiUrl, token, data);
288
+
289
+ if (onRejection) {
290
+ onRejection(error);
197
291
  }
198
- }, [onResolved]);
292
+ }, [enableLogging, onRejection]);
293
+
294
+ // Show error state if initialization failed
295
+ if (initializationError && !isInitializing) {
296
+ return (
297
+ <View style={styles.errorContainer}>
298
+ <TouchableOpacity
299
+ style={[styles.errorButton, { backgroundColor: '#FF6B6B' }]}
300
+ onPress={() => {
301
+ Alert.alert(
302
+ 'SDK Error',
303
+ `Onairos SDK initialization failed:\n\n${initializationError}\n\nPlease check your API key and try again.`,
304
+ [{ text: 'OK' }]
305
+ );
306
+ }}
307
+ >
308
+ <Text style={styles.errorButtonText}>⚠️ SDK Error</Text>
309
+ </TouchableOpacity>
310
+ </View>
311
+ );
312
+ }
313
+
314
+ // Show loading state while initializing
315
+ if (isInitializing || !isInitialized) {
316
+ return (
317
+ <View style={styles.loadingContainer}>
318
+ <TouchableOpacity
319
+ style={[styles.loadingButton, { backgroundColor: '#999' }]}
320
+ disabled={true}
321
+ >
322
+ <Text style={styles.loadingButtonText}>🔄 Initializing...</Text>
323
+ </TouchableOpacity>
324
+ </View>
325
+ );
326
+ }
199
327
 
200
- // Apply custom styling based on props
201
- const buttonStyle: ViewStyle[] = [
202
- styles.button,
203
- {
328
+ // Get button style based on type
329
+ const getButtonStyle = (): ViewStyle => {
330
+ const baseStyle: ViewStyle = {
204
331
  width: buttonWidth,
205
- height: buttonHeight || 48,
206
- backgroundColor: getBackgroundColor(),
207
- borderWidth: hasStroke ? 1 : 0,
208
- borderColor: darkMode ? '#555555' : '#000000',
209
- borderRadius: buttonType === 'pill' ? 24 : 8,
210
- },
211
- ];
332
+ height: buttonHeight,
333
+ backgroundColor: color,
334
+ borderRadius: buttonType === 'pill' ? buttonHeight / 2 : 8,
335
+ alignItems: 'center',
336
+ justifyContent: 'center',
337
+ flexDirection: 'row',
338
+ opacity: enabled ? 1 : 0.6,
339
+ };
340
+
341
+ if (hasStroke) {
342
+ baseStyle.borderWidth = 2;
343
+ baseStyle.borderColor = darkMode ? '#fff' : '#000';
344
+ }
345
+
346
+ return baseStyle;
347
+ };
212
348
 
213
- const textStyle: TextStyle = {
214
- ...styles.buttonText,
215
- color: getTextColor(),
216
- opacity: enabled ? 1 : 0.7,
349
+ const getButtonText = (): string => {
350
+ switch (buttonForm) {
351
+ case 'connect':
352
+ return 'Connect with Onairos';
353
+ default:
354
+ return 'Continue with Onairos';
355
+ }
217
356
  };
218
357
 
219
358
  return (
220
359
  <>
221
360
  <TouchableOpacity
222
- style={buttonStyle}
223
- onPress={handlePress}
224
- disabled={!enabled || isLoading}
225
- accessibilityLabel="Sign in with Onairos"
226
- onPressIn={() => setIsPressed(true)}
227
- onPressOut={() => setIsPressed(false)}
361
+ style={getButtonStyle()}
362
+ onPress={handleShowOverlay}
363
+ disabled={!enabled || isInitializing || !isInitialized}
364
+ activeOpacity={0.8}
228
365
  >
229
- <View style={styles.buttonContent}>
230
- <Image
231
- source={require('../assets/images/onairos_logo.png')}
232
- style={styles.logo}
233
- resizeMode="contain"
234
- />
235
- <Text style={textStyle}>{getButtonText()}</Text>
236
- </View>
366
+ <Image
367
+ source={require('../assets/images/onairos_logo.png')}
368
+ style={styles.logo}
369
+ resizeMode="contain"
370
+ />
371
+ <Text style={[styles.buttonText, { color: darkMode ? '#000' : '#fff' }]}>
372
+ {getButtonText()}
373
+ </Text>
237
374
  </TouchableOpacity>
238
375
 
239
- {/* Overlay and Onboarding components rendered outside the button */}
240
- {showOnboarding && (
241
- <UniversalOnboarding
242
- visible={showOnboarding}
243
- onClose={() => {
244
- setShowOnboarding(false);
245
- onRejection?.('User closed onboarding');
246
- }}
247
- AppName={AppName}
248
- requestData={requestData as any}
249
- returnLink={returnLink || ''}
250
- onComplete={handleOnboardingComplete}
251
- debug={debug}
252
- test={testMode}
253
- preferredPlatform={preferredPlatform}
254
- />
255
- )}
256
-
257
- {/* Overlay rendered through Portal to ensure it appears at root level */}
258
- {showOverlay && storedCredentials && (
376
+ {showOverlay && (
259
377
  <Portal>
260
- <Overlay
261
- data={requestData || {}}
262
- username={storedCredentials.username}
263
- modelKey={storedCredentials.userPin || ''}
264
- onResolved={handleOverlayResolved}
265
- appName={AppName}
266
- darkMode={darkMode}
378
+ <UniversalOnboarding
379
+ visible={showOverlay}
380
+ onClose={handleCloseOverlay}
381
+ AppName={AppName}
382
+ requestData={requestData || {}}
383
+ returnLink={returnLink}
384
+ prefillUrl={prefillUrl}
385
+ onComplete={handleCloseOverlay}
386
+ embedd={false}
387
+ debug={debug}
388
+ testMode={testMode}
389
+ preferredPlatform={preferredPlatform}
390
+ config={getApiConfig() || undefined}
267
391
  />
268
392
  </Portal>
269
393
  )}
@@ -299,4 +423,32 @@ const styles = StyleSheet.create({
299
423
  fontWeight: '600',
300
424
  textAlign: 'center',
301
425
  },
426
+ errorContainer: {
427
+ flex: 1,
428
+ justifyContent: 'center',
429
+ alignItems: 'center',
430
+ },
431
+ errorButton: {
432
+ padding: 16,
433
+ borderRadius: 8,
434
+ },
435
+ errorButtonText: {
436
+ fontSize: 16,
437
+ fontWeight: '600',
438
+ color: '#fff',
439
+ },
440
+ loadingContainer: {
441
+ flex: 1,
442
+ justifyContent: 'center',
443
+ alignItems: 'center',
444
+ },
445
+ loadingButton: {
446
+ padding: 16,
447
+ borderRadius: 8,
448
+ },
449
+ loadingButtonText: {
450
+ fontSize: 16,
451
+ fontWeight: '600',
452
+ color: '#fff',
453
+ },
302
454
  });
@@ -288,7 +288,7 @@ export const OnairosButton = forwardRef<OnairosButtonRef, OnairosButtonProps>(({
288
288
  returnLink={returnLink || ''}
289
289
  onComplete={handleOnboardingComplete}
290
290
  debug={debug}
291
- test={testMode}
291
+ testMode={testMode}
292
292
  preferredPlatform={preferredPlatform}
293
293
  />
294
294
  )}
@@ -56,7 +56,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
56
56
  onComplete,
57
57
  embedd = false,
58
58
  debug = false,
59
- test = false,
59
+ testMode = false,
60
60
  preferredPlatform,
61
61
  inferenceData,
62
62
  auto = false,
@@ -93,8 +93,8 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
93
93
 
94
94
 
95
95
  // Parse test mode options
96
- const testModeOptions = typeof test === 'object' ? test : {};
97
- const isTestMode = test === true || (typeof test === 'object' && test !== null);
96
+ const testModeOptions = typeof testMode === 'object' ? testMode : {} as any;
97
+ const isTestMode = testMode === true || (typeof testMode === 'object' && testMode !== null);
98
98
  const showTestControls = (debug || isTestMode) && requestData;
99
99
 
100
100
  // Simple 2-flow system
@@ -169,7 +169,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
169
169
  });
170
170
 
171
171
  // Pre-populate with mock connections in debug mode
172
- if (test || Platform.OS === 'web') {
172
+ if (testMode || Platform.OS === 'web') {
173
173
  setConnections({
174
174
  instagram: { userName: 'instagram_user', connected: true },
175
175
  youtube: { userName: 'youtube_user', connected: true },
@@ -573,7 +573,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
573
573
  Alert.alert('Error', 'An unexpected error occurred. Please try again.');
574
574
  }
575
575
  }
576
- }, [email, isVerifyingCode, debug, test]);
576
+ }, [email, isVerifyingCode, debug, testMode]);
577
577
 
578
578
  // Function to handle verification code submission
579
579
  const handleVerificationSubmit = useCallback(async () => {
@@ -1157,7 +1157,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
1157
1157
  <Text style={styles.privacyMessage}>
1158
1158
  None of your app data is shared with ANYONE
1159
1159
  </Text>
1160
- {(debug || test) && (
1160
+ {(debug || testMode) && (
1161
1161
  <Text style={styles.developmentNote}>
1162
1162
  🧪 Test Mode: You can proceed without connecting any platforms
1163
1163
  </Text>