react-native-unit-components 3.5.1 → 3.5.3
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/lib/commonjs/components/UNCheckDepositComponent/UNCheckDepositComponent.js +3 -0
- package/lib/commonjs/components/UNCheckDepositComponent/UNCheckDepositComponent.js.map +1 -1
- package/lib/commonjs/components/UNCheckDepositComponent/UNCheckDepositComponent.utils.js +7 -0
- package/lib/commonjs/components/UNCheckDepositComponent/UNCheckDepositComponent.utils.js.map +1 -1
- package/lib/commonjs/messages/webMessages/unitComponentsMessages.js +1 -0
- package/lib/commonjs/messages/webMessages/unitComponentsMessages.js.map +1 -1
- package/lib/commonjs/services/veryfiService.js +68 -12
- package/lib/commonjs/services/veryfiService.js.map +1 -1
- package/lib/commonjs/services/veryfiService.utils.js +87 -0
- package/lib/commonjs/services/veryfiService.utils.js.map +1 -0
- package/lib/commonjs/types/shared/error.types.js.map +1 -1
- package/lib/commonjs/unitComponentsSdkManager/UnitComponentsSdkManager.js +19 -19
- package/lib/commonjs/unitComponentsSdkManager/UnitComponentsSdkManager.js.map +1 -1
- package/lib/module/components/UNCheckDepositComponent/UNCheckDepositComponent.js +3 -0
- package/lib/module/components/UNCheckDepositComponent/UNCheckDepositComponent.js.map +1 -1
- package/lib/module/components/UNCheckDepositComponent/UNCheckDepositComponent.utils.js +7 -0
- package/lib/module/components/UNCheckDepositComponent/UNCheckDepositComponent.utils.js.map +1 -1
- package/lib/module/messages/webMessages/unitComponentsMessages.js +1 -0
- package/lib/module/messages/webMessages/unitComponentsMessages.js.map +1 -1
- package/lib/module/services/veryfiService.js +68 -12
- package/lib/module/services/veryfiService.js.map +1 -1
- package/lib/module/services/veryfiService.utils.js +79 -0
- package/lib/module/services/veryfiService.utils.js.map +1 -0
- package/lib/module/types/shared/error.types.js.map +1 -1
- package/lib/module/unitComponentsSdkManager/UnitComponentsSdkManager.js +19 -19
- package/lib/module/unitComponentsSdkManager/UnitComponentsSdkManager.js.map +1 -1
- package/lib/typescript/src/components/UNCheckDepositComponent/UNCheckDepositComponent.d.ts +2 -1
- package/lib/typescript/src/components/UNCheckDepositComponent/UNCheckDepositComponent.d.ts.map +1 -1
- package/lib/typescript/src/components/UNCheckDepositComponent/UNCheckDepositComponent.utils.d.ts.map +1 -1
- package/lib/typescript/src/messages/webMessages/unitComponentsMessages.d.ts +3 -1
- package/lib/typescript/src/messages/webMessages/unitComponentsMessages.d.ts.map +1 -1
- package/lib/typescript/src/services/veryfiService.d.ts +2 -4
- package/lib/typescript/src/services/veryfiService.d.ts.map +1 -1
- package/lib/typescript/src/services/veryfiService.utils.d.ts +10 -0
- package/lib/typescript/src/services/veryfiService.utils.d.ts.map +1 -0
- package/lib/typescript/src/types/shared/error.types.d.ts +4 -0
- package/lib/typescript/src/types/shared/error.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/UNCheckDepositComponent/UNCheckDepositComponent.tsx +5 -1
- package/src/components/UNCheckDepositComponent/UNCheckDepositComponent.utils.ts +7 -0
- package/src/messages/webMessages/unitComponentsMessages.ts +3 -0
- package/src/services/veryfiService.ts +76 -16
- package/src/services/veryfiService.utils.ts +87 -0
- package/src/types/shared/error.types.ts +5 -0
- package/src/unitComponentsSdkManager/UnitComponentsSdkManager.ts +19 -19
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { NativeEventEmitter } from 'react-native';
|
|
2
2
|
import type { UNVeryfiCredentials } from '../types/shared/veryfi.types';
|
|
3
|
+
import { labelSidesFromPages } from './veryfiService.utils';
|
|
4
|
+
import type { UNVeryfiImage } from './veryfiService.utils';
|
|
5
|
+
|
|
6
|
+
export type { UNVeryfiImage } from './veryfiService.utils';
|
|
3
7
|
|
|
4
8
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
9
|
let VeryfiLens: any = null;
|
|
@@ -14,16 +18,15 @@ export const isVeryfiAvailable = (): boolean => {
|
|
|
14
18
|
return VeryfiLens != null;
|
|
15
19
|
};
|
|
16
20
|
|
|
17
|
-
export interface UNVeryfiImage {
|
|
18
|
-
base64Img: string;
|
|
19
|
-
isFront: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
21
|
const CHECK_SETTINGS = {
|
|
23
22
|
documentTypes: ['check'],
|
|
24
23
|
checksBackIsOn: true,
|
|
24
|
+
checksBackIsRequired: true,
|
|
25
25
|
blurDetectionIsOn: true,
|
|
26
26
|
autoDocDetectionAndCropIsOn: true,
|
|
27
|
+
// Without this, a no-document capture is kept in the package and the user
|
|
28
|
+
// lands on the submit screen with an image that can only fail.
|
|
29
|
+
allowSubmitUndetectedDocsIsOn: false,
|
|
27
30
|
dataExtractionEngine: true,
|
|
28
31
|
returnStitchedPDF: true,
|
|
29
32
|
originalImageMaxSizeInMB: 1.4,
|
|
@@ -38,6 +41,10 @@ const buildEndorsement = (bankName?: string): string => {
|
|
|
38
41
|
return `Please make sure to sign the back and write “For mobile deposit ${bank ? `at ${bank}` : 'only'}”`;
|
|
39
42
|
};
|
|
40
43
|
|
|
44
|
+
// How long to hold delivery waiting for Veryfi's parsed result before falling
|
|
45
|
+
// back to positional labeling.
|
|
46
|
+
const VERDICT_WAIT_MS = 10000;
|
|
47
|
+
|
|
41
48
|
export const configureAndShowVeryfiCamera = (
|
|
42
49
|
credentials: UNVeryfiCredentials,
|
|
43
50
|
bankName: string | undefined,
|
|
@@ -52,15 +59,48 @@ export const configureAndShowVeryfiCamera = (
|
|
|
52
59
|
const emitter = new NativeEventEmitter(VeryfiLens.NativeModule);
|
|
53
60
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
61
|
const subscriptions: any[] = [];
|
|
55
|
-
let
|
|
62
|
+
let capturing = false;
|
|
63
|
+
let dispatched = false;
|
|
64
|
+
let convertedImages: UNVeryfiImage[] | null = null;
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
let verdictPages: any = null;
|
|
67
|
+
let fallbackTimer: ReturnType<typeof setTimeout> | null = null;
|
|
56
68
|
|
|
57
69
|
const cleanup = () => {
|
|
58
70
|
subscriptions.forEach((sub) => sub.remove());
|
|
71
|
+
if (fallbackTimer != null) {
|
|
72
|
+
clearTimeout(fallbackTimer);
|
|
73
|
+
fallbackTimer = null;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const dispatchToWeb = (images: UNVeryfiImage[]) => {
|
|
78
|
+
if (dispatched) return;
|
|
79
|
+
dispatched = true;
|
|
80
|
+
cleanup();
|
|
81
|
+
onImages(images);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Delivery is held briefly so Veryfi's parsed result — the authoritative
|
|
85
|
+
// source for which image is the front — can label the pair before the web
|
|
86
|
+
// renders it. The positional fallback covers slow or failed uploads;
|
|
87
|
+
// position is unreliable across Veryfi versions (the order reversed in
|
|
88
|
+
// Android lens 2.4.0.0), which is exactly why the verdict is preferred.
|
|
89
|
+
const dispatchWhenReady = () => {
|
|
90
|
+
if (dispatched || !convertedImages) return;
|
|
91
|
+
if (verdictPages) {
|
|
92
|
+
const labeled = labelSidesFromPages(convertedImages, verdictPages);
|
|
93
|
+
dispatchToWeb(labeled ?? convertedImages);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (fallbackTimer == null) {
|
|
97
|
+
fallbackTimer = setTimeout(() => dispatchToWeb(convertedImages as UNVeryfiImage[]), VERDICT_WAIT_MS);
|
|
98
|
+
}
|
|
59
99
|
};
|
|
60
100
|
|
|
61
|
-
const
|
|
62
|
-
if (
|
|
63
|
-
|
|
101
|
+
const convertImages = (imagePaths: string[]) => {
|
|
102
|
+
if (capturing) return;
|
|
103
|
+
capturing = true;
|
|
64
104
|
|
|
65
105
|
let converted = 0;
|
|
66
106
|
const images: UNVeryfiImage[] = [];
|
|
@@ -72,10 +112,11 @@ export const configureAndShowVeryfiCamera = (
|
|
|
72
112
|
() => {
|
|
73
113
|
converted++;
|
|
74
114
|
if (converted === imagePaths.length) {
|
|
75
|
-
cleanup();
|
|
76
115
|
if (images.length > 0) {
|
|
77
|
-
|
|
116
|
+
convertedImages = images;
|
|
117
|
+
dispatchWhenReady();
|
|
78
118
|
} else {
|
|
119
|
+
cleanup();
|
|
79
120
|
onError('Failed to convert check images');
|
|
80
121
|
}
|
|
81
122
|
}
|
|
@@ -88,8 +129,8 @@ export const configureAndShowVeryfiCamera = (
|
|
|
88
129
|
});
|
|
89
130
|
converted++;
|
|
90
131
|
if (converted === imagePaths.length) {
|
|
91
|
-
|
|
92
|
-
|
|
132
|
+
convertedImages = images;
|
|
133
|
+
dispatchWhenReady();
|
|
93
134
|
}
|
|
94
135
|
}
|
|
95
136
|
);
|
|
@@ -103,14 +144,33 @@ export const configureAndShowVeryfiCamera = (
|
|
|
103
144
|
if (event.status === 'inprogress' && event.msg === 'img_stitched_pdf_path') {
|
|
104
145
|
const paths = event.img_original_paths || [];
|
|
105
146
|
if (paths.length > 0) {
|
|
106
|
-
|
|
147
|
+
convertImages(paths);
|
|
107
148
|
}
|
|
108
149
|
}
|
|
109
150
|
})
|
|
110
151
|
);
|
|
111
152
|
|
|
112
|
-
|
|
113
|
-
|
|
153
|
+
subscriptions.push(
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
155
|
+
emitter.addListener(VeryfiLens.Events.onVeryfiLensSuccess, (event: any) => {
|
|
156
|
+
verdictPages = event?.data?.meta?.pages ?? null;
|
|
157
|
+
dispatchWhenReady();
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// User cancelled (X button) without submitting: the web side never resets its
|
|
162
|
+
// loading state on its own, so deliver an empty response to move it off the
|
|
163
|
+
// stuck Continue. Grace period covers a close event racing the stitched event.
|
|
164
|
+
subscriptions.push(
|
|
165
|
+
emitter.addListener(VeryfiLens.Events.onVeryfiLensClose, () => {
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
if (capturing || dispatched) return;
|
|
168
|
+
dispatched = true;
|
|
169
|
+
cleanup();
|
|
170
|
+
onImages([]);
|
|
171
|
+
}, 1500);
|
|
172
|
+
})
|
|
173
|
+
);
|
|
114
174
|
|
|
115
175
|
subscriptions.push(
|
|
116
176
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface UNVeryfiImage {
|
|
2
|
+
base64Img: string;
|
|
3
|
+
isFront: boolean;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const JPEG_SOF_MARKERS = [0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf];
|
|
7
|
+
|
|
8
|
+
export const readJpegDimensions = (base64: string): { width: number; height: number } | null => {
|
|
9
|
+
try {
|
|
10
|
+
// SOF sits near the file start; a 4-aligned prefix keeps atob happy and cheap.
|
|
11
|
+
const prefix = base64.length > 786432 ? base64.slice(0, 786432) : base64;
|
|
12
|
+
const bytes = atob(prefix);
|
|
13
|
+
if (bytes.charCodeAt(0) !== 0xff || bytes.charCodeAt(1) !== 0xd8) return null;
|
|
14
|
+
let i = 2;
|
|
15
|
+
while (i + 9 < bytes.length) {
|
|
16
|
+
if (bytes.charCodeAt(i) !== 0xff) {
|
|
17
|
+
i++;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const marker = bytes.charCodeAt(i + 1);
|
|
21
|
+
if (marker === 0xff) {
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (marker === 0x01 || (marker >= 0xd0 && marker <= 0xd9)) {
|
|
26
|
+
i += 2;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (JPEG_SOF_MARKERS.includes(marker)) {
|
|
30
|
+
return {
|
|
31
|
+
height: bytes.charCodeAt(i + 5) * 256 + bytes.charCodeAt(i + 6),
|
|
32
|
+
width: bytes.charCodeAt(i + 7) * 256 + bytes.charCodeAt(i + 8),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
i += 2 + bytes.charCodeAt(i + 2) * 256 + bytes.charCodeAt(i + 3);
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Veryfi's parsed result is the authority on which image is the front
|
|
44
|
+
// (their meta.pages[].is_front); page order does not correspond to the
|
|
45
|
+
// delivery array's order, so pages are matched to our images by exact
|
|
46
|
+
// pixel dimensions. Returns null whenever the verdict is not unambiguous.
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
|
+
export const labelSidesFromPages = (images: UNVeryfiImage[], pages: any): UNVeryfiImage[] | null => {
|
|
49
|
+
if (!Array.isArray(pages) || pages.length !== 2 || images.length !== 2) return null;
|
|
50
|
+
|
|
51
|
+
const fronts = pages.filter((p) => p && p.is_front === true);
|
|
52
|
+
const backs = pages.filter((p) => p && p.is_front === false);
|
|
53
|
+
const frontPage = fronts[0];
|
|
54
|
+
const backPage = backs[0];
|
|
55
|
+
if (fronts.length !== 1 || backs.length !== 1 || !frontPage || !backPage) return null;
|
|
56
|
+
if (typeof frontPage.width !== 'number' || typeof frontPage.height !== 'number') return null;
|
|
57
|
+
|
|
58
|
+
const dims: { width: number; height: number }[] = [];
|
|
59
|
+
for (const img of images) {
|
|
60
|
+
const d = readJpegDimensions(img.base64Img);
|
|
61
|
+
if (!d) return null;
|
|
62
|
+
dims.push(d);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Veryfi may auto-rotate pages in the parsed result, so dimensions are
|
|
66
|
+
// compared as an unordered pair.
|
|
67
|
+
const sameDims = (d: { width: number; height: number }, w: number, h: number) =>
|
|
68
|
+
(d.width === w && d.height === h) || (d.width === h && d.height === w);
|
|
69
|
+
|
|
70
|
+
const matchesFront = dims.map((d) => sameDims(d, frontPage.width, frontPage.height));
|
|
71
|
+
if (matchesFront.filter(Boolean).length !== 1) return null;
|
|
72
|
+
|
|
73
|
+
const frontIdx = matchesFront.indexOf(true);
|
|
74
|
+
const backIdx = 1 - frontIdx;
|
|
75
|
+
const frontImage = images[frontIdx];
|
|
76
|
+
const backImage = images[backIdx];
|
|
77
|
+
const backDims = dims[backIdx];
|
|
78
|
+
if (!frontImage || !backImage || !backDims) return null;
|
|
79
|
+
if (typeof backPage.width === 'number' && typeof backPage.height === 'number') {
|
|
80
|
+
if (!sameDims(backDims, backPage.width, backPage.height)) return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return [
|
|
84
|
+
{ base64Img: frontImage.base64Img, isFront: true },
|
|
85
|
+
{ base64Img: backImage.base64Img, isFront: false },
|
|
86
|
+
];
|
|
87
|
+
};
|
|
@@ -27,7 +27,7 @@ export class UnitComponentsSDK {
|
|
|
27
27
|
protected static fonts?: UNFonts;
|
|
28
28
|
protected static signedNonce?: string;
|
|
29
29
|
protected static pushProvisionModule?: typeof NativeModules;
|
|
30
|
-
protected static sdkVersion = '3.5.
|
|
30
|
+
protected static sdkVersion = '3.5.3';
|
|
31
31
|
static iosFontBase64Map: Record<string, string> = {};
|
|
32
32
|
|
|
33
33
|
public static init = async (
|
|
@@ -39,23 +39,23 @@ export class UnitComponentsSDK {
|
|
|
39
39
|
securitySettings: UNComponentsSecuritySettings = UNComponentsSDKConstants.securitySettings
|
|
40
40
|
) => {
|
|
41
41
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
UnitComponentsSDK.webVersioningStrategy = webVersioningStrategy;
|
|
43
|
+
UnitComponentsSDK.ui = new UnitComponentsUiManager();
|
|
44
|
+
UnitComponentsSDK.helpers = new UnitComponentsHelpersManager();
|
|
45
45
|
|
|
46
46
|
const isJailbroke = await UNSecurityManagerHelper.isDeviceJailbroke();
|
|
47
47
|
if (isJailbroke) {
|
|
48
48
|
throw Error('Device is jailbroke');
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
UnitComponentsSDK.env = env;
|
|
51
|
+
UnitComponentsSDK.securitySettings = securitySettings;
|
|
52
|
+
UnitComponentsSDK.fonts = fonts;
|
|
53
53
|
if (Platform.OS === 'ios' && fonts) {
|
|
54
|
-
|
|
54
|
+
UnitComponentsSDK.iosFontBase64Map = await loadIosFontBase64(fonts);
|
|
55
55
|
}
|
|
56
56
|
store.dispatch(setTheme(theme));
|
|
57
57
|
store.dispatch(setLanguage(language));
|
|
58
|
-
warnClientIfNeeded(
|
|
58
|
+
warnClientIfNeeded(UnitComponentsSDK.webVersioningStrategy);
|
|
59
59
|
const shouldProtectFromSnapshot = securitySettings.snapshotProtectionStrategy != UNComponentsSnapshotProtectionStrategy.None;
|
|
60
60
|
if (Platform.OS === 'ios') {
|
|
61
61
|
UNSnapshotProtectionHelper.setIosSecurity(shouldProtectFromSnapshot, 'light');
|
|
@@ -67,45 +67,45 @@ export class UnitComponentsSDK {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
public static isInitialized = () => {
|
|
70
|
-
return
|
|
70
|
+
return UnitComponentsSDK.env != undefined;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
public static setPushProvisioningModule = (pushProvisionModule?: typeof NativeModules) => {
|
|
74
|
-
|
|
74
|
+
UnitComponentsSDK.pushProvisionModule = pushProvisionModule;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
public static getPushProvisionModule = () => {
|
|
78
|
-
return
|
|
78
|
+
return UnitComponentsSDK.pushProvisionModule;
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
public static getSecuritySettings = () => {
|
|
82
|
-
return
|
|
82
|
+
return UnitComponentsSDK.securitySettings;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
86
|
* @deprecated - Unit SDK is managing the signedNonce, no need to provide it
|
|
87
87
|
*/
|
|
88
88
|
public static setSignedNonce = (signedNonce: string) => {
|
|
89
|
-
|
|
89
|
+
UnitComponentsSDK.signedNonce = signedNonce;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
public static getEnv = () => {
|
|
93
|
-
return
|
|
93
|
+
return UnitComponentsSDK.env;
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
public static getWebVersioningStrategy = () => {
|
|
97
|
-
return
|
|
97
|
+
return UnitComponentsSDK.webVersioningStrategy;
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
public static getFonts = () => {
|
|
101
|
-
return
|
|
101
|
+
return UnitComponentsSDK.fonts;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* @deprecated - Unit SDK is managing the signedNonce, no need to provide it
|
|
106
106
|
*/
|
|
107
107
|
public static getSignedNonce = () => {
|
|
108
|
-
return
|
|
108
|
+
return UnitComponentsSDK.signedNonce;
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
public static setCustomerToken = (customerToken: string) => {
|
|
@@ -113,7 +113,7 @@ export class UnitComponentsSDK {
|
|
|
113
113
|
};
|
|
114
114
|
|
|
115
115
|
public static getSdkVersion = () => {
|
|
116
|
-
return
|
|
116
|
+
return UnitComponentsSDK.sdkVersion;
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
public static setVeryfiCredentials = (credentials: UNVeryfiCredentials) => {
|