@neofaceid/web-sdk 1.31.0 → 1.33.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 +1 -1
- package/dist/neoface-id-sdk.es.js +421 -35
- package/dist/neoface-id-sdk.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1626,7 +1626,7 @@ export declare const validateToken: (applicationToken: string) => Promise<boolea
|
|
|
1626
1626
|
* MINOR: Incrementado quando adicionamos funcionalidades mantendo compatibilidade
|
|
1627
1627
|
* PATCH: Incrementado quando corrigimos bugs mantendo compatibilidade
|
|
1628
1628
|
*/
|
|
1629
|
-
export declare const VERSION = "1.
|
|
1629
|
+
export declare const VERSION = "1.33.0";
|
|
1630
1630
|
|
|
1631
1631
|
/**
|
|
1632
1632
|
* Executa `fn(sessionId)`. Se o servidor devolver 410 (sessão consumida/expirada),
|
|
@@ -4362,6 +4362,12 @@ const INK = {
|
|
|
4362
4362
|
900: "#111C2B",
|
|
4363
4363
|
950: "#0A1320"
|
|
4364
4364
|
};
|
|
4365
|
+
const SEMANTIC = {
|
|
4366
|
+
success: { fg: "#046C4E", bg: "#E7F7F0", solid: "#0E9F6E" },
|
|
4367
|
+
attention: { fg: "#6E5600", bg: "#FFF6D9", solid: "#F1BE00" },
|
|
4368
|
+
critical: { fg: "#9B1C1C", bg: "#FDEAEA", solid: "#E02424" },
|
|
4369
|
+
info: { fg: "#00449A", bg: "#EBF6FE", solid: "#0073F4" }
|
|
4370
|
+
};
|
|
4365
4371
|
const LIGHT_TOKENS = {
|
|
4366
4372
|
ground: INK[25],
|
|
4367
4373
|
surface: "#FFFFFF",
|
|
@@ -10059,7 +10065,7 @@ class EmailPasswordModal {
|
|
|
10059
10065
|
}
|
|
10060
10066
|
}
|
|
10061
10067
|
}
|
|
10062
|
-
const MAX_ATTEMPTS = 2;
|
|
10068
|
+
const MAX_ATTEMPTS$1 = 2;
|
|
10063
10069
|
const RETRY_DELAY = 500;
|
|
10064
10070
|
const CAMERA_READY_DELAY = 200;
|
|
10065
10071
|
const CAMERA_STABILITY_DELAY = 100;
|
|
@@ -10477,7 +10483,7 @@ async function executeBiometricLoginFlow(options) {
|
|
|
10477
10483
|
ErrorType.UNKNOWN
|
|
10478
10484
|
);
|
|
10479
10485
|
overlay.updateStatus("error");
|
|
10480
|
-
if (attempts < MAX_ATTEMPTS) {
|
|
10486
|
+
if (attempts < MAX_ATTEMPTS$1) {
|
|
10481
10487
|
setTimeout(() => {
|
|
10482
10488
|
tryLogin();
|
|
10483
10489
|
}, RETRY_DELAY);
|
|
@@ -10860,7 +10866,7 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
10860
10866
|
initializeBiometricDetection,
|
|
10861
10867
|
isAdvancedDetectionAvailable
|
|
10862
10868
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
10863
|
-
const VERSION = "1.
|
|
10869
|
+
const VERSION = "1.33.0";
|
|
10864
10870
|
const RELEASE_DATE = "2026-09-02";
|
|
10865
10871
|
let cachedSession = null;
|
|
10866
10872
|
function getCachedCaptureSession() {
|
|
@@ -12153,6 +12159,306 @@ function pointsFor(g) {
|
|
|
12153
12159
|
return ["24 24", "24 24", "24 24"];
|
|
12154
12160
|
}
|
|
12155
12161
|
}
|
|
12162
|
+
function StatusPill({ tone, children, icon, className }) {
|
|
12163
|
+
const palette = SEMANTIC[tone];
|
|
12164
|
+
return /* @__PURE__ */ jsxs(
|
|
12165
|
+
"span",
|
|
12166
|
+
{
|
|
12167
|
+
className,
|
|
12168
|
+
style: {
|
|
12169
|
+
display: "inline-flex",
|
|
12170
|
+
alignItems: "center",
|
|
12171
|
+
gap: 6,
|
|
12172
|
+
padding: "4px 10px",
|
|
12173
|
+
borderRadius: 9999,
|
|
12174
|
+
background: palette.bg,
|
|
12175
|
+
color: palette.fg,
|
|
12176
|
+
fontSize: 13,
|
|
12177
|
+
fontWeight: 600,
|
|
12178
|
+
fontFamily: "inherit",
|
|
12179
|
+
lineHeight: 1.3
|
|
12180
|
+
},
|
|
12181
|
+
children: [
|
|
12182
|
+
icon,
|
|
12183
|
+
children
|
|
12184
|
+
]
|
|
12185
|
+
}
|
|
12186
|
+
);
|
|
12187
|
+
}
|
|
12188
|
+
const DEFAULT = {
|
|
12189
|
+
title: "Não deu certo desta vez",
|
|
12190
|
+
hint: "Tente se posicionar em um ambiente mais estável.",
|
|
12191
|
+
actions: [
|
|
12192
|
+
"Segure o dispositivo firme",
|
|
12193
|
+
"Fique de frente para uma luz suave"
|
|
12194
|
+
]
|
|
12195
|
+
};
|
|
12196
|
+
const MAP = {
|
|
12197
|
+
LIVENESS_LOW: {
|
|
12198
|
+
title: "Precisamos ver com mais nitidez",
|
|
12199
|
+
hint: "A prova de vida veio abaixo do esperado.",
|
|
12200
|
+
actions: [
|
|
12201
|
+
"Faça o movimento com calma até o fim",
|
|
12202
|
+
"Aproxime o rosto sem cortar as bordas"
|
|
12203
|
+
]
|
|
12204
|
+
},
|
|
12205
|
+
NO_FACE_DETECTED: {
|
|
12206
|
+
title: "Não vi seu rosto",
|
|
12207
|
+
hint: "A câmera não conseguiu identificar um rosto na moldura.",
|
|
12208
|
+
actions: [
|
|
12209
|
+
"Centralize o rosto no oval",
|
|
12210
|
+
"Afaste-se um pouco se estiver muito próximo"
|
|
12211
|
+
]
|
|
12212
|
+
},
|
|
12213
|
+
LOW_LIGHT: {
|
|
12214
|
+
title: "A luz está baixa demais",
|
|
12215
|
+
hint: "Falta contraste para o algoritmo distinguir seu rosto.",
|
|
12216
|
+
actions: [
|
|
12217
|
+
"Fique de frente para uma janela ou lâmpada",
|
|
12218
|
+
"Evite luz vindo por trás — deixa o rosto em sombra"
|
|
12219
|
+
]
|
|
12220
|
+
},
|
|
12221
|
+
LOOK_STRAIGHT: {
|
|
12222
|
+
title: "Olhe direto para a câmera",
|
|
12223
|
+
hint: "O rosto está um pouco de lado para reconhecimento facial.",
|
|
12224
|
+
actions: [
|
|
12225
|
+
"Fique de frente para a câmera",
|
|
12226
|
+
"Mantenha o queixo paralelo ao chão"
|
|
12227
|
+
]
|
|
12228
|
+
},
|
|
12229
|
+
RECOGNITION_FAILED: {
|
|
12230
|
+
title: "Não consegui confirmar",
|
|
12231
|
+
hint: "A imagem não bate com o cadastro que temos.",
|
|
12232
|
+
actions: [
|
|
12233
|
+
"Retire óculos ou máscara temporariamente",
|
|
12234
|
+
"Faça em um lugar mais iluminado"
|
|
12235
|
+
]
|
|
12236
|
+
},
|
|
12237
|
+
INVALID_TOKEN: {
|
|
12238
|
+
title: "Sessão expirada",
|
|
12239
|
+
hint: "A conexão com o serviço perdeu validade.",
|
|
12240
|
+
actions: [
|
|
12241
|
+
"Volte à tela anterior e tente novamente",
|
|
12242
|
+
"Se persistir, entre em contato com o suporte"
|
|
12243
|
+
]
|
|
12244
|
+
},
|
|
12245
|
+
NETWORK: {
|
|
12246
|
+
title: "A conexão está oscilando",
|
|
12247
|
+
hint: "A imagem não chegou até nosso servidor.",
|
|
12248
|
+
actions: [
|
|
12249
|
+
"Verifique a rede do dispositivo",
|
|
12250
|
+
"Repita a captura em alguns segundos"
|
|
12251
|
+
]
|
|
12252
|
+
}
|
|
12253
|
+
};
|
|
12254
|
+
function copyForErrorCode(code) {
|
|
12255
|
+
if (!code) return DEFAULT;
|
|
12256
|
+
const key = code.toUpperCase();
|
|
12257
|
+
return MAP[key] ?? DEFAULT;
|
|
12258
|
+
}
|
|
12259
|
+
function detectBrowser(ua = navigator.userAgent) {
|
|
12260
|
+
const s = ua.toLowerCase();
|
|
12261
|
+
if (s.includes("edg/")) return "edge";
|
|
12262
|
+
if (s.includes("firefox")) return "firefox";
|
|
12263
|
+
if (s.includes("chrome") && !s.includes("edg/")) return "chrome";
|
|
12264
|
+
if (s.includes("safari") && !s.includes("chrome")) return "safari";
|
|
12265
|
+
return "unknown";
|
|
12266
|
+
}
|
|
12267
|
+
const CAMERA_INSTRUCTIONS = {
|
|
12268
|
+
chrome: "Clique no cadeado da barra de endereço → Configurações do site → Câmera → Permitir. Recarregue a página.",
|
|
12269
|
+
edge: "Clique no cadeado da barra de endereço → Permissões do site → Câmera → Permitir. Recarregue a página.",
|
|
12270
|
+
firefox: 'Clique no ícone da câmera bloqueada na barra de endereço e escolha "Permitir". Recarregue a página.',
|
|
12271
|
+
safari: "Menu Safari → Configurações → Sites → Câmera → Permitir para este site. Recarregue a página.",
|
|
12272
|
+
unknown: 'Abra as configurações do navegador, procure por "câmera" e permita o acesso para este site. Depois recarregue a página.'
|
|
12273
|
+
};
|
|
12274
|
+
function cameraInstructionFor(browser) {
|
|
12275
|
+
return CAMERA_INSTRUCTIONS[browser];
|
|
12276
|
+
}
|
|
12277
|
+
function classifyMediaError(err) {
|
|
12278
|
+
if (!err || typeof err !== "object") return "UNKNOWN";
|
|
12279
|
+
const name = (err.name ?? "").toString();
|
|
12280
|
+
if (name === "NotAllowedError" || name === "SecurityError") return "PERMISSION_DENIED";
|
|
12281
|
+
if (name === "NotFoundError" || name === "OverconstrainedError") return "NO_CAMERA";
|
|
12282
|
+
if (name === "NotReadableError" || name === "TrackStartError") return "IN_USE";
|
|
12283
|
+
return "UNKNOWN";
|
|
12284
|
+
}
|
|
12285
|
+
const STYLE_ID$1 = "neofaceid-state-views-styles";
|
|
12286
|
+
const CSS = `
|
|
12287
|
+
.neofaceid-root .nfid-state {
|
|
12288
|
+
display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px;
|
|
12289
|
+
padding: 8px 8px 4px;
|
|
12290
|
+
}
|
|
12291
|
+
.neofaceid-root .nfid-state h2 {
|
|
12292
|
+
margin: 6px 0 0; font-size: 20px; font-weight: 700; color: var(--nfid-text); line-height: 1.25;
|
|
12293
|
+
letter-spacing: -0.015em;
|
|
12294
|
+
}
|
|
12295
|
+
.neofaceid-root .nfid-state p {
|
|
12296
|
+
margin: 0; font-size: 14px; color: var(--nfid-text-muted); line-height: 1.5;
|
|
12297
|
+
}
|
|
12298
|
+
.neofaceid-root .nfid-state-actions {
|
|
12299
|
+
display: flex; flex-direction: column; gap: 10px; width: 100%; margin-top: 12px;
|
|
12300
|
+
}
|
|
12301
|
+
.neofaceid-root .nfid-state-actions--row {
|
|
12302
|
+
flex-direction: row; justify-content: center;
|
|
12303
|
+
}
|
|
12304
|
+
.neofaceid-root .nfid-state-icon-success {
|
|
12305
|
+
width: 64px; height: 64px; color: #0E9F6E;
|
|
12306
|
+
animation: nfidCelebrate 500ms cubic-bezier(.2,1.4,.4,1) both;
|
|
12307
|
+
}
|
|
12308
|
+
@keyframes nfidCelebrate {
|
|
12309
|
+
0% { transform: scale(0.6); opacity: 0; }
|
|
12310
|
+
60% { transform: scale(1.08); opacity: 1; }
|
|
12311
|
+
100% { transform: scale(1); }
|
|
12312
|
+
}
|
|
12313
|
+
.neofaceid-root .nfid-state-warn-icon { width: 56px; height: 56px; color: #F1BE00; }
|
|
12314
|
+
.neofaceid-root .nfid-state-cameraoff-icon { width: 56px; height: 56px; color: var(--nfid-text-muted); }
|
|
12315
|
+
.neofaceid-root .nfid-state-hints {
|
|
12316
|
+
display: flex; flex-direction: column; gap: 6px; margin-top: 8px; text-align: left; width: 100%;
|
|
12317
|
+
}
|
|
12318
|
+
.neofaceid-root .nfid-state-hint {
|
|
12319
|
+
display: flex; gap: 8px; align-items: flex-start; font-size: 13px; color: var(--nfid-text);
|
|
12320
|
+
padding: 8px 12px; background: var(--nfid-surface-muted); border-radius: 12px;
|
|
12321
|
+
}
|
|
12322
|
+
.neofaceid-root .nfid-state-hint::before { content: "•"; color: var(--nfid-action); font-weight: 700; }
|
|
12323
|
+
.neofaceid-root .nfid-state-attempt {
|
|
12324
|
+
font-size: 12px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
|
|
12325
|
+
color: var(--nfid-text-subtle);
|
|
12326
|
+
}
|
|
12327
|
+
.neofaceid-root .nfid-state-techcode {
|
|
12328
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
12329
|
+
font-size: 11px; color: var(--nfid-text-subtle); margin-top: 8px;
|
|
12330
|
+
}
|
|
12331
|
+
`;
|
|
12332
|
+
function useStateStyles() {
|
|
12333
|
+
useEffect(() => {
|
|
12334
|
+
injectThemeStyles$1();
|
|
12335
|
+
injectScopedStyles$1(STYLE_ID$1, CSS);
|
|
12336
|
+
}, []);
|
|
12337
|
+
}
|
|
12338
|
+
function AuthorizeSuccess({ appName, onContinue }) {
|
|
12339
|
+
useStateStyles();
|
|
12340
|
+
return /* @__PURE__ */ jsxs("div", { className: "nfid-state", role: "status", "aria-live": "polite", children: [
|
|
12341
|
+
/* @__PURE__ */ jsxs(
|
|
12342
|
+
"svg",
|
|
12343
|
+
{
|
|
12344
|
+
className: "nfid-state-icon-success",
|
|
12345
|
+
viewBox: "0 0 64 64",
|
|
12346
|
+
fill: "none",
|
|
12347
|
+
stroke: "currentColor",
|
|
12348
|
+
strokeWidth: "4",
|
|
12349
|
+
strokeLinecap: "round",
|
|
12350
|
+
strokeLinejoin: "round",
|
|
12351
|
+
"aria-hidden": "true",
|
|
12352
|
+
children: [
|
|
12353
|
+
/* @__PURE__ */ jsx("circle", { cx: "32", cy: "32", r: "28" }),
|
|
12354
|
+
/* @__PURE__ */ jsx("path", { d: "M20 33 L28 41 L44 24" })
|
|
12355
|
+
]
|
|
12356
|
+
}
|
|
12357
|
+
),
|
|
12358
|
+
/* @__PURE__ */ jsx("h2", { children: "Identidade confirmada" }),
|
|
12359
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
12360
|
+
"Você já pode continuar no ",
|
|
12361
|
+
appName,
|
|
12362
|
+
"."
|
|
12363
|
+
] }),
|
|
12364
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-state-actions", children: /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: onContinue, children: "Continuar" }) })
|
|
12365
|
+
] });
|
|
12366
|
+
}
|
|
12367
|
+
function formatHms(d) {
|
|
12368
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
12369
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
12370
|
+
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
12371
|
+
return `${hh}:${mm}:${ss}`;
|
|
12372
|
+
}
|
|
12373
|
+
function AuthorizeFailure({
|
|
12374
|
+
errorCode,
|
|
12375
|
+
attempt,
|
|
12376
|
+
maxAttempts,
|
|
12377
|
+
timestamp,
|
|
12378
|
+
onRetry,
|
|
12379
|
+
onFallback
|
|
12380
|
+
}) {
|
|
12381
|
+
useStateStyles();
|
|
12382
|
+
const copy = copyForErrorCode(errorCode);
|
|
12383
|
+
const stamp = timestamp ?? /* @__PURE__ */ new Date();
|
|
12384
|
+
return /* @__PURE__ */ jsxs("div", { className: "nfid-state", role: "alert", "aria-live": "assertive", children: [
|
|
12385
|
+
/* @__PURE__ */ jsxs(StatusPill, { tone: "attention", children: [
|
|
12386
|
+
"Tentativa ",
|
|
12387
|
+
attempt,
|
|
12388
|
+
" de ",
|
|
12389
|
+
maxAttempts
|
|
12390
|
+
] }),
|
|
12391
|
+
/* @__PURE__ */ jsxs(
|
|
12392
|
+
"svg",
|
|
12393
|
+
{
|
|
12394
|
+
className: "nfid-state-warn-icon",
|
|
12395
|
+
viewBox: "0 0 64 64",
|
|
12396
|
+
fill: "none",
|
|
12397
|
+
stroke: "currentColor",
|
|
12398
|
+
strokeWidth: "3",
|
|
12399
|
+
strokeLinecap: "round",
|
|
12400
|
+
strokeLinejoin: "round",
|
|
12401
|
+
"aria-hidden": "true",
|
|
12402
|
+
children: [
|
|
12403
|
+
/* @__PURE__ */ jsx("path", { d: "M32 8 L58 54 H6 Z" }),
|
|
12404
|
+
/* @__PURE__ */ jsx("path", { d: "M32 26 V38" }),
|
|
12405
|
+
/* @__PURE__ */ jsx("circle", { cx: "32", cy: "45", r: "2", fill: "currentColor" })
|
|
12406
|
+
]
|
|
12407
|
+
}
|
|
12408
|
+
),
|
|
12409
|
+
/* @__PURE__ */ jsx("h2", { children: copy.title }),
|
|
12410
|
+
/* @__PURE__ */ jsx("p", { children: copy.hint }),
|
|
12411
|
+
/* @__PURE__ */ jsxs("div", { className: "nfid-state-hints", "aria-label": "O que fazer", children: [
|
|
12412
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-state-hint", children: copy.actions[0] }),
|
|
12413
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-state-hint", children: copy.actions[1] })
|
|
12414
|
+
] }),
|
|
12415
|
+
/* @__PURE__ */ jsxs("div", { className: "nfid-state-actions", children: [
|
|
12416
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: onRetry, children: "Tentar de novo" }),
|
|
12417
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: onFallback, children: "Verificar de outro jeito" })
|
|
12418
|
+
] }),
|
|
12419
|
+
/* @__PURE__ */ jsxs("p", { className: "nfid-state-techcode", children: [
|
|
12420
|
+
(errorCode ?? "UNKNOWN").toUpperCase(),
|
|
12421
|
+
" · ",
|
|
12422
|
+
formatHms(stamp)
|
|
12423
|
+
] })
|
|
12424
|
+
] });
|
|
12425
|
+
}
|
|
12426
|
+
function AuthorizePermissionDenied({
|
|
12427
|
+
browser,
|
|
12428
|
+
onFallback,
|
|
12429
|
+
onCancel
|
|
12430
|
+
}) {
|
|
12431
|
+
useStateStyles();
|
|
12432
|
+
const detected = browser ?? detectBrowser();
|
|
12433
|
+
const instruction = cameraInstructionFor(detected);
|
|
12434
|
+
return /* @__PURE__ */ jsxs("div", { className: "nfid-state", role: "alert", "aria-live": "assertive", children: [
|
|
12435
|
+
/* @__PURE__ */ jsxs(
|
|
12436
|
+
"svg",
|
|
12437
|
+
{
|
|
12438
|
+
className: "nfid-state-cameraoff-icon",
|
|
12439
|
+
viewBox: "0 0 24 24",
|
|
12440
|
+
fill: "none",
|
|
12441
|
+
stroke: "currentColor",
|
|
12442
|
+
strokeWidth: "1.75",
|
|
12443
|
+
strokeLinecap: "round",
|
|
12444
|
+
strokeLinejoin: "round",
|
|
12445
|
+
"aria-hidden": "true",
|
|
12446
|
+
children: [
|
|
12447
|
+
/* @__PURE__ */ jsx("path", { d: "m3 3 18 18" }),
|
|
12448
|
+
/* @__PURE__ */ jsx("path", { d: "M20.66 15.34A2 2 0 0 0 22 13.5V7.5a2 2 0 0 0-3.13-1.65L15 8.5" }),
|
|
12449
|
+
/* @__PURE__ */ jsx("path", { d: "M9 6H4a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1" })
|
|
12450
|
+
]
|
|
12451
|
+
}
|
|
12452
|
+
),
|
|
12453
|
+
/* @__PURE__ */ jsx("h2", { children: "Câmera bloqueada" }),
|
|
12454
|
+
/* @__PURE__ */ jsx("p", { children: "Precisamos da câmera para confirmar que é você." }),
|
|
12455
|
+
/* @__PURE__ */ jsx("p", { style: { marginTop: 8 }, children: instruction }),
|
|
12456
|
+
/* @__PURE__ */ jsxs("div", { className: "nfid-state-actions", children: [
|
|
12457
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: onFallback, children: "Verificar de outro jeito" }),
|
|
12458
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: onCancel, children: "Agora não" })
|
|
12459
|
+
] })
|
|
12460
|
+
] });
|
|
12461
|
+
}
|
|
12156
12462
|
const STYLE_ID = "neofaceid-authorize-styles";
|
|
12157
12463
|
const GESTURE_TO_GLYPH = {
|
|
12158
12464
|
center: "center",
|
|
@@ -12186,6 +12492,7 @@ function formatCurrency(amount, locale) {
|
|
|
12186
12492
|
return `R$ ${amount.toFixed(2)}`;
|
|
12187
12493
|
}
|
|
12188
12494
|
}
|
|
12495
|
+
const MAX_ATTEMPTS = 3;
|
|
12189
12496
|
function AuthorizeModalComponent({
|
|
12190
12497
|
applicationToken,
|
|
12191
12498
|
appName,
|
|
@@ -12201,6 +12508,10 @@ function AuthorizeModalComponent({
|
|
|
12201
12508
|
const [progress, setProgress] = useState(0);
|
|
12202
12509
|
const [currentGesture, setCurrentGesture] = useState(null);
|
|
12203
12510
|
const [phase, setPhase] = useState("preparing");
|
|
12511
|
+
const [attempt, setAttempt] = useState(1);
|
|
12512
|
+
const [failureCode, setFailureCode] = useState(void 0);
|
|
12513
|
+
const [failureAt, setFailureAt] = useState(void 0);
|
|
12514
|
+
const [runCounter, setRunCounter] = useState(0);
|
|
12204
12515
|
const cancelRef = useRef(false);
|
|
12205
12516
|
const locale = getLocale();
|
|
12206
12517
|
const headerAppName = appName ?? getAppName() ?? "sua aplicação";
|
|
@@ -12237,11 +12548,27 @@ function AuthorizeModalComponent({
|
|
|
12237
12548
|
}, []);
|
|
12238
12549
|
useEffect(() => {
|
|
12239
12550
|
let stream = null;
|
|
12551
|
+
cancelRef.current = false;
|
|
12552
|
+
setPhase("preparing");
|
|
12553
|
+
setProgress(0);
|
|
12554
|
+
setCurrentGesture(null);
|
|
12240
12555
|
async function run() {
|
|
12241
12556
|
try {
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12557
|
+
try {
|
|
12558
|
+
stream = await navigator.mediaDevices.getUserMedia({
|
|
12559
|
+
video: { facingMode: "user", width: { ideal: 1280 }, height: { ideal: 720 } }
|
|
12560
|
+
});
|
|
12561
|
+
} catch (mediaErr) {
|
|
12562
|
+
const kind = classifyMediaError(mediaErr);
|
|
12563
|
+
if (kind === "PERMISSION_DENIED") {
|
|
12564
|
+
setPhase("permission-denied");
|
|
12565
|
+
return;
|
|
12566
|
+
}
|
|
12567
|
+
throw new NeoFaceError(
|
|
12568
|
+
kind === "NO_CAMERA" ? "Câmera não encontrada" : kind === "IN_USE" ? "Câmera em uso por outro app" : "Falha ao acessar a câmera",
|
|
12569
|
+
ErrorType.CAMERA_ERROR
|
|
12570
|
+
);
|
|
12571
|
+
}
|
|
12245
12572
|
if (videoRef.current) {
|
|
12246
12573
|
videoRef.current.srcObject = stream;
|
|
12247
12574
|
videoRef.current.play().catch(() => {
|
|
@@ -12262,13 +12589,23 @@ function AuthorizeModalComponent({
|
|
|
12262
12589
|
return frame ? [frame] : [];
|
|
12263
12590
|
}
|
|
12264
12591
|
});
|
|
12265
|
-
|
|
12592
|
+
if (stream) stream.getTracks().forEach((t) => t.stop());
|
|
12593
|
+
stream = null;
|
|
12594
|
+
if (result.success === false || result.liveness_passed === false) {
|
|
12595
|
+
setFailureCode("LIVENESS_LOW");
|
|
12596
|
+
setFailureAt(/* @__PURE__ */ new Date());
|
|
12597
|
+
setPhase("failure");
|
|
12598
|
+
return;
|
|
12599
|
+
}
|
|
12600
|
+
setPhase("success");
|
|
12266
12601
|
if (onSuccess) onSuccess(result);
|
|
12267
|
-
onClose();
|
|
12268
12602
|
} catch (err) {
|
|
12603
|
+
if (cancelRef.current) return;
|
|
12269
12604
|
const nfe = err instanceof NeoFaceError ? err : new NeoFaceError(err instanceof Error ? err.message : "Falha", ErrorType.UNKNOWN);
|
|
12605
|
+
setFailureCode(nfe.type);
|
|
12606
|
+
setFailureAt(/* @__PURE__ */ new Date());
|
|
12607
|
+
setPhase("failure");
|
|
12270
12608
|
if (onError) onError(nfe);
|
|
12271
|
-
onClose();
|
|
12272
12609
|
} finally {
|
|
12273
12610
|
if (stream) stream.getTracks().forEach((t) => t.stop());
|
|
12274
12611
|
}
|
|
@@ -12278,14 +12615,55 @@ function AuthorizeModalComponent({
|
|
|
12278
12615
|
cancelRef.current = true;
|
|
12279
12616
|
if (stream) stream.getTracks().forEach((t) => t.stop());
|
|
12280
12617
|
};
|
|
12281
|
-
}, []);
|
|
12618
|
+
}, [runCounter]);
|
|
12282
12619
|
const handleClose = () => {
|
|
12283
12620
|
cancelRef.current = true;
|
|
12284
12621
|
if (onCancel) onCancel();
|
|
12285
12622
|
onClose();
|
|
12286
12623
|
};
|
|
12624
|
+
const handleRetry = () => {
|
|
12625
|
+
if (attempt >= MAX_ATTEMPTS) {
|
|
12626
|
+
handleClose();
|
|
12627
|
+
return;
|
|
12628
|
+
}
|
|
12629
|
+
setAttempt((a) => a + 1);
|
|
12630
|
+
setFailureCode(void 0);
|
|
12631
|
+
setFailureAt(void 0);
|
|
12632
|
+
setRunCounter((c) => c + 1);
|
|
12633
|
+
};
|
|
12634
|
+
const handleFallback = () => {
|
|
12635
|
+
cancelRef.current = true;
|
|
12636
|
+
if (onError) {
|
|
12637
|
+
onError(
|
|
12638
|
+
new NeoFaceError(
|
|
12639
|
+
"Fluxo alternativo solicitado pelo usuário",
|
|
12640
|
+
ErrorType.CONSENT_DENIED
|
|
12641
|
+
)
|
|
12642
|
+
);
|
|
12643
|
+
}
|
|
12644
|
+
onClose();
|
|
12645
|
+
};
|
|
12287
12646
|
const gestureKey = currentGesture ? GESTURE_TO_GLYPH[currentGesture.gesture_key] ?? "center" : "center";
|
|
12288
12647
|
const instruction = currentGesture ? GESTURE_TO_INSTRUCTION[currentGesture.gesture_key] ?? "Siga a instrução" : "Preparando a câmera…";
|
|
12648
|
+
if (phase === "success") {
|
|
12649
|
+
return /* @__PURE__ */ jsx(Sheet, { open: true, dismissOnOverlay: false, ariaLabel: "Identidade confirmada", children: /* @__PURE__ */ jsx(AuthorizeSuccess, { appName: headerAppName, onContinue: onClose }) });
|
|
12650
|
+
}
|
|
12651
|
+
if (phase === "permission-denied") {
|
|
12652
|
+
return /* @__PURE__ */ jsx(Sheet, { open: true, dismissOnOverlay: false, ariaLabel: "Câmera bloqueada", children: /* @__PURE__ */ jsx(AuthorizePermissionDenied, { onFallback: handleFallback, onCancel: handleClose }) });
|
|
12653
|
+
}
|
|
12654
|
+
if (phase === "failure") {
|
|
12655
|
+
return /* @__PURE__ */ jsx(Sheet, { open: true, dismissOnOverlay: false, ariaLabel: "Não foi possível confirmar", children: /* @__PURE__ */ jsx(
|
|
12656
|
+
AuthorizeFailure,
|
|
12657
|
+
{
|
|
12658
|
+
errorCode: failureCode,
|
|
12659
|
+
attempt,
|
|
12660
|
+
maxAttempts: MAX_ATTEMPTS,
|
|
12661
|
+
timestamp: failureAt,
|
|
12662
|
+
onRetry: handleRetry,
|
|
12663
|
+
onFallback: handleFallback
|
|
12664
|
+
}
|
|
12665
|
+
) });
|
|
12666
|
+
}
|
|
12289
12667
|
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
12668
|
/* @__PURE__ */ jsx(
|
|
12291
12669
|
"button",
|
|
@@ -12557,7 +12935,7 @@ class DocumentCaptureModal {
|
|
|
12557
12935
|
</div>
|
|
12558
12936
|
<div class="neoface-doc-instruction">
|
|
12559
12937
|
<svg class="neoface-doc-instruction-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
|
12560
|
-
<span>
|
|
12938
|
+
<span>Sem reflexo do flash sobre o texto</span>
|
|
12561
12939
|
</div>
|
|
12562
12940
|
</div>
|
|
12563
12941
|
</div>
|
|
@@ -12613,15 +12991,16 @@ class DocumentCaptureModal {
|
|
|
12613
12991
|
<div class="neoface-doc-body">
|
|
12614
12992
|
<div class="neoface-doc-preview-single">
|
|
12615
12993
|
<span class="neoface-doc-preview-label">${label}</span>
|
|
12616
|
-
<img class="neoface-doc-preview-img neoface-doc-preview-current" />
|
|
12994
|
+
<img class="neoface-doc-preview-img neoface-doc-preview-current" alt="Prévia do documento capturado" />
|
|
12617
12995
|
</div>
|
|
12618
|
-
|
|
12996
|
+
|
|
12997
|
+
<h3 class="neoface-doc-preview-question" id="neoface-doc-preview-question">Está legível?</h3>
|
|
12619
12998
|
<div class="neoface-doc-preview-hint">
|
|
12620
12999
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
|
|
12621
|
-
<span>
|
|
13000
|
+
<span>Confira se dá para ler nome, número e data sem esforço.</span>
|
|
12622
13001
|
</div>
|
|
12623
13002
|
</div>
|
|
12624
|
-
|
|
13003
|
+
|
|
12625
13004
|
<div class="neoface-doc-footer">
|
|
12626
13005
|
<button class="neoface-doc-btn neoface-doc-btn-secondary neoface-doc-retake-btn">
|
|
12627
13006
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
@@ -12630,11 +13009,11 @@ class DocumentCaptureModal {
|
|
|
12630
13009
|
</svg>
|
|
12631
13010
|
Refazer
|
|
12632
13011
|
</button>
|
|
12633
|
-
<button class="neoface-doc-btn neoface-doc-btn-
|
|
13012
|
+
<button class="neoface-doc-btn neoface-doc-btn-primary neoface-doc-confirm-btn">
|
|
12634
13013
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
12635
13014
|
<path d="M20 6L9 17l-5-5"/>
|
|
12636
13015
|
</svg>
|
|
12637
|
-
${isLastStep ? "
|
|
13016
|
+
${isLastStep ? "Sim, enviar" : "Sim, próximo"}
|
|
12638
13017
|
</button>
|
|
12639
13018
|
</div>
|
|
12640
13019
|
|
|
@@ -13051,8 +13430,8 @@ class DocumentCaptureModal {
|
|
|
13051
13430
|
}
|
|
13052
13431
|
|
|
13053
13432
|
.neoface-doc-select-option:hover {
|
|
13054
|
-
background: rgba(0,
|
|
13055
|
-
border-color: rgba(0,
|
|
13433
|
+
background: rgba(0, 145, 246, 0.1);
|
|
13434
|
+
border-color: rgba(0, 145, 246, 0.4);
|
|
13056
13435
|
transform: translateX(4px);
|
|
13057
13436
|
}
|
|
13058
13437
|
|
|
@@ -13062,7 +13441,7 @@ class DocumentCaptureModal {
|
|
|
13062
13441
|
justify-content: center;
|
|
13063
13442
|
width: 44px;
|
|
13064
13443
|
height: 44px;
|
|
13065
|
-
background: rgba(0,
|
|
13444
|
+
background: rgba(0, 145, 246, 0.15);
|
|
13066
13445
|
border-radius: 12px;
|
|
13067
13446
|
color: #0091F6;
|
|
13068
13447
|
}
|
|
@@ -13098,8 +13477,8 @@ class DocumentCaptureModal {
|
|
|
13098
13477
|
align-items: center;
|
|
13099
13478
|
justify-content: center;
|
|
13100
13479
|
padding: 14px 16px;
|
|
13101
|
-
background: rgba(0,
|
|
13102
|
-
border: 1px solid rgba(0,
|
|
13480
|
+
background: rgba(0, 145, 246, 0.08);
|
|
13481
|
+
border: 1px solid rgba(0, 145, 246, 0.15);
|
|
13103
13482
|
border-radius: 10px;
|
|
13104
13483
|
color: rgba(255, 255, 255, 0.8);
|
|
13105
13484
|
font-size: 13px;
|
|
@@ -13116,13 +13495,13 @@ class DocumentCaptureModal {
|
|
|
13116
13495
|
flex-shrink: 0;
|
|
13117
13496
|
}
|
|
13118
13497
|
|
|
13119
|
-
/* Camera */
|
|
13498
|
+
/* Camera — ISO/IEC 7810 ID-1 (85.60 × 53.98 mm ≈ 1.586:1) */
|
|
13120
13499
|
.neoface-doc-camera-container {
|
|
13121
13500
|
position: relative;
|
|
13122
13501
|
background: #000;
|
|
13123
13502
|
border-radius: 16px;
|
|
13124
13503
|
overflow: hidden;
|
|
13125
|
-
aspect-ratio:
|
|
13504
|
+
aspect-ratio: 1.586 / 1;
|
|
13126
13505
|
}
|
|
13127
13506
|
|
|
13128
13507
|
.neoface-doc-video {
|
|
@@ -13144,20 +13523,19 @@ class DocumentCaptureModal {
|
|
|
13144
13523
|
pointer-events: none;
|
|
13145
13524
|
}
|
|
13146
13525
|
|
|
13526
|
+
/* Moldura Focus Frame — proporção ID-1 (1.586:1), sem borda contínua. */
|
|
13147
13527
|
.neoface-doc-frame {
|
|
13148
|
-
width:
|
|
13149
|
-
|
|
13528
|
+
width: 82%;
|
|
13529
|
+
aspect-ratio: 1.586 / 1;
|
|
13150
13530
|
position: relative;
|
|
13151
|
-
border: 2px dashed rgba(0, 200, 255, 0.5);
|
|
13152
13531
|
border-radius: 12px;
|
|
13153
|
-
background: rgba(0, 200, 255, 0.03);
|
|
13154
13532
|
}
|
|
13155
|
-
|
|
13533
|
+
|
|
13156
13534
|
.neoface-doc-corner {
|
|
13157
13535
|
position: absolute;
|
|
13158
13536
|
width: 28px;
|
|
13159
13537
|
height: 28px;
|
|
13160
|
-
border-color: #
|
|
13538
|
+
border-color: var(--nfid-action, #0059C4);
|
|
13161
13539
|
border-style: solid;
|
|
13162
13540
|
}
|
|
13163
13541
|
|
|
@@ -13246,23 +13624,31 @@ class DocumentCaptureModal {
|
|
|
13246
13624
|
width: 75%;
|
|
13247
13625
|
height: auto;
|
|
13248
13626
|
border-radius: 12px;
|
|
13249
|
-
border: 2px solid rgba(0,
|
|
13627
|
+
border: 2px solid rgba(0, 145, 246, 0.3);
|
|
13250
13628
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
13251
13629
|
}
|
|
13252
13630
|
|
|
13631
|
+
.neoface-doc-preview-question {
|
|
13632
|
+
margin: 12px 0 4px;
|
|
13633
|
+
font-size: 17px;
|
|
13634
|
+
font-weight: 700;
|
|
13635
|
+
color: var(--nfid-text, #0A1320);
|
|
13636
|
+
text-align: center;
|
|
13637
|
+
}
|
|
13638
|
+
|
|
13253
13639
|
.neoface-doc-preview-hint {
|
|
13254
13640
|
display: flex;
|
|
13255
13641
|
align-items: center;
|
|
13256
13642
|
gap: 10px;
|
|
13257
13643
|
padding: 12px 16px;
|
|
13258
|
-
background: rgba(0,
|
|
13259
|
-
border: 1px solid rgba(0,
|
|
13644
|
+
background: rgba(0, 145, 246, 0.08);
|
|
13645
|
+
border: 1px solid rgba(0, 145, 246, 0.15);
|
|
13260
13646
|
border-radius: 10px;
|
|
13261
13647
|
font-size: 13px;
|
|
13262
13648
|
color: rgba(255, 255, 255, 0.8);
|
|
13263
13649
|
margin-top: 8px;
|
|
13264
13650
|
}
|
|
13265
|
-
|
|
13651
|
+
|
|
13266
13652
|
.neoface-doc-preview-hint svg {
|
|
13267
13653
|
color: #0091F6;
|
|
13268
13654
|
flex-shrink: 0;
|
|
@@ -13297,7 +13683,7 @@ class DocumentCaptureModal {
|
|
|
13297
13683
|
|
|
13298
13684
|
.neoface-doc-btn-primary:hover {
|
|
13299
13685
|
transform: translateY(-2px);
|
|
13300
|
-
box-shadow: 0 6px 20px rgba(0,
|
|
13686
|
+
box-shadow: 0 6px 20px rgba(0, 145, 246, 0.4);
|
|
13301
13687
|
}
|
|
13302
13688
|
|
|
13303
13689
|
.neoface-doc-btn-success {
|