@finos_sdk/sdk-ekyc 1.5.1 → 1.5.3

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  React Native SDK for eKYC (electronic Know Your Customer) and eSign. Features include Vietnamese CCCD NFC reading, OCR, Liveness detection, Face matching, C06 residence verification, SMS OTP verification, and Electronic Signature (eSign) capabilities.
7
7
 
8
- **Version**: 1.4.8
8
+ **Version**: 1.5.2
9
9
 
10
10
  ## Features
11
11
 
@@ -65,7 +65,7 @@ dependencies {
65
65
  implementation 'com.facebook.react:react-android'
66
66
 
67
67
  // Finos eKYC SDK dependencies from GitHub Packages Maven repository
68
- def sdkVersion = "1.4.8"
68
+ def sdkVersion = "1.5.3"
69
69
  implementation("finos.sdk.ekyc:ekyc:$sdkVersion")
70
70
  implementation("finos.sdk.ekyc:ekycui:$sdkVersion")
71
71
  implementation("finos.sdk.ekyc:nfc:$sdkVersion")
@@ -30,8 +30,8 @@ import finos.sdk.core.model.response.SDKEkycResult
30
30
  import finos.sdk.core.model.sdk.config.AppKeyConfig
31
31
  import finos.sdk.core.model.sdk.config.C06Config
32
32
  import finos.sdk.core.model.sdk.config.EKYCConfigSDK
33
+ import finos.sdk.core.model.sdk.config.ExitConfirmConfig
33
34
  import finos.sdk.core.model.sdk.config.FaceServiceConfig
34
- import finos.sdk.core.model.sdk.config.LivenessBackConfirmConfig
35
35
  import finos.sdk.core.model.sdk.config.LivenessConfig
36
36
  import finos.sdk.core.model.sdk.config.NfcConfig
37
37
  import finos.sdk.core.model.sdk.config.OcrConfig
@@ -565,6 +565,28 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
565
565
  .emit(eventName, params)
566
566
  }
567
567
 
