@finos_sdk/sdk-ekyc 1.5.0 → 1.5.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/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.2"
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
@@ -66,7 +66,10 @@ import java.io.FileInputStream
66
66
  import java.io.InputStream
67
67
  import java.util.Date
68
68
  import android.app.Activity
69
+ import android.app.Application
70
+ import android.os.Bundle
69
71
  import android.view.ViewGroup
72
+ import java.lang.ref.WeakReference
70
73
 
71
74
  @ReactModule(name = EKYCModule.NAME)
72
75
  class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
@@ -74,10 +77,71 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
74
77
  companion object {
75
78
  const val NAME = "EKYCModule"
76
79
  private const val TAG = "EKYCModule"
80
+
81
+ // Full class name của SDK activity duy nhất
82
+ private const val SDK_EKYC_ACTIVITY = "finos.sdk.ekyc.sdkui.SDKeKYCActivity"
77
83
  }
78
84
 
79
85
  override fun getName(): String = NAME
80
86
 
87
+ /**
88
+ * WeakReference tới SDK activity đang foreground.
89
+ * Được set/clear bởi ActivityLifecycleCallbacks khi SDK activity resume/pause.
90
+ * @Volatile: viết từ UI thread (lifecycle callback), đọc từ JS bridge thread (showRNExitSheet).
91
+ * WeakReference để tránh memory leak nếu activity bị destroy mà chưa clear.
92
+ */
93
+ @Volatile
94
+ private var activeSdkActivity: WeakReference<Activity>? = null
95
+
96
+ private val sdkActivityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
97
+ override fun onActivityResumed(activity: Activity) {
98
+ if (isSDKActivity(activity)) {
99
+ activeSdkActivity = WeakReference(activity)
100
+ Log.d(TAG, "📌 SDK Activity resumed: ${activity.javaClass.simpleName}")
101
+ }
102
+ }
103
+ override fun onActivityPaused(activity: Activity) {
104
+ if (activeSdkActivity?.get() == activity) {
105
+ activeSdkActivity = null
106
+ Log.d(TAG, "📌 SDK Activity paused: ${activity.javaClass.simpleName}")
107
+ }
108
+ }
109
+ override fun onActivityDestroyed(activity: Activity) {
110
+ if (activeSdkActivity?.get() == activity) {
111
+ activeSdkActivity = null
112
+ Log.d(TAG, "📌 SDK Activity destroyed: ${activity.javaClass.simpleName}")
113
+ }
114
+ }
115
+ override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
116
+ override fun onActivityStarted(activity: Activity) {}
117
+ override fun onActivityStopped(activity: Activity) {}
118
+ override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
119
+ }
120
+
121
+ private fun isSDKActivity(activity: Activity): Boolean {
122
+ return activity.javaClass.name == SDK_EKYC_ACTIVITY
123
+ }
124
+
125
+ init {
126
+ // Đăng ký lifecycle callback để track SDK activity tự động
127
+ val app = reactContext.applicationContext as? Application
128
+ app?.registerActivityLifecycleCallbacks(sdkActivityLifecycleCallbacks)
129
+ ?: Log.w(TAG, "⚠️ Could not register ActivityLifecycleCallbacks")
130
+ }
131
+
132
+ /**
133
+ * Lấy SDK activity đang active, fallback về getTrueCurrentActivity() nếu không có.
134
+ */
135
+ private fun getSDKActivity(): Activity? {
136
+ val sdk = activeSdkActivity?.get()
137
+ if (sdk != null && !sdk.isFinishing && !sdk.isDestroyed) {
138
+ Log.d(TAG, "✅ Using tracked SDK Activity: ${sdk.javaClass.simpleName}")
139
+ return sdk
140
+ }
141
+ Log.d(TAG, "⚠️ No active SDK activity tracked, falling back to getTrueCurrentActivity")
142
+ return getTrueCurrentActivity()
143
+ }
144
+
81
145
  /**
82
146
  * Reference tới BottomSheetDialog hiện đang hiển thị.
83
147
  * @Volatile: resolveExit() chạy trên JS bridge thread, đọc field này được viết bởi UI thread.
@@ -199,9 +263,8 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
199
263
 
200
264
  @ReactMethod
201
265
  fun showRNExitSheet(bundleName: String, initialProps: ReadableMap, promise: Promise) {
202
- // Fix: Move activity detection to UI thread to avoid race conditions and ensure correct window attachment
203
266
  Handler(Looper.getMainLooper()).post {
204
- val activity = getTrueCurrentActivity() ?: run {
267
+ val activity = getSDKActivity() ?: run {
205
268
  Log.e(TAG, "❌ showRNExitSheet failed: No visible activity found")
206
269
  promise.reject("NO_ACTIVITY", "No visible activity found")
207
270
  return@post
@@ -926,6 +989,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
926
989
  activeActionCount: Int?,
927
990
  forceCaptureTimeout: Double?,
928
991
  isActiveLivenessColor: Boolean?,
992
+ exitConfirmConfigJson: String?,
929
993
  promise: Promise
930
994
  ) {
931
995
  Log.d(TAG, "▶️ startLiveness() called")
@@ -971,11 +1035,13 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
971
1035
  selfieImage = imageFile,
972
1036
  transactionId = transactionId
973
1037
  )
1038
+ val exitConfirmConfig = parseExitConfirmConfig(exitConfirmConfigJson)
974
1039
  val ekycConfig =
975
1040
  EKYCConfigSDK(
976
1041
  appKey = AppKeyConfig(appKey),
977
1042
  sdkType = SDKType.LIVENESS,
978
- livenessConfig = livenessConfig
1043
+ livenessConfig = livenessConfig,
1044
+ exitConfirmConfig = exitConfirmConfig
979
1045
  )
980
1046
  eKYCFinOSLiveness.startEkyc(
981
1047
  ekycConfigSDK = ekycConfig,
@@ -1231,6 +1297,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1231
1297
  optionConfigJson: String, // JSON string for option config
1232
1298
  appKeyConfigJson: String, // JSON string for app key config
1233
1299
  styleConfigJson: String, // JSON string for style config
1300
+ exitConfirmConfigJson: String?, // JSON string for exit confirm bottom sheet config
1234
1301
  promise: Promise
1235
1302
  ) {
1236
1303
  Log.d(TAG, "▶️ startEkycUI() called")
@@ -1285,6 +1352,9 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1285
1352
  )
1286
1353
  } else null
1287
1354
 
1355
+ // Parse exit confirm bottom sheet config (optional)
1356
+ val exitConfirmConfig = parseExitConfirmConfig(exitConfirmConfigJson)
1357
+
1288
1358
  // Create EKYCConfigSDK like SDKeKYCActivity / MainActivity.kt
1289
1359
  val ekycConfigSDK = EKYCConfigSDK(
1290
1360
  appKey = appKeyConfig,
@@ -1292,7 +1362,8 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1292
1362
  livenessConfig = livenessConfig,
1293
1363
  styleConfig = styleConfig,
1294
1364
  appIDType = appIDType,
1295
- flowSDK = finalFlow
1365
+ flowSDK = finalFlow,
1366
+ exitConfirmConfig = exitConfirmConfig
1296
1367
  )
1297
1368
 
1298
1369
  eKYCFinOSUI.startEkyc(
@@ -1624,6 +1695,174 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1624
1695
  }
1625
1696
  }
1626
1697
 
1698
+ // ==================== ExitConfirmConfig parsing ====================
1699
+
1700
+ /**
1701
+ * Parse JSON từ React Native sang ExitConfirmConfig của SDK.
1702
+ * Trả null nếu json rỗng / lỗi — SDK sẽ dùng giá trị mặc định.
1703
+ */
1704
+ private fun parseExitConfirmConfig(json: String?): ExitConfirmConfig? {
1705
+ if (json.isNullOrBlank() || json == "{}") return null
1706
+ return try {
1707
+ val obj = JSONObject(json)
1708
+ ExitConfirmConfig(
1709
+ iconProps = parseExitIconProps(obj.optJSONObject("iconProps")),
1710
+ titleProps = parseExitTitleProps(obj.optJSONObject("titleProps")),
1711
+ contentProps = parseExitContentProps(obj.optJSONObject("contentProps")),
1712
+ confirmButtonProps = parseExitButtonProps(obj.optJSONObject("confirmButtonProps")),
1713
+ cancelButtonProps = parseExitButtonProps(obj.optJSONObject("cancelButtonProps")),
1714
+ )
1715
+ } catch (e: Exception) {
1716
+ Log.e(TAG, "parseExitConfirmConfig failed: ${e.message}", e)
1717
+ null
1718
+ }
1719
+ }
1720
+
1721
+ private fun parseExitIconProps(obj: JSONObject?): ExitConfirmConfig.IconProps? {
1722
+ if (obj == null) return null
1723
+ val iconResName = obj.optStringOrNull("iconResName")
1724
+ val iconResId: Int? = iconResName?.let { resolveDrawableId(it) }
1725
+ val iconViewStyle = parseExitViewStyle(obj.optJSONObject("iconViewStyle"))
1726
+ if (iconResId == null && iconViewStyle == null) return null
1727
+ return ExitConfirmConfig.IconProps(
1728
+ icon = iconResId,
1729
+ iconViewStyle = iconViewStyle,
1730
+ )
1731
+ }
1732
+
1733
+ private fun parseExitTitleProps(obj: JSONObject?): ExitConfirmConfig.TitleProps? {
1734
+ if (obj == null) return null
1735
+ val title = obj.optStringOrNull("title")
1736
+ val titleStyles = parseExitTextStyles(obj.optJSONObject("titleStyles"))
1737
+ if (title == null && titleStyles == null) return null
1738
+ return ExitConfirmConfig.TitleProps(title = title, titleStyles = titleStyles)
1739
+ }
1740
+
1741
+ private fun parseExitContentProps(obj: JSONObject?): ExitConfirmConfig.ContentProps? {
1742
+ if (obj == null) return null
1743
+ val content = obj.optStringOrNull("content")
1744
+ val contentStyles = parseExitTextStyles(obj.optJSONObject("contentStyles"))
1745
+ if (content == null && contentStyles == null) return null
1746
+ return ExitConfirmConfig.ContentProps(content = content, contentStyles = contentStyles)
1747
+ }
1748
+
1749
+ private fun parseExitButtonProps(obj: JSONObject?): ExitConfirmConfig.ButtonProps? {
1750
+ if (obj == null) return null
1751
+ val title = obj.optStringOrNull("buttonTitle")
1752
+ val textStyles = parseExitTextStyles(obj.optJSONObject("buttonTextStyles"))
1753
+ val viewStyles = parseExitViewStyle(obj.optJSONObject("buttonStyles"))
1754
+ if (title == null && textStyles == null && viewStyles == null) return null
1755
+ return ExitConfirmConfig.ButtonProps(
1756
+ buttonTitle = title,
1757
+ buttonTextStyles = textStyles,
1758
+ buttonStyles = viewStyles,
1759
+ )
1760
+ }
1761
+
1762
+ private fun parseExitTextStyles(obj: JSONObject?): ExitConfirmConfig.TextStyles? {
1763
+ if (obj == null) return null
1764
+ val textColor = obj.optStringOrNull("textColor")
1765
+ val textSize = obj.optIntOrNull("textSize")
1766
+ val textFont = obj.optStringOrNull("textFont")
1767
+ val textStyle = obj.optIntOrNull("textStyle")
1768
+ val textAlign = obj.optIntOrNull("textAlign")
1769
+ if (textColor == null && textSize == null && textFont == null && textStyle == null && textAlign == null) {
1770
+ return null
1771
+ }
1772
+ return ExitConfirmConfig.TextStyles(
1773
+ textColor = textColor,
1774
+ textSize = textSize,
1775
+ textFont = textFont,
1776
+ textStyle = textStyle,
1777
+ textAlign = textAlign,
1778
+ )
1779
+ }
1780
+
1781
+ private fun parseExitViewStyle(obj: JSONObject?): ExitConfirmConfig.ViewStyle? {
1782
+ if (obj == null) return null
1783
+ val backgroundColor = obj.optStringOrNull("backgroundColor")
1784
+ val gradientColors = obj.optJSONArray("backgroundGradientColors")?.let { arr ->
1785
+ val list = mutableListOf<String>()
1786
+ for (i in 0 until arr.length()) {
1787
+ arr.optString(i, null)?.takeIf { it.isNotBlank() }?.let(list::add)
1788
+ }
1789
+ list.takeIf { it.isNotEmpty() }
1790
+ }
1791
+ val gradientPositions = obj.optJSONArray("backgroundGradientPositions")?.let { arr ->
1792
+ val list = mutableListOf<Float>()
1793
+ for (i in 0 until arr.length()) list.add(arr.optDouble(i, 0.0).toFloat())
1794
+ list.takeIf { it.isNotEmpty() }
1795
+ }
1796
+ val orientation = obj.optStringOrNull("backgroundGradientOrientation")?.let {
1797
+ try { ExitConfirmConfig.GradientOrientation.valueOf(it) } catch (_: Exception) { null }
1798
+ }
1799
+ val width = obj.optIntOrNull("width")
1800
+ val height = obj.optIntOrNull("height")
1801
+ val marginTop = obj.optIntOrNull("marginTop")
1802
+ val marginBottom = obj.optIntOrNull("marginBottom")
1803
+ val marginStart = obj.optIntOrNull("marginStart")
1804
+ val marginEnd = obj.optIntOrNull("marginEnd")
1805
+ val paddingTop = obj.optIntOrNull("paddingTop")
1806
+ val paddingBottom = obj.optIntOrNull("paddingBottom")
1807
+ val paddingStart = obj.optIntOrNull("paddingStart")
1808
+ val paddingEnd = obj.optIntOrNull("paddingEnd")
1809
+ val gravity = obj.optIntOrNull("gravity")
1810
+ val cornerRadius = if (obj.has("cornerRadius") && !obj.isNull("cornerRadius")) {
1811
+ obj.optDouble("cornerRadius", Double.NaN).takeIf { !it.isNaN() }?.toFloat()
1812
+ } else null
1813
+
1814
+ val anySet = backgroundColor != null || gradientColors != null || gradientPositions != null ||
1815
+ orientation != null || width != null || height != null ||
1816
+ marginTop != null || marginBottom != null || marginStart != null || marginEnd != null ||
1817
+ paddingTop != null || paddingBottom != null || paddingStart != null || paddingEnd != null ||
1818
+ gravity != null || cornerRadius != null
1819
+ if (!anySet) return null
1820
+
1821
+ return ExitConfirmConfig.ViewStyle(
1822
+ backgroundColor = backgroundColor,
1823
+ backgroundGradientColors = gradientColors,
1824
+ backgroundGradientPositions = gradientPositions,
1825
+ backgroundGradientOrientation = orientation,
1826
+ width = width,
1827
+ height = height,
1828
+ marginTop = marginTop,
1829
+ marginBottom = marginBottom,
1830
+ marginStart = marginStart,
1831
+ marginEnd = marginEnd,
1832
+ paddingTop = paddingTop,
1833
+ paddingBottom = paddingBottom,
1834
+ paddingStart = paddingStart,
1835
+ paddingEnd = paddingEnd,
1836
+ gravity = gravity,
1837
+ cornerRadius = cornerRadius,
1838
+ )
1839
+ }
1840
+
1841
+ /** Resolve drawable resource id từ tên (vd "ic_warning"). Trả null nếu host app không có. */
1842
+ private fun resolveDrawableId(name: String): Int? {
1843
+ return try {
1844
+ val ctx = reactApplicationContext
1845
+ val id = ctx.resources.getIdentifier(name, "drawable", ctx.packageName)
1846
+ if (id != 0) id else null
1847
+ } catch (e: Exception) {
1848
+ Log.w(TAG, "resolveDrawableId('$name') failed: ${e.message}")
1849
+ null
1850
+ }
1851
+ }
1852
+
1853
+ /** `optString` của org.json trả "" thay vì null khi key missing — wrap để có null thực sự. */
1854
+ private fun JSONObject.optStringOrNull(key: String): String? {
1855
+ if (!has(key) || isNull(key)) return null
1856
+ val v = optString(key, "")
1857
+ return v.takeIf { it.isNotEmpty() }
1858
+ }
1859
+
1860
+ private fun JSONObject.optIntOrNull(key: String): Int? {
1861
+ if (!has(key) || isNull(key)) return null
1862
+ return optInt(key, Int.MIN_VALUE).takeIf { it != Int.MIN_VALUE }
1863
+ ?: try { getInt(key) } catch (_: Exception) { null }
1864
+ }
1865
+
1627
1866
  // ==================== SMS OTP Methods ====================
