respectlytics-react-native 1.0.1 → 2.0.1

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 (50) hide show
  1. package/README.md +44 -33
  2. package/lib/commonjs/EventQueue.js +174 -0
  3. package/lib/commonjs/EventQueue.js.map +1 -0
  4. package/lib/commonjs/NetworkClient.js +158 -0
  5. package/lib/commonjs/NetworkClient.js.map +1 -0
  6. package/lib/commonjs/Respectlytics.js +167 -0
  7. package/lib/commonjs/Respectlytics.js.map +1 -0
  8. package/lib/commonjs/SessionManager.js +75 -0
  9. package/lib/commonjs/SessionManager.js.map +1 -0
  10. package/lib/commonjs/Storage.js +57 -0
  11. package/lib/commonjs/Storage.js.map +1 -0
  12. package/lib/commonjs/index.js +37 -0
  13. package/lib/commonjs/index.js.map +1 -0
  14. package/lib/commonjs/types.js +35 -0
  15. package/lib/commonjs/types.js.map +1 -0
  16. package/lib/module/EventQueue.js +166 -0
  17. package/lib/module/EventQueue.js.map +1 -0
  18. package/lib/module/NetworkClient.js +151 -0
  19. package/lib/module/NetworkClient.js.map +1 -0
  20. package/lib/module/Respectlytics.js +162 -0
  21. package/lib/module/Respectlytics.js.map +1 -0
  22. package/lib/module/SessionManager.js +68 -0
  23. package/lib/module/SessionManager.js.map +1 -0
  24. package/lib/module/Storage.js +50 -0
  25. package/lib/module/Storage.js.map +1 -0
  26. package/lib/module/index.js +23 -0
  27. package/lib/module/index.js.map +1 -0
  28. package/lib/module/types.js +29 -0
  29. package/lib/module/types.js.map +1 -0
  30. package/lib/typescript/EventQueue.d.ts +47 -0
  31. package/lib/typescript/EventQueue.d.ts.map +1 -0
  32. package/lib/typescript/NetworkClient.d.ts +48 -0
  33. package/lib/typescript/NetworkClient.d.ts.map +1 -0
  34. package/lib/typescript/Respectlytics.d.ts +61 -0
  35. package/lib/typescript/Respectlytics.d.ts.map +1 -0
  36. package/lib/typescript/SessionManager.d.ts +39 -0
  37. package/lib/typescript/SessionManager.d.ts.map +1 -0
  38. package/lib/typescript/Storage.d.ts +26 -0
  39. package/lib/typescript/Storage.d.ts.map +1 -0
  40. package/lib/typescript/index.d.ts +18 -0
  41. package/lib/typescript/index.d.ts.map +1 -0
  42. package/lib/typescript/types.d.ts +38 -0
  43. package/lib/typescript/types.d.ts.map +1 -0
  44. package/package.json +2 -2
  45. package/src/NetworkClient.ts +1 -1
  46. package/src/Respectlytics.ts +7 -29
  47. package/src/SessionManager.ts +24 -20
  48. package/src/index.ts +8 -1
  49. package/src/types.ts +5 -2
  50. package/src/UserManager.ts +0 -74
