@transfergratis/react-native-sdk 0.1.24 → 0.1.25
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/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
- package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
- package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
- package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
- package/android/src/main/AndroidManifest.xml +10 -7
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js +193 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +180 -7
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js +2 -2
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +7 -3
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/TemplateKYCExample.d.ts +4 -0
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +7 -30
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +4 -0
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +14 -2
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/config/KYCConfig.d.ts +14 -0
- package/build/config/KYCConfig.d.ts.map +1 -0
- package/build/config/KYCConfig.js +26 -0
- package/build/config/KYCConfig.js.map +1 -0
- package/build/config/allowedDomains.d.ts.map +1 -1
- package/build/config/allowedDomains.js +4 -19
- package/build/config/allowedDomains.js.map +1 -1
- package/build/hooks/useOrientationVideo.d.ts +2 -1
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +3 -3
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.d.ts +6 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +286 -23
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +40 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +41 -1
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +26 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +27 -1
- package/build/i18n/fr/index.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts +24 -3
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +68 -10
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +7 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +101 -37
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -1
- package/build/modules/api/SelfieVerification.d.ts.map +1 -1
- package/build/modules/api/SelfieVerification.js +17 -1
- package/build/modules/api/SelfieVerification.js.map +1 -1
- package/build/modules/api/TemplateService.d.ts +0 -1
- package/build/modules/api/TemplateService.d.ts.map +1 -1
- package/build/modules/api/TemplateService.js +3 -3
- package/build/modules/api/TemplateService.js.map +1 -1
- package/build/types/KYC.types.d.ts +124 -3
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js.map +1 -1
- package/build/types/env.types.d.ts +13 -0
- package/build/types/env.types.d.ts.map +1 -0
- package/build/types/env.types.js +2 -0
- package/build/types/env.types.js.map +1 -0
- package/build/utils/deviceDetection.d.ts +6 -0
- package/build/utils/deviceDetection.d.ts.map +1 -0
- package/build/utils/deviceDetection.js +12 -0
- package/build/utils/deviceDetection.js.map +1 -0
- package/build/utils/platformAlert.d.ts.map +1 -1
- package/build/utils/platformAlert.js.map +1 -1
- package/build/utils/template-transformer.d.ts.map +1 -1
- package/build/utils/template-transformer.js +12 -0
- package/build/utils/template-transformer.js.map +1 -1
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +82 -38
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
- package/src/components/KYCElements/IDCardCapture.tsx +216 -15
- package/src/components/KYCElements/OrientationVideoCapture.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +4 -1
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +4 -1
- package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +6 -3
- package/src/components/TemplateKYCExample.tsx +31 -46
- package/src/components/TemplateKYCFlowRefactored.tsx +27 -1
- package/src/config/KYCConfig.ts +34 -0
- package/src/config/allowedDomains.ts +7 -26
- package/src/hooks/useOrientationVideo.ts +5 -4
- package/src/hooks/useTemplateKYCFlow.tsx +314 -21
- package/src/i18n/en/index.ts +43 -2
- package/src/i18n/fr/index.ts +28 -1
- package/src/index.ts +3 -0
- package/src/modules/api/CardAuthentification.ts +75 -10
- package/src/modules/api/KYCService.ts +117 -37
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +4 -4
- package/src/types/KYC.types.ts +146 -3
- package/src/types/env.types.ts +13 -0
- package/src/utils/deviceDetection.ts +11 -0
- package/src/utils/platformAlert.ts +1 -0
- package/src/utils/template-transformer.ts +20 -8
- package/src/web/WebKYCEntry.tsx +112 -61
|
@@ -2,7 +2,21 @@ import axios from 'axios';
|
|
|
2
2
|
import { GovernmentDocumentType, GovernmentDocumentTypeShorted, OrientationVideoResponse } from '../../types/KYC.types';
|
|
3
3
|
import { CheckTemplateTypeResponse, ExtractMrzTextResponse } from '../../components/OverLay/type';
|
|
4
4
|
import { SessionResponse, VerificationResult, VerificationSessionRequest } from './types';
|
|
5
|
+
import { KycEnvironment } from '../../types/env.types';
|
|
5
6
|
import { logger } from '../../utils/logger';
|
|
7
|
+
import { Platform } from 'react-native';
|
|
8
|
+
import KYCConfig from '../../config/KYCConfig';
|
|
9
|
+
|
|
10
|
+
const appendFileToFormData = async (formData: FormData, key: string, uri: string, name: string = 'file.jpg', type: string = 'image/jpeg') => {
|
|
11
|
+
if (Platform.OS === 'web') {
|
|
12
|
+
const response = await fetch(uri);
|
|
13
|
+
const blob = await response.blob();
|
|
14
|
+
formData.append(key, blob, name);
|
|
15
|
+
} else {
|
|
16
|
+
formData.append(key, { uri, type, name } as any);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
6
20
|
|
|
7
21
|
export interface KYCRequest {
|
|
8
22
|
userId: string;
|
|
@@ -48,7 +62,6 @@ export class KYCService {
|
|
|
48
62
|
private mrzServiceURL = 'https://kyc-engine.transfergratis.net:8002';
|
|
49
63
|
private barcodeServiceURL = 'https://kyc-engine.transfergratis.net:8000';
|
|
50
64
|
private orientationServiceURL = 'http://18.188.180.154:8080';
|
|
51
|
-
private backendServiceURL = 'https://service.sanctumkey.com/api/v1';
|
|
52
65
|
|
|
53
66
|
constructor(baseURL: string, apiKey: string) {
|
|
54
67
|
this.baseURL = baseURL;
|
|
@@ -120,12 +133,8 @@ export class KYCService {
|
|
|
120
133
|
async processSelfieOrientationPicture(videoFile: string, token: string): Promise<SelfieVideoResponse[]> {
|
|
121
134
|
try {
|
|
122
135
|
const formData = new FormData();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
type: 'image/jpeg',
|
|
126
|
-
name: 'selfie_picture.jpg',
|
|
127
|
-
};
|
|
128
|
-
formData.append('file', rnFile);
|
|
136
|
+
await appendFileToFormData(formData, 'file', videoFile, 'selfie_picture.jpg', 'image/jpeg');
|
|
137
|
+
|
|
129
138
|
const response = await axios.post<SelfieVideoResponse[]>(
|
|
130
139
|
`${this.faceServiceURL}/detect_face_orientation/`,
|
|
131
140
|
formData,
|
|
@@ -141,17 +150,27 @@ export class KYCService {
|
|
|
141
150
|
}
|
|
142
151
|
}
|
|
143
152
|
|
|
144
|
-
async processOrientationVideo(videoFile: string): Promise<OrientationVideoResponse> {
|
|
153
|
+
async processOrientationVideo(videoFile: string, env: KycEnvironment = 'PRODUCTION'): Promise<OrientationVideoResponse> {
|
|
145
154
|
try {
|
|
155
|
+
// SANDBOX mode: skip AI verification and return mock response
|
|
156
|
+
if (env === 'SANDBOX') {
|
|
157
|
+
console.log("SANDBOX mode: Skipping AI orientation video processing");
|
|
158
|
+
logger.log("SANDBOX mode: Returning mock orientation video response");
|
|
159
|
+
return {
|
|
160
|
+
success: true,
|
|
161
|
+
data: {
|
|
162
|
+
center: { captured: true, frame: 10 },
|
|
163
|
+
left: { captured: true, frame: 30 },
|
|
164
|
+
right: { captured: true, frame: 50 }
|
|
165
|
+
},
|
|
166
|
+
message: 'SANDBOX: Orientation video processed successfully (mocked)'
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
146
170
|
// Create FormData for multipart/form-data request
|
|
147
171
|
const formData = new FormData();
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
uri: videoFile,
|
|
151
|
-
type: 'video/mp4',
|
|
152
|
-
name: 'orientation_video.mp4',
|
|
153
|
-
};
|
|
154
|
-
formData.append('file', rnFile);
|
|
172
|
+
await appendFileToFormData(formData, 'file', videoFile, 'orientation_video.mp4', 'video/mp4');
|
|
173
|
+
|
|
155
174
|
|
|
156
175
|
const response = await axios.post(
|
|
157
176
|
`${this.orientationServiceURL}/process_orientation_video_stream/`,
|
|
@@ -196,10 +215,21 @@ export class KYCService {
|
|
|
196
215
|
}
|
|
197
216
|
|
|
198
217
|
// STEP 1 - ID CARD VALIDATION
|
|
199
|
-
async detectFaceOnId(idCardImageUri: string, token: string, docType: string): Promise<{ result: boolean, detail: any[] }> {
|
|
218
|
+
async detectFaceOnId(idCardImageUri: string, token: string, docType: string, env: KycEnvironment = 'PRODUCTION'): Promise<{ result: boolean, detail: any[] }> {
|
|
219
|
+
// SANDBOX mode: skip AI verification and return mock response
|
|
220
|
+
if (env === 'SANDBOX') {
|
|
221
|
+
console.log("SANDBOX mode: Skipping AI face detection on ID");
|
|
222
|
+
logger.log("SANDBOX mode: Returning mock face detection response");
|
|
223
|
+
return {
|
|
224
|
+
result: true,
|
|
225
|
+
detail: [{ confidence: 0.95, bbox: [50, 50, 200, 200] }],
|
|
226
|
+
card_obb: { x: 50, y: 50, width: 200, height: 200 }
|
|
227
|
+
} as any;
|
|
228
|
+
}
|
|
229
|
+
|
|
200
230
|
const formData = new FormData();
|
|
201
|
-
|
|
202
|
-
|
|
231
|
+
await appendFileToFormData(formData, 'file', idCardImageUri, 'id_card_photo.jpg', 'image/jpeg');
|
|
232
|
+
|
|
203
233
|
logger.log('detectFaceOnId formData', JSON.stringify(formData, null, 2));
|
|
204
234
|
|
|
205
235
|
const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType];
|
|
@@ -221,11 +251,22 @@ export class KYCService {
|
|
|
221
251
|
}
|
|
222
252
|
|
|
223
253
|
//check templatetemplate_type
|
|
224
|
-
async checkTemplateType(params: { fileUri: string; docType: string; docRegion: string; token: string; postfix: string }): Promise<any> {
|
|
254
|
+
async checkTemplateType(params: { fileUri: string; docType: string; docRegion: string; token: string; postfix: string }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
|
|
255
|
+
// SANDBOX mode: skip AI verification and return mock response
|
|
256
|
+
if (env === 'SANDBOX') {
|
|
257
|
+
console.log("SANDBOX mode: Skipping AI template type check");
|
|
258
|
+
logger.log("SANDBOX mode: Returning mock template type response");
|
|
259
|
+
const { docType, docRegion, postfix } = params;
|
|
260
|
+
return {
|
|
261
|
+
template_path: `templates/${docType}_${docRegion}_${postfix}.jpg`,
|
|
262
|
+
card_obb: { x: 50, y: 50, width: 200, height: 200 }
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
225
266
|
const { fileUri, docType, docRegion, token, postfix } = params;
|
|
226
267
|
const formData = new FormData();
|
|
227
|
-
|
|
228
|
-
|
|
268
|
+
await appendFileToFormData(formData, 'file', fileUri, 'id_card_front.jpg', 'image/jpeg');
|
|
269
|
+
|
|
229
270
|
const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType];
|
|
230
271
|
const url = `${this.mrzServiceURL}/get_template_version/?doc_type=${encodeURIComponent(docTypeShorted)}&doc_region=${encodeURIComponent(docRegion)}&postfix=${postfix}`;
|
|
231
272
|
|
|
@@ -247,8 +288,8 @@ export class KYCService {
|
|
|
247
288
|
async extractDocumentInformation(params: { fileUri: string; docType: string; docRegion: string; token: string }): Promise<any> {
|
|
248
289
|
const { fileUri, docType, docRegion, token } = params;
|
|
249
290
|
const formData = new FormData();
|
|
250
|
-
|
|
251
|
-
|
|
291
|
+
await appendFileToFormData(formData, 'file', fileUri, 'id_card_front.jpg', 'image/jpeg');
|
|
292
|
+
|
|
252
293
|
|
|
253
294
|
const url = `${this.textExtractionServiceURL}/extract_doc_information/?doc_type=${encodeURIComponent(docType)}&doc_region=${encodeURIComponent(docRegion)}`;
|
|
254
295
|
const attempt = async () => {
|
|
@@ -271,11 +312,21 @@ export class KYCService {
|
|
|
271
312
|
}
|
|
272
313
|
}
|
|
273
314
|
// STEP 2 - barcode extraction
|
|
274
|
-
async extractBarcode(params: { fileUri: string; token: string }): Promise<any> {
|
|
315
|
+
async extractBarcode(params: { fileUri: string; token: string }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
|
|
316
|
+
// SANDBOX mode: skip AI verification and return mock response
|
|
317
|
+
if (env === 'SANDBOX') {
|
|
318
|
+
console.log("SANDBOX mode: Skipping AI barcode extraction");
|
|
319
|
+
logger.log("SANDBOX mode: Returning mock barcode response");
|
|
320
|
+
return {
|
|
321
|
+
barcode_data: 'SANDBOX_MOCK_BARCODE_DATA',
|
|
322
|
+
card_obb: { x: 50, y: 50, width: 200, height: 200 }
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
275
326
|
const { fileUri, token } = params;
|
|
276
327
|
const formData = new FormData();
|
|
277
|
-
|
|
278
|
-
|
|
328
|
+
await appendFileToFormData(formData, 'file', fileUri, 'id_card_back.jpg', 'image/jpeg');
|
|
329
|
+
|
|
279
330
|
|
|
280
331
|
const url = `${this.barcodeServiceURL}/decode_barcode/`;
|
|
281
332
|
const attempt = async () => {
|
|
@@ -300,11 +351,29 @@ export class KYCService {
|
|
|
300
351
|
}
|
|
301
352
|
}
|
|
302
353
|
// STEP 3 - MRZ TEXT EXTRACTION
|
|
303
|
-
async extractMrzText(params: { fileUri: string; docType: string; docRegion: string; postfix?: string; token: string; template_path: string; mrz_type: string }): Promise<any> {
|
|
354
|
+
async extractMrzText(params: { fileUri: string; docType: string; docRegion: string; postfix?: string; token: string; template_path: string; mrz_type: string }, env: KycEnvironment = 'PRODUCTION'): Promise<any> {
|
|
355
|
+
// SANDBOX mode: skip AI verification and return mock response
|
|
356
|
+
if (env === 'SANDBOX') {
|
|
357
|
+
console.log("SANDBOX mode: Skipping AI MRZ extraction");
|
|
358
|
+
logger.log("SANDBOX mode: Returning mock MRZ response");
|
|
359
|
+
const { docType, docRegion, postfix = 'back', mrz_type } = params;
|
|
360
|
+
return {
|
|
361
|
+
success: true,
|
|
362
|
+
parsed_data: {
|
|
363
|
+
status: 'success',
|
|
364
|
+
document_type: docType,
|
|
365
|
+
mrz_type: mrz_type || 'TD1',
|
|
366
|
+
doc_region: docRegion,
|
|
367
|
+
postfix: postfix
|
|
368
|
+
},
|
|
369
|
+
card_obb: { x: 50, y: 50, width: 200, height: 200 }
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
304
373
|
const { fileUri, docType, docRegion, postfix = 'back', token, template_path, mrz_type } = params;
|
|
305
374
|
const formData = new FormData();
|
|
306
|
-
|
|
307
|
-
|
|
375
|
+
await appendFileToFormData(formData, 'file', fileUri, 'id_card_back.jpg', 'image/jpeg');
|
|
376
|
+
|
|
308
377
|
const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType];
|
|
309
378
|
logger.log("docTypeShorted", docTypeShorted, docRegion, postfix);
|
|
310
379
|
|
|
@@ -335,13 +404,24 @@ export class KYCService {
|
|
|
335
404
|
}
|
|
336
405
|
|
|
337
406
|
// STEP 2 - SELFIE VALIDATION
|
|
338
|
-
async recognizeFace(params: { idPhotoUri: string; selfiePhotoUri: string }): Promise<{ is_match: boolean; similarity: number; id_bbox?: number[]; selfie_bbox?: number[] }> {
|
|
407
|
+
async recognizeFace(params: { idPhotoUri: string; selfiePhotoUri: string }, env: KycEnvironment = 'PRODUCTION'): Promise<{ is_match: boolean; similarity: number; id_bbox?: number[]; selfie_bbox?: number[] }> {
|
|
408
|
+
// SANDBOX mode: skip AI verification and return mock response
|
|
409
|
+
if (env === 'SANDBOX') {
|
|
410
|
+
console.log("SANDBOX mode: Skipping AI face recognition");
|
|
411
|
+
logger.log("SANDBOX mode: Returning mock face recognition response");
|
|
412
|
+
return {
|
|
413
|
+
is_match: true,
|
|
414
|
+
similarity: 0.95,
|
|
415
|
+
id_bbox: [50, 50, 200, 200],
|
|
416
|
+
selfie_bbox: [50, 50, 200, 200]
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
339
420
|
const { idPhotoUri, selfiePhotoUri } = params;
|
|
340
421
|
const formData = new FormData();
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
formData.append('selfie_photo', selfieFile);
|
|
422
|
+
await appendFileToFormData(formData, 'id_photo', idPhotoUri, 'id_card_photo.jpg', 'image/jpeg');
|
|
423
|
+
await appendFileToFormData(formData, 'selfie_photo', selfiePhotoUri, 'selfie_final.jpg', 'image/jpeg');
|
|
424
|
+
|
|
345
425
|
|
|
346
426
|
const res = await axios.post(`${this.faceServiceURL}/recognize_face/`, formData, { timeout: 45000 });
|
|
347
427
|
if (res.data?.detail) throw new Error(res.data.detail);
|
|
@@ -375,7 +455,7 @@ export class KYCService {
|
|
|
375
455
|
"status": "PENDING",
|
|
376
456
|
"metadata": {},
|
|
377
457
|
}
|
|
378
|
-
const res = await axios.post<SessionResponse>(`${
|
|
458
|
+
const res = await axios.post<SessionResponse>(`${KYCConfig.getBackendUrl()}/verification/sessions/`,
|
|
379
459
|
data, {
|
|
380
460
|
headers: {
|
|
381
461
|
'Content-Type': 'application/json',
|
|
@@ -419,7 +499,7 @@ export class KYCService {
|
|
|
419
499
|
...({ session_id: session_id }),
|
|
420
500
|
timestamp: new Date().toISOString()
|
|
421
501
|
}
|
|
422
|
-
const url = `${
|
|
502
|
+
const url = `${KYCConfig.getBackendUrl()}/verification/api/kyc/sessions/${session_id}/steps/${step}/`;
|
|
423
503
|
|
|
424
504
|
|
|
425
505
|
const logPayload = truncateFields({ payloadData, session_id, step });
|
|
@@ -448,7 +528,7 @@ export class KYCService {
|
|
|
448
528
|
async getVerificationResult(session_id: string): Promise<VerificationResult> {
|
|
449
529
|
try {
|
|
450
530
|
const token = await authentification();
|
|
451
|
-
const url = `${
|
|
531
|
+
const url = `${KYCConfig.getBackendUrl()}/verification/api/kyc/result/?session_id=${session_id}`;
|
|
452
532
|
const res = await axios.get<VerificationResult>(url,
|
|
453
533
|
{ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } });
|
|
454
534
|
logger.log('getVerificationResult res', JSON.stringify(truncateFields(res.data), null, 2));
|
|
@@ -1,11 +1,33 @@
|
|
|
1
|
-
import kycService, { authentification } from "./KYCService";
|
|
1
|
+
import kycService, { authentification, SelfieVideoResponse } from "./KYCService";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { KycEnvironment } from "../../types/env.types";
|
|
4
|
+
|
|
5
|
+
const selfieVerification = async (selfieImage: string, env: KycEnvironment = 'PRODUCTION'): Promise<SelfieVideoResponse[]> => {
|
|
6
|
+
// In SANDBOX mode, skip AI verification and return a mock success response
|
|
7
|
+
if (env === 'SANDBOX') {
|
|
8
|
+
console.log("SANDBOX mode: Skipping AI verification for selfie");
|
|
9
|
+
// Return a mock response that simulates successful verification
|
|
10
|
+
// This allows the flow to continue without actual AI processing
|
|
11
|
+
|
|
12
|
+
const mockResponse: SelfieVideoResponse[] = [{
|
|
13
|
+
orientation_direction: "center",
|
|
14
|
+
turn_score: 1.0,
|
|
15
|
+
bbox: [0, 0, 100, 100],
|
|
16
|
+
capture: true,
|
|
17
|
+
instruction: "SANDBOX: AI verification skipped",
|
|
18
|
+
error: ""
|
|
19
|
+
}];
|
|
20
|
+
return mockResponse;
|
|
21
|
+
}
|
|
5
22
|
|
|
23
|
+
// PRODUCTION mode: perform actual AI verification
|
|
24
|
+
const token = await authentification();
|
|
6
25
|
const response = await kycService.processSelfieOrientationPicture(selfieImage, token);
|
|
7
26
|
console.log("selfieVerification response", JSON.stringify(response, null, 2));
|
|
8
27
|
return response;
|
|
9
28
|
}
|
|
10
29
|
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
11
33
|
export default selfieVerification;
|
|
@@ -2,9 +2,9 @@ import axios from 'axios';
|
|
|
2
2
|
import { BackendKYCTemplate, TemplateAPIResponse } from '../../types/KYC.types';
|
|
3
3
|
import { logger } from '../../utils/logger';
|
|
4
4
|
import { errorMessage } from './KYCService';
|
|
5
|
+
import KYCConfig from '../../config/KYCConfig';
|
|
5
6
|
|
|
6
7
|
export class TemplateServiceClass {
|
|
7
|
-
private backendServiceURL = 'https://service.sanctumkey.com/api/v1';
|
|
8
8
|
private cache: Map<string, { template: BackendKYCTemplate; timestamp: number }> = new Map();
|
|
9
9
|
private cacheTimeout = 5 * 60 * 1000; // 5 minutes
|
|
10
10
|
|
|
@@ -55,8 +55,8 @@ export class TemplateServiceClass {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
|
-
const url = `${
|
|
59
|
-
logger.log(`Fetching template from: ${url} with apiKey: ${apiKey} and token: ${token}`,{
|
|
58
|
+
const url = `${KYCConfig.getBackendUrl()}/templates/kyc/template/${templateId}/`;
|
|
59
|
+
logger.log(`Fetching template from: ${url} with apiKey: ${apiKey} and token: ${token}`, {
|
|
60
60
|
headers: this.getHeaders(apiKey, token)
|
|
61
61
|
});
|
|
62
62
|
|
|
@@ -142,7 +142,7 @@ export class TemplateServiceClass {
|
|
|
142
142
|
*/
|
|
143
143
|
async fetchTemplateList(apiKey?: string, token?: string): Promise<Array<{ id: string; name: Record<string, string>; version?: string; status?: string }>> {
|
|
144
144
|
try {
|
|
145
|
-
const url = `${
|
|
145
|
+
const url = `${KYCConfig.getBackendUrl()}/templates/kyc/templates`;
|
|
146
146
|
logger.log(`Fetching template list from: ${url}`);
|
|
147
147
|
|
|
148
148
|
const response = await axios.get<Array<{ id: string; name: Record<string, string>; version?: string; status?: string }>>(url, {
|
package/src/types/KYC.types.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface Document {
|
|
|
8
8
|
uploadedAt: Date;
|
|
9
9
|
validated: boolean;
|
|
10
10
|
extractedData?: DocumentData;
|
|
11
|
+
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export type DocumentType = 'passport' | 'id_card' | 'drivers_license';
|
|
@@ -406,12 +407,17 @@ export type ComponentConfig =
|
|
|
406
407
|
| FileUploadConfig
|
|
407
408
|
| LocationConfig
|
|
408
409
|
| CountrySelectionConfig
|
|
409
|
-
|
|
|
410
|
+
| CountrySelectionConfig
|
|
411
|
+
| WelcomeConfig
|
|
412
|
+
| EmailVerificationConfig
|
|
413
|
+
| PhoneVerificationConfig
|
|
414
|
+
| PersonalInformationConfig
|
|
415
|
+
| AdditionalDocumentsConfig;
|
|
410
416
|
|
|
411
417
|
// Nouveau type de composant basé sur le template JSON
|
|
412
418
|
export interface TemplateComponent {
|
|
413
419
|
id: number;
|
|
414
|
-
type: 'id_card' | 'selfie' | 'file_upload' | 'location' | 'country_selection' | 'initialization' | 'review_submit' | 'verification_progress' | 'welcome';
|
|
420
|
+
type: 'id_card' | 'selfie' | 'file_upload' | 'location' | 'country_selection' | 'initialization' | 'review_submit' | 'verification_progress' | 'welcome' | 'email_verification' | 'phone_verification' | 'personal_information' | 'additional_documents';
|
|
415
421
|
order: number;
|
|
416
422
|
templateId?: number;
|
|
417
423
|
labels: LocalizedText | Record<string, LocalizedText>;
|
|
@@ -487,6 +493,7 @@ export interface UseTemplateReturn {
|
|
|
487
493
|
isComplete: boolean;
|
|
488
494
|
getLocalizedText: (text: LocalizedText) => string;
|
|
489
495
|
initializeSession: () => Promise<void>;
|
|
496
|
+
env: 'PRODUCTION' | 'SANDBOX';
|
|
490
497
|
}
|
|
491
498
|
|
|
492
499
|
|
|
@@ -646,7 +653,7 @@ export interface BackendComponentTranslations {
|
|
|
646
653
|
// Backend template component
|
|
647
654
|
export interface BackendTemplateComponent {
|
|
648
655
|
id: string;
|
|
649
|
-
type: 'welcome' | 'location-capture' | 'government-id' | 'selfie-capture' | 'review-submit' | 'verification-progress';
|
|
656
|
+
type: 'welcome' | 'location-capture' | 'government-id' | 'selfie-capture' | 'review-submit' | 'verification-progress' | 'email-verification' | 'phone-verification' | 'personal-information' | 'additional-documents';
|
|
650
657
|
order: number;
|
|
651
658
|
config: BackendComponentConfig;
|
|
652
659
|
required?: boolean;
|
|
@@ -671,6 +678,74 @@ export interface BackendKYCTemplate {
|
|
|
671
678
|
};
|
|
672
679
|
}
|
|
673
680
|
|
|
681
|
+
// ===== NEW CONFIG TYPES FOR INPUT VERIFICATION =====
|
|
682
|
+
|
|
683
|
+
export interface EmailVerificationConfig {
|
|
684
|
+
allowResend: boolean;
|
|
685
|
+
otpSettings: {
|
|
686
|
+
codeLength: number;
|
|
687
|
+
expiryTime: number;
|
|
688
|
+
};
|
|
689
|
+
resendCooldown: number;
|
|
690
|
+
emailValidation: {
|
|
691
|
+
corporateOnly: boolean;
|
|
692
|
+
validateFormat: boolean;
|
|
693
|
+
checkDisposable: boolean;
|
|
694
|
+
checkDeliverability: boolean;
|
|
695
|
+
};
|
|
696
|
+
verificationMethod: string;
|
|
697
|
+
required?: boolean;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export interface PhoneVerificationConfig {
|
|
701
|
+
required: boolean;
|
|
702
|
+
codeExpiry: number;
|
|
703
|
+
codeLength: number;
|
|
704
|
+
maxAttempts: number;
|
|
705
|
+
resendDelay: number;
|
|
706
|
+
countryRestrictions: string;
|
|
707
|
+
verificationMethods: string[];
|
|
708
|
+
allowSkipForVerified: boolean;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export interface PersonalInfoField {
|
|
712
|
+
id: string;
|
|
713
|
+
type: string;
|
|
714
|
+
label: string;
|
|
715
|
+
required: boolean;
|
|
716
|
+
placeholder?: string;
|
|
717
|
+
autoFillFromId?: boolean;
|
|
718
|
+
minAge?: number;
|
|
719
|
+
verifyAge?: boolean;
|
|
720
|
+
dateFormat?: string;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
export interface PersonalInformationConfig {
|
|
724
|
+
fields: PersonalInfoField[];
|
|
725
|
+
validationSettings: {
|
|
726
|
+
validateOnBlur: boolean;
|
|
727
|
+
showAllErrorsAtOnce: boolean;
|
|
728
|
+
preventSubmissionWithErrors: boolean;
|
|
729
|
+
};
|
|
730
|
+
required?: boolean;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export interface DocumentCategory {
|
|
734
|
+
enabled: boolean;
|
|
735
|
+
category: string;
|
|
736
|
+
documentTypes: string[];
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
export interface AdditionalDocumentsConfig {
|
|
740
|
+
required: boolean;
|
|
741
|
+
maxSizeEach: string;
|
|
742
|
+
maxDocuments: number;
|
|
743
|
+
minDocuments: number;
|
|
744
|
+
documentCategories: DocumentCategory[];
|
|
745
|
+
customDocumentTypes: any[];
|
|
746
|
+
showBasedOnUserProfile: boolean;
|
|
747
|
+
}
|
|
748
|
+
|
|
674
749
|
// API response for template
|
|
675
750
|
export interface TemplateAPIResponse {
|
|
676
751
|
id: string;
|
|
@@ -687,4 +762,72 @@ export interface TemplateAPIResponse {
|
|
|
687
762
|
fr: string;
|
|
688
763
|
[key: string]: string;
|
|
689
764
|
};
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// ===== NEW CONFIG TYPES FOR INPUT VERIFICATION =====
|
|
768
|
+
|
|
769
|
+
export interface EmailVerificationConfig {
|
|
770
|
+
allowResend: boolean;
|
|
771
|
+
otpSettings: {
|
|
772
|
+
codeLength: number;
|
|
773
|
+
expiryTime: number;
|
|
774
|
+
};
|
|
775
|
+
resendCooldown: number;
|
|
776
|
+
emailValidation: {
|
|
777
|
+
corporateOnly: boolean;
|
|
778
|
+
validateFormat: boolean;
|
|
779
|
+
checkDisposable: boolean;
|
|
780
|
+
checkDeliverability: boolean;
|
|
781
|
+
};
|
|
782
|
+
verificationMethod: string;
|
|
783
|
+
required?: boolean;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
export interface PhoneVerificationConfig {
|
|
787
|
+
required: boolean;
|
|
788
|
+
codeExpiry: number;
|
|
789
|
+
codeLength: number;
|
|
790
|
+
maxAttempts: number;
|
|
791
|
+
resendDelay: number;
|
|
792
|
+
countryRestrictions: string;
|
|
793
|
+
verificationMethods: string[];
|
|
794
|
+
allowSkipForVerified: boolean;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
export interface PersonalInfoField {
|
|
798
|
+
id: string;
|
|
799
|
+
type: string;
|
|
800
|
+
label: string;
|
|
801
|
+
required: boolean;
|
|
802
|
+
placeholder?: string;
|
|
803
|
+
autoFillFromId?: boolean;
|
|
804
|
+
minAge?: number;
|
|
805
|
+
verifyAge?: boolean;
|
|
806
|
+
dateFormat?: string;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export interface PersonalInformationConfig {
|
|
810
|
+
fields: PersonalInfoField[];
|
|
811
|
+
validationSettings: {
|
|
812
|
+
validateOnBlur: boolean;
|
|
813
|
+
showAllErrorsAtOnce: boolean;
|
|
814
|
+
preventSubmissionWithErrors: boolean;
|
|
815
|
+
};
|
|
816
|
+
required?: boolean;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export interface DocumentCategory {
|
|
820
|
+
enabled: boolean;
|
|
821
|
+
category: string;
|
|
822
|
+
documentTypes: string[];
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export interface AdditionalDocumentsConfig {
|
|
826
|
+
required: boolean;
|
|
827
|
+
maxSizeEach: string;
|
|
828
|
+
maxDocuments: number;
|
|
829
|
+
minDocuments: number;
|
|
830
|
+
documentCategories: DocumentCategory[];
|
|
831
|
+
customDocumentTypes: any[];
|
|
832
|
+
showBasedOnUserProfile: boolean;
|
|
690
833
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYC Environment types
|
|
3
|
+
* PRODUCTION: Full verification with AI checks
|
|
4
|
+
* SANDBOX: Skip AI verification, only save data to backend
|
|
5
|
+
*/
|
|
6
|
+
export type KycEnvironment = 'PRODUCTION' | 'SANDBOX';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Backend Environment types
|
|
10
|
+
* PRODUCTION: Production backend
|
|
11
|
+
* TEST: Test backend
|
|
12
|
+
*/
|
|
13
|
+
export type BackendEnvironment = 'PRODUCTION' | 'TEST';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the current environment is a mobile web browser based on User Agent.
|
|
3
|
+
* This can be used to distinguish between desktop web and mobile web.
|
|
4
|
+
*/
|
|
5
|
+
export const isMobileWeb = (): boolean => {
|
|
6
|
+
if (typeof window === 'undefined' || !window.navigator) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const userAgent = window.navigator.userAgent;
|
|
10
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
|
|
11
|
+
};
|
|
@@ -42,6 +42,10 @@ const COMPONENT_TYPE_MAPPING: Record<string, TemplateComponent['type']> = {
|
|
|
42
42
|
'verification-progress': 'verification_progress',
|
|
43
43
|
'file-upload': 'file_upload',
|
|
44
44
|
'country-selection': 'country_selection',
|
|
45
|
+
'email-verification': 'email_verification',
|
|
46
|
+
'phone-verification': 'phone_verification',
|
|
47
|
+
'personal-information': 'personal_information',
|
|
48
|
+
'additional-documents': 'additional_documents',
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
/**
|
|
@@ -241,6 +245,14 @@ function transformComponentConfig(
|
|
|
241
245
|
default_country: backendConfig.default_country || '',
|
|
242
246
|
required: backendConfig.required !== false,
|
|
243
247
|
} as CountrySelectionConfig;
|
|
248
|
+
case 'email_verification':
|
|
249
|
+
return backendConfig as any;
|
|
250
|
+
case 'phone_verification':
|
|
251
|
+
return backendConfig as any;
|
|
252
|
+
case 'personal_information':
|
|
253
|
+
return backendConfig as any;
|
|
254
|
+
case 'additional_documents':
|
|
255
|
+
return backendConfig as any;
|
|
244
256
|
default:
|
|
245
257
|
return backendConfig as ComponentConfig;
|
|
246
258
|
}
|
|
@@ -328,23 +340,23 @@ export function transformBackendTemplateToSDK(
|
|
|
328
340
|
// Auto-create country_selection component before id_card if government-id has selection data
|
|
329
341
|
// Check if country_selection already exists in backend template
|
|
330
342
|
const hasCountrySelectionInBackend = sortedComponents.some(c => (c as any).type === 'country-selection');
|
|
331
|
-
|
|
343
|
+
|
|
332
344
|
if (!hasCountrySelectionInBackend) {
|
|
333
345
|
// Find the first government-id component with selection data
|
|
334
|
-
const govIdWithSelection = sortedComponents.find(backendComp =>
|
|
335
|
-
backendComp.type === 'government-id' &&
|
|
346
|
+
const govIdWithSelection = sortedComponents.find(backendComp =>
|
|
347
|
+
backendComp.type === 'government-id' &&
|
|
336
348
|
backendComp.config && (
|
|
337
349
|
(backendComp.config as any).selectedCountries ||
|
|
338
350
|
(backendComp.config as any).documentTypesByCountry
|
|
339
351
|
)
|
|
340
352
|
);
|
|
341
|
-
|
|
353
|
+
|
|
342
354
|
if (govIdWithSelection) {
|
|
343
355
|
// Find the corresponding transformed id_card component
|
|
344
|
-
const transformedIdCard = transformedComponents.find(c =>
|
|
356
|
+
const transformedIdCard = transformedComponents.find(c =>
|
|
345
357
|
hashStringToNumber(govIdWithSelection.id) === c.id
|
|
346
358
|
);
|
|
347
|
-
|
|
359
|
+
|
|
348
360
|
if (transformedIdCard) {
|
|
349
361
|
// Create a country_selection component before id_card
|
|
350
362
|
const countrySelectionComponent: TemplateComponent = {
|
|
@@ -372,14 +384,14 @@ export function transformBackendTemplateToSDK(
|
|
|
372
384
|
required: true,
|
|
373
385
|
} as CountrySelectionConfig,
|
|
374
386
|
};
|
|
375
|
-
|
|
387
|
+
|
|
376
388
|
// Insert country_selection before id_card in transformedComponents
|
|
377
389
|
const idCardIndex = transformedComponents.indexOf(transformedIdCard);
|
|
378
390
|
transformedComponents.splice(idCardIndex, 0, countrySelectionComponent);
|
|
379
391
|
}
|
|
380
392
|
}
|
|
381
393
|
}
|
|
382
|
-
|
|
394
|
+
|
|
383
395
|
// Re-assign order values sequentially after insertion
|
|
384
396
|
transformedComponents.forEach((comp, index) => {
|
|
385
397
|
comp.order = index + 1;
|