react-native-smallcase-gateway 7.0.0 → 7.1.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.
Files changed (37) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/com/reactnativesmallcasegateway/SmallcaseGatewayModule.kt +8 -3
  3. package/ios/SmallcaseGateway.m +6 -3
  4. package/lib/commonjs/SCGatewayEventEmitter.js.map +1 -1
  5. package/lib/commonjs/SCLoansEventEmitter.js.map +1 -1
  6. package/lib/commonjs/ScLoan.js.map +1 -1
  7. package/lib/commonjs/SmallcaseGateway.js +10 -4
  8. package/lib/commonjs/SmallcaseGateway.js.map +1 -1
  9. package/lib/commonjs/constants.js +27 -27
  10. package/lib/commonjs/constants.js.map +1 -1
  11. package/lib/commonjs/index.js.map +1 -1
  12. package/lib/commonjs/util.js +14 -2
  13. package/lib/commonjs/util.js.map +1 -1
  14. package/lib/module/SCGatewayEventEmitter.js +1 -1
  15. package/lib/module/SCGatewayEventEmitter.js.map +1 -1
  16. package/lib/module/SCLoansEventEmitter.js +1 -1
  17. package/lib/module/SCLoansEventEmitter.js.map +1 -1
  18. package/lib/module/ScLoan.js.map +1 -1
  19. package/lib/module/SmallcaseGateway.js +12 -6
  20. package/lib/module/SmallcaseGateway.js.map +1 -1
  21. package/lib/module/constants.js +27 -27
  22. package/lib/module/constants.js.map +1 -1
  23. package/lib/module/index.js +3 -3
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/module/util.js +13 -1
  26. package/lib/module/util.js.map +1 -1
  27. package/package.json +7 -33
  28. package/react-native-smallcase-gateway.podspec +2 -2
  29. package/src/SCGatewayEventEmitter.js +96 -85
  30. package/src/SCLoansEventEmitter.js +94 -83
  31. package/src/ScLoan.js +18 -17
  32. package/src/SmallcaseGateway.js +28 -18
  33. package/src/constants.js +27 -27
  34. package/src/index.js +13 -5
  35. package/src/util.js +17 -4
  36. package/types/SmallcaseGateway.d.ts +3 -1
  37. package/types/index.d.ts +1 -1
@@ -1,8 +1,4 @@
1
- import {
2
- NativeEventEmitter,
3
- NativeModules,
4
- Platform
5
- } from 'react-native';
1
+ import { NativeEventEmitter, NativeModules } from 'react-native';
6
2
 
