@onairos/react-native 3.0.68 → 3.0.70

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.
@@ -100,6 +100,17 @@ export const initiateOAuth = async (platform: string, username: string, appName?
100
100
  console.log('🌐 Platform uses OAuth WebView flow');
101
101
  console.log('🔗 Auth endpoint:', PLATFORM_AUTH_CONFIG[platform].authEndpoint);
102
102
 
103
+ // Pre-flight connectivity check
104
+ console.log('🔍 Performing pre-flight connectivity check...');
105
+ const connectivityResult = await testApiConnectivity();
106
+
107
+ if (!connectivityResult.success) {
108
+ console.error('❌ Pre-flight connectivity check failed:', connectivityResult.error);
109
+ throw new Error(`Cannot reach authentication server: ${connectivityResult.error}`);
110
+ }
111
+
112
+ console.log('✅ Pre-flight connectivity check passed');
113
+
103
114
  // Handle Instagram with specific API format
104
115
  if (platform === 'instagram') {
105
116
  const state = 'djksbfds';
@@ -112,13 +123,31 @@ export const initiateOAuth = async (platform: string, username: string, appName?
112
123
 
113
124
  console.log('📤 Sending Instagram OAuth request:', jsonData);
114
125
 
115
- const response = await fetch('https://api2.onairos.uk/instagram/authorize', {
116
- method: 'POST',
117
- headers: {
118
- 'Content-Type': 'application/json',
119
- },
120
- body: JSON.stringify(jsonData),
121
- });
126
+ const controller = new AbortController();
127
+ const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
128
+
129
+ let response: Response;
130
+ try {
131
+ response = await fetch('https://api2.onairos.uk/instagram/authorize', {
132
+ method: 'POST',
133
+ headers: {
134
+ 'Content-Type': 'application/json',
135
+ 'User-Agent': 'OnairosReactNative/1.0',
136
+ },
137
+ body: JSON.stringify(jsonData),
138
+ signal: controller.signal,
139
+ });
140
+ } catch (fetchError) {
141
+ clearTimeout(timeoutId);
142
+
143
+ if (fetchError.name === 'AbortError') {
144
+ throw new Error(`Request timeout: Instagram OAuth server took too long to respond`);
145
+ }
146
+
147
+ throw new Error(`Network error: ${fetchError.message || 'Failed to connect to Instagram OAuth server'}`);
148
+ }
149
+
150
+ clearTimeout(timeoutId);
122
151
 
123
152
  console.log('📡 Instagram OAuth response status:', response.status);
124
153
  console.log('📡 Instagram OAuth response headers:', response.headers);
@@ -134,7 +163,13 @@ export const initiateOAuth = async (platform: string, username: string, appName?
134
163
 
135
164
  if (responseData.instagramURL) {
136
165
  console.log('✅ Instagram OAuth URL received:', responseData.instagramURL);
137
- return responseData.instagramURL;
166
+
167
+ // Validate the URL before returning
168
+ if (await validateOAuthUrl(responseData.instagramURL)) {
169
+ return responseData.instagramURL;
170
+ } else {
171
+ throw new Error('Received invalid Instagram OAuth URL');
172
+ }
138
173
  }
139
174
 
140
175
  console.error('❌ No Instagram URL found in response');
@@ -152,14 +187,32 @@ export const initiateOAuth = async (platform: string, username: string, appName?
152
187
 
153
188
  console.log(`📤 Sending ${platform} OAuth request:`, jsonData);
154
189
 
155
- // Make the request to get the OAuth URL
156
- const response = await fetch(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
157
- method: 'POST',
158
- headers: {
159
- 'Content-Type': 'application/json',
160
- },
161
- body: JSON.stringify(jsonData),
162
- });
190
+ // Make the request to get the OAuth URL with enhanced error handling
191
+ const controller = new AbortController();
192
+ const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
193
+
194
+ let response: Response;
195
+ try {
196
+ response = await fetch(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
197
+ method: 'POST',
198
+ headers: {
199
+ 'Content-Type': 'application/json',
200
+ 'User-Agent': 'OnairosReactNative/1.0',
201
+ },
202
+ body: JSON.stringify(jsonData),
203
+ signal: controller.signal,
204
+ });
205
+ } catch (fetchError) {
206
+ clearTimeout(timeoutId);
207
+
208
+ if (fetchError.name === 'AbortError') {
209
+ throw new Error(`Request timeout: ${platform} OAuth server took too long to respond`);
210
+ }
211
+
212
+ throw new Error(`Network error: ${fetchError.message || 'Failed to connect to OAuth server'}`);
213
+ }
214
+
215
+ clearTimeout(timeoutId);
163
216
 
164
217
  console.log(`📡 ${platform} OAuth response status:`, response.status);
165
218
  console.log(`📡 ${platform} OAuth response headers:`, response.headers);
@@ -181,36 +234,108 @@ export const initiateOAuth = async (platform: string, username: string, appName?
181
234
  }
182
235
 
183
236
  // Check if the response contains the OAuth URL based on platform
237
+ let oauthUrl: string | null = null;
238
+
184
239
  switch (platform) {
185
240
  case 'reddit':
186
- if (data.redditURL) return data.redditURL;
241
+ oauthUrl = data.redditURL;
187
242
  break;
188
243
  case 'pinterest':
189
- if (data.pinterestURL) return data.pinterestURL;
244
+ oauthUrl = data.pinterestURL;
190
245
  break;
191
246
  case 'youtube':
192
- if (data.youtubeURL) return data.youtubeURL;
247
+ oauthUrl = data.youtubeURL;
193
248
  break;
194
249
  case 'email':
195
250
  // Gmail might return under different field names
196
- if (data.emailURL) return data.emailURL;
197
- if (data.gmailURL) return data.gmailURL;
198
- if (data.authUrl) return data.authUrl;
199
- if (data.url) return data.url;
251
+ oauthUrl = data.emailURL || data.gmailURL || data.authUrl || data.url;
200
252
  break;
201
253
  default:
202
- if (data.url) return data.url;
254
+ oauthUrl = data.url;
203
255
  break;
204
256
  }
205
257
 
206
- console.error(`❌ No OAuth URL found in response for ${platform}. Response:`, data);
207
- throw new Error(`No OAuth URL found in response for ${platform}`);
258
+ if (!oauthUrl) {
259
+ console.error(`❌ No OAuth URL found in response for ${platform}. Response:`, data);
260
+ throw new Error(`No OAuth URL found in response for ${platform}`);
261
+ }
262
+
263
+ console.log(`✅ ${platform} OAuth URL received:`, oauthUrl);
264
+
265
+ // Validate the URL before returning
266
+ if (await validateOAuthUrl(oauthUrl)) {
267
+ return oauthUrl;
268
+ } else {
269
+ throw new Error(`Received invalid ${platform} OAuth URL`);
270
+ }
208
271
  } catch (error) {
209
272
  console.error(`Error initiating OAuth for ${platform}:`, error);
210
273
  throw error;
211
274
  }
212
275
  };
213
276
 
277
+ /**
278
+ * Validates an OAuth URL to ensure it's reachable
279
+ * @param url The OAuth URL to validate
280
+ * @returns Promise<boolean> indicating if the URL is valid and reachable
281
+ */
282
+ const validateOAuthUrl = async (url: string): Promise<boolean> => {
283
+ try {
284
+ console.log('🔍 Validating OAuth URL:', url);
285
+
286
+ // Basic URL format validation
287
+ if (!url || typeof url !== 'string') {
288
+ console.error('❌ Invalid URL format:', url);
289
+ return false;
290
+ }
291
+
292
+ // Check if URL starts with https
293
+ if (!url.startsWith('https://')) {
294
+ console.error('❌ URL must use HTTPS:', url);
295
+ return false;
296
+ }
297
+
298
+ // Try to parse the URL
299
+ try {
300
+ new URL(url);
301
+ } catch (parseError) {
302
+ console.error('❌ URL parsing failed:', parseError);
303
+ return false;
304
+ }
305
+
306
+ // Make a HEAD request to check if the URL is reachable
307
+ const controller = new AbortController();
308
+ const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout
309
+
310
+ try {
311
+ const response = await fetch(url, {
312
+ method: 'HEAD',
313
+ signal: controller.signal,
314
+ });
315
+
316
+ clearTimeout(timeoutId);
317
+
318
+ // Accept any response that's not a network error
319
+ // OAuth pages might return various status codes
320
+ console.log('✅ OAuth URL validation successful, status:', response.status);
321
+ return true;
322
+ } catch (fetchError) {
323
+ clearTimeout(timeoutId);
324
+
325
+ if (fetchError.name === 'AbortError') {
326
+ console.warn('⚠️ OAuth URL validation timeout, but proceeding anyway');
327
+ return true; // Allow timeout as URLs might be slow to respond
328
+ }
329
+
330
+ console.warn('⚠️ OAuth URL validation failed, but proceeding anyway:', fetchError.message);
331
+ return true; // Allow network errors as they might be temporary
332
+ }
333
+ } catch (error) {
334
+ console.warn('⚠️ OAuth URL validation error, but proceeding anyway:', error);
335
+ return true; // Allow validation errors to not block the flow
336
+ }
337
+ };
338
+
214
339
  /**
215
340
  * Initiates the native SDK authentication flow for a platform
216
341
  * @param platform The platform to authenticate with
@@ -473,22 +598,62 @@ export const testApiConnectivity = async (): Promise<{ success: boolean; error?:
473
598
  try {
474
599
  console.log('🔍 Testing connectivity to Onairos API...');
475
600
 
476
- const response = await fetch('https://api2.onairos.uk/health', {
477
- method: 'GET',
478
- headers: {
479
- 'Content-Type': 'application/json',
480
- },
481
- });
601
+ // Test multiple endpoints for better reliability
602
+ const testEndpoints = [
603
+ 'https://api2.onairos.uk/health',
604
+ 'https://api2.onairos.uk', // Base URL
605
+ ];
482
606
 
483
- console.log('🌐 API connectivity test response:', response.status);
607
+ let lastError: string | null = null;
484
608
 
485
- if (response.ok) {
486
- console.log('✅ API server is reachable');
487
- return { success: true };
488
- } else {
489
- console.log('⚠️ API server responded with error:', response.status);
490
- return { success: false, error: `API server error: ${response.status}` };
609
+ for (const endpoint of testEndpoints) {
610
+ try {
611
+ console.log(`🔍 Testing endpoint: ${endpoint}`);
612
+
613
+ const controller = new AbortController();
614
+ const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout
615
+
616
+ const response = await fetch(endpoint, {
617
+ method: 'GET',
618
+ headers: {
619
+ 'Content-Type': 'application/json',
620
+ 'User-Agent': 'OnairosReactNative/1.0',
621
+ },
622
+ signal: controller.signal,
623
+ });
624
+
625
+ clearTimeout(timeoutId);
626
+
627
+ console.log(`🌐 API connectivity test response for ${endpoint}:`, response.status);
628
+
629
+ if (response.ok || response.status === 404) {
630
+ // Accept 404 as it means the server is reachable
631
+ console.log('✅ API server is reachable');
632
+ return { success: true };
633
+ } else {
634
+ console.log(`⚠️ API server responded with status ${response.status} for ${endpoint}`);
635
+ lastError = `API server error: ${response.status}`;
636
+ // Continue to next endpoint
637
+ }
638
+ } catch (fetchError) {
639
+ console.log(`❌ Failed to reach ${endpoint}:`, fetchError);
640
+
641
+ if (fetchError.name === 'AbortError') {
642
+ lastError = 'Connection timeout - API server took too long to respond';
643
+ } else if (fetchError.message.includes('Network request failed')) {
644
+ lastError = 'Network error - check your internet connection';
645
+ } else if (fetchError.message.includes('not connected to the internet')) {
646
+ lastError = 'No internet connection';
647
+ } else {
648
+ lastError = `Network error: ${fetchError.message}`;
649
+ }
650
+
651
+ // Continue to next endpoint
652
+ }
491
653
  }
654
+
655
+ console.error('❌ All API connectivity tests failed');
656
+ return { success: false, error: lastError || 'Cannot reach API server' };
492
657
  } catch (error) {
493
658
  console.error('❌ API connectivity test failed:', error);
494
659
  return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };