@neofaceid/web-sdk 1.10.0 → 1.13.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.
|
@@ -1124,7 +1124,7 @@ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
|
|
|
1124
1124
|
class NeoFaceError extends Error {
|
|
1125
1125
|
/**
|
|
1126
1126
|
* Constrói um erro do SDK com mensagem e tipo categórico.
|
|
1127
|
-
* @param message Mensagem descritiva do erro
|
|
1127
|
+
* @param message Mensagem descritiva do erro (pode ser técnica)
|
|
1128
1128
|
* @param type Tipo categórico do erro
|
|
1129
1129
|
*/
|
|
1130
1130
|
constructor(message, type) {
|
|
@@ -1133,6 +1133,35 @@ class NeoFaceError extends Error {
|
|
|
1133
1133
|
this.name = type;
|
|
1134
1134
|
this.type = type;
|
|
1135
1135
|
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Retorna uma mensagem amigável para o usuário final, ocultando termos técnicos.
|
|
1138
|
+
*/
|
|
1139
|
+
getFriendlyMessage() {
|
|
1140
|
+
if (/[áéíóúãõç]/i.test(this.message)) {
|
|
1141
|
+
return this.message;
|
|
1142
|
+
}
|
|
1143
|
+
switch (this.type) {
|
|
1144
|
+
case "NetworkError":
|
|
1145
|
+
if (this.message.includes("timeout")) return "A conexão demorou muito. Tente novamente.";
|
|
1146
|
+
return "Não foi possível conectar ao servidor. Verifique sua internet.";
|
|
1147
|
+
case "InvalidTokenError":
|
|
1148
|
+
return "Falha na autenticação do aplicativo. Entre em contato com o suporte.";
|
|
1149
|
+
case "CameraError":
|
|
1150
|
+
case "NoCameraError":
|
|
1151
|
+
return "Não conseguimos acessar sua câmera. Verifique as permissões do navegador.";
|
|
1152
|
+
case "LoginFailedError":
|
|
1153
|
+
case "RecognitionFailedError":
|
|
1154
|
+
return "Não foi possível reconhecer seu rosto. Tente se posicionar em um local mais iluminado.";
|
|
1155
|
+
case "ValidationError":
|
|
1156
|
+
return "Dados inválidos ou rosto não detectado corretamente.";
|
|
1157
|
+
case "ApiError":
|
|
1158
|
+
if (this.message.includes("400")) return "Requisição inválida. Tente novamente.";
|
|
1159
|
+
if (this.message.includes("500")) return "Ocorreu um erro interno no sistema. Tente mais tarde.";
|
|
1160
|
+
return "O serviço encontrou um problema inesperado.";
|
|
1161
|
+
default:
|
|
1162
|
+
return "Ocorreu um erro inesperado. Por favor, tente novamente.";
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1136
1165
|
}
|
|
1137
1166
|
const __vite_import_meta_env__ = {};
|
|
1138
1167
|
const ENVIRONMENT_URLS = {
|
|
@@ -1291,15 +1320,18 @@ const validateToken = async (applicationToken) => {
|
|
|
1291
1320
|
body: JSON.stringify({}),
|
|
1292
1321
|
signal: controller.signal
|
|
1293
1322
|
});
|
|
1323
|
+
if (!response.ok) {
|
|
1324
|
+
throw new NeoFaceError(`API Error ${response.status}`, ErrorType.INVALID_TOKEN);
|
|
1325
|
+
}
|
|
1294
1326
|
return response.ok;
|
|
1295
1327
|
} catch (error) {
|
|
1296
1328
|
if (error instanceof Error) {
|
|
1297
1329
|
if (error.name === "AbortError") {
|
|
1298
|
-
throw new NeoFaceError("Request
|
|
1330
|
+
throw new NeoFaceError("Request timeout", ErrorType.NETWORK_ERROR);
|
|
1299
1331
|
}
|
|
1300
1332
|
throw new NeoFaceError(error.message, ErrorType.NETWORK_ERROR);
|
|
1301
1333
|
}
|
|
1302
|
-
throw new NeoFaceError("Unknown error
|
|
1334
|
+
throw new NeoFaceError("Unknown error", ErrorType.NETWORK_ERROR);
|
|
1303
1335
|
}
|
|
1304
1336
|
};
|
|
1305
1337
|
const getOnboardingDetails = async (applicationToken, onboardingToken) => {
|
|
@@ -1554,7 +1586,7 @@ const recognize = async (image, applicationToken) => {
|
|
|
1554
1586
|
throw new NeoFaceError("Unknown error occurred", ErrorType.NETWORK_ERROR);
|
|
1555
1587
|
}
|
|
1556
1588
|
};
|
|
1557
|
-
const loginWithBiometric
|
|
1589
|
+
const loginWithBiometric = async (image, applicationToken) => {
|
|
1558
1590
|
var _a, _b, _c, _d, _e;
|
|
1559
1591
|
ensureSecureContext();
|
|
1560
1592
|
const controller = createTimeoutController();
|
|
@@ -1578,9 +1610,12 @@ const loginWithBiometric$1 = async (image, applicationToken) => {
|
|
|
1578
1610
|
});
|
|
1579
1611
|
if (!response.ok) {
|
|
1580
1612
|
if (response.status === 401 || response.status === 403) {
|
|
1581
|
-
throw new NeoFaceError("Invalid
|
|
1613
|
+
throw new NeoFaceError("Invalid application token", ErrorType.INVALID_TOKEN);
|
|
1582
1614
|
}
|
|
1583
|
-
|
|
1615
|
+
if (response.status >= 500) {
|
|
1616
|
+
throw new NeoFaceError(`Server Error ${response.status}`, ErrorType.API_ERROR);
|
|
1617
|
+
}
|
|
1618
|
+
throw new NeoFaceError(`API Error ${response.status}`, ErrorType.API_ERROR);
|
|
1584
1619
|
}
|
|
1585
1620
|
const data = await response.json();
|
|
1586
1621
|
if (!data.success) {
|
|
@@ -2003,9 +2038,9 @@ const loginWithEmail = async (email, password, applicationToken) => {
|
|
|
2003
2038
|
});
|
|
2004
2039
|
if (!response.ok) {
|
|
2005
2040
|
if (response.status === 401 || response.status === 403) {
|
|
2006
|
-
throw new NeoFaceError("
|
|
2041
|
+
throw new NeoFaceError("Email ou senha inválidos", ErrorType.INVALID_TOKEN);
|
|
2007
2042
|
}
|
|
2008
|
-
throw new NeoFaceError(`
|
|
2043
|
+
throw new NeoFaceError(`API Error ${response.status}`, ErrorType.API_ERROR);
|
|
2009
2044
|
}
|
|
2010
2045
|
const data = await response.json();
|
|
2011
2046
|
return {
|
|
@@ -2773,12 +2808,14 @@ const modalReducer = (state, action) => {
|
|
|
2773
2808
|
};
|
|
2774
2809
|
}
|
|
2775
2810
|
return state;
|
|
2811
|
+
case "CAMERA_LOADING":
|
|
2812
|
+
return { status: "camera-loading" };
|
|
2776
2813
|
case "START_PROCESSING":
|
|
2777
2814
|
return { status: "processing" };
|
|
2778
2815
|
case "SUCCESS":
|
|
2779
2816
|
return { status: "success" };
|
|
2780
2817
|
case "ERROR":
|
|
2781
|
-
return { status: "error", message: action.message };
|
|
2818
|
+
return { status: "error", message: action.message, retryable: action.retryable ?? true };
|
|
2782
2819
|
case "RESET":
|
|
2783
2820
|
return initialState;
|
|
2784
2821
|
default:
|
|
@@ -2824,9 +2861,7 @@ function BiometricRegistrationModal({
|
|
|
2824
2861
|
onClose,
|
|
2825
2862
|
onSuccess,
|
|
2826
2863
|
onPhotosCaptured,
|
|
2827
|
-
onError
|
|
2828
|
-
useRealApi = true
|
|
2829
|
-
// Sempre usa API real em produção
|
|
2864
|
+
onError
|
|
2830
2865
|
}) {
|
|
2831
2866
|
const videoRef = useRef(null);
|
|
2832
2867
|
const canvasRef = useRef(null);
|
|
@@ -2835,10 +2870,12 @@ function BiometricRegistrationModal({
|
|
|
2835
2870
|
const progressIntervalRef = useRef(null);
|
|
2836
2871
|
const isCapturingRef = useRef(false);
|
|
2837
2872
|
const currentStepRef = useRef("center");
|
|
2873
|
+
const watchdogTimerRef = useRef(null);
|
|
2874
|
+
const detectionStartedRef = useRef(false);
|
|
2838
2875
|
const captureStateRef = useRef(null);
|
|
2839
2876
|
const [state, dispatch] = useReducer(modalReducer, initialState);
|
|
2840
2877
|
const [faceDetected, setFaceDetected] = useState(false);
|
|
2841
|
-
const [
|
|
2878
|
+
const [_faceDistance, setFaceDistance] = useState("ok");
|
|
2842
2879
|
useEffect(() => {
|
|
2843
2880
|
if (state.status === "liveness") {
|
|
2844
2881
|
const newStep = state.step;
|
|
@@ -2954,20 +2991,66 @@ function BiometricRegistrationModal({
|
|
|
2954
2991
|
const loadModels = async () => {
|
|
2955
2992
|
try {
|
|
2956
2993
|
const MODEL_URL = "https://cdn.jsdelivr.net/npm/@vladmandic/face-api/model";
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2994
|
+
const timeout = new Promise(
|
|
2995
|
+
(_, reject) => setTimeout(() => reject(new Error("Timeout ao carregar modelos")), 1e4)
|
|
2996
|
+
);
|
|
2997
|
+
await Promise.race([
|
|
2998
|
+
Promise.all([
|
|
2999
|
+
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),
|
|
3000
|
+
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL)
|
|
3001
|
+
]),
|
|
3002
|
+
timeout
|
|
2960
3003
|
]);
|
|
2961
3004
|
} catch (error) {
|
|
2962
|
-
dispatch({
|
|
3005
|
+
dispatch({
|
|
3006
|
+
type: "ERROR",
|
|
3007
|
+
message: "Não foi possível carregar os modelos de IA. Verifique sua conexão e tente novamente.",
|
|
3008
|
+
retryable: true
|
|
3009
|
+
});
|
|
2963
3010
|
}
|
|
2964
3011
|
};
|
|
2965
3012
|
loadModels();
|
|
2966
3013
|
}, []);
|
|
3014
|
+
useEffect(() => {
|
|
3015
|
+
return () => {
|
|
3016
|
+
if (streamRef.current) {
|
|
3017
|
+
streamRef.current.getTracks().forEach((track) => {
|
|
3018
|
+
track.stop();
|
|
3019
|
+
});
|
|
3020
|
+
streamRef.current = null;
|
|
3021
|
+
}
|
|
3022
|
+
if (videoRef.current) {
|
|
3023
|
+
videoRef.current.srcObject = null;
|
|
3024
|
+
}
|
|
3025
|
+
if (watchdogTimerRef.current) {
|
|
3026
|
+
clearTimeout(watchdogTimerRef.current);
|
|
3027
|
+
watchdogTimerRef.current = null;
|
|
3028
|
+
}
|
|
3029
|
+
if (progressIntervalRef.current) {
|
|
3030
|
+
clearInterval(progressIntervalRef.current);
|
|
3031
|
+
progressIntervalRef.current = null;
|
|
3032
|
+
}
|
|
3033
|
+
};
|
|
3034
|
+
}, []);
|
|
2967
3035
|
useEffect(() => {
|
|
2968
3036
|
let mounted = true;
|
|
2969
3037
|
const initCamera = async () => {
|
|
2970
3038
|
if (state.status !== "liveness" || streamRef.current) return;
|
|
3039
|
+
detectionStartedRef.current = false;
|
|
3040
|
+
if (watchdogTimerRef.current) {
|
|
3041
|
+
clearTimeout(watchdogTimerRef.current);
|
|
3042
|
+
watchdogTimerRef.current = null;
|
|
3043
|
+
}
|
|
3044
|
+
watchdogTimerRef.current = window.setTimeout(() => {
|
|
3045
|
+
if (!mounted) return;
|
|
3046
|
+
if (detectionStartedRef.current === false) {
|
|
3047
|
+
dispatch({
|
|
3048
|
+
type: "ERROR",
|
|
3049
|
+
message: "A câmera não respondeu a tempo. Verifique se ela está disponível e tente novamente.",
|
|
3050
|
+
retryable: true
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
}, 2e4);
|
|
2971
3054
|
try {
|
|
2972
3055
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
2973
3056
|
video: {
|
|
@@ -2997,13 +3080,30 @@ function BiometricRegistrationModal({
|
|
|
2997
3080
|
await video.play();
|
|
2998
3081
|
} catch (error) {
|
|
2999
3082
|
if (!mounted) return;
|
|
3000
|
-
|
|
3001
|
-
|
|
3083
|
+
if (watchdogTimerRef.current) {
|
|
3084
|
+
clearTimeout(watchdogTimerRef.current);
|
|
3085
|
+
watchdogTimerRef.current = null;
|
|
3086
|
+
}
|
|
3087
|
+
let errorMessage = error instanceof Error ? error.message : "Erro ao acessar câmera";
|
|
3088
|
+
if (error instanceof DOMException) {
|
|
3089
|
+
if (error.name === "NotAllowedError" || error.name === "PermissionDeniedError") {
|
|
3090
|
+
errorMessage = "Permissão de câmera negada. Permita o acesso à câmera nas configurações do navegador e tente novamente.";
|
|
3091
|
+
} else if (error.name === "NotFoundError" || error.name === "DevicesNotFoundError") {
|
|
3092
|
+
errorMessage = "Nenhuma câmera encontrada. Conecte uma câmera e tente novamente.";
|
|
3093
|
+
} else if (error.name === "NotReadableError") {
|
|
3094
|
+
errorMessage = "A câmera está sendo usada por outro programa. Feche-o e tente novamente.";
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
dispatch({ type: "ERROR", message: errorMessage, retryable: true });
|
|
3002
3098
|
}
|
|
3003
3099
|
};
|
|
3004
3100
|
initCamera();
|
|
3005
3101
|
return () => {
|
|
3006
3102
|
mounted = false;
|
|
3103
|
+
if (watchdogTimerRef.current) {
|
|
3104
|
+
clearTimeout(watchdogTimerRef.current);
|
|
3105
|
+
watchdogTimerRef.current = null;
|
|
3106
|
+
}
|
|
3007
3107
|
if (streamRef.current) {
|
|
3008
3108
|
streamRef.current.getTracks().forEach((track) => track.stop());
|
|
3009
3109
|
streamRef.current = null;
|
|
@@ -3083,21 +3183,59 @@ function BiometricRegistrationModal({
|
|
|
3083
3183
|
requestAnimationFrame(detectFace2);
|
|
3084
3184
|
}
|
|
3085
3185
|
};
|
|
3086
|
-
const
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
clearTimeout(startTimer);
|
|
3095
|
-
if (progressIntervalRef.current) {
|
|
3096
|
-
clearInterval(progressIntervalRef.current);
|
|
3097
|
-
progressIntervalRef.current = null;
|
|
3098
|
-
}
|
|
3099
|
-
holdStartTimeRef.current = null;
|
|
3186
|
+
const startDetection = () => {
|
|
3187
|
+
if (!isRunning || !videoRef.current) return;
|
|
3188
|
+
detectionStartedRef.current = true;
|
|
3189
|
+
if (watchdogTimerRef.current) {
|
|
3190
|
+
clearTimeout(watchdogTimerRef.current);
|
|
3191
|
+
watchdogTimerRef.current = null;
|
|
3192
|
+
}
|
|
3193
|
+
detectFace2();
|
|
3100
3194
|
};
|
|
3195
|
+
const video = videoRef.current;
|
|
3196
|
+
if (video && video.readyState >= 2) {
|
|
3197
|
+
const startTimer = setTimeout(startDetection, 200);
|
|
3198
|
+
return () => {
|
|
3199
|
+
isRunning = false;
|
|
3200
|
+
clearTimeout(startTimer);
|
|
3201
|
+
if (progressIntervalRef.current) {
|
|
3202
|
+
clearInterval(progressIntervalRef.current);
|
|
3203
|
+
progressIntervalRef.current = null;
|
|
3204
|
+
}
|
|
3205
|
+
holdStartTimeRef.current = null;
|
|
3206
|
+
};
|
|
3207
|
+
} else {
|
|
3208
|
+
const onCanPlay = () => {
|
|
3209
|
+
if (isRunning) startDetection();
|
|
3210
|
+
};
|
|
3211
|
+
let pollCount = 0;
|
|
3212
|
+
const MAX_POLLS = 50;
|
|
3213
|
+
const pollTimer = window.setInterval(() => {
|
|
3214
|
+
pollCount++;
|
|
3215
|
+
if (!isRunning) {
|
|
3216
|
+
clearInterval(pollTimer);
|
|
3217
|
+
return;
|
|
3218
|
+
}
|
|
3219
|
+
if (videoRef.current && videoRef.current.readyState >= 2) {
|
|
3220
|
+
clearInterval(pollTimer);
|
|
3221
|
+
videoRef.current.removeEventListener("canplay", onCanPlay);
|
|
3222
|
+
startDetection();
|
|
3223
|
+
} else if (pollCount >= MAX_POLLS) {
|
|
3224
|
+
clearInterval(pollTimer);
|
|
3225
|
+
}
|
|
3226
|
+
}, 300);
|
|
3227
|
+
video == null ? void 0 : video.addEventListener("canplay", onCanPlay, { once: true });
|
|
3228
|
+
return () => {
|
|
3229
|
+
isRunning = false;
|
|
3230
|
+
clearInterval(pollTimer);
|
|
3231
|
+
video == null ? void 0 : video.removeEventListener("canplay", onCanPlay);
|
|
3232
|
+
if (progressIntervalRef.current) {
|
|
3233
|
+
clearInterval(progressIntervalRef.current);
|
|
3234
|
+
progressIntervalRef.current = null;
|
|
3235
|
+
}
|
|
3236
|
+
holdStartTimeRef.current = null;
|
|
3237
|
+
};
|
|
3238
|
+
}
|
|
3101
3239
|
}, [state.status]);
|
|
3102
3240
|
const capturePhoto = async () => {
|
|
3103
3241
|
if (!videoRef.current || !canvasRef.current || isCapturingRef.current) {
|
|
@@ -3252,14 +3390,37 @@ function BiometricRegistrationModal({
|
|
|
3252
3390
|
}
|
|
3253
3391
|
)
|
|
3254
3392
|
] }) }),
|
|
3255
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Não foi possível
|
|
3393
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Não foi possível processar" }),
|
|
3256
3394
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: state.message }),
|
|
3257
3395
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "button-group", children: [
|
|
3258
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "secondary-button", onClick: () => dispatch({ type: "RESET" }), children: "Tentar Novamente" }),
|
|
3396
|
+
state.retryable && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "secondary-button", onClick: () => dispatch({ type: "RESET" }), children: "Tentar Novamente" }),
|
|
3259
3397
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ghost-button", onClick: onClose, children: "Cancelar" })
|
|
3260
3398
|
] })
|
|
3261
3399
|
] });
|
|
3262
3400
|
};
|
|
3401
|
+
const renderCameraLoading = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "processing-container", children: [
|
|
3402
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "spinner-wrapper", children: [
|
|
3403
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "spinner" }),
|
|
3404
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "spinner-ring" })
|
|
3405
|
+
] }),
|
|
3406
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Inicializando câmera" }),
|
|
3407
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Aguarde enquanto preparamos a câmera..." }),
|
|
3408
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
3409
|
+
"div",
|
|
3410
|
+
{
|
|
3411
|
+
className: "branding",
|
|
3412
|
+
style: {
|
|
3413
|
+
marginTop: "40px",
|
|
3414
|
+
paddingTop: "24px",
|
|
3415
|
+
borderTop: "1px solid rgba(255, 255, 255, 0.1)"
|
|
3416
|
+
},
|
|
3417
|
+
children: [
|
|
3418
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "NeoFaceId by" }),
|
|
3419
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "brand-name", children: "OCTA" })
|
|
3420
|
+
]
|
|
3421
|
+
}
|
|
3422
|
+
)
|
|
3423
|
+
] });
|
|
3263
3424
|
const renderSuccess = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "result-container success", children: [
|
|
3264
3425
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "result-icon success-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "60", height: "60", viewBox: "0 0 60 60", fill: "none", children: [
|
|
3265
3426
|
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "30", cy: "30", r: "28", stroke: "currentColor", strokeWidth: "3" }),
|
|
@@ -3841,6 +4002,7 @@ function BiometricRegistrationModal({
|
|
|
3841
4002
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "modal-overlay", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "modal-content", children: [
|
|
3842
4003
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "close-button", onClick: onClose, children: "×" }),
|
|
3843
4004
|
state.status === "liveness" && renderLivenessDetection(),
|
|
4005
|
+
state.status === "camera-loading" && renderCameraLoading(),
|
|
3844
4006
|
state.status === "processing" && renderProcessing(),
|
|
3845
4007
|
state.status === "error" && renderError(),
|
|
3846
4008
|
state.status === "success" && renderSuccess()
|
|
@@ -3848,7 +4010,7 @@ function BiometricRegistrationModal({
|
|
|
3848
4010
|
/* @__PURE__ */ jsxRuntimeExports.jsx("canvas", { ref: canvasRef })
|
|
3849
4011
|
] });
|
|
3850
4012
|
}
|
|
3851
|
-
|
|
4013
|
+
class BiometricCaptureModal {
|
|
3852
4014
|
constructor(options) {
|
|
3853
4015
|
__publicField(this, "modal", null);
|
|
3854
4016
|
__publicField(this, "video", null);
|
|
@@ -4342,7 +4504,7 @@ let BiometricCaptureModal$1 = class BiometricCaptureModal2 {
|
|
|
4342
4504
|
`;
|
|
4343
4505
|
document.head.appendChild(style);
|
|
4344
4506
|
}
|
|
4345
|
-
}
|
|
4507
|
+
}
|
|
4346
4508
|
class BiometricStatusOverlay {
|
|
4347
4509
|
constructor() {
|
|
4348
4510
|
__publicField(this, "container", null);
|
|
@@ -4366,43 +4528,21 @@ class BiometricStatusOverlay {
|
|
|
4366
4528
|
opacity: 1;
|
|
4367
4529
|
}
|
|
4368
4530
|
50% {
|
|
4369
|
-
transform: scale(1.
|
|
4531
|
+
transform: scale(1.05);
|
|
4370
4532
|
opacity: 0.9;
|
|
4371
4533
|
}
|
|
4372
4534
|
}
|
|
4373
4535
|
|
|
4374
|
-
@keyframes neofaceid-
|
|
4375
|
-
0% {
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
}
|
|
4379
|
-
50% {
|
|
4380
|
-
opacity: 1;
|
|
4381
|
-
}
|
|
4382
|
-
100% {
|
|
4383
|
-
stroke-dashoffset: 0;
|
|
4384
|
-
opacity: 1;
|
|
4385
|
-
}
|
|
4536
|
+
@keyframes neofaceid-scaleIn {
|
|
4537
|
+
0% { transform: scale(0); opacity: 0; }
|
|
4538
|
+
50% { transform: scale(1.1); }
|
|
4539
|
+
100% { transform: scale(1); opacity: 1; }
|
|
4386
4540
|
}
|
|
4387
4541
|
|
|
4388
4542
|
@keyframes neofaceid-errorShake {
|
|
4389
|
-
0%, 100% { transform: translateX(0)
|
|
4390
|
-
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px)
|
|
4391
|
-
20%, 40%, 60%, 80% { transform: translateX(4px)
|
|
4392
|
-
}
|
|
4393
|
-
|
|
4394
|
-
@keyframes neofaceid-scaleIn {
|
|
4395
|
-
0% {
|
|
4396
|
-
transform: scale(0);
|
|
4397
|
-
opacity: 0;
|
|
4398
|
-
}
|
|
4399
|
-
50% {
|
|
4400
|
-
transform: scale(1.1);
|
|
4401
|
-
}
|
|
4402
|
-
100% {
|
|
4403
|
-
transform: scale(1);
|
|
4404
|
-
opacity: 1;
|
|
4405
|
-
}
|
|
4543
|
+
0%, 100% { transform: translateX(0); }
|
|
4544
|
+
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
|
|
4545
|
+
20%, 40%, 60%, 80% { transform: translateX(4px); }
|
|
4406
4546
|
}
|
|
4407
4547
|
|
|
4408
4548
|
.neofaceid-overlay-container {
|
|
@@ -4417,6 +4557,7 @@ class BiometricStatusOverlay {
|
|
|
4417
4557
|
z-index: 10000;
|
|
4418
4558
|
pointer-events: none;
|
|
4419
4559
|
animation: neofaceid-fadeIn 0.3s ease-out;
|
|
4560
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
4420
4561
|
}
|
|
4421
4562
|
|
|
4422
4563
|
.neofaceid-overlay-container.fade-out {
|
|
@@ -4432,10 +4573,10 @@ class BiometricStatusOverlay {
|
|
|
4432
4573
|
pointer-events: auto;
|
|
4433
4574
|
}
|
|
4434
4575
|
|
|
4435
|
-
.neofaceid-
|
|
4576
|
+
.neofaceid-visual-wrapper {
|
|
4436
4577
|
position: relative;
|
|
4437
|
-
width:
|
|
4438
|
-
height:
|
|
4578
|
+
width: 100px;
|
|
4579
|
+
height: 100px;
|
|
4439
4580
|
display: flex;
|
|
4440
4581
|
align-items: center;
|
|
4441
4582
|
justify-content: center;
|
|
@@ -4445,13 +4586,57 @@ class BiometricStatusOverlay {
|
|
|
4445
4586
|
width: 80px;
|
|
4446
4587
|
height: 80px;
|
|
4447
4588
|
object-fit: contain;
|
|
4589
|
+
transition: all 0.5s ease;
|
|
4448
4590
|
filter: drop-shadow(0 4px 12px rgba(124, 58, 237, 0.3));
|
|
4449
4591
|
}
|
|
4450
4592
|
|
|
4593
|
+
/* Cores por estado */
|
|
4594
|
+
.neofaceid-state-preparing .neofaceid-logo { filter: drop-shadow(0 0 15px rgba(124, 58, 237, 0.4)); }
|
|
4595
|
+
.neofaceid-state-detecting .neofaceid-logo { filter: hue-rotate(180deg) drop-shadow(0 0 15px rgba(59, 130, 246, 0.6)); }
|
|
4596
|
+
.neofaceid-state-capturing .neofaceid-logo { filter: hue-rotate(45deg) drop-shadow(0 0 15px rgba(245, 158, 11, 0.6)); }
|
|
4597
|
+
.neofaceid-state-verifying .neofaceid-logo { filter: hue-rotate(90deg) drop-shadow(0 0 15px rgba(34, 197, 94, 0.6)); }
|
|
4598
|
+
|
|
4451
4599
|
.neofaceid-logo.pulsing {
|
|
4452
4600
|
animation: neofaceid-pulse 2s ease-in-out infinite;
|
|
4453
4601
|
}
|
|
4454
4602
|
|
|
4603
|
+
@keyframes neofaceid-dots {
|
|
4604
|
+
0%, 20% { opacity: 0; transform: translateY(0); }
|
|
4605
|
+
50% { opacity: 1; transform: translateY(-2px); }
|
|
4606
|
+
80%, 100% { opacity: 0; transform: translateY(0); }
|
|
4607
|
+
}
|
|
4608
|
+
|
|
4609
|
+
.neofaceid-status-text {
|
|
4610
|
+
font-size: 15px;
|
|
4611
|
+
font-weight: 500;
|
|
4612
|
+
color: #ffffff;
|
|
4613
|
+
text-align: center;
|
|
4614
|
+
padding: 10px 24px;
|
|
4615
|
+
background: rgba(15, 23, 42, 0.8);
|
|
4616
|
+
backdrop-filter: blur(8px);
|
|
4617
|
+
border-radius: 100px;
|
|
4618
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
|
4619
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
4620
|
+
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
4621
|
+
animation: neofaceid-fadeIn 0.3s ease-out;
|
|
4622
|
+
display: flex;
|
|
4623
|
+
align-items: center;
|
|
4624
|
+
gap: 2px;
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
.neofaceid-dots {
|
|
4628
|
+
display: inline-flex;
|
|
4629
|
+
margin-left: 2px;
|
|
4630
|
+
}
|
|
4631
|
+
|
|
4632
|
+
.neofaceid-dot {
|
|
4633
|
+
animation: neofaceid-dots 1.5s infinite;
|
|
4634
|
+
opacity: 0;
|
|
4635
|
+
}
|
|
4636
|
+
|
|
4637
|
+
.neofaceid-dot:nth-child(2) { animation-delay: 0.2s; }
|
|
4638
|
+
.neofaceid-dot:nth-child(3) { animation-delay: 0.4s; }
|
|
4639
|
+
|
|
4455
4640
|
.neofaceid-status-icon {
|
|
4456
4641
|
position: absolute;
|
|
4457
4642
|
inset: 0;
|
|
@@ -4461,42 +4646,50 @@ class BiometricStatusOverlay {
|
|
|
4461
4646
|
}
|
|
4462
4647
|
|
|
4463
4648
|
.neofaceid-success-icon {
|
|
4464
|
-
width:
|
|
4465
|
-
height:
|
|
4649
|
+
width: 80px;
|
|
4650
|
+
height: 80px;
|
|
4466
4651
|
color: #10b981;
|
|
4467
|
-
animation: neofaceid-scaleIn 0.
|
|
4652
|
+
animation: neofaceid-scaleIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
4468
4653
|
}
|
|
4469
4654
|
|
|
4470
4655
|
.neofaceid-error-icon {
|
|
4471
|
-
width:
|
|
4472
|
-
height:
|
|
4656
|
+
width: 80px;
|
|
4657
|
+
height: 80px;
|
|
4473
4658
|
color: #ef4444;
|
|
4474
|
-
animation: neofaceid-errorShake 0.5s
|
|
4475
|
-
}
|
|
4476
|
-
|
|
4477
|
-
@media (max-width: 640px) {
|
|
4478
|
-
.neofaceid-logo-wrapper {
|
|
4479
|
-
width: 100px;
|
|
4480
|
-
height: 100px;
|
|
4481
|
-
}
|
|
4482
|
-
|
|
4483
|
-
.neofaceid-logo {
|
|
4484
|
-
width: 70px;
|
|
4485
|
-
height: 70px;
|
|
4486
|
-
}
|
|
4659
|
+
animation: neofaceid-errorShake 0.5s linear, neofaceid-scaleIn 0.4s ease-out;
|
|
4487
4660
|
}
|
|
4488
4661
|
`;
|
|
4489
4662
|
}
|
|
4663
|
+
getStatusText() {
|
|
4664
|
+
switch (this.currentStatus) {
|
|
4665
|
+
case "preparing":
|
|
4666
|
+
return "Iniciando câmera";
|
|
4667
|
+
case "detecting":
|
|
4668
|
+
return "Posicione seu rosto";
|
|
4669
|
+
case "capturing":
|
|
4670
|
+
return "Capturando";
|
|
4671
|
+
case "verifying":
|
|
4672
|
+
return "Verificando identidade";
|
|
4673
|
+
case "success":
|
|
4674
|
+
return "Identificado!";
|
|
4675
|
+
case "error":
|
|
4676
|
+
return "Falha na identificação";
|
|
4677
|
+
default:
|
|
4678
|
+
return "";
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4490
4681
|
renderContent() {
|
|
4491
|
-
const isPulsing =
|
|
4492
|
-
const showLogo =
|
|
4682
|
+
const isPulsing = ["detecting", "verifying"].includes(this.currentStatus);
|
|
4683
|
+
const showLogo = !["success", "error"].includes(this.currentStatus);
|
|
4493
4684
|
const showSuccess = this.currentStatus === "success";
|
|
4494
4685
|
const showError = this.currentStatus === "error";
|
|
4686
|
+
const statusText = this.getStatusText();
|
|
4687
|
+
const showDots = ["preparing", "detecting", "capturing", "verifying"].includes(this.currentStatus);
|
|
4495
4688
|
return `
|
|
4496
4689
|
<style>${this.getStyles()}</style>
|
|
4497
|
-
<div class="neofaceid-overlay-container">
|
|
4690
|
+
<div class="neofaceid-overlay-container neofaceid-state-${this.currentStatus}">
|
|
4498
4691
|
<div class="neofaceid-overlay-content">
|
|
4499
|
-
<div class="neofaceid-
|
|
4692
|
+
<div class="neofaceid-visual-wrapper">
|
|
4500
4693
|
${showLogo ? `
|
|
4501
4694
|
<img
|
|
4502
4695
|
src="/logo-icone-no-background.png"
|
|
@@ -4524,13 +4717,22 @@ class BiometricStatusOverlay {
|
|
|
4524
4717
|
</div>
|
|
4525
4718
|
` : ""}
|
|
4526
4719
|
</div>
|
|
4720
|
+
|
|
4721
|
+
${statusText ? `
|
|
4722
|
+
<div class="neofaceid-status-text">
|
|
4723
|
+
${statusText}${showDots ? `
|
|
4724
|
+
<span class="neofaceid-dots">
|
|
4725
|
+
<span class="neofaceid-dot">.</span>
|
|
4726
|
+
<span class="neofaceid-dot">.</span>
|
|
4727
|
+
<span class="neofaceid-dot">.</span>
|
|
4728
|
+
</span>
|
|
4729
|
+
` : ""}
|
|
4730
|
+
</div>
|
|
4731
|
+
` : ""}
|
|
4527
4732
|
</div>
|
|
4528
4733
|
</div>
|
|
4529
4734
|
`;
|
|
4530
4735
|
}
|
|
4531
|
-
/**
|
|
4532
|
-
* Cria e exibe o overlay
|
|
4533
|
-
*/
|
|
4534
4736
|
show(status = "preparing") {
|
|
4535
4737
|
if (this.container) {
|
|
4536
4738
|
this.updateStatus(status);
|
|
@@ -4542,18 +4744,12 @@ class BiometricStatusOverlay {
|
|
|
4542
4744
|
this.container.innerHTML = this.renderContent();
|
|
4543
4745
|
document.body.appendChild(this.container);
|
|
4544
4746
|
}
|
|
4545
|
-
/**
|
|
4546
|
-
* Atualiza o status do overlay
|
|
4547
|
-
*/
|
|
4548
4747
|
updateStatus(status) {
|
|
4549
4748
|
this.currentStatus = status;
|
|
4550
4749
|
if (this.container) {
|
|
4551
4750
|
this.container.innerHTML = this.renderContent();
|
|
4552
4751
|
}
|
|
4553
4752
|
}
|
|
4554
|
-
/**
|
|
4555
|
-
* Fecha e remove o overlay
|
|
4556
|
-
*/
|
|
4557
4753
|
close() {
|
|
4558
4754
|
if (this.container) {
|
|
4559
4755
|
const overlayElement = this.container.querySelector(".neofaceid-overlay-container");
|
|
@@ -4732,7 +4928,7 @@ function FallbackPromptComponent({
|
|
|
4732
4928
|
)
|
|
4733
4929
|
] }) }),
|
|
4734
4930
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "neofaceid-fallback-title", children: "Não foi possível reconhecer" }),
|
|
4735
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "neofaceid-fallback-message", children: (error == null ? void 0 : error.
|
|
4931
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "neofaceid-fallback-message", children: (error == null ? void 0 : error.getFriendlyMessage()) || "Não conseguimos reconhecer sua face. Tente novamente ou use email e senha." }),
|
|
4736
4932
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "neofaceid-fallback-actions", children: [
|
|
4737
4933
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4738
4934
|
"button",
|
|
@@ -5272,8 +5468,12 @@ async function detectFaceQuickly(video, maxTime = FACE_DETECTION_TIME, interval
|
|
|
5272
5468
|
checkFace();
|
|
5273
5469
|
});
|
|
5274
5470
|
}
|
|
5275
|
-
async function attemptLogin(applicationToken, overlay, fastMode = false) {
|
|
5276
|
-
|
|
5471
|
+
async function attemptLogin(applicationToken, overlay, fastMode = false, isRetry = false) {
|
|
5472
|
+
if (!isRetry) {
|
|
5473
|
+
overlay.updateStatus("preparing");
|
|
5474
|
+
} else {
|
|
5475
|
+
overlay.updateStatus("detecting");
|
|
5476
|
+
}
|
|
5277
5477
|
const video = document.createElement("video");
|
|
5278
5478
|
video.style.position = "fixed";
|
|
5279
5479
|
video.style.top = "-9999px";
|
|
@@ -5304,6 +5504,7 @@ async function attemptLogin(applicationToken, overlay, fastMode = false) {
|
|
|
5304
5504
|
video.onloadedmetadata = () => resolve(void 0);
|
|
5305
5505
|
}
|
|
5306
5506
|
});
|
|
5507
|
+
overlay.updateStatus("detecting");
|
|
5307
5508
|
await new Promise((resolve) => setTimeout(resolve, CAMERA_STABILITY_DELAY));
|
|
5308
5509
|
let faceDetected = true;
|
|
5309
5510
|
if (!fastMode) {
|
|
@@ -5318,6 +5519,7 @@ async function attemptLogin(applicationToken, overlay, fastMode = false) {
|
|
|
5318
5519
|
}
|
|
5319
5520
|
throw new NeoFaceError("Rosto não detectado. Posicione seu rosto na frente da câmera.", ErrorType.VALIDATION_ERROR);
|
|
5320
5521
|
}
|
|
5522
|
+
overlay.updateStatus("capturing");
|
|
5321
5523
|
const canvas = document.createElement("canvas");
|
|
5322
5524
|
canvas.width = video.videoWidth;
|
|
5323
5525
|
canvas.height = video.videoHeight;
|
|
@@ -5352,7 +5554,8 @@ async function attemptLogin(applicationToken, overlay, fastMode = false) {
|
|
|
5352
5554
|
0.85
|
|
5353
5555
|
);
|
|
5354
5556
|
});
|
|
5355
|
-
|
|
5557
|
+
overlay.updateStatus("verifying");
|
|
5558
|
+
const result = await loginWithBiometric(imageBlob, applicationToken);
|
|
5356
5559
|
if (!result.success) {
|
|
5357
5560
|
throw new NeoFaceError("Login falhou", ErrorType.LOGIN_FAILED);
|
|
5358
5561
|
}
|
|
@@ -5387,7 +5590,7 @@ async function executeBiometricLoginFlow(options) {
|
|
|
5387
5590
|
const tryLogin = async () => {
|
|
5388
5591
|
try {
|
|
5389
5592
|
attempts++;
|
|
5390
|
-
const result = await attemptLogin(applicationToken, overlay, fastMode);
|
|
5593
|
+
const result = await attemptLogin(applicationToken, overlay, fastMode, attempts > 1);
|
|
5391
5594
|
overlay.updateStatus("success");
|
|
5392
5595
|
setTimeout(() => {
|
|
5393
5596
|
overlay.close();
|
|
@@ -5768,8 +5971,8 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
5768
5971
|
initializeBiometricDetection,
|
|
5769
5972
|
isAdvancedDetectionAvailable
|
|
5770
5973
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
5771
|
-
const VERSION = "1.
|
|
5772
|
-
const RELEASE_DATE = "2026-
|
|
5974
|
+
const VERSION = "1.13.0";
|
|
5975
|
+
const RELEASE_DATE = "2026-02-20";
|
|
5773
5976
|
class OnboardingCaptureModal {
|
|
5774
5977
|
constructor(options) {
|
|
5775
5978
|
__publicField(this, "overlay", null);
|
|
@@ -5995,11 +6198,9 @@ class NeoFaceID {
|
|
|
5995
6198
|
*/
|
|
5996
6199
|
constructor(config) {
|
|
5997
6200
|
__publicField(this, "appToken");
|
|
5998
|
-
__publicField(this, "baseUrl");
|
|
5999
6201
|
__publicField(this, "signature");
|
|
6000
6202
|
__publicField(this, "sessionData");
|
|
6001
6203
|
this.appToken = config.appToken;
|
|
6002
|
-
this.baseUrl = config.baseUrl || getBaseUrl();
|
|
6003
6204
|
this.signature = config.signature;
|
|
6004
6205
|
this.sessionData = config.sessionData;
|
|
6005
6206
|
if (this.signature && !this.validateSignatureFormat(this.signature)) {
|
|
@@ -6088,7 +6289,7 @@ class NeoFaceID {
|
|
|
6088
6289
|
* ```
|
|
6089
6290
|
*/
|
|
6090
6291
|
async loginRecognition(options) {
|
|
6091
|
-
const { biometricData,
|
|
6292
|
+
const { biometricData, purpose, confidenceThreshold = 0.8 } = options;
|
|
6092
6293
|
const imageBlobs = Array.isArray(biometricData) ? biometricData : [biometricData];
|
|
6093
6294
|
if (imageBlobs.length === 0) {
|
|
6094
6295
|
throw new NeoFaceError(
|
|
@@ -7431,7 +7632,12 @@ function startBiometricRegistration(personData, applicationToken, callbacks, opt
|
|
|
7431
7632
|
const container = document.createElement("div");
|
|
7432
7633
|
container.id = "neoface-biometric-registration-container";
|
|
7433
7634
|
document.body.appendChild(container);
|
|
7635
|
+
let rootRef = null;
|
|
7434
7636
|
const cleanup = () => {
|
|
7637
|
+
if (rootRef) {
|
|
7638
|
+
rootRef.unmount();
|
|
7639
|
+
rootRef = null;
|
|
7640
|
+
}
|
|
7435
7641
|
if (document.body.contains(container)) {
|
|
7436
7642
|
document.body.removeChild(container);
|
|
7437
7643
|
}
|
|
@@ -7441,7 +7647,6 @@ function startBiometricRegistration(personData, applicationToken, callbacks, opt
|
|
|
7441
7647
|
personData,
|
|
7442
7648
|
applicationToken,
|
|
7443
7649
|
useRealApi: (options == null ? void 0 : options.useRealApi) ?? true,
|
|
7444
|
-
// Sempre usa API real em produção
|
|
7445
7650
|
onClose: cleanup,
|
|
7446
7651
|
onSuccess: (result) => {
|
|
7447
7652
|
cleanup();
|
|
@@ -7452,8 +7657,8 @@ function startBiometricRegistration(personData, applicationToken, callbacks, opt
|
|
|
7452
7657
|
callbacks.onError("BIOMETRIC_REGISTRATION_ERROR", error);
|
|
7453
7658
|
}
|
|
7454
7659
|
});
|
|
7455
|
-
|
|
7456
|
-
|
|
7660
|
+
rootRef = clientExports.createRoot(container);
|
|
7661
|
+
rootRef.render(modalElement);
|
|
7457
7662
|
}).catch((error) => {
|
|
7458
7663
|
cleanup();
|
|
7459
7664
|
callbacks.onError("TOKEN_VALIDATION_ERROR", error.message || "Failed to validate token");
|
|
@@ -7463,16 +7668,29 @@ function startLivenessCapture(applicationToken, callbacks) {
|
|
|
7463
7668
|
const container = document.createElement("div");
|
|
7464
7669
|
container.id = "neoface-liveness-capture-container";
|
|
7465
7670
|
document.body.appendChild(container);
|
|
7671
|
+
let completed = false;
|
|
7672
|
+
let rootRef = null;
|
|
7466
7673
|
const cleanup = () => {
|
|
7674
|
+
if (rootRef) {
|
|
7675
|
+
rootRef.unmount();
|
|
7676
|
+
rootRef = null;
|
|
7677
|
+
}
|
|
7467
7678
|
if (document.body.contains(container)) {
|
|
7468
7679
|
document.body.removeChild(container);
|
|
7469
7680
|
}
|
|
7470
7681
|
};
|
|
7682
|
+
const handleClose = () => {
|
|
7683
|
+
cleanup();
|
|
7684
|
+
if (!completed && callbacks.onCancel) {
|
|
7685
|
+
callbacks.onCancel();
|
|
7686
|
+
}
|
|
7687
|
+
};
|
|
7471
7688
|
validateToken(applicationToken).then(() => {
|
|
7472
7689
|
const modalElement = React.createElement(BiometricRegistrationModal, {
|
|
7473
7690
|
applicationToken,
|
|
7474
|
-
onClose:
|
|
7691
|
+
onClose: handleClose,
|
|
7475
7692
|
onPhotosCaptured: (photos) => {
|
|
7693
|
+
completed = true;
|
|
7476
7694
|
callbacks.onSuccess(photos);
|
|
7477
7695
|
},
|
|
7478
7696
|
onError: (error) => {
|
|
@@ -7480,15 +7698,15 @@ function startLivenessCapture(applicationToken, callbacks) {
|
|
|
7480
7698
|
callbacks.onError("LIVENESS_CAPTURE_ERROR", error);
|
|
7481
7699
|
}
|
|
7482
7700
|
});
|
|
7483
|
-
|
|
7484
|
-
|
|
7701
|
+
rootRef = clientExports.createRoot(container);
|
|
7702
|
+
rootRef.render(modalElement);
|
|
7485
7703
|
}).catch((error) => {
|
|
7486
7704
|
cleanup();
|
|
7487
7705
|
callbacks.onError("TOKEN_VALIDATION_ERROR", error.message || "Failed to validate token");
|
|
7488
7706
|
});
|
|
7489
7707
|
}
|
|
7490
7708
|
export {
|
|
7491
|
-
BiometricCaptureModal
|
|
7709
|
+
BiometricCaptureModal,
|
|
7492
7710
|
BiometricRegistrationModal,
|
|
7493
7711
|
BiometricStatusOverlay,
|
|
7494
7712
|
DocumentCaptureModal,
|
|
@@ -7516,7 +7734,7 @@ export {
|
|
|
7516
7734
|
initializeBiometricDetection,
|
|
7517
7735
|
isAdvancedDetectionAvailable,
|
|
7518
7736
|
isInitialized,
|
|
7519
|
-
loginWithBiometric
|
|
7737
|
+
loginWithBiometric,
|
|
7520
7738
|
loginWithEmail,
|
|
7521
7739
|
preloadFaceDetectionModels,
|
|
7522
7740
|
recognize,
|