@sanctum-key/react-native-sdk 1.0.19 → 1.0.21
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/build/package.json +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.js +40 -128
- package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +166 -129
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/VerificationProgressTemplate.js +62 -40
- package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
- package/build/src/config/region_mapping.d.ts.map +1 -1
- package/build/src/config/region_mapping.js.map +1 -1
- package/build/src/hooks/useTemplateKYCFlow.js +1 -1
- package/build/src/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/src/modules/api/CardAuthentification.d.ts +5 -0
- package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/src/modules/api/CardAuthentification.js +82 -14
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +11 -0
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +104 -29
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/build/src/web/WebKYCEntry.d.ts.map +1 -1
- package/build/src/web/WebKYCEntry.js +34 -6
- package/build/src/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +53 -133
- package/src/components/KYCElements/IDCardCapture.tsx +613 -556
- package/src/components/KYCElements/VerificationProgressTemplate.tsx +80 -71
- package/src/config/region_mapping.ts +2 -1
- package/src/hooks/useTemplateKYCFlow.tsx +14 -14
- package/src/modules/api/CardAuthentification.ts +147 -67
- package/src/modules/api/KYCService.ts +166 -43
- package/src/web/WebKYCEntry.tsx +42 -7
|
@@ -30,19 +30,20 @@ export async function frontVerification(
|
|
|
30
30
|
code: string,
|
|
31
31
|
currentSide: string,
|
|
32
32
|
templatePath?: string,
|
|
33
|
-
mrzType?: string
|
|
33
|
+
mrzType?: string,
|
|
34
|
+
issuingSubdivision?: string
|
|
34
35
|
},
|
|
35
36
|
env: KycEnvironment = 'PRODUCTION'
|
|
36
37
|
) {
|
|
37
38
|
try {
|
|
38
39
|
console.log("Front verification START", JSON.stringify({ result }, null, 2));
|
|
39
40
|
logger.log("Front verification", JSON.stringify({ result }, null, 2));
|
|
40
|
-
|
|
41
|
+
|
|
41
42
|
const authMethods = Array.isArray(result.regionMapping?.authMethod)
|
|
42
43
|
? result.regionMapping.authMethod.map(m => String(m).toUpperCase())
|
|
43
44
|
: [];
|
|
44
45
|
const hasMrz = authMethods.some(m => m.includes('MRZ'));
|
|
45
|
-
|
|
46
|
+
|
|
46
47
|
if (env === 'SANDBOX') {
|
|
47
48
|
console.log("SANDBOX mode: Skipping AI verification for front document");
|
|
48
49
|
const mockBbox: IBbox = { minX: 400, minY: 800, width: 2200, height: 1400 };
|
|
@@ -69,25 +70,25 @@ export async function frontVerification(
|
|
|
69
70
|
};
|
|
70
71
|
return mockResponse;
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
+
|
|
73
74
|
const token = await authentification();
|
|
74
75
|
const detected = await kycService.detectFaceOnId(
|
|
75
76
|
result?.path || '', token, result?.selectedDocumentType || '', env
|
|
76
77
|
) as ApiVerificationResponse;
|
|
77
|
-
|
|
78
|
+
|
|
78
79
|
if (!detected.result) {
|
|
79
80
|
throw new Error('Aucun visage détecté sur la carte. Veuillez reprendre.');
|
|
80
81
|
}
|
|
81
|
-
|
|
82
|
+
|
|
82
83
|
const cardData = detected.card_obb && Array.isArray(detected.card_obb) && detected.card_obb.length > 0
|
|
83
84
|
? detected.card_obb[0]
|
|
84
85
|
: null;
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
let points: number[][] | null = null;
|
|
88
|
+
console.log(points)
|
|
87
89
|
let isCardInFrame = true;
|
|
88
90
|
let hasCroppedSides = false;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
|
|
91
92
|
if (cardData) {
|
|
92
93
|
points = cardData.obb;
|
|
93
94
|
if (typeof cardData.card_in_frame !== 'undefined') {
|
|
@@ -95,27 +96,45 @@ export async function frontVerification(
|
|
|
95
96
|
hasCroppedSides = Array.isArray(cardData.cropped_sides) && cardData.cropped_sides.length > 0;
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
|
|
99
100
|
if (!isCardInFrame || hasCroppedSides) {
|
|
100
101
|
logger.log(`Front Framing failed. Cropped sides detected by backend.`);
|
|
101
102
|
throw new Error('CARD_NOT_FULLY_IN_FRAME');
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
+
|
|
104
105
|
const obbConfidence = getObbConfidence(detected.card_obb);
|
|
105
106
|
if (obbConfidence !== null && obbConfidence < OBB_CONFIDENCE_THRESHOLD) {
|
|
106
107
|
throw new Error('Carte non entièrement visible. Positionnez toute la carte dans le cadre.');
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
+
|
|
109
110
|
let croppedBase64: string | undefined;
|
|
110
111
|
let bbox: IBbox | undefined;
|
|
111
112
|
let mrz: any | undefined;
|
|
112
|
-
|
|
113
|
+
let documentData: any | undefined;
|
|
114
|
+
|
|
113
115
|
try {
|
|
114
116
|
const crop = await cropByObb(result?.path || '', detected.card_obb);
|
|
115
117
|
croppedBase64 = crop.base64;
|
|
116
118
|
bbox = crop.bbox;
|
|
117
119
|
} catch { }
|
|
118
120
|
|
|
121
|
+
if (result.code === 'CA') {
|
|
122
|
+
try {
|
|
123
|
+
logger.log("Tentative d'extraction OCR (Front) - Canada Only");
|
|
124
|
+
documentData = await kycService.extractDocumentInformation({
|
|
125
|
+
fileUri: result.path || '',
|
|
126
|
+
docType: result.selectedDocumentType,
|
|
127
|
+
docRegion: result.code,
|
|
128
|
+
templatePath: result.templatePath || '',
|
|
129
|
+
issuingSubdivision: result.issuingSubdivision,
|
|
130
|
+
token: token,
|
|
131
|
+
postfix: result.currentSide || 'front'
|
|
132
|
+
});
|
|
133
|
+
} catch (err: any) {
|
|
134
|
+
logger.log("Front OCR Extraction Error:", err?.message || err);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
119
138
|
if (hasMrz) {
|
|
120
139
|
try {
|
|
121
140
|
logger.log("Tentative d'extraction MRZ (Front)");
|
|
@@ -131,11 +150,11 @@ export async function frontVerification(
|
|
|
131
150
|
},
|
|
132
151
|
env
|
|
133
152
|
);
|
|
134
|
-
|
|
153
|
+
|
|
135
154
|
mrz = typeof mrzResponse === 'string' ? JSON.parse(mrzResponse) : mrzResponse;
|
|
136
|
-
|
|
155
|
+
|
|
137
156
|
if (mrz?.parsed_data?.status === 'FAILURE' || mrz?.success === false) {
|
|
138
|
-
logger.log("
|
|
157
|
+
logger.log("Front MRZ Extraction Failed:", mrz?.parsed_data?.status_message);
|
|
139
158
|
throw new Error(`MRZ illisible: ${mrz?.parsed_data?.status_message || 'Veuillez nettoyer l\'objectif et réessayer'}`);
|
|
140
159
|
}
|
|
141
160
|
} catch (err: any) {
|
|
@@ -143,9 +162,10 @@ export async function frontVerification(
|
|
|
143
162
|
throw new Error(err?.message || "Erreur lors de l'extraction MRZ. Veuillez reprendre la photo.");
|
|
144
163
|
}
|
|
145
164
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
165
|
+
|
|
166
|
+
// Return detected frame, crop, MRZ, AND the new extracted OCR documentData
|
|
167
|
+
return { ...detected, croppedBase64, bbox, ...(mrz ? { mrz } : {}), ...(documentData ? { documentData } : {}) };
|
|
168
|
+
|
|
149
169
|
} catch (e: any) {
|
|
150
170
|
logger.log('Error front verification:', e?.message);
|
|
151
171
|
throw new Error(e?.message || 'Erreur de détection du visage');
|
|
@@ -161,22 +181,23 @@ export async function backVerification(
|
|
|
161
181
|
currentSide: string,
|
|
162
182
|
templatePath?: string,
|
|
163
183
|
mrzType?: string,
|
|
164
|
-
templateResponse?: ApiVerificationResponse
|
|
184
|
+
templateResponse?: ApiVerificationResponse,
|
|
185
|
+
issuingSubdivision?: string, // Capture province/state
|
|
186
|
+
frontTemplatePath?: string // Capture the front template to compare against
|
|
165
187
|
},
|
|
166
188
|
env: KycEnvironment = 'PRODUCTION'
|
|
167
189
|
) {
|
|
168
190
|
try {
|
|
169
191
|
if (!result.path) throw new Error('No path provided');
|
|
170
192
|
logger.log("result.regionMapping", result.regionMapping, result.currentSide, result.code);
|
|
171
|
-
|
|
172
|
-
|
|
193
|
+
|
|
173
194
|
const authMethods = Array.isArray(result.regionMapping?.authMethod)
|
|
174
195
|
? result.regionMapping.authMethod.map(m => String(m).toUpperCase())
|
|
175
196
|
: [];
|
|
176
|
-
|
|
177
|
-
const hasMrz = authMethods.some(m => m.includes('MRZ'))
|
|
197
|
+
|
|
198
|
+
const hasMrz = authMethods.some(m => m.includes('MRZ'));
|
|
178
199
|
const hasBarcode = authMethods.some(m => m.includes('BARCODE') || m.includes('2D'));
|
|
179
|
-
|
|
200
|
+
|
|
180
201
|
if (env === 'SANDBOX') {
|
|
181
202
|
console.log("SANDBOX mode: Skipping AI verification for back document");
|
|
182
203
|
const mockBbox: IBbox = { minX: 400, minY: 800, width: 2200, height: 1400 };
|
|
@@ -211,34 +232,34 @@ export async function backVerification(
|
|
|
211
232
|
}
|
|
212
233
|
return { success: true, bbox: mockBbox, card_obb: mockCardObb };
|
|
213
234
|
}
|
|
214
|
-
|
|
235
|
+
|
|
215
236
|
const token = await authentification();
|
|
216
237
|
logger.log("1. Checking template and framing for back document...");
|
|
217
|
-
|
|
238
|
+
|
|
218
239
|
const templateResponse: ApiVerificationResponse = result.templateResponse ||
|
|
219
240
|
await kycService.checkTemplateType({
|
|
220
241
|
fileUri: result.path,
|
|
221
242
|
docType: result.selectedDocumentType as any,
|
|
222
243
|
docRegion: result.code,
|
|
223
244
|
postfix: 'back',
|
|
224
|
-
token: token
|
|
245
|
+
token: token,
|
|
225
246
|
}, env);
|
|
226
|
-
|
|
247
|
+
|
|
227
248
|
if (templateResponse.success === false || templateResponse.Error) {
|
|
228
249
|
throw new Error('Impossible de lire le document. Veuillez vous rapprocher et stabiliser la caméra.');
|
|
229
250
|
}
|
|
230
|
-
|
|
251
|
+
|
|
231
252
|
const cardData = templateResponse?.card_obb && Array.isArray(templateResponse.card_obb) && templateResponse.card_obb.length > 0
|
|
232
253
|
? templateResponse.card_obb[0]
|
|
233
254
|
: null;
|
|
234
|
-
|
|
255
|
+
|
|
235
256
|
if (!cardData) throw new Error('CARD_NOT_FULLY_IN_FRAME');
|
|
236
|
-
|
|
257
|
+
|
|
237
258
|
let points: number[][] | null = null;
|
|
259
|
+
console.log(points)
|
|
238
260
|
let isCardInFrame = false;
|
|
239
261
|
let hasCroppedSides = true;
|
|
240
|
-
|
|
241
|
-
|
|
262
|
+
|
|
242
263
|
if (cardData.obb) {
|
|
243
264
|
points = cardData.obb;
|
|
244
265
|
if (typeof cardData.card_in_frame !== 'undefined') {
|
|
@@ -250,33 +271,86 @@ export async function backVerification(
|
|
|
250
271
|
isCardInFrame = true;
|
|
251
272
|
hasCroppedSides = false;
|
|
252
273
|
}
|
|
253
|
-
|
|
274
|
+
|
|
254
275
|
if (!isCardInFrame || hasCroppedSides) {
|
|
255
276
|
logger.log(`Back Framing failed. Backend reported document out of bounds.`);
|
|
256
277
|
throw new Error('CARD_NOT_FULLY_IN_FRAME');
|
|
257
278
|
}
|
|
258
|
-
|
|
279
|
+
|
|
259
280
|
const obbConf = getObbConfidence(templateResponse?.card_obb);
|
|
260
281
|
if (obbConf !== null && obbConf < OBB_CONFIDENCE_THRESHOLD) {
|
|
261
282
|
throw new Error('Carte non entièrement visible. Positionnez toute la carte dans le cadre.');
|
|
262
283
|
}
|
|
263
|
-
|
|
284
|
+
|
|
264
285
|
const activeTemplatePath = templateResponse.template_path || result.templatePath || '';
|
|
286
|
+
|
|
265
287
|
if (activeTemplatePath) {
|
|
266
288
|
const expectedCountryName = countryData[result.code]?.name_en || '';
|
|
267
289
|
const hasCodeMatch = activeTemplatePath.includes(`_${result.code}_`);
|
|
268
290
|
const hasNameMatch = expectedCountryName && activeTemplatePath.toLowerCase().includes(expectedCountryName.toLowerCase());
|
|
269
|
-
|
|
291
|
+
|
|
270
292
|
if (!hasCodeMatch && !hasNameMatch) {
|
|
271
293
|
logger.log(`Template mismatch! Expected: ${result.code} (${expectedCountryName}), Detected: ${activeTemplatePath}`);
|
|
272
294
|
throw new Error(`Le document ne correspond pas au pays sélectionné (${result.code}).`);
|
|
273
295
|
}
|
|
274
296
|
}
|
|
275
297
|
|
|
276
|
-
|
|
277
|
-
|
|
298
|
+
// 🚨 FRONT VS BACK TEMPLATE VALIDATION 🚨
|
|
299
|
+
if (result.frontTemplatePath && activeTemplatePath) {
|
|
300
|
+
try {
|
|
301
|
+
const frontPy = result.frontTemplatePath.split("/").pop()?.replace(/\.(jpg|png)$/i, ".py");
|
|
302
|
+
const backPy = activeTemplatePath.split("/").pop()?.replace(/\.(jpg|png)$/i, ".py");
|
|
303
|
+
|
|
304
|
+
if (frontPy && backPy) {
|
|
305
|
+
logger.log(`Validating Front (${frontPy}) vs Back (${backPy}) for region ${result.code}`);
|
|
306
|
+
|
|
307
|
+
// 🚨 THE FIX: Only populate subRegion for Canadian 'hic' documents. Empty for all others.
|
|
308
|
+
const isCanadianHic = result.code === 'CA' && result.selectedDocumentType === 'hic';
|
|
309
|
+
const safeSubRegion = isCanadianHic ? (result.issuingSubdivision || "") : "";
|
|
310
|
+
|
|
311
|
+
const matchValidation = await kycService.validateBackTemplate({
|
|
312
|
+
region: result.code,
|
|
313
|
+
docType: result.selectedDocumentType,
|
|
314
|
+
frontTemplateName: frontPy,
|
|
315
|
+
backTemplateName: backPy,
|
|
316
|
+
subRegion: safeSubRegion,
|
|
317
|
+
token: token
|
|
318
|
+
}, env);
|
|
319
|
+
|
|
320
|
+
// If the API succeeds but explicitly returns false, stop immediately.
|
|
321
|
+
if (!matchValidation || matchValidation.is_match === false) {
|
|
322
|
+
logger.log(`Front/Back Mismatch: ${matchValidation?.status_message}`);
|
|
323
|
+
throw new Error(`Le verso ne correspond pas au recto fourni. Vous avez scanné un document différent.`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
} catch (err: any) {
|
|
327
|
+
// Throw hard errors (like the mismatch). Ignore harmless 400s if a template mapping doesn't exist yet
|
|
328
|
+
if (err?.message?.includes('ne correspond pas')) throw err;
|
|
329
|
+
logger.log("Template matching validation skipped/failed internally:", err?.message);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
logger.log("Framing, Country, and Match verified successfully. Proceeding to Data Extraction.");
|
|
278
334
|
let extractionResult: any = {};
|
|
279
335
|
|
|
336
|
+
if (result.code === 'CA') {
|
|
337
|
+
try {
|
|
338
|
+
logger.log("Tentative d'extraction OCR (Back) - Canada Only");
|
|
339
|
+
const documentData = await kycService.extractDocumentInformation({
|
|
340
|
+
fileUri: result.path!,
|
|
341
|
+
docType: result.selectedDocumentType,
|
|
342
|
+
docRegion: result.code,
|
|
343
|
+
templatePath: activeTemplatePath,
|
|
344
|
+
issuingSubdivision: result.issuingSubdivision,
|
|
345
|
+
token: token,
|
|
346
|
+
postfix: result.currentSide || 'back'
|
|
347
|
+
});
|
|
348
|
+
extractionResult.documentData = documentData;
|
|
349
|
+
} catch (err: any) {
|
|
350
|
+
logger.log("Back OCR Extraction Error:", err?.message || err);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
280
354
|
if (hasMrz) {
|
|
281
355
|
try {
|
|
282
356
|
logger.log("Tentative d'extraction MRZ (Back)");
|
|
@@ -289,35 +363,31 @@ export async function backVerification(
|
|
|
289
363
|
template_path: activeTemplatePath,
|
|
290
364
|
mrz_type: result?.mrzType || 'TD1'
|
|
291
365
|
}, env);
|
|
292
|
-
|
|
366
|
+
|
|
293
367
|
const mrz = typeof mrzResponse === 'string' ? JSON.parse(mrzResponse) : mrzResponse;
|
|
294
|
-
|
|
368
|
+
|
|
295
369
|
if (mrz?.parsed_data?.status === 'FAILURE' || mrz?.success === false) {
|
|
296
370
|
throw new Error(mrz?.parsed_data?.status_message || 'Lecture MRZ échouée');
|
|
297
371
|
}
|
|
298
|
-
|
|
299
|
-
extractionResult.mrz = mrz; // Attaching securely to result object
|
|
300
|
-
|
|
372
|
+
extractionResult.mrz = mrz;
|
|
301
373
|
} catch (mrzError: any) {
|
|
302
374
|
logger.log(`MRZ échoué: ${mrzError?.message}`);
|
|
303
|
-
// If MRZ fails, we MUST throw an error so the user is forced to retake it!
|
|
304
375
|
throw new Error(`Lecture MRZ invalide: ${mrzError?.message || 'Veuillez nettoyer l\'objectif et réessayer'}`);
|
|
305
376
|
}
|
|
306
377
|
}
|
|
307
|
-
|
|
378
|
+
|
|
308
379
|
if (hasBarcode) {
|
|
309
380
|
try {
|
|
310
381
|
logger.log("Tentative d'extraction barcode");
|
|
311
382
|
const barcode = await kycService.extractBarcode({ fileUri: result.path!, token: token }, env);
|
|
312
383
|
extractionResult.barcode = barcode;
|
|
313
384
|
} catch (e: any) {
|
|
314
|
-
// Only throw barcode error if MRZ wasn't already successfully extracted
|
|
315
385
|
if (!extractionResult.mrz) {
|
|
316
386
|
throw new Error(`Lecture Barcode échouée: ${e?.message}`);
|
|
317
387
|
}
|
|
318
388
|
}
|
|
319
389
|
}
|
|
320
|
-
|
|
390
|
+
|
|
321
391
|
let bbox: IBbox | undefined;
|
|
322
392
|
let croppedBase64: string | undefined;
|
|
323
393
|
try {
|
|
@@ -325,7 +395,7 @@ export async function backVerification(
|
|
|
325
395
|
bbox = crop.bbox;
|
|
326
396
|
croppedBase64 = crop.base64;
|
|
327
397
|
} catch { }
|
|
328
|
-
|
|
398
|
+
|
|
329
399
|
return {
|
|
330
400
|
success: true,
|
|
331
401
|
...extractionResult,
|
|
@@ -333,15 +403,21 @@ export async function backVerification(
|
|
|
333
403
|
croppedBase64,
|
|
334
404
|
card_obb: templateResponse.card_obb
|
|
335
405
|
};
|
|
336
|
-
|
|
406
|
+
|
|
337
407
|
} catch (e: any) {
|
|
338
|
-
if (e?.message === 'CARD_NOT_FULLY_IN_FRAME') throw e;
|
|
408
|
+
if (e?.message === 'CARD_NOT_FULLY_IN_FRAME') throw e;
|
|
339
409
|
throw new Error(e?.message || 'Erreur de détection des données');
|
|
340
410
|
}
|
|
341
411
|
}
|
|
342
412
|
|
|
343
413
|
export async function checkTemplateType(
|
|
344
|
-
result: {
|
|
414
|
+
result: {
|
|
415
|
+
path?: string,
|
|
416
|
+
docType: string,
|
|
417
|
+
docRegion: string,
|
|
418
|
+
postfix: string,
|
|
419
|
+
issuingSubdivision?: string
|
|
420
|
+
},
|
|
345
421
|
env: KycEnvironment = 'PRODUCTION'
|
|
346
422
|
) {
|
|
347
423
|
try {
|
|
@@ -356,32 +432,36 @@ export async function checkTemplateType(
|
|
|
356
432
|
}]
|
|
357
433
|
};
|
|
358
434
|
}
|
|
359
|
-
|
|
435
|
+
|
|
360
436
|
const token = await authentification();
|
|
437
|
+
const isCanada = result.docRegion?.toUpperCase() === 'CA';
|
|
438
|
+
|
|
361
439
|
const templateType = await kycService.checkTemplateType({
|
|
362
440
|
fileUri: result.path || '',
|
|
363
441
|
docType: result?.docType as GovernmentDocumentType,
|
|
364
442
|
docRegion: result?.docRegion || "",
|
|
365
443
|
postfix: result?.postfix,
|
|
366
|
-
token: token
|
|
444
|
+
token: token,
|
|
445
|
+
// 🚨 Pass the subdivision strictly if the region is Canada
|
|
446
|
+
issuingSubdivision: isCanada ? result.issuingSubdivision : undefined
|
|
367
447
|
}, env);
|
|
368
|
-
|
|
448
|
+
|
|
369
449
|
if (templateType.success === false || templateType.Error) {
|
|
370
450
|
logger.log("Backend returned an error:", templateType.Error);
|
|
371
451
|
throw new Error('Impossible de lire le document. Veuillez vous rapprocher et stabiliser la caméra.');
|
|
372
452
|
}
|
|
373
|
-
|
|
453
|
+
|
|
374
454
|
const cardData = templateType.card_obb && Array.isArray(templateType.card_obb) && templateType.card_obb.length > 0
|
|
375
455
|
? templateType.card_obb[0]
|
|
376
456
|
: null;
|
|
377
|
-
|
|
457
|
+
|
|
378
458
|
if (!cardData) throw new Error('CARD_NOT_FULLY_IN_FRAME');
|
|
379
|
-
|
|
459
|
+
|
|
380
460
|
let points: number[][] | null = null;
|
|
461
|
+
console.log(points);
|
|
381
462
|
let isCardInFrame = false;
|
|
382
463
|
let hasCroppedSides = true;
|
|
383
|
-
|
|
384
|
-
|
|
464
|
+
|
|
385
465
|
if (cardData.obb) {
|
|
386
466
|
points = cardData.obb;
|
|
387
467
|
if (typeof cardData.card_in_frame !== 'undefined') {
|
|
@@ -392,25 +472,25 @@ export async function checkTemplateType(
|
|
|
392
472
|
points = cardData[0];
|
|
393
473
|
isCardInFrame = true;
|
|
394
474
|
hasCroppedSides = false;
|
|
395
|
-
// 🚨 ARTIFICIAL CHECK REMOVED HERE
|
|
396
475
|
}
|
|
397
|
-
|
|
476
|
+
|
|
398
477
|
if (!isCardInFrame || hasCroppedSides) {
|
|
399
478
|
logger.log(`Template Framing failed by backend check.`);
|
|
400
479
|
throw new Error('CARD_NOT_FULLY_IN_FRAME');
|
|
401
480
|
}
|
|
402
|
-
|
|
481
|
+
|
|
403
482
|
const LPIPS_THRESHOLD = 0.75;
|
|
404
483
|
if (templateType.lpips_score !== undefined && templateType.lpips_score > LPIPS_THRESHOLD) {
|
|
405
484
|
logger.log(`🛑 Country Mismatch! LPIPS: ${templateType.lpips_score}`);
|
|
406
485
|
throw new Error(`Le document présenté ne correspond pas au pays sélectionné (${result.docRegion}).`);
|
|
407
486
|
}
|
|
408
|
-
|
|
487
|
+
|
|
409
488
|
logger.log("templateType result", JSON.stringify(truncateFields(templateType), null, 2));
|
|
410
489
|
return templateType;
|
|
490
|
+
|
|
411
491
|
} catch (e: any) {
|
|
412
|
-
logger.log('
|
|
413
|
-
if (e?.message === 'CARD_NOT_FULLY_IN_FRAME' || e?.message?.includes('ne correspond pas')) throw e;
|
|
492
|
+
logger.log('Error checking template type:', JSON.stringify(errorMessage(e), null, 2));
|
|
493
|
+
if (e?.message === 'CARD_NOT_FULLY_IN_FRAME' || e?.message?.includes('ne correspond pas')) throw e;
|
|
414
494
|
throw new Error(e?.message || 'Erreur de vérification du template');
|
|
415
495
|
}
|
|
416
496
|
}
|