package/README.md CHANGED
@@ -4,15 +4,15 @@
4
4
  [![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20Android-lightgrey.svg)](https://github.com/respectlytics/respectlytics-react-native)
5
5
  [![License](https://img.shields.io/badge/license-Proprietary-blue.svg)](LICENSE)
6
6
 
7
- Official Respectlytics SDK for React Native. Privacy-first analytics with automatic session management, offline event queuing, and zero device identifier collection.
7
+ Official Respectlytics SDK for React Native. Privacy-first, session-based analytics with automatic session management, offline event queuing, and zero device identifier collection.
8
8
 
9
9
  ## Features
10
10
 
11
11
  - 🔒 **Privacy-First**: No device identifiers (IDFA, GAID, Android ID)
12
- - ⚡ **Simple Integration**: 3 lines of code to get started
12
+ - ⚡ **Simple Integration**: 2 lines of code to get started
13
13
  - 📡 **Offline Support**: Events queue automatically and sync when online
14
- - 🔄 **Automatic Sessions**: 30-minute inactivity timeout, handled internally
15
- - 🎯 **Cross-Session Tracking**: Optional persistent user IDs
14
+ - 🔄 **Automatic Sessions**: RAM-only, 2-hour rotation, new session on app restart
15
+ - **Designed for GDPR/ePrivacy compliance** - Potentially consent-free
16
16
  - 📱 **Cross-Platform**: iOS and Android support
17
17
 
18
18
  ## Requirements
@@ -51,14 +51,13 @@ import Respectlytics from 'respectlytics-react-native';
51
51
  // 1. Configure at app startup
52
52
  Respectlytics.configure('your-api-key');
53
53
 
54
- // 2. Enable user tracking (optional)
55
- Respectlytics.identify();
56
-
57
- // 3. Track events
54
+ // 2. Track events
58
55
  Respectlytics.track('purchase');
59
56
  Respectlytics.track('view_product', 'ProductScreen');
60
57
  ```
61
58
 
59
+ That's it! Session management is fully automatic.
60
+
62
61
  ## API Reference
63
62
 
64
63
  ### `configure(apiKey: string)`
@@ -78,47 +77,49 @@ Respectlytics.track('button_clicked');
78
77
  Respectlytics.track('checkout_started', 'CartScreen');
79
78
  ```
80
79
 
81
- ### `identify()`
80
+ ### `flush()`
82
81
 
83
- Enable cross-session user tracking. Generates and persists a random user ID.
82
+ Force send all queued events immediately. Rarely needed - the SDK auto-flushes.
84
83
 
85
84
  ```typescript
86
- Respectlytics.identify();
85
+ await Respectlytics.flush();
87
86
  ```
88
87
 
89
- ### `reset()`
88
+ ## 🔄 Automatic Session Management
90
89
 
91
- Clear the user ID. Call when user logs out.
90
+ Session IDs are managed entirely by the SDK - no configuration needed.
92
91
 
93
- ```typescript
94
- Respectlytics.reset();
95
- ```
92
+ | Behavior | Description |
93
+ |----------|-------------|
94
+ | **New session on app launch** | Every time your app starts, a fresh session begins |
95
+ | **2-hour rotation** | Sessions automatically rotate after 2 hours of use |
96
+ | **RAM-only storage** | Session IDs are never written to disk |
97
+ | **No cross-session tracking** | Each session is independent and anonymous |
96
98
 
97
- ### `flush()`
99
+ This RAM-only approach ensures compliance with ePrivacy Directive Article 5(3) - no device storage means no consent requirement for the session identifier.
98
100
 
99
- Force send all queued events immediately. Rarely needed - the SDK auto-flushes.
101
+ ## Privacy by Design
100
102
 
101
- ```typescript
102
- await Respectlytics.flush();
103
- ```
103
+ Respectlytics is designed to minimize data collection by default. We use anonymized identifiers that are stored only in device memory (RAM) and rotate automatically every two hours or upon app restart. IP addresses are processed transiently for approximate region lookup and immediately discarded—no personal data is ever persisted server-side.
104
104
 
105
- ## Privacy by Design
105
+ This privacy-by-design architecture avoids persistent device storage and cross-session tracking, significantly reducing compliance complexity compared to traditional analytics. While this approach may reduce or eliminate consent requirements in some jurisdictions, regulations and their interpretation vary. We recommend consulting with your legal team to determine your specific compliance requirements.
106
106
 
107
107
  | What we DON'T collect | Why |
108
108
  |----------------------|-----|
109
109
  | IDFA / GAID | Device advertising IDs can track users across apps |
110
110
  | Device fingerprints | Can be used to identify users without consent |
111
- | IP addresses | Used only for geolocation lookup, then discarded |
111
+ | IP addresses | Processed transiently for geolocation, then discarded |
112
112
  | Custom properties | Prevents accidental PII collection |
113
+ | Persistent user IDs | Cross-session tracking requires consent |
113
114
 
114
115
  | What we DO collect | Purpose |
115
116
  |-------------------|---------|
116
117
  | Event name | Analytics |
117
118
  | Screen name | Navigation analytics |
118
- | Random session ID | Group events in a session |
119
- | Random user ID (opt-in) | Cross-session analytics |
119
+ | Random session ID (RAM-only) | Group events in a session |
120
120
  | Platform, OS version | Debugging |
121
- | App version | Debugging |
121
+ | App version, locale | Debugging |
122
+ | Country, region | Approximate geolocation |
122
123
 
123
124
  ## Automatic Behaviors
124
125
 
@@ -126,7 +127,7 @@ The SDK handles these automatically - no developer action needed:
126
127
 
127
128
  | Feature | Behavior |
128
129
  |---------|----------|
129
- | **Session Management** | New session ID generated on first event, rotates after 30 min inactivity |
130
+ | **Session Management** | New session ID on app launch, rotates after 2 hours |
130
131
  | **Event Batching** | Events queued and sent in batches (max 10 events or 30 seconds) |
131
132
  | **Offline Support** | Events queued when offline, sent when connectivity returns |
132
133
  | **Retry Logic** | Failed requests retry with exponential backoff (max 3 attempts) |
@@ -141,13 +142,23 @@ Events are automatically queued when offline and sent when connectivity returns:
141
142
  3. Queue is flushed when connectivity is restored
142
143
  4. Failed sends are retried with exponential backoff
143
144
 
144
- ## Session Management
145
+ ## Migration from v1.x
146
+
147
+ ### Breaking Changes
148
+
149
+ - `identify()` method removed - no longer needed
150
+ - `reset()` method removed - no longer needed
151
+ - AsyncStorage no longer used for user IDs - sessions are RAM-only
152
+
153
+ ### What to do
154
+
155
+ 1. Remove any calls to `Respectlytics.identify()`
156
+ 2. Remove any calls to `Respectlytics.reset()`
157
+ 3. That's it! Session management is now automatic.
145
158
 
146
- Sessions are managed automatically:
159
+ ### Why This Change?
147
160
 
148
- - New session starts on first event
149
- - Session rotates after 30 minutes of inactivity
150
- - No developer action required
161
+ Storing identifiers on device (AsyncStorage) requires user consent under ePrivacy Directive Article 5(3). In-memory sessions require no consent, making Respectlytics truly consent-free analytics.
151
162
 
152
163
  ## License
153
164
 
@@ -155,6 +166,6 @@ This SDK is provided under a proprietary license. See [LICENSE](LICENSE) for det
155
166
 
156
167
  ## Support
157
168
 
158
- - Documentation: [https://respectlytics.com/docs/](https://respectlytics.com/docs/)
169
+ - Documentation: [https://respectlytics.com/sdk/](https://respectlytics.com/sdk/)
159
170
  - Issues: [https://github.com/respectlytics/respectlytics-react-native/issues](https://github.com/respectlytics/respectlytics-react-native/issues)
160
171
  - Email: respectlytics@loheden.com
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.EventQueue = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _netinfo = _interopRequireDefault(require("@react-native-community/netinfo"));
9
+ var _Storage = require("./Storage");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ /**
12
+ * EventQueue.ts
13
+ * Respectlytics React Native SDK
14
+ *
15
+ * Manages event batching, persistence, and automatic flushing.
16
+ * Events are NEVER lost - they are persisted immediately and retried on failure.
17
+ * Copyright (c) 2025 Respectlytics. All rights reserved.
18
+ */
19
+
20
+ const MAX_QUEUE_SIZE = 10;
21
+ const FLUSH_INTERVAL_MS = 30000; // 30 seconds
22
+ const QUEUE_STORAGE_KEY = 'com.respectlytics.eventQueue';
23
+ class EventQueue {
24
+ events = [];
25
+ isOnline = true;
26
+ flushTimer = null;
27
+ isFlushing = false;
28
+ unsubscribeNetInfo = null;
29
+ appStateSubscription = null;
30
+ constructor(networkClient) {
31
+ this.networkClient = networkClient;
32
+ }
33
+
34
+ /**
35
+ * Initialize the queue - load persisted events and set up listeners
36
+ */
37
+ async start() {
38
+ await this.loadPersistedQueue();
39
+ this.setupNetworkMonitor();
40
+ this.setupAppStateMonitor();
41
+ this.scheduleFlush();
42
+ console.log('[Respectlytics] ✓ Event queue started');
43
+ }
44
+
45
+ /**
46
+ * Stop the queue and clean up resources
47
+ */
48
+ stop() {
49
+ if (this.flushTimer) {
50
+ clearInterval(this.flushTimer);
51
+ this.flushTimer = null;
52
+ }
53
+ if (this.unsubscribeNetInfo) {
54
+ this.unsubscribeNetInfo();
55
+ this.unsubscribeNetInfo = null;
56
+ }
57
+ if (this.appStateSubscription) {
58
+ this.appStateSubscription.remove();
59
+ this.appStateSubscription = null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Add an event to the queue
65
+ * CRITICAL: Events are persisted IMMEDIATELY before any async operations
66
+ */
67
+ async add(event) {
68
+ this.events.push(event);
69
+
70
+ // IMMEDIATELY persist before any async operations
71
+ await this.persistQueue();
72
+
73
+ // Check if we should flush
74
+ if (this.events.length >= MAX_QUEUE_SIZE) {
75
+ this.flush();
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Force flush all queued events
81
+ */
82
+ async flush() {
83
+ if (this.isFlushing || this.events.length === 0) {
84
+ return;
85
+ }
86
+ if (!this.isOnline) {
87
+ console.log('[Respectlytics] Offline, skipping flush');
88
+ return;
89
+ }
90
+ if (!this.networkClient.isConfigured()) {
91
+ console.log('[Respectlytics] ⚠️ SDK not configured, skipping flush');
92
+ return;
93
+ }
94
+ this.isFlushing = true;
95
+
96
+ // Take a snapshot of events to send
97
+ const batch = [...this.events];
98
+ this.events = [];
99
+ await this.persistQueue();
100
+ try {
101
+ await this.networkClient.send(batch);
102
+ console.log(`[Respectlytics] ✓ Sent ${batch.length} event(s)`);
103
+ } catch (error) {
104
+ // Re-add failed events to the front of the queue
105
+ this.events = [...batch, ...this.events];
106
+ await this.persistQueue();
107
+ console.log('[Respectlytics] Failed to send events, will retry later');
108
+ } finally {
109
+ this.isFlushing = false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Get current queue size (for testing)
115
+ */
116
+ getQueueSize() {
117
+ return this.events.length;
118
+ }
119
+
120
+ // MARK: - Private Helpers
121
+
122
+ scheduleFlush() {
123
+ if (this.flushTimer) {
124
+ clearInterval(this.flushTimer);
125
+ }
126
+ this.flushTimer = setInterval(() => {
127
+ this.flush();
128
+ }, FLUSH_INTERVAL_MS);
129
+ }
130
+ setupNetworkMonitor() {
131
+ this.unsubscribeNetInfo = _netinfo.default.addEventListener(state => {
132
+ const wasOffline = !this.isOnline;
133
+ this.isOnline = state.isConnected ?? false;
134
+
135
+ // If we just came online, try to flush
136
+ if (wasOffline && this.isOnline) {
137
+ console.log('[Respectlytics] Network restored, flushing queue');
138
+ this.flush();
139
+ }
140
+ });
141
+ }
142
+ setupAppStateMonitor() {
143
+ this.appStateSubscription = _reactNative.AppState.addEventListener('change', nextAppState => {
144
+ // Flush when app goes to background
145
+ if (nextAppState === 'background' || nextAppState === 'inactive') {
146
+ this.flush();
147
+ }
148
+ });
149
+ }
150
+ async persistQueue() {
151
+ try {
152
+ await _Storage.Storage.setItem(QUEUE_STORAGE_KEY, JSON.stringify(this.events));
153
+ } catch (error) {
154
+ console.log('[Respectlytics] Failed to persist queue:', error);
155
+ }
156
+ }
157
+ async loadPersistedQueue() {
158
+ try {
159
+ const data = await _Storage.Storage.getItem(QUEUE_STORAGE_KEY);
160
+ if (data) {
161
+ const parsed = JSON.parse(data);
162
+ if (Array.isArray(parsed)) {
163
+ this.events = parsed;
164
+ console.log(`[Respectlytics] Loaded ${this.events.length} persisted event(s)`);
165
+ }
166
+ }
167
+ } catch (error) {
168
+ console.log('[Respectlytics] Failed to load persisted queue:', error);
169
+ this.events = [];
170
+ }
171
+ }
172
+ }
173
+ exports.EventQueue = EventQueue;
174
+ //# sourceMappingURL=EventQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_netinfo","_interopRequireDefault","_Storage","e","__esModule","default","MAX_QUEUE_SIZE","FLUSH_INTERVAL_MS","QUEUE_STORAGE_KEY","EventQueue","events","isOnline","flushTimer","isFlushing","unsubscribeNetInfo","appStateSubscription","constructor","networkClient","start","loadPersistedQueue","setupNetworkMonitor","setupAppStateMonitor","scheduleFlush","console","log","stop","clearInterval","remove","add","event","push","persistQueue","length","flush","isConfigured","batch","send","error","getQueueSize","setInterval","NetInfo","addEventListener","state","wasOffline","isConnected","AppState","nextAppState","Storage","setItem","JSON","stringify","data","getItem","parsed","parse","Array","isArray","exports"],"sourceRoot":"../../src","sources":["EventQueue.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.networkClient = exports.NetworkError = exports.NetworkClient = void 0;
7
+ /**
8
+ * NetworkClient.ts
9
+ * Respectlytics React Native SDK
10
+ *
11
+ * Handles HTTP communication with the Respectlytics API.
12
+ * Copyright (c) 2025 Respectlytics. All rights reserved.
13
+ */
14
+
15
+ const API_ENDPOINT = 'https://respectlytics.com/api/v1/events/';
16
+ const MAX_RETRIES = 3;
17
+ const TIMEOUT_MS = 30000;
18
+ let NetworkError = exports.NetworkError = /*#__PURE__*/function (NetworkError) {
19
+ NetworkError["NotConfigured"] = "NOT_CONFIGURED";
20
+ NetworkError["InvalidResponse"] = "INVALID_RESPONSE";
21
+ NetworkError["Unauthorized"] = "UNAUTHORIZED";
22
+ NetworkError["BadRequest"] = "BAD_REQUEST";
23
+ NetworkError["RateLimited"] = "RATE_LIMITED";
24
+ NetworkError["ServerError"] = "SERVER_ERROR";
25
+ NetworkError["NetworkError"] = "NETWORK_ERROR";
26
+ NetworkError["Timeout"] = "TIMEOUT";
27
+ return NetworkError;
28
+ }({});
29
+ class NetworkClient {
30
+ apiKey = null;
31
+
32
+ /**
33
+ * Configure the network client with an API key
34
+ */
35
+ configure(apiKey) {
36
+ this.apiKey = apiKey;
37
+ }
38
+
39
+ /**
40
+ * Check if the client is configured
41
+ */
42
+ isConfigured() {
43
+ return this.apiKey !== null;
44
+ }
45
+
46
+ /**
47
+ * Send events to the API
48
+ */
49
+ async send(events) {
50
+ if (!this.apiKey) {
51
+ throw new Error(NetworkError.NotConfigured);
52
+ }
53
+ for (const event of events) {
54
+ await this.sendEvent(event, 1);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Send a single event with retry logic
60
+ */
61
+ async sendEvent(event, attempt) {
62
+ if (!this.apiKey) {
63
+ throw new Error(NetworkError.NotConfigured);
64
+ }
65
+ const controller = new AbortController();
66
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
67
+ try {
68
+ const response = await fetch(API_ENDPOINT, {
69
+ method: 'POST',
70
+ headers: {
71
+ 'Content-Type': 'application/json',
72
+ 'X-App-Key': this.apiKey
73
+ },
74
+ body: JSON.stringify(this.eventToPayload(event)),
75
+ signal: controller.signal
76
+ });
77
+ clearTimeout(timeoutId);
78
+ if (response.ok) {
79
+ return; // Success
80
+ }
81
+ switch (response.status) {
82
+ case 401:
83
+ throw new Error(NetworkError.Unauthorized);
84
+ case 400:
85
+ throw new Error(NetworkError.BadRequest);
86
+ case 429:
87
+ // Rate limited - retry with backoff
88
+ if (attempt < MAX_RETRIES) {
89
+ await this.delay(Math.pow(2, attempt) * 1000);
90
+ return this.sendEvent(event, attempt + 1);
91
+ }
92
+ throw new Error(NetworkError.RateLimited);
93
+ default:
94
+ if (response.status >= 500) {
95
+ // Server error - retry with backoff
96
+ if (attempt < MAX_RETRIES) {
97
+ await this.delay(Math.pow(2, attempt) * 1000);
98
+ return this.sendEvent(event, attempt + 1);
99
+ }
100
+ throw new Error(NetworkError.ServerError);
101
+ }
102
+ throw new Error(NetworkError.InvalidResponse);
103
+ }
104
+ } catch (error) {
105
+ clearTimeout(timeoutId);
106
+ if (error instanceof Error) {
107
+ // Don't retry auth or bad request errors
108
+ if (error.message === NetworkError.Unauthorized || error.message === NetworkError.BadRequest) {
109
+ throw error;
110
+ }
111
+
112
+ // Check for abort (timeout)
113
+ if (error.name === 'AbortError') {
114
+ if (attempt < MAX_RETRIES) {
115
+ await this.delay(Math.pow(2, attempt) * 1000);
116
+ return this.sendEvent(event, attempt + 1);
117
+ }
118
+ throw new Error(NetworkError.Timeout);
119
+ }
120
+ }
121
+
122
+ // Network error - retry with backoff
123
+ if (attempt < MAX_RETRIES) {
124
+ await this.delay(Math.pow(2, attempt) * 1000);
125
+ return this.sendEvent(event, attempt + 1);
126
+ }
127
+ throw new Error(NetworkError.NetworkError);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Convert Event object to API payload format
133
+ * Note: As of v2.0.0, no user_id field is sent (session-based analytics only)
134
+ */
135
+ eventToPayload(event) {
136
+ return {
137
+ event_name: event.eventName,
138
+ timestamp: event.timestamp,
139
+ session_id: event.sessionId,
140
+ screen: event.screen || undefined,
141
+ platform: event.platform,
142
+ os_version: event.osVersion,
143
+ app_version: event.appVersion,
144
+ locale: event.locale,
145
+ device_type: event.deviceType
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Helper to delay for exponential backoff
151
+ */
152
+ delay(ms) {
153
+ return new Promise(resolve => setTimeout(resolve, ms));
154
+ }
155
+ }
156
+ exports.NetworkClient = NetworkClient;
157
+ const networkClient = exports.networkClient = new NetworkClient();
158
+ //# sourceMappingURL=NetworkClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["API_ENDPOINT","MAX_RETRIES","TIMEOUT_MS","NetworkError","exports","NetworkClient","apiKey","configure","isConfigured","send","events","Error","NotConfigured","event","sendEvent","attempt","controller","AbortController","timeoutId","setTimeout","abort","response","fetch","method","headers","body","JSON","stringify","eventToPayload","signal","clearTimeout","ok","status","Unauthorized","BadRequest","delay","Math","pow","RateLimited","ServerError","InvalidResponse","error","message","name","Timeout","event_name","eventName","timestamp","session_id","sessionId","screen","undefined","platform","os_version","osVersion","app_version","appVersion","locale","device_type","deviceType","ms","Promise","resolve","networkClient"],"sourceRoot":"../../src","sources":["NetworkClient.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.RespectlyticsSDK = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _SessionManager = require("./SessionManager");
9
+ var _NetworkClient = require("./NetworkClient");
10
+ var _EventQueue = require("./EventQueue");
11
+ /**
12
+ * Respectlytics.ts
13
+ * Respectlytics React Native SDK
14
+ *
15
+ * Main entry point for the SDK.
16
+ * Copyright (c) 2025 Respectlytics. All rights reserved.
17
+ */
18
+
19
+ /**
20
+ * Main entry point for the Respectlytics SDK.
21
+ *
22
+ * v2.0.0 uses session-based analytics only:
23
+ * - Session IDs are generated automatically in RAM
24
+ * - Sessions rotate every 2 hours
25
+ * - New session on every app restart
26
+ * - No persistent user tracking (GDPR/ePrivacy compliant)
27
+ *
28
+ * Usage:
29
+ * ```typescript
30
+ * // 1. Configure at app launch
31
+ * Respectlytics.configure('your-api-key');
32
+ *
33
+ * // 2. Track events
34
+ * Respectlytics.track('purchase');
35
+ * Respectlytics.track('view_product', 'ProductScreen');
36
+ * ```
37
+ */
38
+ class RespectlyticsSDK {
39
+ isConfigured = false;
40
+ constructor() {
41
+ this.networkClient = new _NetworkClient.NetworkClient();
42
+ this.eventQueue = new _EventQueue.EventQueue(this.networkClient);
43
+ this.sessionManager = new _SessionManager.SessionManager();
44
+ }
45
+
46
+ /**
47
+ * Initialize the SDK with your API key.
48
+ * Call once at app startup.
49
+ *
50
+ * @param apiKey Your Respectlytics API key from the dashboard
51
+ */
52
+ configure(apiKey) {
53
+ if (!apiKey || apiKey.trim() === '') {
54
+ console.log('[Respectlytics] ⚠️ API key cannot be empty');
55
+ return;
56
+ }
57
+ this.networkClient.configure(apiKey);
58
+ this.eventQueue.start();
59
+ this.isConfigured = true;
60
+ console.log('[Respectlytics] ✓ SDK configured');
61
+ }
62
+
63
+ /**
64
+ * Track an event with an optional screen name.
65
+ *
66
+ * The SDK automatically collects privacy-safe metadata:
67
+ * - timestamp, session_id, platform, os_version, app_version, locale
68
+ *
69
+ * @param eventName Name of the event (e.g., "purchase", "button_clicked")
70
+ * @param screen Optional screen name where the event occurred
71
+ */
72
+ track(eventName, screen) {
73
+ if (!this.isConfigured) {
74
+ console.log('[Respectlytics] ⚠️ SDK not configured. Call configure(apiKey) first.');
75
+ return;
76
+ }
77
+ if (!eventName || eventName.trim() === '') {
78
+ console.log('[Respectlytics] ⚠️ Event name cannot be empty');
79
+ return;
80
+ }
81
+ if (eventName.length > 100) {
82
+ console.log('[Respectlytics] ⚠️ Event name too long (max 100 characters)');
83
+ return;
84
+ }
85
+ const event = this.createEvent(eventName, screen);
86
+ this.eventQueue.add(event);
87
+ }
88
+
89
+ /**
90
+ * Force send all queued events immediately.
91
+ * Rarely needed - the SDK auto-flushes every 30 seconds or when the queue reaches 10 events.
92
+ */
93
+ async flush() {
94
+ await this.eventQueue.flush();
95
+ }
96
+
97
+ // MARK: - Private Helpers
98
+
99
+ createEvent(eventName, screen) {
100
+ const metadata = this.collectMetadata();
101
+ return {
102
+ eventName,
103
+ timestamp: new Date().toISOString(),
104
+ sessionId: this.sessionManager.getSessionId(),
105
+ screen: screen || null,
106
+ ...metadata
107
+ };
108
+ }
109
+ collectMetadata() {
110
+ // Determine platform
111
+ const platform = _reactNative.Platform.OS === 'ios' ? 'iOS' : 'Android';
112
+
113
+ // Get OS version
114
+ const osVersion = String(_reactNative.Platform.Version);
115
+
116
+ // Get app version - try to get from native modules
117
+ let appVersion = 'unknown';
118
+ try {
119
+ // React Native provides app info through different native modules
120
+ const {
121
+ PlatformConstants
122
+ } = _reactNative.NativeModules;
123
+ if (PlatformConstants?.reactNativeVersion) {
124
+ // This is React Native version, not app version
125
+ // App version should come from the host app
126
+ }
127
+ // For now, use 'unknown' as we can't reliably get app version without additional dependencies
128
+ // In a real app, the developer would configure this
129
+ } catch {
130
+ appVersion = 'unknown';
131
+ }
132
+
133
+ // Get locale
134
+ let locale = 'en_US';
135
+ try {
136
+ // React Native doesn't expose locale directly, but we can get it from platform
137
+ if (_reactNative.Platform.OS === 'ios') {
138
+ locale = _reactNative.NativeModules.SettingsManager?.settings?.AppleLocale || _reactNative.NativeModules.SettingsManager?.settings?.AppleLanguages?.[0] || 'en_US';
139
+ } else {
140
+ locale = _reactNative.NativeModules.I18nManager?.localeIdentifier || 'en_US';
141
+ }
142
+ } catch {
143
+ locale = 'en_US';
144
+ }
145
+
146
+ // Determine device type based on screen size
147
+ const {
148
+ width,
149
+ height
150
+ } = _reactNative.Dimensions.get('window');
151
+ const minDimension = Math.min(width, height);
152
+ const deviceType = minDimension >= 600 ? 'tablet' : 'phone';
153
+ return {
154
+ platform,
155
+ osVersion,
156
+ appVersion,
157
+ locale,
158
+ deviceType
159
+ };
160
+ }
161
+ }
162
+
163
+ // Export singleton instance
164
+ exports.RespectlyticsSDK = RespectlyticsSDK;
165
+ const Respectlytics = new RespectlyticsSDK();
166
+ var _default = exports.default = Respectlytics;
167
+ //# sourceMappingURL=Respectlytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_SessionManager","_NetworkClient","_EventQueue","RespectlyticsSDK","isConfigured","constructor","networkClient","NetworkClient","eventQueue","EventQueue","sessionManager","SessionManager","configure","apiKey","trim","console","log","start","track","eventName","screen","length","event","createEvent","add","flush","metadata","collectMetadata","timestamp","Date","toISOString","sessionId","getSessionId","platform","Platform","OS","osVersion","String","Version","appVersion","PlatformConstants","NativeModules","reactNativeVersion","locale","SettingsManager","settings","AppleLocale","AppleLanguages","I18nManager","localeIdentifier","width","height","Dimensions","get","minDimension","Math","min","deviceType","exports","Respectlytics","_default","default"],"sourceRoot":"../../src","sources":["Respectlytics.ts"],"mappings":"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","ignoreList":[]}