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.
Files changed (36) hide show
  1. package/lib/module/helpers/ServiceNames.js +3 -0
  2. package/lib/module/helpers/ServiceNames.js.map +1 -1
  3. package/lib/module/helpers/analytics/analytics_event_model.js +37 -0
  4. package/lib/module/helpers/analytics/analytics_event_model.js.map +1 -0
  5. package/lib/module/helpers/analytics/analytics_logger.js +72 -0
  6. package/lib/module/helpers/analytics/analytics_logger.js.map +1 -0
  7. package/lib/module/helpers/analytics/event_storage.js +35 -0
  8. package/lib/module/helpers/analytics/event_storage.js.map +1 -0
  9. package/lib/module/helpers/partner_library_react_native.js +23 -2
  10. package/lib/module/helpers/partner_library_react_native.js.map +1 -1
  11. package/lib/module/helpers/webview.js +31 -10
  12. package/lib/module/helpers/webview.js.map +1 -1
  13. package/lib/module/index.js +1 -0
  14. package/lib/module/index.js.map +1 -1
  15. package/lib/typescript/src/helpers/ServiceNames.d.ts +1 -0
  16. package/lib/typescript/src/helpers/ServiceNames.d.ts.map +1 -1
  17. package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts +16 -0
  18. package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts.map +1 -0
  19. package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts +17 -0
  20. package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts.map +1 -0
  21. package/lib/typescript/src/helpers/analytics/event_storage.d.ts +8 -0
  22. package/lib/typescript/src/helpers/analytics/event_storage.d.ts.map +1 -0
  23. package/lib/typescript/src/helpers/partner_library_react_native.d.ts +1 -0
  24. package/lib/typescript/src/helpers/partner_library_react_native.d.ts.map +1 -1
  25. package/lib/typescript/src/helpers/webview.d.ts.map +1 -1
  26. package/lib/typescript/src/index.d.ts +1 -0
  27. package/lib/typescript/src/index.d.ts.map +1 -1
  28. package/package.json +2 -5
  29. package/src/helpers/ServiceNames.tsx +4 -0
  30. package/src/helpers/analytics/analytics_event_model.tsx +47 -0
  31. package/src/helpers/analytics/analytics_logger.tsx +90 -0
  32. package/src/helpers/analytics/event_storage.tsx +44 -0
  33. package/src/helpers/partner_library_react_native.tsx +26 -4
  34. package/src/helpers/webview.tsx +346 -306
  35. package/src/index.tsx +2 -1
  36. package/lib/typescript/package.json +0 -1
@@ -1,3 +1,4 @@
1
+ export { PartnerLibrary } from './helpers/partner_library_react_native';
1
2
  export { WebView } from './helpers/webview';
2
3
  import type { WebViewCallbackFunction } from './helpers/utils/webviewCallback';
3
4
  export type { WebViewCallbackFunction };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAGxC,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD"}
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.0",
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": "^0.40.6",
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 (tokenResponse?.data && 'RATE_LIMIT_USER' in tokenResponse.data) {
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 (response?.data && 'RATE_LIMIT_USER' in response.data) {
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 (