@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.
Files changed (149) hide show
  1. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
  2. package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
  3. package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
  4. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  5. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  6. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
  7. package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
  8. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
  9. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  10. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  11. package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
  12. package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
  13. package/android/src/main/AndroidManifest.xml +10 -7
  14. package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
  15. package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
  16. package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
  17. package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
  18. package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
  19. package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
  20. package/build/components/KYCElements/EmailVerificationTemplate.js +193 -0
  21. package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
  22. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  23. package/build/components/KYCElements/IDCardCapture.js +180 -7
  24. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  25. package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
  26. package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
  27. package/build/components/KYCElements/OrientationVideoCapture.js +2 -2
  28. package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
  29. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
  30. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
  31. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +2 -2
  32. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
  33. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
  34. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
  35. package/build/components/KYCElements/OrientationVideoCaptureFinal.js +2 -2
  36. package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
  37. package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
  38. package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
  39. package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
  40. package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
  41. package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
  42. package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
  43. package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
  44. package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
  45. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
  46. package/build/components/KYCElements/SelfieCaptureTemplate.js +7 -3
  47. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  48. package/build/components/TemplateKYCExample.d.ts +4 -0
  49. package/build/components/TemplateKYCExample.d.ts.map +1 -1
  50. package/build/components/TemplateKYCExample.js +7 -30
  51. package/build/components/TemplateKYCExample.js.map +1 -1
  52. package/build/components/TemplateKYCFlowRefactored.d.ts +4 -0
  53. package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  54. package/build/components/TemplateKYCFlowRefactored.js +14 -2
  55. package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
  56. package/build/config/KYCConfig.d.ts +14 -0
  57. package/build/config/KYCConfig.d.ts.map +1 -0
  58. package/build/config/KYCConfig.js +26 -0
  59. package/build/config/KYCConfig.js.map +1 -0
  60. package/build/config/allowedDomains.d.ts.map +1 -1
  61. package/build/config/allowedDomains.js +4 -19
  62. package/build/config/allowedDomains.js.map +1 -1
  63. package/build/hooks/useOrientationVideo.d.ts +2 -1
  64. package/build/hooks/useOrientationVideo.d.ts.map +1 -1
  65. package/build/hooks/useOrientationVideo.js +3 -3
  66. package/build/hooks/useOrientationVideo.js.map +1 -1
  67. package/build/hooks/useTemplateKYCFlow.d.ts +6 -1
  68. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  69. package/build/hooks/useTemplateKYCFlow.js +286 -23
  70. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  71. package/build/i18n/en/index.d.ts +40 -0
  72. package/build/i18n/en/index.d.ts.map +1 -1
  73. package/build/i18n/en/index.js +41 -1
  74. package/build/i18n/en/index.js.map +1 -1
  75. package/build/i18n/fr/index.d.ts +26 -0
  76. package/build/i18n/fr/index.d.ts.map +1 -1
  77. package/build/i18n/fr/index.js +27 -1
  78. package/build/i18n/fr/index.js.map +1 -1
  79. package/build/index.d.ts +1 -0
  80. package/build/index.d.ts.map +1 -1
  81. package/build/index.js +2 -0
  82. package/build/index.js.map +1 -1
  83. package/build/modules/api/CardAuthentification.d.ts +24 -3
  84. package/build/modules/api/CardAuthentification.d.ts.map +1 -1
  85. package/build/modules/api/CardAuthentification.js +68 -10
  86. package/build/modules/api/CardAuthentification.js.map +1 -1
  87. package/build/modules/api/KYCService.d.ts +7 -7
  88. package/build/modules/api/KYCService.d.ts.map +1 -1
  89. package/build/modules/api/KYCService.js +101 -37
  90. package/build/modules/api/KYCService.js.map +1 -1
  91. package/build/modules/api/SelfieVerification.d.ts +3 -1
  92. package/build/modules/api/SelfieVerification.d.ts.map +1 -1
  93. package/build/modules/api/SelfieVerification.js +17 -1
  94. package/build/modules/api/SelfieVerification.js.map +1 -1
  95. package/build/modules/api/TemplateService.d.ts +0 -1
  96. package/build/modules/api/TemplateService.d.ts.map +1 -1
  97. package/build/modules/api/TemplateService.js +3 -3
  98. package/build/modules/api/TemplateService.js.map +1 -1
  99. package/build/types/KYC.types.d.ts +124 -3
  100. package/build/types/KYC.types.d.ts.map +1 -1
  101. package/build/types/KYC.types.js.map +1 -1
  102. package/build/types/env.types.d.ts +13 -0
  103. package/build/types/env.types.d.ts.map +1 -0
  104. package/build/types/env.types.js +2 -0
  105. package/build/types/env.types.js.map +1 -0
  106. package/build/utils/deviceDetection.d.ts +6 -0
  107. package/build/utils/deviceDetection.d.ts.map +1 -0
  108. package/build/utils/deviceDetection.js +12 -0
  109. package/build/utils/deviceDetection.js.map +1 -0
  110. package/build/utils/platformAlert.d.ts.map +1 -1
  111. package/build/utils/platformAlert.js.map +1 -1
  112. package/build/utils/template-transformer.d.ts.map +1 -1
  113. package/build/utils/template-transformer.js +12 -0
  114. package/build/utils/template-transformer.js.map +1 -1
  115. package/build/web/WebKYCEntry.d.ts.map +1 -1
  116. package/build/web/WebKYCEntry.js +82 -38
  117. package/build/web/WebKYCEntry.js.map +1 -1
  118. package/package.json +1 -1
  119. package/plugin/build/withVisionCamera.js +3 -4
  120. package/plugin/src/withVisionCamera.js +3 -4
  121. package/plugin/src/withVisionCamera.ts +3 -4
  122. package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
  123. package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
  124. package/src/components/KYCElements/IDCardCapture.tsx +216 -15
  125. package/src/components/KYCElements/OrientationVideoCapture.tsx +4 -1
  126. package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +4 -1
  127. package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +4 -1
  128. package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
  129. package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
  130. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +6 -3
  131. package/src/components/TemplateKYCExample.tsx +31 -46
  132. package/src/components/TemplateKYCFlowRefactored.tsx +27 -1
  133. package/src/config/KYCConfig.ts +34 -0
  134. package/src/config/allowedDomains.ts +7 -26
  135. package/src/hooks/useOrientationVideo.ts +5 -4
  136. package/src/hooks/useTemplateKYCFlow.tsx +314 -21
  137. package/src/i18n/en/index.ts +43 -2
  138. package/src/i18n/fr/index.ts +28 -1
  139. package/src/index.ts +3 -0
  140. package/src/modules/api/CardAuthentification.ts +75 -10
  141. package/src/modules/api/KYCService.ts +117 -37
  142. package/src/modules/api/SelfieVerification.ts +25 -3
  143. package/src/modules/api/TemplateService.ts +4 -4
  144. package/src/types/KYC.types.ts +146 -3
  145. package/src/types/env.types.ts +13 -0
  146. package/src/utils/deviceDetection.ts +11 -0
  147. package/src/utils/platformAlert.ts +1 -0
  148. package/src/utils/template-transformer.ts +20 -8
  149. 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
