riuve-rn 1.0.0

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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +848 -0
  3. package/dist/Riuve.d.ts +91 -0
  4. package/dist/Riuve.d.ts.map +1 -0
  5. package/dist/Riuve.js +402 -0
  6. package/dist/Rive.d.ts +91 -0
  7. package/dist/Rive.d.ts.map +1 -0
  8. package/dist/Rive.js +402 -0
  9. package/dist/adapters/deviceInfo/ExpoDeviceInfo.d.ts +13 -0
  10. package/dist/adapters/deviceInfo/ExpoDeviceInfo.d.ts.map +1 -0
  11. package/dist/adapters/deviceInfo/ExpoDeviceInfo.js +91 -0
  12. package/dist/adapters/deviceInfo/FallbackDeviceInfo.d.ts +13 -0
  13. package/dist/adapters/deviceInfo/FallbackDeviceInfo.d.ts.map +1 -0
  14. package/dist/adapters/deviceInfo/FallbackDeviceInfo.js +36 -0
  15. package/dist/adapters/deviceInfo/NativeDeviceInfo.d.ts +17 -0
  16. package/dist/adapters/deviceInfo/NativeDeviceInfo.d.ts.map +1 -0
  17. package/dist/adapters/deviceInfo/NativeDeviceInfo.js +83 -0
  18. package/dist/adapters/deviceInfo/index.d.ts +14 -0
  19. package/dist/adapters/deviceInfo/index.d.ts.map +1 -0
  20. package/dist/adapters/deviceInfo/index.js +38 -0
  21. package/dist/adapters/deviceInfo/types.d.ts +25 -0
  22. package/dist/adapters/deviceInfo/types.d.ts.map +1 -0
  23. package/dist/adapters/deviceInfo/types.js +7 -0
  24. package/dist/adapters/network/ExpoNetworkManager.d.ts +20 -0
  25. package/dist/adapters/network/ExpoNetworkManager.d.ts.map +1 -0
  26. package/dist/adapters/network/ExpoNetworkManager.js +114 -0
  27. package/dist/adapters/network/FallbackNetworkManager.d.ts +15 -0
  28. package/dist/adapters/network/FallbackNetworkManager.d.ts.map +1 -0
  29. package/dist/adapters/network/FallbackNetworkManager.js +27 -0
  30. package/dist/adapters/network/NativeNetworkManager.d.ts +20 -0
  31. package/dist/adapters/network/NativeNetworkManager.d.ts.map +1 -0
  32. package/dist/adapters/network/NativeNetworkManager.js +68 -0
  33. package/dist/adapters/network/index.d.ts +14 -0
  34. package/dist/adapters/network/index.d.ts.map +1 -0
  35. package/dist/adapters/network/index.js +38 -0
  36. package/dist/adapters/network/types.d.ts +28 -0
  37. package/dist/adapters/network/types.d.ts.map +1 -0
  38. package/dist/adapters/network/types.js +7 -0
  39. package/dist/adapters/utils/moduleDetector.d.ts +17 -0
  40. package/dist/adapters/utils/moduleDetector.d.ts.map +1 -0
  41. package/dist/adapters/utils/moduleDetector.js +32 -0
  42. package/dist/constants.d.ts +41 -0
  43. package/dist/constants.d.ts.map +1 -0
  44. package/dist/constants.js +43 -0
  45. package/dist/core/ApiClient.d.ts +49 -0
  46. package/dist/core/ApiClient.d.ts.map +1 -0
  47. package/dist/core/ApiClient.js +184 -0
  48. package/dist/core/DeviceInfo.d.ts +27 -0
  49. package/dist/core/DeviceInfo.d.ts.map +1 -0
  50. package/dist/core/DeviceInfo.js +69 -0
  51. package/dist/core/EventQueue.d.ts +71 -0
  52. package/dist/core/EventQueue.d.ts.map +1 -0
  53. package/dist/core/EventQueue.js +216 -0
  54. package/dist/core/Storage.d.ts +29 -0
  55. package/dist/core/Storage.d.ts.map +1 -0
  56. package/dist/core/Storage.js +88 -0
  57. package/dist/index.d.ts +9 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +17 -0
  60. package/dist/managers/BatchManager.d.ts +50 -0
  61. package/dist/managers/BatchManager.d.ts.map +1 -0
  62. package/dist/managers/BatchManager.js +277 -0
  63. package/dist/managers/IdentityManager.d.ts +47 -0
  64. package/dist/managers/IdentityManager.d.ts.map +1 -0
  65. package/dist/managers/IdentityManager.js +135 -0
  66. package/dist/managers/NetworkManager.d.ts +32 -0
  67. package/dist/managers/NetworkManager.d.ts.map +1 -0
  68. package/dist/managers/NetworkManager.js +67 -0
  69. package/dist/types/api.d.ts +65 -0
  70. package/dist/types/api.d.ts.map +1 -0
  71. package/dist/types/api.js +15 -0
  72. package/dist/types/config.d.ts +32 -0
  73. package/dist/types/config.d.ts.map +1 -0
  74. package/dist/types/config.js +5 -0
  75. package/dist/types/events.d.ts +63 -0
  76. package/dist/types/events.d.ts.map +1 -0
  77. package/dist/types/events.js +5 -0
  78. package/dist/types/index.d.ts +8 -0
  79. package/dist/types/index.d.ts.map +1 -0
  80. package/dist/types/index.js +23 -0
  81. package/dist/types/storage.d.ts +26 -0
  82. package/dist/types/storage.d.ts.map +1 -0
  83. package/dist/types/storage.js +5 -0
  84. package/dist/utils/fetchWithTimeout.d.ts +6 -0
  85. package/dist/utils/fetchWithTimeout.d.ts.map +1 -0
  86. package/dist/utils/fetchWithTimeout.js +28 -0
  87. package/dist/utils/logger.d.ts +21 -0
  88. package/dist/utils/logger.d.ts.map +1 -0
  89. package/dist/utils/logger.js +39 -0
  90. package/dist/utils/retry.d.ts +29 -0
  91. package/dist/utils/retry.d.ts.map +1 -0
  92. package/dist/utils/retry.js +78 -0
  93. package/dist/utils/uuid.d.ts +12 -0
  94. package/dist/utils/uuid.d.ts.map +1 -0
  95. package/dist/utils/uuid.js +27 -0
  96. package/dist/utils/validators.d.ts +32 -0
  97. package/dist/utils/validators.d.ts.map +1 -0
  98. package/dist/utils/validators.js +68 -0
  99. package/package.json +65 -0
