kewa-react-native 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.
- package/LICENSE +20 -0
- package/README.md +592 -0
- package/lib/KewaProvider.d.ts +26 -0
- package/lib/KewaProvider.js +91 -0
- package/lib/core/EventManager.d.ts +13 -0
- package/lib/core/EventManager.js +129 -0
- package/lib/core/KewaAnalytics.d.ts +41 -0
- package/lib/core/KewaAnalytics.js +317 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +94 -0
- package/lib/types/config.d.ts +32 -0
- package/lib/types/config.js +2 -0
- package/lib/types/events.d.ts +104 -0
- package/lib/types/events.js +2 -0
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.js +19 -0
- package/lib/types/response.d.ts +15 -0
- package/lib/types/response.js +2 -0
- package/lib/utils/DeviceInfo.d.ts +4 -0
- package/lib/utils/DeviceInfo.js +32 -0
- package/lib/utils/NetworkManager.d.ts +17 -0
- package/lib/utils/NetworkManager.js +77 -0
- package/lib/utils/StorageManager.d.ts +16 -0
- package/lib/utils/StorageManager.js +120 -0
- package/lib/utils/constants.d.ts +26 -0
- package/lib/utils/constants.js +29 -0
- package/lib/utils/debug.d.ts +3 -0
- package/lib/utils/debug.js +17 -0
- package/package.json +59 -0
- package/src/KewaProvider.tsx +87 -0
- package/src/core/EventManager.ts +160 -0
- package/src/core/KewaAnalytics.ts +419 -0
- package/src/index.tsx +89 -0
- package/src/types/config.ts +33 -0
- package/src/types/events.ts +123 -0
- package/src/types/index.ts +3 -0
- package/src/types/response.ts +16 -0
- package/src/utils/DeviceInfo.ts +29 -0
- package/src/utils/NetworkManager.ts +85 -0
- package/src/utils/StorageManager.ts +121 -0
- package/src/utils/constants.ts +26 -0
- package/src/utils/debug.ts +15 -0
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kewa-react-native",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Kewa Mobile SDK for tracking events in mobile app",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react-native",
|
|
7
|
+
"analytics",
|
|
8
|
+
"tracking",
|
|
9
|
+
"user-behavior",
|
|
10
|
+
"mobile-analytics"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/TopChunks/kewa-react-native.git#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/TopChunks/kewa-react-native/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/TopChunks/kewa-react-native.git"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Topchunks Solutions Pvt Ltd",
|
|
22
|
+
"type": "commonjs",
|
|
23
|
+
"main": "lib/index.js",
|
|
24
|
+
"types": "lib/index.d.ts",
|
|
25
|
+
"directories": {
|
|
26
|
+
"lib": "lib"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib",
|
|
30
|
+
"src",
|
|
31
|
+
"package.json",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"build:watch": "tsc -w",
|
|
37
|
+
"test": "jest",
|
|
38
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
39
|
+
"prepare": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@react-native-async-storage/async-storage": "^1.19.0",
|
|
43
|
+
"@react-native-community/netinfo": "^9.4.0",
|
|
44
|
+
"react-native-device-info": "^14.0.4"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/react": "^18.2.0",
|
|
48
|
+
"@types/react-native": "^0.72.0",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
50
|
+
"@typescript-eslint/parser": "^5.0.0",
|
|
51
|
+
"eslint": "^8.0.0",
|
|
52
|
+
"jest": "^29.0.0",
|
|
53
|
+
"typescript": "^5.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"react": ">=16.8.0",
|
|
57
|
+
"react-native": ">=0.60.0"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { createContext, useContext, useEffect, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { KewaAnalytics } from './core/KewaAnalytics';
|
|
4
|
+
import { KewaConfig, ContactData, BaseEventData, UserLoginEvent, UserRegistrationEvent, ScreenViewEvent } from './types';
|
|
5
|
+
|
|
6
|
+
export interface KewaContextValue {
|
|
7
|
+
trackEvent: (eventName: string, eventData?: BaseEventData, contactData?: ContactData) => Promise<void>;
|
|
8
|
+
setUserProperties: (properties: ContactData) => Promise<void>;
|
|
9
|
+
trackLogin: (userData: Partial<UserLoginEvent>) => Promise<void>;
|
|
10
|
+
trackLogout: () => Promise<void>;
|
|
11
|
+
trackRegistration: (userData: Partial<UserRegistrationEvent>) => Promise<void>;
|
|
12
|
+
trackScreenView: (screenName: string, additionalData?: Partial<ScreenViewEvent>) => Promise<void>;
|
|
13
|
+
trackError: (error: Error, context?: Record<string, any>, isFatal?: boolean) => Promise<void>;
|
|
14
|
+
reset: () => Promise<void>;
|
|
15
|
+
getKtcId: () => Promise<string | null>;
|
|
16
|
+
getDeviceId: () => Promise<string | null>;
|
|
17
|
+
getUserProperties: () => Promise<ContactData>;
|
|
18
|
+
isSDKInitialized: () => boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const KewaContext = createContext<KewaContextValue | null>(null);
|
|
22
|
+
|
|
23
|
+
interface KewaProviderProps {
|
|
24
|
+
config: KewaConfig;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
kewa?: KewaAnalytics;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const defaultKewaInstance = new KewaAnalytics();
|
|
30
|
+
|
|
31
|
+
function createContextValue(kewa: KewaAnalytics): KewaContextValue {
|
|
32
|
+
return {
|
|
33
|
+
trackEvent: kewa.trackEvent.bind(kewa),
|
|
34
|
+
setUserProperties: kewa.setUserProperties.bind(kewa),
|
|
35
|
+
trackLogin: kewa.trackLogin.bind(kewa),
|
|
36
|
+
trackLogout: kewa.trackLogout.bind(kewa),
|
|
37
|
+
trackRegistration: kewa.trackRegistration.bind(kewa),
|
|
38
|
+
trackScreenView: kewa.trackScreenView.bind(kewa),
|
|
39
|
+
trackError: kewa.trackError.bind(kewa),
|
|
40
|
+
reset: kewa.reset.bind(kewa),
|
|
41
|
+
getKtcId: kewa.getKtcId.bind(kewa),
|
|
42
|
+
getDeviceId: kewa.getDeviceId.bind(kewa),
|
|
43
|
+
getUserProperties: kewa.getUserProperties.bind(kewa),
|
|
44
|
+
isSDKInitialized: kewa.isSDKInitialized.bind(kewa),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function KewaProvider({ config, children, kewa }: KewaProviderProps) {
|
|
49
|
+
const instance = kewa ?? defaultKewaInstance;
|
|
50
|
+
const value = createContextValue(instance);
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
instance.init(config);
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
instance.cleanup();
|
|
57
|
+
};
|
|
58
|
+
}, [
|
|
59
|
+
instance,
|
|
60
|
+
config.appUrl,
|
|
61
|
+
config.apiKey,
|
|
62
|
+
config.projectId,
|
|
63
|
+
config.disableTracking,
|
|
64
|
+
config.disableEventTracking,
|
|
65
|
+
config.disableAppStateTracking,
|
|
66
|
+
config.disableScreenViewTracking,
|
|
67
|
+
config.enableDebugLogging,
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<KewaContext.Provider value={value}>
|
|
72
|
+
{children}
|
|
73
|
+
</KewaContext.Provider>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function useKewa(): KewaContextValue {
|
|
78
|
+
const context = useContext(KewaContext);
|
|
79
|
+
if (!context) {
|
|
80
|
+
throw new Error('useKewa must be used within a KewaProvider');
|
|
81
|
+
}
|
|
82
|
+
return context;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getDefaultKewaInstance(): KewaAnalytics {
|
|
86
|
+
return defaultKewaInstance;
|
|
87
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { KewaEvent, KewaConfig, BaseEventData, DeviceInfo, ContactData } from '../types';
|
|
2
|
+
import { StorageManager } from '../utils/StorageManager';
|
|
3
|
+
import { NetworkManager } from '../utils/NetworkManager';
|
|
4
|
+
import { KEWA_CONSTANTS } from '../utils/constants';
|
|
5
|
+
import { kewaDebug } from '../utils/debug';
|
|
6
|
+
|
|
7
|
+
export class EventManager {
|
|
8
|
+
private networkManager: NetworkManager;
|
|
9
|
+
private config: KewaConfig;
|
|
10
|
+
private isProcessingQueue: boolean = false;
|
|
11
|
+
|
|
12
|
+
constructor(networkManager: NetworkManager, config: KewaConfig) {
|
|
13
|
+
this.networkManager = networkManager;
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async processEvent(
|
|
18
|
+
eventName: string,
|
|
19
|
+
eventData: BaseEventData,
|
|
20
|
+
contactData: ContactData,
|
|
21
|
+
deviceId: string | null,
|
|
22
|
+
deviceInfo: DeviceInfo
|
|
23
|
+
): Promise<void> {
|
|
24
|
+
const event: KewaEvent = {
|
|
25
|
+
eventName,
|
|
26
|
+
eventData: {
|
|
27
|
+
...eventData,
|
|
28
|
+
},
|
|
29
|
+
contactData : contactData,
|
|
30
|
+
deviceId,
|
|
31
|
+
deviceInfo,
|
|
32
|
+
timestamp: eventData.timestamp || new Date().toISOString(),
|
|
33
|
+
metadata: {
|
|
34
|
+
eventId: this.generateEventId(),
|
|
35
|
+
attemptCount: 1,
|
|
36
|
+
queuedAt: new Date().toISOString(),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (this.networkManager.getNetworkStatus()) {
|
|
41
|
+
try {
|
|
42
|
+
await this.sendEvent(event);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Failed to send event, queuing for retry:', error);
|
|
45
|
+
await StorageManager.addQueuedEvent(event);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
await StorageManager.addQueuedEvent(event);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async sendEvent(event: KewaEvent): Promise<void> {
|
|
53
|
+
try {
|
|
54
|
+
|
|
55
|
+
kewaDebug('Kewa Analytics SDK: Sending event:', event.eventName, {
|
|
56
|
+
eventData: event.eventData,
|
|
57
|
+
contactData: event.contactData,
|
|
58
|
+
deviceId: event.deviceId,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const response = await this.networkManager.sendEvent(event);
|
|
62
|
+
|
|
63
|
+
const ktcId = await StorageManager.getKtcId();
|
|
64
|
+
const deviceId = await StorageManager.getDeviceId();
|
|
65
|
+
|
|
66
|
+
kewaDebug('Kewa Analytics SDK: Event response:', event.eventName, response);
|
|
67
|
+
|
|
68
|
+
// Logout clears identity after send — do not persist ids from its response
|
|
69
|
+
if (event.eventName !== KEWA_CONSTANTS.EVENTS.USER_LOGOUT) {
|
|
70
|
+
if (response.id && response.id !== ktcId) {
|
|
71
|
+
await StorageManager.setKtcId(response.id);
|
|
72
|
+
|
|
73
|
+
kewaDebug('Kewa Analytics SDK: Updated ktc_id:', response.id);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (response.device_id && response.device_id !== deviceId) {
|
|
77
|
+
await StorageManager.setDeviceId(response.device_id);
|
|
78
|
+
kewaDebug('Kewa Analytics SDK: Updated device_id:', response.device_id);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.warn('Kewa Analytics SDK: Error sending event to kewa, queuing for retry:', error);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async processAppStateEvent(
|
|
89
|
+
eventName: string,
|
|
90
|
+
eventData: BaseEventData,
|
|
91
|
+
contactData: ContactData,
|
|
92
|
+
deviceId: string | null,
|
|
93
|
+
deviceInfo: DeviceInfo,
|
|
94
|
+
): Promise<void> {
|
|
95
|
+
const event: KewaEvent = {
|
|
96
|
+
eventName,
|
|
97
|
+
eventData: { ...eventData },
|
|
98
|
+
contactData,
|
|
99
|
+
deviceId,
|
|
100
|
+
deviceInfo,
|
|
101
|
+
timestamp: eventData.timestamp || new Date().toISOString(),
|
|
102
|
+
metadata: {
|
|
103
|
+
eventId: this.generateEventId(),
|
|
104
|
+
attemptCount: 1,
|
|
105
|
+
queuedAt: new Date().toISOString(),
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
if (this.networkManager.getNetworkStatus()) {
|
|
110
|
+
try {
|
|
111
|
+
await this.sendEvent(event);
|
|
112
|
+
return;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.warn(`Failed to send ${eventName}, queuing for retry:`, error);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await StorageManager.addQueuedEvent(event);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async processQueuedEvents(): Promise<void> {
|
|
122
|
+
if (this.isProcessingQueue || !this.networkManager.getNetworkStatus()) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.isProcessingQueue = true;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const queuedEvents = await StorageManager.getQueuedEvents();
|
|
130
|
+
if (queuedEvents.length === 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
kewaDebug(`Kewa Analytics SDK: Processing ${queuedEvents.length} queued events`);
|
|
135
|
+
|
|
136
|
+
//TODO: Consider batch processing if supported by backend
|
|
137
|
+
|
|
138
|
+
// Process events one by one
|
|
139
|
+
for (const event of queuedEvents) {
|
|
140
|
+
try {
|
|
141
|
+
await this.networkManager.sendEvent(event);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('Kewa Analytics SDK: Failed to send event:', error);
|
|
144
|
+
// Keep the failed event in the queue for next retry
|
|
145
|
+
await StorageManager.addQueuedEvent(event);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Clear all events after successful processing
|
|
150
|
+
await StorageManager.clearQueuedEvents();
|
|
151
|
+
|
|
152
|
+
} finally {
|
|
153
|
+
this.isProcessingQueue = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private generateEventId(): string {
|
|
158
|
+
return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
159
|
+
}
|
|
160
|
+
}
|