@finos_sdk/sdk-ekyc 1.3.1 → 1.3.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.
@@ -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.3.1"
68
+ def sdkVersion = "1.3.3.1"
69
69
  implementation("finos.sdk.ekyc:ekyc:$sdkVersion")
70
70
  implementation("finos.sdk.ekyc:ekycui:$sdkVersion")
71
71
  implementation("finos.sdk.ekyc:nfc:$sdkVersion")
@@ -37,7 +37,8 @@ import finos.sdk.ocr.SdkEkycOcr
37
37
  import finos.sdk.smsotp.SdkSmsOtpService
38
38
  import finos.sdk.core.model.sdk.config.SmsOtpConfig
39
39
  import vn.softdreams.easyca.sdk.SdkeSign
40
- import vn.softdreams.easyca.sdk.utils.UserEsignModel
40
+
41
+ import org.json.JSONArray
41
42
  import org.json.JSONObject
42
43
  import java.io.File
43
44
  import java.io.FileOutputStream
@@ -102,8 +103,20 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
102
103
  promise.resolve(true)
103
104
  }
104
105
  } catch (e: Exception) {
105
- Log.e(TAG, "❌ initSdkEkyc() failed: ${e.message}", e)
106
- promise.reject("INIT_ERROR", "Failed to initialize SDK EKYC: ${e.message}")
106
+ val msg = e.message?.lowercase() ?: ""
107
+ // SDK đã được khởi tạo (Koin/DI already started) → coi là thành công, cho icon pass xanh / text xanh
108
+ if (msg.contains("already been started") || msg.contains("already started") || msg.contains("already initialized")) {
109
+ Log.d(TAG, "✅ initSdkEkyc() – SDK đã khởi tạo, trả success (không coi là lỗi)")
110
+ val params = Arguments.createMap().apply {
111
+ putString("status", "success")
112
+ putString("message", "SDK EKYC already initialized")
113
+ }
114
+ sendEvent("EKYCInitEvent", params)
115
+ promise.resolve(true)
116
+ } else {
117
+ Log.e(TAG, "❌ initSdkEkyc() failed: ${e.message}", e)
118
+ promise.reject("INIT_ERROR", "Failed to initialize SDK EKYC: ${e.message}")
119
+ }
107
120
  }
108
121
  }
109
122
 
@@ -535,6 +548,20 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
535
548
  }
536
549
  }
537
550
 
551
+ /**
552
+ * Convert File to base64 string for passing to React Native.
553
+ * Mirrors Android SDK: data?.ekycStateModel?.eKYCFileModel?.imageFace
554
+ */
555
+ private fun fileToBase64(file: File?): String? {
556
+ if (file == null || !file.exists()) return null
557
+ return try {
558
+ Base64.encodeToString(file.readBytes(), Base64.NO_WRAP)
559
+ } catch (e: Exception) {
560
+ Log.e(TAG, "fileToBase64 error: ${e.message}", e)
561
+ null
562
+ }
563
+ }
564
+
538
565
  @ReactMethod
