@smileid/web-components 11.0.1 → 11.0.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/dist/esm/{DocumentCaptureScreens-DmH2JZDA.js → DocumentCaptureScreens-C5BhNB-0.js} +2 -2
- package/dist/esm/{DocumentCaptureScreens-DmH2JZDA.js.map → DocumentCaptureScreens-C5BhNB-0.js.map} +1 -1
- package/dist/esm/{SelfieCaptureScreens-DbdN2zNk.js → SelfieCaptureScreens-KoQpCxtc.js} +274 -275
- package/dist/esm/SelfieCaptureScreens-KoQpCxtc.js.map +1 -0
- package/dist/esm/document.js +1 -1
- package/dist/esm/main.js +2 -2
- package/dist/esm/{package-bgeQiff6.js → package-B-UwEdv7.js} +2 -2
- package/dist/esm/{package-bgeQiff6.js.map → package-B-UwEdv7.js.map} +1 -1
- package/dist/esm/selfie.js +1 -1
- package/dist/esm/smart-camera-web.js +3 -3
- package/dist/smart-camera-web.js +20 -45
- package/dist/smart-camera-web.js.map +1 -1
- package/lib/components/selfie/src/selfie-capture-wrapper/SelfieCaptureWrapper.tsx +25 -0
- package/lib/components/selfie/src/smartselfie-capture/utils/mediapipeManager.ts +42 -1
- package/lib/components/signature-pad/package-lock.json +11 -9
- package/lib/components/signature-pad/package.json +1 -1
- package/package.json +2 -2
- package/dist/esm/SelfieCaptureScreens-DbdN2zNk.js.map +0 -1
|
@@ -5,7 +5,9 @@ import type { FunctionComponent } from 'preact';
|
|
|
5
5
|
|
|
6
6
|
import { getBoolProp } from '@/utils/props';
|
|
7
7
|
import SmartSelfieCapture from '../smartselfie-capture/SmartSelfieCapture';
|
|
8
|
+
// Legacy web component fallback (used when Mediapipe isn't available)
|
|
8
9
|
import '../selfie-capture/SelfieCapture';
|
|
10
|
+
// Mediapipe loader/manager used by SmartSelfieCapture
|
|
9
11
|
import { getMediapipeInstance } from '../smartselfie-capture/utils/mediapipeManager';
|
|
10
12
|
|
|
11
13
|
interface Props {
|
|
@@ -23,12 +25,16 @@ interface Props {
|
|
|
23
25
|
hidden?: string | boolean;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
// Wrapper component that decides whether to use the modern
|
|
29
|
+
// SmartSelfieCapture (Mediapipe-based) or fallback to the legacy `selfie-capture`
|
|
30
|
+
// web component after a timeout of 20 seconds.
|
|
26
31
|
const SelfieCaptureWrapper: FunctionComponent<Props> = ({
|
|
27
32
|
timeout = 20000,
|
|
28
33
|
'start-countdown': startCountdownProp = false,
|
|
29
34
|
hidden: hiddenProp = false,
|
|
30
35
|
...props
|
|
31
36
|
}) => {
|
|
37
|
+
// Detect if tests are running under Cypress/Electron (affects loading behavior)
|
|
32
38
|
const isParentCypress = (() => {
|
|
33
39
|
try {
|
|
34
40
|
return (
|
|
@@ -48,12 +54,21 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
|
|
|
48
54
|
|
|
49
55
|
const hidden = getBoolProp(hiddenProp);
|
|
50
56
|
const startCountdown = getBoolProp(startCountdownProp);
|
|
57
|
+
// Component state:
|
|
58
|
+
// - mediapipeReady: whether the mediapipe instance has successfully loaded
|
|
59
|
+
// - loadingProgress: percentage used for the visible loading UI
|
|
60
|
+
// - initialSessionCompleted: set when the legacy component emits publish/cancel/close
|
|
61
|
+
// - mediapipeLoading: true while attempting to load mediapipe
|
|
62
|
+
// - usingSelfieCapture: whether we've mounted the legacy `selfie-capture` element
|
|
51
63
|
const [mediapipeReady, setMediapipeReady] = useState(false);
|
|
52
64
|
const [loadingProgress, setLoadingProgress] = useState(isCypress ? 100 : 0);
|
|
53
65
|
const [initialSessionCompleted, setInitialSessionCompleted] = useState(false);
|
|
54
66
|
const [mediapipeLoading, setMediapipeLoading] = useState(false);
|
|
55
67
|
const [usingSelfieCapture, setUsingSelfieCapture] = useState(false);
|
|
56
68
|
|
|
69
|
+
// Attempt to load Mediapipe (once). If Mediapipe is already ready, loading,
|
|
70
|
+
// or running under Cypress, skip the attempt. This side-effect flips
|
|
71
|
+
// mediapipeReady/mediapipeLoading flags which control which component is used.
|
|
57
72
|
useEffect(() => {
|
|
58
73
|
if (mediapipeReady || mediapipeLoading || isCypress) return;
|
|
59
74
|
|
|
@@ -63,6 +78,8 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
|
|
|
63
78
|
await getMediapipeInstance();
|
|
64
79
|
setMediapipeReady(true);
|
|
65
80
|
} catch (error) {
|
|
81
|
+
// Loading failed; we'll fall back to the legacy selfie-capture component
|
|
82
|
+
// after the loadingProgress reaches 100%.
|
|
66
83
|
console.error('Failed to load Mediapipe:', error);
|
|
67
84
|
}
|
|
68
85
|
setMediapipeLoading(false);
|
|
@@ -71,6 +88,9 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
|
|
|
71
88
|
loadMediapipe();
|
|
72
89
|
}, [mediapipeReady, mediapipeLoading]);
|
|
73
90
|
|
|
91
|
+
// When using the loading countdown (startCountdown), increment the
|
|
92
|
+
// visible loading progress. This is only used while mediapipe hasn't
|
|
93
|
+
// reported ready; once mediapipeReady becomes true we stop the timer.
|
|
74
94
|
useEffect(() => {
|
|
75
95
|
if (hidden || !startCountdown || mediapipeReady) return undefined;
|
|
76
96
|
|
|
@@ -135,6 +155,8 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
|
|
|
135
155
|
};
|
|
136
156
|
}, [hidden, mediapipeReady, loadingProgress]);
|
|
137
157
|
|
|
158
|
+
// Announce to any `smart-camera-web` element which liveness version is active.
|
|
159
|
+
// The old capture users 0.0.1, the new one 1.0.0.
|
|
138
160
|
useEffect(() => {
|
|
139
161
|
if (hidden || mediapipeLoading) return;
|
|
140
162
|
|
|
@@ -163,6 +185,9 @@ const SelfieCaptureWrapper: FunctionComponent<Props> = ({
|
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
if (loadingProgress >= 100) {
|
|
188
|
+
// When loading completes without Mediapipe becoming ready, mount the legacy
|
|
189
|
+
// `selfie-capture` web component. We also set `usingSelfieCapture` so other
|
|
190
|
+
// effects can react (e.g. metadata dispatch).
|
|
166
191
|
if (!usingSelfieCapture) {
|
|
167
192
|
setUsingSelfieCapture(true);
|
|
168
193
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { FaceLandmarker, FilesetResolver } from '@mediapipe/tasks-vision';
|
|
2
2
|
|
|
3
|
+
// SM-S931 (for the standard S25), SM-S936 (for the S25+), and SM-S938 (for the S25 Ultra)
|
|
4
|
+
const EXCLUDED_DEVICES = ['sm-s936', 'sm-s931', 'sm-s938'];
|
|
5
|
+
|
|
3
6
|
declare global {
|
|
4
7
|
interface Window {
|
|
5
8
|
__smileIdentityMediapipe?: {
|
|
@@ -10,6 +13,42 @@ declare global {
|
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @description Detects if the user is on an excluded device using the modern and more accurate
|
|
18
|
+
* User-Agent Client Hints (UA-CH) API to get the device model.
|
|
19
|
+
* @returns {Promise<boolean>} - True if the device model is in the exclusion list.
|
|
20
|
+
*/
|
|
21
|
+
const isExcludedDeviceUsingHints = async (): Promise<boolean> => {
|
|
22
|
+
// Check for User-Agent Client Hints API support
|
|
23
|
+
if (typeof navigator !== 'undefined' && navigator.userAgentData) {
|
|
24
|
+
try {
|
|
25
|
+
// Request the 'model' high-entropy value and destructure it directly
|
|
26
|
+
const { model } = await navigator.userAgentData.getHighEntropyValues([
|
|
27
|
+
'model',
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
if (!model) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const lowerModel = model.toLowerCase();
|
|
35
|
+
|
|
36
|
+
// Check if the extracted model string matches any of the excluded prefixes
|
|
37
|
+
return EXCLUDED_DEVICES.some((prefix) => lowerModel.includes(prefix));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Log the error but fail safe (return false)
|
|
40
|
+
console.warn(
|
|
41
|
+
'UA-CH model fetch failed, falling back to UA string check.',
|
|
42
|
+
error,
|
|
43
|
+
);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// If API is not supported, return false (rely on synchronous isExcludedDevice)
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// this was added because devices (mostly older) that do not support FP16 will fail to load the model.
|
|
13
52
|
const hasFP16Support = () => {
|
|
14
53
|
const canvas = document.createElement('canvas');
|
|
15
54
|
const gl =
|
|
@@ -52,10 +91,12 @@ export const getMediapipeInstance = async (): Promise<FaceLandmarker> => {
|
|
|
52
91
|
'https://web-models.smileidentity.com/mediapipe-tasks-vision-wasm',
|
|
53
92
|
);
|
|
54
93
|
|
|
94
|
+
const isExcluded = await isExcludedDeviceUsingHints();
|
|
95
|
+
|
|
55
96
|
const faceLandmarker = await FaceLandmarker.createFromOptions(vision, {
|
|
56
97
|
baseOptions: {
|
|
57
98
|
modelAssetPath: `https://web-models.smileidentity.com/face_landmarker/face_landmarker.task`,
|
|
58
|
-
delegate: hasFP16Support() ? '
|
|
99
|
+
delegate: isExcluded || !hasFP16Support() ? 'CPU' : 'GPU',
|
|
59
100
|
},
|
|
60
101
|
outputFaceBlendshapes: true,
|
|
61
102
|
runningMode: 'VIDEO',
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smileid/signature-pad",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@smileid/signature-pad",
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "11.0.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"signature_pad": "^5.0.2"
|
|
12
12
|
},
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"eslint-config-prettier": "^9.1.0",
|
|
17
17
|
"eslint-plugin-cypress": "^3.3.0",
|
|
18
18
|
"eslint-plugin-import": "^2.29.1",
|
|
19
|
-
"eslint-plugin-jest": "^28.
|
|
19
|
+
"eslint-plugin-jest": "^28.8.3",
|
|
20
20
|
"eslint-plugin-prettier": "^5.2.1",
|
|
21
21
|
"prettier": "^3.3.3"
|
|
22
22
|
}
|
|
@@ -1099,10 +1099,11 @@
|
|
|
1099
1099
|
}
|
|
1100
1100
|
},
|
|
1101
1101
|
"node_modules/eslint-plugin-jest": {
|
|
1102
|
-
"version": "28.
|
|
1103
|
-
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.
|
|
1104
|
-
"integrity": "sha512-
|
|
1102
|
+
"version": "28.14.0",
|
|
1103
|
+
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.14.0.tgz",
|
|
1104
|
+
"integrity": "sha512-P9s/qXSMTpRTerE2FQ0qJet2gKbcGyFTPAJipoKxmWqR6uuFqIqk8FuEfg5yBieOezVrEfAMZrEwJ6yEp+1MFQ==",
|
|
1105
1105
|
"dev": true,
|
|
1106
|
+
"license": "MIT",
|
|
1106
1107
|
"dependencies": {
|
|
1107
1108
|
"@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
1108
1109
|
},
|
|
@@ -1964,10 +1965,11 @@
|
|
|
1964
1965
|
"dev": true
|
|
1965
1966
|
},
|
|
1966
1967
|
"node_modules/js-yaml": {
|
|
1967
|
-
"version": "4.1.
|
|
1968
|
-
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.
|
|
1969
|
-
"integrity": "sha512-
|
|
1968
|
+
"version": "4.1.1",
|
|
1969
|
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
|
1970
|
+
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
|
1970
1971
|
"dev": true,
|
|
1972
|
+
"license": "MIT",
|
|
1971
1973
|
"dependencies": {
|
|
1972
1974
|
"argparse": "^2.0.1"
|
|
1973
1975
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smileid/web-components",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.3",
|
|
4
4
|
"main": "dist/esm/main.js",
|
|
5
5
|
"module": "dist/esm/main.js",
|
|
6
6
|
"types": "dist/types/main.d.ts",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"prettier": "^3.6.2",
|
|
105
105
|
"rollup-plugin-visualizer": "^6.0.3",
|
|
106
106
|
"typescript": "^5.8.3",
|
|
107
|
-
"vite": "^7.
|
|
107
|
+
"vite": "^7.2.2",
|
|
108
108
|
"vite-plugin-dts": "^4.5.4",
|
|
109
109
|
"vite-plugin-tsconfig-paths": "^1.4.1"
|
|
110
110
|
}
|