@onairos/react-native 3.1.9 → 3.1.12

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.
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.NETWORK_RETRY_OPTIONS = exports.DEFAULT_RETRY_OPTIONS = exports.API_RETRY_OPTIONS = void 0;
7
+ exports.fetchWithRetry = fetchWithRetry;
8
+ exports.healthCheck = healthCheck;
9
+ exports.withRetry = withRetry;
10
+ /**
11
+ * 🔄 Retry Helper Utility
12
+ *
13
+ * Provides robust retry logic with exponential backoff for network operations.
14
+ * Used throughout the Onairos SDK for handling transient failures gracefully.
15
+ */
16
+
17
+ /**
18
+ * Default retry options for the Onairos SDK
19
+ */
20
+ const DEFAULT_RETRY_OPTIONS = exports.DEFAULT_RETRY_OPTIONS = {
21
+ maxRetries: 3,
22
+ baseDelay: 1000,
23
+ maxDelay: 5000,
24
+ exponentialBackoff: true,
25
+ enableLogging: false,
26
+ shouldRetry: (error, attempt) => {
27
+ // Don't retry client errors (4xx) except for 408 (timeout) and 429 (rate limit)
28
+ if (error.status >= 400 && error.status < 500 && error.status !== 408 && error.status !== 429) {
29
+ return false;
30
+ }
31
+
32
+ // Retry network errors, timeouts, and server errors (5xx)
33
+ if (error.name === 'AbortError' || error.message.includes('Network request failed') || error.message.includes('fetch') || error.message.includes('ENOTFOUND') || error.message.includes('timeout') || error.status >= 500) {
34
+ return true;
35
+ }
36
+
37
+ // Retry JSON parse errors (likely server issues)
38
+ if (error.message.includes('JSON Parse error') || error.message.includes('Unexpected character')) {
39
+ return true;
40
+ }
41
+ return false;
42
+ }
43
+ };
44
+
45
+ /**
46
+ * Execute a function with retry logic and exponential backoff
47
+ * @param fn Function to execute (should return a Promise)
48
+ * @param options Retry configuration options
49
+ * @returns Promise with retry result
50
+ */
51
+ async function withRetry(fn, options = {}) {
52
+ const config = {
53
+ ...DEFAULT_RETRY_OPTIONS,
54
+ ...options
55
+ };
56
+ const startTime = Date.now();
57
+ let lastError = null;
58
+ for (let attempt = 1; attempt <= config.maxRetries + 1; attempt++) {
59
+ try {
60
+ if (config.enableLogging && attempt > 1) {
61
+ console.log(`🔄 Retry attempt ${attempt}/${config.maxRetries + 1}`);
62
+ }
63
+ const result = await fn();
64
+ return {
65
+ success: true,
66
+ data: result,
67
+ attempts: attempt,
68
+ totalDuration: Date.now() - startTime
69
+ };
70
+ } catch (error) {
71
+ lastError = error;
72
+
73
+ // Check if we should retry this error
74
+ const shouldRetryError = config.shouldRetry ? config.shouldRetry(error, attempt) : true;
75
+
76
+ // If this is the last attempt or we shouldn't retry, throw the error
77
+ if (attempt > config.maxRetries || !shouldRetryError) {
78
+ if (config.enableLogging) {
79
+ console.error(`❌ All retry attempts exhausted or error not retryable: ${error.message}`);
80
+ }
81
+ break;
82
+ }
83
+
84
+ // Calculate delay for next attempt
85
+ let delay = config.baseDelay;
86
+ if (config.exponentialBackoff) {
87
+ delay = Math.min(config.baseDelay * Math.pow(2, attempt - 1), config.maxDelay);
88
+ }
89
+
90
+ // Add some jitter to prevent thundering herd
91
+ const jitter = Math.random() * 0.1 * delay;
92
+ delay = Math.floor(delay + jitter);
93
+ if (config.onRetry) {
94
+ config.onRetry(error, attempt, delay);
95
+ }
96
+ if (config.enableLogging) {
97
+ console.log(`⏳ Waiting ${delay}ms before retry (attempt ${attempt}/${config.maxRetries + 1})`);
98
+ }
99
+
100
+ // Wait before next attempt
101
+ await new Promise(resolve => setTimeout(() => resolve(), delay));
102
+ }
103
+ }
104
+ return {
105
+ success: false,
106
+ error: lastError || new Error('Unknown error'),
107
+ attempts: config.maxRetries + 1,
108
+ totalDuration: Date.now() - startTime
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Retry configuration for API calls
114
+ */
115
+ const API_RETRY_OPTIONS = exports.API_RETRY_OPTIONS = {
116
+ maxRetries: 3,
117
+ baseDelay: 1000,
118
+ maxDelay: 5000,
119
+ exponentialBackoff: true,
120
+ shouldRetry: (error, attempt) => {
121
+ // Enhanced retry logic for API calls
122
+
123
+ // Never retry authentication errors (401) or permission errors (403)
124
+ if (error.status === 401 || error.status === 403) {
125
+ return false;
126
+ }
127
+
128
+ // Never retry bad request errors (400) or not found (404) unless it's a specific case
129
+ if (error.status === 400 || error.status === 404 && !error.message.includes('validation endpoint')) {
130
+ return false;
131
+ }
132
+
133
+ // Retry rate limiting (429) with longer delays
134
+ if (error.status === 429) {
135
+ return attempt <= 2; // Limit retries for rate limiting
136
+ }
137
+
138
+ // Retry server errors (5xx)
139
+ if (error.status >= 500) {
140
+ return true;
141
+ }
142
+
143
+ // Retry timeout and network errors
144
+ if (error.name === 'AbortError' || error.message.includes('timeout') || error.message.includes('Network request failed') || error.message.includes('fetch') || error.message.includes('ENOTFOUND')) {
145
+ return true;
146
+ }
147
+
148
+ // Retry JSON parse errors (server returning HTML instead of JSON)
149
+ if (error.message.includes('JSON Parse error') || error.message.includes('Unexpected character') || error.message.includes('HTML page instead of JSON')) {
150
+ return true;
151
+ }
152
+ return false;
153
+ },
154
+ onRetry: (error, attempt, delay) => {
155
+ console.warn(`⚠️ API call failed (attempt ${attempt}), retrying in ${delay}ms: ${error.message}`);
156
+ }
157
+ };
158
+
159
+ /**
160
+ * Specialized retry for network/connectivity issues
161
+ */
162
+ const NETWORK_RETRY_OPTIONS = exports.NETWORK_RETRY_OPTIONS = {
163
+ maxRetries: 2,
164
+ baseDelay: 2000,
165
+ maxDelay: 8000,
166
+ exponentialBackoff: true,
167
+ shouldRetry: (error, attempt) => {
168
+ // Only retry actual network/connectivity issues
169
+ return error.message.includes('Network request failed') || error.message.includes('ENOTFOUND') || error.message.includes('DNS') || error.name === 'AbortError';
170
+ }
171
+ };
172
+
173
+ /**
174
+ * Create a retry wrapper for fetch requests
175
+ * @param url Request URL
176
+ * @param options Fetch options
177
+ * @param retryOptions Retry configuration
178
+ * @returns Promise with fetch response
179
+ */
180
+ async function fetchWithRetry(url, options = {}, retryOptions = API_RETRY_OPTIONS) {
181
+ const result = await withRetry(() => fetch(url, options), retryOptions);
182
+ if (!result.success) {
183
+ throw result.error;
184
+ }
185
+ return result.data;
186
+ }
187
+
188
+ /**
189
+ * Health check function with retry for testing connectivity
190
+ * @param url URL to check
191
+ * @param timeout Timeout in milliseconds
192
+ * @returns Promise indicating if the service is reachable
193
+ */
194
+ async function healthCheck(url, timeout = 5000) {
195
+ const startTime = Date.now();
196
+ try {
197
+ const controller = new AbortController();
198
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
199
+ const response = await fetch(url, {
200
+ method: 'GET',
201
+ signal: controller.signal,
202
+ headers: {
203
+ 'User-Agent': 'OnairosReactNative/HealthCheck'
204
+ }
205
+ });
206
+ clearTimeout(timeoutId);
207
+ return {
208
+ reachable: true,
209
+ status: response.status,
210
+ duration: Date.now() - startTime
211
+ };
212
+ } catch (error) {
213
+ return {
214
+ reachable: false,
215
+ error: error.message,
216
+ duration: Date.now() - startTime
217
+ };
218
+ }
219
+ }
220
+ //# sourceMappingURL=retryHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["DEFAULT_RETRY_OPTIONS","exports","maxRetries","baseDelay","maxDelay","exponentialBackoff","enableLogging","shouldRetry","error","attempt","status","name","message","includes","withRetry","fn","options","config","startTime","Date","now","lastError","console","log","result","success","data","attempts","totalDuration","shouldRetryError","delay","Math","min","pow","jitter","random","floor","onRetry","Promise","resolve","setTimeout","Error","API_RETRY_OPTIONS","warn","NETWORK_RETRY_OPTIONS","fetchWithRetry","url","retryOptions","fetch","healthCheck","timeout","controller","AbortController","timeoutId","abort","response","method","signal","headers","clearTimeout","reachable","duration"],"sourceRoot":"..\\..\\..\\src","sources":["utils/retryHelper.ts"],"mappings":"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","ignoreList":[]}
@@ -87,7 +87,15 @@ export const initializeApiKey = async config => {
87
87
  // Validate the API key (handles both admin and developer keys)
88
88
  const validation = await validateApiKey(config.apiKey);
89
89
  if (!validation.isValid) {
90
- throw new Error(`API key validation failed: ${validation.error}`);
90
+ // If it's a network error or JSON parse error, warn but don't fail initialization
91
+ // Use defensive error checking to prevent compilation issues
92
+ const errorMessage = validation.error || '';
93
+ if (errorMessage.includes('Network error') || errorMessage.includes('JSON Parse error') || errorMessage.includes('API validation endpoint returned')) {
94
+ console.warn('⚠️ API key validation failed due to network/server issues, continuing in offline mode:', validation.error);
95
+ console.warn('📝 SDK will function with limited validation. Ensure your API key is valid for production use.');
96
+ } else {
97
+ throw new Error(`API key validation failed: ${validation.error}`);
98
+ }
91
99
  }
92
100
 
93
101
  // Try to load existing JWT token
@@ -150,7 +158,7 @@ export const isAdminKey = apiKey => {
150
158
  */
151
159
  export const validateApiKey = async apiKey => {
152
160
  try {
153
- var _globalConfig2, _globalConfig3;
161
+ var _globalConfig2, _globalConfig3, _globalConfig4;
154
162
  console.log('🔍 Validating API key...');
155
163
 
156
164
  // Check if it's an admin key
@@ -190,82 +198,187 @@ export const validateApiKey = async apiKey => {
190
198
  const environment = ((_globalConfig2 = globalConfig) === null || _globalConfig2 === void 0 ? void 0 : _globalConfig2.environment) || 'production';
191
199
  const baseUrl = API_ENDPOINTS[environment];
192
200
  const timeout = ((_globalConfig3 = globalConfig) === null || _globalConfig3 === void 0 ? void 0 : _globalConfig3.timeout) || 30000;
201
+ const maxRetries = ((_globalConfig4 = globalConfig) === null || _globalConfig4 === void 0 ? void 0 : _globalConfig4.retryAttempts) || 3;
202
+
203
+ // Retry logic for network failures
204
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
205
+ // Create abort controller for timeout
206
+ const controller = new AbortController();
207
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
208
+ try {
209
+ var _globalConfig5;
210
+ if ((_globalConfig5 = globalConfig) !== null && _globalConfig5 !== void 0 && _globalConfig5.enableLogging && attempt > 1) {
211
+ console.log(`🔄 Retry attempt ${attempt}/${maxRetries} for API key validation`);
212
+ }
213
+ const response = await fetch(`${baseUrl}/auth/validate-key`, {
214
+ method: 'POST',
215
+ headers: {
216
+ 'Content-Type': 'application/json',
217
+ 'Authorization': `Bearer ${apiKey}`,
218
+ 'User-Agent': 'OnairosReactNative/3.1.11',
219
+ 'X-API-Key-Type': keyType,
220
+ 'X-SDK-Platform': 'react-native',
221
+ 'X-Retry-Attempt': attempt.toString()
222
+ },
223
+ body: JSON.stringify({
224
+ environment,
225
+ sdk_version: '3.1.11',
226
+ platform: 'react-native',
227
+ keyType,
228
+ timestamp: new Date().toISOString(),
229
+ attempt
230
+ }),
231
+ signal: controller.signal
232
+ });
233
+ clearTimeout(timeoutId);
193
234
 
194
- // Create abort controller for timeout
195
- const controller = new AbortController();
196
- const timeoutId = setTimeout(() => controller.abort(), timeout);
197
- try {
198
- const response = await fetch(`${baseUrl}/auth/validate-key`, {
199
- method: 'POST',
200
- headers: {
201
- 'Content-Type': 'application/json',
202
- 'Authorization': `Bearer ${apiKey}`,
203
- 'User-Agent': 'OnairosReactNative/1.0',
204
- 'X-API-Key-Type': keyType
205
- },
206
- body: JSON.stringify({
207
- environment,
208
- sdk_version: '3.0.72',
209
- platform: 'react-native',
210
- keyType,
211
- timestamp: new Date().toISOString()
212
- }),
213
- signal: controller.signal
214
- });
215
- clearTimeout(timeoutId);
216
- const data = await response.json();
217
- if (response.ok && data.success) {
218
- var _globalConfig4;
219
- const result = {
220
- isValid: true,
221
- permissions: data.permissions || [],
222
- rateLimits: data.rateLimits || null,
223
- keyType: keyType
224
- };
225
-
226
- // Cache the successful result
227
- validationCache.set(apiKey, {
228
- result,
229
- timestamp: Date.now()
235
+ // First check if we got a valid response
236
+ if (!response) {
237
+ throw new Error('No response received from server');
238
+ }
239
+
240
+ // Check if response is actually JSON before trying to parse
241
+ const contentType = response.headers.get('content-type');
242
+ const isJsonResponse = contentType && contentType.includes('application/json');
243
+ if (!isJsonResponse) {
244
+ const textContent = await response.text();
245
+ const previewText = textContent.substring(0, 200);
246
+ console.error('❌ API endpoint returned non-JSON response:', {
247
+ status: response.status,
248
+ statusText: response.statusText,
249
+ contentType: contentType || 'unknown',
250
+ preview: previewText,
251
+ url: `${baseUrl}/auth/validate-key`,
252
+ attempt: attempt
253
+ });
254
+
255
+ // Handle specific error cases
256
+ if (response.status === 404) {
257
+ throw new Error(`API validation endpoint not found (404). The endpoint ${baseUrl}/auth/validate-key may not exist or be configured correctly.`);
258
+ } else if (response.status === 500) {
259
+ throw new Error(`Server error (500). The Onairos backend is experiencing issues.`);
260
+ } else if (response.status === 502 || response.status === 503) {
261
+ throw new Error(`Service unavailable (${response.status}). The Onairos backend may be temporarily down.`);
262
+ } else if (textContent.includes('<html') || textContent.includes('<!DOCTYPE')) {
263
+ throw new Error(`Server returned HTML page instead of JSON API response. This often indicates a routing issue or server misconfiguration.`);
264
+ } else {
265
+ throw new Error(`API validation endpoint returned ${response.status} - ${response.statusText}. Expected JSON but got ${contentType || 'unknown content type'}.`);
266
+ }
267
+ }
268
+
269
+ // Parse JSON response
270
+ let data;
271
+ try {
272
+ data = await response.json();
273
+ } catch (jsonError) {
274
+ console.error('❌ Failed to parse JSON response:', {
275
+ error: jsonError.message,
276
+ status: response.status,
277
+ contentType,
278
+ attempt: attempt
279
+ });
280
+ throw new Error(`Failed to parse server response as JSON: ${jsonError.message}`);
281
+ }
282
+
283
+ // Handle successful response
284
+ if (response.ok && data.success) {
285
+ var _globalConfig6;
286
+ const result = {
287
+ isValid: true,
288
+ permissions: data.permissions || [],
289
+ rateLimits: data.rateLimits || null,
290
+ keyType: keyType
291
+ };
292
+
293
+ // Cache the successful result
294
+ validationCache.set(apiKey, {
295
+ result,
296
+ timestamp: Date.now()
297
+ });
298
+ if ((_globalConfig6 = globalConfig) !== null && _globalConfig6 !== void 0 && _globalConfig6.enableLogging) {
299
+ console.log('✅ API key validation successful');
300
+ }
301
+ return result;
302
+ } else {
303
+ // Handle API errors (invalid key, etc.)
304
+ const errorMessage = data.error || data.message || `HTTP ${response.status}: ${response.statusText}`;
305
+ const result = {
306
+ isValid: false,
307
+ error: errorMessage,
308
+ keyType: keyType
309
+ };
310
+
311
+ // For client errors (4xx), don't retry
312
+ if (response.status >= 400 && response.status < 500) {
313
+ var _globalConfig7;
314
+ if ((_globalConfig7 = globalConfig) !== null && _globalConfig7 !== void 0 && _globalConfig7.enableLogging) {
315
+ console.error('❌ API key validation failed (client error):', errorMessage);
316
+ }
317
+ return result;
318
+ }
319
+
320
+ // For server errors (5xx), retry
321
+ throw new Error(errorMessage);
322
+ }
323
+ } catch (fetchError) {
324
+ var _globalConfig8;
325
+ clearTimeout(timeoutId);
326
+ if (fetchError.name === 'AbortError') {
327
+ const errorMessage = `API key validation timeout (${timeout}ms)`;
328
+ console.error('⏱️ API key validation timeout');
329
+ if (attempt === maxRetries) {
330
+ return {
331
+ isValid: false,
332
+ error: errorMessage,
333
+ keyType: keyType
334
+ };
335
+ }
336
+ continue; // Retry timeout errors
337
+ }
338
+
339
+ // Enhanced error message based on error type
340
+ let errorMessage = `Network error during API key validation: ${fetchError.message}`;
341
+
342
+ // Add specific guidance for common errors
343
+ if (fetchError.message.includes('JSON Parse error') || fetchError.message.includes('Unexpected character')) {
344
+ errorMessage = `Server returned invalid JSON response. This usually indicates the API endpoint returned HTML instead of JSON (often a 404 or server error page). ${fetchError.message}`;
345
+ } else if (fetchError.message.includes('Network request failed') || fetchError.message.includes('fetch')) {
346
+ errorMessage = `Network connectivity issue. Please check internet connection and verify the Onairos API is accessible. ${fetchError.message}`;
347
+ } else if (fetchError.message.includes('DNS') || fetchError.message.includes('ENOTFOUND')) {
348
+ errorMessage = `DNS resolution failed for ${baseUrl}. Please check network settings and domain accessibility. ${fetchError.message}`;
349
+ }
350
+ console.error('🌐 Network error during API key validation:', {
351
+ error: fetchError,
352
+ endpoint: `${baseUrl}/auth/validate-key`,
353
+ attempt: attempt,
354
+ maxRetries: maxRetries,
355
+ retryable: attempt < maxRetries
230
356
  });
231
- if ((_globalConfig4 = globalConfig) !== null && _globalConfig4 !== void 0 && _globalConfig4.enableLogging) {
232
- console.log('✅ API key validation successful');
357
+
358
+ // If this is the last attempt, return the error
359
+ if (attempt === maxRetries) {
360
+ return {
361
+ isValid: false,
362
+ error: errorMessage,
363
+ keyType: keyType
364
+ };
233
365
  }
234
- return result;
235
- } else {
236
- var _globalConfig5;
237
- const errorMessage = data.error || `HTTP ${response.status}: ${response.statusText}`;
238
- const result = {
239
- isValid: false,
240
- error: errorMessage,
241
- keyType: keyType
242
- };
243
-
244
- // Don't cache failed results
245
- if ((_globalConfig5 = globalConfig) !== null && _globalConfig5 !== void 0 && _globalConfig5.enableLogging) {
246
- console.error('❌ API key validation failed:', errorMessage);
366
+
367
+ // Wait before retrying (exponential backoff)
368
+ const backoffDelay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
369
+ if ((_globalConfig8 = globalConfig) !== null && _globalConfig8 !== void 0 && _globalConfig8.enableLogging) {
370
+ console.log(`⏳ Waiting ${backoffDelay}ms before retry...`);
247
371
  }
248
- return result;
249
- }
250
- } catch (fetchError) {
251
- clearTimeout(timeoutId);
252
- if (fetchError.name === 'AbortError') {
253
- const errorMessage = 'API key validation timeout';
254
- console.error('⏱️ API key validation timeout');
255
- return {
256
- isValid: false,
257
- error: errorMessage,
258
- keyType: keyType
259
- };
372
+ await new Promise(resolve => setTimeout(() => resolve(), backoffDelay));
260
373
  }
261
- const errorMessage = `Network error during API key validation: ${fetchError.message}`;
262
- console.error('🌐 Network error during API key validation:', fetchError);
263
- return {
264
- isValid: false,
265
- error: errorMessage,
266
- keyType: keyType
267
- };
268
374
  }
375
+
376
+ // This should never be reached, but just in case
377
+ return {
378
+ isValid: false,
379
+ error: 'All retry attempts exhausted',
380
+ keyType: keyType
381
+ };
269
382
  } catch (error) {
270
383
  const errorMessage = `API key validation error: ${error.message}`;
271
384
  console.error('❌ API key validation error:', error);
@@ -290,8 +403,8 @@ export const getApiConfig = () => {
290
403
  * @returns Current API key or null if not initialized
291
404
  */
292
405
  export const getApiKey = () => {
293
- var _globalConfig6;
294
- return ((_globalConfig6 = globalConfig) === null || _globalConfig6 === void 0 ? void 0 : _globalConfig6.apiKey) || null;
406
+ var _globalConfig9;
407
+ return ((_globalConfig9 = globalConfig) === null || _globalConfig9 === void 0 ? void 0 : _globalConfig9.apiKey) || null;
295
408
  };
296
409
 
297
410
  /**
@@ -308,10 +421,10 @@ export const isApiKeyInitialized = () => {
308
421
  */
309
422
  export const storeJWT = async token => {
310
423
  try {
311
- var _globalConfig7;
424
+ var _globalConfig0;
312
425
  await AsyncStorage.setItem(JWT_TOKEN_KEY, token);
313
426
  userToken = token;
314
- if ((_globalConfig7 = globalConfig) !== null && _globalConfig7 !== void 0 && _globalConfig7.enableLogging) {
427
+ if ((_globalConfig0 = globalConfig) !== null && _globalConfig0 !== void 0 && _globalConfig0.enableLogging) {
315
428
  console.log('🎫 JWT token stored successfully');
316
429
  }
317
430
  } catch (error) {
@@ -348,10 +461,10 @@ export const getJWT = () => {
348
461
  */
349
462
  export const clearJWT = async () => {
350
463
  try {
351
- var _globalConfig8;
464
+ var _globalConfig1;
352
465
  await AsyncStorage.removeItem(JWT_TOKEN_KEY);
353
466
  userToken = null;
354
- if ((_globalConfig8 = globalConfig) !== null && _globalConfig8 !== void 0 && _globalConfig8.enableLogging) {
467
+ if ((_globalConfig1 = globalConfig) !== null && _globalConfig1 !== void 0 && _globalConfig1.enableLogging) {
355
468
  console.log('🗑️ JWT token cleared');
356
469
  }
357
470
  } catch (error) {
@@ -420,7 +533,7 @@ export const decodeJWTPayload = token => {
420
533
  */
421
534
  export const extractUsernameFromJWT = token => {
422
535
  try {
423
- var _globalConfig9;
536
+ var _globalConfig10;
424
537
  const jwtToken = token || userToken;
425
538
  if (!jwtToken) {
426
539
  console.warn('⚠️ No JWT token available for username extraction');
@@ -433,7 +546,7 @@ export const extractUsernameFromJWT = token => {
433
546
 
434
547
  // Try different possible username fields in order of preference
435
548
  const username = payload.userName || payload.username || payload.userId || payload.email;
436
- if ((_globalConfig9 = globalConfig) !== null && _globalConfig9 !== void 0 && _globalConfig9.enableLogging) {
549
+ if ((_globalConfig10 = globalConfig) !== null && _globalConfig10 !== void 0 && _globalConfig10.enableLogging) {
437
550
  console.log('👤 Extracted username from JWT:', username);
438
551
  }
439
552
  return username || null;
@@ -450,7 +563,7 @@ export const extractUsernameFromJWT = token => {
450
563
  */
451
564
  export const extractUserDataFromJWT = token => {
452
565
  try {
453
- var _globalConfig0;
566
+ var _globalConfig11;
454
567
  const jwtToken = token || userToken;
455
568
  if (!jwtToken) {
456
569
  console.warn('⚠️ No JWT token available for user data extraction');
@@ -469,7 +582,7 @@ export const extractUserDataFromJWT = token => {
469
582
  iat: payload.iat,
470
583
  exp: payload.exp
471
584
  };
472
- if ((_globalConfig0 = globalConfig) !== null && _globalConfig0 !== void 0 && _globalConfig0.enableLogging) {
585
+ if ((_globalConfig11 = globalConfig) !== null && _globalConfig11 !== void 0 && _globalConfig11.enableLogging) {
473
586
  console.log('👤 Extracted user data from JWT:', userData);
474
587
  }
475
588
  return userData;
@@ -492,16 +605,16 @@ export const isUserAuthenticated = () => {
492
605
  * @returns Headers object with Authorization and other required headers
493
606
  */
494
607
  export const getAuthHeaders = () => {
495
- var _globalConfig1;
496
- if (!((_globalConfig1 = globalConfig) !== null && _globalConfig1 !== void 0 && _globalConfig1.apiKey)) {
608
+ var _globalConfig12;
609
+ if (!((_globalConfig12 = globalConfig) !== null && _globalConfig12 !== void 0 && _globalConfig12.apiKey)) {
497
610
  throw new Error('SDK not initialized. Call initializeApiKey() first.');
498
611
  }
499
612
  const keyType = getApiKeyType(globalConfig.apiKey);
500
613
  return {
501
614
  'Content-Type': 'application/json',
502
615
  'Authorization': `Bearer ${globalConfig.apiKey}`,
503
- 'User-Agent': 'OnairosReactNative/3.0.72',
504
- 'X-SDK-Version': '3.0.72',
616
+ 'User-Agent': 'OnairosReactNative/3.1.11',
617
+ 'X-SDK-Version': '3.1.11',
505
618
  'X-SDK-Environment': globalConfig.environment || 'production',
506
619
  'X-API-Key-Type': keyType,
507
620
  'X-Timestamp': new Date().toISOString()
@@ -513,8 +626,8 @@ export const getAuthHeaders = () => {
513
626
  * @returns Headers with developer API key
514
627
  */
515
628
  export const getDeveloperAuthHeaders = () => {
516
- var _globalConfig10;
517
- if (!((_globalConfig10 = globalConfig) !== null && _globalConfig10 !== void 0 && _globalConfig10.apiKey)) {
629
+ var _globalConfig13;
630
+ if (!((_globalConfig13 = globalConfig) !== null && _globalConfig13 !== void 0 && _globalConfig13.apiKey)) {
518
631
  throw new Error('SDK not initialized. Call initializeApiKey() first.');
519
632
  }
520
633
  const keyType = getApiKeyType(globalConfig.apiKey);
@@ -522,7 +635,7 @@ export const getDeveloperAuthHeaders = () => {
522
635
  'Content-Type': 'application/json',
523
636
  'Authorization': `Bearer ${globalConfig.apiKey}`,
524
637
  'User-Agent': 'OnairosSDK/1.0.0',
525
- 'X-SDK-Version': '3.0.72',
638
+ 'X-SDK-Version': '3.1.11',
526
639
  'X-SDK-Environment': globalConfig.environment || 'production',
527
640
  'X-API-Key-Type': keyType,
528
641
  'X-Timestamp': new Date().toISOString()
@@ -534,7 +647,7 @@ export const getDeveloperAuthHeaders = () => {
534
647
  * @returns Headers with user JWT token
535
648
  */
536
649
  export const getUserAuthHeaders = () => {
537
- var _globalConfig11;
650
+ var _globalConfig14;
538
651
  if (!userToken) {
539
652
  throw new Error('User not authenticated. Please verify email first.');
540
653
  }
@@ -542,8 +655,8 @@ export const getUserAuthHeaders = () => {
542
655
  'Content-Type': 'application/json',
543
656
  'Authorization': `Bearer ${userToken}`,
544
657
  'User-Agent': 'OnairosSDK/1.0.0',
545
- 'X-SDK-Version': '3.0.72',
546
- 'X-SDK-Environment': ((_globalConfig11 = globalConfig) === null || _globalConfig11 === void 0 ? void 0 : _globalConfig11.environment) || 'production'
658
+ 'X-SDK-Version': '3.1.11',
659
+ 'X-SDK-Environment': ((_globalConfig14 = globalConfig) === null || _globalConfig14 === void 0 ? void 0 : _globalConfig14.environment) || 'production'
547
660
  };
548
661
  };
549
662
 
@@ -738,9 +851,9 @@ export const makeUserRequest = async (endpoint, options = {}) => {
738
851
  * Clear the API key validation cache
739
852
  */
740
853
  export const clearValidationCache = () => {
741
- var _globalConfig12;
854
+ var _globalConfig15;
742
855
  validationCache.clear();
743
- if ((_globalConfig12 = globalConfig) !== null && _globalConfig12 !== void 0 && _globalConfig12.enableLogging) {
856
+ if ((_globalConfig15 = globalConfig) !== null && _globalConfig15 !== void 0 && _globalConfig15.enableLogging) {
744
857
  console.log('🗑️ API key validation cache cleared');
745
858
  }
746
859
  };