539
566
  fun startEkycUI(
540
567
  appKey: String,
@@ -574,15 +601,26 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
574
601
  // Parse StyleConfig JSON from React Native
575
602
  val styleConfig = parseStyleConfig(styleConfigJson)
576
603
 
577
- // Extract switchFrontCamera from optionConfigJson
604
+ // LivenessConfig theo SDKeKYCActivity (157-169): isActiveLiveness, autoCapture, forceCaptureTimeout, isShowCameraFont, customActions, activeActionCount
578
605
  val switchFrontCamera = extractBooleanValue(optionConfigJson, "switchFrontCamera") ?: false
606
+ val isActiveLiveness = extractBooleanValue(optionConfigJson, "isActiveLiveness") ?: true
607
+ val autoCapture = extractBooleanValue(optionConfigJson, "autoCapture") ?: true
608
+ val forceCaptureTimeoutSec = extractIntValue(optionConfigJson, "forceCaptureTimeout") ?: 30
609
+ val customActionsList = parseCustomActionsFromJson(optionConfigJson)
610
+ val activeActionCount = extractIntValue(optionConfigJson, "activeActionCount") ?: customActionsList?.size ?: 2
579
611
 
580
- // Create LivenessConfig if LIVENESS is in the flow and switchFrontCamera is set
581
- val livenessConfig = if (finalFlow.contains(SDKType.LIVENESS) && switchFrontCamera) {
582
- LivenessConfig(isShowCameraFont = true)
612
+ val livenessConfig = if (finalFlow.contains(SDKType.LIVENESS)) {
613
+ LivenessConfig(
614
+ isActiveLiveness = isActiveLiveness,
615
+ autoCapture = autoCapture,
616
+ forceCaptureTimeout = (forceCaptureTimeoutSec * 1000L).coerceAtLeast(0),
617
+ isShowCameraFont = switchFrontCamera,
618
+ customActions = customActionsList?.takeIf { it.isNotEmpty() },
619
+ activeActionCount = activeActionCount,
620
+ )
583
621
  } else null
584
622
 
585
- // Create EKYCConfigSDK like MainActivity.kt
623
+ // Create EKYCConfigSDK like SDKeKYCActivity / MainActivity.kt
586
624
  val ekycConfigSDK = EKYCConfigSDK(
587
625
  appKey = appKeyConfig,
588
626
  optionConfig = optionConfig.copy(language = if (language == "en") "en" else "vi"),
@@ -596,14 +634,31 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
596
634
  activity = currentActivity,
597
635
  ekycConfigSDK = ekycConfigSDK,
598
636
  callbackSuccess = { event, data ->
599
- Log.d(TAG, "✅ startEkycUI() success")
600
- val (eventMap, promiseMap) = createSeparateMaps { map ->
601
- map.putString("status", "success")
602
- map.putString("event", event.name.toString())
603
- map.putString("data", data.toString())
637
+ Log.d(TAG, "✅ startEkycUI() callback - event=${event.name}")
638
+ val result = data as? SDKEkycResult
639
+ val hasRealData = result?.ekycStateModel != null
640
+ // Chỉ resolve promise khi flow hoàn thành có data (SDK_END_SUCCESS); SDK_START_SUCCESS = activity vừa mở, bỏ qua
641
+ if (event == EKYCEvent.SDK_START_SUCCESS && !hasRealData) {
642
+ Log.d(TAG, "⏳ startEkycUI() SDK_START_SUCCESS – chờ SDK_END_SUCCESS")
643
+ sendEvent("onEkycUISuccess", Arguments.createMap().apply {
644
+ putString("status", "started")
645
+ putString("event", event.name.toString())
646
+ })
647
+ } else {
648
+ val ekycFiles = result?.ekycStateModel?.eKYCFileModel
649
+ val ekycTransactionId = result?.ekycStateModel?.transactionId ?: ""
650
+ val (eventMap, promiseMap) = createSeparateMaps { map ->
651
+ map.putString("status", "success")
652
+ map.putString("event", event.name.toString())
653
+ map.putString("data", data.toString())
654
+ map.putString("transactionId", ekycTransactionId)
655
+ ekycFiles?.imageFace?.absolutePath?.let { map.putString("imageFacePath", it) }
656
+ ekycFiles?.imageOcrFront?.absolutePath?.let { map.putString("imageOcrFrontPath", it) }
657
+ ekycFiles?.imageOcrBack?.absolutePath?.let { map.putString("imageOcrBackPath", it) }
658
+ }
659
+ sendEvent("onEkycUISuccess", eventMap)
660
+ promise.resolve(promiseMap)
604
661
  }
605
- sendEvent("onEkycUISuccess", eventMap)
606
- promise.resolve(promiseMap)
607
662
  },
608
663
  callbackError = { event, errorResult ->
609
664
  Log.e(TAG, "❌ startEkycUI() failed - Event: $event, Message: ${errorResult.message}")
@@ -703,6 +758,37 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
703
758
  }
704
759
  }
705
760
 
761
+ /** Parse customActions array from optionConfig JSON. Maps như SDKeKYCActivity getSelectedCustomActions. */
762
+ private fun parseCustomActionsFromJson(optionConfigJson: String): List<SDKFaceDetectStatus>? {
763
+ return try {
764
+ val obj = JSONObject(optionConfigJson)
765
+ val arr = obj.optJSONArray("customActions") ?: return null
766
+ if (arr.length() == 0) return null
767
+ val actions = mutableListOf<SDKFaceDetectStatus>()
768
+ for (i in 0 until arr.length()) {
769
+ val s = arr.optString(i, "")
770
+ when (s) {
771
+ "LEFT" -> actions.add(SDKFaceDetectStatus.LEFT)
772
+ "RIGHT" -> actions.add(SDKFaceDetectStatus.RIGHT)
773
+ "UP" -> actions.add(SDKFaceDetectStatus.UP)
774
+ "DOWN" -> actions.add(SDKFaceDetectStatus.DOWN)
775
+ "SMILE" -> actions.add(SDKFaceDetectStatus.SMILE)
776
+ "BLINK" -> actions.add(SDKFaceDetectStatus.BLINK)
777
+ "TILT_LEFT" -> actions.add(SDKFaceDetectStatus.TILT_LEFT)
778
+ "TILT_RIGHT" -> actions.add(SDKFaceDetectStatus.TILT_RIGHT)
779
+ "WINK_LEFT" -> actions.add(SDKFaceDetectStatus.WINK_LEFT)
780
+ "WINK_RIGHT" -> actions.add(SDKFaceDetectStatus.WINK_RIGHT)
781
+ "STRAIGHT" -> actions.add(SDKFaceDetectStatus.STRAIGHT)
782
+ else -> if (s.isNotEmpty()) Log.w(TAG, "parseCustomActionsFromJson: unknown action=$s")
783
+ }
784
+ }
785
+ if (actions.isNotEmpty()) actions else null
786
+ } catch (e: Exception) {
787
+ Log.w(TAG, "parseCustomActionsFromJson: ${e.message}")
788
+ null
789
+ }
790
+ }
791
+
706
792
  private fun parseAppKeyConfig(appKeyConfigJson: String): AppKeyConfig {
707
793
  return try {
708
794
  if (appKeyConfigJson.isBlank() || appKeyConfigJson == "{}") {
@@ -1019,14 +1105,26 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1019
1105
  promise.resolve(promiseMap)
1020
1106
  },
1021
1107
  callbackError = { event, error ->
1022
- Log.e(TAG, "❌ initializeESign() failed - Event: $event, Message: ${error.message}")
1023
- val errorMap = Arguments.createMap().apply {
1024
- putString("event", event.name.toString())
1025
- putString("message", error.message ?: "")
1026
- putString("code", error.code.toString())
1108
+ val msg = (error.message ?: "").lowercase()
1109
+ // eSign đã được khởi tạo → coi là thành công, cho icon pass xanh / text xanh
1110
+ if (msg.contains("đã được khởi tạo") || msg.contains("already") || msg.contains("already initialized")) {
1111
+ Log.d(TAG, "✅ initializeESign() – eSign đã khởi tạo, trả success (không coi là lỗi)")
1112
+ val (eventMap, promiseMap) = createSeparateMaps { map ->
1113
+ map.putString("code", "0")
1114
+ map.putString("message", "eSign already initialized")
1115
+ }
1116
+ sendEvent("onESignInitSuccess", eventMap)
1117
+ promise.resolve(promiseMap)
1118
+ } else {
1119
+ Log.e(TAG, "❌ initializeESign() failed - Event: $event, Message: ${error.message}")
1120
+ val errorMap = Arguments.createMap().apply {
1121
+ putString("event", event.name.toString())
1122
+ putString("message", error.message ?: "")
1123
+ putString("code", error.code.toString())
1124
+ }
1125
+ sendEvent("onESignError", errorMap)
1126
+ promise.reject(event.name.toString(), error.message ?: "Unknown Error")
1027
1127
  }
1028
- sendEvent("onESignError", errorMap)
1029
- promise.reject(event.name.toString(), error.message ?: "Unknown Error")
1030
1128
  }
1031
1129
  )
1032
1130
  } catch (e: Exception) {
@@ -1052,10 +1150,15 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1052
1150
  Log.d(TAG, "✅ getSdkToken() success")
1053
1151
  promise.resolve(token)
1054
1152
  },
1055
- callbackError = { error ->
1056
- Log.e(TAG, "❌ getSdkToken() failed: $error")
1057
- // error might be String or Object, toString() covers both
1058
- promise.reject("GET_SDK_TOKEN_ERROR", error.toString())
1153
+ callbackError = { event, error ->
1154
+ Log.e(TAG, "❌ getSdkToken() failed - Event: $event, Message: ${error.message}")
1155
+ val errorMap = Arguments.createMap().apply {
1156
+ putString("event", event.name.toString())
1157
+ putString("message", error.message ?: "")
1158
+ putString("code", error.code.toString())
1159
+ }
1160
+ sendEvent("onESignError", errorMap)
1161
+ promise.reject(event.name.toString(), error.message ?: "Get SDK Token failed")
1059
1162
  }
1060
1163
  )
1061
1164
  } catch (e: Exception) {
@@ -1069,8 +1172,6 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1069
1172
  accessToken: String?,
1070
1173
  username: String?,
1071
1174
  rememberMe: Boolean?,
1072
- userEsignModelJson: String?,
1073
- privateKeyFilePath: String?,
1074
1175
  promise: Promise
1075
1176
  ) {
1076
1177
  Log.d(TAG, "▶️ openSessionId() called")
@@ -1110,49 +1211,9 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1110
1211
  promise.reject(event.name.toString(), error.message ?: "Unknown Error")
1111
1212
  }
1112
1213
  )
1113
- } else if (userEsignModelJson != null && privateKeyFilePath != null) {
1114
- // Option 2: Auto-create token from user info
1115
- val json = JSONObject(userEsignModelJson)
1116
- val userInfo = UserEsignModel(
1117
- cccd = json.getString("cccd"),
1118
- name = json.getString("name"),
1119
- device = json.optString("device", "Android"),
1120
- deviceId = json.optString("deviceId", android.provider.Settings.Secure.getString(
1121
- reactApplicationContext.contentResolver,
1122
- android.provider.Settings.Secure.ANDROID_ID
1123
- ) ?: "")
1124
- )
1125
-
1126
- SdkeSign.openSessionId(
1127
- context = currentActivity,
1128
- userEsignModel = userInfo,
1129
- privateKeyFilePath = privateKeyFilePath,
1130
- username = username ?: "",
1131
- rememberMe = rememberMe ?: false,
1132
- callbackSuccess = { deviceState, code, message ->
1133
- Log.d(TAG, "✅ openSessionId() success")
1134
- val (eventMap, promiseMap) = createSeparateMaps { map ->
1135
- map.putString("deviceState", deviceState)
1136
- map.putString("code", code.toString())
1137
- map.putString("message", message)
1138
- }
1139
- sendEvent("onESignOpenSessionSuccess", eventMap)
1140
- promise.resolve(promiseMap)
1141
- },
1142
- callbackError = { event, error ->
1143
- Log.e(TAG, "❌ openSessionId() failed - Event: $event, Message: ${error.message}")
1144
- val errorMap = Arguments.createMap().apply {
1145
- putString("event", event.name.toString())
1146
- putString("message", error.message ?: "")
1147
- putString("code", error.code.toString())
1148
- }
1149
- sendEvent("onESignError", errorMap)
1150
- promise.reject(event.name.toString(), error.message ?: "Unknown Error")
1151
- }
1152
- )
1153
1214
  } else {
1154
1215
  Log.e(TAG, "❌ openSessionId() failed: Invalid parameters")
1155
- promise.reject("INVALID_PARAMS", "Either accessToken or (userEsignModelJson + privateKeyFilePath) must be provided")
1216
+ promise.reject("INVALID_PARAMS", "accessToken must be provided")
1156
1217
  }
1157
1218
  } catch (e: Exception) {
1158
1219
  Log.e(TAG, "❌ openSessionId() exception: ${e.message}", e)
@@ -1462,26 +1523,14 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1462
1523
  callbackError = { event, error ->
1463
1524
  val errorMessage = error.message ?: ""
1464
1525
  val errorCode = error.code.toString()
1465
-
1466
- // Check if message contains "thành công" or code == "0" -> treat as success
1467
- if (errorMessage.contains("thành công", ignoreCase = true) || errorCode == "0") {
1468
- Log.d(TAG, "✅ registerRemoteSigning() success (async operation) - Message: $errorMessage")
1469
- val (eventMap, promiseMap) = createSeparateMaps { map ->
1470
- map.putString("response", "{\"status\":1,\"msg\":\"$errorMessage\"}")
1471
- map.putString("message", errorMessage)
1472
- }
1473
- sendEvent("onESignRegisterRemoteSigningSuccess", eventMap)
1474
- promise.resolve(promiseMap)
1475
- } else {
1476
- Log.e(TAG, "❌ registerRemoteSigning() failed - Event: $event, Message: $errorMessage")
1477
- val errorMap = Arguments.createMap().apply {
1478
- putString("event", event.name.toString())
1479
- putString("message", errorMessage)
1480
- putString("code", errorCode)
1481
- }
1482
- sendEvent("onESignError", errorMap)
1483
- promise.reject(event.name.toString(), errorMessage)
1526
+ Log.e(TAG, "❌ registerRemoteSigning() failed - Event: $event, Message: $errorMessage")
1527
+ val errorMap = Arguments.createMap().apply {
1528
+ putString("event", event.name.toString())
1529
+ putString("message", errorMessage)
1530
+ putString("code", errorCode)
1484
1531
  }
1532
+ sendEvent("onESignError", errorMap)
1533
+ promise.reject(event.name.toString(), errorMessage)
1485
1534
  }
1486
1535
  )
1487
1536
  } catch (e: Exception) {
@@ -1490,6 +1539,48 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1490
1539
  }
