@onairos/react-native 3.1.9 → 3.1.11

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,14 @@ 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
+ var _validation$error, _validation$error2, _validation$error3;
91
+ // If it's a network error or JSON parse error, warn but don't fail initialization
92
+ if ((_validation$error = validation.error) !== null && _validation$error !== void 0 && _validation$error.includes('Network error') || (_validation$error2 = validation.error) !== null && _validation$error2 !== void 0 && _validation$error2.includes('JSON Parse error') || (_validation$error3 = validation.error) !== null && _validation$error3 !== void 0 && _validation$error3.includes('API validation endpoint returned')) {
93
+ console.warn('⚠️ API key validation failed due to network/server issues, continuing in offline mode:', validation.error);
94
+ console.warn('📝 SDK will function with limited validation. Ensure your API key is valid for production use.');
95
+ } else {
96
+ throw new Error(`API key validation failed: ${validation.error}`);
97
+ }
91
98
  }
92
99
 
93
100
  // Try to load existing JWT token
@@ -150,7 +157,7 @@ export const isAdminKey = apiKey => {
150
157
  */
151
158
  export const validateApiKey = async apiKey => {
152
159
  try {
153
- var _globalConfig2, _globalConfig3;
160
+ var _globalConfig2, _globalConfig3, _globalConfig4;
154
161
  console.log('🔍 Validating API key...');
155
162
 
156
163
  // Check if it's an admin key
@@ -190,82 +197,187 @@ export const validateApiKey = async apiKey => {
190
197
  const environment = ((_globalConfig2 = globalConfig) === null || _globalConfig2 === void 0 ? void 0 : _globalConfig2.environment) || 'production';
191
198
  const baseUrl = API_ENDPOINTS[environment];
192
199
  const timeout = ((_globalConfig3 = globalConfig) === null || _globalConfig3 === void 0 ? void 0 : _globalConfig3.timeout) || 30000;
200
+ const maxRetries = ((_globalConfig4 = globalConfig) === null || _globalConfig4 === void 0 ? void 0 : _globalConfig4.retryAttempts) || 3;
201
+
202
+ // Retry logic for network failures
203
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
204
+ // Create abort controller for timeout
205
+ const controller = new AbortController();
206
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
207
+ try {
208
+ var _globalConfig5;
209
+ if ((_globalConfig5 = globalConfig) !== null && _globalConfig5 !== void 0 && _globalConfig5.enableLogging && attempt > 1) {
210
+ console.log(`🔄 Retry attempt ${attempt}/${maxRetries} for API key validation`);
211
+ }
212
+ const response = await fetch(`${baseUrl}/auth/validate-key`, {
213
+ method: 'POST',
214
+ headers: {
215
+ 'Content-Type': 'application/json',
216
+ 'Authorization': `Bearer ${apiKey}`,
217
+ 'User-Agent': 'OnairosReactNative/3.1.10',
218
+ 'X-API-Key-Type': keyType,
219
+ 'X-SDK-Platform': 'react-native',
220
+ 'X-Retry-Attempt': attempt.toString()
221
+ },
222
+ body: JSON.stringify({
223
+ environment,
224
+ sdk_version: '3.1.10',
225
+ platform: 'react-native',
226
+ keyType,
227
+ timestamp: new Date().toISOString(),
228
+ attempt
229
+ }),
230
+ signal: controller.signal
231
+ });
232
+ clearTimeout(timeoutId);
193
233
 
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()
234
+ // First check if we got a valid response
235
+ if (!response) {
236
+ throw new Error('No response received from server');
237
+ }
238
+
239
+ // Check if response is actually JSON before trying to parse
240
+ const contentType = response.headers.get('content-type');
241
+ const isJsonResponse = contentType && contentType.includes('application/json');
242
+ if (!isJsonResponse) {
243
+ const textContent = await response.text();
244
+ const previewText = textContent.substring(0, 200);
245
+ console.error('❌ API endpoint returned non-JSON response:', {
246
+ status: response.status,
247
+ statusText: response.statusText,
248
+ contentType: contentType || 'unknown',
249
+ preview: previewText,
250
+ url: `${baseUrl}/auth/validate-key`,
251
+ attempt: attempt
252
+ });
253
+
254
+ // Handle specific error cases
255
+ if (response.status === 404) {
256
+ throw new Error(`API validation endpoint not found (404). The endpoint ${baseUrl}/auth/validate-key may not exist or be configured correctly.`);
257
+ } else if (response.status === 500) {
258
+ throw new Error(`Server error (500). The Onairos backend is experiencing issues.`);
259
+ } else if (response.status === 502 || response.status === 503) {
260
+ throw new Error(`Service unavailable (${response.status}). The Onairos backend may be temporarily down.`);
261
+ } else if (textContent.includes('<html') || textContent.includes('<!DOCTYPE')) {
262
+ throw new Error(`Server returned HTML page instead of JSON API response. This often indicates a routing issue or server misconfiguration.`);
263
+ } else {
264
+ throw new Error(`API validation endpoint returned ${response.status} - ${response.statusText}. Expected JSON but got ${contentType || 'unknown content type'}.`);
265
+ }
266
+ }
267
+
268
+ // Parse JSON response
269
+ let data;
270
+ try {
271
+ data = await response.json();
272
+ } catch (jsonError) {
273
+ console.error('❌ Failed to parse JSON response:', {
274
+ error: jsonError.message,
275
+ status: response.status,
276
+ contentType,
277
+ attempt: attempt
278
+ });
279
+ throw new Error(`Failed to parse server response as JSON: ${jsonError.message}`);
280
+ }
281
+
282
+ // Handle successful response
283
+ if (response.ok && data.success) {
284
+ var _globalConfig6;
285
+ const result = {
286
+ isValid: true,
287
+ permissions: data.permissions || [],
288
+ rateLimits: data.rateLimits || null,
289
+ keyType: keyType
290
+ };
291
+
292
+ // Cache the successful result
293
+ validationCache.set(apiKey, {
294
+ result,
295
+ timestamp: Date.now()
296
+ });
297
+ if ((_globalConfig6 = globalConfig) !== null && _globalConfig6 !== void 0 && _globalConfig6.enableLogging) {
298
+ console.log('✅ API key validation successful');
299
+ }
300
+ return result;
301
+ } else {
302
+ // Handle API errors (invalid key, etc.)
303
+ const errorMessage = data.error || data.message || `HTTP ${response.status}: ${response.statusText}`;
304
+ const result = {
305
+ isValid: false,
306
+ error: errorMessage,
307
+ keyType: keyType
308
+ };
309
+
310
+ // For client errors (4xx), don't retry
311
+ if (response.status >= 400 && response.status < 500) {
312
+ var _globalConfig7;
313
+ if ((_globalConfig7 = globalConfig) !== null && _globalConfig7 !== void 0 && _globalConfig7.enableLogging) {
314
+ console.error('❌ API key validation failed (client error):', errorMessage);
315
+ }
316
+ return result;
317
+ }
318
+
319
+ // For server errors (5xx), retry
320
+ throw new Error(errorMessage);
321
+ }
322
+ } catch (fetchError) {
323
+ var _globalConfig8;
324
+ clearTimeout(timeoutId);
325
+ if (fetchError.name === 'AbortError') {
326
+ const errorMessage = `API key validation timeout (${timeout}ms)`;
327
+ console.error('⏱️ API key validation timeout');
328
+ if (attempt === maxRetries) {
329
+ return {
330
+ isValid: false,
331
+ error: errorMessage,
332
+ keyType: keyType
333
+ };
334
+ }
335
+ continue; // Retry timeout errors
336
+ }
337
+
338
+ // Enhanced error message based on error type
339
+ let errorMessage = `Network error during API key validation: ${fetchError.message}`;
340
+
341
+ // Add specific guidance for common errors
342
+ if (fetchError.message.includes('JSON Parse error') || fetchError.message.includes('Unexpected character')) {
343
+ 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}`;
344
+ } else if (fetchError.message.includes('Network request failed') || fetchError.message.includes('fetch')) {
345
+ errorMessage = `Network connectivity issue. Please check internet connection and verify the Onairos API is accessible. ${fetchError.message}`;
346
+ } else if (fetchError.message.includes('DNS') || fetchError.message.includes('ENOTFOUND')) {
347
+ errorMessage = `DNS resolution failed for ${baseUrl}. Please check network settings and domain accessibility. ${fetchError.message}`;
348
+ }
349
+ console.error('🌐 Network error during API key validation:', {
350
+ error: fetchError,
351
+ endpoint: `${baseUrl}/auth/validate-key`,
352
+ attempt: attempt,
353
+ maxRetries: maxRetries,
354
+ retryable: attempt < maxRetries
230
355
  });
231
- if ((_globalConfig4 = globalConfig) !== null && _globalConfig4 !== void 0 && _globalConfig4.enableLogging) {
232
- console.log('✅ API key validation successful');
356
+
357
+ // If this is the last attempt, return the error
358
+ if (attempt === maxRetries) {
359
+ return {
360
+ isValid: false,
361
+ error: errorMessage,
362
+ keyType: keyType
363
+ };
233
364
  }
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);
365
+
366
+ // Wait before retrying (exponential backoff)
367
+ const backoffDelay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
368
+ if ((_globalConfig8 = globalConfig) !== null && _globalConfig8 !== void 0 && _globalConfig8.enableLogging) {
369
+ console.log(`⏳ Waiting ${backoffDelay}ms before retry...`);
247
370
  }
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
- };
371
+ await new Promise(resolve => setTimeout(() => resolve(), backoffDelay));
260
372
  }
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
373
  }
374
+
375
+ // This should never be reached, but just in case
376
+ return {
377
+ isValid: false,
378
+ error: 'All retry attempts exhausted',
379
+ keyType: keyType
380
+ };
269
381
  } catch (error) {
270
382
  const errorMessage = `API key validation error: ${error.message}`;
271
383
  console.error('❌ API key validation error:', error);
@@ -290,8 +402,8 @@ export const getApiConfig = () => {
290
402
  * @returns Current API key or null if not initialized
291
403
  */
292
404
  export const getApiKey = () => {
293
- var _globalConfig6;
294
- return ((_globalConfig6 = globalConfig) === null || _globalConfig6 === void 0 ? void 0 : _globalConfig6.apiKey) || null;
405
+ var _globalConfig9;
406
+ return ((_globalConfig9 = globalConfig) === null || _globalConfig9 === void 0 ? void 0 : _globalConfig9.apiKey) || null;
295
407
  };
296
408
 
297
409
  /**
@@ -308,10 +420,10 @@ export const isApiKeyInitialized = () => {
308
420
  */
309
421
  export const storeJWT = async token => {
310
422
  try {
311
- var _globalConfig7;
423
+ var _globalConfig0;
312
424
  await AsyncStorage.setItem(JWT_TOKEN_KEY, token);
313
425
  userToken = token;
314
- if ((_globalConfig7 = globalConfig) !== null && _globalConfig7 !== void 0 && _globalConfig7.enableLogging) {
426
+ if ((_globalConfig0 = globalConfig) !== null && _globalConfig0 !== void 0 && _globalConfig0.enableLogging) {
315
427
  console.log('🎫 JWT token stored successfully');
316
428
  }
317
429
  } catch (error) {
@@ -348,10 +460,10 @@ export const getJWT = () => {
348
460
  */
349
461
  export const clearJWT = async () => {
350
462
  try {
351
- var _globalConfig8;
463
+ var _globalConfig1;
352
464
  await AsyncStorage.removeItem(JWT_TOKEN_KEY);
353
465
  userToken = null;
354
- if ((_globalConfig8 = globalConfig) !== null && _globalConfig8 !== void 0 && _globalConfig8.enableLogging) {
466
+ if ((_globalConfig1 = globalConfig) !== null && _globalConfig1 !== void 0 && _globalConfig1.enableLogging) {
355
467
  console.log('🗑️ JWT token cleared');
356
468
  }
357
469
  } catch (error) {
@@ -420,7 +532,7 @@ export const decodeJWTPayload = token => {
420
532
  */
421
533
  export const extractUsernameFromJWT = token => {
422
534
  try {
423
- var _globalConfig9;
535
+ var _globalConfig10;
424
536
  const jwtToken = token || userToken;
425
537
  if (!jwtToken) {
426
538
  console.warn('⚠️ No JWT token available for username extraction');
@@ -433,7 +545,7 @@ export const extractUsernameFromJWT = token => {
433
545
 
434
546
  // Try different possible username fields in order of preference
435
547
  const username = payload.userName || payload.username || payload.userId || payload.email;
436
- if ((_globalConfig9 = globalConfig) !== null && _globalConfig9 !== void 0 && _globalConfig9.enableLogging) {
548
+ if ((_globalConfig10 = globalConfig) !== null && _globalConfig10 !== void 0 && _globalConfig10.enableLogging) {
437
549
  console.log('👤 Extracted username from JWT:', username);
438
550
  }
439
551
  return username || null;
@@ -450,7 +562,7 @@ export const extractUsernameFromJWT = token => {
450
562
  */
451
563
  export const extractUserDataFromJWT = token => {
452
564
  try {
453
- var _globalConfig0;
565
+ var _globalConfig11;
454
566
  const jwtToken = token || userToken;
455
567
  if (!jwtToken) {
456
568
  console.warn('⚠️ No JWT token available for user data extraction');
@@ -469,7 +581,7 @@ export const extractUserDataFromJWT = token => {
469
581
  iat: payload.iat,
470
582
  exp: payload.exp
471
583
  };
472
- if ((_globalConfig0 = globalConfig) !== null && _globalConfig0 !== void 0 && _globalConfig0.enableLogging) {
584
+ if ((_globalConfig11 = globalConfig) !== null && _globalConfig11 !== void 0 && _globalConfig11.enableLogging) {
473
585
  console.log('👤 Extracted user data from JWT:', userData);
474
586
  }
475
587
  return userData;
@@ -492,8 +604,8 @@ export const isUserAuthenticated = () => {
492
604
  * @returns Headers object with Authorization and other required headers
493
605
  */
494
606
  export const getAuthHeaders = () => {
495
- var _globalConfig1;
496
- if (!((_globalConfig1 = globalConfig) !== null && _globalConfig1 !== void 0 && _globalConfig1.apiKey)) {
607
+ var _globalConfig12;
608
+ if (!((_globalConfig12 = globalConfig) !== null && _globalConfig12 !== void 0 && _globalConfig12.apiKey)) {
497
609
  throw new Error('SDK not initialized. Call initializeApiKey() first.');
498
610
  }
499
611
  const keyType = getApiKeyType(globalConfig.apiKey);
@@ -513,8 +625,8 @@ export const getAuthHeaders = () => {
513
625
  * @returns Headers with developer API key
514
626
  */
515
627
  export const getDeveloperAuthHeaders = () => {
516
- var _globalConfig10;
517
- if (!((_globalConfig10 = globalConfig) !== null && _globalConfig10 !== void 0 && _globalConfig10.apiKey)) {
628
+ var _globalConfig13;
629
+ if (!((_globalConfig13 = globalConfig) !== null && _globalConfig13 !== void 0 && _globalConfig13.apiKey)) {
518
630
  throw new Error('SDK not initialized. Call initializeApiKey() first.');
519
631
  }
520
632
  const keyType = getApiKeyType(globalConfig.apiKey);
@@ -534,7 +646,7 @@ export const getDeveloperAuthHeaders = () => {
534
646
  * @returns Headers with user JWT token
535
647
  */
536
648
  export const getUserAuthHeaders = () => {
537
- var _globalConfig11;
649
+ var _globalConfig14;
538
650
  if (!userToken) {
539
651
  throw new Error('User not authenticated. Please verify email first.');
540
652
  }
@@ -543,7 +655,7 @@ export const getUserAuthHeaders = () => {
543
655
  'Authorization': `Bearer ${userToken}`,
544
656
  'User-Agent': 'OnairosSDK/1.0.0',
545
657
  'X-SDK-Version': '3.0.72',
546
- 'X-SDK-Environment': ((_globalConfig11 = globalConfig) === null || _globalConfig11 === void 0 ? void 0 : _globalConfig11.environment) || 'production'
658
+ 'X-SDK-Environment': ((_globalConfig14 = globalConfig) === null || _globalConfig14 === void 0 ? void 0 : _globalConfig14.environment) || 'production'
547
659
  };
548
660
  };
549
661
 
@@ -738,9 +850,9 @@ export const makeUserRequest = async (endpoint, options = {}) => {
738
850
  * Clear the API key validation cache
739
851
  */
740
852
  export const clearValidationCache = () => {
741
- var _globalConfig12;
853
+ var _globalConfig15;
742
854
  validationCache.clear();
743
- if ((_globalConfig12 = globalConfig) !== null && _globalConfig12 !== void 0 && _globalConfig12.enableLogging) {
855
+ if ((_globalConfig15 = globalConfig) !== null && _globalConfig15 !== void 0 && _globalConfig15.enableLogging) {
744
856
  console.log('🗑️ API key validation cache cleared');
745
857
  }
746
858
  };