partner_react_native_sdk 0.1.0 → 0.1.2
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/lib/module/helpers/ServiceNames.js +3 -0
- package/lib/module/helpers/ServiceNames.js.map +1 -1
- package/lib/module/helpers/analytics/analytics_event_model.js +37 -0
- package/lib/module/helpers/analytics/analytics_event_model.js.map +1 -0
- package/lib/module/helpers/analytics/analytics_logger.js +72 -0
- package/lib/module/helpers/analytics/analytics_logger.js.map +1 -0
- package/lib/module/helpers/analytics/event_storage.js +35 -0
- package/lib/module/helpers/analytics/event_storage.js.map +1 -0
- package/lib/module/helpers/partner_library_react_native.js +23 -2
- package/lib/module/helpers/partner_library_react_native.js.map +1 -1
- package/lib/module/helpers/webview.js +31 -10
- package/lib/module/helpers/webview.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/helpers/ServiceNames.d.ts +1 -0
- package/lib/typescript/src/helpers/ServiceNames.d.ts.map +1 -1
- package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts +16 -0
- package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts +17 -0
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/event_storage.d.ts +8 -0
- package/lib/typescript/src/helpers/analytics/event_storage.d.ts.map +1 -0
- package/lib/typescript/src/helpers/partner_library_react_native.d.ts +1 -0
- package/lib/typescript/src/helpers/partner_library_react_native.d.ts.map +1 -1
- package/lib/typescript/src/helpers/webview.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -5
- package/src/helpers/ServiceNames.tsx +4 -0
- package/src/helpers/analytics/analytics_event_model.tsx +47 -0
- package/src/helpers/analytics/analytics_logger.tsx +90 -0
- package/src/helpers/analytics/event_storage.tsx +44 -0
- package/src/helpers/partner_library_react_native.tsx +26 -4
- package/src/helpers/webview.tsx +346 -306
- package/src/index.tsx +2 -1
- package/lib/typescript/package.json +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAGxE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAExC,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "partner_react_native_sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React Native package for Fintech Partner",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -71,14 +71,11 @@
|
|
|
71
71
|
"@types/react": "^19.0.0",
|
|
72
72
|
"commitlint": "^19.6.1",
|
|
73
73
|
"del-cli": "^5.1.0",
|
|
74
|
-
"eslint": "^9.22.0",
|
|
75
|
-
"eslint-config-prettier": "^10.1.1",
|
|
76
|
-
"eslint-plugin-prettier": "^5.2.3",
|
|
77
74
|
"jest": "^29.7.0",
|
|
78
75
|
"prettier": "^3.0.3",
|
|
79
76
|
"react": "19.0.0",
|
|
80
77
|
"react-native": "0.78.2",
|
|
81
|
-
"react-native-builder-bob": "
|
|
78
|
+
"react-native-builder-bob": "0.39.0",
|
|
82
79
|
"release-it": "^17.10.0",
|
|
83
80
|
"turbo": "^1.10.7",
|
|
84
81
|
"typescript": "^5.2.2"
|
|
@@ -29,6 +29,10 @@ export class ServiceNames {
|
|
|
29
29
|
return `${this.HOST_URL}/network/keys`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
static get ANALYTICS_URL(): string {
|
|
33
|
+
return `${this.HOST_URL}/utils/event/SDK_EVENT`;
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
static readonly USER_SLUG = "/user";
|
|
33
37
|
static readonly GLOBAL_SLUG = "/global";
|
|
34
38
|
static readonly BANKING_SLUG = "/banking/{bank}";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface AnalyticsEventProps {
|
|
2
|
+
|
|
3
|
+
time: string;
|
|
4
|
+
info: Record<string, any>;
|
|
5
|
+
device: Record<string, any>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export class AnalyticsEvent {
|
|
10
|
+
time: string;
|
|
11
|
+
info: Record<string, any>;
|
|
12
|
+
device: Record<string, any>;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
constructor({ time, info, device }: AnalyticsEventProps) {
|
|
16
|
+
this.time = time;
|
|
17
|
+
this.info = info;
|
|
18
|
+
this.device = device;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toJson(): Record<string, any> {
|
|
22
|
+
return {
|
|
23
|
+
time: this.time,
|
|
24
|
+
event: {
|
|
25
|
+
info: this.info,
|
|
26
|
+
device: this.device,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static fromJson(json: Record<string, any>): AnalyticsEvent {
|
|
32
|
+
return new AnalyticsEvent({
|
|
33
|
+
time: json['time'],
|
|
34
|
+
info: json['event']['info'],
|
|
35
|
+
device: json['event']['device'],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static listFromJson(jsonString: string): AnalyticsEvent[] {
|
|
40
|
+
const decodedJson = JSON.parse(jsonString);
|
|
41
|
+
return decodedJson.map((json: any) => AnalyticsEvent.fromJson(json));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static listToJson(events: AnalyticsEvent[]): string {
|
|
45
|
+
return JSON.stringify(events.map((event) => event.toJson()));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { APICall } from "../network/APICall";
|
|
2
|
+
import { ServiceNames } from "../ServiceNames";
|
|
3
|
+
import { DeviceInfoManager } from "../utils/deviceInfoManager";
|
|
4
|
+
import { AnalyticsEvent } from "./analytics_event_model";
|
|
5
|
+
import { EventStorage } from "./event_storage";
|
|
6
|
+
|
|
7
|
+
export class AnalyticsLogger {
|
|
8
|
+
private static instance: AnalyticsLogger;
|
|
9
|
+
|
|
10
|
+
private apiCall = new APICall();
|
|
11
|
+
|
|
12
|
+
private events: AnalyticsEvent[] = [];
|
|
13
|
+
private debouncerTimer: ReturnType<typeof setTimeout> | null = null;
|
|
14
|
+
private _lastPost = 0;
|
|
15
|
+
private readonly maxBatchSize = 100;
|
|
16
|
+
private readonly maxInterval = 10 * 60 * 1000;
|
|
17
|
+
private readonly analyticsUrl = ServiceNames.ANALYTICS_URL;
|
|
18
|
+
private readonly eventStorage = new EventStorage();
|
|
19
|
+
|
|
20
|
+
constructor() { }
|
|
21
|
+
|
|
22
|
+
public static getInstance(): AnalyticsLogger {
|
|
23
|
+
if (!AnalyticsLogger.instance) {
|
|
24
|
+
AnalyticsLogger.instance = new AnalyticsLogger();
|
|
25
|
+
}
|
|
26
|
+
return AnalyticsLogger.instance;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async logEvent(info: Record<string, any>): Promise<void> {
|
|
30
|
+
const device = await DeviceInfoManager.getDeviceInfo();
|
|
31
|
+
const now = new Date().toLocaleString('sv-SE').replace('T', ' ').slice(0, 19);
|
|
32
|
+
console.log('Logging event:', info);
|
|
33
|
+
|
|
34
|
+
const event = new AnalyticsEvent({ time: now, info, device });
|
|
35
|
+
|
|
36
|
+
this.events = await this.eventStorage.loadEvents();
|
|
37
|
+
this.events.push(event);
|
|
38
|
+
|
|
39
|
+
await this.eventStorage.saveEvents(this.events);
|
|
40
|
+
|
|
41
|
+
const nowMillis = Date.now();
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
this.events.length >= this.maxBatchSize ||
|
|
45
|
+
nowMillis - this._lastPost > this.maxInterval
|
|
46
|
+
) {
|
|
47
|
+
await this.post();
|
|
48
|
+
} else {
|
|
49
|
+
this.debouncePost();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private debouncePost(): void {
|
|
54
|
+
if (this.debouncerTimer) {
|
|
55
|
+
clearTimeout(this.debouncerTimer);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.debouncerTimer = setTimeout(() => {
|
|
59
|
+
this.post(); // call post() after delay
|
|
60
|
+
}, 10000); // 10 seconds in milliseconds
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
private async post(): Promise<void> {
|
|
65
|
+
|
|
66
|
+
if (this.events.length == 0) return;
|
|
67
|
+
|
|
68
|
+
const eventsToSend = [...this.events];
|
|
69
|
+
this.events = [];
|
|
70
|
+
|
|
71
|
+
this._lastPost = Date.now();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
console.log("ANALYTICS_URL ", this.analyticsUrl);
|
|
75
|
+
console.log('Posting events:', eventsToSend);
|
|
76
|
+
const payload = {
|
|
77
|
+
body: { data: eventsToSend.map(event => event.toJson()) },
|
|
78
|
+
|
|
79
|
+
};
|
|
80
|
+
const response = await this.apiCall.callAPI('POST', this.analyticsUrl, payload);
|
|
81
|
+
await this.eventStorage.clearEvents();
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error('Error posting events:', error);
|
|
85
|
+
this.events = eventsToSend;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
2
|
+
import { AnalyticsEvent } from "./analytics_event_model";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class EventStorage {
|
|
6
|
+
|
|
7
|
+
private static readonly key = "analytics_events_spense";
|
|
8
|
+
|
|
9
|
+
async loadEvents(): Promise<AnalyticsEvent[]> {
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const jsonString = await AsyncStorage.getItem(EventStorage.key);
|
|
13
|
+
if (!jsonString) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return AnalyticsEvent.listFromJson(jsonString);
|
|
18
|
+
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("Error loading events from storage: ", error);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async saveEvents(events: AnalyticsEvent[]): Promise<void> {
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const jsonSting = AnalyticsEvent.listToJson(events);
|
|
30
|
+
await AsyncStorage.setItem(EventStorage.key, jsonSting);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.error("Error saving events to storage: ", error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async clearEvents(): Promise<void> {
|
|
38
|
+
try {
|
|
39
|
+
await AsyncStorage.removeItem(EventStorage.key);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Failed to clear analytics events:', error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -8,6 +8,7 @@ import { WebView } from '../helpers/webview';
|
|
|
8
8
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
9
9
|
import { StatusBar } from 'react-native';
|
|
10
10
|
export type { WebViewCallbackFunction } from './utils/webviewCallback';
|
|
11
|
+
import { AnalyticsLogger } from './analytics/analytics_logger';
|
|
11
12
|
type InitOptions = {
|
|
12
13
|
whitelistedDomains: string[];
|
|
13
14
|
deviceBindingEnabled: boolean;
|
|
@@ -21,7 +22,7 @@ export class PartnerLibrary {
|
|
|
21
22
|
|
|
22
23
|
private _apiCall = new APICall();
|
|
23
24
|
static webViewCallback: WebViewCallbackFunction;
|
|
24
|
-
|
|
25
|
+
private _analyticsLogger!: AnalyticsLogger;
|
|
25
26
|
private constructor() { }
|
|
26
27
|
|
|
27
28
|
static getInstance(): PartnerLibrary {
|
|
@@ -65,7 +66,8 @@ export class PartnerLibrary {
|
|
|
65
66
|
whitelistedDomains: whitelistedDomains,
|
|
66
67
|
deviceBinding: deviceBindingEnabled
|
|
67
68
|
});
|
|
68
|
-
|
|
69
|
+
this._analyticsLogger = new AnalyticsLogger();
|
|
70
|
+
this._analyticsLogger.logEvent({ "event": "REACT_NATIVE_INTIALIZED" })
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
async open(
|
|
@@ -74,6 +76,9 @@ export class PartnerLibrary {
|
|
|
74
76
|
WebViewCallbackFunction: WebViewCallbackFunction,
|
|
75
77
|
|
|
76
78
|
): Promise<React.ReactElement> {
|
|
79
|
+
|
|
80
|
+
this._analyticsLogger.logEvent({ "event": "REACT_NATIVE_OPEN_FN_CALLED" })
|
|
81
|
+
|
|
77
82
|
if (!PartnerLibrary.intialized) {
|
|
78
83
|
throw new Error('PartnerLibrary not initialized. Call init() first.');
|
|
79
84
|
}
|
|
@@ -101,6 +106,7 @@ export class PartnerLibrary {
|
|
|
101
106
|
WebViewCallbackFunction: WebViewCallbackFunction,
|
|
102
107
|
|
|
103
108
|
): Promise<React.ReactElement> {
|
|
109
|
+
this._analyticsLogger.logEvent({ "event": "REACT_NATIVE_DEVICE_BINDING_CALLED" })
|
|
104
110
|
|
|
105
111
|
console.log("entered in check device binding")
|
|
106
112
|
if (LibraryConstants.deviceBindingEnabled) {
|
|
@@ -123,6 +129,7 @@ export class PartnerLibrary {
|
|
|
123
129
|
): Promise<React.ReactElement> {
|
|
124
130
|
// console.log("PartnerLibrary._loginAndNavigateToWebView - LibraryConstants.hostName:", LibraryConstants.hostName);
|
|
125
131
|
try {
|
|
132
|
+
this._analyticsLogger.logEvent({ "event": "REACT_NATIVE_LOGIN_FN_CALLED" })
|
|
126
133
|
let tokenResponse: any;
|
|
127
134
|
const url = ServiceNames.LOGIN_URL;
|
|
128
135
|
console.log("url is : ", url)
|
|
@@ -134,13 +141,21 @@ export class PartnerLibrary {
|
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
);
|
|
144
|
+
this._analyticsLogger.logEvent({ "event": "REACT_NATIVE_LOGIN_FN_RESPONSE :", "response": tokenResponse })
|
|
145
|
+
|
|
137
146
|
|
|
138
147
|
if (tokenResponse?.data?.code === "USER_TOKEN_EXPIRED") {
|
|
139
148
|
console.log("Token expired");
|
|
140
149
|
return Promise.resolve(<></>);
|
|
141
150
|
}
|
|
142
151
|
|
|
143
|
-
if (
|
|
152
|
+
if (
|
|
153
|
+
tokenResponse &&
|
|
154
|
+
tokenResponse.data &&
|
|
155
|
+
typeof tokenResponse.data === 'object' &&
|
|
156
|
+
tokenResponse.data !== null &&
|
|
157
|
+
'RATE_LIMIT_USER' in tokenResponse.data
|
|
158
|
+
) {
|
|
144
159
|
console.log("rate limit user");
|
|
145
160
|
}
|
|
146
161
|
|
|
@@ -199,7 +214,13 @@ export class PartnerLibrary {
|
|
|
199
214
|
}
|
|
200
215
|
);
|
|
201
216
|
//console.log("response from setup device session is : ", response)
|
|
202
|
-
if (
|
|
217
|
+
if (
|
|
218
|
+
response &&
|
|
219
|
+
response.data &&
|
|
220
|
+
typeof response.data === 'object' &&
|
|
221
|
+
response.data !== null &&
|
|
222
|
+
'RATE_LIMIT_USER' in response.data
|
|
223
|
+
) {
|
|
203
224
|
console.log("rate limit user");
|
|
204
225
|
}
|
|
205
226
|
|
|
@@ -224,6 +245,7 @@ export class PartnerLibrary {
|
|
|
224
245
|
): Promise<React.ReactElement> {
|
|
225
246
|
console.log("entered in open web view");
|
|
226
247
|
console.log("url is : ", LibraryConstants.hostName + url);
|
|
248
|
+
this._analyticsLogger.logEvent({ "event": "REACT_NATIVE_WEBVIEW_OPEN_CALLED" })
|
|
227
249
|
|
|
228
250
|
|
|
229
251
|
return (
|