@transfergratis/react-native-sdk 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/build/api/axios.d.ts +30 -0
  2. package/build/api/axios.d.ts.map +1 -0
  3. package/build/api/axios.js +92 -0
  4. package/build/api/axios.js.map +1 -0
  5. package/build/components/EnhancedCameraView.d.ts +1 -41
  6. package/build/components/EnhancedCameraView.d.ts.map +1 -1
  7. package/build/components/EnhancedCameraView.js +75 -34
  8. package/build/components/EnhancedCameraView.js.map +1 -1
  9. package/build/components/EnhancedCameraView.web.d.ts +1 -41
  10. package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
  11. package/build/components/EnhancedCameraView.web.js +28 -4
  12. package/build/components/EnhancedCameraView.web.js.map +1 -1
  13. package/build/components/KYCElements/CountrySelectionTemplate.d.ts +2 -2
  14. package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  15. package/build/components/KYCElements/CountrySelectionTemplate.js +77 -114
  16. package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  17. package/build/components/KYCElements/FileUploadTemplate.d.ts.map +1 -1
  18. package/build/components/KYCElements/FileUploadTemplate.js +7 -3
  19. package/build/components/KYCElements/FileUploadTemplate.js.map +1 -1
  20. package/build/components/KYCElements/IDCardCapture.d.ts +7 -2
  21. package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  22. package/build/components/KYCElements/IDCardCapture.js +253 -104
  23. package/build/components/KYCElements/IDCardCapture.js.map +1 -1
  24. package/build/components/KYCElements/InitializationStep.d.ts +5 -0
  25. package/build/components/KYCElements/InitializationStep.d.ts.map +1 -0
  26. package/build/components/KYCElements/InitializationStep.js +41 -0
  27. package/build/components/KYCElements/InitializationStep.js.map +1 -0
  28. package/build/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
  29. package/build/components/KYCElements/LocationCaptureTemplate.js +15 -13
  30. package/build/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
  31. package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -2
  32. package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
  33. package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
  34. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -2
  35. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
  36. package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
  37. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -2
  38. package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
  39. package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
  40. package/build/components/KYCElements/ReviewSubmitTemplate.d.ts +12 -0
  41. package/build/components/KYCElements/ReviewSubmitTemplate.d.ts.map +1 -0
  42. package/build/components/KYCElements/ReviewSubmitTemplate.js +171 -0
  43. package/build/components/KYCElements/ReviewSubmitTemplate.js.map +1 -0
  44. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts +6 -2
  45. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
  46. package/build/components/KYCElements/SelfieCaptureTemplate.js +137 -38
  47. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  48. package/build/components/KYCElements/VerificationProgressTemplate.d.ts +12 -0
  49. package/build/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -0
  50. package/build/components/KYCElements/VerificationProgressTemplate.js +194 -0
  51. package/build/components/KYCElements/VerificationProgressTemplate.js.map +1 -0
  52. package/build/components/OverLay/IdCard.d.ts +1 -1
  53. package/build/components/OverLay/IdCard.d.ts.map +1 -1
  54. package/build/components/OverLay/IdCard.js +10 -6
  55. package/build/components/OverLay/IdCard.js.map +1 -1
  56. package/build/components/OverLay/SelfieOverlay.d.ts +1 -1
  57. package/build/components/OverLay/SelfieOverlay.d.ts.map +1 -1
  58. package/build/components/OverLay/SelfieOverlay.js +5 -4
  59. package/build/components/OverLay/SelfieOverlay.js.map +1 -1
  60. package/build/components/OverLay/type.d.ts +71 -1
  61. package/build/components/OverLay/type.d.ts.map +1 -1
  62. package/build/components/OverLay/type.js.map +1 -1
  63. package/build/components/TemplateKYCExample.d.ts +4 -1
  64. package/build/components/TemplateKYCExample.d.ts.map +1 -1
  65. package/build/components/TemplateKYCExample.js +74 -199
  66. package/build/components/TemplateKYCExample.js.map +1 -1
  67. package/build/components/TemplateKYCFlowRefactored.d.ts +3 -2
  68. package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  69. package/build/components/TemplateKYCFlowRefactored.js +64 -40
  70. package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
  71. package/build/components/example/OrientationVideoExample.d.ts.map +1 -1
  72. package/build/components/example/OrientationVideoExample.js +1 -5
  73. package/build/components/example/OrientationVideoExample.js.map +1 -1
  74. package/build/config/countriesData.d.ts +3 -0
  75. package/build/config/countriesData.d.ts.map +1 -0
  76. package/build/config/countriesData.js +79 -0
  77. package/build/config/countriesData.js.map +1 -0
  78. package/build/config/region_mapping.d.ts +3 -0
  79. package/build/config/region_mapping.d.ts.map +1 -0
  80. package/build/config/region_mapping.js +687 -0
  81. package/build/config/region_mapping.js.map +1 -0
  82. package/build/hooks/useI18n.d.ts +11 -0
  83. package/build/hooks/useI18n.d.ts.map +1 -0
  84. package/build/hooks/useI18n.js +37 -0
  85. package/build/hooks/useI18n.js.map +1 -0
  86. package/build/hooks/useOrientationVideo.d.ts +1 -2
  87. package/build/hooks/useOrientationVideo.d.ts.map +1 -1
  88. package/build/hooks/useOrientationVideo.js +2 -1
  89. package/build/hooks/useOrientationVideo.js.map +1 -1
  90. package/build/hooks/useRealtimeVerifier.d.ts +28 -0
  91. package/build/hooks/useRealtimeVerifier.d.ts.map +1 -0
  92. package/build/hooks/useRealtimeVerifier.js +91 -0
  93. package/build/hooks/useRealtimeVerifier.js.map +1 -0
  94. package/build/hooks/useTemplateKYCFlow.d.ts +6 -3
  95. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  96. package/build/hooks/useTemplateKYCFlow.js +356 -42
  97. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  98. package/build/i18n/en/index.d.ts +168 -0
  99. package/build/i18n/en/index.d.ts.map +1 -0
  100. package/build/i18n/en/index.js +195 -0
  101. package/build/i18n/en/index.js.map +1 -0
  102. package/build/i18n/fr/index.d.ts +168 -0
  103. package/build/i18n/fr/index.d.ts.map +1 -0
  104. package/build/i18n/fr/index.js +194 -0
  105. package/build/i18n/fr/index.js.map +1 -0
  106. package/build/i18n/index.d.ts +10 -0
  107. package/build/i18n/index.d.ts.map +1 -0
  108. package/build/i18n/index.js +56 -0
  109. package/build/i18n/index.js.map +1 -0
  110. package/build/i18n/types.d.ts +153 -0
  111. package/build/i18n/types.d.ts.map +1 -0
  112. package/build/i18n/types.js +3 -0
  113. package/build/i18n/types.js.map +1 -0
  114. package/build/i18n/usage-example.d.ts +4 -0
  115. package/build/i18n/usage-example.d.ts.map +1 -0
  116. package/build/i18n/usage-example.js +189 -0
  117. package/build/i18n/usage-example.js.map +1 -0
  118. package/build/index.d.ts +1 -0
  119. package/build/index.d.ts.map +1 -1
  120. package/build/index.js +2 -0
  121. package/build/index.js.map +1 -1
  122. package/build/modules/api/CardAuthentification.d.ts +22 -0
  123. package/build/modules/api/CardAuthentification.d.ts.map +1 -0
  124. package/build/modules/api/CardAuthentification.js +107 -0
  125. package/build/modules/api/CardAuthentification.js.map +1 -0
  126. package/build/modules/api/KYCService.d.ts +58 -1
  127. package/build/modules/api/KYCService.d.ts.map +1 -1
  128. package/build/modules/api/KYCService.js +304 -27
  129. package/build/modules/api/KYCService.js.map +1 -1
  130. package/build/modules/api/SelfieVerification.d.ts +3 -0
  131. package/build/modules/api/SelfieVerification.d.ts.map +1 -0
  132. package/build/modules/api/SelfieVerification.js +9 -0
  133. package/build/modules/api/SelfieVerification.js.map +1 -0
  134. package/build/modules/api/backendApi.d.ts +2 -0
  135. package/build/modules/api/backendApi.d.ts.map +1 -0
  136. package/build/modules/api/backendApi.js +6 -0
  137. package/build/modules/api/backendApi.js.map +1 -0
  138. package/build/modules/api/types.d.ts +45 -0
  139. package/build/modules/api/types.d.ts.map +1 -0
  140. package/build/modules/api/types.js +2 -0
  141. package/build/modules/api/types.js.map +1 -0
  142. package/build/types/KYC.types.d.ts +56 -7
  143. package/build/types/KYC.types.d.ts.map +1 -1
  144. package/build/types/KYC.types.js +9 -1
  145. package/build/types/KYC.types.js.map +1 -1
  146. package/build/utils/cropByObb.d.ts +11 -0
  147. package/build/utils/cropByObb.d.ts.map +1 -0
  148. package/build/utils/cropByObb.js +78 -0
  149. package/build/utils/cropByObb.js.map +1 -0
  150. package/build/utils/get-document-type-info.d.ts +13 -0
  151. package/build/utils/get-document-type-info.d.ts.map +1 -0
  152. package/build/utils/get-document-type-info.js +59 -0
  153. package/build/utils/get-document-type-info.js.map +1 -0
  154. package/build/utils/pathToBase64.d.ts +3 -0
  155. package/build/utils/pathToBase64.d.ts.map +1 -0
  156. package/build/utils/pathToBase64.js +47 -0
  157. package/build/utils/pathToBase64.js.map +1 -0
  158. package/build/utils/remove-duplicate.d.ts +2 -0
  159. package/build/utils/remove-duplicate.d.ts.map +1 -0
  160. package/build/utils/remove-duplicate.js +4 -0
  161. package/build/utils/remove-duplicate.js.map +1 -0
  162. package/build/web/WebKYCEntry.d.ts +9 -0
  163. package/build/web/WebKYCEntry.d.ts.map +1 -0
  164. package/build/web/WebKYCEntry.js +156 -0
  165. package/build/web/WebKYCEntry.js.map +1 -0
  166. package/build/web/index.d.ts +2 -0
  167. package/build/web/index.d.ts.map +1 -0
  168. package/build/web/index.js +2 -0
  169. package/build/web/index.js.map +1 -0
  170. package/package.json +3 -1
  171. package/src/api/axios.ts +144 -0
  172. package/src/components/EnhancedCameraView.tsx +96 -78
  173. package/src/components/EnhancedCameraView.web.tsx +41 -40
  174. package/src/components/KYCElements/CountrySelectionTemplate.tsx +111 -136
  175. package/src/components/KYCElements/FileUploadTemplate.tsx +14 -8
  176. package/src/components/KYCElements/IDCardCapture.tsx +311 -115
  177. package/src/components/KYCElements/InitializationStep.tsx +53 -0
  178. package/src/components/KYCElements/LocationCaptureTemplate.tsx +17 -15
  179. package/src/components/KYCElements/OrientationVideoCapture.tsx +2 -2
  180. package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +2 -2
  181. package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +2 -2
  182. package/src/components/KYCElements/ReviewSubmitTemplate.tsx +201 -0
  183. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +174 -57
  184. package/src/components/KYCElements/VerificationProgressTemplate.tsx +246 -0
  185. package/src/components/OverLay/IdCard.tsx +17 -9
  186. package/src/components/OverLay/SelfieOverlay.tsx +6 -5
  187. package/src/components/OverLay/type.ts +64 -2
  188. package/src/components/TemplateKYCExample.tsx +80 -200
  189. package/src/components/TemplateKYCFlowRefactored.tsx +80 -48
  190. package/src/components/example/OrientationVideoExample.tsx +3 -7
  191. package/src/config/countriesData.ts +84 -0
  192. package/src/config/region_mapping.ts +688 -0
  193. package/src/hooks/useI18n.ts +53 -0
  194. package/src/hooks/useOrientationVideo.ts +2 -2
  195. package/src/hooks/useRealtimeVerifier.ts +128 -0
  196. package/src/hooks/useTemplateKYCFlow.tsx +407 -57
  197. package/src/i18n/README.md +288 -0
  198. package/src/i18n/en/index.ts +206 -0
  199. package/src/i18n/fr/index.ts +205 -0
  200. package/src/i18n/index.ts +65 -0
  201. package/src/i18n/types.ts +172 -0
  202. package/src/i18n/usage-example.tsx +202 -0
  203. package/src/index.ts +3 -0
  204. package/src/modules/api/CardAuthentification.ts +114 -0
  205. package/src/modules/api/KYCService.ts +350 -30
  206. package/src/modules/api/SelfieVerification.ts +11 -0
  207. package/src/modules/api/backendApi.ts +8 -0
  208. package/src/modules/api/types.ts +51 -0
  209. package/src/types/KYC.types.ts +82 -14
  210. package/src/utils/cropByObb.ts +99 -0
  211. package/src/utils/get-document-type-info.ts +62 -0
  212. package/src/utils/pathToBase64.ts +47 -0
  213. package/src/utils/remove-duplicate.ts +3 -0
  214. package/src/web/WebKYCEntry.tsx +215 -0
  215. package/src/web/index.ts +1 -0
  216. package/src/types/nativewind.d.ts +0 -2