1491
1540
  }
1492
1541
 
1542
+ /**
1543
+ * Composite API: Register Remote Signing + Send Confirmation Document
1544
+ * Align với SdkeSignImpl.registerAndConfirm: gọi registerRemoteSigning -> parse sessionId -> sendConfirmationDocument
1545
+ */
1546
+ @ReactMethod
1547
+ fun registerAndConfirm(
1548
+ requestJson: String,
1549
+ confirmationDocBase64: String,
1550
+ promise: Promise
1551
+ ) {
1552
+ Log.d(TAG, "▶️ registerAndConfirm() called")
1553
+ try {
1554
+ SdkeSign.registerAndConfirm(
1555
+ requestJson = requestJson,
1556
+ confirmationDocBase64 = confirmationDocBase64,
1557
+ callbackSuccess = { rawResponse ->
1558
+ Log.d(TAG, "✅ registerAndConfirm() success")
1559
+ val (eventMap, promiseMap) = createSeparateMaps { map ->
1560
+ map.putString("response", rawResponse)
1561
+ }
1562
+ sendEvent("onESignRegisterAndConfirmSuccess", eventMap)
1563
+ promise.resolve(promiseMap)
1564
+ },
1565
+ callbackError = { event, error ->
1566
+ val errorMessage = error.message ?: ""
1567
+ val errorCode = error.code.toString()
1568
+ Log.e(TAG, "❌ registerAndConfirm() failed - Event: $event, Message: $errorMessage")
1569
+ val errorMap = Arguments.createMap().apply {
1570
+ putString("event", event.name.toString())
1571
+ putString("message", errorMessage)
1572
+ putString("code", errorCode)
1573
+ }
1574
+ sendEvent("onESignError", errorMap)
1575
+ promise.reject(event.name.toString(), errorMessage)
1576
+ }
1577
+ )
1578
+ } catch (e: Exception) {
1579
+ Log.e(TAG, "❌ registerAndConfirm() exception: ${e.message}", e)
1580
+ promise.reject("ESIGN_EXCEPTION", e.message, e)
1581
+ }
1582
+ }
1583
+
1493
1584
  @ReactMethod
