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
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.KewaProvider = KewaProvider;
|
|
37
|
+
exports.useKewa = useKewa;
|
|
38
|
+
exports.getDefaultKewaInstance = getDefaultKewaInstance;
|
|
39
|
+
const react_1 = __importStar(require("react"));
|
|
40
|
+
const KewaAnalytics_1 = require("./core/KewaAnalytics");
|
|
41
|
+
const KewaContext = (0, react_1.createContext)(null);
|
|
42
|
+
const defaultKewaInstance = new KewaAnalytics_1.KewaAnalytics();
|
|
43
|
+
function createContextValue(kewa) {
|
|
44
|
+
return {
|
|
45
|
+
trackEvent: kewa.trackEvent.bind(kewa),
|
|
46
|
+
setUserProperties: kewa.setUserProperties.bind(kewa),
|
|
47
|
+
trackLogin: kewa.trackLogin.bind(kewa),
|
|
48
|
+
trackLogout: kewa.trackLogout.bind(kewa),
|
|
49
|
+
trackRegistration: kewa.trackRegistration.bind(kewa),
|
|
50
|
+
trackScreenView: kewa.trackScreenView.bind(kewa),
|
|
51
|
+
trackError: kewa.trackError.bind(kewa),
|
|
52
|
+
reset: kewa.reset.bind(kewa),
|
|
53
|
+
getKtcId: kewa.getKtcId.bind(kewa),
|
|
54
|
+
getDeviceId: kewa.getDeviceId.bind(kewa),
|
|
55
|
+
getUserProperties: kewa.getUserProperties.bind(kewa),
|
|
56
|
+
isSDKInitialized: kewa.isSDKInitialized.bind(kewa),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function KewaProvider({ config, children, kewa }) {
|
|
60
|
+
const instance = kewa !== null && kewa !== void 0 ? kewa : defaultKewaInstance;
|
|
61
|
+
const value = createContextValue(instance);
|
|
62
|
+
(0, react_1.useEffect)(() => {
|
|
63
|
+
instance.init(config);
|
|
64
|
+
return () => {
|
|
65
|
+
instance.cleanup();
|
|
66
|
+
};
|
|
67
|
+
}, [
|
|
68
|
+
instance,
|
|
69
|
+
config.appUrl,
|
|
70
|
+
config.apiKey,
|
|
71
|
+
config.projectId,
|
|
72
|
+
config.disableTracking,
|
|
73
|
+
config.disableEventTracking,
|
|
74
|
+
config.disableAppStateTracking,
|
|
75
|
+
config.disableScreenViewTracking,
|
|
76
|
+
config.enableDebugLogging,
|
|
77
|
+
]);
|
|
78
|
+
return (<KewaContext.Provider value={value}>
|
|
79
|
+
{children}
|
|
80
|
+
</KewaContext.Provider>);
|
|
81
|
+
}
|
|
82
|
+
function useKewa() {
|
|
83
|
+
const context = (0, react_1.useContext)(KewaContext);
|
|
84
|
+
if (!context) {
|
|
85
|
+
throw new Error('useKewa must be used within a KewaProvider');
|
|
86
|
+
}
|
|
87
|
+
return context;
|
|
88
|
+
}
|
|
89
|
+
function getDefaultKewaInstance() {
|
|
90
|
+
return defaultKewaInstance;
|
|
91
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { KewaConfig, BaseEventData, DeviceInfo, ContactData } from '../types';
|
|
2
|
+
import { NetworkManager } from '../utils/NetworkManager';
|
|
3
|
+
export declare class EventManager {
|
|
4
|
+
private networkManager;
|
|
5
|
+
private config;
|
|
6
|
+
private isProcessingQueue;
|
|
7
|
+
constructor(networkManager: NetworkManager, config: KewaConfig);
|
|
8
|
+
processEvent(eventName: string, eventData: BaseEventData, contactData: ContactData, deviceId: string | null, deviceInfo: DeviceInfo): Promise<void>;
|
|
9
|
+
private sendEvent;
|
|
10
|
+
processAppStateEvent(eventName: string, eventData: BaseEventData, contactData: ContactData, deviceId: string | null, deviceInfo: DeviceInfo): Promise<void>;
|
|
11
|
+
processQueuedEvents(): Promise<void>;
|
|
12
|
+
private generateEventId;
|
|
13
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventManager = void 0;
|
|
4
|
+
const StorageManager_1 = require("../utils/StorageManager");
|
|
5
|
+
const constants_1 = require("../utils/constants");
|
|
6
|
+
const debug_1 = require("../utils/debug");
|
|
7
|
+
class EventManager {
|
|
8
|
+
constructor(networkManager, config) {
|
|
9
|
+
this.isProcessingQueue = false;
|
|
10
|
+
this.networkManager = networkManager;
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
async processEvent(eventName, eventData, contactData, deviceId, deviceInfo) {
|
|
14
|
+
const event = {
|
|
15
|
+
eventName,
|
|
16
|
+
eventData: {
|
|
17
|
+
...eventData,
|
|
18
|
+
},
|
|
19
|
+
contactData: contactData,
|
|
20
|
+
deviceId,
|
|
21
|
+
deviceInfo,
|
|
22
|
+
timestamp: eventData.timestamp || new Date().toISOString(),
|
|
23
|
+
metadata: {
|
|
24
|
+
eventId: this.generateEventId(),
|
|
25
|
+
attemptCount: 1,
|
|
26
|
+
queuedAt: new Date().toISOString(),
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
if (this.networkManager.getNetworkStatus()) {
|
|
30
|
+
try {
|
|
31
|
+
await this.sendEvent(event);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error('Failed to send event, queuing for retry:', error);
|
|
35
|
+
await StorageManager_1.StorageManager.addQueuedEvent(event);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
await StorageManager_1.StorageManager.addQueuedEvent(event);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async sendEvent(event) {
|
|
43
|
+
try {
|
|
44
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Sending event:', event.eventName, {
|
|
45
|
+
eventData: event.eventData,
|
|
46
|
+
contactData: event.contactData,
|
|
47
|
+
deviceId: event.deviceId,
|
|
48
|
+
});
|
|
49
|
+
const response = await this.networkManager.sendEvent(event);
|
|
50
|
+
const ktcId = await StorageManager_1.StorageManager.getKtcId();
|
|
51
|
+
const deviceId = await StorageManager_1.StorageManager.getDeviceId();
|
|
52
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Event response:', event.eventName, response);
|
|
53
|
+
// Logout clears identity after send — do not persist ids from its response
|
|
54
|
+
if (event.eventName !== constants_1.KEWA_CONSTANTS.EVENTS.USER_LOGOUT) {
|
|
55
|
+
if (response.id && response.id !== ktcId) {
|
|
56
|
+
await StorageManager_1.StorageManager.setKtcId(response.id);
|
|
57
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Updated ktc_id:', response.id);
|
|
58
|
+
}
|
|
59
|
+
if (response.device_id && response.device_id !== deviceId) {
|
|
60
|
+
await StorageManager_1.StorageManager.setDeviceId(response.device_id);
|
|
61
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Updated device_id:', response.device_id);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.warn('Kewa Analytics SDK: Error sending event to kewa, queuing for retry:', error);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async processAppStateEvent(eventName, eventData, contactData, deviceId, deviceInfo) {
|
|
71
|
+
const event = {
|
|
72
|
+
eventName,
|
|
73
|
+
eventData: { ...eventData },
|
|
74
|
+
contactData,
|
|
75
|
+
deviceId,
|
|
76
|
+
deviceInfo,
|
|
77
|
+
timestamp: eventData.timestamp || new Date().toISOString(),
|
|
78
|
+
metadata: {
|
|
79
|
+
eventId: this.generateEventId(),
|
|
80
|
+
attemptCount: 1,
|
|
81
|
+
queuedAt: new Date().toISOString(),
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
if (this.networkManager.getNetworkStatus()) {
|
|
85
|
+
try {
|
|
86
|
+
await this.sendEvent(event);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.warn(`Failed to send ${eventName}, queuing for retry:`, error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
await StorageManager_1.StorageManager.addQueuedEvent(event);
|
|
94
|
+
}
|
|
95
|
+
async processQueuedEvents() {
|
|
96
|
+
if (this.isProcessingQueue || !this.networkManager.getNetworkStatus()) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.isProcessingQueue = true;
|
|
100
|
+
try {
|
|
101
|
+
const queuedEvents = await StorageManager_1.StorageManager.getQueuedEvents();
|
|
102
|
+
if (queuedEvents.length === 0) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
(0, debug_1.kewaDebug)(`Kewa Analytics SDK: Processing ${queuedEvents.length} queued events`);
|
|
106
|
+
//TODO: Consider batch processing if supported by backend
|
|
107
|
+
// Process events one by one
|
|
108
|
+
for (const event of queuedEvents) {
|
|
109
|
+
try {
|
|
110
|
+
await this.networkManager.sendEvent(event);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error('Kewa Analytics SDK: Failed to send event:', error);
|
|
114
|
+
// Keep the failed event in the queue for next retry
|
|
115
|
+
await StorageManager_1.StorageManager.addQueuedEvent(event);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Clear all events after successful processing
|
|
119
|
+
await StorageManager_1.StorageManager.clearQueuedEvents();
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
this.isProcessingQueue = false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
generateEventId() {
|
|
126
|
+
return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.EventManager = EventManager;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { KewaConfig, BaseEventData, UserLoginEvent, UserRegistrationEvent, ScreenViewEvent, ContactData } from '../types';
|
|
2
|
+
export declare class KewaAnalytics {
|
|
3
|
+
private config;
|
|
4
|
+
private networkManager;
|
|
5
|
+
private eventManager;
|
|
6
|
+
private isInitialized;
|
|
7
|
+
private deviceInfo;
|
|
8
|
+
private appStateSubscription;
|
|
9
|
+
private hasLaunched;
|
|
10
|
+
private currentAppState;
|
|
11
|
+
private identityCache;
|
|
12
|
+
init(config: KewaConfig): Promise<void>;
|
|
13
|
+
private normalizeConfig;
|
|
14
|
+
private isTrackingDisabled;
|
|
15
|
+
private isEventTrackingDisabled;
|
|
16
|
+
private isAppStateTrackingDisabled;
|
|
17
|
+
isAutoScreenViewTrackingEnabled(): boolean;
|
|
18
|
+
private refreshIdentityCache;
|
|
19
|
+
private trackAppLaunch;
|
|
20
|
+
private setupAppStateMonitoring;
|
|
21
|
+
private handleAppForeground;
|
|
22
|
+
private backgroundEventPending;
|
|
23
|
+
private handleAppBackground;
|
|
24
|
+
private emitAppStateEvent;
|
|
25
|
+
private emitEvent;
|
|
26
|
+
trackEvent(eventName: string, eventData?: BaseEventData, contactData?: ContactData): Promise<void>;
|
|
27
|
+
setUserProperties(properties: ContactData): Promise<void>;
|
|
28
|
+
private applyIdentityFromResponse;
|
|
29
|
+
trackLogin(userData: Partial<UserLoginEvent>): Promise<void>;
|
|
30
|
+
trackLogout(): Promise<void>;
|
|
31
|
+
trackRegistration(userData: Partial<UserRegistrationEvent>): Promise<void>;
|
|
32
|
+
trackScreenView(screenName: string, additionalData?: Partial<ScreenViewEvent>): Promise<void>;
|
|
33
|
+
trackError(error: Error, context?: Record<string, any>, isFatal?: boolean): Promise<void>;
|
|
34
|
+
reset(): Promise<void>;
|
|
35
|
+
private clearLocalIdentity;
|
|
36
|
+
getKtcId(): Promise<string | null>;
|
|
37
|
+
getDeviceId(): Promise<string | null>;
|
|
38
|
+
getUserProperties(): Promise<ContactData>;
|
|
39
|
+
isSDKInitialized(): boolean;
|
|
40
|
+
cleanup(): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KewaAnalytics = void 0;
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const StorageManager_1 = require("../utils/StorageManager");
|
|
6
|
+
const NetworkManager_1 = require("../utils/NetworkManager");
|
|
7
|
+
const EventManager_1 = require("../core/EventManager");
|
|
8
|
+
const DeviceInfo_1 = require("../utils/DeviceInfo");
|
|
9
|
+
const constants_1 = require("../utils/constants");
|
|
10
|
+
const debug_1 = require("../utils/debug");
|
|
11
|
+
class KewaAnalytics {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.config = null;
|
|
14
|
+
this.networkManager = null;
|
|
15
|
+
this.eventManager = null;
|
|
16
|
+
this.isInitialized = false;
|
|
17
|
+
this.deviceInfo = null;
|
|
18
|
+
this.appStateSubscription = null;
|
|
19
|
+
this.hasLaunched = false;
|
|
20
|
+
this.currentAppState = 'active';
|
|
21
|
+
this.identityCache = {
|
|
22
|
+
ktcId: null,
|
|
23
|
+
deviceId: null,
|
|
24
|
+
userProperties: {},
|
|
25
|
+
};
|
|
26
|
+
this.backgroundEventPending = false;
|
|
27
|
+
}
|
|
28
|
+
async init(config) {
|
|
29
|
+
var _a;
|
|
30
|
+
try {
|
|
31
|
+
this.config = this.normalizeConfig(config);
|
|
32
|
+
(0, debug_1.setDebugLogging)((_a = this.config.enableDebugLogging) !== null && _a !== void 0 ? _a : false);
|
|
33
|
+
if (this.config.disableTracking) {
|
|
34
|
+
this.isInitialized = true;
|
|
35
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK initialized with tracking disabled');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!this.config.projectId) {
|
|
39
|
+
throw new Error('Kewa Analytics SDK: projectId is required when tracking is enabled');
|
|
40
|
+
}
|
|
41
|
+
this.networkManager = new NetworkManager_1.NetworkManager(this.config.appUrl, this.config.apiKey, this.config.projectId);
|
|
42
|
+
this.eventManager = new EventManager_1.EventManager(this.networkManager, this.config);
|
|
43
|
+
this.deviceInfo = await DeviceInfo_1.DeviceInfoCollector.collect();
|
|
44
|
+
await this.refreshIdentityCache();
|
|
45
|
+
if (!this.isAppStateTrackingDisabled() && !this.isInitialized) {
|
|
46
|
+
this.setupAppStateMonitoring();
|
|
47
|
+
}
|
|
48
|
+
await this.eventManager.processQueuedEvents();
|
|
49
|
+
this.isInitialized = true;
|
|
50
|
+
this.hasLaunched = true;
|
|
51
|
+
if (!this.isEventTrackingDisabled()) {
|
|
52
|
+
await this.trackAppLaunch();
|
|
53
|
+
}
|
|
54
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK initialized successfully');
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.warn('Failed to initialize Kewa Analytics SDK:', error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
normalizeConfig(config) {
|
|
61
|
+
var _a;
|
|
62
|
+
const appUrl = (_a = config.appUrl) !== null && _a !== void 0 ? _a : config.apiUrl;
|
|
63
|
+
if (!appUrl) {
|
|
64
|
+
throw new Error('Kewa Analytics SDK: appUrl is required');
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
batchSize: constants_1.KEWA_CONSTANTS.DEFAULTS.BATCH_SIZE,
|
|
68
|
+
maxQueueSize: constants_1.KEWA_CONSTANTS.DEFAULTS.MAX_QUEUE_SIZE,
|
|
69
|
+
disableTracking: false,
|
|
70
|
+
disableEventTracking: false,
|
|
71
|
+
disableAppStateTracking: false,
|
|
72
|
+
disableScreenViewTracking: false,
|
|
73
|
+
enableDebugLogging: false,
|
|
74
|
+
...config,
|
|
75
|
+
appUrl,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
isTrackingDisabled() {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.disableTracking) !== null && _b !== void 0 ? _b : false;
|
|
81
|
+
}
|
|
82
|
+
isEventTrackingDisabled() {
|
|
83
|
+
var _a, _b;
|
|
84
|
+
return this.isTrackingDisabled() || ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.disableEventTracking) !== null && _b !== void 0 ? _b : false);
|
|
85
|
+
}
|
|
86
|
+
isAppStateTrackingDisabled() {
|
|
87
|
+
var _a, _b;
|
|
88
|
+
return this.isTrackingDisabled() || ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.disableAppStateTracking) !== null && _b !== void 0 ? _b : false);
|
|
89
|
+
}
|
|
90
|
+
isAutoScreenViewTrackingEnabled() {
|
|
91
|
+
var _a, _b;
|
|
92
|
+
if (this.isTrackingDisabled() || this.isEventTrackingDisabled()) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return !((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.disableScreenViewTracking) !== null && _b !== void 0 ? _b : false);
|
|
96
|
+
}
|
|
97
|
+
async refreshIdentityCache() {
|
|
98
|
+
const [ktcId, deviceId, userProperties] = await Promise.all([
|
|
99
|
+
StorageManager_1.StorageManager.getKtcId(),
|
|
100
|
+
StorageManager_1.StorageManager.getDeviceId(),
|
|
101
|
+
StorageManager_1.StorageManager.getUserProperties(),
|
|
102
|
+
]);
|
|
103
|
+
this.identityCache = { ktcId, deviceId, userProperties };
|
|
104
|
+
}
|
|
105
|
+
async trackAppLaunch() {
|
|
106
|
+
const isFirstLaunch = !(await StorageManager_1.StorageManager.getDeviceId());
|
|
107
|
+
const launchData = {
|
|
108
|
+
...this.deviceInfo,
|
|
109
|
+
isFirstLaunch,
|
|
110
|
+
timestamp: new Date().toISOString(),
|
|
111
|
+
};
|
|
112
|
+
await this.emitEvent(constants_1.KEWA_CONSTANTS.EVENTS.APP_LAUNCH, launchData);
|
|
113
|
+
}
|
|
114
|
+
setupAppStateMonitoring() {
|
|
115
|
+
this.appStateSubscription = react_native_1.AppState.addEventListener('change', (nextAppState) => {
|
|
116
|
+
if (!this.hasLaunched || this.currentAppState === nextAppState) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const previousState = this.currentAppState;
|
|
120
|
+
this.currentAppState = nextAppState;
|
|
121
|
+
if (nextAppState === 'active' && (previousState === 'background' || previousState === 'inactive')) {
|
|
122
|
+
void this.handleAppForeground();
|
|
123
|
+
}
|
|
124
|
+
else if (nextAppState === 'background' && (previousState === 'active' || previousState === 'inactive')) {
|
|
125
|
+
// Fire immediately without awaiting — the OS may suspend the app before async work finishes
|
|
126
|
+
void this.handleAppBackground();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async handleAppForeground() {
|
|
131
|
+
this.backgroundEventPending = false;
|
|
132
|
+
await this.emitAppStateEvent(constants_1.KEWA_CONSTANTS.EVENTS.APP_FOREGROUND);
|
|
133
|
+
if (this.eventManager) {
|
|
134
|
+
await this.eventManager.processQueuedEvents();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async handleAppBackground() {
|
|
138
|
+
if (this.backgroundEventPending) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
this.backgroundEventPending = true;
|
|
142
|
+
try {
|
|
143
|
+
await this.emitAppStateEvent(constants_1.KEWA_CONSTANTS.EVENTS.APP_BACKGROUND);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
// Reset when app returns to foreground
|
|
147
|
+
if (react_native_1.AppState.currentState === 'active') {
|
|
148
|
+
this.backgroundEventPending = false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async emitAppStateEvent(eventName) {
|
|
153
|
+
if (this.isAppStateTrackingDisabled()) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!this.isInitialized || !this.eventManager || !this.deviceInfo) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const { ktcId, deviceId, userProperties } = this.identityCache;
|
|
160
|
+
await this.eventManager.processAppStateEvent(eventName, {
|
|
161
|
+
...this.deviceInfo,
|
|
162
|
+
timestamp: new Date().toISOString(),
|
|
163
|
+
}, {
|
|
164
|
+
id: ktcId || undefined,
|
|
165
|
+
...userProperties,
|
|
166
|
+
}, deviceId, this.deviceInfo);
|
|
167
|
+
await this.refreshIdentityCache();
|
|
168
|
+
}
|
|
169
|
+
async emitEvent(eventName, eventData = {}, contactData, options) {
|
|
170
|
+
var _a;
|
|
171
|
+
if (!this.isInitialized) {
|
|
172
|
+
console.warn('Kewa Analytics SDK not initialized. Call init() first.');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (!this.eventManager || !this.deviceInfo) {
|
|
176
|
+
console.warn('Kewa Analytics SDK not properly initialized');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const identity = (_a = options === null || options === void 0 ? void 0 : options.identity) !== null && _a !== void 0 ? _a : this.identityCache;
|
|
180
|
+
const { ktcId, deviceId, userProperties } = identity;
|
|
181
|
+
await this.eventManager.processEvent(eventName, eventData, {
|
|
182
|
+
id: ktcId || undefined,
|
|
183
|
+
...userProperties,
|
|
184
|
+
...contactData,
|
|
185
|
+
}, deviceId, this.deviceInfo);
|
|
186
|
+
if (!(options === null || options === void 0 ? void 0 : options.skipIdentityRefresh)) {
|
|
187
|
+
await this.refreshIdentityCache();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async trackEvent(eventName, eventData = {}, contactData) {
|
|
191
|
+
if (this.isEventTrackingDisabled()) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
await this.emitEvent(eventName, eventData, contactData);
|
|
195
|
+
}
|
|
196
|
+
async setUserProperties(properties) {
|
|
197
|
+
if (this.isTrackingDisabled()) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!this.networkManager) {
|
|
201
|
+
console.warn('Kewa Analytics SDK not properly initialized');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const currentUserProperties = await StorageManager_1.StorageManager.getUserProperties();
|
|
205
|
+
const userProperties = { ...currentUserProperties, ...properties };
|
|
206
|
+
await StorageManager_1.StorageManager.setUserProperties(userProperties);
|
|
207
|
+
const contact = {
|
|
208
|
+
...properties,
|
|
209
|
+
};
|
|
210
|
+
await this.refreshIdentityCache();
|
|
211
|
+
if (!this.networkManager.getNetworkStatus()) {
|
|
212
|
+
(0, debug_1.kewaDebug)('Offline — user properties saved locally only');
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Updating contact:', contact);
|
|
217
|
+
const response = await this.networkManager.updateContact(contact);
|
|
218
|
+
await this.applyIdentityFromResponse(response);
|
|
219
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Contact update response:', response);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
console.warn('Kewa Analytics SDK: Failed to update contact on Kewa:', error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async applyIdentityFromResponse(response) {
|
|
226
|
+
const ktcId = await StorageManager_1.StorageManager.getKtcId();
|
|
227
|
+
const deviceId = await StorageManager_1.StorageManager.getDeviceId();
|
|
228
|
+
if (response.id && response.id !== ktcId) {
|
|
229
|
+
await StorageManager_1.StorageManager.setKtcId(response.id);
|
|
230
|
+
}
|
|
231
|
+
if (response.device_id && response.device_id !== deviceId) {
|
|
232
|
+
await StorageManager_1.StorageManager.setDeviceId(response.device_id);
|
|
233
|
+
}
|
|
234
|
+
await this.refreshIdentityCache();
|
|
235
|
+
}
|
|
236
|
+
async trackLogin(userData) {
|
|
237
|
+
const loginData = {
|
|
238
|
+
loginMethod: 'custom',
|
|
239
|
+
...userData,
|
|
240
|
+
userId: userData.userId || '',
|
|
241
|
+
timestamp: new Date().toISOString(),
|
|
242
|
+
};
|
|
243
|
+
await this.trackEvent(constants_1.KEWA_CONSTANTS.EVENTS.USER_LOGIN, loginData);
|
|
244
|
+
}
|
|
245
|
+
async trackLogout() {
|
|
246
|
+
if (this.isTrackingDisabled()) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const logoutIdentity = { ...this.identityCache };
|
|
250
|
+
// Clear identity immediately so concurrent navigation events (screen_view) use no id
|
|
251
|
+
this.identityCache = { ktcId: null, deviceId: null, userProperties: {} };
|
|
252
|
+
if (!this.isEventTrackingDisabled()) {
|
|
253
|
+
await this.emitEvent(constants_1.KEWA_CONSTANTS.EVENTS.USER_LOGOUT, { timestamp: new Date().toISOString() }, undefined, { identity: logoutIdentity, skipIdentityRefresh: true });
|
|
254
|
+
}
|
|
255
|
+
await this.clearLocalIdentity();
|
|
256
|
+
(0, debug_1.kewaDebug)('Kewa Analytics SDK: Logout complete — identity cleared');
|
|
257
|
+
}
|
|
258
|
+
async trackRegistration(userData) {
|
|
259
|
+
const registrationData = {
|
|
260
|
+
registrationMethod: 'email',
|
|
261
|
+
...userData,
|
|
262
|
+
userId: userData.userId || '',
|
|
263
|
+
timestamp: new Date().toISOString(),
|
|
264
|
+
};
|
|
265
|
+
await this.trackEvent(constants_1.KEWA_CONSTANTS.EVENTS.USER_REGISTRATION, registrationData);
|
|
266
|
+
}
|
|
267
|
+
async trackScreenView(screenName, additionalData = {}) {
|
|
268
|
+
const screenData = {
|
|
269
|
+
screenName,
|
|
270
|
+
...additionalData,
|
|
271
|
+
timestamp: new Date().toISOString(),
|
|
272
|
+
};
|
|
273
|
+
await this.trackEvent(constants_1.KEWA_CONSTANTS.EVENTS.SCREEN_VIEW, screenData);
|
|
274
|
+
}
|
|
275
|
+
async trackError(error, context = {}, isFatal = false) {
|
|
276
|
+
const errorData = {
|
|
277
|
+
errorMessage: error.message,
|
|
278
|
+
errorStack: error.stack,
|
|
279
|
+
errorName: error.name,
|
|
280
|
+
isFatal,
|
|
281
|
+
context,
|
|
282
|
+
timestamp: new Date().toISOString(),
|
|
283
|
+
};
|
|
284
|
+
await this.trackEvent(constants_1.KEWA_CONSTANTS.EVENTS.ERROR, errorData);
|
|
285
|
+
}
|
|
286
|
+
async reset() {
|
|
287
|
+
await this.clearLocalIdentity();
|
|
288
|
+
}
|
|
289
|
+
async clearLocalIdentity() {
|
|
290
|
+
await StorageManager_1.StorageManager.removeKtcId();
|
|
291
|
+
await StorageManager_1.StorageManager.removeDeviceId();
|
|
292
|
+
await StorageManager_1.StorageManager.removeUserProperties();
|
|
293
|
+
this.identityCache = { ktcId: null, deviceId: null, userProperties: {} };
|
|
294
|
+
this.backgroundEventPending = false;
|
|
295
|
+
}
|
|
296
|
+
async getKtcId() {
|
|
297
|
+
return await StorageManager_1.StorageManager.getKtcId();
|
|
298
|
+
}
|
|
299
|
+
async getDeviceId() {
|
|
300
|
+
return await StorageManager_1.StorageManager.getDeviceId();
|
|
301
|
+
}
|
|
302
|
+
getUserProperties() {
|
|
303
|
+
return StorageManager_1.StorageManager.getUserProperties();
|
|
304
|
+
}
|
|
305
|
+
isSDKInitialized() {
|
|
306
|
+
return this.isInitialized;
|
|
307
|
+
}
|
|
308
|
+
cleanup() {
|
|
309
|
+
if (this.appStateSubscription) {
|
|
310
|
+
this.appStateSubscription.remove();
|
|
311
|
+
}
|
|
312
|
+
if (this.networkManager) {
|
|
313
|
+
this.networkManager.cleanup();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
exports.KewaAnalytics = KewaAnalytics;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { KewaProvider, useKewa } from './KewaProvider';
|
|
2
|
+
export * from './types';
|
|
3
|
+
export { KEWA_CONSTANTS } from './utils/constants';
|
|
4
|
+
export { DeviceInfoCollector } from './utils/DeviceInfo';
|
|
5
|
+
export { KewaProvider, useKewa };
|
|
6
|
+
declare const Kewa: import("./core/KewaAnalytics").KewaAnalytics;
|
|
7
|
+
export default Kewa;
|
|
8
|
+
export declare class KewaTracker {
|
|
9
|
+
static setupNavigationTracking(navigationRef: any): {
|
|
10
|
+
onReady: () => void;
|
|
11
|
+
onStateChange: () => Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
static trackButtonPress(buttonName: string, additionalData?: Record<string, any>): () => Promise<void>;
|
|
14
|
+
static trackFormSubmission(formName: string, formData?: Record<string, any>): () => Promise<void>;
|
|
15
|
+
static trackError(error: Error, context?: Record<string, any>): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare const KewaAutoTracker: typeof KewaTracker;
|
|
18
|
+
export declare function useAutoTracker(): {
|
|
19
|
+
setupNavigationTracking: typeof KewaTracker.setupNavigationTracking;
|
|
20
|
+
trackButtonPress: (buttonName: string, additionalData?: Record<string, any>) => () => Promise<void>;
|
|
21
|
+
trackFormSubmission: (formName: string, formData?: Record<string, any>) => () => Promise<void>;
|
|
22
|
+
trackError: (error: Error, context?: Record<string, any>, isFatal?: boolean) => Promise<void>;
|
|
23
|
+
};
|