@trustchex/react-native-sdk 1.495.11 → 1.496.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +4 -1
- package/android/src/main/java/com/trustchex/reactnativesdk/mlkit/MLKitModule.kt +5 -1
- package/ios/Camera/TrustchexCameraView.swift +3 -0
- package/ios/MLKit/MLKitModule.swift +1 -1
- package/lib/module/Shared/Components/EIDScanner.js +35 -4
- package/lib/module/Shared/Components/IdentityDocumentCamera.constants.js +9 -0
- package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +38 -3
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +56 -18
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +20 -5
- package/lib/module/Shared/EIDReader/eidReader.js +11 -1
- package/lib/module/Translation/Resources/en.js +3 -0
- package/lib/module/Translation/Resources/tr.js +3 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.constants.d.ts +1 -0
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.constants.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +3 -0
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +3 -0
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/lib/typescript/src/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Shared/Components/EIDScanner.tsx +49 -2
- package/src/Shared/Components/IdentityDocumentCamera.constants.ts +9 -0
- package/src/Shared/Components/IdentityDocumentCamera.flows.ts +49 -3
- package/src/Shared/Components/IdentityDocumentCamera.tsx +64 -26
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +21 -3
- package/src/Shared/EIDReader/eidReader.ts +11 -1
- package/src/Translation/Resources/en.ts +5 -0
- package/src/Translation/Resources/tr.ts +5 -0
- package/src/version.ts +1 -1
|
@@ -106,9 +106,12 @@ class TrustchexCameraView(context: ThemedReactContext) : FrameLayout(context) {
|
|
|
106
106
|
private val barcodeScanner by lazy {
|
|
107
107
|
BarcodeScanning.getClient(
|
|
108
108
|
BarcodeScannerOptions.Builder()
|
|
109
|
+
// CODE_128 (Turkish e-ID), QR, and PDF417 (US/EU driver-licenses
|
|
110
|
+
// and many national IDs carry the back-side data as PDF417).
|
|
109
111
|
.setBarcodeFormats(
|
|
110
112
|
Barcode.FORMAT_CODE_128,
|
|
111
|
-
Barcode.FORMAT_QR_CODE
|
|
113
|
+
Barcode.FORMAT_QR_CODE,
|
|
114
|
+
Barcode.FORMAT_PDF417
|
|
112
115
|
)
|
|
113
116
|
.build()
|
|
114
117
|
)
|
|
@@ -30,7 +30,11 @@ class MLKitModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM
|
|
|
30
30
|
)
|
|
31
31
|
private val barcodeScanner = BarcodeScanning.getClient(
|
|
32
32
|
BarcodeScannerOptions.Builder()
|
|
33
|
-
.setBarcodeFormats(
|
|
33
|
+
.setBarcodeFormats(
|
|
34
|
+
Barcode.FORMAT_CODE_128,
|
|
35
|
+
Barcode.FORMAT_QR_CODE,
|
|
36
|
+
Barcode.FORMAT_PDF417
|
|
37
|
+
)
|
|
34
38
|
.build()
|
|
35
39
|
)
|
|
36
40
|
|
|
@@ -220,6 +220,9 @@ class TrustchexCameraView: UIView {
|
|
|
220
220
|
|
|
221
221
|
if supportedTypes.contains(.code128) { typesToEnable.append(.code128) }
|
|
222
222
|
if supportedTypes.contains(.qr) { typesToEnable.append(.qr) }
|
|
223
|
+
// PDF417: US/EU driver-licenses and many national IDs carry the
|
|
224
|
+
// back-side data as PDF417 (already mapped to BarcodeFormat below).
|
|
225
|
+
if supportedTypes.contains(.pdf417) { typesToEnable.append(.pdf417) }
|
|
223
226
|
|
|
224
227
|
metadataOutput.metadataObjectTypes = typesToEnable
|
|
225
228
|
}
|
|
@@ -19,7 +19,7 @@ class MLKitModule: NSObject {
|
|
|
19
19
|
return FaceDetector.faceDetector(options: options)
|
|
20
20
|
}()
|
|
21
21
|
private lazy var barcodeScanner: BarcodeScanner = {
|
|
22
|
-
let formats: BarcodeFormat = [.code128, .qrCode]
|
|
22
|
+
let formats: BarcodeFormat = [.code128, .qrCode, .PDF417]
|
|
23
23
|
let options = BarcodeScannerOptions(formats: formats)
|
|
24
24
|
return BarcodeScanner.barcodeScanner(options: options)
|
|
25
25
|
}()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|
4
|
-
import { Alert, View, Text, Image, StyleSheet, Animated } from 'react-native';
|
|
4
|
+
import { Alert, View, Text, Image, StyleSheet, Animated, Vibration } from 'react-native';
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
6
|
import NFCManager from 'react-native-nfc-manager';
|
|
7
7
|
import DeviceInfo from 'react-native-device-info';
|
|
@@ -186,15 +186,27 @@ const EIDScanner = ({
|
|
|
186
186
|
// "reading document" spinner never clears and the user is stuck with no
|
|
187
187
|
// error. Cap the whole read; on timeout we throw a categorized error so
|
|
188
188
|
// the catch below surfaces a retry prompt and finally resets the UI.
|
|
189
|
+
// Fire a "chip detected" haptic exactly once, the moment progress first
|
|
190
|
+
// moves off 0 (the chip connected and the read began). Confirms contact
|
|
191
|
+
// to a user who can't see the screen while holding the phone to the doc.
|
|
192
|
+
let chipDetectedHapticFired = false;
|
|
189
193
|
const readPromise = eidReader(documentNumber, dateOfBirth, dateOfExpiry, progressValue => {
|
|
194
|
+
if (progressValue > 0 && !chipDetectedHapticFired) {
|
|
195
|
+
chipDetectedHapticFired = true;
|
|
196
|
+
Vibration.vibrate(40);
|
|
197
|
+
}
|
|
190
198
|
setProgress(progressValue);
|
|
191
199
|
// Update stage message based on progress
|
|
192
200
|
if (progressValue <= 20) {
|
|
193
201
|
setProgressStage(t('eidScannerScreen.connecting'));
|
|
194
202
|
} else if (progressValue <= 30) {
|
|
195
203
|
setProgressStage(t('eidScannerScreen.readingMRZ'));
|
|
196
|
-
} else if (progressValue <
|
|
204
|
+
} else if (progressValue < 95) {
|
|
197
205
|
setProgressStage(t('eidScannerScreen.readingFaceImage'));
|
|
206
|
+
} else if (progressValue < 100) {
|
|
207
|
+
// 95→100 is the (possibly slow) photo decode — give it its own
|
|
208
|
+
// stage so the bar doesn't look frozen at "Finalizing".
|
|
209
|
+
setProgressStage(t('eidScannerScreen.decodingFaceImage'));
|
|
198
210
|
} else {
|
|
199
211
|
setProgressStage(t('eidScannerScreen.completing'));
|
|
200
212
|
}
|
|
@@ -217,6 +229,11 @@ const EIDScanner = ({
|
|
|
217
229
|
}
|
|
218
230
|
}
|
|
219
231
|
if (passportData) {
|
|
232
|
+
// Success haptic: the phone is pressed against the document, so the
|
|
233
|
+
// user often can't see the screen — a buzz confirms the chip read
|
|
234
|
+
// finished. (The NFC step previously had no haptics at all, unlike the
|
|
235
|
+
// camera/liveness screens.)
|
|
236
|
+
Vibration.vibrate(120);
|
|
220
237
|
const scanDuration = Date.now() - startTime;
|
|
221
238
|
const documentData = normalizeFromMRZInfo(passportData.mrz);
|
|
222
239
|
const builtName = buildDocumentName(documentData.firstName, documentData.lastName, documentData.issuingCountry, passportData.dg11FirstName, passportData.dg11LastName);
|
|
@@ -299,7 +316,11 @@ const EIDScanner = ({
|
|
|
299
316
|
auth_failed: 'eidScannerScreen.nfcAuthFailed',
|
|
300
317
|
tag_lost: 'eidScannerScreen.nfcTagLost',
|
|
301
318
|
timeout: 'eidScannerScreen.nfcTimeout',
|
|
302
|
-
not_enabled: 'eidScannerScreen.nfcNotEnabled'
|
|
319
|
+
not_enabled: 'eidScannerScreen.nfcNotEnabled',
|
|
320
|
+
// The default/most-common "chip just wouldn't read" bucket. Show the
|
|
321
|
+
// actionable hold-flat-and-retry guidance rather than the generic
|
|
322
|
+
// "contact support" message — re-placing the phone usually fixes it.
|
|
323
|
+
reading_error: 'eidScannerScreen.nfcReadFailed'
|
|
303
324
|
};
|
|
304
325
|
if (category !== 'user_cancelled') {
|
|
305
326
|
const actionableKey = ACTIONABLE[category];
|
|
@@ -569,7 +590,10 @@ const EIDScanner = ({
|
|
|
569
590
|
}) || documentType === 'UNKNOWN' && /*#__PURE__*/_jsx(Text, {
|
|
570
591
|
style: styles.mainText,
|
|
571
592
|
children: t('eidScannerScreen.placeDocumentOnNFC')
|
|
572
|
-
})), hasNfc && isEnabled &&
|
|
593
|
+
})), hasNfc && isEnabled && isScanning && progress === 0 && /*#__PURE__*/_jsx(Text, {
|
|
594
|
+
style: styles.keepStillHint,
|
|
595
|
+
children: t('eidScannerScreen.keepStill')
|
|
596
|
+
}), hasNfc && isEnabled && !isScanning && !isScanned && /*#__PURE__*/_jsx(View, {
|
|
573
597
|
style: styles.buttonsContainer,
|
|
574
598
|
children: /*#__PURE__*/_jsx(StyledButton, {
|
|
575
599
|
mode: "contained",
|
|
@@ -661,6 +685,13 @@ const styles = StyleSheet.create({
|
|
|
661
685
|
color: 'black',
|
|
662
686
|
textAlign: 'center'
|
|
663
687
|
},
|
|
688
|
+
keepStillHint: {
|
|
689
|
+
fontSize: 15,
|
|
690
|
+
color: '#666',
|
|
691
|
+
textAlign: 'center',
|
|
692
|
+
marginTop: 12,
|
|
693
|
+
paddingHorizontal: 24
|
|
694
|
+
},
|
|
664
695
|
// ── ID Card result layout ──────────────────────────────────────────────
|
|
665
696
|
idCardWrapper: {
|
|
666
697
|
gap: 10
|
|
@@ -17,6 +17,15 @@ export const REQUIRED_CONSISTENT_DOCTYPE_DETECTIONS = 3;
|
|
|
17
17
|
export const SIGNATURE_REGEX = /s[gi]g?n[au]?t[u]?r|imz[a]s?/i;
|
|
18
18
|
export const SIGNATURE_TEXT_REGEX = /signature|imza|İmza/i;
|
|
19
19
|
export const MRZ_BLOCK_PATTERN = /[A-Z0-9<]{8,}.*</i;
|
|
20
|
+
// A DENSE MRZ run — a contiguous block of MRZ characters that contains a chevron
|
|
21
|
+
// FILLER pair (`<<`). Real machine-readable zones are padded with `<<…`; a card
|
|
22
|
+
// FACE (ID front) has no MRZ, and the occasional stray single `<` OCR'd from a
|
|
23
|
+
// guilloche/chevron glyph will NOT contain a `<<` filler run. Used to decide
|
|
24
|
+
// "is a real MRZ visible on this front?" without the false positives of
|
|
25
|
+
// MRZ_BLOCK_PATTERN (whose `.*<` lets a lone detached `<` anywhere in the frame
|
|
26
|
+
// match) — that looseness could otherwise wedge a legitimate ID front that
|
|
27
|
+
// happens to OCR a stray `<`.
|
|
28
|
+
export const MRZ_DENSE_PATTERN = /[A-Z0-9<]{6,}<<[A-Z0-9<]*/i;
|
|
20
29
|
// Matches the line-1 start of ANY ICAO TD3 passport MRZ, so the camera routes
|
|
21
30
|
// every passport variant into the passport flow (not the ID-card back-side
|
|
22
31
|
// flow). Per ICAO 9303 Part 4: `P` + a type char (filler `<` or a subtype
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* - No face, has MRZ with code 'I'
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
import { PASSPORT_MRZ_PATTERN } from "./IdentityDocumentCamera.constants.js";
|
|
33
|
+
import { PASSPORT_MRZ_PATTERN, MRZ_DENSE_PATTERN } from "./IdentityDocumentCamera.constants.js";
|
|
34
34
|
import { isIDCardDocumentCode, isPassportDocumentCode, documentHasBackSide } from "./IdentityDocumentCamera.utils.js";
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -142,8 +142,15 @@ export function handleIDFrontFlow(faces, text, mrzText, mrzFields, retryCount) {
|
|
|
142
142
|
nextAction: 'REJECT_AS_PASSPORT'
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
|
|
146
|
+
// Passport MRZ pattern visible even if not fully parsed. Check BOTH the
|
|
147
|
+
// parsed `mrzText` (null until the MRZ validates) AND the raw OCR `text` — a
|
|
148
|
+
// passport's MRZ is dense and frequently OCRs a few frames after its face +
|
|
149
|
+
// signature, so on the accepting frame `mrzText` is often still null while the
|
|
150
|
+
// raw `P<XXX...` run is already visible. Testing only `mrzText` (the old bug)
|
|
151
|
+
// let such a passport pass as an ID front and get routed to a back side that
|
|
152
|
+
// does not exist.
|
|
153
|
+
if (mrzText && PASSPORT_MRZ_PATTERN.test(mrzText) || PASSPORT_MRZ_PATTERN.test(text)) {
|
|
147
154
|
return {
|
|
148
155
|
shouldProceed: false,
|
|
149
156
|
reason: 'Passport MRZ pattern visible - not an ID card',
|
|
@@ -163,6 +170,34 @@ export function handleIDFrontFlow(faces, text, mrzText, mrzFields, retryCount) {
|
|
|
163
170
|
};
|
|
164
171
|
}
|
|
165
172
|
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// STEP 2b: An ID-card FRONT has NO MRZ (the MRZ is on the back). So if a real
|
|
175
|
+
// MRZ is currently visible on this "front", it is almost certainly a passport
|
|
176
|
+
// data page whose 'P' code we just haven't parsed yet — do NOT accept it as an
|
|
177
|
+
// ID front; wait for the MRZ to resolve (→ a 'P' code routes it to the
|
|
178
|
+
// passport flow). This is the guard that stops a passport (face + signature +
|
|
179
|
+
// not-yet-parsed MRZ) being accepted as ID_FRONT and then getting stuck at
|
|
180
|
+
// SCAN_ID_BACK, which rejects the passport's photo page because it has a face.
|
|
181
|
+
//
|
|
182
|
+
// We use MRZ_DENSE_PATTERN (requires a `<<` filler run), NOT the loose
|
|
183
|
+
// MRZ_BLOCK_PATTERN — a card face has no MRZ, but a stray single `<` OCR'd
|
|
184
|
+
// from a guilloche could match the loose pattern and wedge a real ID front.
|
|
185
|
+
// We ALSO honor the signature retry threshold: a real ID front genuinely has
|
|
186
|
+
// no MRZ, so if a "dense MRZ" keeps matching frame after frame past the
|
|
187
|
+
// threshold it is OCR noise, not a passport — fall through and let STEP 3's
|
|
188
|
+
// face-only acceptance proceed rather than waiting forever.
|
|
189
|
+
const mrzVisibleOnFront = !!mrzText || MRZ_DENSE_PATTERN.test(text);
|
|
190
|
+
const stillWaitingForMrz = retryCount <= SIGNATURE_RETRY_THRESHOLD;
|
|
191
|
+
if (mrzVisibleOnFront && stillWaitingForMrz && !isIDCardDocumentCode(mrzFields?.documentCode)) {
|
|
192
|
+
// An ID-card MRZ code (I/A/C) is allowed to proceed (handled in STEP 4); any
|
|
193
|
+
// other visible MRZ → keep waiting for it to parse and reveal a 'P' code.
|
|
194
|
+
return {
|
|
195
|
+
shouldProceed: false,
|
|
196
|
+
reason: 'MRZ block visible on front - waiting to confirm it is not a passport',
|
|
197
|
+
nextAction: 'WAIT_FOR_MRZ'
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
166
201
|
// ============================================================================
|
|
167
202
|
// STEP 3: Check for signature (optional front side confirmation)
|
|
168
203
|
// ============================================================================
|
|
@@ -23,7 +23,7 @@ import { useTheme } from "../Contexts/ThemeContext.js";
|
|
|
23
23
|
import DebugOverlay, { TestModePanel } from "./DebugOverlay.js";
|
|
24
24
|
import { getStatusMessage, getFrameToScreenTransform, transformBoundsToScreen, getScanAreaBounds, angleBetweenPoints, detectDocumentType, determineDocumentTypeToSet, areMRZFieldsEqual, hasRequiredMRZFields, validateFacePosition, isPassportDocumentCode } from "./IdentityDocumentCamera.utils.js";
|
|
25
25
|
import { handlePassportFlow, handleIDFrontFlow, handleIDBackFlow, getNextStepAfterHologram } from "./IdentityDocumentCamera.flows.js";
|
|
26
|
-
import { HOLOGRAM_IMAGE_COUNT, HOLOGRAM_DETECTION_THRESHOLD, HOLOGRAM_DETECTION_RETRY_COUNT, HOLOGRAM_CAPTURE_INTERVAL, HOLOGRAM_MAX_FRAMES_WITHOUT_FACE, MIN_BRIGHTNESS_THRESHOLD, MAX_BRIGHTNESS_THRESHOLD, FACE_EDGE_MARGIN_PERCENT, MAX_CONSECUTIVE_QUALITY_FAILURES, REQUIRED_CONSISTENT_DOCTYPE_DETECTIONS, SIGNATURE_TEXT_REGEX, MRZ_BLOCK_PATTERN,
|
|
26
|
+
import { HOLOGRAM_IMAGE_COUNT, HOLOGRAM_DETECTION_THRESHOLD, HOLOGRAM_DETECTION_RETRY_COUNT, HOLOGRAM_CAPTURE_INTERVAL, HOLOGRAM_MAX_FRAMES_WITHOUT_FACE, MIN_BRIGHTNESS_THRESHOLD, MAX_BRIGHTNESS_THRESHOLD, FACE_EDGE_MARGIN_PERCENT, MAX_CONSECUTIVE_QUALITY_FAILURES, REQUIRED_CONSISTENT_DOCTYPE_DETECTIONS, SIGNATURE_TEXT_REGEX, MRZ_BLOCK_PATTERN, MIN_CARD_FACE_SIZE_PERCENT } from "./IdentityDocumentCamera.constants.js";
|
|
27
27
|
|
|
28
28
|
// Re-export types for backward compatibility
|
|
29
29
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -71,6 +71,11 @@ const IdentityDocumentCamera = ({
|
|
|
71
71
|
const [currentSecondaryFaceImage, setCurrentSecondaryFaceImage] = useState(undefined);
|
|
72
72
|
const [isBrightnessLow, setIsBrightnessLow] = useState(false);
|
|
73
73
|
const [isFrameBlurry, setIsFrameBlurry] = useState(false);
|
|
74
|
+
// Glare was being silently rejected (frames dropped with no user feedback), so
|
|
75
|
+
// a user fighting reflections just saw the scan hang. Surface it so we can show
|
|
76
|
+
// an actionable "move away from glare" hint. Set at each glare rejection;
|
|
77
|
+
// cleared when a frame passes the brightness check (a fresh, glare-free frame).
|
|
78
|
+
const [isGlareDetected, setIsGlareDetected] = useState(false);
|
|
74
79
|
const [hasGuideShown, setHasGuideShown] = useState(false);
|
|
75
80
|
const [status, setStatus] = useState('SEARCHING');
|
|
76
81
|
// True once the multi-frame voted MRZ consensus is STABLE + valid (the same
|
|
@@ -153,7 +158,8 @@ const IdentityDocumentCamera = ({
|
|
|
153
158
|
frameW: 0,
|
|
154
159
|
frameH: 0,
|
|
155
160
|
hadLowBrightness: false,
|
|
156
|
-
hadBlurryFrames: false
|
|
161
|
+
hadBlurryFrames: false,
|
|
162
|
+
hadGlare: false
|
|
157
163
|
});
|
|
158
164
|
const [faceDetectionEnabled, setFaceDetectionEnabled] = useState(true);
|
|
159
165
|
const faceImages = useRef([]);
|
|
@@ -219,7 +225,8 @@ const IdentityDocumentCamera = ({
|
|
|
219
225
|
frameW: 0,
|
|
220
226
|
frameH: 0,
|
|
221
227
|
hadLowBrightness: false,
|
|
222
|
-
hadBlurryFrames: false
|
|
228
|
+
hadBlurryFrames: false,
|
|
229
|
+
hadGlare: false
|
|
223
230
|
};
|
|
224
231
|
cachedBarcode.current = null;
|
|
225
232
|
isCompletionCallbackInvoked.current = false;
|
|
@@ -255,7 +262,7 @@ const IdentityDocumentCamera = ({
|
|
|
255
262
|
}, [isFocused, hasPermission, hasGuideShown]);
|
|
256
263
|
useEffect(() => {
|
|
257
264
|
if (!hasGuideShown || !appContext.currentWorkflowStep?.data?.voiceGuidanceActive) return;
|
|
258
|
-
const message = getStatusMessage(nextStep, status, detectedDocumentType, isBrightnessLow, isFrameBlurry, allElementsDetected, elementsOutsideScanArea, t);
|
|
265
|
+
const message = getStatusMessage(nextStep, status, detectedDocumentType, isBrightnessLow, isFrameBlurry, isGlareDetected, allElementsDetected, elementsOutsideScanArea, t);
|
|
259
266
|
if (message) {
|
|
260
267
|
if (nextStep === 'COMPLETED') {
|
|
261
268
|
if (isCompletionAnnouncementSpoken.current) {
|
|
@@ -268,7 +275,7 @@ const IdentityDocumentCamera = ({
|
|
|
268
275
|
const shouldBypassInterval = nextStep !== 'COMPLETED';
|
|
269
276
|
speak(message, shouldBypassInterval);
|
|
270
277
|
}
|
|
271
|
-
}, [appContext.currentWorkflowStep?.data?.voiceGuidanceActive, hasGuideShown, isBrightnessLow, isFrameBlurry, nextStep, status, detectedDocumentType, allElementsDetected, elementsOutsideScanArea, t]);
|
|
278
|
+
}, [appContext.currentWorkflowStep?.data?.voiceGuidanceActive, hasGuideShown, isBrightnessLow, isFrameBlurry, isGlareDetected, nextStep, status, detectedDocumentType, allElementsDetected, elementsOutsideScanArea, t]);
|
|
272
279
|
useEffect(() => {
|
|
273
280
|
if (status === 'INCORRECT') {
|
|
274
281
|
const timeout = setTimeout(() => {
|
|
@@ -377,7 +384,9 @@ const IdentityDocumentCamera = ({
|
|
|
377
384
|
}
|
|
378
385
|
};
|
|
379
386
|
|
|
380
|
-
// Check if face image has glare (brightness exceeds threshold)
|
|
387
|
+
// Check if face image has glare (brightness exceeds threshold). Also surfaces
|
|
388
|
+
// the result to `isGlareDetected` so the user gets an actionable hint instead
|
|
389
|
+
// of a silently-stalled scan.
|
|
381
390
|
const checkFaceGlare = async faceImage => {
|
|
382
391
|
try {
|
|
383
392
|
// Check entire face region for glare
|
|
@@ -386,6 +395,8 @@ const IdentityDocumentCamera = ({
|
|
|
386
395
|
100,
|
|
387
396
|
// Full face height
|
|
388
397
|
MAX_BRIGHTNESS_THRESHOLD);
|
|
398
|
+
setIsGlareDetected(hasGlare);
|
|
399
|
+
if (hasGlare) diagStats.current.hadGlare = true;
|
|
389
400
|
return hasGlare;
|
|
390
401
|
} catch (error) {
|
|
391
402
|
return false; // Assume no glare on error
|
|
@@ -404,6 +415,8 @@ const IdentityDocumentCamera = ({
|
|
|
404
415
|
try {
|
|
405
416
|
// Check center 80% region for glare (document area)
|
|
406
417
|
const hasGlare = await OpenCVModule.isRectangularRegionBright(image, Math.round(width * 0.1), Math.round(height * 0.1), Math.round(width * 0.8), Math.round(height * 0.8), MAX_BRIGHTNESS_THRESHOLD);
|
|
418
|
+
setIsGlareDetected(hasGlare);
|
|
419
|
+
if (hasGlare) diagStats.current.hadGlare = true;
|
|
407
420
|
return hasGlare;
|
|
408
421
|
} catch (error) {
|
|
409
422
|
return false;
|
|
@@ -817,22 +830,38 @@ const IdentityDocumentCamera = ({
|
|
|
817
830
|
const hasFaces = primaryFaces.length > 0;
|
|
818
831
|
const hasSignature = /signature|imza|İmza/i.test(text);
|
|
819
832
|
const hasPassportMRZ = parsedMRZData?.fields?.documentCode === 'P';
|
|
820
|
-
const hasPassportMRZPattern = mrzText && PASSPORT_MRZ_PATTERN.test(mrzText);
|
|
821
|
-
if (hasFaces || hasSignature || hasPassportMRZ || hasPassportMRZPattern) {
|
|
822
|
-
setStatus('INCORRECT');
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
833
|
|
|
826
|
-
//
|
|
827
|
-
|
|
834
|
+
// RECOVERY (must run BEFORE the wrong-side guard below): a passport was
|
|
835
|
+
// misrouted to SCAN_ID_BACK. A passport has only its data page, which
|
|
836
|
+
// carries a face + MRZ — exactly what the wrong-side guard treats as
|
|
837
|
+
// "wrong side", so without this it would loop on INCORRECT forever
|
|
838
|
+
// (the reported "stuck asking for ID back" case). If we have positive
|
|
839
|
+
// passport evidence here, the front was already captured, so complete
|
|
840
|
+
// as a passport instead of waiting for a back that does not exist.
|
|
841
|
+
//
|
|
842
|
+
// We deliberately gate ONLY on authoritative signals: a locked PASSPORT
|
|
843
|
+
// classification, or a PARSED MRZ document code of 'P'. We do NOT test
|
|
844
|
+
// the raw OCR `text` against PASSPORT_MRZ_PATTERN here — an ID card's
|
|
845
|
+
// BACK legitimately carries an MRZ whose name line ("PAPPAS<<MARIA…",
|
|
846
|
+
// "…<<PHILIPP…") can false-match the unanchored pattern and would then
|
|
847
|
+
// wrongly complete a real ID card as a passport, skipping the back-side
|
|
848
|
+
// MRZ + barcode validation entirely.
|
|
849
|
+
if (detectedDocumentType === 'PASSPORT' || hasPassportMRZ) {
|
|
828
850
|
transitionStepWithCallback('COMPLETED', 'SCAN_ID_BACK', {
|
|
829
851
|
image,
|
|
830
852
|
documentType: 'PASSPORT',
|
|
831
|
-
mrzText: mrzText ?? undefined,
|
|
832
|
-
mrzFields: parsedMRZData?.fields
|
|
853
|
+
mrzText: mrzText ?? lastValidMRZText.current ?? undefined,
|
|
854
|
+
mrzFields: parsedMRZData?.fields ?? lastValidMRZFields.current ?? undefined
|
|
833
855
|
});
|
|
834
856
|
return;
|
|
835
857
|
}
|
|
858
|
+
|
|
859
|
+
// Wrong-side detection: a face or signature means we're looking at a
|
|
860
|
+
// front, not an ID-card back (which has neither).
|
|
861
|
+
if (hasFaces || hasSignature) {
|
|
862
|
+
setStatus('INCORRECT');
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
836
865
|
setElementsOutsideScanArea([]);
|
|
837
866
|
const flowResult = handleIDBackFlow(mrzText, parsedMRZData?.fields, parsedMRZData?.valid === true, mrzStableAndValid, hasRequiredMRZFields(parsedMRZData?.fields), barcodeToUse?.rawValue, onlyMRZScan);
|
|
838
867
|
if (!flowResult.shouldProceed) {
|
|
@@ -1354,6 +1383,15 @@ const IdentityDocumentCamera = ({
|
|
|
1354
1383
|
setIsBrightnessLow(!isRegionBright);
|
|
1355
1384
|
if (!isRegionBright) diagStats.current.hadLowBrightness = true;
|
|
1356
1385
|
|
|
1386
|
+
// Reset glare to false at the start of every frame. The glare helpers
|
|
1387
|
+
// (checkDocumentGlare/checkFaceGlare) only run at accept-time and set it
|
|
1388
|
+
// true when they find glare; without this per-frame clear the flag would
|
|
1389
|
+
// latch — a "Glare detected" warning would stick over a now-clean view
|
|
1390
|
+
// (and, once a face is locked, the face-glare site never runs again so it
|
|
1391
|
+
// could never clear at all). The accept-time checks run later in this same
|
|
1392
|
+
// frame's handlers and re-assert true if glare is still present.
|
|
1393
|
+
setIsGlareDetected(false);
|
|
1394
|
+
|
|
1357
1395
|
// Check blur only in center region (area of interest) to avoid false positives
|
|
1358
1396
|
// from iOS depth-of-field background blur
|
|
1359
1397
|
let isNotBlurry = true;
|
|
@@ -1838,12 +1876,12 @@ const IdentityDocumentCamera = ({
|
|
|
1838
1876
|
opacity: errorFlashAnim
|
|
1839
1877
|
},
|
|
1840
1878
|
// 3. Warning (yellow) - quality issues
|
|
1841
|
-
(isBrightnessLow || isFrameBlurry) && styles.topZoneTextWarning,
|
|
1879
|
+
(isBrightnessLow || isFrameBlurry || isGlareDetected) && styles.topZoneTextWarning,
|
|
1842
1880
|
// 4. Scanning (green) - all elements detected AND inside scan area
|
|
1843
|
-
status === 'SCANNING' && allElementsDetected && elementsOutsideScanArea.length === 0 && !isBrightnessLow && !isFrameBlurry && styles.topZoneTextScanning
|
|
1881
|
+
status === 'SCANNING' && allElementsDetected && elementsOutsideScanArea.length === 0 && !isBrightnessLow && !isFrameBlurry && !isGlareDetected && styles.topZoneTextScanning
|
|
1844
1882
|
// 5. Default (white) - aligning (not all detected OR elements outside scan area)
|
|
1845
1883
|
],
|
|
1846
|
-
children: getStatusMessage(nextStep, status, detectedDocumentType, isBrightnessLow, isFrameBlurry, allElementsDetected, elementsOutsideScanArea, t)
|
|
1884
|
+
children: getStatusMessage(nextStep, status, detectedDocumentType, isBrightnessLow, isFrameBlurry, isGlareDetected, allElementsDetected, elementsOutsideScanArea, t)
|
|
1847
1885
|
})]
|
|
1848
1886
|
}), /*#__PURE__*/_jsx(View, {
|
|
1849
1887
|
style: styles.leftZone
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { Dimensions } from 'react-native';
|
|
4
|
-
import { SIGNATURE_REGEX, PASSPORT_MRZ_PATTERN } from "./IdentityDocumentCamera.constants.js";
|
|
4
|
+
import { SIGNATURE_REGEX, PASSPORT_MRZ_PATTERN, MRZ_DENSE_PATTERN } from "./IdentityDocumentCamera.constants.js";
|
|
5
5
|
import { debugLog, isDebugEnabled } from "../Libs/debug.utils.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -100,7 +100,7 @@ export function transformBoundsToScreen(bounds, scale, offsetX, offsetY) {
|
|
|
100
100
|
* Unified status message logic used by both voice guidance and render text.
|
|
101
101
|
* Returns the appropriate i18n key arguments for the current scan state.
|
|
102
102
|
*/
|
|
103
|
-
export function getStatusMessage(nextStep, status, detectedDocumentType, isBrightnessLow, isFrameBlurry, allElementsDetected, elementsOutsideScanArea, t) {
|
|
103
|
+
export function getStatusMessage(nextStep, status, detectedDocumentType, isBrightnessLow, isFrameBlurry, isGlareDetected, allElementsDetected, elementsOutsideScanArea, t) {
|
|
104
104
|
if (nextStep === 'COMPLETED') {
|
|
105
105
|
return t('identityDocumentCamera.scanCompleted');
|
|
106
106
|
}
|
|
@@ -126,6 +126,14 @@ export function getStatusMessage(nextStep, status, detectedDocumentType, isBrigh
|
|
|
126
126
|
if (isBrightnessLow) {
|
|
127
127
|
return t('identityDocumentCamera.lowBrightness');
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
// Glare is a primary failure mode (reflections off the laminate/photo). It was
|
|
131
|
+
// previously detected but never communicated, so the scan just appeared to
|
|
132
|
+
// hang. Tell the user how to fix it. Ranked above blur because a glare hotspot
|
|
133
|
+
// both blocks acceptance and often reads as a "sharp" (non-blurry) frame.
|
|
134
|
+
if (isGlareDetected) {
|
|
135
|
+
return t('identityDocumentCamera.reduceGlare');
|
|
136
|
+
}
|
|
129
137
|
if (isFrameBlurry) {
|
|
130
138
|
return t('identityDocumentCamera.avoidBlur');
|
|
131
139
|
}
|
|
@@ -248,10 +256,17 @@ export function detectDocumentType(faces, ocrText, mrzFields, frameWidth, mrzTex
|
|
|
248
256
|
return 'ID_FRONT';
|
|
249
257
|
}
|
|
250
258
|
|
|
251
|
-
// If signature present and NO passport MRZ pattern, likely ID_FRONT
|
|
252
|
-
//
|
|
259
|
+
// If signature present and NO passport MRZ pattern, likely ID_FRONT —
|
|
260
|
+
// BUT an ID-card front has no MRZ, so if a real (dense) MRZ is visible here
|
|
261
|
+
// (and it is not a confirmed ID code — that returned above) this is almost
|
|
262
|
+
// certainly a passport data page whose 'P' code just hasn't OCR'd yet.
|
|
263
|
+
// Stay UNKNOWN and let later frames resolve it, rather than locking
|
|
264
|
+
// ID_FRONT and routing a passport to a back side it does not have. We use
|
|
265
|
+
// MRZ_DENSE_PATTERN (needs a `<<` filler run) so a stray single `<` OCR'd
|
|
266
|
+
// from a card-face guilloche cannot wedge a genuine ID front at UNKNOWN.
|
|
267
|
+
const hasUnresolvedMrzBlock = !!mrzText || MRZ_DENSE_PATTERN.test(ocrText);
|
|
253
268
|
const hasSignature = hasSignatureMatch;
|
|
254
|
-
if (hasSignature && !hasPassportMRZPattern) {
|
|
269
|
+
if (hasSignature && !hasPassportMRZPattern && !hasUnresolvedMrzBlock) {
|
|
255
270
|
return 'ID_FRONT';
|
|
256
271
|
}
|
|
257
272
|
}
|
|
@@ -633,8 +633,12 @@ const eidReader = async (documentNumber, dateOfBirth, dateOfExpiry, progressCall
|
|
|
633
633
|
// step (it was previously outside, so an early DG2 failure went unlabelled).
|
|
634
634
|
const dg2InputStream = passportService.getInputStream(EIDService.EF_DG2);
|
|
635
635
|
await dg2InputStream.init();
|
|
636
|
+
// Map the DG2 byte stream to 30→95 (not →100): the JPEG2000 decode that
|
|
637
|
+
// follows can take a noticeable beat (esp. large passport portraits), and
|
|
638
|
+
// jumping to 100 before it made the UI sit at "100% Finalizing" looking
|
|
639
|
+
// frozen during the decode. We reserve 95→100 for the decode step below.
|
|
636
640
|
InputStream.onRead((totalBytesRead, fileLength) => {
|
|
637
|
-
progress = 30 + totalBytesRead / fileLength *
|
|
641
|
+
progress = 30 + totalBytesRead / fileLength * 65;
|
|
638
642
|
if (progressCallback) {
|
|
639
643
|
progressCallback(progress);
|
|
640
644
|
}
|
|
@@ -656,6 +660,12 @@ const eidReader = async (documentNumber, dateOfBirth, dateOfExpiry, progressCall
|
|
|
656
660
|
const buffer = Buffer.alloc(imageLength);
|
|
657
661
|
await imageInputStream.readBytesWithOffset(buffer, 0, imageLength);
|
|
658
662
|
const rawMimeType = faceImageInfo.getMimeType();
|
|
663
|
+
// Signal the (potentially slow) photo decode so the UI shows a distinct
|
|
664
|
+
// "decoding photo" stage at 95% rather than appearing frozen at 100%.
|
|
665
|
+
progress = 95;
|
|
666
|
+
if (progressCallback) {
|
|
667
|
+
progressCallback(progress);
|
|
668
|
+
}
|
|
659
669
|
const converted = await convertJP2IfNeeded(buffer, rawMimeType);
|
|
660
670
|
imageAsBase64 = converted.base64;
|
|
661
671
|
mimeType = converted.mimeType;
|
|
@@ -113,11 +113,13 @@ export default {
|
|
|
113
113
|
'eidScannerScreen.placePassportOnNFC': 'Place your passport near the NFC reader',
|
|
114
114
|
'eidScannerScreen.placeDocumentOnNFC': 'Place your document near the NFC reader',
|
|
115
115
|
'eidScannerScreen.readingDocument': 'Hold steady - Reading document',
|
|
116
|
+
'eidScannerScreen.keepStill': 'Keep the document and phone still until the read completes.',
|
|
116
117
|
'eidScannerScreen.checkYourInformation': 'Review your information carefully',
|
|
117
118
|
'eidScannerScreen.approveAndContinue': 'Approve and Continue',
|
|
118
119
|
'eidScannerScreen.connecting': 'Establishing secure connection...',
|
|
119
120
|
'eidScannerScreen.readingMRZ': 'Reading document information...',
|
|
120
121
|
'eidScannerScreen.readingFaceImage': 'Reading photo data...',
|
|
122
|
+
'eidScannerScreen.decodingFaceImage': 'Decoding photo...',
|
|
121
123
|
'eidScannerScreen.completing': 'Finalizing verification...',
|
|
122
124
|
'eidScannerScreen.progress': 'Progress',
|
|
123
125
|
'identityDocumentCamera.guideHeader': 'Document Scan',
|
|
@@ -142,6 +144,7 @@ export default {
|
|
|
142
144
|
'identityDocumentCamera.hologramCheck': 'Hologram',
|
|
143
145
|
'identityDocumentCamera.keepSteady': 'Keep device steady',
|
|
144
146
|
'identityDocumentCamera.avoidBlur': 'Keep device steady',
|
|
147
|
+
'identityDocumentCamera.reduceGlare': 'Glare detected. Tilt the document or move away from direct light.',
|
|
145
148
|
'identityDocumentCamera.wrongSideFront': 'Show the front side of your document',
|
|
146
149
|
'identityDocumentCamera.wrongSideBack': 'Show the back side of your document',
|
|
147
150
|
'identityDocumentCamera.idCardDetected': 'ID detected',
|
|
@@ -113,11 +113,13 @@ export default {
|
|
|
113
113
|
'eidScannerScreen.placePassportOnNFC': 'Pasaportunuzu NFC okuyucuya yaklaştırın',
|
|
114
114
|
'eidScannerScreen.placeDocumentOnNFC': 'Belgenizi NFC okuyucuya yaklaştırın',
|
|
115
115
|
'eidScannerScreen.readingDocument': 'Sabit tutun - Belge okunuyor',
|
|
116
|
+
'eidScannerScreen.keepStill': 'Okuma tamamlanana kadar belgeyi ve telefonu sabit tutun.',
|
|
116
117
|
'eidScannerScreen.checkYourInformation': 'Bilgilerinizi dikkatle kontrol edin',
|
|
117
118
|
'eidScannerScreen.approveAndContinue': 'Onayla ve Devam Et',
|
|
118
119
|
'eidScannerScreen.connecting': 'Güvenli bağlantı kuruluyor...',
|
|
119
120
|
'eidScannerScreen.readingMRZ': 'Belge bilgileri okunuyor...',
|
|
120
121
|
'eidScannerScreen.readingFaceImage': 'Fotoğraf verisi okunuyor...',
|
|
122
|
+
'eidScannerScreen.decodingFaceImage': 'Fotoğraf çözümleniyor...',
|
|
121
123
|
'eidScannerScreen.completing': 'Doğrulama tamamlanıyor...',
|
|
122
124
|
'eidScannerScreen.progress': 'İlerleme',
|
|
123
125
|
'identityDocumentCamera.guideHeader': 'Belge Taraması',
|
|
@@ -142,6 +144,7 @@ export default {
|
|
|
142
144
|
'identityDocumentCamera.hologramCheck': 'Hologram',
|
|
143
145
|
'identityDocumentCamera.keepSteady': 'Cihazı sabit tutun',
|
|
144
146
|
'identityDocumentCamera.avoidBlur': 'Cihazı sabit tutun',
|
|
147
|
+
'identityDocumentCamera.reduceGlare': 'Parlama algılandı. Belgeyi hafifçe eğin veya doğrudan ışıktan uzaklaşın.',
|
|
145
148
|
'identityDocumentCamera.wrongSideFront': 'Belgenizin ön yüzünü gösterin',
|
|
146
149
|
'identityDocumentCamera.wrongSideBack': 'Belgenizin arka yüzünü gösterin',
|
|
147
150
|
'identityDocumentCamera.idCardDetected': 'Kimlik kartı algılandı',
|
package/lib/module/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EIDScanner.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/EIDScanner.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EIDScanner.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/EIDScanner.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAwBpD,UAAU,eAAe;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,SAAS,EAClB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,KACtB,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAED,QAAA,MAAM,UAAU,GAAI,6FAOjB,eAAe,4CA80BjB,CAAC;AAmOF,eAAe,UAAU,CAAC"}
|
|
@@ -14,6 +14,7 @@ export declare const REQUIRED_CONSISTENT_DOCTYPE_DETECTIONS = 3;
|
|
|
14
14
|
export declare const SIGNATURE_REGEX: RegExp;
|
|
15
15
|
export declare const SIGNATURE_TEXT_REGEX: RegExp;
|
|
16
16
|
export declare const MRZ_BLOCK_PATTERN: RegExp;
|
|
17
|
+
export declare const MRZ_DENSE_PATTERN: RegExp;
|
|
17
18
|
export declare const PASSPORT_MRZ_PATTERN: RegExp;
|
|
18
19
|
export declare const MIN_SECURITY_FEATURES_REQUIRED = 4;
|
|
19
20
|
export declare const SECURITY_FEATURE_NAMES: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.constants.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,4BAA4B,OAAO,CAAC;AACjD,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAEnD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AACnD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAC/C,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,sCAAsC,IAAI,CAAC;AAExD,eAAO,MAAM,eAAe,QAAkC,CAAC;AAC/D,eAAO,MAAM,oBAAoB,QAAyB,CAAC;AAC3D,eAAO,MAAM,iBAAiB,QAAsB,CAAC;AASrD,eAAO,MAAM,oBAAoB,QAAyC,CAAC;AAI3E,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,eAAO,MAAM,sBAAsB;;;;;;;;;;CAUzB,CAAC;AAKX,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,gCAAgC,MAAM,CAAC;AACpD,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,mBAAmB,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.constants.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,4BAA4B,OAAO,CAAC;AACjD,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAEnD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AACnD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAC/C,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,sCAAsC,IAAI,CAAC;AAExD,eAAO,MAAM,eAAe,QAAkC,CAAC;AAC/D,eAAO,MAAM,oBAAoB,QAAyB,CAAC;AAC3D,eAAO,MAAM,iBAAiB,QAAsB,CAAC;AASrD,eAAO,MAAM,iBAAiB,QAA+B,CAAC;AAS9D,eAAO,MAAM,oBAAoB,QAAyC,CAAC;AAI3E,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,eAAO,MAAM,sBAAsB;;;;;;;;;;CAUzB,CAAC;AAKX,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,gCAAgC,MAAM,CAAC;AACpD,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,mBAAmB,MAAM,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.tsx"],"names":[],"mappings":"AAyEA,OAAO,KAAK,EACV,mBAAmB,EACnB,SAAS,EACT,2BAA2B,EAK5B,MAAM,gCAAgC,CAAC;AAGxC,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAMnE,QAAA,MAAM,sBAAsB,GAAI,uDAI7B,2BAA2B,4CA0oF7B,CAAC;AAiIF,eAAe,sBAAsB,CAAC"}
|
|
@@ -37,7 +37,7 @@ export interface PassportFlowResult {
|
|
|
37
37
|
export interface IDFrontFlowResult {
|
|
38
38
|
shouldProceed: boolean;
|
|
39
39
|
reason?: string;
|
|
40
|
-
nextAction?: 'WAIT_FOR_ELEMENTS' | 'REJECT_AS_PASSPORT' | 'PROCEED_TO_HOLOGRAM';
|
|
40
|
+
nextAction?: 'WAIT_FOR_ELEMENTS' | 'WAIT_FOR_MRZ' | 'REJECT_AS_PASSPORT' | 'PROCEED_TO_HOLOGRAM';
|
|
41
41
|
}
|
|
42
42
|
export interface IDBackFlowResult {
|
|
43
43
|
shouldProceed: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.flows.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.flows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAgB,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.flows.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.flows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAgB,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiBpD,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EACP,mBAAmB,GACnB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EACP,mBAAmB,GACnB,cAAc,GACd,oBAAoB,GACpB,qBAAqB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;CAC3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,iBAAiB,EAAE,OAAO,EAC1B,WAAW,EAAE,OAAO,EACpB,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,OAAO,GACpB,kBAAkB,CAgEpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAoHnB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,QAAQ,EAAE,OAAO,EACjB,iBAAiB,EAAE,OAAO,EAC1B,iBAAiB,EAAE,OAAO,EAC1B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,WAAW,EAAE,OAAO,GACnB,gBAAgB,CA2DlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,wBAAwB,CACtC,oBAAoB,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,EACrE,mBAAmB,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,EACpE,UAAU,EAAE,MAAM,GAAG,SAAS,EAM9B,iBAAiB,GAAE,OAAe,GACjC,WAAW,GAAG,cAAc,CAuB9B"}
|
|
@@ -57,7 +57,7 @@ export declare function transformBoundsToScreen(bounds: {
|
|
|
57
57
|
* Unified status message logic used by both voice guidance and render text.
|
|
58
58
|
* Returns the appropriate i18n key arguments for the current scan state.
|
|
59
59
|
*/
|
|
60
|
-
export declare function getStatusMessage(nextStep: ScanStep, status: ScanStatus, detectedDocumentType: DocumentType, isBrightnessLow: boolean, isFrameBlurry: boolean, allElementsDetected: boolean, elementsOutsideScanArea: string[], t: (key: string, params?: Record<string, unknown>) => string): string;
|
|
60
|
+
export declare function getStatusMessage(nextStep: ScanStep, status: ScanStatus, detectedDocumentType: DocumentType, isBrightnessLow: boolean, isFrameBlurry: boolean, isGlareDetected: boolean, allElementsDetected: boolean, elementsOutsideScanArea: string[], t: (key: string, params?: Record<string, unknown>) => string): string;
|
|
61
61
|
/**
|
|
62
62
|
* Calculate angle from two points in degrees
|
|
63
63
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityDocumentCamera.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,IAAI,EACL,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"IdentityDocumentCamera.utils.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/Components/IdentityDocumentCamera.utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eidReader.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/EIDReader/eidReader.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AA2Y7C,QAAA,MAAM,SAAS,GACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,EACnB,cAAc,MAAM,EACpB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KAC5C,OAAO,CACN;IACE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GACD,SAAS,
|
|
1
|
+
{"version":3,"file":"eidReader.d.ts","sourceRoot":"","sources":["../../../../../src/Shared/EIDReader/eidReader.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AA2Y7C,QAAA,MAAM,SAAS,GACb,gBAAgB,MAAM,EACtB,aAAa,MAAM,EACnB,cAAc,MAAM,EACpB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KAC5C,OAAO,CACN;IACE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GACD,SAAS,CAyYZ,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -111,11 +111,13 @@ declare const _default: {
|
|
|
111
111
|
'eidScannerScreen.placePassportOnNFC': string;
|
|
112
112
|
'eidScannerScreen.placeDocumentOnNFC': string;
|
|
113
113
|
'eidScannerScreen.readingDocument': string;
|
|
114
|
+
'eidScannerScreen.keepStill': string;
|
|
114
115
|
'eidScannerScreen.checkYourInformation': string;
|
|
115
116
|
'eidScannerScreen.approveAndContinue': string;
|
|
116
117
|
'eidScannerScreen.connecting': string;
|
|
117
118
|
'eidScannerScreen.readingMRZ': string;
|
|
118
119
|
'eidScannerScreen.readingFaceImage': string;
|
|
120
|
+
'eidScannerScreen.decodingFaceImage': string;
|
|
119
121
|
'eidScannerScreen.completing': string;
|
|
120
122
|
'eidScannerScreen.progress': string;
|
|
121
123
|
'identityDocumentCamera.guideHeader': string;
|
|
@@ -140,6 +142,7 @@ declare const _default: {
|
|
|
140
142
|
'identityDocumentCamera.hologramCheck': string;
|
|
141
143
|
'identityDocumentCamera.keepSteady': string;
|
|
142
144
|
'identityDocumentCamera.avoidBlur': string;
|
|
145
|
+
'identityDocumentCamera.reduceGlare': string;
|
|
143
146
|
'identityDocumentCamera.wrongSideFront': string;
|
|
144
147
|
'identityDocumentCamera.wrongSideBack': string;
|
|
145
148
|
'identityDocumentCamera.idCardDetected': string;
|