1494
1585
  fun signPdf(
1495
1586
  requestJson: String,
@@ -1556,25 +1647,13 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1556
1647
  callbackError = { event, error ->
1557
1648
  val errorMessage = error.message ?: ""
1558
1649
  val errorCode = error.code.toString()
1559
-
1560
- // Check if message contains "thành công" or code == "0" -> treat as success
1561
- if (errorMessage.contains("thành công", ignoreCase = true) || errorCode == "0") {
1562
- Log.d(TAG, "✅ sendConfirmationDocument() success (async operation) - Message: $errorMessage")
1563
- val (eventMap, promiseMap) = createSeparateMaps { map ->
1564
- map.putString("response", "{\"status\":1,\"msg\":\"$errorMessage\"}")
1565
- map.putString("message", errorMessage)
1566
- }
1567
- sendEvent("onESignSendConfirmationDocumentSuccess", eventMap)
1568
- promise.resolve(promiseMap)
1569
- } else {
1570
- val errorMap = Arguments.createMap().apply {
1571
- putString("event", event.name.toString())
1572
- putString("message", errorMessage)
1573
- putString("code", errorCode)
1574
- }
1575
- sendEvent("onESignError", errorMap)
1576
- promise.reject(event.name.toString(), errorMessage)
1650
+ val errorMap = Arguments.createMap().apply {
1651
+ putString("event", event.name.toString())
1652
+ putString("message", errorMessage)
1653
+ putString("code", errorCode)
1577
1654
  }
1655
+ sendEvent("onESignError", errorMap)
1656
+ promise.reject(event.name.toString(), errorMessage)
1578
1657
  }
1579
1658
  )
1580
1659
  } catch (e: Exception) {
@@ -1,12 +1,12 @@
1
1
  import { EmitterSubscription } from 'react-native';
2
2
  import { NfcConfig, NfcError } from './src/types/ekycNFCType';
3
- import { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent } from './src/types/ekycType';
3
+ import { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent, StartEkycUIResult } from './src/types/ekycType';
4
4
  import { C06Config } from './src/types/ekycC06Type';
5
5
  import { OcrConfig } from './src/types/ekycOCRType';
6
6
  import { LivenessConfig, SDKFaceDetectStatus } from './src/types/ekycLivenessType';
7
7
  import { FaceServiceConfig } from './src/types/ekycFaceType';
8
8
  import { SmsOtpConfig, SmsOtpResult, SmsOtpError } from './src/types/ekycSmsOtpType';
9
- import { UserEsignModel, ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError } from './src/types/ekycESignType';
9
+ import { ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError } from './src/types/ekycESignType';
10
10
  export declare const SDK_VERSION: string;
11
11
  export declare const SDK_NAME: string;
12
12
  declare class SDKeKYC {
@@ -54,7 +54,7 @@ declare class SDKeKYC {
54
54
  onSmsOtpError(callback: (error: SmsOtpError) => void): EmitterSubscription | null;
55
55
  initializeESign(finosToken?: string): Promise<ESignInitResult>;
56
56
  getSdkToken(identity: string, name: string, deviceId: string): Promise<string>;
57
- openSessionId(accessToken?: string, username?: string, rememberMe?: boolean, userEsignModel?: UserEsignModel, privateKeyFilePath?: string): Promise<ESignOpenSessionResult>;
57
+ openSessionId(accessToken: string | null, username: string | null, rememberMe: boolean | null): Promise<ESignOpenSessionResult>;
58
58
  registerDevice(recoverCode: string, pinCode: string, fcmToken?: string): Promise<{
59
59
  code: string;
60
60
  message: string;
@@ -82,6 +82,13 @@ declare class SDKeKYC {
82
82
  sendConfirmationDocument(requestJson: string): Promise<{
83
83
  response: string;
84
84
  }>;
85
+ /**
86
+ * Composite API: Register Remote Signing + Send Confirmation Document
87
+ * Align với SdkeSignImpl.registerAndConfirm
88
+ */
89
+ registerAndConfirm(requestJson: string, confirmationDocBase64: string): Promise<{
90
+ response: string;
91
+ }>;
85
92
  onESignInitSuccess(callback: (data: ESignInitResult) => void): EmitterSubscription | null;
86
93
  onESignOpenSessionSuccess(callback: (data: ESignOpenSessionResult) => void): EmitterSubscription | null;
87
94
  onESignRegisterDeviceSuccess(callback: (data: {
@@ -111,7 +118,15 @@ declare class SDKeKYC {
111
118
  onESignSendConfirmationDocumentSuccess(callback: (data: {
112
119
  response: string;
113
120
  }) => void): EmitterSubscription | null;
121
+ onESignRegisterAndConfirmSuccess(callback: (data: {
122
+ response: string;
123
+ }) => void): EmitterSubscription | null;
114
124
  onESignError(callback: (error: ESignError) => void): EmitterSubscription | null;
125
+ /**
126
+ * Start eKYC UI flow. On success, result contains the same data as Android:
127
+ * data.ekycStateModel.eKYCFileModel.imageFace → result.imageFace (base64),
128
+ * result.imageFacePath (file path), result.imageOcrFront / imageOcrBack, result.transactionId.
129
+ */
115
130
  startEkycUI(appKey: string, flowSDK: string[], language: string, transactionId: string, appKeyConfig: {
116
131
  appKey: string;
117
132
  appKeyNfc: string;
@@ -159,7 +174,7 @@ declare class SDKeKYC {
159
174
  textFont?: string;
160
175
  textColor?: number;
161
176
  };
162
- }): Promise<any>;
177
+ }): Promise<StartEkycUIResult>;
163
178
  }
164
179
  declare const sdkEKYC: SDKeKYC;
165
180
  export { SDKeKYC };
@@ -552,11 +552,10 @@ class SDKeKYC {
552
552
  throw error;
553
553
  }
554
554
  }
555
- async openSessionId(accessToken, username, rememberMe, userEsignModel, privateKeyFilePath) {
555
+ async openSessionId(accessToken, username, rememberMe) {
556
556
  const nativeModule = this.ensureNativeModule();
557
557
  try {
558
- const userEsignModelJson = userEsignModel ? JSON.stringify(userEsignModel) : null;
559
- const result = await nativeModule.openSessionId(accessToken || null, username || null, rememberMe !== undefined ? rememberMe : false, userEsignModelJson, privateKeyFilePath || null);
558
+ const result = await nativeModule.openSessionId(accessToken || null, username || null, rememberMe !== null ? rememberMe : null);
560
559
  return result;
561
560
  }
562
561
  catch (error) {
@@ -701,6 +700,21 @@ class SDKeKYC {
701
700
  throw error;
702
701
  }
703
702
  }
703
+ /**
704
+ * Composite API: Register Remote Signing + Send Confirmation Document
705
+ * Align với SdkeSignImpl.registerAndConfirm
706
+ */
707
+ async registerAndConfirm(requestJson, confirmationDocBase64) {
708
+ const nativeModule = this.ensureNativeModule();
709
+ try {
710
+ const result = await nativeModule.registerAndConfirm(requestJson, confirmationDocBase64);
711
+ return result;
712
+ }
713
+ catch (error) {
714
+ console.error('eSign Register And Confirm Error:', error);
715
+ throw error;
716
+ }
717
+ }
704
718
  // eSign Event Listeners
705
719
  onESignInitSuccess(callback) {
706
720
  try {
@@ -862,6 +876,22 @@ class SDKeKYC {
862
876
  return null;
863
877
  }
864
878
  }
879
+ onESignRegisterAndConfirmSuccess(callback) {
880
+ try {
881
+ const emitter = this.ensureEventEmitter();
882
+ if (!emitter) {
883
+ console.error('❌ Event emitter not available for onESignRegisterAndConfirmSuccess');
884
+ return null;
885
+ }
886
+ const listener = emitter.addListener('onESignRegisterAndConfirmSuccess', callback);
887
+ this.listeners.push(listener);
888
+ return listener;
889
+ }
890
+ catch (error) {
891
+ console.error('Failed to add onESignRegisterAndConfirmSuccess listener:', error);
892
+ return null;
893
+ }
894
+ }
865
895
  onESignError(callback) {
866
896
  try {
867
897
  const emitter = this.ensureEventEmitter();
@@ -878,7 +908,11 @@ class SDKeKYC {
878
908
  return null;
879
909
  }
880
910
  }
881
- // SdkEkycUI method
911
+ /**
912
+ * Start eKYC UI flow. On success, result contains the same data as Android:
913
+ * data.ekycStateModel.eKYCFileModel.imageFace → result.imageFace (base64),
914
+ * result.imageFacePath (file path), result.imageOcrFront / imageOcrBack, result.transactionId.
915
+ */
882
916
  async startEkycUI(appKey, flowSDK, language, transactionId, appKeyConfig, optionConfig, styleConfig) {
883
917
  if (!this.isInitialized) {
884
918
  throw new Error('SDK is not initialized. Please call initSdkEkyc() first.');
@@ -893,7 +927,7 @@ class SDKeKYC {
893
927
  const appKeyConfigJson = JSON.stringify(appKeyConfig);
894
928
  const styleConfigJson = styleConfig ? JSON.stringify(styleConfig) : '{}';
895
929
  const nativeModule = this.ensureNativeModule();
896
- const result = await nativeModule.startEkycUI(appKey, flowSDKJson, language, transactionId, optionConfigJson, appKeyConfigJson, styleConfigJson);
930
+ const result = (await nativeModule.startEkycUI(appKey, flowSDKJson, language, transactionId, optionConfigJson, appKeyConfigJson, styleConfigJson));
897
931
  console.log('✅ SdkEkycUI started successfully');
898
932
  return result;
899
933
  }
package/dist/index.d.ts CHANGED
@@ -5,16 +5,17 @@ export default sdkEKYC;
5
5
  export { sdkEKYC, SDKeKYC };
6
6
  export { FinosEKYC, FinosEKYCModule };
7
7
  export { FinosESign, FinosESignModule };
8
+ export { SDKFlowType, SDK_FLOW_OPTIONS, flowToStrings } from './src/types/ekycFlowType';
8
9
  export type { NfcConfig, NFCData, NfcInfo } from './src/types/ekycNFCType';
9
10
  export type { C06Config } from './src/types/ekycC06Type';
10
11
  export type { OcrConfig } from './src/types/ekycOCRType';
11
12
  export type { LivenessConfig } from './src/types/ekycLivenessType';
12
- export { SDKFaceDetectStatus } from './src/types/ekycLivenessType';
13
+ export { SDKFaceDetectStatus, SDK_LIVENESS_ACTIONS, customActionsToStrings } from './src/types/ekycLivenessType';
13
14
  export type { FaceServiceConfig } from './src/types/ekycFaceType';
14
- export type { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent } from './src/types/ekycType';
15
+ export type { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent, StartEkycUIResult } from './src/types/ekycType';
15
16
  export type { NfcError } from './src/types/ekycNFCType';
16
17
  export type { SDKTransactionResponse } from './src/types/ekycTransactionType';
17
18
  export type { SmsOtpConfig, SmsOtpResult, SmsOtpError } from './src/types/ekycSmsOtpType';
18
- export type { UserEsignModel, ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError, ESignAuthenticateResult } from './src/types/ekycESignType';
19
+ export type { ESignInitResult, ESignOpenSessionResult, ESignCertificate, ESignSignRequest, ESignError, ESignAuthenticateResult, UserEsignModel } from './src/types/ekycESignType';
19
20
  export { parseNfcResponse } from './src/utils/utils';
20
21
  export { SDK_VERSION, SDK_NAME };
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.SDK_NAME = exports.SDK_VERSION = exports.parseNfcResponse = exports.SDKFaceDetectStatus = exports.FinosESignModule = exports.FinosESign = exports.FinosEKYCModule = exports.FinosEKYC = exports.SDKeKYC = exports.sdkEKYC = void 0;
26
+ exports.SDK_NAME = exports.SDK_VERSION = exports.parseNfcResponse = 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;
27
27
  const EKYCModule_1 = __importStar(require("./EKYCModule"));
28
28
  exports.sdkEKYC = EKYCModule_1.default;
29
29
  Object.defineProperty(exports, "SDKeKYC", { enumerable: true, get: function () { return EKYCModule_1.SDKeKYC; } });
@@ -38,8 +38,15 @@ Object.defineProperty(exports, "FinosESignModule", { enumerable: true, get: func
38
38
  console.log('✅ SDK modules loaded successfully');
39
39
  // Export main SDK instance and class (legacy)
40
40
  exports.default = EKYCModule_1.default;
41
+ // Flow type enum – bên sử dụng truyền enum vào startEkycUI(flowSDK: SDKFlowType[])
42
+ var ekycFlowType_1 = require("./src/types/ekycFlowType");
43
+ Object.defineProperty(exports, "SDKFlowType", { enumerable: true, get: function () { return ekycFlowType_1.SDKFlowType; } });
44
+ Object.defineProperty(exports, "SDK_FLOW_OPTIONS", { enumerable: true, get: function () { return ekycFlowType_1.SDK_FLOW_OPTIONS; } });
45
+ Object.defineProperty(exports, "flowToStrings", { enumerable: true, get: function () { return ekycFlowType_1.flowToStrings; } });
41
46
  var ekycLivenessType_1 = require("./src/types/ekycLivenessType");
42
47
  Object.defineProperty(exports, "SDKFaceDetectStatus", { enumerable: true, get: function () { return ekycLivenessType_1.SDKFaceDetectStatus; } });
48
+ Object.defineProperty(exports, "SDK_LIVENESS_ACTIONS", { enumerable: true, get: function () { return ekycLivenessType_1.SDK_LIVENESS_ACTIONS; } });
49
+ Object.defineProperty(exports, "customActionsToStrings", { enumerable: true, get: function () { return ekycLivenessType_1.customActionsToStrings; } });
43
50
  // Export utility functions
44
51
  var utils_1 = require("./src/utils/utils");
45
52
  Object.defineProperty(exports, "parseNfcResponse", { enumerable: true, get: function () { return utils_1.parseNfcResponse; } });
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos_sdk/sdk-ekyc",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
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",