respectlytics-react-native 2.0.1 → 2.2.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/LICENSE +17 -20
- package/README.md +77 -29
- package/lib/commonjs/EventQueue.js +1 -1
- package/lib/commonjs/NetworkClient.js +13 -14
- package/lib/commonjs/NetworkClient.js.map +1 -1
- package/lib/commonjs/Respectlytics.js +28 -85
- package/lib/commonjs/Respectlytics.js.map +1 -1
- package/lib/commonjs/SessionManager.js +4 -4
- package/lib/commonjs/Storage.js +1 -1
- package/lib/commonjs/index.js +3 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.js +12 -11
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/EventQueue.js +1 -1
- package/lib/module/NetworkClient.js +13 -14
- package/lib/module/NetworkClient.js.map +1 -1
- package/lib/module/Respectlytics.js +29 -86
- package/lib/module/Respectlytics.js.map +1 -1
- package/lib/module/SessionManager.js +4 -4
- package/lib/module/Storage.js +1 -1
- package/lib/module/index.js +3 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +12 -11
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/EventQueue.d.ts +1 -1
- package/lib/typescript/NetworkClient.d.ts +6 -5
- package/lib/typescript/NetworkClient.d.ts.map +1 -1
- package/lib/typescript/Respectlytics.d.ts +15 -12
- package/lib/typescript/Respectlytics.d.ts.map +1 -1
- package/lib/typescript/SessionManager.d.ts +4 -4
- package/lib/typescript/Storage.d.ts +1 -1
- package/lib/typescript/index.d.ts +2 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +10 -14
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +5 -2
- package/src/EventQueue.ts +4 -4
- package/src/NetworkClient.ts +12 -13
- package/src/Respectlytics.ts +31 -92
- package/src/SessionManager.ts +6 -6
- package/src/Storage.ts +1 -1
- package/src/index.ts +5 -6
- package/src/types.ts +12 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "respectlytics-react-native",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Official Respectlytics SDK for React Native. Privacy-first analytics with automatic session management, offline event queuing, and zero device identifier collection.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"url": "git+https://github.com/respectlytics/respectlytics-react-native.git"
|
|
39
39
|
},
|
|
40
40
|
"author": "Respectlytics <respectlytics@loheden.com>",
|
|
41
|
-
"license": "
|
|
41
|
+
"license": "MIT",
|
|
42
42
|
"bugs": {
|
|
43
43
|
"url": "https://github.com/respectlytics/respectlytics-react-native/issues"
|
|
44
44
|
},
|
|
@@ -47,11 +47,14 @@
|
|
|
47
47
|
"registry": "https://registry.npmjs.org/"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
+
"@babel/preset-env": "^7.28.5",
|
|
51
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
50
52
|
"@react-native-async-storage/async-storage": "^2.0.0",
|
|
51
53
|
"@react-native-community/netinfo": "^11.3.0",
|
|
52
54
|
"@types/jest": "^29.5.12",
|
|
53
55
|
"@types/react": "^18.2.0",
|
|
54
56
|
"@types/react-native": "^0.72.0",
|
|
57
|
+
"babel-jest": "^30.2.0",
|
|
55
58
|
"eslint": "^8.56.0",
|
|
56
59
|
"jest": "^29.7.0",
|
|
57
60
|
"react": "^18.2.0",
|
package/src/EventQueue.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* EventQueue.ts
|
|
3
3
|
* Respectlytics React Native SDK
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
5
|
* Manages event batching, persistence, and automatic flushing.
|
|
6
6
|
* Events are NEVER lost - they are persisted immediately and retried on failure.
|
|
7
|
-
* Copyright (c) 2025 Respectlytics.
|
|
7
|
+
* Copyright (c) 2025 Respectlytics. Licensed under MIT.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { AppState, AppStateStatus } from 'react-native';
|
|
@@ -65,10 +65,10 @@ export class EventQueue {
|
|
|
65
65
|
*/
|
|
66
66
|
async add(event: Event): Promise<void> {
|
|
67
67
|
this.events.push(event);
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
// IMMEDIATELY persist before any async operations
|
|
70
70
|
await this.persistQueue();
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
// Check if we should flush
|
|
73
73
|
if (this.events.length >= MAX_QUEUE_SIZE) {
|
|
74
74
|
this.flush();
|
package/src/NetworkClient.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NetworkClient.ts
|
|
3
3
|
* Respectlytics React Native SDK
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
5
|
* Handles HTTP communication with the Respectlytics API.
|
|
6
|
-
* Copyright (c) 2025 Respectlytics.
|
|
6
|
+
* Copyright (c) 2025 Respectlytics. Licensed under MIT.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { Event } from './types';
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const DEFAULT_API_ENDPOINT = 'https://respectlytics.com/api/v1/events/';
|
|
12
12
|
const MAX_RETRIES = 3;
|
|
13
13
|
const TIMEOUT_MS = 30000;
|
|
14
14
|
|
|
@@ -25,12 +25,16 @@ export enum NetworkError {
|
|
|
25
25
|
|
|
26
26
|
export class NetworkClient {
|
|
27
27
|
private apiKey: string | null = null;
|
|
28
|
+
private apiEndpoint: string = DEFAULT_API_ENDPOINT;
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
* Configure the network client with an API key
|
|
31
|
+
* Configure the network client with an API key and optional custom endpoint
|
|
31
32
|
*/
|
|
32
|
-
configure(apiKey: string): void {
|
|
33
|
+
configure(apiKey: string, apiEndpoint?: string): void {
|
|
33
34
|
this.apiKey = apiKey;
|
|
35
|
+
if (apiEndpoint) {
|
|
36
|
+
this.apiEndpoint = apiEndpoint;
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/**
|
|
@@ -65,7 +69,7 @@ export class NetworkClient {
|
|
|
65
69
|
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
66
70
|
|
|
67
71
|
try {
|
|
68
|
-
const response = await fetch(
|
|
72
|
+
const response = await fetch(this.apiEndpoint, {
|
|
69
73
|
method: 'POST',
|
|
70
74
|
headers: {
|
|
71
75
|
'Content-Type': 'application/json',
|
|
@@ -137,20 +141,15 @@ export class NetworkClient {
|
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
/**
|
|
140
|
-
* Convert Event object to API payload format
|
|
141
|
-
*
|
|
144
|
+
* Convert Event object to API payload format.
|
|
145
|
+
* The SDK sends 4 fields; the API stores 5 (adding country derived from IP).
|
|
142
146
|
*/
|
|
143
147
|
private eventToPayload(event: Event): Record<string, unknown> {
|
|
144
148
|
return {
|
|
145
149
|
event_name: event.eventName,
|
|
146
150
|
timestamp: event.timestamp,
|
|
147
151
|
session_id: event.sessionId,
|
|
148
|
-
screen: event.screen || undefined,
|
|
149
152
|
platform: event.platform,
|
|
150
|
-
os_version: event.osVersion,
|
|
151
|
-
app_version: event.appVersion,
|
|
152
|
-
locale: event.locale,
|
|
153
|
-
device_type: event.deviceType,
|
|
154
153
|
};
|
|
155
154
|
}
|
|
156
155
|
|
package/src/Respectlytics.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Respectlytics.ts
|
|
3
3
|
* Respectlytics React Native SDK
|
|
4
|
-
*
|
|
4
|
+
*
|
|
5
5
|
* Main entry point for the SDK.
|
|
6
|
-
* Copyright (c) 2025 Respectlytics.
|
|
6
|
+
* Copyright (c) 2025 Respectlytics. Licensed under MIT.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { Platform
|
|
9
|
+
import { Platform } from 'react-native';
|
|
10
10
|
import { Event } from './types';
|
|
11
11
|
import { SessionManager } from './SessionManager';
|
|
12
12
|
import { NetworkClient } from './NetworkClient';
|
|
@@ -14,21 +14,23 @@ import { EventQueue } from './EventQueue';
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Main entry point for the Respectlytics SDK.
|
|
17
|
-
*
|
|
18
|
-
* v2.
|
|
17
|
+
*
|
|
18
|
+
* v2.1.0 uses session-based analytics only:
|
|
19
19
|
* - Session IDs are generated automatically in RAM
|
|
20
20
|
* - Sessions rotate every 2 hours
|
|
21
21
|
* - New session on every app restart
|
|
22
|
-
* -
|
|
23
|
-
*
|
|
22
|
+
* - Only 4 fields sent by SDK; 5 stored (country derived server-side)
|
|
23
|
+
*
|
|
24
24
|
* Usage:
|
|
25
25
|
* ```typescript
|
|
26
26
|
* // 1. Configure at app launch
|
|
27
27
|
* Respectlytics.configure('your-api-key');
|
|
28
|
-
*
|
|
28
|
+
*
|
|
29
|
+
* // For self-hosted instances:
|
|
30
|
+
* Respectlytics.configure('your-api-key', { apiEndpoint: 'https://your-server.com/api/v1/events/' });
|
|
31
|
+
*
|
|
29
32
|
* // 2. Track events
|
|
30
33
|
* Respectlytics.track('purchase');
|
|
31
|
-
* Respectlytics.track('view_product', 'ProductScreen');
|
|
32
34
|
* ```
|
|
33
35
|
*/
|
|
34
36
|
class RespectlyticsSDK {
|
|
@@ -36,42 +38,44 @@ class RespectlyticsSDK {
|
|
|
36
38
|
private networkClient: NetworkClient;
|
|
37
39
|
private eventQueue: EventQueue;
|
|
38
40
|
private sessionManager: SessionManager;
|
|
41
|
+
private platform: string;
|
|
39
42
|
|
|
40
43
|
constructor() {
|
|
41
44
|
this.networkClient = new NetworkClient();
|
|
42
45
|
this.eventQueue = new EventQueue(this.networkClient);
|
|
43
46
|
this.sessionManager = new SessionManager();
|
|
47
|
+
this.platform = Platform.OS === 'ios' ? 'iOS' : 'Android';
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/**
|
|
47
51
|
* Initialize the SDK with your API key.
|
|
48
52
|
* Call once at app startup.
|
|
49
|
-
*
|
|
53
|
+
*
|
|
50
54
|
* @param apiKey Your Respectlytics API key from the dashboard
|
|
55
|
+
* @param options Optional configuration (e.g., apiEndpoint for self-hosted instances)
|
|
51
56
|
*/
|
|
52
|
-
configure(apiKey: string): void {
|
|
57
|
+
configure(apiKey: string, options?: { apiEndpoint?: string }): void {
|
|
53
58
|
if (!apiKey || apiKey.trim() === '') {
|
|
54
59
|
console.log('[Respectlytics] ⚠️ API key cannot be empty');
|
|
55
60
|
return;
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
this.networkClient.configure(apiKey);
|
|
63
|
+
this.networkClient.configure(apiKey, options?.apiEndpoint);
|
|
59
64
|
this.eventQueue.start();
|
|
60
65
|
this.isConfigured = true;
|
|
61
66
|
|
|
62
|
-
console.log('[Respectlytics] ✓ SDK configured');
|
|
67
|
+
console.log('[Respectlytics] ✓ SDK configured (v2.2.0)');
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
/**
|
|
66
|
-
* Track an event
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
+
* Track an event.
|
|
72
|
+
*
|
|
73
|
+
* Custom properties are NOT supported - this is by design for privacy.
|
|
74
|
+
* The API stores 5 fields (these 4 plus country derived server-side).
|
|
75
|
+
*
|
|
71
76
|
* @param eventName Name of the event (e.g., "purchase", "button_clicked")
|
|
72
|
-
* @param screen Optional screen name where the event occurred
|
|
73
77
|
*/
|
|
74
|
-
track(eventName: string
|
|
78
|
+
track(eventName: string): void {
|
|
75
79
|
if (!this.isConfigured) {
|
|
76
80
|
console.log('[Respectlytics] ⚠️ SDK not configured. Call configure(apiKey) first.');
|
|
77
81
|
return;
|
|
@@ -87,7 +91,13 @@ class RespectlyticsSDK {
|
|
|
87
91
|
return;
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
const event =
|
|
94
|
+
const event: Event = {
|
|
95
|
+
eventName,
|
|
96
|
+
timestamp: new Date().toISOString(),
|
|
97
|
+
sessionId: this.sessionManager.getSessionId(),
|
|
98
|
+
platform: this.platform,
|
|
99
|
+
};
|
|
100
|
+
|
|
91
101
|
this.eventQueue.add(event);
|
|
92
102
|
}
|
|
93
103
|
|
|
@@ -98,77 +108,6 @@ class RespectlyticsSDK {
|
|
|
98
108
|
async flush(): Promise<void> {
|
|
99
109
|
await this.eventQueue.flush();
|
|
100
110
|
}
|
|
101
|
-
|
|
102
|
-
// MARK: - Private Helpers
|
|
103
|
-
|
|
104
|
-
private createEvent(eventName: string, screen?: string): Event {
|
|
105
|
-
const metadata = this.collectMetadata();
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
eventName,
|
|
109
|
-
timestamp: new Date().toISOString(),
|
|
110
|
-
sessionId: this.sessionManager.getSessionId(),
|
|
111
|
-
screen: screen || null,
|
|
112
|
-
...metadata,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private collectMetadata(): {
|
|
117
|
-
platform: string;
|
|
118
|
-
osVersion: string;
|
|
119
|
-
appVersion: string;
|
|
120
|
-
locale: string;
|
|
121
|
-
deviceType: string;
|
|
122
|
-
} {
|
|
123
|
-
// Determine platform
|
|
124
|
-
const platform = Platform.OS === 'ios' ? 'iOS' : 'Android';
|
|
125
|
-
|
|
126
|
-
// Get OS version
|
|
127
|
-
const osVersion = String(Platform.Version);
|
|
128
|
-
|
|
129
|
-
// Get app version - try to get from native modules
|
|
130
|
-
let appVersion = 'unknown';
|
|
131
|
-
try {
|
|
132
|
-
// React Native provides app info through different native modules
|
|
133
|
-
const { PlatformConstants } = NativeModules;
|
|
134
|
-
if (PlatformConstants?.reactNativeVersion) {
|
|
135
|
-
// This is React Native version, not app version
|
|
136
|
-
// App version should come from the host app
|
|
137
|
-
}
|
|
138
|
-
// For now, use 'unknown' as we can't reliably get app version without additional dependencies
|
|
139
|
-
// In a real app, the developer would configure this
|
|
140
|
-
} catch {
|
|
141
|
-
appVersion = 'unknown';
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Get locale
|
|
145
|
-
let locale = 'en_US';
|
|
146
|
-
try {
|
|
147
|
-
// React Native doesn't expose locale directly, but we can get it from platform
|
|
148
|
-
if (Platform.OS === 'ios') {
|
|
149
|
-
locale = NativeModules.SettingsManager?.settings?.AppleLocale ||
|
|
150
|
-
NativeModules.SettingsManager?.settings?.AppleLanguages?.[0] ||
|
|
151
|
-
'en_US';
|
|
152
|
-
} else {
|
|
153
|
-
locale = NativeModules.I18nManager?.localeIdentifier || 'en_US';
|
|
154
|
-
}
|
|
155
|
-
} catch {
|
|
156
|
-
locale = 'en_US';
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Determine device type based on screen size
|
|
160
|
-
const { width, height } = Dimensions.get('window');
|
|
161
|
-
const minDimension = Math.min(width, height);
|
|
162
|
-
const deviceType = minDimension >= 600 ? 'tablet' : 'phone';
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
platform,
|
|
166
|
-
osVersion,
|
|
167
|
-
appVersion,
|
|
168
|
-
locale,
|
|
169
|
-
deviceType,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
111
|
}
|
|
173
112
|
|
|
174
113
|
// Export singleton instance
|
package/src/SessionManager.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Respectlytics React Native SDK
|
|
4
4
|
*
|
|
5
5
|
* Manages session ID generation and rotation.
|
|
6
|
-
* Sessions are stored in RAM only (never persisted
|
|
6
|
+
* Sessions are stored in RAM only (never persisted to disk).
|
|
7
7
|
* Sessions automatically rotate every 2 hours.
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2025 Respectlytics.
|
|
9
|
+
* Copyright (c) 2025 Respectlytics. Licensed under MIT.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -22,15 +22,15 @@ function generateUUID(): string {
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Manages session ID generation and rotation.
|
|
25
|
-
*
|
|
25
|
+
*
|
|
26
26
|
* Session IDs are:
|
|
27
27
|
* - Generated immediately when the SDK initializes
|
|
28
28
|
* - Stored in RAM only (never persisted to AsyncStorage)
|
|
29
29
|
* - Rotated automatically every 2 hours
|
|
30
30
|
* - Regenerated on every app restart (new instance = new session)
|
|
31
|
-
*
|
|
32
|
-
* This RAM-only approach
|
|
33
|
-
* -
|
|
31
|
+
*
|
|
32
|
+
* This RAM-only approach means session data never touches device storage:
|
|
33
|
+
* - Sessions exist only in memory and are lost on app restart
|
|
34
34
|
* - Each app launch creates a fresh, unlinked session
|
|
35
35
|
*/
|
|
36
36
|
export class SessionManager {
|
package/src/Storage.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Respectlytics React Native SDK
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Official SDK for privacy-first, session-based analytics.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* v2.0.0 Features:
|
|
7
7
|
* - Session-based analytics (no persistent user tracking)
|
|
8
|
-
* - RAM-only session storage (
|
|
8
|
+
* - RAM-only session storage (never persisted to disk)
|
|
9
9
|
* - Automatic 2-hour session rotation
|
|
10
10
|
* - New session on every app restart
|
|
11
|
-
*
|
|
12
|
-
* Copyright (c) 2025 Respectlytics.
|
|
11
|
+
*
|
|
12
|
+
* Copyright (c) 2025 Respectlytics. Licensed under MIT.
|
|
13
13
|
*/
|
|
14
|
-
|
|
15
14
|
import Respectlytics from './Respectlytics';
|
|
16
15
|
|
|
17
16
|
// Default export - the main SDK instance
|
package/src/types.ts
CHANGED
|
@@ -2,37 +2,33 @@
|
|
|
2
2
|
* types.ts
|
|
3
3
|
* Respectlytics React Native SDK
|
|
4
4
|
*
|
|
5
|
-
* Copyright (c) 2025 Respectlytics.
|
|
6
|
-
* This SDK is provided under a proprietary license.
|
|
7
|
-
* See LICENSE file for details.
|
|
5
|
+
* Copyright (c) 2025 Respectlytics. Licensed under MIT.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
9
|
* Represents an analytics event - flat structure matching API payload
|
|
12
10
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
11
|
+
* The SDK sends these 4 fields. The API stores 5 total
|
|
12
|
+
* (adding country, derived server-side from IP which is immediately discarded):
|
|
13
|
+
* - event_name (required)
|
|
14
|
+
* - timestamp
|
|
15
|
+
* - session_id
|
|
16
|
+
* - platform
|
|
17
|
+
*
|
|
18
|
+
* Country is derived server-side from IP (which is immediately discarded).
|
|
18
19
|
*/
|
|
19
20
|
export interface Event {
|
|
20
21
|
eventName: string;
|
|
21
22
|
timestamp: string;
|
|
22
23
|
sessionId: string;
|
|
23
|
-
screen: string | null;
|
|
24
24
|
platform: string;
|
|
25
|
-
osVersion: string;
|
|
26
|
-
appVersion: string;
|
|
27
|
-
locale: string;
|
|
28
|
-
deviceType: string;
|
|
29
25
|
}
|
|
30
26
|
|
|
31
27
|
/**
|
|
32
28
|
* Storage keys used by the SDK
|
|
33
|
-
*
|
|
34
|
-
* Note:
|
|
35
|
-
* Session IDs are RAM-only for
|
|
29
|
+
*
|
|
30
|
+
* Note: Only the event queue is persisted.
|
|
31
|
+
* Session IDs are RAM-only for privacy.
|
|
36
32
|
*/
|
|
37
33
|
export const STORAGE_KEYS = {
|
|
38
34
|
EVENT_QUEUE: 'com.respectlytics.eventQueue',
|