1628
1867
 
1629
1868
  @ReactMethod
@@ -2733,6 +2972,10 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
2733
2972
  override fun onCatalystInstanceDestroy() {
2734
2973
  super.onCatalystInstanceDestroy()
2735
2974
  SDKeKYCExitHandlerManager.uiListener = null
2975
+ // Unregister lifecycle callback để tránh memory leak
2976
+ val app = reactApplicationContext.applicationContext as? Application
2977
+ app?.unregisterActivityLifecycleCallbacks(sdkActivityLifecycleCallbacks)
2978
+ activeSdkActivity = null
2736
2979
  // Dismiss sheet nếu vẫn đang hiển thị khi RN catalyst instance destroy
2737
2980
  val sheet = currentExitSheet
2738
2981
  currentExitSheet = null
@@ -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) {
@@ -7,6 +7,7 @@ import { LivenessConfig, SDKFaceDetectStatus, LivenessSuccessEvent } from './src
7
7
  import { FaceServiceConfig, FaceCompareSuccessEvent } from './src/types/ekycFaceType';
8
8
  import { SmsOtpConfig, SmsOtpResult, SmsOtpError } 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,7 +47,6 @@ 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
51
  sendOtp(config: SmsOtpConfig): Promise<SmsOtpResult>;
56
52
  verifyOtp(config: SmsOtpConfig, otpCode: string): Promise<SmsOtpResult>;
@@ -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;
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';
package/dist/index.js CHANGED
@@ -32,14 +32,10 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.OCR_USE_NEW_ID_DOCUMENT_2 = exports.OCR_USE_NEW_ID_DOCUMENT_1 = exports.OCR_FAKE_MRZ = exports.OCR_INVALID_GENDER_CODE = exports.OCR_INVALID_ID_CARD = exports.OCR_GLARE_ID_CARD = exports.OCR_BLURRY_ID_CARD = exports.OCR_CUT_CORNER_ID_CARD = exports.OCR_CANNOT_RECOGNIZE_PORTRAIT = exports.OCR_ID_CARD_FROM_OTHER_DEVICE = exports.OCR_NOT_ORIGINAL_ID_CARD = exports.OCR_MISSING_ID_CARD_PART = exports.OCR_CANNOT_GET_ISSUE_PLACE = exports.OCR_CANNOT_GET_GENDER = exports.OCR_CANNOT_GET_HOMETOWN = exports.OCR_CANNOT_GET_RESIDENCE = exports.OCR_CANNOT_GET_ISSUE_DATE = exports.OCR_CANNOT_GET_EXPIRY_DATE = exports.OCR_CANNOT_GET_BIRTH_YEAR = exports.OCR_CANNOT_GET_NAME = exports.OCR_CANNOT_GET_ID_NUMBER = exports.OCR_WRONG_ID_CARD_SIDE = exports.OCR_UNRECOGNIZED_ID_CARD = exports.SDK_MISS_KEY = exports.ERROR_UNKNOWN = exports.SDK_START_ERROR = exports.SDK_START_FLOW_ERROR = exports.getMessage = exports.getErrorResultFromDetails = exports.createCustom = exports.fromCode = exports.getLocalizedMessage = exports.parseNfcResponse = exports.AuthorizationStatus = exports.AppIDType = exports.getEkycError = exports.EKYCErrorEvent = exports.EKYCEvent = exports.customActionsToStrings = exports.SDK_LIVENESS_ACTIONS = exports.SDKFaceDetectStatus = exports.flowToStrings = exports.SDK_FLOW_OPTIONS = exports.SDKFlowType = exports.FinosESignModule = exports.FinosESign = exports.FinosEKYCModule = exports.FinosEKYC = exports.SDKeKYC = exports.sdkEKYC = void 0;
40
- exports.ESIGN_INVALID_USER_ACCOUNT = exports.ESIGN_APP_LIMITED = exports.ESIGN_DEVICE_NOT_INIT = exports.ESIGN_INVALID_LICENSE_CONTENT = exports.ESIGN_INVALID_LICENSE = exports.ESIGN_DEVICE_ALREADY_INIT = exports.ESIGN_SESSION_INVALID = exports.FETCH_HISTORY_ERROR = exports.QRCODE_ERROR = exports.SMS_OTP_RATE_LIMIT = exports.SMS_OTP_NOT_FOUND = exports.SMS_OTP_MAX_ATTEMPTS = exports.SMS_OTP_INVALID_PHONE = exports.SMS_OTP_ERROR = exports.NFC_CHIP_AUTH_FAILED = exports.NFC_USER_CANCEL = exports.NFC_UNKNOWN_ERROR = exports.NFC_IO_ERROR = exports.NFC_INVALID_MRZ_KEY = exports.NFC_CONNECTION_LOST = exports.NFC_MUTUAL_AUTH_FAILED = exports.C06_ERROR = exports.SCAN_NFC_ENABLE = exports.SCAN_NFC_CHECK = exports.SCAN_NFC_ERROR = exports.HEAD_IS_TURNED_IN_SELFIE = exports.NUDITY_DETECTED_IN_SELFIE = exports.READING_GLASSES_DETECTED_IN_SELFIE = exports.EYEWEAR_DETECTED_IN_SELFIE = exports.FACE_OCCLUDED_IN_SELFIE = exports.FACE_IS_BLURRED = exports.MASK_PRESENT_IN_SELFIE = exports.EYES_CLOSED_IN_SELFIE = exports.MULTIPLE_FACES_IN_SELFIE = exports.LIVENESS_FAIL = exports.LIVENESS_ERROR = exports.FACE_ERROR = exports.FACE_HAT_ERROR = exports.OCR_ERROR = exports.OCR_FONT_BACK_NOT_MATCH = exports.OCR_PHOTOCOPY_ID_CARD = exports.OCR_FAKE_PORTRAIT_DETECTED = exports.OCR_FAKE_CHARACTERS_DETECTED_2 = exports.OCR_FAKE_CHARACTERS_DETECTED_1 = exports.OCR_UNKNOWN_ID_NUMBER_LENGTH = exports.OCR_MODIFIED_BIRTH_DATE_DETECTED_CMND = exports.OCR_MODIFIED_SYMBOL_DETECTED_CMND = exports.OCR_FAKE_BIRTH_DATE_DETECTED_CMND = exports.OCR_FAKE_PORTRAIT_DETECTED_CMND = exports.OCR_FAKE_CHARACTERS_DETECTED_CMND = void 0;
41
- exports.SDK_NAME = exports.SDK_VERSION = exports.USER_CANCEL = exports.ESIGN_INVALID_PIN_CODE = exports.ESIGN_INVALID_RECOVERY_CODE = exports.ESIGN_INVALID_LICENSE_CODE = exports.ESIGN_INVALID_CONTEXT = exports.ESIGN_MISSING_REQUEST_ID = exports.ESIGN_MISSING_SERIAL = exports.ESIGN_MISSING_IDENTITY = exports.ESIGN_MISSING_ACCESS_TOKEN = exports.ESIGN_NO_SESSION_ID = exports.ESIGN_MISSING_CONFIRMATION_DOC = exports.ESIGN_MISSING_REQUEST_JSON = exports.ESIGN_MISSING_CCCD = exports.ESIGN_MISSING_TOKEN = exports.ESIGN_ERROR_UNKNOWN = exports.ESIGN_AUTH_REQUEST_EXISTS = exports.ESIGN_INVALID_CERT_FOR_AUTH = exports.ESIGN_INVALID_SIGN_COUNT_OR_TIME = exports.ESIGN_AUTH_EXISTS = exports.ESIGN_SESSION_INVALID_LIST_CERT = exports.ESIGN_INVALID_RECOVERY_OR_PIN = exports.ESIGN_SESSION_INVALID_REGISTER = void 0;
42
- const react_native_1 = require("react-native");
36
+ exports.OCR_USE_NEW_ID_DOCUMENT_1 = exports.OCR_FAKE_MRZ = exports.OCR_INVALID_GENDER_CODE = exports.OCR_INVALID_ID_CARD = exports.OCR_GLARE_ID_CARD = exports.OCR_BLURRY_ID_CARD = exports.OCR_CUT_CORNER_ID_CARD = exports.OCR_CANNOT_RECOGNIZE_PORTRAIT = exports.OCR_ID_CARD_FROM_OTHER_DEVICE = exports.OCR_NOT_ORIGINAL_ID_CARD = exports.OCR_MISSING_ID_CARD_PART = exports.OCR_CANNOT_GET_ISSUE_PLACE = exports.OCR_CANNOT_GET_GENDER = exports.OCR_CANNOT_GET_HOMETOWN = exports.OCR_CANNOT_GET_RESIDENCE = exports.OCR_CANNOT_GET_ISSUE_DATE = exports.OCR_CANNOT_GET_EXPIRY_DATE = exports.OCR_CANNOT_GET_BIRTH_YEAR = exports.OCR_CANNOT_GET_NAME = exports.OCR_CANNOT_GET_ID_NUMBER = exports.OCR_WRONG_ID_CARD_SIDE = exports.OCR_UNRECOGNIZED_ID_CARD = exports.SDK_MISS_KEY = exports.ERROR_UNKNOWN = exports.SDK_START_ERROR = exports.SDK_START_FLOW_ERROR = exports.getMessage = exports.getErrorResultFromDetails = exports.createCustom = exports.fromCode = exports.getLocalizedMessage = exports.parseNfcResponse = exports.AuthorizationStatus = exports.ExitConfirmGradientOrientation = exports.AppIDType = exports.getEkycError = exports.EKYCErrorEvent = exports.EKYCEvent = exports.customActionsToStrings = exports.SDK_LIVENESS_ACTIONS = exports.SDKFaceDetectStatus = exports.flowToStrings = exports.SDK_FLOW_OPTIONS = exports.SDKFlowType = exports.FinosESignModule = exports.FinosESign = exports.FinosEKYCModule = exports.FinosEKYC = exports.SDKeKYC = exports.sdkEKYC = void 0;
37
+ exports.ESIGN_APP_LIMITED = exports.ESIGN_DEVICE_NOT_INIT = exports.ESIGN_INVALID_LICENSE_CONTENT = exports.ESIGN_INVALID_LICENSE = exports.ESIGN_DEVICE_ALREADY_INIT = exports.ESIGN_SESSION_INVALID = exports.FETCH_HISTORY_ERROR = exports.QRCODE_ERROR = exports.SMS_OTP_RATE_LIMIT = exports.SMS_OTP_NOT_FOUND = exports.SMS_OTP_MAX_ATTEMPTS = exports.SMS_OTP_INVALID_PHONE = exports.SMS_OTP_ERROR = exports.NFC_CHIP_AUTH_FAILED = exports.NFC_USER_CANCEL = exports.NFC_UNKNOWN_ERROR = exports.NFC_IO_ERROR = exports.NFC_INVALID_MRZ_KEY = exports.NFC_CONNECTION_LOST = exports.NFC_MUTUAL_AUTH_FAILED = exports.C06_ERROR = exports.SCAN_NFC_ENABLE = exports.SCAN_NFC_CHECK = exports.SCAN_NFC_ERROR = exports.HEAD_IS_TURNED_IN_SELFIE = exports.NUDITY_DETECTED_IN_SELFIE = exports.READING_GLASSES_DETECTED_IN_SELFIE = exports.EYEWEAR_DETECTED_IN_SELFIE = exports.FACE_OCCLUDED_IN_SELFIE = exports.FACE_IS_BLURRED = exports.MASK_PRESENT_IN_SELFIE = exports.EYES_CLOSED_IN_SELFIE = exports.MULTIPLE_FACES_IN_SELFIE = exports.LIVENESS_FAIL = exports.LIVENESS_ERROR = exports.FACE_ERROR = exports.FACE_HAT_ERROR = exports.OCR_ERROR = exports.OCR_FONT_BACK_NOT_MATCH = exports.OCR_PHOTOCOPY_ID_CARD = exports.OCR_FAKE_PORTRAIT_DETECTED = exports.OCR_FAKE_CHARACTERS_DETECTED_2 = exports.OCR_FAKE_CHARACTERS_DETECTED_1 = exports.OCR_UNKNOWN_ID_NUMBER_LENGTH = exports.OCR_MODIFIED_BIRTH_DATE_DETECTED_CMND = exports.OCR_MODIFIED_SYMBOL_DETECTED_CMND = exports.OCR_FAKE_BIRTH_DATE_DETECTED_CMND = exports.OCR_FAKE_PORTRAIT_DETECTED_CMND = exports.OCR_FAKE_CHARACTERS_DETECTED_CMND = exports.OCR_USE_NEW_ID_DOCUMENT_2 = void 0;
38
+ exports.SDK_NAME = exports.SDK_VERSION = exports.USER_CANCEL = exports.ESIGN_INVALID_PIN_CODE = exports.ESIGN_INVALID_RECOVERY_CODE = exports.ESIGN_INVALID_LICENSE_CODE = exports.ESIGN_INVALID_CONTEXT = exports.ESIGN_MISSING_REQUEST_ID = exports.ESIGN_MISSING_SERIAL = exports.ESIGN_MISSING_IDENTITY = exports.ESIGN_MISSING_ACCESS_TOKEN = exports.ESIGN_NO_SESSION_ID = exports.ESIGN_MISSING_CONFIRMATION_DOC = exports.ESIGN_MISSING_REQUEST_JSON = exports.ESIGN_MISSING_CCCD = exports.ESIGN_MISSING_TOKEN = exports.ESIGN_ERROR_UNKNOWN = exports.ESIGN_AUTH_REQUEST_EXISTS = exports.ESIGN_INVALID_CERT_FOR_AUTH = exports.ESIGN_INVALID_SIGN_COUNT_OR_TIME = exports.ESIGN_AUTH_EXISTS = exports.ESIGN_SESSION_INVALID_LIST_CERT = exports.ESIGN_INVALID_RECOVERY_OR_PIN = exports.ESIGN_SESSION_INVALID_REGISTER = exports.ESIGN_INVALID_USER_ACCOUNT = void 0;
43
39
  const EKYCModule_1 = __importStar(require("./EKYCModule"));
44
40
  exports.sdkEKYC = EKYCModule_1.default;
45
41
  Object.defineProperty(exports, "SDKeKYC", { enumerable: true, get: function () { return EKYCModule_1.SDKeKYC; } });
@@ -51,9 +47,6 @@ Object.defineProperty(exports, "FinosEKYCModule", { enumerable: true, get: funct
51
47
  const FinosESignModule_1 = require("./src/modules/FinosESignModule");
52
48
  Object.defineProperty(exports, "FinosESign", { enumerable: true, get: function () { return FinosESignModule_1.FinosESign; } });
53
49
  Object.defineProperty(exports, "FinosESignModule", { enumerable: true, get: function () { return FinosESignModule_1.FinosESignModule; } });
54
- const ExitSheetWrapper_1 = __importDefault(require("./src/components/ExitSheetWrapper"));
55
- // Auto-register exit sheet wrapper — khách hàng không cần khai báo AppRegistry
56
- react_native_1.AppRegistry.registerComponent('SDKExitSheetWrapper', () => ExitSheetWrapper_1.default);
57
50
  console.log('✅ SDK modules loaded successfully');
58
51
  // Export main SDK instance and class (legacy)
59
52
  exports.default = EKYCModule_1.default;
@@ -73,6 +66,8 @@ Object.defineProperty(exports, "EKYCErrorEvent", { enumerable: true, get: functi
73
66
  var ekycType_1 = require("./src/types/ekycType");
74
67
  Object.defineProperty(exports, "getEkycError", { enumerable: true, get: function () { return ekycType_1.getEkycError; } });
75
68
  Object.defineProperty(exports, "AppIDType", { enumerable: true, get: function () { return ekycType_1.AppIDType; } });
69
+ var ekycExitConfirmType_1 = require("./src/types/ekycExitConfirmType");
70
+ Object.defineProperty(exports, "ExitConfirmGradientOrientation", { enumerable: true, get: function () { return ekycExitConfirmType_1.ExitConfirmGradientOrientation; } });
76
71
  var ekycESignType_1 = require("./src/types/ekycESignType");
77
72
  Object.defineProperty(exports, "AuthorizationStatus", { enumerable: true, get: function () { return ekycESignType_1.AuthorizationStatus; } });
78
73
  // Export utility functions
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos_sdk/sdk-ekyc",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "React Native SDK for eKYC - Vietnamese CCCD NFC reading, OCR, Liveness detection, Face matching, and C06, eSign, SmsOTP residence verification",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",