@neofaceid/web-sdk 1.30.0 → 1.31.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/dist/index.d.ts +34 -3
- package/dist/neoface-id-sdk.es.js +598 -57
- package/dist/neoface-id-sdk.umd.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import React, { useRef, useState, useCallback, useReducer, useEffect } from "react";
|
|
4
|
+
import React, { useRef, useState, useCallback, useReducer, useEffect, forwardRef } from "react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
6
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
7
7
|
import * as faceapi from "face-api.js";
|
|
@@ -4504,6 +4504,15 @@ function buildRootCss(theme) {
|
|
|
4504
4504
|
.neofaceid-root :focus-visible {
|
|
4505
4505
|
outline: 2px solid var(${CSS_VAR.focusRing});
|
|
4506
4506
|
outline-offset: 2px;
|
|
4507
|
+
}
|
|
4508
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4509
|
+
.neofaceid-root,
|
|
4510
|
+
.neofaceid-root * {
|
|
4511
|
+
animation-duration: 0.001ms !important;
|
|
4512
|
+
animation-iteration-count: 1 !important;
|
|
4513
|
+
transition-duration: 0.001ms !important;
|
|
4514
|
+
scroll-behavior: auto !important;
|
|
4515
|
+
}
|
|
4507
4516
|
}`;
|
|
4508
4517
|
}
|
|
4509
4518
|
function injectScopedStyles$1(id, css) {
|
|
@@ -8773,7 +8782,7 @@ class BiometricCaptureModal {
|
|
|
8773
8782
|
try {
|
|
8774
8783
|
await this.createModal();
|
|
8775
8784
|
await this.initializeCamera();
|
|
8776
|
-
this.
|
|
8785
|
+
this.enableCaptureButton();
|
|
8777
8786
|
} catch (error) {
|
|
8778
8787
|
this.options.onError(
|
|
8779
8788
|
new NeoFaceError(
|
|
@@ -8806,7 +8815,7 @@ class BiometricCaptureModal {
|
|
|
8806
8815
|
<div class="neofaceid-modal-content">
|
|
8807
8816
|
<div class="neofaceid-modal-header">
|
|
8808
8817
|
<h2>${title}</h2>
|
|
8809
|
-
<button class="neofaceid-close-btn" type="button">×</button>
|
|
8818
|
+
<button class="neofaceid-close-btn" type="button" aria-label="Fechar">×</button>
|
|
8810
8819
|
</div>
|
|
8811
8820
|
<div class="neofaceid-modal-body">
|
|
8812
8821
|
<p class="neofaceid-subtitle">${subtitle}</p>
|
|
@@ -8815,9 +8824,6 @@ class BiometricCaptureModal {
|
|
|
8815
8824
|
<canvas class="neofaceid-canvas" style="display: none;"></canvas>
|
|
8816
8825
|
<div class="neofaceid-overlay">
|
|
8817
8826
|
<div class="neofaceid-frame"></div>
|
|
8818
|
-
<div class="neofaceid-countdown">
|
|
8819
|
-
<span class="neofaceid-countdown-number">${this.options.countdown || 3}</span>
|
|
8820
|
-
</div>
|
|
8821
8827
|
</div>
|
|
8822
8828
|
</div>
|
|
8823
8829
|
<div class="neofaceid-status">
|
|
@@ -8828,6 +8834,9 @@ class BiometricCaptureModal {
|
|
|
8828
8834
|
<button class="neofaceid-cancel-btn" type="button">Cancelar</button>
|
|
8829
8835
|
<button class="neofaceid-capture-btn" type="button" disabled>Capturar</button>
|
|
8830
8836
|
</div>
|
|
8837
|
+
<div class="neofaceid-seal-row">
|
|
8838
|
+
<span class="neofaceid-seal">Protegido por NeoFaceID</span>
|
|
8839
|
+
</div>
|
|
8831
8840
|
</div>
|
|
8832
8841
|
</div>
|
|
8833
8842
|
`;
|
|
@@ -8864,42 +8873,24 @@ class BiometricCaptureModal {
|
|
|
8864
8873
|
}
|
|
8865
8874
|
}
|
|
8866
8875
|
/**
|
|
8867
|
-
*
|
|
8876
|
+
* NEO-413 · US14.6 (item 18) — a contagem "3, 2, 1" foi removida.
|
|
8877
|
+
* Agora habilita direto o botão "Capturar" assim que a câmera fica pronta.
|
|
8878
|
+
* Vivacidade fica com o desafio `runLivenessChallenge` (NEO-408), servidor decide.
|
|
8868
8879
|
*/
|
|
8869
|
-
|
|
8880
|
+
enableCaptureButton() {
|
|
8870
8881
|
if (!this.modal) return;
|
|
8871
|
-
const countdownElement = this.modal.querySelector(".neofaceid-countdown-number");
|
|
8872
8882
|
const captureBtn = this.modal.querySelector(".neofaceid-capture-btn");
|
|
8873
8883
|
const statusText = this.modal.querySelector(".neofaceid-status-text");
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8884
|
+
if (captureBtn) {
|
|
8885
|
+
captureBtn.disabled = false;
|
|
8886
|
+
captureBtn.textContent = "Capturar";
|
|
8887
|
+
}
|
|
8888
|
+
if (statusText) {
|
|
8889
|
+
statusText.textContent = "Pronto para capturar";
|
|
8890
|
+
}
|
|
8891
|
+
if (this.options.mode === "auto") {
|
|
8892
|
+
setTimeout(() => this.captureImage(), 300);
|
|
8877
8893
|
}
|
|
8878
|
-
this.countdownInterval = window.setInterval(() => {
|
|
8879
|
-
count--;
|
|
8880
|
-
if (countdownElement) {
|
|
8881
|
-
countdownElement.textContent = count.toString();
|
|
8882
|
-
}
|
|
8883
|
-
if (count <= 0) {
|
|
8884
|
-
if (this.countdownInterval) {
|
|
8885
|
-
clearInterval(this.countdownInterval);
|
|
8886
|
-
this.countdownInterval = null;
|
|
8887
|
-
}
|
|
8888
|
-
if (countdownElement) {
|
|
8889
|
-
countdownElement.style.display = "none";
|
|
8890
|
-
}
|
|
8891
|
-
if (captureBtn) {
|
|
8892
|
-
captureBtn.disabled = false;
|
|
8893
|
-
captureBtn.textContent = "Capturar Agora";
|
|
8894
|
-
}
|
|
8895
|
-
if (statusText) {
|
|
8896
|
-
statusText.textContent = "Pronto para capturar!";
|
|
8897
|
-
}
|
|
8898
|
-
if (this.options.mode === "auto") {
|
|
8899
|
-
setTimeout(() => this.captureImage(), 500);
|
|
8900
|
-
}
|
|
8901
|
-
}
|
|
8902
|
-
}, 1e3);
|
|
8903
8894
|
}
|
|
8904
8895
|
/**
|
|
8905
8896
|
* Captura a imagem da câmera
|
|
@@ -9081,18 +9072,22 @@ class BiometricCaptureModal {
|
|
|
9081
9072
|
.neofaceid-close-btn {
|
|
9082
9073
|
background: none;
|
|
9083
9074
|
border: none;
|
|
9084
|
-
font-size:
|
|
9075
|
+
font-size: 22px;
|
|
9085
9076
|
cursor: pointer;
|
|
9086
9077
|
color: #666;
|
|
9087
9078
|
padding: 0;
|
|
9088
|
-
width:
|
|
9089
|
-
height:
|
|
9079
|
+
min-width: 44px;
|
|
9080
|
+
min-height: 44px;
|
|
9090
9081
|
display: flex;
|
|
9091
9082
|
align-items: center;
|
|
9092
9083
|
justify-content: center;
|
|
9093
|
-
border-radius:
|
|
9084
|
+
border-radius: 22px;
|
|
9094
9085
|
transition: background-color 0.2s;
|
|
9095
9086
|
}
|
|
9087
|
+
.neofaceid-close-btn:focus-visible {
|
|
9088
|
+
outline: 2px solid var(--nfid-focus-ring);
|
|
9089
|
+
outline-offset: 2px;
|
|
9090
|
+
}
|
|
9096
9091
|
|
|
9097
9092
|
.neofaceid-close-btn:hover {
|
|
9098
9093
|
background-color: #f0f0f0;
|
|
@@ -9150,24 +9145,18 @@ class BiometricCaptureModal {
|
|
|
9150
9145
|
animation: pulse 2s infinite;
|
|
9151
9146
|
}
|
|
9152
9147
|
|
|
9153
|
-
.neofaceid-
|
|
9154
|
-
position: absolute;
|
|
9155
|
-
top: 20px;
|
|
9156
|
-
right: 20px;
|
|
9157
|
-
background: rgba(0, 0, 0, 0.7);
|
|
9158
|
-
color: white;
|
|
9159
|
-
padding: 10px;
|
|
9160
|
-
border-radius: 50%;
|
|
9161
|
-
width: 50px;
|
|
9162
|
-
height: 50px;
|
|
9148
|
+
.neofaceid-seal-row {
|
|
9163
9149
|
display: flex;
|
|
9164
|
-
align-items: center;
|
|
9165
9150
|
justify-content: center;
|
|
9151
|
+
padding: 12px 20px 16px;
|
|
9152
|
+
border-top: 1px solid var(--nfid-line, #E6ECF4);
|
|
9166
9153
|
}
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
font-
|
|
9170
|
-
|
|
9154
|
+
.neofaceid-seal {
|
|
9155
|
+
font-size: 11px;
|
|
9156
|
+
font-weight: 700;
|
|
9157
|
+
letter-spacing: 0.09em;
|
|
9158
|
+
text-transform: uppercase;
|
|
9159
|
+
color: var(--nfid-text-subtle, #617489);
|
|
9171
9160
|
}
|
|
9172
9161
|
|
|
9173
9162
|
.neofaceid-status {
|
|
@@ -10871,7 +10860,7 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
10871
10860
|
initializeBiometricDetection,
|
|
10872
10861
|
isAdvancedDetectionAvailable
|
|
10873
10862
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
10874
|
-
const VERSION = "1.
|
|
10863
|
+
const VERSION = "1.31.0";
|
|
10875
10864
|
const RELEASE_DATE = "2026-09-02";
|
|
10876
10865
|
let cachedSession = null;
|
|
10877
10866
|
function getCachedCaptureSession() {
|
|
@@ -11185,6 +11174,9 @@ class OnboardingCaptureModal {
|
|
|
11185
11174
|
<button class="neofaceid-cancel-btn">Cancelar</button>
|
|
11186
11175
|
<button class="neofaceid-capture-btn" disabled>Capturar</button>
|
|
11187
11176
|
</div>
|
|
11177
|
+
<div class="neofaceid-seal-row">
|
|
11178
|
+
<span class="neofaceid-seal">Protegido por NeoFaceID</span>
|
|
11179
|
+
</div>
|
|
11188
11180
|
</div>
|
|
11189
11181
|
`;
|
|
11190
11182
|
injectThemeStyles();
|
|
@@ -11208,6 +11200,8 @@ class OnboardingCaptureModal {
|
|
|
11208
11200
|
.neofaceid-root .neofaceid-cancel-btn { background: var(--nfid-surface-muted); color: var(--nfid-text-muted); border:none; border-radius:8px; padding:10px 18px; cursor:pointer; min-height: 44px; }
|
|
11209
11201
|
.neofaceid-root .neofaceid-capture-btn { background: var(--nfid-action); color: var(--nfid-action-text); border:none; border-radius:8px; padding:10px 18px; cursor:pointer; min-height: 44px; }
|
|
11210
11202
|
.neofaceid-root .neofaceid-capture-btn:disabled { background: var(--nfid-line); cursor:not-allowed; }
|
|
11203
|
+
.neofaceid-root .neofaceid-seal-row { display:flex; justify-content:center; padding:12px 20px 14px; border-top: 1px solid var(--nfid-line); }
|
|
11204
|
+
.neofaceid-root .neofaceid-seal { font-size:11px; font-weight:700; letter-spacing:0.09em; text-transform:uppercase; color: var(--nfid-text-subtle); }
|
|
11211
11205
|
`
|
|
11212
11206
|
);
|
|
11213
11207
|
overlay.classList.add("neofaceid-root");
|
|
@@ -11828,6 +11822,552 @@ const authorizeOperation = async (applicationToken, cpf, options) => {
|
|
|
11828
11822
|
throw new NeoFaceError("Unknown error during authorization", ErrorType.UNKNOWN);
|
|
11829
11823
|
}
|
|
11830
11824
|
};
|
|
11825
|
+
function Sheet({
|
|
11826
|
+
open,
|
|
11827
|
+
onDismiss,
|
|
11828
|
+
dismissOnOverlay = true,
|
|
11829
|
+
ariaLabel,
|
|
11830
|
+
ariaLabelledBy,
|
|
11831
|
+
children,
|
|
11832
|
+
className,
|
|
11833
|
+
style
|
|
11834
|
+
}) {
|
|
11835
|
+
useEffect(() => {
|
|
11836
|
+
injectThemeStyles$1();
|
|
11837
|
+
}, []);
|
|
11838
|
+
if (!open) return null;
|
|
11839
|
+
const handleOverlay = () => {
|
|
11840
|
+
if (dismissOnOverlay && onDismiss) onDismiss();
|
|
11841
|
+
};
|
|
11842
|
+
return /* @__PURE__ */ jsx(
|
|
11843
|
+
"div",
|
|
11844
|
+
{
|
|
11845
|
+
className: "neofaceid-root",
|
|
11846
|
+
role: "presentation",
|
|
11847
|
+
style: {
|
|
11848
|
+
position: "fixed",
|
|
11849
|
+
inset: 0,
|
|
11850
|
+
zIndex: 10001,
|
|
11851
|
+
display: "flex",
|
|
11852
|
+
alignItems: "center",
|
|
11853
|
+
justifyContent: "center",
|
|
11854
|
+
padding: 20,
|
|
11855
|
+
background: `var(${CSS_VAR.overlay})`,
|
|
11856
|
+
backdropFilter: "blur(3px)",
|
|
11857
|
+
WebkitBackdropFilter: "blur(3px)"
|
|
11858
|
+
},
|
|
11859
|
+
onClick: handleOverlay,
|
|
11860
|
+
children: /* @__PURE__ */ jsx(
|
|
11861
|
+
"div",
|
|
11862
|
+
{
|
|
11863
|
+
role: "dialog",
|
|
11864
|
+
"aria-modal": "true",
|
|
11865
|
+
"aria-label": ariaLabel,
|
|
11866
|
+
"aria-labelledby": ariaLabelledBy,
|
|
11867
|
+
className,
|
|
11868
|
+
onClick: (e) => e.stopPropagation(),
|
|
11869
|
+
style: {
|
|
11870
|
+
background: `var(${CSS_VAR.surface})`,
|
|
11871
|
+
color: `var(${CSS_VAR.text})`,
|
|
11872
|
+
borderRadius: `var(${CSS_VAR.radius}, 16px)`,
|
|
11873
|
+
padding: 28,
|
|
11874
|
+
maxWidth: 440,
|
|
11875
|
+
width: "100%",
|
|
11876
|
+
boxShadow: "0 1px 3px rgba(10,19,32,.08)",
|
|
11877
|
+
boxSizing: "border-box",
|
|
11878
|
+
...style
|
|
11879
|
+
},
|
|
11880
|
+
children
|
|
11881
|
+
}
|
|
11882
|
+
)
|
|
11883
|
+
}
|
|
11884
|
+
);
|
|
11885
|
+
}
|
|
11886
|
+
const BASE_STYLE = {
|
|
11887
|
+
minHeight: 44,
|
|
11888
|
+
minWidth: 44,
|
|
11889
|
+
padding: "12px 20px",
|
|
11890
|
+
borderRadius: 16,
|
|
11891
|
+
border: "none",
|
|
11892
|
+
fontSize: 15,
|
|
11893
|
+
fontWeight: 600,
|
|
11894
|
+
fontFamily: "inherit",
|
|
11895
|
+
cursor: "pointer",
|
|
11896
|
+
transition: "background 120ms ease-out",
|
|
11897
|
+
display: "inline-flex",
|
|
11898
|
+
alignItems: "center",
|
|
11899
|
+
justifyContent: "center",
|
|
11900
|
+
gap: 8
|
|
11901
|
+
};
|
|
11902
|
+
const Button = forwardRef(
|
|
11903
|
+
({ variant = "primary", style, type = "button", ...rest }, ref) => {
|
|
11904
|
+
const variantStyle = variant === "primary" ? {
|
|
11905
|
+
background: `var(${CSS_VAR.action})`,
|
|
11906
|
+
color: `var(${CSS_VAR.actionText})`
|
|
11907
|
+
} : variant === "secondary" ? {
|
|
11908
|
+
background: `var(${CSS_VAR.surfaceMuted})`,
|
|
11909
|
+
color: `var(${CSS_VAR.text})`
|
|
11910
|
+
} : {
|
|
11911
|
+
background: "transparent",
|
|
11912
|
+
color: `var(${CSS_VAR.textMuted})`
|
|
11913
|
+
};
|
|
11914
|
+
return (
|
|
11915
|
+
// eslint-disable-next-line react/button-has-type
|
|
11916
|
+
/* @__PURE__ */ jsx(
|
|
11917
|
+
"button",
|
|
11918
|
+
{
|
|
11919
|
+
ref,
|
|
11920
|
+
type,
|
|
11921
|
+
...rest,
|
|
11922
|
+
style: { ...BASE_STYLE, ...variantStyle, ...style }
|
|
11923
|
+
}
|
|
11924
|
+
)
|
|
11925
|
+
);
|
|
11926
|
+
}
|
|
11927
|
+
);
|
|
11928
|
+
Button.displayName = "Button";
|
|
11929
|
+
function FocusFrame({
|
|
11930
|
+
size = 96,
|
|
11931
|
+
color,
|
|
11932
|
+
strokeWidth,
|
|
11933
|
+
glow = false,
|
|
11934
|
+
className,
|
|
11935
|
+
style
|
|
11936
|
+
}) {
|
|
11937
|
+
const stroke = strokeWidth ?? autoStroke(size);
|
|
11938
|
+
const arm = size * 0.28;
|
|
11939
|
+
const offset = stroke / 2;
|
|
11940
|
+
const stops = [
|
|
11941
|
+
{ x: offset, y: offset, dx: 1, dy: 1 },
|
|
11942
|
+
{ x: size - offset, y: offset, dx: -1, dy: 1 },
|
|
11943
|
+
{ x: offset, y: size - offset, dx: 1, dy: -1 },
|
|
11944
|
+
{ x: size - offset, y: size - offset, dx: -1, dy: -1 }
|
|
11945
|
+
];
|
|
11946
|
+
return /* @__PURE__ */ jsx(
|
|
11947
|
+
"svg",
|
|
11948
|
+
{
|
|
11949
|
+
width: size,
|
|
11950
|
+
height: size,
|
|
11951
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
11952
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
11953
|
+
className,
|
|
11954
|
+
style: {
|
|
11955
|
+
color: color ?? `var(${CSS_VAR.action})`,
|
|
11956
|
+
filter: glow ? "drop-shadow(0 0 6px rgba(0,176,248,.5))" : void 0,
|
|
11957
|
+
...style
|
|
11958
|
+
},
|
|
11959
|
+
"aria-hidden": "true",
|
|
11960
|
+
children: stops.map((c, i) => /* @__PURE__ */ jsx(
|
|
11961
|
+
"path",
|
|
11962
|
+
{
|
|
11963
|
+
d: `M ${c.x + c.dx * arm} ${c.y} L ${c.x} ${c.y} L ${c.x} ${c.y + c.dy * arm}`,
|
|
11964
|
+
fill: "none",
|
|
11965
|
+
stroke: "currentColor",
|
|
11966
|
+
strokeWidth: stroke,
|
|
11967
|
+
strokeLinecap: "round"
|
|
11968
|
+
},
|
|
11969
|
+
i
|
|
11970
|
+
))
|
|
11971
|
+
}
|
|
11972
|
+
);
|
|
11973
|
+
}
|
|
11974
|
+
function autoStroke(size) {
|
|
11975
|
+
if (size <= 24) return 2;
|
|
11976
|
+
if (size <= 48) return 2.5;
|
|
11977
|
+
return 3.4;
|
|
11978
|
+
}
|
|
11979
|
+
function ChallengeRing({
|
|
11980
|
+
progress,
|
|
11981
|
+
size = 268,
|
|
11982
|
+
children,
|
|
11983
|
+
className,
|
|
11984
|
+
style
|
|
11985
|
+
}) {
|
|
11986
|
+
const clamped = Math.max(0, Math.min(1, Number.isFinite(progress) ? progress : 0));
|
|
11987
|
+
const stroke = 4.2;
|
|
11988
|
+
const radius = size / 2 - stroke;
|
|
11989
|
+
const circumference = 2 * Math.PI * radius;
|
|
11990
|
+
const dashOffset = circumference * (1 - clamped);
|
|
11991
|
+
const frameSize = size + 24;
|
|
11992
|
+
return /* @__PURE__ */ jsxs(
|
|
11993
|
+
"div",
|
|
11994
|
+
{
|
|
11995
|
+
className,
|
|
11996
|
+
style: {
|
|
11997
|
+
position: "relative",
|
|
11998
|
+
width: frameSize,
|
|
11999
|
+
height: frameSize,
|
|
12000
|
+
display: "inline-flex",
|
|
12001
|
+
alignItems: "center",
|
|
12002
|
+
justifyContent: "center",
|
|
12003
|
+
...style
|
|
12004
|
+
},
|
|
12005
|
+
children: [
|
|
12006
|
+
/* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0 }, children: /* @__PURE__ */ jsx(FocusFrame, { size: frameSize, glow: true }) }),
|
|
12007
|
+
/* @__PURE__ */ jsx(
|
|
12008
|
+
"div",
|
|
12009
|
+
{
|
|
12010
|
+
style: {
|
|
12011
|
+
position: "relative",
|
|
12012
|
+
width: size,
|
|
12013
|
+
height: size,
|
|
12014
|
+
borderRadius: "50%",
|
|
12015
|
+
overflow: "hidden",
|
|
12016
|
+
background: "linear-gradient(160deg, #274B6E, #0F2438, #05080F)"
|
|
12017
|
+
},
|
|
12018
|
+
children
|
|
12019
|
+
}
|
|
12020
|
+
),
|
|
12021
|
+
/* @__PURE__ */ jsxs(
|
|
12022
|
+
"svg",
|
|
12023
|
+
{
|
|
12024
|
+
width: size,
|
|
12025
|
+
height: size,
|
|
12026
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
12027
|
+
style: {
|
|
12028
|
+
position: "absolute",
|
|
12029
|
+
top: (frameSize - size) / 2,
|
|
12030
|
+
left: (frameSize - size) / 2,
|
|
12031
|
+
transform: "rotate(-90deg)",
|
|
12032
|
+
pointerEvents: "none"
|
|
12033
|
+
},
|
|
12034
|
+
"aria-hidden": "true",
|
|
12035
|
+
children: [
|
|
12036
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "nfid-challenge-arc", x1: "0%", y1: "0%", x2: "100%", y2: "100%", children: [
|
|
12037
|
+
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "#00B0F8" }),
|
|
12038
|
+
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: "#0073F4" })
|
|
12039
|
+
] }) }),
|
|
12040
|
+
/* @__PURE__ */ jsx(
|
|
12041
|
+
"circle",
|
|
12042
|
+
{
|
|
12043
|
+
cx: size / 2,
|
|
12044
|
+
cy: size / 2,
|
|
12045
|
+
r: radius,
|
|
12046
|
+
stroke: "rgba(255,255,255,0.18)",
|
|
12047
|
+
strokeWidth: stroke,
|
|
12048
|
+
fill: "none"
|
|
12049
|
+
}
|
|
12050
|
+
),
|
|
12051
|
+
/* @__PURE__ */ jsx(
|
|
12052
|
+
"circle",
|
|
12053
|
+
{
|
|
12054
|
+
cx: size / 2,
|
|
12055
|
+
cy: size / 2,
|
|
12056
|
+
r: radius,
|
|
12057
|
+
stroke: `var(${CSS_VAR.action}, url(#nfid-challenge-arc))`,
|
|
12058
|
+
strokeWidth: stroke,
|
|
12059
|
+
strokeLinecap: "round",
|
|
12060
|
+
strokeDasharray: circumference,
|
|
12061
|
+
strokeDashoffset: dashOffset,
|
|
12062
|
+
fill: "none",
|
|
12063
|
+
style: { transition: "stroke-dashoffset 200ms ease-out" }
|
|
12064
|
+
}
|
|
12065
|
+
)
|
|
12066
|
+
]
|
|
12067
|
+
}
|
|
12068
|
+
)
|
|
12069
|
+
]
|
|
12070
|
+
}
|
|
12071
|
+
);
|
|
12072
|
+
}
|
|
12073
|
+
function ChallengeGlyph({
|
|
12074
|
+
gesture,
|
|
12075
|
+
size = 48,
|
|
12076
|
+
color,
|
|
12077
|
+
className,
|
|
12078
|
+
style
|
|
12079
|
+
}) {
|
|
12080
|
+
const stroke = 3.4;
|
|
12081
|
+
return /* @__PURE__ */ jsxs(
|
|
12082
|
+
"svg",
|
|
12083
|
+
{
|
|
12084
|
+
width: size,
|
|
12085
|
+
height: size,
|
|
12086
|
+
viewBox: "0 0 48 48",
|
|
12087
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12088
|
+
className,
|
|
12089
|
+
style: { color: color ?? `var(${CSS_VAR.action})`, ...style },
|
|
12090
|
+
role: "img",
|
|
12091
|
+
"aria-label": LABELS[gesture],
|
|
12092
|
+
children: [
|
|
12093
|
+
gesture === "blink" ? /* @__PURE__ */ jsx(BlinkGlyph, { stroke }) : /* @__PURE__ */ jsx(FaceGlyph, { stroke }),
|
|
12094
|
+
gesture !== "blink" && gesture !== "center" && /* @__PURE__ */ jsx(Chevron, { gesture, stroke })
|
|
12095
|
+
]
|
|
12096
|
+
}
|
|
12097
|
+
);
|
|
12098
|
+
}
|
|
12099
|
+
const LABELS = {
|
|
12100
|
+
center: "Centralize o rosto",
|
|
12101
|
+
turn_right: "Vire o rosto para a direita",
|
|
12102
|
+
turn_left: "Vire o rosto para a esquerda",
|
|
12103
|
+
look_up: "Olhe para cima",
|
|
12104
|
+
look_down: "Olhe para baixo",
|
|
12105
|
+
blink: "Pisque os olhos",
|
|
12106
|
+
move_closer: "Aproxime-se da câmera"
|
|
12107
|
+
};
|
|
12108
|
+
function FaceGlyph({ stroke }) {
|
|
12109
|
+
return /* @__PURE__ */ jsxs("g", { fill: "none", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
12110
|
+
/* @__PURE__ */ jsx("path", { d: "M14 20c0-5.5 4.5-10 10-10s10 4.5 10 10v4c0 5.5-4.5 10-10 10s-10-4.5-10-10v-4z" }),
|
|
12111
|
+
/* @__PURE__ */ jsx("circle", { cx: "20", cy: "22", r: "1.2", fill: "currentColor", stroke: "none" }),
|
|
12112
|
+
/* @__PURE__ */ jsx("circle", { cx: "28", cy: "22", r: "1.2", fill: "currentColor", stroke: "none" }),
|
|
12113
|
+
/* @__PURE__ */ jsx("path", { d: "M21 28c1 1 2 1.5 3 1.5s2-.5 3-1.5" })
|
|
12114
|
+
] });
|
|
12115
|
+
}
|
|
12116
|
+
function BlinkGlyph({ stroke }) {
|
|
12117
|
+
return /* @__PURE__ */ jsxs("g", { fill: "none", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
12118
|
+
/* @__PURE__ */ jsx("path", { d: "M8 24c4-4 8-6 16-6s12 2 16 6" }),
|
|
12119
|
+
/* @__PURE__ */ jsx("path", { d: "M12 26v3" }),
|
|
12120
|
+
/* @__PURE__ */ jsx("path", { d: "M18 27v3.5" }),
|
|
12121
|
+
/* @__PURE__ */ jsx("path", { d: "M24 27.5v4" }),
|
|
12122
|
+
/* @__PURE__ */ jsx("path", { d: "M30 27v3.5" }),
|
|
12123
|
+
/* @__PURE__ */ jsx("path", { d: "M36 26v3" })
|
|
12124
|
+
] });
|
|
12125
|
+
}
|
|
12126
|
+
function Chevron({ gesture, stroke }) {
|
|
12127
|
+
const [start2, mid, end] = pointsFor(gesture);
|
|
12128
|
+
return /* @__PURE__ */ jsx(
|
|
12129
|
+
"path",
|
|
12130
|
+
{
|
|
12131
|
+
d: `M ${start2} L ${mid} L ${end}`,
|
|
12132
|
+
fill: "none",
|
|
12133
|
+
stroke: "currentColor",
|
|
12134
|
+
strokeWidth: stroke,
|
|
12135
|
+
strokeLinecap: "round",
|
|
12136
|
+
strokeLinejoin: "round"
|
|
12137
|
+
}
|
|
12138
|
+
);
|
|
12139
|
+
}
|
|
12140
|
+
function pointsFor(g) {
|
|
12141
|
+
switch (g) {
|
|
12142
|
+
case "turn_right":
|
|
12143
|
+
return ["40 18", "44 24", "40 30"];
|
|
12144
|
+
case "turn_left":
|
|
12145
|
+
return ["8 18", "4 24", "8 30"];
|
|
12146
|
+
case "look_up":
|
|
12147
|
+
return ["18 8", "24 4", "30 8"];
|
|
12148
|
+
case "look_down":
|
|
12149
|
+
return ["18 40", "24 44", "30 40"];
|
|
12150
|
+
case "move_closer":
|
|
12151
|
+
return ["18 40", "24 44", "30 40"];
|
|
12152
|
+
default:
|
|
12153
|
+
return ["24 24", "24 24", "24 24"];
|
|
12154
|
+
}
|
|
12155
|
+
}
|
|
12156
|
+
const STYLE_ID = "neofaceid-authorize-styles";
|
|
12157
|
+
const GESTURE_TO_GLYPH = {
|
|
12158
|
+
center: "center",
|
|
12159
|
+
turn_right: "turn_right",
|
|
12160
|
+
turn_left: "turn_left",
|
|
12161
|
+
look_up: "look_up",
|
|
12162
|
+
look_down: "look_down",
|
|
12163
|
+
blink: "blink",
|
|
12164
|
+
move_closer: "move_closer",
|
|
12165
|
+
smile: "blink",
|
|
12166
|
+
open_mouth: "blink"
|
|
12167
|
+
};
|
|
12168
|
+
const GESTURE_TO_INSTRUCTION = {
|
|
12169
|
+
center: "Centralize seu rosto no oval",
|
|
12170
|
+
turn_right: "Vire lentamente o rosto para a direita",
|
|
12171
|
+
turn_left: "Vire lentamente o rosto para a esquerda",
|
|
12172
|
+
look_up: "Olhe para cima",
|
|
12173
|
+
look_down: "Olhe para baixo",
|
|
12174
|
+
blink: "Pisque os olhos",
|
|
12175
|
+
move_closer: "Aproxime-se da câmera",
|
|
12176
|
+
smile: "Sorria para a câmera",
|
|
12177
|
+
open_mouth: "Abra a boca"
|
|
12178
|
+
};
|
|
12179
|
+
function formatCurrency(amount, locale) {
|
|
12180
|
+
try {
|
|
12181
|
+
return new Intl.NumberFormat(locale, {
|
|
12182
|
+
style: "currency",
|
|
12183
|
+
currency: "BRL"
|
|
12184
|
+
}).format(amount);
|
|
12185
|
+
} catch {
|
|
12186
|
+
return `R$ ${amount.toFixed(2)}`;
|
|
12187
|
+
}
|
|
12188
|
+
}
|
|
12189
|
+
function AuthorizeModalComponent({
|
|
12190
|
+
applicationToken,
|
|
12191
|
+
appName,
|
|
12192
|
+
amount,
|
|
12193
|
+
onChallengeStart,
|
|
12194
|
+
onChallengeComplete,
|
|
12195
|
+
onSuccess,
|
|
12196
|
+
onError,
|
|
12197
|
+
onCancel,
|
|
12198
|
+
onClose
|
|
12199
|
+
}) {
|
|
12200
|
+
const videoRef = useRef(null);
|
|
12201
|
+
const [progress, setProgress] = useState(0);
|
|
12202
|
+
const [currentGesture, setCurrentGesture] = useState(null);
|
|
12203
|
+
const [phase, setPhase] = useState("preparing");
|
|
12204
|
+
const cancelRef = useRef(false);
|
|
12205
|
+
const locale = getLocale();
|
|
12206
|
+
const headerAppName = appName ?? getAppName() ?? "sua aplicação";
|
|
12207
|
+
const headerAmount = typeof amount === "number" && Number.isFinite(amount) ? formatCurrency(amount, locale) : null;
|
|
12208
|
+
useEffect(() => {
|
|
12209
|
+
injectThemeStyles$1();
|
|
12210
|
+
injectScopedStyles$1(
|
|
12211
|
+
STYLE_ID,
|
|
12212
|
+
`
|
|
12213
|
+
.neofaceid-root .nfid-authorize-header { display: flex; flex-direction: column; gap: 4px; margin-bottom: 16px; }
|
|
12214
|
+
.neofaceid-root .nfid-authorize-appname { font-size: 15px; font-weight: 700; color: var(--nfid-text); line-height: 1.2; }
|
|
12215
|
+
.neofaceid-root .nfid-authorize-amount { font-size: 13px; color: var(--nfid-text-muted); }
|
|
12216
|
+
.neofaceid-root .nfid-authorize-brand { font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--nfid-text-subtle); }
|
|
12217
|
+
.neofaceid-root .nfid-authorize-video { width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); }
|
|
12218
|
+
.neofaceid-root .nfid-authorize-instruction { margin: 20px 0 0; font-size: 17px; font-weight: 600; color: var(--nfid-text); text-align: center; line-height: 1.3; }
|
|
12219
|
+
.neofaceid-root .nfid-authorize-support { margin: 6px 0 0; font-size: 13px; color: var(--nfid-text-muted); text-align: center; }
|
|
12220
|
+
.neofaceid-root .nfid-authorize-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 20px; align-items: center; }
|
|
12221
|
+
.neofaceid-root .nfid-authorize-footer { display: flex; justify-content: center; margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--nfid-line); }
|
|
12222
|
+
.neofaceid-root .nfid-authorize-seal { font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--nfid-text-subtle); }
|
|
12223
|
+
.neofaceid-root .nfid-authorize-close {
|
|
12224
|
+
position: absolute; top: 8px; right: 8px;
|
|
12225
|
+
min-width: 44px; min-height: 44px;
|
|
12226
|
+
background: transparent; border: none;
|
|
12227
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
12228
|
+
color: var(--nfid-text-muted); cursor: pointer; border-radius: 22px;
|
|
12229
|
+
}
|
|
12230
|
+
.neofaceid-root .nfid-authorize-close:hover { background: var(--nfid-surface-muted); }
|
|
12231
|
+
.neofaceid-root .nfid-authorize-close:focus-visible { outline: 2px solid var(--nfid-focus-ring); outline-offset: 2px; }
|
|
12232
|
+
@media (prefers-reduced-motion: reduce) {
|
|
12233
|
+
.neofaceid-root svg circle { transition: none !important; }
|
|
12234
|
+
}
|
|
12235
|
+
`
|
|
12236
|
+
);
|
|
12237
|
+
}, []);
|
|
12238
|
+
useEffect(() => {
|
|
12239
|
+
let stream = null;
|
|
12240
|
+
async function run() {
|
|
12241
|
+
try {
|
|
12242
|
+
stream = await navigator.mediaDevices.getUserMedia({
|
|
12243
|
+
video: { facingMode: "user", width: { ideal: 1280 }, height: { ideal: 720 } }
|
|
12244
|
+
});
|
|
12245
|
+
if (videoRef.current) {
|
|
12246
|
+
videoRef.current.srcObject = stream;
|
|
12247
|
+
videoRef.current.play().catch(() => {
|
|
12248
|
+
});
|
|
12249
|
+
}
|
|
12250
|
+
setPhase("challenging");
|
|
12251
|
+
const result = await runLivenessChallenge({
|
|
12252
|
+
applicationToken,
|
|
12253
|
+
purpose: "authorization",
|
|
12254
|
+
collectFramesForGesture: async (gesture, index, total) => {
|
|
12255
|
+
if (cancelRef.current) throw new NeoFaceError("Cancelado", ErrorType.UNKNOWN);
|
|
12256
|
+
setCurrentGesture(gesture);
|
|
12257
|
+
setProgress(0);
|
|
12258
|
+
if (onChallengeStart) onChallengeStart(gesture, index, total);
|
|
12259
|
+
await progressiveHold(setProgress);
|
|
12260
|
+
if (onChallengeComplete) onChallengeComplete(gesture, index, total);
|
|
12261
|
+
const frame = await captureFrame(videoRef.current);
|
|
12262
|
+
return frame ? [frame] : [];
|
|
12263
|
+
}
|
|
12264
|
+
});
|
|
12265
|
+
setPhase("done");
|
|
12266
|
+
if (onSuccess) onSuccess(result);
|
|
12267
|
+
onClose();
|
|
12268
|
+
} catch (err) {
|
|
12269
|
+
const nfe = err instanceof NeoFaceError ? err : new NeoFaceError(err instanceof Error ? err.message : "Falha", ErrorType.UNKNOWN);
|
|
12270
|
+
if (onError) onError(nfe);
|
|
12271
|
+
onClose();
|
|
12272
|
+
} finally {
|
|
12273
|
+
if (stream) stream.getTracks().forEach((t) => t.stop());
|
|
12274
|
+
}
|
|
12275
|
+
}
|
|
12276
|
+
run();
|
|
12277
|
+
return () => {
|
|
12278
|
+
cancelRef.current = true;
|
|
12279
|
+
if (stream) stream.getTracks().forEach((t) => t.stop());
|
|
12280
|
+
};
|
|
12281
|
+
}, []);
|
|
12282
|
+
const handleClose = () => {
|
|
12283
|
+
cancelRef.current = true;
|
|
12284
|
+
if (onCancel) onCancel();
|
|
12285
|
+
onClose();
|
|
12286
|
+
};
|
|
12287
|
+
const gestureKey = currentGesture ? GESTURE_TO_GLYPH[currentGesture.gesture_key] ?? "center" : "center";
|
|
12288
|
+
const instruction = currentGesture ? GESTURE_TO_INSTRUCTION[currentGesture.gesture_key] ?? "Siga a instrução" : "Preparando a câmera…";
|
|
12289
|
+
return /* @__PURE__ */ jsx(Sheet, { open: true, onDismiss: void 0, dismissOnOverlay: false, ariaLabel: "Autorização por biometria", children: /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
12290
|
+
/* @__PURE__ */ jsx(
|
|
12291
|
+
"button",
|
|
12292
|
+
{
|
|
12293
|
+
type: "button",
|
|
12294
|
+
className: "nfid-authorize-close",
|
|
12295
|
+
onClick: handleClose,
|
|
12296
|
+
"aria-label": "Cancelar autorização",
|
|
12297
|
+
children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
12298
|
+
}
|
|
12299
|
+
),
|
|
12300
|
+
/* @__PURE__ */ jsxs("div", { className: "nfid-authorize-header", children: [
|
|
12301
|
+
/* @__PURE__ */ jsx("span", { className: "nfid-authorize-appname", children: headerAppName }),
|
|
12302
|
+
headerAmount && /* @__PURE__ */ jsxs("span", { className: "nfid-authorize-amount", children: [
|
|
12303
|
+
"Autorizando ",
|
|
12304
|
+
headerAmount
|
|
12305
|
+
] }),
|
|
12306
|
+
/* @__PURE__ */ jsx("span", { className: "nfid-authorize-brand", children: "NeoFaceID" })
|
|
12307
|
+
] }),
|
|
12308
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx(ChallengeRing, { progress, size: 220, children: /* @__PURE__ */ jsx("video", { ref: videoRef, className: "nfid-authorize-video", autoPlay: true, muted: true, playsInline: true }) }) }),
|
|
12309
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 12, marginTop: 16 }, children: [
|
|
12310
|
+
/* @__PURE__ */ jsx(ChallengeGlyph, { gesture: gestureKey, size: 40 }),
|
|
12311
|
+
/* @__PURE__ */ jsx(
|
|
12312
|
+
"p",
|
|
12313
|
+
{
|
|
12314
|
+
className: "nfid-authorize-instruction",
|
|
12315
|
+
"aria-live": "assertive",
|
|
12316
|
+
style: { margin: 0 },
|
|
12317
|
+
children: instruction
|
|
12318
|
+
}
|
|
12319
|
+
)
|
|
12320
|
+
] }),
|
|
12321
|
+
phase === "preparing" && /* @__PURE__ */ jsx("p", { className: "nfid-authorize-support", children: "Ligando sua câmera…" }),
|
|
12322
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-authorize-actions", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleClose, children: "Não consigo fazer esse movimento" }) }),
|
|
12323
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-authorize-footer", children: /* @__PURE__ */ jsx("span", { className: "nfid-authorize-seal", children: "Protegido por NeoFaceID" }) })
|
|
12324
|
+
] }) });
|
|
12325
|
+
}
|
|
12326
|
+
async function progressiveHold(setter) {
|
|
12327
|
+
const total = 1500;
|
|
12328
|
+
const start2 = Date.now();
|
|
12329
|
+
return new Promise((resolve) => {
|
|
12330
|
+
const tick = () => {
|
|
12331
|
+
const elapsed = Date.now() - start2;
|
|
12332
|
+
const p = Math.min(1, elapsed / total);
|
|
12333
|
+
setter(p);
|
|
12334
|
+
if (elapsed >= total) resolve();
|
|
12335
|
+
else setTimeout(tick, 50);
|
|
12336
|
+
};
|
|
12337
|
+
tick();
|
|
12338
|
+
});
|
|
12339
|
+
}
|
|
12340
|
+
async function captureFrame(video) {
|
|
12341
|
+
if (!video || video.videoWidth === 0) return null;
|
|
12342
|
+
const canvas = document.createElement("canvas");
|
|
12343
|
+
canvas.width = video.videoWidth;
|
|
12344
|
+
canvas.height = video.videoHeight;
|
|
12345
|
+
const ctx = canvas.getContext("2d");
|
|
12346
|
+
if (!ctx) return null;
|
|
12347
|
+
ctx.drawImage(video, 0, 0);
|
|
12348
|
+
return canvas.toDataURL("image/jpeg", 0.85);
|
|
12349
|
+
}
|
|
12350
|
+
async function authorize(options) {
|
|
12351
|
+
const consentAccepted = await requestConsent({
|
|
12352
|
+
appName: options.appName,
|
|
12353
|
+
flow: "verification"
|
|
12354
|
+
});
|
|
12355
|
+
if (!consentAccepted) {
|
|
12356
|
+
if (options.onError) {
|
|
12357
|
+
options.onError(new NeoFaceError("Consentimento recusado", ErrorType.CONSENT_DENIED));
|
|
12358
|
+
}
|
|
12359
|
+
return;
|
|
12360
|
+
}
|
|
12361
|
+
const container = document.createElement("div");
|
|
12362
|
+
container.id = "neofaceid-authorize-container";
|
|
12363
|
+
document.body.appendChild(container);
|
|
12364
|
+
const root = createRoot(container);
|
|
12365
|
+
const cleanup = () => {
|
|
12366
|
+
root.unmount();
|
|
12367
|
+
if (document.body.contains(container)) document.body.removeChild(container);
|
|
12368
|
+
};
|
|
12369
|
+
root.render(/* @__PURE__ */ jsx(AuthorizeModalComponent, { ...options, onClose: cleanup }));
|
|
12370
|
+
}
|
|
11831
12371
|
const DOCUMENT_INFO = {
|
|
11832
12372
|
RG: {
|
|
11833
12373
|
name: "Documento de Identidade (RG / CIN / CPF)",
|
|
@@ -12986,6 +13526,7 @@ export {
|
|
|
12986
13526
|
NeoFaceID,
|
|
12987
13527
|
RELEASE_DATE,
|
|
12988
13528
|
VERSION,
|
|
13529
|
+
authorize,
|
|
12989
13530
|
authorizeOperation,
|
|
12990
13531
|
biometricLogin,
|
|
12991
13532
|
biometricLoginWithFallback,
|