@sanctum-key/react-native-sdk 1.0.52 → 1.0.54
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 +7 -2
- package/android/build/.transforms/3db9b15041d4285a820fc84462995ea1/results.bin +1 -0
- package/android/build/.transforms/3db9b15041d4285a820fc84462995ea1/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$BarcodeRegion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$5$1.class → SanctumKeySdkModule$definition$1$6$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$5$2.class → SanctumKeySdkModule$definition$1$6$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$1.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$5.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$3.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$4.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$4.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$2.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$5.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunction$6.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$6.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$1.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$3.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$3.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$2.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$5.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$6.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$AsyncFunctionWithPromise$4.class → SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$7.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$$inlined$View$1.class → SanctumKeySdkModule$definition$lambda$16$$inlined$View$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$lambda$4$$inlined$Prop$1.class → SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$5$lambda$4$$inlined$Prop$2.class → SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule.class +0 -0
- package/android/build.gradle +7 -0
- package/android/src/main/java/kyc/sanctumkey/com/SanctumKeySdkModule.kt +428 -1
- package/build/package.json +1 -1
- package/build/src/SanctumKeySdkModule.d.ts +1 -0
- package/build/src/SanctumKeySdkModule.d.ts.map +1 -1
- package/build/src/SanctumKeySdkModule.js.map +1 -1
- package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/src/components/EnhancedCameraView.js +50 -41
- package/build/src/components/EnhancedCameraView.js.map +1 -1
- package/build/src/components/EnhancedCameraView.web.d.ts +2 -0
- package/build/src/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/src/components/EnhancedCameraView.web.js +11 -6
- package/build/src/components/EnhancedCameraView.web.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +499 -78
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/src/components/TemplateKYCExample.js +17 -21
- package/build/src/components/TemplateKYCExample.js.map +1 -1
- package/build/src/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/src/components/TemplateKYCFlowRefactored.js +2 -10
- package/build/src/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/src/components/WebBarcodeScanner.d.ts +2 -0
- package/build/src/components/WebBarcodeScanner.d.ts.map +1 -1
- package/build/src/components/WebBarcodeScanner.js +99 -85
- package/build/src/components/WebBarcodeScanner.js.map +1 -1
- package/build/src/hooks/useTemplateLoader.d.ts.map +1 -1
- package/build/src/hooks/useTemplateLoader.js +0 -2
- package/build/src/hooks/useTemplateLoader.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +1 -0
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +1 -1
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/build/src/modules/api/TemplateService.d.ts.map +1 -1
- package/build/src/modules/api/TemplateService.js +2 -1
- package/build/src/modules/api/TemplateService.js.map +1 -1
- package/build/src/modules/api/types.d.ts +35 -27
- package/build/src/modules/api/types.d.ts.map +1 -1
- package/build/src/modules/api/types.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/withVisionCamera.d.ts +1 -0
- package/plugin/build/withVisionCamera.js +13 -1
- package/plugin/src/withVisionCamera.js +18 -2
- package/plugin/src/withVisionCamera.ts +19 -2
- package/src/SanctumKeySdkModule.ts +1 -0
- package/src/components/EnhancedCameraView.tsx +52 -41
- package/src/components/EnhancedCameraView.web.tsx +15 -5
- package/src/components/KYCElements/IDCardCapture.tsx +552 -75
- package/src/components/TemplateKYCExample.tsx +23 -25
- package/src/components/TemplateKYCFlowRefactored.tsx +2 -8
- package/src/components/WebBarcodeScanner.tsx +147 -198
- package/src/hooks/useTemplateLoader.ts +0 -2
- package/src/modules/api/KYCService.ts +3 -3
- package/src/modules/api/TemplateService.ts +3 -2
- package/src/modules/api/types.ts +37 -29
|
@@ -86,53 +86,51 @@ export function TemplateKYCExample({
|
|
|
86
86
|
let finalPayload: any = data; // Fallback to raw data if mapping fails
|
|
87
87
|
|
|
88
88
|
if ((data.status === 'success' || data.status === 'in_progress') && data.result) {
|
|
89
|
-
// 1. Extract the dynamic root key (e.g., 'national_id', 'passport')
|
|
90
|
-
const docKey = Object.keys(data.result)[0];
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
const backendData = data.result.data;
|
|
91
|
+
|
|
92
|
+
if (backendData) {
|
|
93
|
+
const personalInfo = backendData.user_data?.personal_information || {};
|
|
94
|
+
const activeSessionId = kyc_session_id || existingSessionId || backendData.session_id || "";
|
|
95
|
+
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
const activeSessionId = kyc_session_id || existingSessionId || "";
|
|
97
|
+
const docType = (backendData as any).document_type || (backendData as any).documentType;
|
|
98
98
|
|
|
99
|
-
// 2. Strict mapping to your expected format
|
|
100
99
|
finalPayload = {
|
|
101
100
|
data: {
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
document_type: docType,
|
|
102
|
+
verification_id: backendData.verification_id,
|
|
103
|
+
verification_status: backendData.verification_status,
|
|
104
104
|
session_id: activeSessionId,
|
|
105
105
|
user_data: {
|
|
106
106
|
personal_information: {
|
|
107
|
-
first_name: personalInfo.first_name || undefined,
|
|
107
|
+
first_name: personalInfo.first_name || personalInfo.given_name || undefined,
|
|
108
|
+
last_name: personalInfo.last_name || personalInfo.surname || undefined,
|
|
108
109
|
given_name: personalInfo.given_name || undefined,
|
|
109
|
-
|
|
110
|
-
surname: personalInfo.last_name || undefined, // fallback
|
|
110
|
+
surname: personalInfo.surname || undefined,
|
|
111
111
|
address: personalInfo.address || undefined,
|
|
112
|
-
city: personalInfo.city || undefined,
|
|
113
|
-
postal_code: personalInfo.postal_code || undefined,
|
|
114
112
|
expiry_date: personalInfo.expiry_date || undefined,
|
|
115
113
|
issue_date: personalInfo.issue_date || undefined,
|
|
116
|
-
date_of_birth: personalInfo.date_of_birth || undefined,
|
|
117
|
-
birth_date: personalInfo.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
date_of_birth: personalInfo.date_of_birth || personalInfo.birth_date || undefined,
|
|
115
|
+
birth_date: personalInfo.birth_date || undefined,
|
|
116
|
+
document_number: personalInfo.document_number || undefined,
|
|
117
|
+
nationality: personalInfo.nationality || undefined,
|
|
118
|
+
sex: personalInfo.sex || undefined,
|
|
121
119
|
}
|
|
122
120
|
}
|
|
123
121
|
}
|
|
124
122
|
};
|
|
125
123
|
|
|
126
|
-
sdkLogger.info("Wrapper
|
|
127
|
-
|
|
124
|
+
sdkLogger.info("Wrapper formatteddddd completion payload successfully", {
|
|
125
|
+
data: finalPayload
|
|
128
126
|
});
|
|
129
127
|
}
|
|
130
128
|
} else {
|
|
131
129
|
sdkLogger.warn("Wrapper received completion without a success result object", { status: data.status });
|
|
132
130
|
}
|
|
133
131
|
|
|
134
|
-
onComplete(finalPayload
|
|
135
|
-
|
|
132
|
+
onComplete(finalPayload);
|
|
133
|
+
};
|
|
136
134
|
|
|
137
135
|
const handleCancel = () => {
|
|
138
136
|
console.log('KYC Template flow cancelled');
|
|
@@ -140,7 +138,7 @@ export function TemplateKYCExample({
|
|
|
140
138
|
};
|
|
141
139
|
|
|
142
140
|
const handleError = (error: string) => {
|
|
143
|
-
|
|
141
|
+
sdkLogger.error('KYC Template error:', error);
|
|
144
142
|
onError(error);
|
|
145
143
|
};
|
|
146
144
|
|
|
@@ -125,11 +125,7 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
|
|
|
125
125
|
|
|
126
126
|
const template = providedTemplate || loadedTemplate;
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
if (template) {
|
|
130
|
-
sdkLogger.info("Template loaded successfully", { componentCount: template.components.length });
|
|
131
|
-
}
|
|
132
|
-
}, [template]);
|
|
128
|
+
|
|
133
129
|
|
|
134
130
|
if (templateId && isLoading && !template) {
|
|
135
131
|
return (
|
|
@@ -178,12 +174,11 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
|
|
|
178
174
|
onError={(err) => {
|
|
179
175
|
sdkLogger.error("KYC Flow Error", { error: err });
|
|
180
176
|
sdkLogger.flush();
|
|
177
|
+
logger.log('Error', err)
|
|
181
178
|
if (onError) onError(err);
|
|
182
179
|
}}
|
|
183
180
|
onCancel={OnCancel}
|
|
184
181
|
initialLanguage={language}
|
|
185
|
-
// 🚨 3. Pass the resolved active API key down to the provider!
|
|
186
|
-
// The context/hooks will automatically use this key.
|
|
187
182
|
apiKey={activeApiKey}
|
|
188
183
|
testApiKey={TEST_API_KEY}
|
|
189
184
|
env={env}
|
|
@@ -203,7 +198,6 @@ const TemplateKYCFlowContent: React.FC<{ onCancel?: () => void }> = ({ onCancel
|
|
|
203
198
|
const { state, actions, currentComponent, progress } = useTemplateKYCFlowContext();
|
|
204
199
|
const { t } = useI18n();
|
|
205
200
|
|
|
206
|
-
console.log(`sessionnnn id: ${state.session.session_id}`)
|
|
207
201
|
|
|
208
202
|
useEffect(() => {
|
|
209
203
|
if (state.session?.session_id) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import type { CodeType } from 'react-native-vision-camera';
|
|
2
3
|
import {
|
|
3
4
|
MultiFormatReader,
|
|
4
5
|
BarcodeFormat,
|
|
@@ -13,261 +14,209 @@ interface WebBarcodeScannerProps {
|
|
|
13
14
|
videoRef: React.RefObject<HTMLVideoElement | null>;
|
|
14
15
|
active: boolean;
|
|
15
16
|
onBarcodeScanned: (value: string) => void;
|
|
17
|
+
formats?: CodeType[];
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
interface RoiProfile {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
contrast: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const ROI_PROFILES: RoiProfile[] = [
|
|
27
|
+
// Full frame catches barcodes before the user has centered them.
|
|
28
|
+
{ width: 1, height: 1, contrast: 1 },
|
|
29
|
+
// Most ID barcodes sit in the wide center strip shown by the overlay.
|
|
30
|
+
{ width: 0.98, height: 0.64, contrast: 1 },
|
|
31
|
+
// A tighter, contrast-enhanced pass helps very dense or low-contrast PDF417.
|
|
32
|
+
{ width: 0.94, height: 0.46, contrast: 1.55 },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const ROTATIONS = [180, 90, -90];
|
|
36
|
+
const DEFAULT_FORMATS: CodeType[] = ['pdf-417'];
|
|
37
|
+
|
|
38
|
+
const ZXING_FORMATS: Partial<Record<CodeType, BarcodeFormat>> = {
|
|
39
|
+
'pdf-417': BarcodeFormat.PDF_417,
|
|
40
|
+
'code-128': BarcodeFormat.CODE_128,
|
|
41
|
+
'code-39': BarcodeFormat.CODE_39,
|
|
42
|
+
'code-93': BarcodeFormat.CODE_93,
|
|
43
|
+
codabar: BarcodeFormat.CODABAR,
|
|
44
|
+
'ean-13': BarcodeFormat.EAN_13,
|
|
45
|
+
'ean-8': BarcodeFormat.EAN_8,
|
|
46
|
+
itf: BarcodeFormat.ITF,
|
|
47
|
+
'itf-14': BarcodeFormat.ITF,
|
|
48
|
+
'upc-a': BarcodeFormat.UPC_A,
|
|
49
|
+
'upc-e': BarcodeFormat.UPC_E,
|
|
50
|
+
qr: BarcodeFormat.QR_CODE,
|
|
51
|
+
aztec: BarcodeFormat.AZTEC,
|
|
52
|
+
'data-matrix': BarcodeFormat.DATA_MATRIX,
|
|
53
|
+
'gs1-data-bar': BarcodeFormat.RSS_14,
|
|
54
|
+
'gs1-data-bar-limited': BarcodeFormat.RSS_14,
|
|
55
|
+
'gs1-data-bar-expanded': BarcodeFormat.RSS_EXPANDED,
|
|
56
|
+
};
|
|
57
|
+
|
|
18
58
|
export const WebBarcodeScanner: React.FC<WebBarcodeScannerProps> = ({
|
|
19
59
|
videoRef,
|
|
20
60
|
active,
|
|
21
61
|
onBarcodeScanned,
|
|
62
|
+
formats = DEFAULT_FORMATS,
|
|
22
63
|
}) => {
|
|
23
64
|
const readerRef = useRef<MultiFormatReader | null>(null);
|
|
24
|
-
|
|
25
65
|
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
26
|
-
|
|
27
|
-
const lastValueRef = useRef<string | null>(null);
|
|
28
|
-
|
|
66
|
+
const rotationCanvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
67
|
+
const lastValueRef = useRef<{ value: string | null; emittedAt: number }>({ value: null, emittedAt: 0 });
|
|
68
|
+
const attemptRef = useRef(0);
|
|
69
|
+
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
29
70
|
const stoppedRef = useRef(false);
|
|
30
|
-
|
|
31
71
|
const callbackRef = useRef(onBarcodeScanned);
|
|
32
72
|
|
|
33
73
|
useEffect(() => {
|
|
34
74
|
callbackRef.current = onBarcodeScanned;
|
|
35
75
|
}, [onBarcodeScanned]);
|
|
36
76
|
|
|
37
|
-
const decodeBitmap = useCallback(
|
|
38
|
-
(canvas
|
|
39
|
-
|
|
40
|
-
|
|
77
|
+
const decodeBitmap = useCallback((canvas: HTMLCanvasElement) => {
|
|
78
|
+
if (!readerRef.current || canvas.width === 0 || canvas.height === 0) return null;
|
|
79
|
+
|
|
80
|
+
const source = new HTMLCanvasElementLuminanceSource(canvas);
|
|
81
|
+
const attempts = [
|
|
82
|
+
new BinaryBitmap(new HybridBinarizer(source)),
|
|
83
|
+
new BinaryBitmap(new GlobalHistogramBinarizer(source)),
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
for (const bitmap of attempts) {
|
|
87
|
+
try {
|
|
88
|
+
const result = readerRef.current.decodeWithState(bitmap);
|
|
89
|
+
const text = result?.getText();
|
|
90
|
+
if (text) return text;
|
|
91
|
+
} catch {
|
|
92
|
+
// Try the next binarization strategy/rotation.
|
|
41
93
|
}
|
|
94
|
+
}
|
|
42
95
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
},
|
|
69
|
-
[]
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const drawROI = useCallback(
|
|
73
|
-
(
|
|
74
|
-
video: HTMLVideoElement,
|
|
75
|
-
canvas: HTMLCanvasElement
|
|
76
|
-
) => {
|
|
77
|
-
const ctx = canvas.getContext('2d', {
|
|
78
|
-
willReadFrequently: true,
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
if (!ctx) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const roi = 0.8;
|
|
86
|
-
|
|
87
|
-
const sw = Math.floor(
|
|
88
|
-
video.videoWidth * roi
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
const sh = Math.floor(
|
|
92
|
-
video.videoHeight * roi
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const sx = Math.floor(
|
|
96
|
-
(video.videoWidth - sw) / 2
|
|
97
|
-
);
|
|
96
|
+
return null;
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
99
|
+
const drawROI = useCallback((video: HTMLVideoElement, canvas: HTMLCanvasElement, profile: RoiProfile) => {
|
|
100
|
+
const ctx = canvas.getContext('2d', { willReadFrequently: true });
|
|
101
|
+
if (!ctx) return false;
|
|
102
|
+
|
|
103
|
+
const sourceWidth = Math.max(1, Math.floor(video.videoWidth * profile.width));
|
|
104
|
+
const sourceHeight = Math.max(1, Math.floor(video.videoHeight * profile.height));
|
|
105
|
+
const sourceX = Math.floor((video.videoWidth - sourceWidth) / 2);
|
|
106
|
+
const sourceY = Math.floor((video.videoHeight - sourceHeight) / 2);
|
|
107
|
+
|
|
108
|
+
// Nearest-neighbour enlargement gives ZXing more pixels per narrow module
|
|
109
|
+
// on sub-1080p browser streams without allocating an unbounded canvas.
|
|
110
|
+
const desiredScale = sourceWidth < 1600 ? Math.min(1.75, 1600 / sourceWidth) : 1;
|
|
111
|
+
const boundedScale = Math.min(desiredScale, 2800 / Math.max(sourceWidth, sourceHeight));
|
|
112
|
+
const outputWidth = Math.max(1, Math.floor(sourceWidth * boundedScale));
|
|
113
|
+
const outputHeight = Math.max(1, Math.floor(sourceHeight * boundedScale));
|
|
114
|
+
|
|
115
|
+
if (canvas.width !== outputWidth || canvas.height !== outputHeight) {
|
|
116
|
+
canvas.width = outputWidth;
|
|
117
|
+
canvas.height = outputHeight;
|
|
118
|
+
}
|
|
98
119
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
121
|
+
ctx.clearRect(0, 0, outputWidth, outputHeight);
|
|
122
|
+
ctx.imageSmoothingEnabled = false;
|
|
123
|
+
ctx.filter = profile.contrast === 1 ? 'none' : `grayscale(1) contrast(${profile.contrast})`;
|
|
124
|
+
ctx.drawImage(
|
|
125
|
+
video,
|
|
126
|
+
sourceX,
|
|
127
|
+
sourceY,
|
|
128
|
+
sourceWidth,
|
|
129
|
+
sourceHeight,
|
|
130
|
+
0,
|
|
131
|
+
0,
|
|
132
|
+
outputWidth,
|
|
133
|
+
outputHeight,
|
|
134
|
+
);
|
|
135
|
+
ctx.filter = 'none';
|
|
136
|
+
return true;
|
|
137
|
+
}, []);
|
|
102
138
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
canvas.height !== sh
|
|
106
|
-
) {
|
|
107
|
-
canvas.width = sw;
|
|
108
|
-
canvas.height = sh;
|
|
109
|
-
}
|
|
139
|
+
const rotateCanvas = useCallback((sourceCanvas: HTMLCanvasElement, degrees: number) => {
|
|
140
|
+
if (!rotationCanvasRef.current) rotationCanvasRef.current = document.createElement('canvas');
|
|
110
141
|
|
|
111
|
-
ctx.drawImage(
|
|
112
|
-
video,
|
|
113
|
-
sx,
|
|
114
|
-
sy,
|
|
115
|
-
sw,
|
|
116
|
-
sh,
|
|
117
|
-
0,
|
|
118
|
-
0,
|
|
119
|
-
sw,
|
|
120
|
-
sh
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
return true;
|
|
124
|
-
},
|
|
125
|
-
[]
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
// Add a persistent rotation canvas ref at the top
|
|
129
|
-
const rotationCanvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
130
|
-
|
|
131
|
-
// Update rotateCanvas to re-use the persistent canvas
|
|
132
|
-
const rotateCanvas = useCallback(
|
|
133
|
-
(sourceCanvas: HTMLCanvasElement, degrees: number) => {
|
|
134
|
-
if (!rotationCanvasRef.current) {
|
|
135
|
-
rotationCanvasRef.current = document.createElement('canvas');
|
|
136
|
-
}
|
|
137
142
|
const rotated = rotationCanvasRef.current;
|
|
138
|
-
const
|
|
139
|
-
|
|
143
|
+
const swapDimensions = Math.abs(degrees) === 90;
|
|
144
|
+
rotated.width = swapDimensions ? sourceCanvas.height : sourceCanvas.width;
|
|
145
|
+
rotated.height = swapDimensions ? sourceCanvas.width : sourceCanvas.height;
|
|
140
146
|
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
143
|
-
rotated.width = sourceCanvas.height;
|
|
144
|
-
rotated.height = sourceCanvas.width;
|
|
145
|
-
} else {
|
|
146
|
-
rotated.width = sourceCanvas.width;
|
|
147
|
-
rotated.height = sourceCanvas.height;
|
|
148
|
-
}
|
|
147
|
+
const ctx = rotated.getContext('2d', { willReadFrequently: true });
|
|
148
|
+
if (!ctx) return null;
|
|
149
149
|
|
|
150
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
150
151
|
ctx.clearRect(0, 0, rotated.width, rotated.height);
|
|
151
152
|
ctx.translate(rotated.width / 2, rotated.height / 2);
|
|
152
|
-
ctx.rotate(
|
|
153
|
+
ctx.rotate((degrees * Math.PI) / 180);
|
|
153
154
|
ctx.drawImage(sourceCanvas, -sourceCanvas.width / 2, -sourceCanvas.height / 2);
|
|
154
155
|
return rotated;
|
|
155
|
-
},
|
|
156
|
-
[]
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
}, []);
|
|
160
157
|
|
|
161
158
|
const tryDecode = useCallback(() => {
|
|
162
159
|
const video = videoRef.current;
|
|
163
|
-
|
|
164
160
|
const canvas = canvasRef.current;
|
|
161
|
+
if (!video || !canvas || video.readyState < 2 || video.videoWidth === 0 || video.videoHeight === 0) return null;
|
|
165
162
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
video.readyState < 2
|
|
170
|
-
) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
163
|
+
const attempt = attemptRef.current++;
|
|
164
|
+
const profile = ROI_PROFILES[attempt % ROI_PROFILES.length];
|
|
165
|
+
if (!drawROI(video, canvas, profile)) return null;
|
|
173
166
|
|
|
174
|
-
const
|
|
167
|
+
const directValue = decodeBitmap(canvas);
|
|
168
|
+
if (directValue) return directValue;
|
|
175
169
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
170
|
+
// Spread rotation work over successive frames to keep the UI responsive.
|
|
171
|
+
const rotation = ROTATIONS[attempt % ROTATIONS.length];
|
|
172
|
+
const rotated = rotateCanvas(canvas, rotation);
|
|
173
|
+
return rotated ? decodeBitmap(rotated) : null;
|
|
174
|
+
}, [decodeBitmap, drawROI, rotateCanvas, videoRef]);
|
|
179
175
|
|
|
180
|
-
|
|
176
|
+
const tick = useCallback(() => {
|
|
177
|
+
if (stoppedRef.current) return;
|
|
181
178
|
|
|
179
|
+
const value = tryDecode();
|
|
182
180
|
if (value) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
for (const rotation of rotations) {
|
|
189
|
-
const rotated = rotateCanvas(
|
|
190
|
-
canvas,
|
|
191
|
-
rotation
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
if (!rotated) {
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
value = decodeBitmap(rotated);
|
|
199
|
-
|
|
200
|
-
if (value) {
|
|
201
|
-
return value;
|
|
181
|
+
const now = Date.now();
|
|
182
|
+
const previous = lastValueRef.current;
|
|
183
|
+
if (value !== previous.value || now - previous.emittedAt > 1500) {
|
|
184
|
+
lastValueRef.current = { value, emittedAt: now };
|
|
185
|
+
callbackRef.current(value);
|
|
202
186
|
}
|
|
203
187
|
}
|
|
204
188
|
|
|
205
|
-
|
|
206
|
-
}, [
|
|
207
|
-
videoRef,
|
|
208
|
-
drawROI,
|
|
209
|
-
decodeBitmap,
|
|
210
|
-
rotateCanvas,
|
|
211
|
-
]);
|
|
212
|
-
|
|
213
|
-
const tick = useCallback(() => {
|
|
214
|
-
if (stoppedRef.current) return;
|
|
215
|
-
|
|
216
|
-
const value = tryDecode();
|
|
217
|
-
if (value && value !== lastValueRef.current) {
|
|
218
|
-
lastValueRef.current = value;
|
|
219
|
-
callbackRef.current(value);
|
|
220
|
-
// If you want it to stop scanning on success, leave 'return;'
|
|
221
|
-
// but ensure your parent component handles unmounting the scanner!
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
setTimeout(tick, 100);
|
|
189
|
+
timerRef.current = setTimeout(tick, 180);
|
|
226
190
|
}, [tryDecode]);
|
|
227
191
|
|
|
228
192
|
useEffect(() => {
|
|
229
|
-
if (!active)
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
193
|
+
if (!active) return;
|
|
232
194
|
|
|
233
195
|
stoppedRef.current = false;
|
|
196
|
+
attemptRef.current = 0;
|
|
197
|
+
lastValueRef.current = { value: null, emittedAt: 0 };
|
|
198
|
+
if (!canvasRef.current) canvasRef.current = document.createElement('canvas');
|
|
234
199
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
canvasRef.current =
|
|
239
|
-
document.createElement('canvas');
|
|
240
|
-
}
|
|
241
|
-
|
|
200
|
+
const possibleFormats = Array.from(new Set(
|
|
201
|
+
formats.map(format => ZXING_FORMATS[format]).filter((format): format is BarcodeFormat => format !== undefined),
|
|
202
|
+
));
|
|
242
203
|
const hints = new Map();
|
|
204
|
+
hints.set(DecodeHintType.POSSIBLE_FORMATS, possibleFormats.length > 0 ? possibleFormats : [BarcodeFormat.PDF_417]);
|
|
205
|
+
hints.set(DecodeHintType.TRY_HARDER, true);
|
|
243
206
|
|
|
244
|
-
|
|
245
|
-
DecodeHintType.POSSIBLE_FORMATS,
|
|
246
|
-
[BarcodeFormat.PDF_417]
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
hints.set(
|
|
250
|
-
DecodeHintType.TRY_HARDER,
|
|
251
|
-
true
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
const reader =
|
|
255
|
-
new MultiFormatReader();
|
|
256
|
-
|
|
207
|
+
const reader = new MultiFormatReader();
|
|
257
208
|
reader.setHints(hints);
|
|
258
|
-
|
|
259
209
|
readerRef.current = reader;
|
|
260
|
-
|
|
261
210
|
tick();
|
|
262
211
|
|
|
263
212
|
return () => {
|
|
264
213
|
stoppedRef.current = true;
|
|
265
|
-
|
|
214
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
215
|
+
timerRef.current = null;
|
|
266
216
|
readerRef.current?.reset();
|
|
267
|
-
|
|
268
217
|
readerRef.current = null;
|
|
269
218
|
};
|
|
270
|
-
}, [active, tick]);
|
|
219
|
+
}, [active, formats, tick]);
|
|
271
220
|
|
|
272
221
|
return null;
|
|
273
|
-
};
|
|
222
|
+
};
|
|
@@ -61,10 +61,8 @@ export function useTemplateLoader(): UseTemplateLoaderReturn {
|
|
|
61
61
|
|
|
62
62
|
// Set the template
|
|
63
63
|
setTemplate(transformedTemplate);
|
|
64
|
-
logger.log(`Template loaded successfully: ${templateId}`);
|
|
65
64
|
} catch (err: any) {
|
|
66
65
|
const errorMessage = err.message || 'Failed to load template';
|
|
67
|
-
logger.error(`Error loading template ${templateId}:`, errorMessage);
|
|
68
66
|
setError(errorMessage);
|
|
69
67
|
setTemplate(null);
|
|
70
68
|
} finally {
|
|
@@ -279,14 +279,14 @@ export class KYCService {
|
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
async extractBarcode(params: { fileUri: string; token: string; docType: string; postfix?: string }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
|
|
282
|
+
async extractBarcode(params: { fileUri: string; token: string; docType: string; postfix?: string; timeoutMs?: number }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
|
|
283
283
|
const formData = new FormData();
|
|
284
284
|
await appendFileToFormData(formData, 'file', params.fileUri, `id_${params.postfix || 'back'}_photo.jpg`, 'image/jpeg');
|
|
285
285
|
|
|
286
286
|
const url = `${this.barcodeServiceURL}/decode_barcode/?doc_type=${encodeURIComponent(params.docType)}`;
|
|
287
287
|
|
|
288
288
|
try {
|
|
289
|
-
return await this.crossPlatformMultipartUpload<any>(url, formData, params.token, 60000);
|
|
289
|
+
return await this.crossPlatformMultipartUpload<any>(url, formData, params.token, params.timeoutMs ?? 60000);
|
|
290
290
|
} catch (e: any) {
|
|
291
291
|
throw e;
|
|
292
292
|
}
|
|
@@ -651,4 +651,4 @@ export const clearAuthToken = () => {
|
|
|
651
651
|
|
|
652
652
|
export const errorMessage = (error: any) => {
|
|
653
653
|
return error.response?.data?.message || error.response?.data?.detail || error.response?.data?.error || error.response?.data || error.message;
|
|
654
|
-
}
|
|
654
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { BackendKYCTemplate, TemplateAPIResponse } from '../../types/KYC.types';
|
|
3
|
-
import { logger } from '../../utils/logger';
|
|
3
|
+
import { logger, sdkLogger } from '../../utils/logger';
|
|
4
4
|
import { errorMessage } from './KYCService';
|
|
5
5
|
import KYCConfig from '../../config/KYCConfig';
|
|
6
6
|
|
|
@@ -82,7 +82,8 @@ export class TemplateServiceClass {
|
|
|
82
82
|
logger.log(`Template ${templateId} fetched successfully`);
|
|
83
83
|
return template;
|
|
84
84
|
} catch (error: any) {
|
|
85
|
-
logger.error(`Error fetching template ${templateId}:`, JSON.stringify(errorMessage(error), null, 2))
|
|
85
|
+
logger.error(`Error fetching template ${templateId}:`, JSON.stringify(errorMessage(error), null, 2))
|
|
86
|
+
sdkLogger.error(`Error fetching template ${templateId}:`, JSON.stringify(errorMessage(error), null, 2));
|
|
86
87
|
|
|
87
88
|
// Extract backend error message if available
|
|
88
89
|
const backendMessage = errorMessage(error);
|
package/src/modules/api/types.ts
CHANGED
|
@@ -26,34 +26,42 @@ export type VerificationSessionData = Record<string, any>;
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
export interface VerificationResult {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
29
|
+
message?: string;
|
|
30
|
+
status?: string;
|
|
31
|
+
referenceId?: string;
|
|
32
|
+
issues?: string[];
|
|
33
|
+
data?: {
|
|
34
|
+
session_id?: string;
|
|
35
|
+
verification_id?: string;
|
|
36
|
+
verification_status?: string;
|
|
37
|
+
document_type?: string;
|
|
38
|
+
completion_timestamp?: string;
|
|
39
|
+
user_data?: {
|
|
40
|
+
personal_information?: {
|
|
41
|
+
full_name?: string | null;
|
|
42
|
+
first_name?: string | null;
|
|
43
|
+
last_name?: string | null;
|
|
44
|
+
given_name?: string | null;
|
|
45
|
+
surname?: string | null;
|
|
46
|
+
date_of_birth?: string | null;
|
|
47
|
+
birth_date?: string | null;
|
|
48
|
+
sex?: string | null;
|
|
49
|
+
expiry_date?: string | null;
|
|
50
|
+
issue_date?: string | null;
|
|
51
|
+
issue_place?: string | null;
|
|
52
|
+
place_of_birth?: string | null;
|
|
53
|
+
address?: string | null;
|
|
54
|
+
city?: string | null;
|
|
55
|
+
postal_code?: string | null;
|
|
56
|
+
country?: string | null;
|
|
57
|
+
nationality?: string | null;
|
|
58
|
+
document_number?: string | null;
|
|
57
59
|
};
|
|
60
|
+
};
|
|
61
|
+
selfie_info?: {
|
|
62
|
+
is_match?: boolean;
|
|
63
|
+
similarity?: number;
|
|
64
|
+
image?: string;
|
|
65
|
+
};
|
|
58
66
|
};
|
|
59
|
-
}
|
|
67
|
+
}
|