7
3
  /**
8
4
  * @typedef {Object} LoansEvent
@@ -16,101 +12,116 @@ import {
16
12
  const nativeModule = NativeModules.SCLoansBridgeEmitter;
17
13
 
18
14
  export const SCLoansEventTypes = {
19
- ANALYTICS_EVENT: 'scloans_analytics_event',
20
- SUPER_PROPERTIES_UPDATED: 'scloans_super_properties_updated',
15
+ ANALYTICS_EVENT: 'scloans_analytics_event',
16
+ SUPER_PROPERTIES_UPDATED: 'scloans_super_properties_updated',
21
17
  };
22
18
 
23
19
  const SCLoansNotificationEvent = 'scloans_notification';
24
20
  class SCLoansEvents {
25
- constructor() {
26
- this.eventEmitter = null;
27
- this.subscriptions = [];
28
- this.initialize();
21
+ constructor() {
22
+ this.eventEmitter = null;
23
+ this.subscriptions = [];
24
+ this.initialize();
25
+ }
26
+
27
+ get isInitialized() {
28
+ return this.eventEmitter !== null;
29
+ }
30
+
31
+ initialize() {
32
+ if (nativeModule) {
33
+ this.eventEmitter = new NativeEventEmitter(nativeModule);
34
+ } else {
35
+ console.warn('[SCLoansEvents] Native module not available');
29
36
  }
30
-
31
- get isInitialized() {
32
- return this.eventEmitter !== null;
37
+ }
38
+
39
+ // ===== LOANS EVENT METHODS =====
40
+ /**
41
+ * Subscribe to Loans Events
42
+ * @param {(event: LoansEvent) => void} callback - Callback function to handle loans events
43
+ * @returns {LoansEventSubscription} subscription - Subscription object with remove() method
44
+ */
45
+ subscribeToLoansEvent(callback) {
46
+ if (!this.isInitialized) {
47
+ console.warn('[SCLoansEvents] Event emitter not initialized');
48
+ return null;
33
49
  }
34
50
 
35
- initialize() {
36
- if (nativeModule) {
37
- this.eventEmitter = new NativeEventEmitter(nativeModule);
38
- } else {
39
- console.warn('[SCLoansEvents] Native module not available');
40
- }
51
+ if (typeof callback !== 'function') {
52
+ console.warn(
53
+ '[SCLoansEvents] Invalid callback provided for subscription'
54
+ );
55
+ return null;
41
56
  }
42
57
 
43
- // ===== LOANS EVENT METHODS =====
44
- /**
45
- * Subscribe to Loans Events
46
- * @param {(event: LoansEvent) => void} callback - Callback function to handle loans events
47
- * @returns {LoansEventSubscription} subscription - Subscription object with remove() method
48
- */
49
- subscribeToLoansEvent(callback) {
50
- if (!this.isInitialized) {
51
- console.warn('[SCLoansEvents] Event emitter not initialized');
52
- return null;
58
+ const subscription = this.eventEmitter.addListener(
59
+ SCLoansNotificationEvent,
60
+ (jsonString) => {
61
+ if (!jsonString) {
62
+ console.warn('[SCLoansEvents] Received null/undefined event data');
63
+ return;
53
64
  }
54
65
 
55
- if (typeof callback !== 'function') {
56
- console.warn('[SCLoansEvents] Invalid callback provided for subscription');
57
- return null;
66
+ let eventData;
67
+ try {
68
+ eventData = JSON.parse(jsonString);
69
+ } catch (error) {
70
+ console.warn(
71
+ '[SCLoansEvents] Failed to parse event JSON:',
72
+ error,
73
+ 'Raw data:',
74
+ jsonString
75
+ );
76
+ return;
58
77
  }
59
78
 
60
- const subscription = this.eventEmitter.addListener(SCLoansNotificationEvent, (jsonString) => {
61
- if (!jsonString) {
62
- console.warn('[SCLoansEvents] Received null/undefined event data');
63
- return;
64
- }
65
-
66
- let eventData;
67
- try {
68
- eventData = JSON.parse(jsonString);
69
- } catch (error) {
70
- console.warn('[SCLoansEvents] Failed to parse event JSON:', error, 'Raw data:', jsonString);
71
- return;
72
- }
73
-
74
- if (!eventData.type) {
75
- console.warn('[SCLoansEvents] Dropping event - missing event type:', eventData);
76
- return;
77
- }
78
-
79
- const normalizedEvent = {
80
- type: eventData.type,
81
- data: eventData.data,
82
- timestamp: eventData.timestamp || Date.now()
83
- };
84
-
85
- callback(normalizedEvent);
86
- });
87
-
88
- this.subscriptions.push(subscription);
89
-
90
- return subscription;
91
- }
92
-
93
- /**
94
- * Unsubscribe from Loans Events
95
- * @param {LoansEventSubscription} subscription - Subscription returned from subscribeToLoansEvents
96
- */
97
- unsubscribeFromLoansEvent(subscription) {
98
- if (subscription && typeof subscription.remove === 'function') {
99
- subscription.remove();
100
- this.subscriptions = this.subscriptions.filter(sub => sub !== subscription);
79
+ if (!eventData.type) {
80
+ console.warn(
81
+ '[SCLoansEvents] Dropping event - missing event type:',
82
+ eventData
83
+ );
84
+ return;
101
85
  }
102
- }
103
86
 
104
- cleanup() {
105
- this.subscriptions.forEach(subscription => {
106
- if (subscription && typeof subscription.remove === 'function') {
107
- subscription.remove();
108
- }
109
- });
110
- this.subscriptions = [];
87
+ const normalizedEvent = {
88
+ type: eventData.type,
89
+ data: eventData.data,
90
+ timestamp: eventData.timestamp || Date.now(),
91
+ };
92
+
93
+ callback(normalizedEvent);
94
+ }
95
+ );
96
+
97
+ this.subscriptions.push(subscription);
98
+
99
+ return subscription;
100
+ }
101
+
102
+ /**
103
+ * Unsubscribe from Loans Events
104
+ * @param {LoansEventSubscription} subscription - Subscription returned from subscribeToLoansEvents
105
+ */
106
+ unsubscribeFromLoansEvent(subscription) {
107
+ if (subscription && typeof subscription.remove === 'function') {
108
+ subscription.remove();
109
+ this.subscriptions = this.subscriptions.filter(
110
+ (sub) => sub !== subscription
111
+ );
111
112
  }
113
+ }
114
+
115
+ cleanup() {
116
+ this.subscriptions.forEach((subscription) => {
117
+ if (subscription && typeof subscription.remove === 'function') {
118
+ subscription.remove();
119
+ }
120
+ });
121
+ this.subscriptions = [];
122
+ }
112
123
  }
113
124
 
114
125
  const scLoansEventManager = new SCLoansEvents();
115
126
 
116
- export default scLoansEventManager;
127
+ export default scLoansEventManager;
package/src/ScLoan.js CHANGED
@@ -31,11 +31,12 @@ const { SmallcaseGateway: SmallcaseGatewayNative } = NativeModules;
31
31
  * @throws {ScLoanError}
32
32
  */
33
33
  const setup = async (config) => {
34
- const safeConfig = safeObject(config);
35
- if(safeConfig.environment === undefined || safeConfig.environment === null) safeConfig.environment = ENV.PROD
34
+ const safeConfig = safeObject(config);
35
+ if (safeConfig.environment === undefined || safeConfig.environment === null)
36
+ safeConfig.environment = ENV.PROD;
36
37
 
37
- return SmallcaseGatewayNative.setupLoans(safeConfig);
38
- };
38
+ return SmallcaseGatewayNative.setupLoans(safeConfig);
39
+ };
39
40
 
40
41
  /**
41
42
  * Triggers the LOS Journey
@@ -46,10 +47,10 @@ const setup = async (config) => {
46
47
  * @deprecated This method is deprecated use triggerInteraction() instead.
47
48
  */
48
49
  const apply = async (loanInfo) => {
49
- const safeLoanInfo = safeObject(loanInfo);
50
+ const safeLoanInfo = safeObject(loanInfo);
50
51
 
51
- return SmallcaseGatewayNative.apply(safeLoanInfo);
52
- };
52
+ return SmallcaseGatewayNative.apply(safeLoanInfo);
53
+ };
53
54
 
54
55
  /**
55
56
  * Triggers the Repayment Journey
@@ -60,10 +61,10 @@ const apply = async (loanInfo) => {
60
61
  * @deprecated This method is deprecated use triggerInteraction() instead.
61
62
  */
62
63
  const pay = async (loanInfo) => {
63
- const safeLoanInfo = safeObject(loanInfo);
64
+ const safeLoanInfo = safeObject(loanInfo);
64
65
 
65
- return SmallcaseGatewayNative.pay(safeLoanInfo);
66
- };
66
+ return SmallcaseGatewayNative.pay(safeLoanInfo);
67
+ };
67
68
 
68
69
  /**
69
70
  * Triggers the Withdraw Journey
@@ -74,10 +75,10 @@ const pay = async (loanInfo) => {
74
75
  * @deprecated This method is deprecated use triggerInteraction() instead.
75
76
  */
76
77
  const withdraw = async (loanInfo) => {
77
- const safeLoanInfo = safeObject(loanInfo);
78
+ const safeLoanInfo = safeObject(loanInfo);
78
79
 
79
- return SmallcaseGatewayNative.withdraw(safeLoanInfo);
80
- };
80
+ return SmallcaseGatewayNative.withdraw(safeLoanInfo);
81
+ };
81
82
 