568
+ private fun WritableMap.putCustomData(customData: Map<*, *>?) {
569
+ customData?.forEach { (key, value) ->
570
+ val k = key.toString()
571
+ when (value) {
572
+ is Boolean -> putBoolean(k, value)
573
+ is Int -> putInt(k, value)
574
+ is Long -> putInt(k, value.toInt())
575
+ is Double -> putDouble(k, value)
576
+ else -> {
577
+ val str = value.toString()
578
+ val intVal = str.toIntOrNull()
579
+ val boolVal = str.lowercase().toBooleanStrictOrNull()
580
+ when {
581
+ boolVal != null -> putBoolean(k, boolVal)
582
+ intVal != null -> putInt(k, intVal)
583
+ else -> putString(k, str)
584
+ }
585
+ }
586
+ }
587
+ }
588
+ }
589
+
568
590
  /**
569
591
  * Helper function to create separate maps for event and promise to avoid "Map already consumed" error
570
592
  * @param builder Lambda function to build the map content
@@ -989,6 +1011,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
989
1011
  activeActionCount: Int?,
990
1012
  forceCaptureTimeout: Double?,
991
1013
  isActiveLivenessColor: Boolean?,
1014
+ exitConfirmConfigJson: String?,
992
1015
  promise: Promise
993
1016
  ) {
994
1017
  Log.d(TAG, "▶️ startLiveness() called")
@@ -1034,11 +1057,13 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1034
1057
  selfieImage = imageFile,
1035
1058
  transactionId = transactionId
1036
1059
  )
1060
+ val exitConfirmConfig = parseExitConfirmConfig(exitConfirmConfigJson)
1037
1061
  val ekycConfig =
1038
1062
  EKYCConfigSDK(
1039
1063
  appKey = AppKeyConfig(appKey),
1040
1064
  sdkType = SDKType.LIVENESS,
1041
- livenessConfig = livenessConfig
1065
+ livenessConfig = livenessConfig,
1066
+ exitConfirmConfig = exitConfirmConfig
1042
1067
  )
1043
1068
  eKYCFinOSLiveness.startEkyc(
1044
1069
  ekycConfigSDK = ekycConfig,
@@ -1294,6 +1319,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1294
1319
  optionConfigJson: String, // JSON string for option config
1295
1320
  appKeyConfigJson: String, // JSON string for app key config
1296
1321
  styleConfigJson: String, // JSON string for style config
1322
+ exitConfirmConfigJson: String?, // JSON string for exit confirm bottom sheet config
1297
1323
  promise: Promise
1298
1324
  ) {
1299
1325
  Log.d(TAG, "▶️ startEkycUI() called")
@@ -1348,6 +1374,9 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1348
1374
  )
1349
1375
  } else null
1350
1376
 
1377
+ // Parse exit confirm bottom sheet config (optional)
1378
+ val exitConfirmConfig = parseExitConfirmConfig(exitConfirmConfigJson)
1379
+
1351
1380
  // Create EKYCConfigSDK like SDKeKYCActivity / MainActivity.kt
1352
1381
  val ekycConfigSDK = EKYCConfigSDK(
1353
1382
  appKey = appKeyConfig,
@@ -1355,7 +1384,8 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1355
1384
  livenessConfig = livenessConfig,
1356
1385
  styleConfig = styleConfig,
1357
1386
  appIDType = appIDType,
1358
- flowSDK = finalFlow
1387
+ flowSDK = finalFlow,
1388
+ exitConfirmConfig = exitConfirmConfig
1359
1389
  )
1360
1390
 
1361
1391
  eKYCFinOSUI.startEkyc(
@@ -1687,6 +1717,174 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1687
1717
  }
1688
1718
  }
1689
1719
 
1720
+ // ==================== ExitConfirmConfig parsing ====================
1721
+
1722
+ /**
1723
+ * Parse JSON từ React Native sang ExitConfirmConfig của SDK.
1724
+ * Trả null nếu json rỗng / lỗi — SDK sẽ dùng giá trị mặc định.
1725
+ */
1726
+ private fun parseExitConfirmConfig(json: String?): ExitConfirmConfig? {
1727
+ if (json.isNullOrBlank() || json == "{}") return null
1728
+ return try {
1729
+ val obj = JSONObject(json)
1730
+ ExitConfirmConfig(
1731
+ iconProps = parseExitIconProps(obj.optJSONObject("iconProps")),
1732
+ titleProps = parseExitTitleProps(obj.optJSONObject("titleProps")),
1733
+ contentProps = parseExitContentProps(obj.optJSONObject("contentProps")),
1734
+ confirmButtonProps = parseExitButtonProps(obj.optJSONObject("confirmButtonProps")),
1735
+ cancelButtonProps = parseExitButtonProps(obj.optJSONObject("cancelButtonProps")),
1736
+ )
1737
+ } catch (e: Exception) {
1738
+ Log.e(TAG, "parseExitConfirmConfig failed: ${e.message}", e)
1739
+ null
1740
+ }
1741
+ }
1742
+
1743
+ private fun parseExitIconProps(obj: JSONObject?): ExitConfirmConfig.IconProps? {
1744
+ if (obj == null) return null
1745
+ val iconResName = obj.optStringOrNull("iconResName")
1746
+ val iconResId: Int? = iconResName?.let { resolveDrawableId(it) }
1747
+ val iconViewStyle = parseExitViewStyle(obj.optJSONObject("iconViewStyle"))
1748
+ if (iconResId == null && iconViewStyle == null) return null
1749
+ return ExitConfirmConfig.IconProps(
1750
+ icon = iconResId,
1751
+ iconViewStyle = iconViewStyle,
1752
+ )
1753
+ }
1754
+
1755
+ private fun parseExitTitleProps(obj: JSONObject?): ExitConfirmConfig.TitleProps? {
1756
+ if (obj == null) return null
1757
+ val title = obj.optStringOrNull("title")
1758
+ val titleStyles = parseExitTextStyles(obj.optJSONObject("titleStyles"))
1759
+ if (title == null && titleStyles == null) return null
1760
+ return ExitConfirmConfig.TitleProps(title = title, titleStyles = titleStyles)
1761
+ }
1762
+
1763
+ private fun parseExitContentProps(obj: JSONObject?): ExitConfirmConfig.ContentProps? {
1764
+ if (obj == null) return null
1765
+ val content = obj.optStringOrNull("content")
1766
+ val contentStyles = parseExitTextStyles(obj.optJSONObject("contentStyles"))
1767
+ if (content == null && contentStyles == null) return null
1768
+ return ExitConfirmConfig.ContentProps(content = content, contentStyles = contentStyles)
1769
+ }
1770
+
1771
+ private fun parseExitButtonProps(obj: JSONObject?): ExitConfirmConfig.ButtonProps? {
1772
+ if (obj == null) return null
1773
+ val title = obj.optStringOrNull("buttonTitle")
1774
+ val textStyles = parseExitTextStyles(obj.optJSONObject("buttonTextStyles"))
1775
+ val viewStyles = parseExitViewStyle(obj.optJSONObject("buttonStyles"))
1776
+ if (title == null && textStyles == null && viewStyles == null) return null
1777
+ return ExitConfirmConfig.ButtonProps(
1778
+ buttonTitle = title,
1779
+ buttonTextStyles = textStyles,
1780
+ buttonStyles = viewStyles,
1781
+ )
1782
+ }
1783
+
1784
+ private fun parseExitTextStyles(obj: JSONObject?): ExitConfirmConfig.TextStyles? {
1785
+ if (obj == null) return null
1786
+ val textColor = obj.optStringOrNull("textColor")
1787
+ val textSize = obj.optIntOrNull("textSize")
1788
+ val textFont = obj.optStringOrNull("textFont")
1789
+ val textStyle = obj.optIntOrNull("textStyle")
1790
+ val textAlign = obj.optIntOrNull("textAlign")
1791
+ if (textColor == null && textSize == null && textFont == null && textStyle == null && textAlign == null) {
1792
+ return null
1793
+ }
1794
+ return ExitConfirmConfig.TextStyles(
1795
+ textColor = textColor,
1796
+ textSize = textSize,
1797
+ textFont = textFont,
1798
+ textStyle = textStyle,
1799
+ textAlign = textAlign,
1800
+ )
1801
+ }
1802
+
1803
+ private fun parseExitViewStyle(obj: JSONObject?): ExitConfirmConfig.ViewStyle? {
1804
+ if (obj == null) return null
1805
+ val backgroundColor = obj.optStringOrNull("backgroundColor")
1806
+ val gradientColors = obj.optJSONArray("backgroundGradientColors")?.let { arr ->
1807
+ val list = mutableListOf<String>()
1808
+ for (i in 0 until arr.length()) {
1809
+ arr.optString(i, null)?.takeIf { it.isNotBlank() }?.let(list::add)
1810
+ }
1811
+ list.takeIf { it.isNotEmpty() }
1812
+ }
1813
+ val gradientPositions = obj.optJSONArray("backgroundGradientPositions")?.let { arr ->
1814
+ val list = mutableListOf<Float>()
1815
+ for (i in 0 until arr.length()) list.add(arr.optDouble(i, 0.0).toFloat())
1816
+ list.takeIf { it.isNotEmpty() }
1817
+ }
1818
+ val orientation = obj.optStringOrNull("backgroundGradientOrientation")?.let {
1819
+ try { ExitConfirmConfig.GradientOrientation.valueOf(it) } catch (_: Exception) { null }
1820
+ }
1821
+ val width = obj.optIntOrNull("width")
1822
+ val height = obj.optIntOrNull("height")
1823
+ val marginTop = obj.optIntOrNull("marginTop")
1824
+ val marginBottom = obj.optIntOrNull("marginBottom")
1825
+ val marginStart = obj.optIntOrNull("marginStart")
1826
+ val marginEnd = obj.optIntOrNull("marginEnd")
1827
+ val paddingTop = obj.optIntOrNull("paddingTop")
1828
+ val paddingBottom = obj.optIntOrNull("paddingBottom")
1829
+ val paddingStart = obj.optIntOrNull("paddingStart")
1830
+ val paddingEnd = obj.optIntOrNull("paddingEnd")
1831
+ val gravity = obj.optIntOrNull("gravity")
1832
+ val cornerRadius = if (obj.has("cornerRadius") && !obj.isNull("cornerRadius")) {
1833
+ obj.optDouble("cornerRadius", Double.NaN).takeIf { !it.isNaN() }?.toFloat()
1834
+ } else null
1835
+
1836
+ val anySet = backgroundColor != null || gradientColors != null || gradientPositions != null ||
1837
+ orientation != null || width != null || height != null ||
1838
+ marginTop != null || marginBottom != null || marginStart != null || marginEnd != null ||
1839
+ paddingTop != null || paddingBottom != null || paddingStart != null || paddingEnd != null ||
1840
+ gravity != null || cornerRadius != null
1841
+ if (!anySet) return null
1842
+
1843
+ return ExitConfirmConfig.ViewStyle(
1844
+ backgroundColor = backgroundColor,
1845
+ backgroundGradientColors = gradientColors,
1846
+ backgroundGradientPositions = gradientPositions,
1847
+ backgroundGradientOrientation = orientation,
1848
+ width = width,
1849
+ height = height,
1850
+ marginTop = marginTop,
1851
+ marginBottom = marginBottom,
1852
+ marginStart = marginStart,
1853
+ marginEnd = marginEnd,
1854
+ paddingTop = paddingTop,
1855
+ paddingBottom = paddingBottom,
1856
+ paddingStart = paddingStart,
1857
+ paddingEnd = paddingEnd,
1858
+ gravity = gravity,
1859
+ cornerRadius = cornerRadius,
1860
+ )
1861
+ }
1862
+
1863
+ /** Resolve drawable resource id từ tên (vd "ic_warning"). Trả null nếu host app không có. */
1864
+ private fun resolveDrawableId(name: String): Int? {
1865
+ return try {
1866
+ val ctx = reactApplicationContext
1867
+ val id = ctx.resources.getIdentifier(name, "drawable", ctx.packageName)
1868
+ if (id != 0) id else null
1869
+ } catch (e: Exception) {
1870
+ Log.w(TAG, "resolveDrawableId('$name') failed: ${e.message}")
1871
+ null
1872
+ }
1873
+ }
1874
+
1875
+ /** `optString` của org.json trả "" thay vì null khi key missing — wrap để có null thực sự. */
1876
+ private fun JSONObject.optStringOrNull(key: String): String? {
1877
+ if (!has(key) || isNull(key)) return null
1878
+ val v = optString(key, "")
1879
+ return v.takeIf { it.isNotEmpty() }
1880
+ }
1881
+
1882
+ private fun JSONObject.optIntOrNull(key: String): Int? {
1883
+ if (!has(key) || isNull(key)) return null
1884
+ return optInt(key, Int.MIN_VALUE).takeIf { it != Int.MIN_VALUE }
1885
+ ?: try { getInt(key) } catch (_: Exception) { null }
1886
+ }
1887
+
1690
1888
  // ==================== SMS OTP Methods ====================
