@onairos/react-native 3.0.71 → 3.0.73

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 (65) 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 +25 -440
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/services/apiKeyService.js +404 -0
  12. package/lib/commonjs/services/apiKeyService.js.map +1 -0
  13. package/lib/commonjs/services/platformAuthService.js +318 -113
  14. package/lib/commonjs/services/platformAuthService.js.map +1 -1
  15. package/lib/commonjs/types/index.js +4 -0
  16. package/lib/commonjs/types.js +12 -0
  17. package/lib/commonjs/types.js.map +1 -1
  18. package/lib/commonjs/utils/programmaticFlow.js +117 -0
  19. package/lib/commonjs/utils/programmaticFlow.js.map +1 -0
  20. package/lib/module/components/Onairos.js +297 -158
  21. package/lib/module/components/Onairos.js.map +1 -1
  22. package/lib/module/components/OnairosButton.js +1 -1
  23. package/lib/module/components/OnairosButton.js.map +1 -1
  24. package/lib/module/components/UniversalOnboarding.js +6 -6
  25. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  26. package/lib/module/components/onboarding/OAuthWebView.js +188 -52
  27. package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
  28. package/lib/module/index.js +17 -61
  29. package/lib/module/index.js.map +1 -1
  30. package/lib/module/services/apiKeyService.js +389 -0
  31. package/lib/module/services/apiKeyService.js.map +1 -0
  32. package/lib/module/services/platformAuthService.js +311 -111
  33. package/lib/module/services/platformAuthService.js.map +1 -1
  34. package/lib/module/types/index.js +1 -1
  35. package/lib/module/types.js +8 -0
  36. package/lib/module/types.js.map +1 -1
  37. package/lib/module/utils/programmaticFlow.js +111 -0
  38. package/lib/module/utils/programmaticFlow.js.map +1 -0
  39. package/lib/typescript/components/Onairos.d.ts +2 -29
  40. package/lib/typescript/components/Onairos.d.ts.map +1 -1
  41. package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
  42. package/lib/typescript/index.d.ts +10 -39
  43. package/lib/typescript/index.d.ts.map +1 -1
  44. package/lib/typescript/services/apiKeyService.d.ts +66 -0
  45. package/lib/typescript/services/apiKeyService.d.ts.map +1 -0
  46. package/lib/typescript/services/platformAuthService.d.ts +26 -0
  47. package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
  48. package/lib/typescript/types/index.d.ts +144 -78
  49. package/lib/typescript/types/index.d.ts.map +1 -1
  50. package/lib/typescript/types.d.ts +92 -3
  51. package/lib/typescript/types.d.ts.map +1 -1
  52. package/lib/typescript/utils/programmaticFlow.d.ts +23 -0
  53. package/lib/typescript/utils/programmaticFlow.d.ts.map +1 -0
  54. package/package.json +1 -1
  55. package/src/components/Onairos.tsx +330 -207
  56. package/src/components/OnairosButton.tsx +1 -1
  57. package/src/components/UniversalOnboarding.tsx +6 -6
  58. package/src/components/onboarding/OAuthWebView.tsx +236 -71
  59. package/src/index.ts +25 -115
  60. package/src/services/apiKeyService.ts +401 -0
  61. package/src/services/platformAuthService.ts +363 -126
  62. package/src/types/index.d.ts +110 -0
  63. package/src/types/index.ts +148 -74
  64. package/src/types.ts +99 -3
  65. package/src/utils/programmaticFlow.ts +113 -0
