@finos_sdk/sdk-ekyc 1.4.4 → 1.4.6

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.4.4"
68
+ def sdkVersion = "1.4.6.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")
@@ -2,6 +2,7 @@ package finos.sdk.ekyc
2
2
 
3
3
  import android.R
4
4
  import android.net.Uri
5
+ import com.google.gson.Gson
5
6
  import android.os.Handler
6
7
  import android.os.Looper
7
8
  import android.util.Base64
@@ -26,6 +27,7 @@ import finos.sdk.core.model.sdk.config.AppKeyConfig
26
27
  import finos.sdk.core.model.sdk.config.C06Config
27
28
  import finos.sdk.core.model.sdk.config.EKYCConfigSDK
28
29
  import finos.sdk.core.model.sdk.config.FaceServiceConfig
30
+ import finos.sdk.core.model.sdk.config.LivenessBackConfirmConfig
29
31
  import finos.sdk.core.model.sdk.config.LivenessConfig
30
32
  import finos.sdk.core.model.sdk.config.NfcConfig
31
33
  import finos.sdk.core.model.sdk.config.OcrConfig
@@ -108,6 +110,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
108
110
  Arguments.createMap().apply {
109
111
  putInt("status", result.status)
110
112
  putString("msg", result.msg)
113
+ result.errorCode?.let { putString("errorCode", it) }
111
114
  result.data?.let { d ->
112
115
  putMap("data", Arguments.createMap().apply {
113
116
  d.sessionId?.let { putString("sessionId", it) }
@@ -130,6 +133,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
130
133
  Arguments.createMap().apply {
131
134
  putInt("status", result.status)
132
135
  putString("msg", result.msg)
136
+ result.errorCode?.let { putString("errorCode", it) }
133
137
  result.data?.let { d ->
134
138
  putMap("data", Arguments.createMap().apply {
135
139
  putString("transactionId", d.transactionId)
@@ -232,7 +236,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
232
236
  val eventMap =
233
237
  Arguments.createMap().apply {
234
238
  putString("event", event.name.toString())
235
- putString("data", data.toString())
239
+ putString("data", Gson().toJson(data))
236
240
  }
237
241
  sendEvent("onNfcScanStart", eventMap)
238
242
  }
@@ -257,7 +261,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
257
261
  val eventMap =
258
262
  Arguments.createMap().apply {
259
263
  putString("event", event.name.toString())
260
- putString("data", data.toString())
264
+ putString("data", Gson().toJson(data))
261
265
  }
262
266
  sendEvent("onNfcEvent", eventMap)
263
267
  }
@@ -311,18 +315,19 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
311
315
  ekycConfigSDK = ekycConfig,
312
316
  callbackSuccess = { event, data ->
313
317
  Log.d(TAG, "✅ checkC06() success")
318
+ val c06Json = Gson().toJson((data as? SDKEkycResult)?.checkC06Response)
314
319
 
315
320
  // Create separate maps for event and promise
316
321
  val eventMap =
317
322
  Arguments.createMap().apply {
318
323
  putString("event", event.name.toString())
319
- putString("data", data.toString())
324
+ putString("data", c06Json)
320
325
  }
321
326
 
322
327
  val promiseMap =
323
328
  Arguments.createMap().apply {
324
329
  putString("event", event.name.toString())
325
- putString("data", data.toString())
330
+ putString("data", c06Json)
326
331
  }
327
332
  sendEvent("onC06Success", eventMap)
328
333
  promise.resolve(promiseMap)
@@ -386,7 +391,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
386
391
  Log.d(TAG, "✅ startOcr() success")
387
392
  val (eventMap, promiseMap) = createSeparateMaps { map ->
388
393
  map.putString("event", event.name.toString())
389
- map.putString("data", (data as SDKEkycResult).ocrResponse.toString())
394
+ map.putString("data", Gson().toJson((data as SDKEkycResult).ocrResponse))
390
395
  }
391
396
  sendEvent("onOcrSuccess", eventMap)
392
397
  promise.resolve(promiseMap)
@@ -425,6 +430,8 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
425
430
  activeActionCount: Int?,
426
431
  forceCaptureTimeout: Double?,
427
432
  isActiveLivenessColor: Boolean?,
433
+ isShowBackConfirmation: Boolean?,
434
+ backConfirmConfigJson: String?,
428
435
  promise: Promise
429
436
  ) {
430
437
  Log.d(TAG, "▶️ startLiveness() called")
@@ -458,6 +465,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
458
465
  null
459
466
  }
460
467
 
468
+ val backConfirmConfig = parseBackConfirmConfig(backConfirmConfigJson)
461
469
  val livenessConfig =
462
470
  LivenessConfig(
463
471
  isActiveLiveness = isActiveLiveness ?: false,
@@ -472,7 +480,9 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
472
480
  activeActionCount = activeActionCount ?: 2,
473
481
  forceCaptureTimeout = (forceCaptureTimeout ?: 0.0).toLong(),
474
482
  selfieImage = imageFile,
475
- transactionId = transactionId
483
+ transactionId = transactionId,
484
+ isShowBackConfirmation = isShowBackConfirmation ?: false,
485
+ backConfirmConfig = backConfirmConfig,
476
486
  )
477
487
  val ekycConfig =
478
488
  EKYCConfigSDK(
@@ -483,10 +493,21 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
483
493
  eKYCFinOSLiveness.startEkyc(
484
494
  ekycConfigSDK = ekycConfig,
485
495
  callbackSuccess = { event, data ->
496
+ // LOG_SUCCESS = internal submit result event (v1.4.6.1), don't resolve promise
497
+ if (event == EKYCEvent.LOG_SUCCESS) {
498
+ val logDataStr = data?.customData?.let { Gson().toJson(it) } ?: (data as? SDKEkycResult)?.checkLivenessResponse?.let { Gson().toJson(it) } ?: Gson().toJson(data)
499
+ Log.d(TAG, "LOG_SUCCESS [Liveness]: $logDataStr")
500
+ val logMap = Arguments.createMap().apply {
501
+ putString("event", event.name.toString())
502
+ putString("data", logDataStr)
503
+ }
504
+ sendEvent("onLivenessSuccess", logMap)
505
+ return@startEkyc
506
+ }
486
507
  Log.d(TAG, "✅ startLiveness() success")
487
508
  val (eventMap, promiseMap) = createSeparateMaps { map ->
488
509
  map.putString("event", event.name.toString())
489
- map.putString("data", (data as SDKEkycResult).checkLivenessResponse.toString())
510
+ map.putString("data", Gson().toJson((data as SDKEkycResult).checkLivenessResponse))
490
511
  }
491
512
  sendEvent("onLivenessSuccess", eventMap)
492
513
  promise.resolve(promiseMap)
@@ -556,10 +577,37 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
556
577
  eKYCFinOSFaceService.startEkyc(
557
578
  ekycConfigSDK = ekycConfig,
558
579
  callbackSuccess = { event, data ->
580
+ // LOG_SUCCESS = internal submit result event (v1.4.6.1), don't resolve promise
581
+ if (event == EKYCEvent.LOG_SUCCESS) {
582
+ val faceResponse = (data as? SDKEkycResult)?.checkFaceResponse
583
+ val logDataStr = data?.customData?.let { Gson().toJson(it) } ?: faceResponse?.let { Gson().toJson(it) } ?: "null"
584
+ Log.d(TAG, "LOG_SUCCESS [FaceCompare]: $logDataStr")
585
+ val logMap = Arguments.createMap().apply {
586
+ putString("event", event.name.toString())
587
+ putString("data", logDataStr)
588
+ }
589
+ sendEvent("onFaceCompareSuccess", logMap)
590
+ return@startEkyc
591
+ }
559
592
  Log.d(TAG, "✅ startFaceCompare() success")
593
+ val faceResponse = (data as? SDKEkycResult)?.checkFaceResponse
560
594
  val (eventMap, promiseMap) = createSeparateMaps { map ->
561
595
  map.putString("event", event.name.toString())
562
- map.putString("data", data.toString())
596
+ val resultMap = Arguments.createMap().apply {
597
+ putDouble("conf", faceResponse?.result?.conf?.toString()?.toDoubleOrNull() ?: 0.0)
598
+ putString("match", faceResponse?.result?.match?.toString())
599
+ putInt("matchScore", faceResponse?.result?.matchScore?.toString()?.toIntOrNull() ?: 0)
600
+ putString("toBeReviewed", faceResponse?.result?.toBeReviewed?.toString())
601
+ }
602
+ val faceMap = Arguments.createMap().apply {
603
+ putString("requestId", faceResponse?.requestId?.toString())
604
+ putMap("result", resultMap)
605
+ putString("status", faceResponse?.status?.toString())
606
+ putInt("statusCode", faceResponse?.statusCode?.toString()?.toIntOrNull() ?: 0)
607
+ putString("error", faceResponse?.error?.toString())
608
+ putString("type", faceResponse?.type?.toString())
609
+ }
610
+ map.putMap("data", faceMap)
563
611
  }
564
612
  sendEvent("onFaceCompareSuccess", eventMap)
565
613
  promise.resolve(promiseMap)
@@ -758,6 +806,9 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
758
806
  else -> AppIDType.NONE
759
807
  }
760
808
 
809
+ val isShowBackConfirmation = extractBooleanValue(optionConfigJson, "isShowBackConfirmation") ?: false
810
+ val backConfirmConfig = parseBackConfirmConfig(extractObjectJson(optionConfigJson, "backConfirmConfig"))
811
+
761
812
  val livenessConfig = if (finalFlow.contains(SDKType.LIVENESS)) {
762
813
  LivenessConfig(
763
814
  isActiveLiveness = isActiveLiveness,
@@ -765,6 +816,8 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
765
816
  isShowCameraFont = switchFrontCamera,
766
817
  customActions = customActionsList?.takeIf { it.isNotEmpty() },
767
818
  activeActionCount = activeActionCount,
819
+ isShowBackConfirmation = isShowBackConfirmation,
820
+ backConfirmConfig = backConfirmConfig,
768
821
  )
769
822
  } else null
770
823
 
@@ -782,6 +835,17 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
782
835
  activity = currentActivity,
783
836
  ekycConfigSDK = ekycConfigSDK,
784
837
  callbackSuccess = { event, data ->
838
+ // LOG_SUCCESS = internal submit result event (v1.4.5), emit event only, don't resolve promise
839
+ if (event == EKYCEvent.LOG_SUCCESS) {
840
+ val logDataStr = data?.customData?.let { Gson().toJson(it) } ?: Gson().toJson(data)
841
+ Log.d(TAG, "LOG_SUCCESS [EkycUI]: $logDataStr")
842
+ sendEvent("onEkycUISuccess", Arguments.createMap().apply {
843
+ putString("status", "log")
844
+ putString("event", event.name.toString())
845
+ putString("data", logDataStr)
846
+ })
847
+ return@startEkyc
848
+ }
785
849
  Log.d(TAG, "✅ startEkycUI() callback - event=${event.name}")
786
850
  val result = data as? SDKEkycResult
787
851
  val hasRealData = result?.ekycStateModel != null
@@ -798,7 +862,7 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
798
862
  val (eventMap, promiseMap) = createSeparateMaps { map ->
799
863
  map.putString("status", "success")
800
864
  map.putString("event", event.name.toString())
801
- map.putString("data", data.toString())
865
+ map.putString("data", Gson().toJson(data))
802
866
  map.putString("transactionId", ekycTransactionId)
803
867
  ekycFiles?.imageFace?.absolutePath?.let { map.putString("imageFacePath", it) }
804
868
  ekycFiles?.imageOcrFront?.absolutePath?.let { map.putString("imageOcrFrontPath", it) }
@@ -859,32 +923,42 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
859
923
  private fun parseOptionConfig(optionConfigJson: String): OptionConfig {
860
924
  return try {
861
925
  if (optionConfigJson.isBlank() || optionConfigJson == "{}") {
862
- // Return default values based on demo OptionConfig.kt
863
- OptionConfig(
864
- baseUrl = null,
865
- countMaxRetry = 3,
866
- language = null
867
- )
926
+ OptionConfig()
868
927
  } else {
869
- // Simple JSON parsing (in real implementation, use proper JSON library)
870
928
  val baseUrl = extractStringValue(optionConfigJson, "baseUrl")
871
929
  val countMaxRetry = extractIntValue(optionConfigJson, "countMaxRetry") ?: 3
872
930
  val language = extractStringValue(optionConfigJson, "language")
931
+ val networkTimeoutMs = extractLongValue(optionConfigJson, "networkTimeoutMs") ?: 30_000L
873
932
 
874
933
  OptionConfig(
875
934
  baseUrl = baseUrl,
876
935
  countMaxRetry = countMaxRetry,
877
- language = language
936
+ language = language,
937
+ networkTimeoutMs = networkTimeoutMs,
878
938
  )
879
939
  }
880
940
  } catch (e: Exception) {
881
941
  Log.e(TAG, "Error parsing optionConfig: ${e.message}", e)
882
- // Return default values
883
- OptionConfig(
884
- baseUrl = null,
885
- countMaxRetry = 3,
886
- language = null
942
+ OptionConfig()
943
+ }
944
+ }
945
+
946
+ private fun parseBackConfirmConfig(json: String?): LivenessBackConfirmConfig? {
947
+ if (json.isNullOrBlank() || json == "{}") return null
948
+ return try {
949
+ LivenessBackConfirmConfig(
950
+ titleVi = extractStringValue(json, "titleVi"),
951
+ titleEn = extractStringValue(json, "titleEn"),
952
+ bodyVi = extractStringValue(json, "bodyVi"),
953
+ bodyEn = extractStringValue(json, "bodyEn"),
954
+ confirmButtonVi = extractStringValue(json, "confirmButtonVi"),
955
+ confirmButtonEn = extractStringValue(json, "confirmButtonEn"),
956
+ cancelButtonVi = extractStringValue(json, "cancelButtonVi"),
957
+ cancelButtonEn = extractStringValue(json, "cancelButtonEn"),
887
958
  )
959
+ } catch (e: Exception) {
960
+ Log.e(TAG, "Error parsing backConfirmConfig: ${e.message}", e)
961
+ null
888
962
  }
889
963
  }
890
964
 
@@ -898,6 +972,16 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
898
972
  }
899
973
  }
900
974
 
975
+ private fun extractLongValue(json: String, key: String): Long? {
976
+ return try {
977
+ val pattern = "\"$key\"\\s*:\\s*(-?\\d+)".toRegex()
978
+ val match = pattern.find(json)
979
+ match?.groupValues?.get(1)?.toLong()
980
+ } catch (e: Exception) {
981
+ null
982
+ }
983
+ }
984
+
901
985
  private fun extractBooleanValue(json: String, key: String): Boolean? {
902
986
  return try {
903
987
  val pattern = "\"$key\"\\s*:\\s*(true|false)".toRegex()
@@ -1052,6 +1136,17 @@ class EKYCModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
1052
1136
  }
1053
1137
  }
1054
1138
 
1139
+ /** Extract a nested JSON object `{ ... }` for a given key. Returns the raw JSON string or null. */
1140
+ private fun extractObjectJson(json: String, key: String): String? {
1141
+ return try {
1142
+ val obj = JSONObject(json)
1143
+ val nested = obj.optJSONObject(key) ?: return null
1144
+ nested.toString()
1145
+ } catch (e: Exception) {
1146
+ null
1147
+ }
1148
+ }
1149
+
1055
1150
  // ==================== SMS OTP Methods ====================
1056
1151
 
1057
1152
  @ReactMethod
@@ -44,6 +44,8 @@ declare class SDKeKYC {
44
44
  onLivenessError(callback: (error: any) => void): EmitterSubscription | null;
45
45
  onFaceCompareSuccess(callback: (data: SDKEkycResultWithEvent) => void): EmitterSubscription | null;
46
46
  onFaceCompareError(callback: (error: any) => void): EmitterSubscription | null;
47
+ onEkycUISuccess(callback: (data: any) => void): EmitterSubscription | null;
48
+ onEkycUIError(callback: (error: any) => void): EmitterSubscription | null;
47
49
  removeAllListeners(): void;
48
50
  sendOtp(config: SmsOtpConfig): Promise<SmsOtpResult>;
49
51
  verifyOtp(config: SmsOtpConfig, otpCode: string): Promise<SmsOtpResult>;
@@ -146,6 +148,16 @@ declare class SDKeKYC {
146
148
  baseUrl?: string;
147
149
  countMaxRetry?: number;
148
150
  language?: string;
151
+ networkTimeoutMs?: number;
152
+ switchFrontCamera?: boolean;
153
+ isActiveLiveness?: boolean;
154
+ autoCapture?: boolean;
155
+ forceCaptureTimeout?: number;
156
+ customActions?: string[];
157
+ activeActionCount?: number;
158
+ appIDType?: string;
159
+ isShowBackConfirmation?: boolean;
160
+ backConfirmConfig?: import('./src/types/ekycLivenessType').LivenessBackConfirmConfig;
149
161
  }, styleConfig?: {
150
162
  textSize?: number;
151
163
  textFont?: string;
@@ -213,7 +213,10 @@ class SDKeKYC {
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 backConfirmConfigJson = config.backConfirmConfig
217
+ ? JSON.stringify(config.backConfirmConfig)
218
+ : undefined;
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, config.isShowBackConfirmation, backConfirmConfigJson);
217
220
  }
218
221
  catch (error) {
219
222
  console.error('Liveness Error:', error);
@@ -420,6 +423,38 @@ class SDKeKYC {
420
423
  return null;
421
424
  }
422
425
  }
426
+ onEkycUISuccess(callback) {
427
+ try {
428
+ const emitter = this.ensureEventEmitter();
429
+ if (!emitter) {
430
+ console.error('❌ Event emitter not available for onEkycUISuccess');
431
+ return null;
432
+ }
433
+ const listener = emitter.addListener('onEkycUISuccess', callback);
434
+ this.listeners.push(listener);
435
+ return listener;
436
+ }
437
+ catch (error) {
438
+ console.error('Failed to add onEkycUISuccess listener:', error);
439
+ return null;
440
+ }
441
+ }
442
+ onEkycUIError(callback) {
443
+ try {
444
+ const emitter = this.ensureEventEmitter();
445
+ if (!emitter) {
446
+ console.error('❌ Event emitter not available for onEkycUIError');
447
+ return null;
448
+ }
449
+ const listener = emitter.addListener('onEkycUIError', callback);
450
+ this.listeners.push(listener);
451
+ return listener;
452
+ }
453
+ catch (error) {
454
+ console.error('Failed to add onEkycUIError listener:', error);
455
+ return null;
456
+ }
457
+ }
423
458
  removeAllListeners() {
424
459
  this.listeners.forEach(listener => listener.remove());
425
460
  this.listeners = [];
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export type { OcrConfig } from './src/types/ekycOCRType';
12
12
  export type { LivenessConfig } from './src/types/ekycLivenessType';
13
13
  export { SDKFaceDetectStatus, SDK_LIVENESS_ACTIONS, customActionsToStrings } from './src/types/ekycLivenessType';
14
14
  export type { FaceServiceConfig } from './src/types/ekycFaceType';
15
+ export { EKYCEvent, EKYCErrorEvent } from './src/types/EKYCEvent';
15
16
  export type { SDKEkycResultWithEvent, SDKEkycResultStringWithEvent, StartEkycUIResult, EKYCError } from './src/types/ekycType';
16
17
  export { getEkycError, AppIDType } from './src/types/ekycType';
17
18
  export type { NfcError } from './src/types/ekycNFCType';
package/dist/index.js CHANGED
@@ -33,9 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.OCR_FAKE_PORTRAIT_DETECTED_CMND = exports.OCR_FAKE_CHARACTERS_DETECTED_CMND = 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.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_INVALID_RECOVERY_OR_PIN = exports.ESIGN_SESSION_INVALID_REGISTER = 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 = 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 = void 0;
36
+ 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;
37
+ 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;
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 = void 0;
39
39
  const EKYCModule_1 = __importStar(require("./EKYCModule"));
40
40
  exports.sdkEKYC = EKYCModule_1.default;
41
41
  Object.defineProperty(exports, "SDKeKYC", { enumerable: true, get: function () { return EKYCModule_1.SDKeKYC; } });
@@ -59,6 +59,10 @@ var ekycLivenessType_1 = require("./src/types/ekycLivenessType");
59
59
  Object.defineProperty(exports, "SDKFaceDetectStatus", { enumerable: true, get: function () { return ekycLivenessType_1.SDKFaceDetectStatus; } });
60
60
  Object.defineProperty(exports, "SDK_LIVENESS_ACTIONS", { enumerable: true, get: function () { return ekycLivenessType_1.SDK_LIVENESS_ACTIONS; } });
61
61
  Object.defineProperty(exports, "customActionsToStrings", { enumerable: true, get: function () { return ekycLivenessType_1.customActionsToStrings; } });
62
+ // Export event enums (port of Android EKYCEvent.kt & EKYCErrorEvent.kt)
63
+ var EKYCEvent_1 = require("./src/types/EKYCEvent");
64
+ Object.defineProperty(exports, "EKYCEvent", { enumerable: true, get: function () { return EKYCEvent_1.EKYCEvent; } });
65
+ Object.defineProperty(exports, "EKYCErrorEvent", { enumerable: true, get: function () { return EKYCEvent_1.EKYCErrorEvent; } });
62
66
  var ekycType_1 = require("./src/types/ekycType");
63
67
  Object.defineProperty(exports, "getEkycError", { enumerable: true, get: function () { return ekycType_1.getEkycError; } });
64
68
  Object.defineProperty(exports, "AppIDType", { enumerable: true, get: function () { return ekycType_1.AppIDType; } });
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos_sdk/sdk-ekyc",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
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",
@@ -146,6 +146,14 @@ export declare class FinosEKYCModule {
146
146
  onFaceCompareSuccess(callback: (data: SDKEkycResultWithEvent) => void): import("react-native").EmitterSubscription | null;
147
147
  /** Payload là EKYCError: { event, code, message }. */
148
148
  onFaceCompareError(callback: (error: EKYCError) => void): import("react-native").EmitterSubscription | null;
149
+ /**
150
+ * Listen for eKYC UI success events (including LOG_SUCCESS from Liveness/FaceService submit)
151
+ */
152
+ onEkycUISuccess(callback: (data: any) => void): import("react-native").EmitterSubscription | null;
153
+ /**
154
+ * Listen for eKYC UI error events
155
+ */
156
+ onEkycUIError(callback: (error: any) => void): import("react-native").EmitterSubscription | null;
149
157
  /**
150
158
  * Remove all event listeners
151
159
  */
@@ -300,6 +308,8 @@ export declare class FinosEKYCModule {
300
308
  baseUrl?: string;
301
309
  countMaxRetry?: number;
302
310
  language?: string;
311
+ /** Network timeout in milliseconds (default: 30000). callTimeout = networkTimeoutMs * 2 */
312
+ networkTimeoutMs?: number;
303
313
  switchFrontCamera?: boolean;
304
314
  /** LivenessConfig – SDKeKYCActivity (157-169) */
305
315
  isActiveLiveness?: boolean;
@@ -310,6 +320,10 @@ export declare class FinosEKYCModule {
310
320
  activeActionCount?: number;
311
321
  /** AppIDType: NONE | HD_BANK | VIKKI (default: AppIDType.NONE) */
312
322
  appIDType?: AppIDType;
323
+ /** Show confirmation bottom sheet when user presses back in liveness screen (v1.4.6+) */
324
+ isShowBackConfirmation?: boolean;
325
+ /** Text config for the back confirmation bottom sheet (v1.4.6+) */
326
+ backConfirmConfig?: import('../types/ekycLivenessType').LivenessBackConfirmConfig;
313
327
  }, styleConfig?: {
314
328
  textSize?: number;
315
329
  textFont?: string;
@@ -345,6 +345,18 @@ class FinosEKYCModule {
345
345
  onFaceCompareError(callback) {
346
346
  return this.sdk.onFaceCompareError(callback);
347
347
  }
348
+ /**
349
+ * Listen for eKYC UI success events (including LOG_SUCCESS from Liveness/FaceService submit)
350
+ */
351
+ onEkycUISuccess(callback) {
352
+ return this.sdk.onEkycUISuccess(callback);
353
+ }
354
+ /**
355
+ * Listen for eKYC UI error events
356
+ */
357
+ onEkycUIError(callback) {
358
+ return this.sdk.onEkycUIError(callback);
359
+ }
348
360
  /**
349
361
  * Remove all event listeners
350
362
  */
@@ -286,6 +286,8 @@ export declare class FinosESignModule {
286
286
  baseUrl?: string;
287
287
  countMaxRetry?: number;
288
288
  language?: string;
289
+ /** Network timeout in milliseconds (default: 30000). callTimeout = networkTimeoutMs * 2 */
290
+ networkTimeoutMs?: number;
289
291
  switchFrontCamera?: boolean;
290
292
  }, styleConfig?: {
291
293
  textSize?: number;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * React Native port of EkycNativeAndroid EKYCEvent.kt
3
+ * Enum các sự kiện SDK trả về qua callback, đồng bộ 1:1 với Android enum.
4
+ *
5
+ * @see EkycNativeAndroid/Module/SDKCore/src/main/java/finos/sdk/core/define/EKYCEvent.kt
6
+ */
7
+ /**
8
+ * EKYCEvent – tên event trả về từ native callback success.
9
+ * Giá trị string map chính xác với Android enum name.
10
+ */
11
+ export declare enum EKYCEvent {
12
+ /** SDK khởi tạo thành công, activity/flow vừa mở. */
13
+ SDK_START_SUCCESS = "SDK_START_SUCCESS",
14
+ /** SDK flow hoàn thành, có data kết quả. */
15
+ SDK_END_SUCCESS = "SDK_END_SUCCESS",
16
+ /** Bắt đầu quét NFC (đang chờ thẻ). */
17
+ SCAN_NFC_START = "SCAN_NFC_START",
18
+ /** Quét NFC thành công, có dữ liệu thẻ. */
19
+ SCAN_NFC_SUCCESS = "SCAN_NFC_SUCCESS",
20
+ /** Xác minh C06 thành công. */
21
+ C06_SUCCESS = "C06_SUCCESS",
22
+ /** Liveness detection thành công. */
23
+ LIVENESS_SUCCESS = "LIVENESS_SUCCESS",
24
+ /** Face detection đang xử lý (progress). */
25
+ FACE_PROGRESS = "FACE_PROGRESS",
26
+ /** Face compare thành công. */
27
+ FACE_SUCCESS = "FACE_SUCCESS",
28
+ /** OCR xử lý thành công. */
29
+ OCR_SUCCESS = "OCR_SUCCESS",
30
+ /** QR Code quét thành công. */
31
+ QRCODE_SUCCESS = "QRCODE_SUCCESS",
32
+ /** Lấy lịch sử giao dịch thành công. */
33
+ FETCH_LATEST_TRANSACTION_SUCCESS = "FETCH_LATEST_TRANSACTION_SUCCESS",
34
+ /** Gửi SMS OTP thành công. */
35
+ SMS_OTP_SEND_SUCCESS = "SMS_OTP_SEND_SUCCESS",
36
+ /** Xác minh SMS OTP thành công. */
37
+ SMS_OTP_VERIFY_SUCCESS = "SMS_OTP_VERIFY_SUCCESS",
38
+ /** Gửi lại SMS OTP thành công. */
39
+ SMS_OTP_RESEND_SUCCESS = "SMS_OTP_RESEND_SUCCESS",
40
+ /** Kết quả NFC/Liveness/FaceService đã submit lên server thành công (v1.4.5). */
41
+ LOG_SUCCESS = "LOG_SUCCESS"
42
+ }
43
+ /**
44
+ * EKYCErrorEvent – tên event trả về từ native callback error.
45
+ * Đồng bộ với Android enum EKYCErrorEvent.
46
+ *
47
+ * @see EkycNativeAndroid/Module/SDKCore/src/main/java/finos/sdk/core/define/EKYCErrorEvent.kt
48
+ */
49
+ export declare enum EKYCErrorEvent {
50
+ SDK_START_ERROR = "SDK_START_ERROR",
51
+ OCR_ERROR = "OCR_ERROR",
52
+ LIVENESS_ERROR = "LIVENESS_ERROR",
53
+ FACE_ERROR = "FACE_ERROR",
54
+ NFC_ERROR = "NFC_ERROR",
55
+ C06_ERROR = "C06_ERROR",
56
+ SDK_DETAIL = "SDK_DETAIL",
57
+ SMS_OTP_ERROR = "SMS_OTP_ERROR",
58
+ ESIGN_ERROR = "ESIGN_ERROR",
59
+ USER_CANCEL = "USER_CANCEL"
60
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /**
3
+ * React Native port of EkycNativeAndroid EKYCEvent.kt
4
+ * Enum các sự kiện SDK trả về qua callback, đồng bộ 1:1 với Android enum.
5
+ *
6
+ * @see EkycNativeAndroid/Module/SDKCore/src/main/java/finos/sdk/core/define/EKYCEvent.kt
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.EKYCErrorEvent = exports.EKYCEvent = void 0;
10
+ /**
11
+ * EKYCEvent – tên event trả về từ native callback success.
12
+ * Giá trị string map chính xác với Android enum name.
13
+ */
14
+ var EKYCEvent;
15
+ (function (EKYCEvent) {
16
+ /** SDK khởi tạo thành công, activity/flow vừa mở. */
17
+ EKYCEvent["SDK_START_SUCCESS"] = "SDK_START_SUCCESS";
18
+ /** SDK flow hoàn thành, có data kết quả. */
19
+ EKYCEvent["SDK_END_SUCCESS"] = "SDK_END_SUCCESS";
20
+ /** Bắt đầu quét NFC (đang chờ thẻ). */
21
+ EKYCEvent["SCAN_NFC_START"] = "SCAN_NFC_START";
22
+ /** Quét NFC thành công, có dữ liệu thẻ. */
23
+ EKYCEvent["SCAN_NFC_SUCCESS"] = "SCAN_NFC_SUCCESS";
24
+ /** Xác minh C06 thành công. */
25
+ EKYCEvent["C06_SUCCESS"] = "C06_SUCCESS";
26
+ /** Liveness detection thành công. */
27
+ EKYCEvent["LIVENESS_SUCCESS"] = "LIVENESS_SUCCESS";
28
+ /** Face detection đang xử lý (progress). */
29
+ EKYCEvent["FACE_PROGRESS"] = "FACE_PROGRESS";
30
+ /** Face compare thành công. */
31
+ EKYCEvent["FACE_SUCCESS"] = "FACE_SUCCESS";
32
+ /** OCR xử lý thành công. */
33
+ EKYCEvent["OCR_SUCCESS"] = "OCR_SUCCESS";
34
+ /** QR Code quét thành công. */
35
+ EKYCEvent["QRCODE_SUCCESS"] = "QRCODE_SUCCESS";
36
+ /** Lấy lịch sử giao dịch thành công. */
37
+ EKYCEvent["FETCH_LATEST_TRANSACTION_SUCCESS"] = "FETCH_LATEST_TRANSACTION_SUCCESS";
38
+ /** Gửi SMS OTP thành công. */
39
+ EKYCEvent["SMS_OTP_SEND_SUCCESS"] = "SMS_OTP_SEND_SUCCESS";
40
+ /** Xác minh SMS OTP thành công. */
41
+ EKYCEvent["SMS_OTP_VERIFY_SUCCESS"] = "SMS_OTP_VERIFY_SUCCESS";
42
+ /** Gửi lại SMS OTP thành công. */
43
+ EKYCEvent["SMS_OTP_RESEND_SUCCESS"] = "SMS_OTP_RESEND_SUCCESS";
44
+ /** Kết quả NFC/Liveness/FaceService đã submit lên server thành công (v1.4.5). */
45
+ EKYCEvent["LOG_SUCCESS"] = "LOG_SUCCESS";
46
+ })(EKYCEvent || (exports.EKYCEvent = EKYCEvent = {}));
47
+ /**
48
+ * EKYCErrorEvent – tên event trả về từ native callback error.
49
+ * Đồng bộ với Android enum EKYCErrorEvent.
50
+ *
51
+ * @see EkycNativeAndroid/Module/SDKCore/src/main/java/finos/sdk/core/define/EKYCErrorEvent.kt
52
+ */
53
+ var EKYCErrorEvent;
54
+ (function (EKYCErrorEvent) {
55
+ EKYCErrorEvent["SDK_START_ERROR"] = "SDK_START_ERROR";
56
+ EKYCErrorEvent["OCR_ERROR"] = "OCR_ERROR";
57
+ EKYCErrorEvent["LIVENESS_ERROR"] = "LIVENESS_ERROR";
58
+ EKYCErrorEvent["FACE_ERROR"] = "FACE_ERROR";
59
+ EKYCErrorEvent["NFC_ERROR"] = "NFC_ERROR";
60
+ EKYCErrorEvent["C06_ERROR"] = "C06_ERROR";
61
+ EKYCErrorEvent["SDK_DETAIL"] = "SDK_DETAIL";
62
+ EKYCErrorEvent["SMS_OTP_ERROR"] = "SMS_OTP_ERROR";
63
+ EKYCErrorEvent["ESIGN_ERROR"] = "ESIGN_ERROR";
64
+ EKYCErrorEvent["USER_CANCEL"] = "USER_CANCEL";
65
+ })(EKYCErrorEvent || (exports.EKYCErrorEvent = EKYCErrorEvent = {}));
@@ -56,6 +56,7 @@ export interface ESignSignRequestConfirm {
56
56
  export interface ESignApiResponse {
57
57
  status: number;
58
58
  msg: string;
59
+ errorCode?: string;
59
60
  data?: {
60
61
  sessionId?: string;
61
62
  [key: string]: any;
@@ -69,6 +70,7 @@ export interface ESignApiResponse {
69
70
  export interface ESignPdfResult {
70
71
  status: number;
71
72
  msg: string;
73
+ errorCode?: string;
72
74
  data?: {
73
75
  transactionId: string;
74
76
  [key: string]: any;
@@ -20,6 +20,17 @@ export declare enum SDKFaceDetectStatus {
20
20
  export declare const SDK_LIVENESS_ACTIONS: readonly SDKFaceDetectStatus[];
21
21
  /** Chuyển customActions enum[] sang string[] khi gửi xuống native. */
22
22
  export declare function customActionsToStrings(actions: SDKFaceDetectStatus[]): string[];
23
+ /** Text config for the back-press confirmation bottom sheet (v1.4.6+). All fields optional – fallback to built-in strings. */
24
+ export interface LivenessBackConfirmConfig {
25
+ titleVi?: string;
26
+ titleEn?: string;
27
+ bodyVi?: string;
28
+ bodyEn?: string;
29
+ confirmButtonVi?: string;
30
+ confirmButtonEn?: string;
31
+ cancelButtonVi?: string;
32
+ cancelButtonEn?: string;
33
+ }
23
34
  export interface LivenessConfig {
24
35
  appKey: string;
25
36
  transactionId?: string;
@@ -30,6 +41,8 @@ export interface LivenessConfig {
30
41
  customActions?: SDKFaceDetectStatus[];
31
42
  activeActionCount?: number;
32
43
  forceCaptureTimeout?: number;
44
+ isShowBackConfirmation?: boolean;
45
+ backConfirmConfig?: LivenessBackConfirmConfig;
33
46
  }
34
47
  export interface CheckLivenessResponse {
35
48
  metadata?: Metadata;
@@ -96,14 +96,14 @@ class EKYCModule: RCTEventEmitter {
96
96
  callbackSuccess: { event, data in
97
97
  switch event {
98
98
  case .SCAN_NFC_START:
99
- self?.emit("onNfcScanStart", body: ["event": event.description, "data": "\(String(describing: data))"])
99
+ self?.emit("onNfcScanStart", body: ["event": event.description, "data": (data as? SDKEkycResult)?.nfcResponse ?? "{}"])
100
100
  case .SCAN_NFC_SUCCESS:
101
101
  let nfcResponse = (data as? SDKEkycResult)?.nfcResponse ?? ""
102
102
  let body: [String: Any] = ["event": event.description, "data": nfcResponse]
103
103
  self?.emit("onNfcScanSuccess", body: body)
104
104
  resolve(body)
105
105
  default:
106
- self?.emit("onNfcEvent", body: ["event": event.description, "data": "\(String(describing: data))"])
106
+ self?.emit("onNfcEvent", body: ["event": event.description, "data": (data as? SDKEkycResult)?.nfcResponse ?? "{}"])
107
107
  }
108
108
  },
109
109
  callbackError: { event, errorResult in
@@ -123,7 +123,8 @@ class EKYCModule: RCTEventEmitter {
123
123
  let ekycConfig = EKYCConfigSDK(appKey: AppKeyConfig(appKey: appKey), c06Config: c06Config)
124
124
  SdkEkycC06.startEkyc(ekycConfigSDK: ekycConfig,
125
125
  callbackSuccess: { [weak self] event, data in
126
- let body: [String: Any] = ["event": event.description, "data": "\(String(describing: data))"]
126
+ let c06Response = (data as? SDKEkycResult)?.checkC06Response?.description ?? "{}"
127
+ let body: [String: Any] = ["event": event.description, "data": c06Response]
127
128
  self?.emit("onC06Success", body: body)
128
129
  resolve(body)
129
130
  },
@@ -210,7 +211,17 @@ class EKYCModule: RCTEventEmitter {
210
211
  DispatchQueue.main.async { [weak self] in
211
212
  SdkEkycFaceService.startEkyc(ekycConfigSDK: ekycConfig,
212
213
  callbackSuccess: { event, data in
213
- let body: [String: Any] = ["event": event.description, "data": "\(String(describing: data))"]
214
+ let faceResponse = (data as? SDKEkycResult)?.checkFaceResponse
215
+ var faceDict: [String: Any] = [:]
216
+ if let v = faceResponse?.requestId { faceDict["requestId"] = v }
217
+ if let r = faceResponse?.result {
218
+ faceDict["result"] = ["conf": r.conf, "match": r.match, "matchScore": r.matchScore, "toBeReviewed": r.toBeReviewed]
219
+ }
220
+ if let v = faceResponse?.status { faceDict["status"] = v }
221
+ if let v = faceResponse?.statusCode { faceDict["statusCode"] = v }
222
+ if let v = faceResponse?.error { faceDict["error"] = v }
223
+ if let v = faceResponse?.type { faceDict["type"] = v }
224
+ let body: [String: Any] = ["event": event.description, "data": faceDict]
214
225
  self?.emit("onFaceCompareSuccess", body: body)
215
226
  resolve(body)
216
227
  },
@@ -291,7 +302,16 @@ class EKYCModule: RCTEventEmitter {
291
302
  return
292
303
  }
293
304
  let files = result?.ekycStateModel?.eKYCFileModel
294
- var body: [String: Any] = ["status": "success", "event": event.description, "data": "\(String(describing: data))", "transactionId": result?.ekycStateModel?.transactionId ?? ""]
305
+ var dataDict: [String: Any] = [:]
306
+ if let v = result?.nfcResponse { dataDict["nfcResponse"] = v }
307
+ if let v = result?.checkC06Response?.description { dataDict["checkC06Response"] = v }
308
+ if let v = result?.ocrResponse?.description { dataDict["ocrResponse"] = v }
309
+ if let v = result?.checkLivenessResponse?.description { dataDict["checkLivenessResponse"] = v }
310
+ if let v = result?.checkFaceResponse?.description { dataDict["checkFaceResponse"] = v }
311
+ if let v = result?.customData { dataDict["customData"] = v }
312
+ let dataJson = (try? JSONSerialization.data(withJSONObject: dataDict))
313
+ .flatMap { String(data: $0, encoding: .utf8) } ?? "{}"
314
+ var body: [String: Any] = ["status": "success", "event": event.description, "data": dataJson, "transactionId": result?.ekycStateModel?.transactionId ?? ""]
295
315
  if let facePath = files?.imageFace { body["imageFacePath"] = facePath.path }
296
316
  if let frontPath = files?.imageOcrFront { body["imageOcrFrontPath"] = frontPath.path }
297
317
  if let backPath = files?.imageOcrBack { body["imageOcrBackPath"] = backPath.path }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos_sdk/sdk-ekyc",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
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",
@@ -361,6 +361,20 @@ export class FinosEKYCModule {
361
361
  return this.sdk.onFaceCompareError(callback);
362
362
  }
363
363
 
364
+ /**
365
+ * Listen for eKYC UI success events (including LOG_SUCCESS from Liveness/FaceService submit)
366
+ */
367
+ public onEkycUISuccess(callback: (data: any) => void) {
368
+ return this.sdk.onEkycUISuccess(callback);
369
+ }
370
+
371
+ /**
372
+ * Listen for eKYC UI error events
373
+ */
374
+ public onEkycUIError(callback: (error: any) => void) {
375
+ return this.sdk.onEkycUIError(callback);
376
+ }
377
+
364
378
  /**
365
379
  * Remove all event listeners
366
380
  */
@@ -750,6 +764,8 @@ export class FinosEKYCModule {
750
764
  baseUrl?: string;
751
765
  countMaxRetry?: number;
752
766
  language?: string;
767
+ /** Network timeout in milliseconds (default: 30000). callTimeout = networkTimeoutMs * 2 */
768
+ networkTimeoutMs?: number;
753
769
  switchFrontCamera?: boolean;
754
770
  /** LivenessConfig – SDKeKYCActivity (157-169) */
755
771
  isActiveLiveness?: boolean;
@@ -760,6 +776,10 @@ export class FinosEKYCModule {
760
776
  activeActionCount?: number;
761
777
  /** AppIDType: NONE | HD_BANK | VIKKI (default: AppIDType.NONE) */
762
778
  appIDType?: AppIDType;
779
+ /** Show confirmation bottom sheet when user presses back in liveness screen (v1.4.6+) */
780
+ isShowBackConfirmation?: boolean;
781
+ /** Text config for the back confirmation bottom sheet (v1.4.6+) */
782
+ backConfirmConfig?: import('../types/ekycLivenessType').LivenessBackConfirmConfig;
763
783
  },
764
784
  styleConfig?: {
765
785
  textSize?: number;
@@ -634,6 +634,8 @@ export class FinosESignModule {
634
634
  baseUrl?: string;
635
635
  countMaxRetry?: number;
636
636
  language?: string;
637
+ /** Network timeout in milliseconds (default: 30000). callTimeout = networkTimeoutMs * 2 */
638
+ networkTimeoutMs?: number;
637
639
  switchFrontCamera?: boolean;
638
640
  },
639
641
  styleConfig?: {
@@ -0,0 +1,76 @@
1
+ /**
2
+ * React Native port of EkycNativeAndroid EKYCEvent.kt
3
+ * Enum các sự kiện SDK trả về qua callback, đồng bộ 1:1 với Android enum.
4
+ *
5
+ * @see EkycNativeAndroid/Module/SDKCore/src/main/java/finos/sdk/core/define/EKYCEvent.kt
6
+ */
7
+
8
+ /**
9
+ * EKYCEvent – tên event trả về từ native callback success.
10
+ * Giá trị string map chính xác với Android enum name.
11
+ */
12
+ export enum EKYCEvent {
13
+ /** SDK khởi tạo thành công, activity/flow vừa mở. */
14
+ SDK_START_SUCCESS = 'SDK_START_SUCCESS',
15
+
16
+ /** SDK flow hoàn thành, có data kết quả. */
17
+ SDK_END_SUCCESS = 'SDK_END_SUCCESS',
18
+
19
+ /** Bắt đầu quét NFC (đang chờ thẻ). */
20
+ SCAN_NFC_START = 'SCAN_NFC_START',
21
+
22
+ /** Quét NFC thành công, có dữ liệu thẻ. */
23
+ SCAN_NFC_SUCCESS = 'SCAN_NFC_SUCCESS',
24
+
25
+ /** Xác minh C06 thành công. */
26
+ C06_SUCCESS = 'C06_SUCCESS',
27
+
28
+ /** Liveness detection thành công. */
29
+ LIVENESS_SUCCESS = 'LIVENESS_SUCCESS',
30
+
31
+ /** Face detection đang xử lý (progress). */
32
+ FACE_PROGRESS = 'FACE_PROGRESS',
33
+
34
+ /** Face compare thành công. */
35
+ FACE_SUCCESS = 'FACE_SUCCESS',
36
+
37
+ /** OCR xử lý thành công. */
38
+ OCR_SUCCESS = 'OCR_SUCCESS',
39
+
40
+ /** QR Code quét thành công. */
41
+ QRCODE_SUCCESS = 'QRCODE_SUCCESS',
42
+
43
+ /** Lấy lịch sử giao dịch thành công. */
44
+ FETCH_LATEST_TRANSACTION_SUCCESS = 'FETCH_LATEST_TRANSACTION_SUCCESS',
45
+
46
+ /** Gửi SMS OTP thành công. */
47
+ SMS_OTP_SEND_SUCCESS = 'SMS_OTP_SEND_SUCCESS',
48
+
49
+ /** Xác minh SMS OTP thành công. */
50
+ SMS_OTP_VERIFY_SUCCESS = 'SMS_OTP_VERIFY_SUCCESS',
51
+
52
+ /** Gửi lại SMS OTP thành công. */
53
+ SMS_OTP_RESEND_SUCCESS = 'SMS_OTP_RESEND_SUCCESS',
54
+
55
+ /** Kết quả NFC/Liveness/FaceService đã submit lên server thành công (v1.4.5). */
56
+ LOG_SUCCESS = 'LOG_SUCCESS',
57
+ }
58
+
59
+ /**
60
+ * EKYCErrorEvent – tên event trả về từ native callback error.
61
+ * Đồng bộ với Android enum EKYCErrorEvent.
62
+ *
63
+ * @see EkycNativeAndroid/Module/SDKCore/src/main/java/finos/sdk/core/define/EKYCErrorEvent.kt
64
+ */
65
+ export enum EKYCErrorEvent {
66
+ SDK_START_ERROR = 'SDK_START_ERROR',
67
+ OCR_ERROR = 'OCR_ERROR',
68
+ LIVENESS_ERROR = 'LIVENESS_ERROR',
69
+ FACE_ERROR = 'FACE_ERROR',
70
+ NFC_ERROR = 'NFC_ERROR',
71
+ C06_ERROR = 'C06_ERROR',
72
+ SDK_DETAIL = 'SDK_DETAIL',
73
+ SMS_OTP_ERROR = 'SMS_OTP_ERROR',
74
+ ESIGN_ERROR = 'ESIGN_ERROR',
75
+ USER_CANCEL = 'USER_CANCEL',
76
+ }
@@ -64,6 +64,7 @@ export interface ESignSignRequestConfirm {
64
64
  export interface ESignApiResponse {
65
65
  status: number;
66
66
  msg: string;
67
+ errorCode?: string;
67
68
  data?: {
68
69
  sessionId?: string;
69
70
  [key: string]: any;
@@ -78,6 +79,7 @@ export interface ESignApiResponse {
78
79
  export interface ESignPdfResult {
79
80
  status: number;
80
81
  msg: string;
82
+ errorCode?: string;
81
83
  data?: {
82
84
  transactionId: string;
83
85
  [key: string]: any; // Cho phép các field động khác
@@ -38,11 +38,23 @@ export function customActionsToStrings(actions: SDKFaceDetectStatus[]): string[]
38
38
  return actions.map(a => a as string);
39
39
  }
40
40
 
41
+ /** Text config for the back-press confirmation bottom sheet (v1.4.6+). All fields optional – fallback to built-in strings. */
42
+ export interface LivenessBackConfirmConfig {
43
+ titleVi?: string;
44
+ titleEn?: string;
45
+ bodyVi?: string;
46
+ bodyEn?: string;
47
+ confirmButtonVi?: string;
48
+ confirmButtonEn?: string;
49
+ cancelButtonVi?: string;
50
+ cancelButtonEn?: string;
51
+ }
52
+
41
53
  export interface LivenessConfig {
42
54
  appKey: string;
43
55
  transactionId?: string;
44
56
  // old fields usingRandomAction and isStraight removed in 1.3.1
45
- // usingRandomAction: boolean;
57
+ // usingRandomAction: boolean;
46
58
  // isStraight: boolean;
47
59
  selfieImage: string;
48
60
  // New fields for version 1.3.0
@@ -52,6 +64,9 @@ export interface LivenessConfig {
52
64
  customActions?: SDKFaceDetectStatus[];
53
65
  activeActionCount?: number;
54
66
  forceCaptureTimeout?: number;
67
+ // New fields for version 1.4.6
68
+ isShowBackConfirmation?: boolean;
69
+ backConfirmConfig?: LivenessBackConfirmConfig;
55
70
  }
56
71
 
57
72
  export interface CheckLivenessResponse {