1691
1889
 
1692
1890
  @ReactMethod
@@ -1715,14 +1913,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1715
1913
  callbackSuccess = { event, result ->
1716
1914
  Log.d(TAG, "✅ sendOtp() success")
1717
1915
  val (eventMap, promiseMap) = createSeparateMaps { map ->
1718
- map.putString("event", event.name.toString())
1719
- result?.let {
1720
- val dataMap = Arguments.createMap()
1721
- it.customData?.forEach { (key, value) ->
1722
- dataMap.putString(key, value.toString())
1723
- }
1724
- map.putMap("data", dataMap)
1725
- }
1916
+ map.putCustomData(result?.customData)
1726
1917
  }
1727
1918
  sendEvent("onSmsOtpSendSuccess", eventMap)
1728
1919
  promise.resolve(promiseMap)
@@ -1776,14 +1967,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1776
1967
  callbackSuccess = { event, result ->
1777
1968
  Log.d(TAG, "✅ verifyOtp() success")
1778
1969
  val (eventMap, promiseMap) = createSeparateMaps { map ->
1779
- map.putString("event", event.name.toString())
1780
- result?.let {
1781
- val dataMap = Arguments.createMap()
1782
- it.customData?.forEach { (key, value) ->
1783
- dataMap.putString(key, value.toString())
1784
- }
1785
- map.putMap("data", dataMap)
1786
- }
1970
+ map.putCustomData(result?.customData)
1787
1971
  }
1788
1972
  sendEvent("onSmsOtpVerifySuccess", eventMap)
1789
1973
  promise.resolve(promiseMap)
@@ -1835,14 +2019,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1835
2019
  callbackSuccess = { event, result ->
1836
2020
  Log.d(TAG, "✅ resendOtp() success")
1837
2021
  val (eventMap, promiseMap) = createSeparateMaps { map ->
1838
- map.putString("event", event.name.toString())
1839
- result?.let {
1840
- val dataMap = Arguments.createMap()
1841
- it.customData?.forEach { (key, value) ->
1842
- dataMap.putString(key, value.toString())
1843
- }
1844
- map.putMap("data", dataMap)
1845
- }
2022
+ map.putCustomData(result?.customData)
1846
2023
  }
1847
2024
  sendEvent("onSmsOtpResendSuccess", eventMap)
1848
2025
  promise.resolve(promiseMap)
@@ -1,20 +1,17 @@
1
1
  package finos.sdk.ekyc
2
2
 
3
3
  import androidx.fragment.app.FragmentManager
4
- import finos.sdk.ekyc.ui.eKYCFinOSUI
5
4
 
5
+ // SDK 1.5.2: Exit confirmation is now handled natively via ExitConfirmConfig.
6
+ // This manager is kept as a no-op for backward API compatibility.
6
7
  object SDKeKYCExitHandlerManager {
7
8
  var uiListener: ((FragmentManager) -> Unit)? = null
8
9
  var pendingConfirm: (() -> Unit)? = null
9
10
  var pendingCancel: (() -> Unit)? = null
10
11
 
11
12
  fun register() {
12
- eKYCFinOSUI.setExitConfirmHandler { fm, onConfirm, onCancel ->
13
- // Lưu callback thông báo cho UI layer (Native/JS/Dart)
14
- this.pendingConfirm = onConfirm
15
- this.pendingCancel = onCancel
16
- uiListener?.invoke(fm)
17
- }
13
+ // No-op: setExitConfirmHandler was removed in SDK 1.5.2.
14
+ // Exit confirmation is now driven by ExitConfirmConfig passed to startEkycUI/startLiveness.
18
15
  }
19
16
 
20
17
  fun resolve(action: String) {
@@ -5,8 +5,9 @@ import { C06Config } from './src/types/ekycC06Type';
5
5
  import { OcrConfig } from './src/types/ekycOCRType';
6
6
  import { LivenessConfig, SDKFaceDetectStatus, LivenessSuccessEvent } from './src/types/ekycLivenessType';
7
7
  import { FaceServiceConfig, FaceCompareSuccessEvent } from './src/types/ekycFaceType';
8
- import { SmsOtpConfig, SmsOtpResult, SmsOtpError } from './src/types/ekycSmsOtpType';
8
+ import { SmsOtpConfig, SmsOtpError, SendOtpResponse, VerifyOtpResponse, ResendOtpResponse } from './src/types/ekycSmsOtpType';
9
9
  import { ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError, AuthorizeInfo, ESignPdfResult, ESignApiResponse } from './src/types/ekycESignType';
10
+ import { ExitConfirmConfig } from './src/types/ekycExitConfirmType';
10
11
  export declare const SDK_VERSION: string;
11
12
  export declare const SDK_NAME: string;
12
13
  declare class SDKeKYC {
@@ -29,14 +30,10 @@ declare class SDKeKYC {
29
30
  startOcr(config: OcrConfig): Promise<SDKEkycResultStringWithEvent>;
30
31
  startNfcScan(config: NfcConfig): Promise<SDKEkycResultStringWithEvent>;
31
32
  checkC06(config: C06Config): Promise<SDKEkycResultStringWithEvent>;
32
- startLiveness(config: LivenessConfig): Promise<LivenessSuccessEvent>;
33
+ startLiveness(config: LivenessConfig, exitConfirmConfig?: ExitConfirmConfig): Promise<LivenessSuccessEvent>;
33
34
  startFaceCompare(config: FaceServiceConfig): Promise<FaceCompareSuccessEvent>;
34
35
  onResume(): void;
35
36
  onPause(): void;
36
- registerExitHandler(): Promise<boolean>;
37
- resolveExit(action: 'CONFIRM' | 'CANCEL' | 'CLOSE'): Promise<boolean>;
38
- showRNExitSheet(bundleName: string, initialProps: any): Promise<boolean>;
39
- showNativeExitDialog(config: any): Promise<any>;
40
37
  onNfcScanStart(callback: (data: SDKEkycResultWithEvent) => void): EmitterSubscription | null;
41
38
  onNfcScanSuccess(callback: (data: SDKEkycResultStringWithEvent) => void): EmitterSubscription | null;
42
39
  onNfcError(callback: (error: NfcError) => void): EmitterSubscription | null;
@@ -50,14 +47,13 @@ declare class SDKeKYC {
50
47
  onFaceCompareError(callback: (error: any) => void): EmitterSubscription | null;
51
48
  onEkycUISuccess(callback: (data: any) => void): EmitterSubscription | null;
52
49
  onEkycUIError(callback: (error: any) => void): EmitterSubscription | null;
53
- onShowExitConfirm(callback: () => void): EmitterSubscription | null;
54
50
  removeAllListeners(): void;
55
- sendOtp(config: SmsOtpConfig): Promise<SmsOtpResult>;
56
- verifyOtp(config: SmsOtpConfig, otpCode: string): Promise<SmsOtpResult>;
57
- resendOtp(config: SmsOtpConfig): Promise<SmsOtpResult>;
58
- onSmsOtpSendSuccess(callback: (data: SmsOtpResult) => void): EmitterSubscription | null;
59
- onSmsOtpVerifySuccess(callback: (data: SmsOtpResult) => void): EmitterSubscription | null;
60
- onSmsOtpResendSuccess(callback: (data: SmsOtpResult) => void): EmitterSubscription | null;
51
+ sendOtp(config: SmsOtpConfig): Promise<SendOtpResponse>;
52
+ verifyOtp(config: SmsOtpConfig, otpCode: string): Promise<VerifyOtpResponse>;
53
+ resendOtp(config: SmsOtpConfig): Promise<ResendOtpResponse>;
54
+ onSmsOtpSendSuccess(callback: (data: SendOtpResponse) => void): EmitterSubscription | null;
55
+ onSmsOtpVerifySuccess(callback: (data: VerifyOtpResponse) => void): EmitterSubscription | null;
56
+ onSmsOtpResendSuccess(callback: (data: ResendOtpResponse) => void): EmitterSubscription | null;
61
57
  onSmsOtpError(callback: (error: SmsOtpError) => void): EmitterSubscription | null;
62
58
  initializeESign(finosToken?: string | null, isProd?: boolean): Promise<ESignInitResult>;
63
59
  getSdkToken(identity: string, name: string, deviceId: string): Promise<string>;
@@ -199,10 +195,12 @@ declare class SDKeKYC {
199
195
  };
200
196
  captureButtonColor?: number;
201
197
  captureButtonDisabledColor?: number;
202
- }): Promise<StartEkycUIResult>;
198
+ }, exitConfirmConfig?: ExitConfirmConfig): Promise<StartEkycUIResult>;
203
199
  }
204
200
  declare const sdkEKYC: SDKeKYC;
205
201
  export { SDKeKYC };
206
202
  export { SDKFaceDetectStatus };
207
203
  export { AuthorizationStatus } from './src/types/ekycESignType';
204
+ export { ExitConfirmGradientOrientation } from './src/types/ekycExitConfirmType';
205
+ export type { ExitConfirmConfig, ExitConfirmIconProps, ExitConfirmTitleProps, ExitConfirmContentProps, ExitConfirmButtonProps, ExitConfirmTextStyles, ExitConfirmViewStyle, } from './src/types/ekycExitConfirmType';
208
206
  export default sdkEKYC;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AuthorizationStatus = exports.SDKFaceDetectStatus = exports.SDKeKYC = exports.SDK_NAME = exports.SDK_VERSION = void 0;
6
+ exports.ExitConfirmGradientOrientation = exports.AuthorizationStatus = exports.SDKFaceDetectStatus = exports.SDKeKYC = exports.SDK_NAME = exports.SDK_VERSION = void 0;
7
7
  const react_native_1 = require("react-native");
8
8
  const ekycType_1 = require("./src/types/ekycType");
9
9
  const ekycLivenessType_1 = require("./src/types/ekycLivenessType");
@@ -206,14 +206,17 @@ class SDKeKYC {
206
206
  throw error;
207
207
  }
208
208
  }
209
- async startLiveness(config) {
209
+ async startLiveness(config, exitConfirmConfig) {
210
210
  var _a, _b, _c;
211
211
  this.validateConfig(config, ['appKey', 'selfieImage', 'transactionId']);
212
212
  const nativeModule = this.ensureNativeModule();
213
213
  try {
214
214
  // Convert SDKFaceDetectStatus enum array to string array
215
215
  const customActionsStrings = (_b = (_a = config.customActions) === null || _a === void 0 ? void 0 : _a.map(action => String(action))) !== null && _b !== void 0 ? _b : undefined;
216
- return await nativeModule.startLiveness(config.appKey, config.selfieImage, (_c = config.transactionId) !== null && _c !== void 0 ? _c : '', config.isActiveLiveness, config.isShowCameraFont, customActionsStrings, config.activeActionCount, config.forceCaptureTimeout, config.isActiveLivenessColor);
216
+ const exitConfirmConfigJson = exitConfirmConfig
217
+ ? JSON.stringify(exitConfirmConfig)
218
+ : '{}';
219
+ return await nativeModule.startLiveness(config.appKey, config.selfieImage, (_c = config.transactionId) !== null && _c !== void 0 ? _c : '', config.isActiveLiveness, config.isShowCameraFont, customActionsStrings, config.activeActionCount, config.forceCaptureTimeout, config.isActiveLivenessColor, exitConfirmConfigJson);
217
220
  }
218
221
  catch (error) {
219
222
  console.error('Liveness Error:', error);
@@ -242,47 +245,6 @@ class SDKeKYC {
242
245
  const nativeModule = this.ensureNativeModule();
243
246
  nativeModule.onPause();
244
247
  }
245
- // Exit Handler Methods
246
- async registerExitHandler() {
247
- const nativeModule = this.ensureNativeModule();
248
- try {
249
- return await nativeModule.registerExitHandler();
250
- }
251
- catch (error) {
252
- console.error('registerExitHandler Error:', error);
253
- throw error;
254
- }
255
- }
256
- async resolveExit(action) {
257
- const nativeModule = this.ensureNativeModule();
258
- try {
259
- return await nativeModule.resolveExit(action);
260
- }
261
- catch (error) {
262
- console.error('resolveExit Error:', error);
263
- throw error;
264
- }
265
- }
266
- async showRNExitSheet(bundleName, initialProps) {
267
- const nativeModule = this.ensureNativeModule();
268
- try {
269
- return await nativeModule.showRNExitSheet(bundleName, initialProps);
270
- }
271
- catch (error) {
272
- console.error('showRNExitSheet Error:', error);
273
- throw error;
274
- }
275
- }
276
- async showNativeExitDialog(config) {
277
- const nativeModule = this.ensureNativeModule();
278
- try {
279
- return await nativeModule.showNativeExitDialog(config);
280
- }
281
- catch (error) {
282
- console.error('showNativeExitDialog Error:', error);
283
- throw error;
284
- }
285
- }
286
248
  // Event listeners
287
249
  onNfcScanStart(callback) {
288
250
  try {
@@ -493,22 +455,6 @@ class SDKeKYC {
493
455
  return null;
494
456
  }
495
457
  }
496
- onShowExitConfirm(callback) {
497
- try {
498
- const emitter = this.ensureEventEmitter();
499
- if (!emitter) {
500
- console.error('❌ Event emitter not available for onShowExitConfirm');
501
- return null;
502
- }
503
- const listener = emitter.addListener('onShowExitConfirm', callback);
504
- this.listeners.push(listener);
505
- return listener;
506
- }
507
- catch (error) {
508
- console.error('Failed to add onShowExitConfirm listener:', error);
509
- return null;
510
- }
511
- }
512
458
  removeAllListeners() {
513
459
  this.listeners.forEach(listener => listener.remove());
514
460
  this.listeners = [];
@@ -1089,7 +1035,7 @@ class SDKeKYC {
1089
1035
  * data.ekycStateModel.eKYCFileModel.imageFace → result.imageFace (base64),
1090
1036
  * result.imageFacePath (file path), result.imageOcrFront / imageOcrBack, result.transactionId.
1091
1037
  */
1092
- async startEkycUI(appKey, flowSDK, language, transactionId, appKeyConfig, optionConfig, styleConfig) {
1038
+ async startEkycUI(appKey, flowSDK, language, transactionId, appKeyConfig, optionConfig, styleConfig, exitConfirmConfig) {
1093
1039
  if (!this.isInitialized) {
1094
1040
  throw new Error('SDK is not initialized. Please call initSdkEkyc() first.');
1095
1041
  }
@@ -1098,12 +1044,14 @@ class SDKeKYC {
1098
1044
  console.log('🔧 OptionConfig:', optionConfig);
1099
1045
  console.log('🔑 AppKeyConfig:', appKeyConfig);
1100
1046
  console.log('🎨 StyleConfig:', styleConfig);
1047
+ console.log('🚪 ExitConfirmConfig:', exitConfirmConfig);
1101
1048
  const flowSDKJson = JSON.stringify(flowSDK);
1102
1049
  const optionConfigJson = optionConfig ? JSON.stringify(optionConfig) : '{}';
1103
1050
  const appKeyConfigJson = JSON.stringify(appKeyConfig);
1104
1051
  const styleConfigJson = styleConfig ? JSON.stringify(styleConfig) : '{}';
1052
+ const exitConfirmConfigJson = exitConfirmConfig ? JSON.stringify(exitConfirmConfig) : '{}';
1105
1053
  const nativeModule = this.ensureNativeModule();
1106
- const result = (await nativeModule.startEkycUI(appKey, flowSDKJson, language, transactionId, optionConfigJson, appKeyConfigJson, styleConfigJson));
1054
+ const result = (await nativeModule.startEkycUI(appKey, flowSDKJson, language, transactionId, optionConfigJson, appKeyConfigJson, styleConfigJson, exitConfirmConfigJson));
1107
1055
  console.log('✅ SdkEkycUI started successfully');
1108
1056
  return result;
1109
1057
  }
@@ -1118,4 +1066,6 @@ exports.SDKeKYC = SDKeKYC;
1118
1066
  const sdkEKYC = new SDKeKYC();
1119
1067
  var ekycESignType_1 = require("./src/types/ekycESignType");
1120
1068
  Object.defineProperty(exports, "AuthorizationStatus", { enumerable: true, get: function () { return ekycESignType_1.AuthorizationStatus; } });
1069
+ var ekycExitConfirmType_1 = require("./src/types/ekycExitConfirmType");
1070
+ Object.defineProperty(exports, "ExitConfirmGradientOrientation", { enumerable: true, get: function () { return ekycExitConfirmType_1.ExitConfirmGradientOrientation; } });
1121
1071
  exports.default = sdkEKYC;
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@finos_sdk/sdk-ekyc",
3
+ "version": "1.5.3",
4
+ "description": "React Native SDK for eKYC - Vietnamese CCCD NFC reading, OCR, Liveness detection, Face matching, and C06, eSign, SmsOTP residence verification",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "react-native.config.js",
10
+ "android/src/main/java",
11
+ "android/build.gradle",
12
+ "android/settings.gradle",
13
+ "android/gradle.properties",
14
+ "android/gradle/wrapper/**",
15
+ "android/gradlew",
16
+ "android/gradlew.bat",
17
+ "android/consumer-rules.pro",
18
+ "ios/**",
19
+ "finos-ekyc-sdk.podspec",
20
+ "src/**"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/finosvn/finos.ekyc.sdk.git"
25
+ },
26
+ "author": "FinOS",
27
+ "license": "MIT",
28
+ "bugs": {
29
+ "url": "https://github.com/finosvn/finos.ekyc.sdk/issues"
30
+ },
31
+ "homepage": "https://github.com/finosvn/finos.ekyc.sdk#readme",
32
+ "keywords": [
33
+ "react-native",
34
+ "ekyc",
35
+ "nfc",
36
+ "ocr",
37
+ "liveness",
38
+ "face-matching",
39
+ "vietnamese",
40
+ "cccd",
41
+ "identity-verification",
42
+ "finos-sdk",
43
+ "android",
44
+ "typescript"
45
+ ],
46
+ "scripts": {
47
+ "clear": "rm -rf node_modules dist package-lock.json && npm cache clean --force && (cd android && ./gradlew clean 2>/dev/null) || true",
48
+ "npm-install": "npm install",
49
+ "npm-install-legacy": "npm install --legacy-peer-deps",
50
+ "build": "tsc && mkdir -p dist && cp package.json dist/",
51
+ "publish-sdk-local": "npm run build && npm pack",
52
+ "publish-sdk": "npm run build && npm publish --access public",
53
+ "publish-sdk-version": "npm run build && npm version patch --force && npm publish --access public"
54
+ },
55
+ "peerDependencies": {
56
+ "react": ">=18.0.0",
57
+ "react-native": ">=0.70.0"
58
+ },
59
+ "dependencies": {
60
+ "reflect-metadata": "^0.2.1",
61
+ "tsyringe": "^4.10.0"
62
+ },
63
+ "devDependencies": {
64
+ "@babel/core": "^7.25.2",
65
+ "@babel/preset-env": "^7.25.3",
66
+ "@babel/runtime": "^7.25.0",
67
+ "@react-native-community/cli": "16.0.3",
68
+ "@react-native/babel-preset": "0.77.0",
69
+ "@react-native/eslint-config": "0.77.0",
70
+ "@react-native/metro-config": "0.77.0",
71
+ "@react-native/typescript-config": "0.77.0",
72
+ "@types/react": "18.2.6",
73
+ "@types/react-test-renderer": "18.0.0",
74
+ "babel-jest": "^29.6.3",
75
+ "eslint": "^8.19.0",
76
+ "jest": "^29.6.3",
77
+ "prettier": "2.8.8",
78
+ "react": "18.2.0",
79
+ "react-native": "0.73.0",
80
+ "react-test-renderer": "18.2.0",
81
+ "typescript": "^5.0.4"
82
+ },
83
+ "engines": {
84
+ "node": ">=18"
85
+ }
86
+ }
package/dist/index.d.ts CHANGED
@@ -21,6 +21,8 @@ export type { LivenessError } from './src/types/ekycLivenessType';
21
21
  export type { FaceCompareError } from './src/types/ekycFaceType';
22
22
  export type { SDKTransactionResponse } from './src/types/ekycTransactionType';
23
23
  export type { SmsOtpConfig, SmsOtpResult, SmsOtpError } from './src/types/ekycSmsOtpType';
24
+ export type { ExitConfirmConfig, ExitConfirmIconProps, ExitConfirmTitleProps, ExitConfirmContentProps, ExitConfirmButtonProps, ExitConfirmTextStyles, ExitConfirmViewStyle, } from './src/types/ekycExitConfirmType';
25
+ export { ExitConfirmGradientOrientation } from './src/types/ekycExitConfirmType';
24
26
  export type { ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError, ESignAuthenticateResult, UserEsignModel, AuthorizeInfo, ESignPdfResult, ESignApiResponse, } from './src/types/ekycESignType';
25
27
  export { AuthorizationStatus } from './src/types/ekycESignType';
26
28
  export { parseNfcResponse } from './src/utils/utils';