@@ -0,0 +1,114 @@
1
+ import kycService, { authentification, errorMessage } from "./KYCService";
2
+ import { cropByObb } from "../../utils/cropByObb";
3
+ import { IBbox } from "../../types/KYC.types";
4
+
5
+ export async function frontVerification(result: { path?: string, regionMapping: string[], selectedDocumentType: string, code: string, currentSide: string, }) {
6
+ try {
7
+
8
+ console.log("Front verification", JSON.stringify({ result }, null, 2));
9
+ const token = await authentification();
10
+ const detected = await kycService.detectFaceOnId(result?.path || '', token, result?.selectedDocumentType || '')
11
+
12
+ if (!detected.result) {
13
+ throw new Error('Aucun visage détecté sur la carte. Veuillez reprendre.');
14
+ }
15
+
16
+ // Optional: crop image using card_obb for better MRZ/barcode extraction
17
+ let croppedBase64: string | undefined;
18
+ let bbox: IBbox | undefined;
19
+ let mrz: any | undefined;
20
+ try {
21
+ const crop = await cropByObb(result?.path || '', (detected as any).card_obb);
22
+ croppedBase64 = crop.base64;
23
+ bbox = crop.bbox;
24
+ } catch { }
25
+
26
+ if (result.regionMapping.length > 0 && result.regionMapping.includes('MRZ')) {
27
+ mrz = await kycService.extractMrzText({ fileUri: result.path || '', docType: result?.selectedDocumentType || '', docRegion: result?.code || "", postfix: result?.currentSide, token: token })
28
+
29
+ }
30
+
31
+ return { ...detected, croppedBase64, bbox, ...(mrz ? { mrz } : {}) };
32
+ } catch (e: any) {
33
+ console.error('Error front verification:', JSON.stringify(errorMessage(e), null, 2));
34
+ throw new Error(e?.message || 'Erreur de détection du visage');
35
+ }
36
+ }
37
+
38
+ export async function backVerification(result: { path?: string, regionMapping: string[], selectedDocumentType: string, code: string, currentSide: string, }) {
39
+ try {
40
+ if (!result.path) throw new Error('No path provided');
41
+ console.log("result.regionMapping", result.regionMapping, result.currentSide, result.code);
42
+ const token = await authentification();
43
+
44
+
45
+
46
+ // Fonction helper pour essayer MRZ puis barcode en fallback
47
+ const tryMrzWithBarcodeFallback = async () => {
48
+ try {
49
+ console.log("Tentative d'extraction MRZ");
50
+ const mrz = await kycService.extractMrzText({
51
+ fileUri: result.path!,
52
+ docType: result?.selectedDocumentType || '',
53
+ docRegion: result?.code || '',
54
+ postfix: 'back',
55
+ token: token
56
+ });
57
+ return mrz;
58
+ } catch (mrzError: any) {
59
+ console.log("MRZ échoué, tentative d'extraction barcode");
60
+ try {
61
+ const barcode = await kycService.extractBarcode({ fileUri: result.path!, token: token });
62
+ return barcode;
63
+ } catch (barcodeError: any) {
64
+ throw new Error(`MRZ et barcode ont échoué. MRZ: ${mrzError?.message}, Barcode: ${barcodeError?.message}`);
65
+ }
66
+ }
67
+ };
68
+
69
+
70
+
71
+ if (result.regionMapping.length > 2) {
72
+ return await tryMrzWithBarcodeFallback();
73
+ }
74
+
75
+ if (result.regionMapping.length > 0 && result.regionMapping.includes('MRZ')) {
76
+ try {
77
+ const mrz = await kycService.extractMrzText({
78
+ fileUri: result.path!,
79
+ docType: result?.selectedDocumentType || '',
80
+ docRegion: result?.code || '',
81
+ postfix: 'back',
82
+ token: token
83
+ });
84
+ let bbox: IBbox | undefined;
85
+ try {
86
+ const crop = await cropByObb(result?.path || '', (mrz as any).card_obb);
87
+ bbox = crop.bbox;
88
+ } catch { }
89
+ return { ...mrz, bbox };
90
+ } catch (mrzError: any) {
91
+ throw new Error(`MRZ et barcode ont échoué. MRZ: ${mrzError?.message}, Barcode: ${mrzError?.message}`);
92
+ }
93
+ }
94
+
95
+ if (result.regionMapping.length > 0 && result.regionMapping.includes('2D_barcode')) {
96
+ try {
97
+ console.log("Tentative d'extraction barcode");
98
+ const barcode = await kycService.extractBarcode({ fileUri: result.path!, token: token });
99
+ let bbox: IBbox | undefined;
100
+ try {
101
+ const crop = await cropByObb(result?.path || '', (barcode as any).card_obb);
102
+ bbox = crop.bbox;
103
+ } catch { }
104
+ return { ...barcode, bbox };
105
+ } catch (barcodeError: any) {
106
+ throw new Error(`Barcode et MRZ ont échoué. Barcode: ${barcodeError?.message}, MRZ: ${barcodeError?.message}`);
107
+ }
108
+ }
109
+ return null;
110
+ } catch (e: any) {
111
+ throw new Error(e?.message || 'Erreur de détection du MRZ ou barcode');
112
+ }
113
+ }
114
+
@@ -1,5 +1,7 @@
1
1
  import axios from 'axios';