package/README.md ADDED
@@ -0,0 +1,848 @@
1
+ # Riuve SDK - React Native/Expo
2
+
3
+ > **Behavioral event tracking SDK for React Native and Expo applications**
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [What is Riuve SDK?](#what-is-riuve-sdk)
10
+ 2. [Installation](#installation)
11
+ 3. [Quick Start](#quick-start)
12
+ 4. [Advanced Features](#advanced-features)
13
+ 5. [Best Practices](#best-practices)
14
+ 6. [Troubleshooting](#troubleshooting)
15
+ 7. [API Reference](#api-reference)
16
+
17
+ ---
18
+
19
+ ## What is Riuve SDK?
20
+
21
+ **Riuve SDK** is a behavioral event tracking library for React Native and Expo applications.
22
+
23
+ ### Features
24
+
25
+ - ✅ **Offline Support**: Events are queued when offline and automatically sent when connection is restored
26
+ - ✅ **Intelligent Batching**: Events are automatically batched for optimal performance
27
+ - ✅ **Automatic Retry**: Failed requests are automatically retried with exponential backoff
28
+ - ✅ **Background Flush**: Events are automatically flushed when app goes to background
29
+ - ✅ **User Identification**: Manages both anonymous and external user IDs
30
+ - ✅ **Push Notification Support**: FCM token management
31
+ - ✅ **Zero Configuration**: Backend URL is hardcoded, only API key is required
32
+ - ✅ **Pending Events Queue**: Events tracked before SDK initialization are automatically processed
33
+
34
+ ### Use Cases
35
+
36
+ - Track user behavior and interactions in your app
37
+ - Monitor which screens are viewed most
38
+ - Track button clicks, form submissions, and user actions
39
+ - Segment users based on their behavior
40
+ - Send targeted push notifications
41
+
42
+ ---
43
+
44
+ ## Installation
45
+
46
+ ### 1. Install the Package
47
+
48
+ ```bash
49
+ npm install riuve-rn
50
+ ```
51
+
52
+ or
53
+
54
+ ```bash
55
+ yarn add riuve-rn
56
+ ```
57
+
58
+ ### 2. Install Required Dependencies
59
+
60
+ **AsyncStorage** is required for the SDK to function:
61
+
62
+ ```bash
63
+ npm install @react-native-async-storage/async-storage
64
+ ```
65
+
66
+ ### 3. (Optional) Expo Modules
67
+
68
+ If you're using Expo, install these for device info and network monitoring:
69
+
70
+ ```bash
71
+ npx expo install expo-device expo-application expo-localization expo-network
72
+ ```
73
+
74
+ ### 4. (Optional) Native Modules
75
+
76
+ For better performance with native modules (Development Build or Bare React Native):
77
+
78
+ ```bash
79
+ npm install react-native-device-info @react-native-community/netinfo
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Quick Start
85
+
86
+ ### Step 1: Initialize the SDK
87
+
88
+ Initialize the SDK at the start of your app (typically in `App.tsx` or `_layout.tsx`):
89
+
90
+ ```typescript
91
+ import { useEffect } from 'react';
92
+ import Riuve from 'riuve-rn';
93
+
94
+ export default function App() {
95
+ useEffect(() => {
96
+ initializeSDK();
97
+ }, []);
98
+
99
+ const initializeSDK = async () => {
100
+ try {
101
+ // Get your API key from Nock dashboard
102
+ await Riuve.initialize('riuve_base_xxxxxxxxxxxxxxxxxxxxx', {
103
+ // Basic configuration
104
+ batchSize: 10, // Number of events per batch (default: 10)
105
+ batchTimeout: 30000, // Auto-send after 30 seconds (default: 30000ms)
106
+ });
107
+
108
+ console.log('✅ SDK initialized successfully');
109
+ } catch (error) {
110
+ console.error('❌ SDK initialization error:', error);
111
+ }
112
+ };
113
+
114
+ return (
115
+ // Your app content
116
+ );
117
+ }
118
+ ```
119
+
120
+ **Important Notes:**
121
+ - The `baseUrl` is hardcoded in the SDK (`https://api.riuve.com`), no need to pass it
122
+ - Get your API key from the [Nock Dashboard](https://dashboard.riuve.com)
123
+
124
+ ### Step 2: Identify Users
125
+
126
+ When a user logs in or user information is available:
127
+
128
+ ```typescript
129
+ import Riuve from 'riuve-rn';
130
+
131
+ // When user logs in
132
+ const handleLogin = async (userId: string, userEmail: string) => {
133
+ try {
134
+ await Riuve.identify(userId, {
135
+ email: userEmail,
136
+ name: 'User Name',
137
+ user_type: 'premium',
138
+ // Add any custom properties you want
139
+ });
140
+
141
+ console.log('✅ User identified');
142
+ } catch (error) {
143
+ console.error('❌ Identify error:', error);
144
+ }
145
+ };
146
+ ```
147
+
148
+ **When to Identify:**
149
+ - When user logs in
150
+ - When user information is updated
151
+ - On app start (if user is already logged in)
152
+
153
+ ### Step 3: Track Events
154
+
155
+ Track important actions in your app:
156
+
157
+ ```typescript
158
+ import Riuve from 'riuve-rn';
159
+ import { useFocusEffect } from '@react-navigation/native';
160
+ import { useCallback } from 'react';
161
+
162
+ // Screen view tracking (use useFocusEffect for tabs)
163
+ useFocusEffect(
164
+ useCallback(() => {
165
+ Riuve.track('screen_viewed', {
166
+ screen_name: 'Home',
167
+ screen_category: 'main',
168
+ }).catch(console.error);
169
+ }, [])
170
+ );
171
+
172
+ // Button click
173
+ const handleButtonClick = async () => {
174
+ try {
175
+ await Riuve.track('button_clicked', {
176
+ button_id: 'subscribe_button',
177
+ button_text: 'Subscribe',
178
+ screen: 'Home',
179
+ });
180
+
181
+ // Button action
182
+ // ...
183
+ } catch (error) {
184
+ console.error('Track error:', error);
185
+ }
186
+ };
187
+
188
+ // Form submission
189
+ const handleFormSubmit = async (formData: any) => {
190
+ try {
191
+ await Riuve.track('form_submitted', {
192
+ form_name: 'contact_form',
193
+ form_fields: Object.keys(formData).length,
194
+ success: true,
195
+ });
196
+ } catch (error) {
197
+ console.error('Track error:', error);
198
+ }
199
+ };
200
+ ```
201
+
202
+ **Event Naming Best Practices:**
203
+ - Use `snake_case`: `screen_viewed`, `button_clicked`
204
+ - Use descriptive names: `user_subscribed` ✅, `event1` ❌
205
+ - Be consistent: `screen_viewed` for all screens, `button_clicked` for all buttons
206
+
207
+ ---
208
+
209
+ ## Advanced Features
210
+
211
+ ### 1. Custom Event Properties
212
+
213
+ Add detailed information to events:
214
+
215
+ ```typescript
216
+ await Riuve.track('purchase_completed', {
217
+ product_id: 'prod_123',
218
+ product_name: 'Premium Subscription',
219
+ price: 99.99,
220
+ currency: 'USD',
221
+ payment_method: 'credit_card',
222
+ discount_code: 'SUMMER2024',
223
+ });
224
+ ```
225
+
226
+ ### 2. Manual Flush
227
+
228
+ Send events immediately when needed:
229
+
230
+ ```typescript
231
+ await Riuve.flush();
232
+ ```
233
+
234
+ **When to Use:**
235
+ - Before user exits the app for important events
236
+ - After critical actions (e.g., payment completed)
237
+
238
+ ### 3. Reset User
239
+
240
+ When user logs out:
241
+
242
+ ```typescript
243
+ await Riuve.reset();
244
+ ```
245
+
246
+ This will:
247
+ - Clear external user ID
248
+ - Clear user properties
249
+ - Generate a new anonymous ID
250
+ - Clear event queue
251
+
252
+ ### 4. FCM Token Management
253
+
254
+ Register FCM token for push notifications:
255
+
256
+ ```typescript
257
+ import * as Notifications from 'expo-notifications';
258
+
259
+ // Get FCM token
260
+ const token = await Notifications.getExpoPushTokenAsync();
261
+
262
+ // Register with SDK
263
+ await Riuve.setFcmToken(token.data);
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Best Practices
269
+
270
+ ### 1. Initialize Early
271
+
272
+ Initialize the SDK **as early as possible**:
273
+
274
+ ```typescript
275
+ // ✅ GOOD: At app start
276
+ export default function App() {
277
+ useEffect(() => {
278
+ Riuve.initialize('api_key');
279
+ }, []);
280
+ }
281
+
282
+ // ❌ BAD: After user action
283
+ const handleButtonClick = () => {
284
+ Riuve.initialize('api_key'); // Too late!
285
+ };
286
+ ```
287
+
288
+ ### 2. Error Handling
289
+
290
+ Always use try-catch:
291
+
292
+ ```typescript
293
+ // ✅ GOOD
294
+ try {
295
+ await Riuve.track('event_name', {});
296
+ } catch (error) {
297
+ console.error('Track failed:', error);
298
+ // Don't break app flow, just log it
299
+ }
300
+
301
+ // ❌ BAD
302
+ await Riuve.track('event_name', {}); // App may crash on error
303
+ ```
304
+
305
+ ### 3. Async/Await vs Promise
306
+
307
+ ```typescript
308
+ // ✅ GOOD: Async/await (more readable)
309
+ const handleAction = async () => {
310
+ try {
311
+ await Riuve.track('action_completed');
312
+ } catch (error) {
313
+ console.error(error);
314
+ }
315
+ };
316
+
317
+ // ✅ GOOD: Promise catch (for quick actions)
318
+ Riuve.track('quick_action').catch(console.error);
319
+
320
+ // ❌ BAD: Unhandled promise
321
+ Riuve.track('action'); // Fails silently on error
322
+ ```
323
+
324
+ ### 4. Event Naming Convention
325
+
326
+ Use a consistent naming convention:
327
+
328
+ ```typescript
329
+ // ✅ GOOD: Consistent and descriptive
330
+ Riuve.track('screen_viewed', { screen_name: 'Home' });
331
+ Riuve.track('screen_viewed', { screen_name: 'Profile' });
332
+ Riuve.track('button_clicked', { button_id: 'subscribe' });
333
+ Riuve.track('button_clicked', { button_id: 'cancel' });
334
+
335
+ // ❌ BAD: Inconsistent
336
+ Riuve.track('home_viewed');
337
+ Riuve.track('profile_screen');
338
+ Riuve.track('click_subscribe');
339
+ Riuve.track('cancelButton');
340
+ ```
341
+
342
+ ### 5. Tab Navigation Events
343
+
344
+ Use `useFocusEffect` for tab screens to avoid tracking events for unmounted tabs:
345
+
346
+ ```typescript
347
+ import { useFocusEffect } from '@react-navigation/native';
348
+
349
+ // ✅ GOOD: Only tracks when tab is actually focused
350
+ useFocusEffect(
351
+ useCallback(() => {
352
+ Riuve.track('screen_viewed', {
353
+ screen_name: 'Home',
354
+ }).catch(console.error);
355
+ }, [])
356
+ );
357
+
358
+ // ❌ BAD: Tracks even if tab is not visible
359
+ useEffect(() => {
360
+ Riuve.track('screen_viewed', {
361
+ screen_name: 'Home',
362
+ }).catch(console.error);
363
+ }, []);
364
+ ```
365
+
366
+ ### 6. Critical Events
367
+
368
+ Use flush for critical events:
369
+
370
+ ```typescript
371
+ // Payment completed - send immediately
372
+ await Riuve.track('purchase_completed', {
373
+ order_id: 'order_123',
374
+ amount: 99.99,
375
+ });
376
+ await Riuve.flush(); // Send immediately
377
+
378
+ // Screen view - send in batch (normal)
379
+ Riuve.track('screen_viewed', { screen_name: 'Home' });
380
+ ```
381
+
382
+ ---
383
+
384
+ ## Configuration Options
385
+
386
+ ### All Configuration Parameters
387
+
388
+ ```typescript
389
+ await Riuve.initialize('api_key', {
390
+ // Debugging
391
+ debugMode: false, // Enable detailed logging (default: false)
392
+
393
+ // Batch Settings
394
+ batchSize: 10, // Number of events per batch (default: 10)
395
+ batchTimeout: 30000, // Auto-send timeout in ms (default: 30000)
396
+
397
+ // Network Settings
398
+ requestTimeout: 10000, // API request timeout in ms (default: 10000)
399
+
400
+ // Retry Settings
401
+ maxRetries: 3, // Maximum retry attempts (default: 3)
402
+ retryDelay: 1000, // Retry delay in ms (default: 1000)
403
+
404
+ // Storage Settings
405
+ persistEvents: true, // Save events to storage (default: true)
406
+ maxQueueSize: 1000, // Maximum queue size (default: 1000)
407
+ eventRetentionDays: 7, // Days to keep failed events (default: 7)
408
+
409
+ // Automatic Operations
410
+ autoFlushOnBackground: true, // Auto-flush on background (default: true)
411
+ });
412
+ ```
413
+
414
+ ### Recommended Configurations
415
+
416
+ **Development:**
417
+ ```typescript
418
+ {
419
+ debugMode: true, // Enable detailed logging
420
+ batchSize: 5, // Smaller batches (for testing)
421
+ batchTimeout: 10000, // Faster sending (for testing)
422
+ }
423
+ ```
424
+
425
+ **Production:**
426
+ ```typescript
427
+ {
428
+ debugMode: false, // Only WARN and ERROR logs (default)
429
+ batchSize: 10, // Standard batch size
430
+ batchTimeout: 30000, // Wait 30 seconds
431
+ autoFlushOnBackground: true, // Send when backgrounded
432
+ }
433
+ ```
434
+
435
+ **High Volume (Many events):**
436
+ ```typescript
437
+ {
438
+ batchSize: 20, // Larger batches
439
+ batchTimeout: 60000, // Wait 1 minute
440
+ maxQueueSize: 5000, // Larger queue
441
+ }
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Troubleshooting
447
+
448
+ ### Problem 1: SDK Not Initializing
449
+
450
+ **Symptoms:**
451
+ - `SDK not initialized` error
452
+ - Events are not being tracked
453
+
454
+ **Solution:**
455
+ ```typescript
456
+ // Wait for initialization to complete
457
+ useEffect(() => {
458
+ const init = async () => {
459
+ await Riuve.initialize('api_key');
460
+ console.log('SDK initialized');
461
+ };
462
+ init();
463
+ }, []);
464
+
465
+ // Check before tracking
466
+ if (Riuve.isReady()) {
467
+ await Riuve.track('event');
468
+ }
469
+ ```
470
+
471
+ **Note:** Events tracked before initialization are automatically queued and processed after initialization.
472
+
473
+ ### Problem 2: Events Not Sending
474
+
475
+ **Checklist:**
476
+ 1. ✅ Is SDK initialized?
477
+ 2. ✅ Is API key correct?
478
+ 3. ✅ Is there internet connection?
479
+
480
+ **Debug:**
481
+ ```typescript
482
+ // Enable debug mode to see detailed logs
483
+ await Riuve.initialize('api_key', {
484
+ debugMode: true, // Shows DEBUG, INFO, WARN, and ERROR logs
485
+ });
486
+
487
+ // With debugMode: false (default), only WARN and ERROR are visible:
488
+ // [Riuve SDK] [WARN] Network offline, events will be stored
489
+ // [Riuve SDK] [ERROR] Failed to send batch
490
+
491
+ // With debugMode: true, you'll see everything:
492
+ // [Riuve SDK] [DEBUG] Config: {...}
493
+ // [Riuve SDK] [INFO] Making HTTP request: POST /api/sdk/track
494
+ // [Riuve SDK] [INFO] Event tracked: button_clicked
495
+ // [Riuve SDK] [WARN] Retry attempt 1...
496
+ // [Riuve SDK] [ERROR] Failed after 3 retries
497
+ ```
498
+
499
+ ### Problem 3: Offline Events Not Sending
500
+
501
+ **Normal Behavior:**
502
+ - Offline events are saved to AsyncStorage
503
+ - Automatically sent when internet connection is restored
504
+ - Sent when app is reopened
505
+
506
+ **Manual Check:**
507
+ ```typescript
508
+ // Manually flush
509
+ await Riuve.flush();
510
+
511
+ // Or on app start
512
+ useEffect(() => {
513
+ Riuve.initialize('api_key').then(() => {
514
+ Riuve.flush(); // Send pending events
515
+ });
516
+ }, []);
517
+ ```
518
+
519
+ ### Problem 4: Too Many Events Accumulating
520
+
521
+ **Solution:**
522
+ ```typescript
523
+ // Increase batch size
524
+ await Riuve.initialize('api_key', {
525
+ batchSize: 20, // Larger batches
526
+ batchTimeout: 15000, // Send more frequently
527
+ });
528
+ ```
529
+
530
+ ### Problem 5: TypeScript Errors
531
+
532
+ **Solution:**
533
+ ```typescript
534
+ // Use type assertion
535
+ await Riuve.track('event_name', {
536
+ custom_prop: value,
537
+ } as any); // Temporary solution
538
+
539
+ // Or proper typing
540
+ interface MyEventProperties {
541
+ custom_prop: string;
542
+ }
543
+
544
+ await Riuve.track('event_name', {
545
+ custom_prop: 'value',
546
+ } as MyEventProperties);
547
+ ```
548
+
549
+ ---
550
+
551
+ ## API Reference
552
+
553
+ ### Riuve.initialize()
554
+
555
+ Initializes the SDK.
556
+
557
+ ```typescript
558
+ await Riuve.initialize(apiKey: string, config?: RiuveConfig): Promise<void>
559
+ ```
560
+
561
+ **Parameters:**
562
+ - `apiKey` (string, required): Your API key from Nock dashboard
563
+ - `config` (object, optional): Configuration object
564
+
565
+ **Example:**
566
+ ```typescript
567
+ await Riuve.initialize('nock_live_xxx', {
568
+ batchSize: 10,
569
+ });
570
+ ```
571
+
572
+ ### Riuve.identify()
573
+
574
+ Identifies a user.
575
+
576
+ ```typescript
577
+ await Riuve.identify(externalUserId: string, properties?: object): Promise<void>
578
+ ```
579
+
580
+ **Parameters:**
581
+ - `externalUserId` (string, required): User's unique ID
582
+ - `properties` (object, optional): User properties
583
+
584
+ **Example:**
585
+ ```typescript
586
+ await Riuve.identify('user_123', {
587
+ email: 'user@example.com',
588
+ name: 'John Doe',
589
+ });
590
+ ```
591
+
592
+ **Note:** If user properties are updated, call `identify` again with the new properties.
593
+
594
+ ### Riuve.track()
595
+
596
+ Tracks an event.
597
+
598
+ ```typescript
599
+ await Riuve.track(eventName: string, properties?: object): Promise<void>
600
+ ```
601
+
602
+ **Parameters:**
603
+ - `eventName` (string, required): Event name
604
+ - `properties` (object, optional): Event properties
605
+
606
+ **Example:**
607
+ ```typescript
608
+ await Riuve.track('button_clicked', {
609
+ button_id: 'subscribe',
610
+ screen: 'Home',
611
+ });
612
+ ```
613
+
614
+ **Note:** Can be called before SDK initialization. Events will be queued and processed after initialization.
615
+
616
+ ### Riuve.flush()
617
+
618
+ Immediately sends all pending events.
619
+
620
+ ```typescript
621
+ await Riuve.flush(): Promise<void>
622
+ ```
623
+
624
+ **Example:**
625
+ ```typescript
626
+ await Riuve.track('purchase_completed');
627
+ await Riuve.flush(); // Send immediately
628
+ ```
629
+
630
+ ### Riuve.reset()
631
+
632
+ Clears user information and queue.
633
+
634
+ ```typescript
635
+ await Riuve.reset(): Promise<void>
636
+ ```
637
+
638
+ **Example:**
639
+ ```typescript
640
+ // When user logs out
641
+ await Riuve.reset();
642
+ ```
643
+
644
+ ### Riuve.setFcmToken()
645
+
646
+ Registers FCM token (for push notifications).
647
+
648
+ ```typescript
649
+ await Riuve.setFcmToken(token: string): Promise<void>
650
+ ```
651
+
652
+ **Example:**
653
+ ```typescript
654
+ const token = await Notifications.getExpoPushTokenAsync();
655
+ await Riuve.setFcmToken(token.data);
656
+ ```
657
+
658
+ ### Riuve.isReady()
659
+
660
+ Checks if SDK is initialized.
661
+
662
+ ```typescript
663
+ const isReady: boolean = Riuve.isReady();
664
+ ```
665
+
666
+ **Example:**
667
+ ```typescript
668
+ if (Riuve.isReady()) {
669
+ await Riuve.track('event');
670
+ }
671
+ ```
672
+
673
+ ### Riuve.getQueueSize()
674
+
675
+ Gets current queue size.
676
+
677
+ ```typescript
678
+ const queueSize: number = Riuve.getQueueSize();
679
+ ```
680
+
681
+ ### Riuve.getFailedBatchCount()
682
+
683
+ Gets number of failed batches waiting for retry.
684
+
685
+ ```typescript
686
+ const failedCount: number = await Riuve.getFailedBatchCount();
687
+ ```
688
+
689
+ ---
690
+
691
+ ## Example Scenarios
692
+
693
+ ### Scenario 1: E-Commerce App
694
+
695
+ ```typescript
696
+ // 1. On app start
697
+ useEffect(() => {
698
+ Riuve.initialize('api_key');
699
+ }, []);
700
+
701
+ // 2. When user logs in
702
+ const handleLogin = async (user: User) => {
703
+ await Riuve.identify(user.id, {
704
+ email: user.email,
705
+ name: user.name,
706
+ membership_type: user.membershipType,
707
+ });
708
+ };
709
+
710
+ // 3. Product view
711
+ const handleProductView = (product: Product) => {
712
+ Riuve.track('product_viewed', {
713
+ product_id: product.id,
714
+ product_name: product.name,
715
+ product_category: product.category,
716
+ price: product.price,
717
+ });
718
+ };
719
+
720
+ // 4. Add to cart
721
+ const handleAddToCart = (product: Product) => {
722
+ Riuve.track('add_to_cart', {
723
+ product_id: product.id,
724
+ product_name: product.name,
725
+ price: product.price,
726
+ quantity: 1,
727
+ });
728
+ };
729
+
730
+ // 5. Purchase completed
731
+ const handlePurchaseComplete = async (order: Order) => {
732
+ await Riuve.track('purchase_completed', {
733
+ order_id: order.id,
734
+ total_amount: order.total,
735
+ items_count: order.items.length,
736
+ payment_method: order.paymentMethod,
737
+ });
738
+ await Riuve.flush(); // Critical event, send immediately
739
+ };
740
+ ```
741
+
742
+ ### Scenario 2: Social Media App
743
+
744
+ ```typescript
745
+ // 1. Post view
746
+ const handlePostView = (post: Post) => {
747
+ Riuve.track('post_viewed', {
748
+ post_id: post.id,
749
+ author_id: post.authorId,
750
+ post_type: post.type,
751
+ });
752
+ };
753
+
754
+ // 2. Like/Unlike
755
+ const handleLike = (post: Post) => {
756
+ Riuve.track('post_liked', {
757
+ post_id: post.id,
758
+ author_id: post.authorId,
759
+ });
760
+ };
761
+
762
+ // 3. Comment
763
+ const handleComment = (post: Post, comment: string) => {
764
+ Riuve.track('comment_added', {
765
+ post_id: post.id,
766
+ comment_length: comment.length,
767
+ });
768
+ };
769
+
770
+ // 4. Profile view
771
+ const handleProfileView = (userId: string) => {
772
+ Riuve.track('profile_viewed', {
773
+ profile_user_id: userId,
774
+ });
775
+ };
776
+ ```
777
+
778
+ ### Scenario 3: Game App
779
+
780
+ ```typescript
781
+ // 1. Level start
782
+ const handleLevelStart = (level: number) => {
783
+ Riuve.track('level_started', {
784
+ level_number: level,
785
+ difficulty: 'normal',
786
+ });
787
+ };
788
+
789
+ // 2. Level completion
790
+ const handleLevelComplete = async (level: number, score: number) => {
791
+ await Riuve.track('level_completed', {
792
+ level_number: level,
793
+ score: score,
794
+ time_spent: getTimeSpent(),
795
+ });
796
+ await Riuve.flush(); // Important event
797
+ };
798
+
799
+ // 3. In-app purchase
800
+ const handleInAppPurchase = async (item: Item) => {
801
+ await Riuve.track('in_app_purchase', {
802
+ item_id: item.id,
803
+ item_name: item.name,
804
+ price: item.price,
805
+ currency: 'USD',
806
+ });
807
+ await Riuve.flush();
808
+ };
809
+ ```
810
+
811
+ ---
812
+
813
+ ## Security
814
+
815
+ ### API Key Security
816
+
817
+ - ✅ **Never** commit API keys to public repositories
818
+ - ✅ Use environment variables or secure storage
819
+ - ✅ Use different API keys for different projects
820
+
821
+ **Example:**
822
+ ```typescript
823
+ // ✅ GOOD: Environment variable
824
+ const API_KEY = process.env.EXPO_PUBLIC_RIUVE_API_KEY || '';
825
+
826
+ // ❌ BAD: Hardcoded
827
+ const API_KEY = 'nock_live_xxxxxxxxxxxxx';
828
+ ```
829
+
830
+ ---
831
+
832
+ ## Support
833
+
834
+ For questions and support:
835
+ - 📧 Email: support@riuve.com
836
+ - 📚 Documentation: https://docs.riuve.com
837
+ - 💬 Discord: [Nock Community](https://discord.gg/nock)
838
+
839
+ ---
840
+
841
+ ## License
842
+
843
+ MIT
844
+
845
+ ---
846
+
847
+ **Last Updated:** 2025-01-29
848
+ **SDK Version:** 1.1.1