82
83
  /**
83
84
  * Triggers the Servicing Journey
@@ -88,10 +89,10 @@ const withdraw = async (loanInfo) => {
88
89
  * @deprecated This method is deprecated use triggerInteraction() instead.
89
90
  */
90
91
  const service = async (loanInfo) => {
91
- const safeLoanInfo = safeObject(loanInfo);
92
+ const safeLoanInfo = safeObject(loanInfo);
92
93
 
93
- return SmallcaseGatewayNative.service(safeLoanInfo);
94
- };
94
+ return SmallcaseGatewayNative.service(safeLoanInfo);
95
+ };
95
96
 
96
97
  /**
97
98
  * Triggers the triggerInteraction function
@@ -115,4 +116,4 @@ const ScLoan = {
115
116
  triggerInteraction,
116
117
  };
117
118
 
118
- export default ScLoan;
119
+ export default ScLoan;
@@ -1,6 +1,10 @@
1
- import { NativeModules, Platform } from 'react-native';
1
+ import { NativeModules } from 'react-native';
2
2
  import { ENV } from './constants';
3
- import { safeObject, platformSpecificColorHex } from './util';
3
+ import {
4
+ safeObject,
5
+ platformSpecificColorHex,
6
+ sanitizeBrokerList,
7
+ } from './util';
4
8
  import { version } from '../package.json';
5
9
  const { SmallcaseGateway: SmallcaseGatewayNative } = NativeModules;
6
10
 
@@ -64,7 +68,7 @@ const setConfigEnvironment = async (envConfig) => {
64
68
 
65
69
  const safeIsLeprechaun = Boolean(isLeprechaun);
66
70
  const safeIsAmoEnabled = Boolean(isAmoEnabled);
67
- const safeBrokerList = Array.isArray(brokerList) ? brokerList : [];
71
+ const safeBrokerList = sanitizeBrokerList(brokerList);
68
72
  const safeGatewayName = typeof gatewayName === 'string' ? gatewayName : '';
69
73
  const safeEnvName =
70
74
  typeof environmentName === 'string' ? environmentName : ENV.PROD;
@@ -85,10 +89,15 @@ const setConfigEnvironment = async (envConfig) => {
85
89
  *
86
90
  * note: this must be called after `setConfigEnvironment()`
87
91
  * @param {string} sdkToken
92
+ * @param {Object} [externalMeta] - external metadata (iOS only, optional)
93
+ * @param {Object} [externalMeta.externalIdentifier] - key-value pairs for external identifiers (e.g., { userId: '123' })
88
94
  */