2
- import { OrientationVideoResponse } from '../../types/KYC.types';
2
+ import { GovernmentDocumentType, GovernmentDocumentTypeShorted, OrientationVideoResponse } from '../../types/KYC.types';
3
+ import { ExtractMrzTextResponse } from '../../components/OverLay/type';
4
+ import { SessionResponse, VerificationResult, VerificationSessionRequest } from './types';
3
5
 
4
6
  export interface KYCRequest {
5
7
  userId: string;
@@ -26,9 +28,26 @@ export interface FaceDetectionResponse {
26
28
  message: string;
27
29
  }
28
30
 
31
+ export interface SelfieVideoResponse {
32
+ orientation_direction: "center" | "left" | "right",
33
+ turn_score: number;
34
+ bbox: number[];
35
+ capture: boolean;
36
+ instruction: string;
37
+ error: string;
38
+ }
39
+
40
+
29
41
  export class KYCService {
30
42
  private baseURL: string;
31
43
  private apiKey: string;
44
+ // Additional service base URLs (fixed as per current infra)
45
+ private faceServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8000';
46
+ private textExtractionServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8006';
47
+ private mrzServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8002';
48
+ private barcodeServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8000';
49
+ private orientationServiceURL = 'http://18.188.180.154:8080';
50
+ private backendServiceURL = 'http://16.170.133.50/api/v1';
32
51
 
33
52
  constructor(baseURL: string, apiKey: string) {
34
53
  this.baseURL = baseURL;
@@ -97,40 +116,48 @@ export class KYCService {
97
116
  }
98
117
  }
99
118
 
100
- async processOrientationVideo(videoFile: string): Promise<OrientationVideoResponse> {
119
+ async processSelfieOrientationPicture(videoFile: string, token: string): Promise<SelfieVideoResponse[]> {
101
120
  try {
102
- // Create FormData for multipart/form-data request
103
121
  const formData = new FormData();
104
-
105
- // Convert base64 to blob if needed, or use file path
106
- let fileData;
107
- if (videoFile.startsWith('data:') || videoFile.startsWith('file://')) {
108
- // Handle base64 or file URI
109
- if (videoFile.startsWith('data:')) {
110
- const response = await fetch(videoFile);
111
- fileData = await response.blob();
112
- } else {
113
- // For file:// URIs, we need to handle this differently
114
- // This is a simplified approach - in a real implementation,
115
- // you might need platform-specific handling
116
- const response = await fetch(videoFile);
117
- fileData = await response.blob();
122
+ const rnFile: any = {
123
+ uri: videoFile,
124
+ type: 'image/jpeg',
125
+ name: 'selfie_picture.jpg',
126
+ };
127
+ formData.append('file', rnFile);
128
+ const response = await axios.post<SelfieVideoResponse[]>(
129
+ `${this.faceServiceURL}/detect_face_orientation/`,
130
+ formData,
131
+ {
132
+ timeout: 20000,
133
+ headers: { 'Content-Type': 'multipart/form-data', 'Authorization': `Bearer ${token}`, },
118
134
  }
119
- } else {
120
- // Assume it's already a blob or file object
121
- fileData = videoFile as any;
122
- }
135
+ );
136
+ return response.data;
137
+ } catch (error) {
138
+ console.error('Error processing selfie orientation:', error);
139
+ throw error;
140
+ }
141
+ }
123
142
 
124
- formData.append('file', fileData, 'orientation_video.mp4');
143
+ async processOrientationVideo(videoFile: string): Promise<OrientationVideoResponse> {
144
+ try {
145
+ // Create FormData for multipart/form-data request
146
+ const formData = new FormData();
147
+ // In React Native, prefer the { uri, type, name } pattern rather than Blob
148
+ const rnFile: any = {
149
+ uri: videoFile,
150
+ type: 'video/mp4',
151
+ name: 'orientation_video.mp4',
152
+ };
153
+ formData.append('file', rnFile);
125
154
 
126
155
  const response = await axios.post(
127
- `${this.baseURL}/process_orientation_video_stream/`,
156
+ `${this.orientationServiceURL}/process_orientation_video_stream/`,
128
157
  formData,
129
- {
130
- headers: {
131
- // 'Authorization': `Bearer ${this.apiKey}`,
132
- 'Content-Type': 'multipart/form-data',
133
- }
158
+ {
159
+ // Let axios set the proper multipart boundary header automatically
160
+ timeout: 90000,
134
161
  }
135
162
  );
136
163
 
@@ -141,7 +168,7 @@ export class KYCService {
141
168
  };
142
169
  } catch (error: any) {
143
170
  console.error('Error processing orientation video:', JSON.stringify(error, null, 2));
144
-
171
+
145
172
  // Handle specific error cases
146
173
  if (error.response?.status === 503) {
147
174
  return {
@@ -166,6 +193,299 @@ export class KYCService {
166
193
  };
167
194
  }
168
195
  }
196
+
197
+ // STEP 1 - ID CARD VALIDATION
198
+ async detectFaceOnId(idCardImageUri: string, token: string, docType: string): Promise<{ result: boolean, detail: any[] }> {
199
+ const formData = new FormData();
200
+ const rnFile: any = { uri: idCardImageUri, type: 'image/jpeg', name: 'id_card_photo.jpg' };
201
+ formData.append('file', rnFile);
202
+
203
+ const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType];
204
+
205
+ try {
206
+ const res = await axios.post(`${this.faceServiceURL}/detect_face/?doc_type=${docTypeShorted}`, formData,
207
+ {
208
+ headers: { 'Content-Type': 'multipart/form-data', 'Authorization': `Bearer ${token}`, },
209
+ timeout: 20000
210
+ });
211
+ console.log('detectFaceOnId res', JSON.stringify(res.data, null, 2));
212
+
213
+ if (res.data?.result) return res.data;
214
+ throw new Error(res.data?.detail || 'detect_face failed');
215
+ } catch (error) {
216
+ console.error('Error detecting face on id:', JSON.stringify(error));
217
+ throw error;
218
+ }
219
+ }
220
+
221
+ async extractDocumentInformation(params: { fileUri: string; docType: string; docRegion: string; token: string }): Promise<any> {
222
+ const { fileUri, docType, docRegion, token } = params;
223
+ const formData = new FormData();
224
+ const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_front.jpg' };
225
+ formData.append('file', rnFile);
226
+
227
+ const url = `${this.textExtractionServiceURL}/extract_doc_information/?doc_type=${encodeURIComponent(docType)}&doc_region=${encodeURIComponent(docRegion)}`;
228
+ const attempt = async () => {
229
+ const res = await axios.post(url, formData, {
230
+ headers: { 'Content-Type': 'multipart/form-data', 'Authorization': `Bearer ${token}`, },
231
+ timeout: 60000,
232
+ });
233
+ console.log('extractDocumentInformation res', JSON.stringify(res));
234
+
235
+ if (res.data?.detail) throw new Error(res.data.detail);
236
+ return res.data;
237
+ };
238
+ try {
239
+ return await attempt();
240
+ } catch (e) {
241
+ console.error('Error extracting document information:', JSON.stringify(e));
242
+ throw e;
243
+ // await new Promise(r => setTimeout(r, 1500));
244
+ // return await attempt();
245
+ }
246
+ }
247
+ // STEP 2 - barcode extraction
248
+ async extractBarcode(params: { fileUri: string; token: string }): Promise<any> {
249
+ const { fileUri, token } = params;
250
+ const formData = new FormData();
251
+ const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_back.jpg' };
252
+ formData.append('file', rnFile);
253
+
254
+ const url = `${this.barcodeServiceURL}/decode_barcode/`;
255
+ const attempt = async () => {
256
+ try {
257
+ const res = await axios.post(url, formData, {
258
+ headers: { 'Content-Type': 'multipart/form-data', 'Authorization': `Bearer ${token}`, },
259
+ timeout: 60000,
260
+ });
261
+ console.log('extractBarcode res', JSON.stringify(res.data));
262
+ //check if res.data has aleast one key
263
+ if (Object.keys(res.data).length === 0) throw new Error('No data found');
264
+ return res.data;
265
+ } catch (e: any) {
266
+ throw new Error(e?.message || 'Erreur de détection du barcode');
267
+ }
268
+ };
269
+ try {
270
+ return await attempt();
271
+ } catch (e) {
272
+ console.error('Error extracting Barcode text:', JSON.stringify(e));
273
+ throw e;
274
+ }
275
+ }
276
+ // STEP 3 - MRZ TEXT EXTRACTION
277
+ async extractMrzText(params: { fileUri: string; docType: string; docRegion: string; postfix?: string; token: string }): Promise<any> {
278
+ const { fileUri, docType, docRegion, postfix = 'back', token } = params;
279
+ const formData = new FormData();
280
+ const rnFile: any = { uri: fileUri, type: 'image/jpeg', name: 'id_card_back.jpg' };
281
+ formData.append('file', rnFile);
282
+ const docTypeShorted = GovernmentDocumentTypeShorted[docType as GovernmentDocumentType];
283
+ console.log("docTypeShorted", docTypeShorted, docRegion, postfix);
284
+
285
+ const url = `${this.mrzServiceURL}/extract_mrz_text/?doc_type=${docTypeShorted}&doc_region=${docRegion}&postfix=${postfix}`;
286
+ console.log("url", url);
287
+
288
+ const attempt = async () => {
289
+ try {
290
+ const res = await axios.post<ExtractMrzTextResponse>(url, formData, {
291
+ headers: { 'Content-Type': 'multipart/form-data', 'Authorization': `Bearer ${token}`, },
292
+ timeout: 60000,
293
+ });
294
+ console.log('extractMrzText res', JSON.stringify(res.data));
295
+ //check if res.data has aleast one key
296
+ if (Object.keys(res.data).length === 0) throw new Error('No data found');
297
+ if (res.data?.success === false) throw new Error(res.data.parsed_data.status);
298
+ return res.data;
299
+ } catch (e: any) {
300
+ throw new Error(e?.message || 'Erreur de détection du MRZ');
301
+ }
302
+ };
303
+ try {
304
+ return await attempt();
305
+ } catch (e) {
306
+ console.error('Error extracting MRZ text:', JSON.stringify(errorMessage(e), null, 2));
307
+ throw e;
308
+ }
309
+ }
310
+
311
+ // STEP 2 - SELFIE VALIDATION
312
+ async recognizeFace(params: { idPhotoUri: string; selfiePhotoUri: string }): Promise<{ is_match: boolean; similarity: number; id_bbox?: number[]; selfie_bbox?: number[] }> {
313
+ const { idPhotoUri, selfiePhotoUri } = params;
314
+ const formData = new FormData();
315
+ const idFile: any = { uri: idPhotoUri, type: 'image/jpeg', name: 'id_card_photo.jpg' };
316
+ const selfieFile: any = { uri: selfiePhotoUri, type: 'image/jpeg', name: 'selfie_final.jpg' };
317
+ formData.append('id_photo', idFile);
318
+ formData.append('selfie_photo', selfieFile);
319
+
320
+ const res = await axios.post(`${this.faceServiceURL}/recognize_face/`, formData, { timeout: 45000 });
321
+ if (res.data?.detail) throw new Error(res.data.detail);
322
+ return res.data;
323
+ }
324
+
325
+ // HEALTH CHECKS
326
+ async healthFaceDetection(): Promise<any> {
327
+ const res = await axios.get(`${this.faceServiceURL}/health`);
328
+ return res.data;
329
+ }
330
+
331
+ async healthTextExtraction(): Promise<any> {
332
+ const res = await axios.get(`${this.textExtractionServiceURL}/health`);
333
+ return res.data;
334
+ }
335
+
336
+ async healthMrzService(): Promise<any> {
337
+ const res = await axios.get(`${this.mrzServiceURL}/health`);
338
+ return res.data;
339
+ }
340
+
341
+ async healthOrientationService(): Promise<any> {
342
+ const res = await axios.get(`${this.orientationServiceURL}/health`);
343
+ return res.data;
344
+ }
345
+
346
+ async newSession(token: string): Promise<SessionResponse> {
347
+ try {
348
+ const data = {
349
+ "status": "PENDING",
350
+ "metadata": {},
351
+ }
352
+ const res = await axios.post<SessionResponse>(`${this.backendServiceURL}/verification/sessions/`,
353
+ data, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } });
354
+ return res.data;
355
+ } catch (error: any) {
356
+ console.error('Error creating session:', JSON.stringify(errorMessage(error), null, 2));
357
+
358
+ // Extract backend error message if available
359
+ const backendMessage = errorMessage(error);
360
+
361
+ if (backendMessage) {
362
+ console.error('Backend error message:', JSON.stringify(backendMessage, null, 2));
363
+ throw new Error(`Backend error: ${JSON.stringify(backendMessage)}`);
364
+ }
365
+
366
+ throw error;
367
+ }
368
+ }
369
+
370
+ async verificationSession(payload: VerificationSessionRequest): Promise<any> {
371
+
372
+ try {
373
+
374
+ const token = await authentification();
375
+
376
+ // /api/v1/verification/api/kyc/sessions/{session_id}/steps/{step}/
377
+ const { session_id, step, data, templateId, action } = payload;
378
+ // const session_id = "kyc-8b4e069258d8";
379
+ const payloadData = {
380
+ action: action,
381
+ data: {
382
+ step,
383
+ templateId,
384
+ ...(action === "location_permission" ? { permissionGranted: true, } : {}),
385
+ ...data,
386
+ },
387
+ ...({ session_id: session_id }),
388
+ timestamp: new Date().toISOString()
389
+ }
390
+ const url = `${this.backendServiceURL}/verification/api/kyc/sessions/${session_id}/steps/${step}/`;
391
+
392
+
393
+ const logPayload = truncateFields({ payloadData, session_id, step });
394
+ console.log('verificationSession payload',
395
+ JSON.stringify({ logPayload, token, path: url },
396
+ null, 2))
397
+
398
+ const res = await axios.post<SessionResponse>(url,
399
+ payloadData,
400
+ {
401
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }
402
+ });
403
+ console.log('verificationSession res', JSON.stringify(res.data, null, 2));
404
+ return res.data;
405
+
406
+
407
+ } catch (error) {
408
+ console.error('Error validating component:', JSON.stringify(errorMessage(error), null, 2));
409
+ throw new Error(errorMessage(error));
410
+ }
411
+ }
412
+ // reultat de la verification
413
+ async getVerificationResult(session_id: string): Promise<VerificationResult> {
414
+ const token = await authentification();
415
+ const url = `${this.backendServiceURL}/verification/api/kyc/result/?session_id=${session_id}`;
416
+ const res = await axios.get<VerificationResult>(url,
417
+ { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } });
418
+ console.log('getVerificationResult res', JSON.stringify(res.data, null, 2));
419
+ return res.data;
420
+ }
421
+ }
422
+
423
+
424
+ const kycService = new KYCService("", "");
425
+ export default kycService;
426
+
427
+
428
+ // Pour éviter d'afficher des champs trop longs, on tronque les valeurs longues dans le log
429
+ export function truncateFields(obj: any, maxLength = 420): any {
430
+ if (typeof obj !== 'object' || obj === null) return obj;
431
+ if (Array.isArray(obj)) return obj.map(item => truncateFields(item, maxLength));
432
+ const truncated: any = {};
433
+ for (const key in obj) {
434
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
435
+ const value = obj[key];
436
+ if (typeof value === 'string' && value.length > maxLength) {
437
+ truncated[key] = value.slice(0, maxLength) + '... [truncated]';
438
+ } else if (typeof value === 'object' && value !== null) {
439
+ truncated[key] = truncateFields(value, maxLength);
440
+ } else {
441
+ truncated[key] = value;
442
+ }
443
+ }
444
+ return truncated;
169
445
  }
446
+ export const authentification = async () => {
447
+ try {
448
+ const params = new URLSearchParams();
449
+ params.append('client_id', 'kyc_frontend');
450
+ params.append('client_secret', 'ZCW4mGaJXWR0UuI40lM1pHNQmYLw2xvX');
451
+ params.append('grant_type', 'client_credentials');
452
+ const res = await axios.post(`http://16.170.133.50:7080/realms/kyc/protocol/openid-connect/token`,
453
+ params,
454
+ {
455
+ headers: {
456
+ 'Content-Type': 'application/x-www-form-urlencoded',
457
+ },
458
+ }
459
+ );
460
+ console.log('authentification res', JSON.stringify(res.data));
461
+ return res.data.access_token;
462
+ } catch (error: any) {
463
+ console.error('Error authentifying:', {
464
+ message: error.message,
465
+ status: error.response?.status,
466
+ statusText: error.response?.statusText,
467
+ data: error.response?.data,
468
+ url: error.config?.url,
469
+ method: error.config?.method
470
+ });
471
+
472
+ // Extract backend error message if available
473
+ const backendMessage = errorMessage(error);
474
+
475
+ if (backendMessage) {
476
+ console.error('Backend authentication error:', JSON.stringify(backendMessage, null, 2));
477
+ throw new Error(`Authentication failed: ${JSON.stringify(backendMessage)}`);
478
+ }
479
+
480
+ throw error;
481
+ }
482
+ }
483
+
484
+
170
485
 
171
- export default KYCService;
486
+ export const errorMessage = (error: any) => {
487
+ return error.response?.data?.message ||
488
+ error.response?.data?.detail ||
489
+ error.response?.data?.error ||
490
+ error.response?.data;
491
+ }
@@ -0,0 +1,11 @@
1
+ import kycService, { authentification } from "./KYCService";
2
+
3
+ const selfieVerification = async (selfieImage: string) => {
4
+ const token = await authentification();
5
+
6
+ const response = await kycService.processSelfieOrientationPicture(selfieImage, token);
7
+ console.log("selfieVerification response", JSON.stringify(response, null, 2));
8
+ return response;
9
+ }
10
+
11
+ export default selfieVerification;
@@ -0,0 +1,8 @@
1
+ // import kycService from "./KYCService"
2
+
3
+
4
+
5
+ // const initializesession = (token: string) => {
6
+
7
+ // // const session = await kycService.post("/session", {
8
+ // }
@@ -0,0 +1,51 @@
1
+ export interface SessionResponse {
2
+ id: number;
3
+ session_id: string;
4
+ status: string;
5
+ created_at: string;
6
+ updated_at: string;
7
+ metadata: string;
8
+ user: number;
9
+ module: number;
10
+ }
11
+
12
+
13
+ export interface VerificationSessionRequest {
14
+ step: number;
15
+ data: VerificationSessionData;
16
+ templateId: string | null;
17
+ session_id: string;
18
+ token: string;
19
+ action: string
20
+ }
21
+
22
+
23
+ // dynamic type
24
+ export type VerificationSessionData = Record<string, any>;
25
+
26
+
27
+ export interface VerificationResult {
28
+ [key: string]: {
29
+ data: {
30
+ verification_id: string;
31
+ verification_status: string;
32
+ completion_timestamp: string;
33
+ user_data: {
34
+ personal_information: {
35
+ full_name: string;
36
+ first_name: string | null;
37
+ last_name: string | null;
38
+ date_of_birth: string | null;
39
+ nationality: string | null;
40
+ gender: string | null;
41
+ place_of_birth: string | null;
42
+ };
43
+ };
44
+ selfie_info: {
45
+ is_match: boolean;
46
+ similarity: number;
47
+ image: string;
48
+ };
49
+ };
50
+ };
51
+ }