respectlytics-react-native 1.0.1 → 2.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.
- package/README.md +43 -34
- package/lib/commonjs/EventQueue.js +174 -0
- package/lib/commonjs/EventQueue.js.map +1 -0
- package/lib/commonjs/NetworkClient.js +158 -0
- package/lib/commonjs/NetworkClient.js.map +1 -0
- package/lib/commonjs/Respectlytics.js +167 -0
- package/lib/commonjs/Respectlytics.js.map +1 -0
- package/lib/commonjs/SessionManager.js +75 -0
- package/lib/commonjs/SessionManager.js.map +1 -0
- package/lib/commonjs/Storage.js +57 -0
- package/lib/commonjs/Storage.js.map +1 -0
- package/lib/commonjs/index.js +37 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types.js +35 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/EventQueue.js +166 -0
- package/lib/module/EventQueue.js.map +1 -0
- package/lib/module/NetworkClient.js +151 -0
- package/lib/module/NetworkClient.js.map +1 -0
- package/lib/module/Respectlytics.js +162 -0
- package/lib/module/Respectlytics.js.map +1 -0
- package/lib/module/SessionManager.js +68 -0
- package/lib/module/SessionManager.js.map +1 -0
- package/lib/module/Storage.js +50 -0
- package/lib/module/Storage.js.map +1 -0
- package/lib/module/index.js +23 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +29 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/EventQueue.d.ts +47 -0
- package/lib/typescript/EventQueue.d.ts.map +1 -0
- package/lib/typescript/NetworkClient.d.ts +48 -0
- package/lib/typescript/NetworkClient.d.ts.map +1 -0
- package/lib/typescript/Respectlytics.d.ts +61 -0
- package/lib/typescript/Respectlytics.d.ts.map +1 -0
- package/lib/typescript/SessionManager.d.ts +39 -0
- package/lib/typescript/SessionManager.d.ts.map +1 -0
- package/lib/typescript/Storage.d.ts +26 -0
- package/lib/typescript/Storage.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +18 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +38 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/NetworkClient.ts +1 -1
- package/src/Respectlytics.ts +7 -29
- package/src/SessionManager.ts +24 -20
- package/src/index.ts +8 -1
- package/src/types.ts +5 -2
- package/src/UserManager.ts +0 -74
package/README.md
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
[](https://github.com/respectlytics/respectlytics-react-native)
|
|
5
5
|
[](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**:
|
|
12
|
+
- ⚡ **Simple Integration**: 2 lines of code to get started
|
|
13
13
|
- 📡 **Offline Support**: Events queue automatically and sync when online
|
|
14
|
-
- 🔄 **Automatic Sessions**:
|
|
15
|
-
-
|
|
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.
|
|
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,47 @@ Respectlytics.track('button_clicked');
|
|
|
78
77
|
Respectlytics.track('checkout_started', 'CartScreen');
|
|
79
78
|
```
|
|
80
79
|
|
|
81
|
-
### `
|
|
80
|
+
### `flush()`
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
Force send all queued events immediately. Rarely needed - the SDK auto-flushes.
|
|
84
83
|
|
|
85
84
|
```typescript
|
|
86
|
-
Respectlytics.
|
|
85
|
+
await Respectlytics.flush();
|
|
87
86
|
```
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
## 🔄 Automatic Session Management
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
Session IDs are managed entirely by the SDK - no configuration needed.
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
Force send all queued events immediately. Rarely needed - the SDK auto-flushes.
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
await Respectlytics.flush();
|
|
103
|
-
```
|
|
99
|
+
This RAM-only approach ensures compliance with ePrivacy Directive Article 5(3) - no device storage means no consent requirement for the session identifier.
|
|
104
100
|
|
|
105
101
|
## Privacy by Design
|
|
106
102
|
|
|
103
|
+
Your privacy is our priority. Our mobile analytics solution is meticulously designed to provide valuable insights without compromising your data. We achieve this by collecting only session-based data, using anonymized identifiers that are stored only in your device's memory and renewed every two hours or upon app restart. IP addresses are processed transiently for approximate geolocation (country and region) only and are never stored. This privacy-by-design approach ensures that no personal data is retained, making our solution designed to comply with GDPR and the ePrivacy Directive, potentially enabling analytics without user consent in many jurisdictions.
|
|
104
|
+
|
|
107
105
|
| What we DON'T collect | Why |
|
|
108
106
|
|----------------------|-----|
|
|
109
107
|
| IDFA / GAID | Device advertising IDs can track users across apps |
|
|
110
108
|
| Device fingerprints | Can be used to identify users without consent |
|
|
111
|
-
| IP addresses |
|
|
109
|
+
| IP addresses | Processed transiently for geolocation, then discarded |
|
|
112
110
|
| Custom properties | Prevents accidental PII collection |
|
|
111
|
+
| Persistent user IDs | Cross-session tracking requires consent |
|
|
113
112
|
|
|
114
113
|
| What we DO collect | Purpose |
|
|
115
114
|
|-------------------|---------|
|
|
116
115
|
| Event name | Analytics |
|
|
117
116
|
| Screen name | Navigation analytics |
|
|
118
|
-
| Random session ID | Group events in a session |
|
|
119
|
-
| Random user ID (opt-in) | Cross-session analytics |
|
|
117
|
+
| Random session ID (RAM-only) | Group events in a session |
|
|
120
118
|
| Platform, OS version | Debugging |
|
|
121
|
-
| App version | Debugging |
|
|
119
|
+
| App version, locale | Debugging |
|
|
120
|
+
| Country, region | Approximate geolocation |
|
|
122
121
|
|
|
123
122
|
## Automatic Behaviors
|
|
124
123
|
|
|
@@ -126,7 +125,7 @@ The SDK handles these automatically - no developer action needed:
|
|
|
126
125
|
|
|
127
126
|
| Feature | Behavior |
|
|
128
127
|
|---------|----------|
|
|
129
|
-
| **Session Management** | New session ID
|
|
128
|
+
| **Session Management** | New session ID on app launch, rotates after 2 hours |
|
|
130
129
|
| **Event Batching** | Events queued and sent in batches (max 10 events or 30 seconds) |
|
|
131
130
|
| **Offline Support** | Events queued when offline, sent when connectivity returns |
|
|
132
131
|
| **Retry Logic** | Failed requests retry with exponential backoff (max 3 attempts) |
|
|
@@ -141,13 +140,23 @@ Events are automatically queued when offline and sent when connectivity returns:
|
|
|
141
140
|
3. Queue is flushed when connectivity is restored
|
|
142
141
|
4. Failed sends are retried with exponential backoff
|
|
143
142
|
|
|
144
|
-
##
|
|
143
|
+
## Migration from v1.x
|
|
144
|
+
|
|
145
|
+
### Breaking Changes
|
|
146
|
+
|
|
147
|
+
- `identify()` method removed - no longer needed
|
|
148
|
+
- `reset()` method removed - no longer needed
|
|
149
|
+
- AsyncStorage no longer used for user IDs - sessions are RAM-only
|
|
150
|
+
|
|
151
|
+
### What to do
|
|
152
|
+
|
|
153
|
+
1. Remove any calls to `Respectlytics.identify()`
|
|
154
|
+
2. Remove any calls to `Respectlytics.reset()`
|
|
155
|
+
3. That's it! Session management is now automatic.
|
|
145
156
|
|
|
146
|
-
|
|
157
|
+
### Why This Change?
|
|
147
158
|
|
|
148
|
-
-
|
|
149
|
-
- Session rotates after 30 minutes of inactivity
|
|
150
|
-
- No developer action required
|
|
159
|
+
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
160
|
|
|
152
161
|
## License
|
|
153
162
|
|
|
@@ -155,6 +164,6 @@ This SDK is provided under a proprietary license. See [LICENSE](LICENSE) for det
|
|
|
155
164
|
|
|
156
165
|
## Support
|
|
157
166
|
|
|
158
|
-
- Documentation: [https://respectlytics.com/
|
|
167
|
+
- Documentation: [https://respectlytics.com/sdk/](https://respectlytics.com/sdk/)
|
|
159
168
|
- Issues: [https://github.com/respectlytics/respectlytics-react-native/issues](https://github.com/respectlytics/respectlytics-react-native/issues)
|
|
160
169
|
- 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":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA,MAAMA,YAAY,GAAG,0CAA0C;AAC/D,MAAMC,WAAW,GAAG,CAAC;AACrB,MAAMC,UAAU,GAAG,KAAK;AAAC,IAEbC,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA;AAWjB,MAAME,aAAa,CAAC;EACjBC,MAAM,GAAkB,IAAI;;EAEpC;AACF;AACA;EACEC,SAASA,CAACD,MAAc,EAAQ;IAC9B,IAAI,CAACA,MAAM,GAAGA,MAAM;EACtB;;EAEA;AACF;AACA;EACEE,YAAYA,CAAA,EAAY;IACtB,OAAO,IAAI,CAACF,MAAM,KAAK,IAAI;EAC7B;;EAEA;AACF;AACA;EACE,MAAMG,IAAIA,CAACC,MAAe,EAAiB;IACzC,IAAI,CAAC,IAAI,CAACJ,MAAM,EAAE;MAChB,MAAM,IAAIK,KAAK,CAACR,YAAY,CAACS,aAAa,CAAC;IAC7C;IAEA,KAAK,MAAMC,KAAK,IAAIH,MAAM,EAAE;MAC1B,MAAM,IAAI,CAACI,SAAS,CAACD,KAAK,EAAE,CAAC,CAAC;IAChC;EACF;;EAEA;AACF;AACA;EACE,MAAcC,SAASA,CAACD,KAAY,EAAEE,OAAe,EAAiB;IACpE,IAAI,CAAC,IAAI,CAACT,MAAM,EAAE;MAChB,MAAM,IAAIK,KAAK,CAACR,YAAY,CAACS,aAAa,CAAC;IAC7C;IAEA,MAAMI,UAAU,GAAG,IAAIC,eAAe,CAAC,CAAC;IACxC,MAAMC,SAAS,GAAGC,UAAU,CAAC,MAAMH,UAAU,CAACI,KAAK,CAAC,CAAC,EAAElB,UAAU,CAAC;IAElE,IAAI;MACF,MAAMmB,QAAQ,GAAG,MAAMC,KAAK,CAACtB,YAAY,EAAE;QACzCuB,MAAM,EAAE,MAAM;QACdC,OAAO,EAAE;UACP,cAAc,EAAE,kBAAkB;UAClC,WAAW,EAAE,IAAI,CAAClB;QACpB,CAAC;QACDmB,IAAI,EAAEC,IAAI,CAACC,SAAS,CAAC,IAAI,CAACC,cAAc,CAACf,KAAK,CAAC,CAAC;QAChDgB,MAAM,EAAEb,UAAU,CAACa;MACrB,CAAC,CAAC;MAEFC,YAAY,CAACZ,SAAS,CAAC;MAEvB,IAAIG,QAAQ,CAACU,EAAE,EAAE;QACf,OAAO,CAAC;MACV;MAEA,QAAQV,QAAQ,CAACW,MAAM;QACrB,KAAK,GAAG;UACN,MAAM,IAAIrB,KAAK,CAACR,YAAY,CAAC8B,YAAY,CAAC;QAC5C,KAAK,GAAG;UACN,MAAM,IAAItB,KAAK,CAACR,YAAY,CAAC+B,UAAU,CAAC;QAC1C,KAAK,GAAG;UACN;UACA,IAAInB,OAAO,GAAGd,WAAW,EAAE;YACzB,MAAM,IAAI,CAACkC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEtB,OAAO,CAAC,GAAG,IAAI,CAAC;YAC7C,OAAO,IAAI,CAACD,SAAS,CAACD,KAAK,EAAEE,OAAO,GAAG,CAAC,CAAC;UAC3C;UACA,MAAM,IAAIJ,KAAK,CAACR,YAAY,CAACmC,WAAW,CAAC;QAC3C;UACE,IAAIjB,QAAQ,CAACW,MAAM,IAAI,GAAG,EAAE;YAC1B;YACA,IAAIjB,OAAO,GAAGd,WAAW,EAAE;cACzB,MAAM,IAAI,CAACkC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEtB,OAAO,CAAC,GAAG,IAAI,CAAC;cAC7C,OAAO,IAAI,CAACD,SAAS,CAACD,KAAK,EAAEE,OAAO,GAAG,CAAC,CAAC;YAC3C;YACA,MAAM,IAAIJ,KAAK,CAACR,YAAY,CAACoC,WAAW,CAAC;UAC3C;UACA,MAAM,IAAI5B,KAAK,CAACR,YAAY,CAACqC,eAAe,CAAC;MACjD;IACF,CAAC,CAAC,OAAOC,KAAK,EAAE;MACdX,YAAY,CAACZ,SAAS,CAAC;MAEvB,IAAIuB,KAAK,YAAY9B,KAAK,EAAE;QAC1B;QACA,IACE8B,KAAK,CAACC,OAAO,KAAKvC,YAAY,CAAC8B,YAAY,IAC3CQ,KAAK,CAACC,OAAO,KAAKvC,YAAY,CAAC+B,UAAU,EACzC;UACA,MAAMO,KAAK;QACb;;QAEA;QACA,IAAIA,KAAK,CAACE,IAAI,KAAK,YAAY,EAAE;UAC/B,IAAI5B,OAAO,GAAGd,WAAW,EAAE;YACzB,MAAM,IAAI,CAACkC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEtB,OAAO,CAAC,GAAG,IAAI,CAAC;YAC7C,OAAO,IAAI,CAACD,SAAS,CAACD,KAAK,EAAEE,OAAO,GAAG,CAAC,CAAC;UAC3C;UACA,MAAM,IAAIJ,KAAK,CAACR,YAAY,CAACyC,OAAO,CAAC;QACvC;MACF;;MAEA;MACA,IAAI7B,OAAO,GAAGd,WAAW,EAAE;QACzB,MAAM,IAAI,CAACkC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEtB,OAAO,CAAC,GAAG,IAAI,CAAC;QAC7C,OAAO,IAAI,CAACD,SAAS,CAACD,KAAK,EAAEE,OAAO,GAAG,CAAC,CAAC;MAC3C;MAEA,MAAM,IAAIJ,KAAK,CAACR,YAAY,CAACA,YAAY,CAAC;IAC5C;EACF;;EAEA;AACF;AACA;AACA;EACUyB,cAAcA,CAACf,KAAY,EAA2B;IAC5D,OAAO;MACLgC,UAAU,EAAEhC,KAAK,CAACiC,SAAS;MAC3BC,SAAS,EAAElC,KAAK,CAACkC,SAAS;MAC1BC,UAAU,EAAEnC,KAAK,CAACoC,SAAS;MAC3BC,MAAM,EAAErC,KAAK,CAACqC,MAAM,IAAIC,SAAS;MACjCC,QAAQ,EAAEvC,KAAK,CAACuC,QAAQ;MACxBC,UAAU,EAAExC,KAAK,CAACyC,SAAS;MAC3BC,WAAW,EAAE1C,KAAK,CAAC2C,UAAU;MAC7BC,MAAM,EAAE5C,KAAK,CAAC4C,MAAM;MACpBC,WAAW,EAAE7C,KAAK,CAAC8C;IACrB,CAAC;EACH;;EAEA;AACF;AACA;EACUxB,KAAKA,CAACyB,EAAU,EAAiB;IACvC,OAAO,IAAIC,OAAO,CAACC,OAAO,IAAI3C,UAAU,CAAC2C,OAAO,EAAEF,EAAE,CAAC,CAAC;EACxD;AACF;AAACxD,OAAA,CAAAC,aAAA,GAAAA,aAAA;AAEM,MAAM0D,aAAa,GAAA3D,OAAA,CAAA2D,aAAA,GAAG,IAAI1D,aAAa,CAAC,CAAC","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":[]}
|