89
- const init = async (sdkToken) => {
95
+ const init = async (sdkToken, externalMeta) => {
90
96
  const safeToken = typeof sdkToken === 'string' ? sdkToken : '';
91
- return SmallcaseGatewayNative.init(safeToken);
97
+ const safeExternalMeta =
98
+ externalMeta && typeof externalMeta === 'object' ? externalMeta : null;
99
+
100
+ return SmallcaseGatewayNative.init(safeToken, safeExternalMeta);
92
101
  };
93
102
 
94
103
  /**
@@ -103,10 +112,11 @@ const triggerTransaction = async (transactionId, utmParams, brokerList) => {
103
112
  const safeUtm = safeObject(utmParams);
104
113
  const safeId = typeof transactionId === 'string' ? transactionId : '';
105
114
 
106
- const safeBrokerList =
107
- Array.isArray(brokerList) && brokerList.length
108
- ? brokerList
109
- : defaultBrokerList;
115
+ let safeBrokerList = sanitizeBrokerList(brokerList);
116
+
117
+ if (safeBrokerList.length === 0) {
118
+ safeBrokerList = defaultBrokerList;
119
+ }
110
120
 
111
121
  return SmallcaseGatewayNative.triggerTransaction(
112
122
  safeId,
@@ -183,14 +193,14 @@ const launchSmallplugWithBranding = async (
183
193
  const safeBackIconOpacity =
184
194
  typeof backIconOpacity === 'number' ? backIconOpacity : 1;
185
195
 
186
- return SmallcaseGatewayNative.launchSmallplugWithBranding(
187
- safeEndpoint,
188
- safeParams,
189
- safeHeaderColor,
190
- safeHeaderOpacity,
191
- safeBackIconColor,
192
- safeBackIconOpacity
193
- );
196
+ return SmallcaseGatewayNative.launchSmallplugWithBranding(
197
+ safeEndpoint,
198
+ safeParams,
199
+ safeHeaderColor,
200
+ safeHeaderOpacity,
201
+ safeBackIconColor,
202
+ safeBackIconOpacity
203
+ );
194
204
  };
195
205
 
196
206
  /**
@@ -298,4 +308,4 @@ const SmallcaseGateway = {
298
308
  showOrders,
299
309
  };
300
310
 
301
- export default SmallcaseGateway;
311
+ export default SmallcaseGateway;
package/src/constants.js CHANGED
@@ -1,35 +1,35 @@
1
1
  export const ENV = {
2
- STAG: "staging",
3
- DEV: "development",
4
- PROD: "production",
2
+ STAG: 'staging',
3
+ DEV: 'development',
4
+ PROD: 'production',
5
5
  };
6
6
 
7
7
  export const TRANSACTION_TYPE = {
8
- connect: "CONNECT",
9
- sipSetup: "SIP_SETUP",
10
- fetchFunds: "FETCH_FUNDS",
11
- transaction: "TRANSACTION",
12
- holdingsImport: "HOLDINGS_IMPORT",
13
- authorizeHoldings: "AUTHORISE_HOLDINGS",
14
- mfHoldingsImport: "MF_HOLDINGS_IMPORT"
8
+ connect: 'CONNECT',
9
+ sipSetup: 'SIP_SETUP',
10
+ fetchFunds: 'FETCH_FUNDS',
11
+ transaction: 'TRANSACTION',
12
+ holdingsImport: 'HOLDINGS_IMPORT',
13
+ authorizeHoldings: 'AUTHORISE_HOLDINGS',
14
+ mfHoldingsImport: 'MF_HOLDINGS_IMPORT',
15
15
  };
16
16
 
17
17
  export const ERROR_MSG = {
18
- init_sdk: "init_sdk",
19
- no_order: "no_order",
20
- no_broker: "no_broker",
21
- invalid_jwt: "invalid_jwt",
22
- market_closed: "market_closed",
23
- user_mismatch: "user_mismatch",
24
- order_pending: "order_pending",
25
- internal_error: "internal_error",
26
- user_cancelled: "user_cancelled",
27
- consent_denied: "consent_denied",
28
- order_in_queue: "order_in_queue",
29
- invalid_gateway: "invalid_gateway",
30
- transaction_expired: "transaction_expired",
31
- invalid_transactionId: "invalid_transactionId",
32
- insufficient_holdings: "insufficient_holdings",
33
- transaction_in_process: "transaction_in_process",
34
- no_compatible_browser: "no_compatible_browser"
18
+ init_sdk: 'init_sdk',
19
+ no_order: 'no_order',
20
+ no_broker: 'no_broker',
21
+ invalid_jwt: 'invalid_jwt',
22
+ market_closed: 'market_closed',
23
+ user_mismatch: 'user_mismatch',
24
+ order_pending: 'order_pending',
25
+ internal_error: 'internal_error',
26
+ user_cancelled: 'user_cancelled',
27
+ consent_denied: 'consent_denied',
28
+ order_in_queue: 'order_in_queue',
29
+ invalid_gateway: 'invalid_gateway',
30
+ transaction_expired: 'transaction_expired',
31
+ invalid_transactionId: 'invalid_transactionId',
32
+ insufficient_holdings: 'insufficient_holdings',
33
+ transaction_in_process: 'transaction_in_process',
34
+ no_compatible_browser: 'no_compatible_browser',
35
35
  };
package/src/index.js CHANGED
@@ -1,8 +1,16 @@
1
- import SmallcaseGateway from "./SmallcaseGateway";
2
- import ScLoan from "./ScLoan";
3
- import scGatewayEventManager, { SCGatewayEventTypes } from './SCGatewayEventEmitter';
1
+ import SmallcaseGateway from './SmallcaseGateway';
2
+ import ScLoan from './ScLoan';
3
+ import scGatewayEventManager, {
4
+ SCGatewayEventTypes,
5
+ } from './SCGatewayEventEmitter';
4
6
  import scLoansEventManager, { SCLoansEventTypes } from './SCLoansEventEmitter';
5
- import { ENV, TRANSACTION_TYPE, ERROR_MSG } from "./constants";
7
+ import { ENV, TRANSACTION_TYPE, ERROR_MSG } from './constants';
6
8
 
7
- export { ScLoan, scGatewayEventManager as SCGatewayEventManager, scLoansEventManager as SCLoansEventManager, SCGatewayEventTypes, SCLoansEventTypes }
9
+ export {
10
+ ScLoan,
11
+ scGatewayEventManager as SCGatewayEventManager,
12
+ scLoansEventManager as SCLoansEventManager,
13
+ SCGatewayEventTypes,
14
+ SCLoansEventTypes,
15
+ };
8
16
  export default { ...SmallcaseGateway, ENV, ERROR_MSG, TRANSACTION_TYPE };
package/src/util.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { Platform } from 'react-native';
2
+
1
3
  /**
2
4
  * check if value is a valid object.
3
5
  *
@@ -6,13 +8,24 @@
6
8
  * @param {*} obj
7
9
  * @returns {Object} same object if its valid, else returns `{}`
8
10
  */
9
- export const safeObject = (obj) => {
10
- return obj && typeof obj === "object" ? obj : {};
11
+ export const safeObject = (obj) => {
12
+ return obj && typeof obj === 'object' ? obj : {};
11
13
  };
12
14
 
13
15
  export function platformSpecificColorHex(hex) {
14
16
  if (Platform.OS === 'android') {
15
- return `#${hex}`
17
+ return `#${hex}`;
16
18
  }
17
- return hex
19
+ return hex;
20
+ }
21
+
22
+ /** sanitize the input broker array to make sure its an array and only has string values */
23
+ export function sanitizeBrokerList(arr) {
24
+ if (!Array.isArray(arr) || arr.length === 0) {
25
+ return [];
26
+ }
27
+
28
+ return arr.filter((val) => {
29
+ return typeof val === 'string' && val.trim() !== '';
30
+ });
18
31
  }
@@ -95,8 +95,10 @@ declare namespace SmallcaseGateway {
95
95
  *
96
96
  * note: this must be called after `setConfigEnvironment()`
97
97
  * @param {string} sdkToken
98
+ * @param {Object} [externalMeta] - external metadata (iOS only, optional)
99
+ * @param {Object} [externalMeta.externalIdentifier] - key-value pairs for external identifiers (e.g., { userId: '123' })
98
100
  */
99
- declare function init(sdkToken: string): unknown;
101
+ declare function init(sdkToken: string, externalMeta?: { externalIdentifier?: { [key: string]: string } }): unknown;
100
102
  /**
101
103
  * Logs the user out and removes the web session.
102
104
  *
package/types/index.d.ts CHANGED
@@ -67,7 +67,7 @@ declare const _default: {
67
67
  authorizeHoldings: string;
68
68
  mfHoldingsImport: string;
69
69
  };
70
- init: (sdkToken: string) => unknown;
70
+ init: (sdkToken: string, externalMeta?: { externalIdentifier?: { [key: string]: string } }) => unknown;
71
71
  logoutUser: () => Promise;
72
72
  triggerLeadGen: (userDetails?: import("./SmallcaseGateway").userDetails, utmParams?: any) => any;
73
73
  triggerLeadGenWithStatus: (userDetails?: import("./SmallcaseGateway").userDetails) => Promise;