- const rnFile: any = {
124
- uri: videoFile,
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
- // In React Native, prefer the { uri, type, name } pattern rather than Blob
149
- const rnFile: any = {
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
- const rnFile: any = { uri: idCardImageUri, type: 'image/jpeg', name: 'id_card_photo.jpg' };
202
- formData.append('file', rnFile);
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
- const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_front.jpg' };
228
- formData.append('file', rnFile);
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
- const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_front.jpg' };
251
- formData.append('file', rnFile);
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
- const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_back.jpg' };
278
- formData.append('file', rnFile);
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
- const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_back.jpg' };
307
- formData.append('file', rnFile);
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
- const idFile: any = { uri: idPhotoUri, type: 'image/jpeg', name: 'id_card_photo.jpg' };
342
- const selfieFile: any = { uri: selfiePhotoUri, type: 'image/jpeg', name: 'selfie_final.jpg' };
343
- formData.append('id_photo', idFile);
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>(`${this.backendServiceURL}/verification/sessions/`,
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 = `${this.backendServiceURL}/verification/api/kyc/sessions/${session_id}/steps/${step}/`;
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 = `${this.backendServiceURL}/verification/api/kyc/result/?session_id=${session_id}`;
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
- const selfieVerification = async (selfieImage: string) => {
4
- const token = await authentification();
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 = `${this.backendServiceURL}/templates/kyc/template/${templateId}/`;
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 = `${this.backendServiceURL}/templates/kyc/templates`;
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, {
@@ -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
- | WelcomeConfig;
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
+ };
@@ -21,6 +21,7 @@ export const showAlert = (
21
21
  const fullMessage = message ? `${title}\n\n${message}` : title;
22
22
 
23
23
  if (buttons && buttons.length > 1) {
24
+
24
25
  // Multiple buttons - use confirm dialog
25
26
  const confirmed = window.confirm(fullMessage);
26
27
 
@@ -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;