@@ -0,0 +1,401 @@
1
+ import type { OnairosConfig, ApiKeyValidationResult } from '../types';
2
+
3
+ // Admin key for backend validation
4
+ export const ADMIN_API_KEY = 'OnairosIsAUnicorn2025';
5
+
6
+ // API key types
7
+ export enum ApiKeyType {
8
+ DEVELOPER = 'developer',
9
+ ADMIN = 'admin',
10
+ INVALID = 'invalid'
11
+ }
12
+
13
+ /**
14
+ * API Key Service for Onairos React Native SDK
15
+ *
16
+ * This service handles API key validation, management, and authentication
17
+ * following standard SDK patterns for secure API key handling.
18
+ *
19
+ * How it works:
20
+ * 1. Initialize with API key and configuration
21
+ * 2. Validate API key with the Onairos backend
22
+ * 3. Cache validation results for performance
23
+ * 4. Include API key in all authenticated requests
24
+ * 5. Handle API key errors gracefully with developer-friendly messages
25
+ *
26
+ * Backend Integration:
27
+ * - All API requests include: Authorization: Bearer {apiKey}
28
+ * - Backend should validate API keys on each request
29
+ * - Admin key "OnairosIsAUnicorn2025" has full permissions
30
+ * - Developer keys have limited permissions based on validation response
31
+ */
32
+
33
+ // Global configuration state
34
+ let globalConfig: OnairosConfig | null = null;
35
+ let validationCache: Map<string, { result: ApiKeyValidationResult; timestamp: number }> = new Map();
36
+ let isInitialized = false;
37
+
38
+ // Cache duration (5 minutes)
39
+ const CACHE_DURATION = 5 * 60 * 1000;
40
+
41
+ // API endpoints for different environments
42
+ const API_ENDPOINTS = {
43
+ production: 'https://api2.onairos.uk',
44
+ staging: 'https://staging-api.onairos.uk',
45
+ development: 'https://dev-api.onairos.uk',
46
+ };
47
+
48
+ /**
49
+ * Initialize the SDK with API key and configuration
50
+ * @param config API configuration including API key
51
+ */
52
+ export const initializeApiKey = async (config: OnairosConfig): Promise<void> => {
53
+ try {
54
+ console.log('🔑 Initializing Onairos SDK with API key...');
55
+
56
+ if (!config.apiKey) {
57
+ throw new Error('API key is required for SDK initialization');
58
+ }
59
+
60
+ if (config.apiKey.length < 32) {
61
+ throw new Error('Invalid API key format. API key must be at least 32 characters long.');
62
+ }
63
+
64
+ // Set global configuration
65
+ globalConfig = {
66
+ apiKey: config.apiKey,
67
+ environment: config.environment || 'production',
68
+ enableLogging: config.enableLogging !== false, // Default to true
69
+ timeout: config.timeout || 30000,
70
+ retryAttempts: config.retryAttempts || 3,
71
+ };
72
+
73
+ if (globalConfig.enableLogging) {
74
+ console.log('📝 SDK Configuration:', {
75
+ environment: globalConfig.environment,
76
+ timeout: globalConfig.timeout,
77
+ retryAttempts: globalConfig.retryAttempts,
78
+ apiKeyPrefix: config.apiKey.substring(0, 8) + '...',
79
+ enableLogging: globalConfig.enableLogging,
80
+ });
81
+ }
82
+
83
+ // Validate the API key
84
+ const validation = await validateApiKey(config.apiKey);
85
+
86
+ if (!validation.isValid) {
87
+ throw new Error(`API key validation failed: ${validation.error}`);
88
+ }
89
+
90
+ isInitialized = true;
91
+
92
+ if (globalConfig.enableLogging) {
93
+ console.log('✅ Onairos SDK initialized successfully');
94
+ if (validation.permissions) {
95
+ console.log('🔐 API Key Permissions:', validation.permissions);
96
+ }
97
+ if (validation.rateLimits) {
98
+ console.log('⏱️ Rate Limits:', validation.rateLimits);
99
+ }
100
+ }
101
+ } catch (error) {
102
+ console.error('❌ Failed to initialize Onairos SDK:', error);
103
+ isInitialized = false;
104
+ throw error;
105
+ }
106
+ };
107
+
108
+ /**
109
+ * Determine API key type
110
+ * @param apiKey The API key to check
111
+ * @returns The type of API key
112
+ */
113
+ export const getApiKeyType = (apiKey: string): ApiKeyType => {
114
+ if (apiKey === ADMIN_API_KEY) {
115
+ return ApiKeyType.ADMIN;
116
+ }
117
+
118
+ // Developer keys should be at least 32 characters and start with specific prefix
119
+ if (apiKey.length >= 32 && (apiKey.startsWith('dev_') || apiKey.startsWith('pk_'))) {
120
+ return ApiKeyType.DEVELOPER;
121
+ }
122
+
123
+ return ApiKeyType.INVALID;
124
+ };
125
+
126
+ /**
127
+ * Check if API key is admin key
128
+ * @param apiKey The API key to check
129
+ * @returns True if admin key
130
+ */
131
+ export const isAdminKey = (apiKey: string): boolean => {
132
+ return apiKey === ADMIN_API_KEY;
133
+ };
134
+
135
+ /**
136
+ * Validate an API key with the Onairos backend
137
+ * @param apiKey The API key to validate
138
+ * @returns Validation result with permissions and rate limits
139
+ */
140
+ export const validateApiKey = async (apiKey: string): Promise<ApiKeyValidationResult> => {
141
+ try {
142
+ console.log('🔍 Validating API key...');
143
+
144
+ // Check if it's an admin key
145
+ if (isAdminKey(apiKey)) {
146
+ console.log('🔑 Admin key detected - granting full permissions');
147
+ return {
148
+ isValid: true,
149
+ permissions: ['*'], // Full permissions for admin
150
+ rateLimits: {
151
+ remaining: 999999,
152
+ resetTime: Date.now() + 24 * 60 * 60 * 1000 // 24 hours
153
+ },
154
+ keyType: ApiKeyType.ADMIN
155
+ };
156
+ }
157
+
158
+ // Check basic format for developer keys
159
+ const keyType = getApiKeyType(apiKey);
160
+ if (keyType === ApiKeyType.INVALID) {
161
+ return {
162
+ isValid: false,
163
+ error: 'Invalid API key format. Developer keys must be at least 32 characters and start with "dev_" or "pk_"',
164
+ keyType: ApiKeyType.INVALID
165
+ };
166
+ }
167
+
168
+ // Check cache first
169
+ const cached = validationCache.get(apiKey);
170
+ if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
171
+ if (globalConfig?.enableLogging) {
172
+ console.log('📋 Using cached API key validation result');
173
+ }
174
+ return cached.result;
175
+ }
176
+
177
+ const environment = globalConfig?.environment || 'production';
178
+ const baseUrl = API_ENDPOINTS[environment];
179
+ const timeout = globalConfig?.timeout || 30000;
180
+
181
+ // Create abort controller for timeout
182
+ const controller = new AbortController();
183
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
184
+
185
+ try {
186
+ const response = await fetch(`${baseUrl}/auth/validate-key`, {
187
+ method: 'POST',
188
+ headers: {
189
+ 'Content-Type': 'application/json',
190
+ 'Authorization': `Bearer ${apiKey}`,
191
+ 'User-Agent': 'OnairosReactNative/1.0',
192
+ 'X-API-Key-Type': keyType,
193
+ },
194
+ body: JSON.stringify({
195
+ environment,
196
+ sdk_version: '3.0.72',
197
+ platform: 'react-native',
198
+ keyType,
199
+ timestamp: new Date().toISOString(),
200
+ }),
201
+ signal: controller.signal,
202
+ });
203
+
204
+ clearTimeout(timeoutId);
205
+
206
+ const data = await response.json();
207
+
208
+ if (response.ok && data.success) {
209
+ const result: ApiKeyValidationResult = {
210
+ isValid: true,
211
+ permissions: data.permissions || [],
212
+ rateLimits: data.rateLimits || null,
213
+ keyType: keyType,
214
+ };
215
+
216
+ // Cache the successful result
217
+ validationCache.set(apiKey, {
218
+ result,
219
+ timestamp: Date.now(),
220
+ });
221
+
222
+ if (globalConfig?.enableLogging) {
223
+ console.log('✅ API key validation successful');
224
+ }
225
+
226
+ return result;
227
+ } else {
228
+ const errorMessage = data.error || `HTTP ${response.status}: ${response.statusText}`;
229
+
230
+ const result: ApiKeyValidationResult = {
231
+ isValid: false,
232
+ error: errorMessage,
233
+ keyType: keyType,
234
+ };
235
+
236
+ // Don't cache failed results
237
+ if (globalConfig?.enableLogging) {
238
+ console.error('❌ API key validation failed:', errorMessage);
239
+ }
240
+
241
+ return result;
242
+ }
243
+ } catch (fetchError: any) {
244
+ clearTimeout(timeoutId);
245
+
246
+ if (fetchError.name === 'AbortError') {
247
+ const errorMessage = 'API key validation timeout';
248
+ console.error('⏱️ API key validation timeout');
249
+ return { isValid: false, error: errorMessage, keyType: keyType };
250
+ }
251
+
252
+ const errorMessage = `Network error during API key validation: ${fetchError.message}`;
253
+ console.error('🌐 Network error during API key validation:', fetchError);
254
+ return { isValid: false, error: errorMessage, keyType: keyType };
255
+ }
256
+ } catch (error: any) {
257
+ const errorMessage = `API key validation error: ${error.message}`;
258
+ console.error('❌ API key validation error:', error);
259
+ return { isValid: false, error: errorMessage, keyType: ApiKeyType.INVALID };
260
+ }
261
+ };
262
+
263
+ /**
264
+ * Get the current API configuration
265
+ * @returns Current API configuration or null if not initialized
266
+ */
267
+ export const getApiConfig = (): OnairosConfig | null => {
268
+ return globalConfig;
269
+ };
270
+
271
+ /**
272
+ * Get the current API key
273
+ * @returns Current API key or null if not initialized
274
+ */
275
+ export const getApiKey = (): string | null => {
276
+ return globalConfig?.apiKey || null;
277
+ };
278
+
279
+ /**
280
+ * Check if the SDK is properly initialized
281
+ * @returns True if initialized with valid API key
282
+ */
283
+ export const isApiKeyInitialized = (): boolean => {
284
+ return isInitialized && globalConfig !== null;
285
+ };
286
+
287
+ /**
288
+ * Get authenticated headers for API requests
289
+ * @returns Headers object with Authorization and other required headers
290
+ */
291
+ export const getAuthHeaders = (): Record<string, string> => {
292
+ if (!globalConfig?.apiKey) {
293
+ throw new Error('SDK not initialized. Call initializeApiKey() first.');
294
+ }
295
+
296
+ const keyType = getApiKeyType(globalConfig.apiKey);
297
+
298
+ return {
299
+ 'Content-Type': 'application/json',
300
+ 'Authorization': `Bearer ${globalConfig.apiKey}`,
301
+ 'User-Agent': 'OnairosReactNative/3.0.72',
302
+ 'X-SDK-Version': '3.0.72',
303
+ 'X-SDK-Environment': globalConfig.environment || 'production',
304
+ 'X-API-Key-Type': keyType,
305
+ 'X-Timestamp': new Date().toISOString(),
306
+ };
307
+ };
308
+
309
+ /**
310
+ * Make an authenticated API request
311
+ * @param endpoint The API endpoint (relative to base URL)
312
+ * @param options Fetch options
313
+ * @returns Response promise
314
+ */
315
+ export const makeAuthenticatedRequest = async (
316
+ endpoint: string,
317
+ options: RequestInit = {}
318
+ ): Promise<Response> => {
319
+ if (!isApiKeyInitialized()) {
320
+ throw new Error('SDK not initialized. Call initializeApiKey() first.');
321
+ }
322
+
323
+ const config = getApiConfig()!;
324
+ const baseUrl = API_ENDPOINTS[config.environment || 'production'];
325
+ const url = `${baseUrl}${endpoint.startsWith('/') ? '' : '/'}${endpoint}`;
326
+
327
+ // Merge authentication headers
328
+ const headers = {
329
+ ...getAuthHeaders(),
330
+ ...(options.headers || {}),
331
+ };
332
+
333
+ // Add timeout
334
+ const controller = new AbortController();
335
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout || 30000);
336
+
337
+ try {
338
+ if (config.enableLogging) {
339
+ console.log(`🌐 Making authenticated request to: ${endpoint}`);
340
+ }
341
+
342
+ const response = await fetch(url, {
343
+ ...options,
344
+ headers,
345
+ signal: controller.signal,
346
+ });
347
+
348
+ clearTimeout(timeoutId);
349
+
350
+ if (config.enableLogging) {
351
+ console.log(`📡 Response status: ${response.status} for ${endpoint}`);
352
+ }
353
+
354
+ // Handle API key errors
355
+ if (response.status === 401) {
356
+ console.error('❌ API key authentication failed. Please check your API key.');
357
+ throw new Error('Invalid or expired API key');
358
+ }
359
+
360
+ if (response.status === 403) {
361
+ console.error('❌ API key permissions insufficient for this operation.');
362
+ throw new Error('Insufficient API key permissions');
363
+ }
364
+
365
+ if (response.status === 429) {
366
+ console.error('❌ API rate limit exceeded. Please try again later.');
367
+ throw new Error('Rate limit exceeded');
368
+ }
369
+
370
+ return response;
371
+ } catch (error) {
372
+ clearTimeout(timeoutId);
373
+
374
+ if (error.name === 'AbortError') {
375
+ console.error('⏱️ Request timeout for:', endpoint);
376
+ throw new Error('Request timeout');
377
+ }
378
+
379
+ throw error;
380
+ }
381
+ };
382
+
383
+ /**
384
+ * Clear the API key validation cache
385
+ */
386
+ export const clearValidationCache = (): void => {
387
+ validationCache.clear();
388
+ if (globalConfig?.enableLogging) {
389
+ console.log('🗑️ API key validation cache cleared');
390
+ }
391
+ };
392
+
393
+ /**
394
+ * Reset the SDK initialization state
395
+ */
396
+ export const resetApiKeyService = (): void => {
397
+ globalConfig = null;
398
+ isInitialized = false;
399
+ clearValidationCache();
400
+ console.log('🔄 API key service reset');
401
+ };