@neofaceid/web-sdk 1.29.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 +123 -9
- package/dist/neoface-id-sdk.es.js +919 -309
- 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";
|
|
@@ -4342,21 +4342,218 @@ object({
|
|
|
4342
4342
|
task_id: string().optional(),
|
|
4343
4343
|
status: string().optional()
|
|
4344
4344
|
});
|
|
4345
|
+
const BLUE = {
|
|
4346
|
+
400: "#00B0F8",
|
|
4347
|
+
500: "#0091F6",
|
|
4348
|
+
700: "#0059C4"
|
|
4349
|
+
};
|
|
4350
|
+
const GOLD = {
|
|
4351
|
+
500: "#F1BE00"
|
|
4352
|
+
};
|
|
4353
|
+
const INK = {
|
|
4354
|
+
25: "#F7F9FC",
|
|
4355
|
+
50: "#F1F5FA",
|
|
4356
|
+
100: "#E6ECF4",
|
|
4357
|
+
300: "#AFBDCE",
|
|
4358
|
+
400: "#8496AD",
|
|
4359
|
+
500: "#617489",
|
|
4360
|
+
600: "#48586B",
|
|
4361
|
+
800: "#1E2B3C",
|
|
4362
|
+
900: "#111C2B",
|
|
4363
|
+
950: "#0A1320"
|
|
4364
|
+
};
|
|
4365
|
+
const LIGHT_TOKENS = {
|
|
4366
|
+
ground: INK[25],
|
|
4367
|
+
surface: "#FFFFFF",
|
|
4368
|
+
surfaceMuted: INK[50],
|
|
4369
|
+
line: INK[100],
|
|
4370
|
+
text: INK[950],
|
|
4371
|
+
textMuted: INK[600],
|
|
4372
|
+
textSubtle: INK[500],
|
|
4373
|
+
action: BLUE[700],
|
|
4374
|
+
actionText: "#FFFFFF",
|
|
4375
|
+
accent: GOLD[500],
|
|
4376
|
+
overlay: "rgba(10,19,32,.55)",
|
|
4377
|
+
focusRing: BLUE[700]
|
|
4378
|
+
};
|
|
4379
|
+
const DARK_TOKENS = {
|
|
4380
|
+
ground: INK[950],
|
|
4381
|
+
surface: INK[900],
|
|
4382
|
+
surfaceMuted: INK[800],
|
|
4383
|
+
line: "#22334D",
|
|
4384
|
+
text: "#EEF3F9",
|
|
4385
|
+
textMuted: INK[300],
|
|
4386
|
+
textSubtle: INK[400],
|
|
4387
|
+
action: BLUE[500],
|
|
4388
|
+
actionText: "#FFFFFF",
|
|
4389
|
+
accent: GOLD[500],
|
|
4390
|
+
overlay: "rgba(10,19,32,.72)",
|
|
4391
|
+
focusRing: BLUE[400]
|
|
4392
|
+
};
|
|
4393
|
+
function contrastRatio(hexA, hexB) {
|
|
4394
|
+
const lumA = luminance(hexA);
|
|
4395
|
+
const lumB = luminance(hexB);
|
|
4396
|
+
const [hi, lo] = lumA > lumB ? [lumA, lumB] : [lumB, lumA];
|
|
4397
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
4398
|
+
}
|
|
4399
|
+
function luminance(hex) {
|
|
4400
|
+
const [r, g, b] = parseHex(hex).map((v) => {
|
|
4401
|
+
const s = v / 255;
|
|
4402
|
+
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
4403
|
+
});
|
|
4404
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
4405
|
+
}
|
|
4406
|
+
function parseHex(hex) {
|
|
4407
|
+
let h = hex.trim().replace("#", "");
|
|
4408
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
4409
|
+
if (!/^[0-9a-fA-F]{6}$/.test(h)) return [0, 0, 0];
|
|
4410
|
+
return [
|
|
4411
|
+
parseInt(h.slice(0, 2), 16),
|
|
4412
|
+
parseInt(h.slice(2, 4), 16),
|
|
4413
|
+
parseInt(h.slice(4, 6), 16)
|
|
4414
|
+
];
|
|
4415
|
+
}
|
|
4416
|
+
const ALLOWED_RADIUS = [8, 16, 24];
|
|
4417
|
+
function resolveTheme(options = {}) {
|
|
4418
|
+
const mode = resolveMode(options.theme);
|
|
4419
|
+
const tokens = mode === "dark" ? { ...DARK_TOKENS } : { ...LIGHT_TOKENS };
|
|
4420
|
+
let radius = 16;
|
|
4421
|
+
if (options.radius !== void 0) {
|
|
4422
|
+
if (ALLOWED_RADIUS.includes(options.radius)) {
|
|
4423
|
+
radius = options.radius;
|
|
4424
|
+
} else {
|
|
4425
|
+
console.warn(
|
|
4426
|
+
`[NeoFaceID SDK] radius ${options.radius} inválido — permitidos: 8, 16, 24. Usando 16.`
|
|
4427
|
+
);
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
let accent = tokens.action;
|
|
4431
|
+
let accentFellBack = false;
|
|
4432
|
+
if (options.accent) {
|
|
4433
|
+
const ratio = contrastRatio(options.accent, "#FFFFFF");
|
|
4434
|
+
if (ratio >= 4.5) {
|
|
4435
|
+
accent = options.accent;
|
|
4436
|
+
} else {
|
|
4437
|
+
accentFellBack = true;
|
|
4438
|
+
console.warn(
|
|
4439
|
+
`[NeoFaceID SDK] accent ${options.accent} reprova AA vs branco (${ratio.toFixed(2)}:1). Usando ${BLUE[700]}.`
|
|
4440
|
+
);
|
|
4441
|
+
accent = BLUE[700];
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
return { mode, tokens: { ...tokens, action: accent }, radius, accent, accentFellBack };
|
|
4445
|
+
}
|
|
4446
|
+
function resolveMode(theme) {
|
|
4447
|
+
if (theme === "dark") return "dark";
|
|
4448
|
+
if (theme === "light") return "light";
|
|
4449
|
+
if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
|
|
4450
|
+
if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark";
|
|
4451
|
+
}
|
|
4452
|
+
return "light";
|
|
4453
|
+
}
|
|
4454
|
+
const CSS_VAR = {
|
|
4455
|
+
ground: "--nfid-ground",
|
|
4456
|
+
surface: "--nfid-surface",
|
|
4457
|
+
surfaceMuted: "--nfid-surface-muted",
|
|
4458
|
+
line: "--nfid-line",
|
|
4459
|
+
text: "--nfid-text",
|
|
4460
|
+
textMuted: "--nfid-text-muted",
|
|
4461
|
+
textSubtle: "--nfid-text-subtle",
|
|
4462
|
+
action: "--nfid-action",
|
|
4463
|
+
actionText: "--nfid-action-text",
|
|
4464
|
+
accent: "--nfid-accent",
|
|
4465
|
+
overlay: "--nfid-overlay",
|
|
4466
|
+
focusRing: "--nfid-focus-ring",
|
|
4467
|
+
radius: "--nfid-radius"
|
|
4468
|
+
};
|
|
4469
|
+
const INJECTED_STYLE_ID = "neofaceid-focus-frame-tokens";
|
|
4470
|
+
function injectThemeStyles$1(options = {}) {
|
|
4471
|
+
const resolved = resolveTheme(options);
|
|
4472
|
+
if (typeof document === "undefined") return resolved;
|
|
4473
|
+
const css = buildRootCss(resolved);
|
|
4474
|
+
const existing = document.getElementById(INJECTED_STYLE_ID);
|
|
4475
|
+
if (existing) {
|
|
4476
|
+
if (existing.textContent !== css) existing.textContent = css;
|
|
4477
|
+
return resolved;
|
|
4478
|
+
}
|
|
4479
|
+
const style = document.createElement("style");
|
|
4480
|
+
style.id = INJECTED_STYLE_ID;
|
|
4481
|
+
style.textContent = css;
|
|
4482
|
+
document.head.appendChild(style);
|
|
4483
|
+
return resolved;
|
|
4484
|
+
}
|
|
4485
|
+
function buildRootCss(theme) {
|
|
4486
|
+
const t = theme.tokens;
|
|
4487
|
+
return `.neofaceid-root {
|
|
4488
|
+
${CSS_VAR.ground}: ${t.ground};
|
|
4489
|
+
${CSS_VAR.surface}: ${t.surface};
|
|
4490
|
+
${CSS_VAR.surfaceMuted}: ${t.surfaceMuted};
|
|
4491
|
+
${CSS_VAR.line}: ${t.line};
|
|
4492
|
+
${CSS_VAR.text}: ${t.text};
|
|
4493
|
+
${CSS_VAR.textMuted}: ${t.textMuted};
|
|
4494
|
+
${CSS_VAR.textSubtle}: ${t.textSubtle};
|
|
4495
|
+
${CSS_VAR.action}: ${t.action};
|
|
4496
|
+
${CSS_VAR.actionText}: ${t.actionText};
|
|
4497
|
+
${CSS_VAR.accent}: ${t.accent};
|
|
4498
|
+
${CSS_VAR.overlay}: ${t.overlay};
|
|
4499
|
+
${CSS_VAR.focusRing}: ${t.focusRing};
|
|
4500
|
+
${CSS_VAR.radius}: ${theme.radius}px;
|
|
4501
|
+
color: var(${CSS_VAR.text});
|
|
4502
|
+
font-family: inherit;
|
|
4503
|
+
}
|
|
4504
|
+
.neofaceid-root :focus-visible {
|
|
4505
|
+
outline: 2px solid var(${CSS_VAR.focusRing});
|
|
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
|
+
}
|
|
4516
|
+
}`;
|
|
4517
|
+
}
|
|
4518
|
+
function injectScopedStyles$1(id, css) {
|
|
4519
|
+
if (typeof document === "undefined") return;
|
|
4520
|
+
const existing = document.getElementById(id);
|
|
4521
|
+
if (existing) {
|
|
4522
|
+
if (existing.textContent !== css) existing.textContent = css;
|
|
4523
|
+
return;
|
|
4524
|
+
}
|
|
4525
|
+
const style = document.createElement("style");
|
|
4526
|
+
style.id = id;
|
|
4527
|
+
style.textContent = css;
|
|
4528
|
+
document.head.appendChild(style);
|
|
4529
|
+
}
|
|
4345
4530
|
const __vite_import_meta_env__ = {};
|
|
4346
4531
|
const ENVIRONMENT_URLS = {
|
|
4347
4532
|
development: "http://localhost:8000",
|
|
4348
4533
|
sandbox: "https://sandbox-core.neofaceid.com",
|
|
4349
4534
|
production: "https://core.neofaceid.com.br"
|
|
4350
4535
|
};
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4536
|
+
const DEFAULT_LOCALE = "pt-BR";
|
|
4537
|
+
const DEFAULT_RADIUS = 16;
|
|
4538
|
+
const DEFAULT_THEME = "light";
|
|
4539
|
+
const ALLOWED_RADII = [8, 16, 24];
|
|
4540
|
+
function makeDefaultConfig() {
|
|
4541
|
+
return {
|
|
4542
|
+
baseUrl: ENVIRONMENT_URLS.sandbox,
|
|
4543
|
+
applicationToken: null,
|
|
4544
|
+
environment: "sandbox",
|
|
4545
|
+
initialized: false,
|
|
4546
|
+
appName: null,
|
|
4547
|
+
accent: null,
|
|
4548
|
+
radius: DEFAULT_RADIUS,
|
|
4549
|
+
theme: DEFAULT_THEME,
|
|
4550
|
+
locale: DEFAULT_LOCALE,
|
|
4551
|
+
resolvedTheme: null
|
|
4552
|
+
};
|
|
4553
|
+
}
|
|
4554
|
+
let globalConfig = makeDefaultConfig();
|
|
4358
4555
|
function init(options = {}) {
|
|
4359
|
-
const { environment, baseUrl, applicationToken } = options;
|
|
4556
|
+
const { environment, baseUrl, applicationToken, appName, accent, radius, theme, locale } = options;
|
|
4360
4557
|
if (baseUrl) {
|
|
4361
4558
|
globalConfig.baseUrl = baseUrl;
|
|
4362
4559
|
globalConfig.environment = "custom";
|
|
@@ -4383,9 +4580,40 @@ function init(options = {}) {
|
|
|
4383
4580
|
"[NeoFaceID SDK] applicationToken vazio em init() — 401 esperado em chamadas autenticadas."
|
|
4384
4581
|
);
|
|
4385
4582
|
}
|
|
4583
|
+
if (appName && appName.trim()) {
|
|
4584
|
+
globalConfig.appName = appName.trim();
|
|
4585
|
+
} else if (appName !== void 0) {
|
|
4586
|
+
console.warn(
|
|
4587
|
+
'[NeoFaceID SDK] init({ appName }) vazio — modais cairão para o fallback "sua aplicação".'
|
|
4588
|
+
);
|
|
4589
|
+
}
|
|
4590
|
+
if (radius !== void 0) {
|
|
4591
|
+
if (ALLOWED_RADII.includes(radius)) {
|
|
4592
|
+
globalConfig.radius = radius;
|
|
4593
|
+
} else {
|
|
4594
|
+
console.warn(
|
|
4595
|
+
`[NeoFaceID SDK] radius ${radius} inválido em init() — permitidos: 8, 16, 24. Usando 16.`
|
|
4596
|
+
);
|
|
4597
|
+
globalConfig.radius = DEFAULT_RADIUS;
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
if (theme) globalConfig.theme = theme;
|
|
4601
|
+
if (locale) globalConfig.locale = locale;
|
|
4602
|
+
if (accent !== void 0) globalConfig.accent = accent;
|
|
4603
|
+
const resolved = resolveTheme({
|
|
4604
|
+
accent: globalConfig.accent ?? void 0,
|
|
4605
|
+
radius: globalConfig.radius,
|
|
4606
|
+
theme: globalConfig.theme
|
|
4607
|
+
});
|
|
4608
|
+
globalConfig.resolvedTheme = resolved;
|
|
4609
|
+
injectThemeStyles$1({
|
|
4610
|
+
accent: globalConfig.accent ?? void 0,
|
|
4611
|
+
radius: globalConfig.radius,
|
|
4612
|
+
theme: globalConfig.theme
|
|
4613
|
+
});
|
|
4386
4614
|
globalConfig.initialized = true;
|
|
4387
4615
|
console.log(
|
|
4388
|
-
`[NeoFaceID SDK] Inicializado
|
|
4616
|
+
`[NeoFaceID SDK] Inicializado — Ambiente: ${globalConfig.environment}, URL: ${globalConfig.baseUrl}, appName: ${globalConfig.appName ?? "(vazio)"}, theme: ${resolved.mode}, radius: ${globalConfig.radius}`
|
|
4389
4617
|
);
|
|
4390
4618
|
}
|
|
4391
4619
|
function getBaseUrl() {
|
|
@@ -4406,6 +4634,25 @@ function isInitialized() {
|
|
|
4406
4634
|
function getConfig() {
|
|
4407
4635
|
return { ...globalConfig };
|
|
4408
4636
|
}
|
|
4637
|
+
function getAppName() {
|
|
4638
|
+
return globalConfig.appName;
|
|
4639
|
+
}
|
|
4640
|
+
function getAccent() {
|
|
4641
|
+
return globalConfig.accent;
|
|
4642
|
+
}
|
|
4643
|
+
function getRadius() {
|
|
4644
|
+
return globalConfig.radius;
|
|
4645
|
+
}
|
|
4646
|
+
function getTheme() {
|
|
4647
|
+
return globalConfig.theme;
|
|
4648
|
+
}
|
|
4649
|
+
function getResolvedThemeMode() {
|
|
4650
|
+
var _a2;
|
|
4651
|
+
return ((_a2 = globalConfig.resolvedTheme) == null ? void 0 : _a2.mode) ?? (globalConfig.theme === "dark" ? "dark" : "light");
|
|
4652
|
+
}
|
|
4653
|
+
function getLocale() {
|
|
4654
|
+
return globalConfig.locale;
|
|
4655
|
+
}
|
|
4409
4656
|
const getApiBaseUrl = () => getBaseUrl();
|
|
4410
4657
|
const REQUEST_TIMEOUT = 1e4;
|
|
4411
4658
|
const ensureSecureContext = () => {
|
|
@@ -5897,251 +6144,75 @@ const identifyPersonAsync = async (image, applicationToken, options = {}) => {
|
|
|
5897
6144
|
return { personFound: false };
|
|
5898
6145
|
}
|
|
5899
6146
|
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
5900
|
-
}
|
|
5901
|
-
throw new NeoFaceError("Timed out waiting for identification", ErrorType.NETWORK_ERROR);
|
|
5902
|
-
};
|
|
5903
|
-
async function requestPasswordReset(email2, applicationToken) {
|
|
5904
|
-
const baseUrl = getBaseUrl();
|
|
5905
|
-
const response = await fetch(`${baseUrl}/api/v1/user/password/reset/request/`, {
|
|
5906
|
-
method: "POST",
|
|
5907
|
-
headers: {
|
|
5908
|
-
"Content-Type": "application/json",
|
|
5909
|
-
"X-App-Token": applicationToken
|
|
5910
|
-
},
|
|
5911
|
-
body: JSON.stringify({ email: email2 })
|
|
5912
|
-
});
|
|
5913
|
-
if (!response.ok) {
|
|
5914
|
-
const errorData = await response.json();
|
|
5915
|
-
throw new NeoFaceError(
|
|
5916
|
-
errorData.message || "Erro ao solicitar recuperação de senha",
|
|
5917
|
-
ErrorType.API_ERROR
|
|
5918
|
-
);
|
|
5919
|
-
}
|
|
5920
|
-
return response.json();
|
|
5921
|
-
}
|
|
5922
|
-
async function confirmPasswordReset(token, new_password) {
|
|
5923
|
-
const baseUrl = getBaseUrl();
|
|
5924
|
-
const response = await fetch(`${baseUrl}/api/v1/user/password/reset/confirm/`, {
|
|
5925
|
-
method: "POST",
|
|
5926
|
-
headers: {
|
|
5927
|
-
"Content-Type": "application/json"
|
|
5928
|
-
},
|
|
5929
|
-
body: JSON.stringify({ token, new_password })
|
|
5930
|
-
});
|
|
5931
|
-
if (!response.ok) {
|
|
5932
|
-
const errorData = await response.json();
|
|
5933
|
-
throw new NeoFaceError(
|
|
5934
|
-
errorData.error || errorData.message || "Erro ao redefinir senha",
|
|
5935
|
-
ErrorType.API_ERROR
|
|
5936
|
-
);
|
|
5937
|
-
}
|
|
5938
|
-
return response.json();
|
|
5939
|
-
}
|
|
5940
|
-
const api = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
5941
|
-
__proto__: null,
|
|
5942
|
-
checkUserExistence,
|
|
5943
|
-
completeOnboarding,
|
|
5944
|
-
completeOnboardingWithData,
|
|
5945
|
-
confirmPasswordReset,
|
|
5946
|
-
getOnboardingDetails,
|
|
5947
|
-
getTaskStatus,
|
|
5948
|
-
identifyPerson,
|
|
5949
|
-
identifyPersonAsync,
|
|
5950
|
-
loginWithBiometric,
|
|
5951
|
-
loginWithEmail,
|
|
5952
|
-
pollTaskStatus,
|
|
5953
|
-
recognize,
|
|
5954
|
-
recognizeBiometric,
|
|
5955
|
-
recognizeByPurpose,
|
|
5956
|
-
recordFaceVideo,
|
|
5957
|
-
registerApplication,
|
|
5958
|
-
registerBiometric,
|
|
5959
|
-
registerDocumentByImage,
|
|
5960
|
-
registerPersonWithBiometric,
|
|
5961
|
-
registerPersonWithoutFace,
|
|
5962
|
-
requestPasswordReset,
|
|
5963
|
-
simpleIdentification,
|
|
5964
|
-
startProofOfLife,
|
|
5965
|
-
validateOnboardingToken,
|
|
5966
|
-
validateToken,
|
|
5967
|
-
videoToBase64
|
|
5968
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
5969
|
-
const BLUE = {
|
|
5970
|
-
400: "#00B0F8",
|
|
5971
|
-
500: "#0091F6",
|
|
5972
|
-
700: "#0059C4"
|
|
5973
|
-
};
|
|
5974
|
-
const GOLD = {
|
|
5975
|
-
500: "#F1BE00"
|
|
5976
|
-
};
|
|
5977
|
-
const INK = {
|
|
5978
|
-
25: "#F7F9FC",
|
|
5979
|
-
50: "#F1F5FA",
|
|
5980
|
-
100: "#E6ECF4",
|
|
5981
|
-
300: "#AFBDCE",
|
|
5982
|
-
400: "#8496AD",
|
|
5983
|
-
500: "#617489",
|
|
5984
|
-
600: "#48586B",
|
|
5985
|
-
800: "#1E2B3C",
|
|
5986
|
-
900: "#111C2B",
|
|
5987
|
-
950: "#0A1320"
|
|
5988
|
-
};
|
|
5989
|
-
const LIGHT_TOKENS = {
|
|
5990
|
-
ground: INK[25],
|
|
5991
|
-
surface: "#FFFFFF",
|
|
5992
|
-
surfaceMuted: INK[50],
|
|
5993
|
-
line: INK[100],
|
|
5994
|
-
text: INK[950],
|
|
5995
|
-
textMuted: INK[600],
|
|
5996
|
-
textSubtle: INK[500],
|
|
5997
|
-
action: BLUE[700],
|
|
5998
|
-
actionText: "#FFFFFF",
|
|
5999
|
-
accent: GOLD[500],
|
|
6000
|
-
overlay: "rgba(10,19,32,.55)",
|
|
6001
|
-
focusRing: BLUE[700]
|
|
6002
|
-
};
|
|
6003
|
-
const DARK_TOKENS = {
|
|
6004
|
-
ground: INK[950],
|
|
6005
|
-
surface: INK[900],
|
|
6006
|
-
surfaceMuted: INK[800],
|
|
6007
|
-
line: "#22334D",
|
|
6008
|
-
text: "#EEF3F9",
|
|
6009
|
-
textMuted: INK[300],
|
|
6010
|
-
textSubtle: INK[400],
|
|
6011
|
-
action: BLUE[500],
|
|
6012
|
-
actionText: "#FFFFFF",
|
|
6013
|
-
accent: GOLD[500],
|
|
6014
|
-
overlay: "rgba(10,19,32,.72)",
|
|
6015
|
-
focusRing: BLUE[400]
|
|
6016
|
-
};
|
|
6017
|
-
function contrastRatio(hexA, hexB) {
|
|
6018
|
-
const lumA = luminance(hexA);
|
|
6019
|
-
const lumB = luminance(hexB);
|
|
6020
|
-
const [hi, lo] = lumA > lumB ? [lumA, lumB] : [lumB, lumA];
|
|
6021
|
-
return (hi + 0.05) / (lo + 0.05);
|
|
6022
|
-
}
|
|
6023
|
-
function luminance(hex) {
|
|
6024
|
-
const [r, g, b] = parseHex(hex).map((v) => {
|
|
6025
|
-
const s = v / 255;
|
|
6026
|
-
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
6027
|
-
});
|
|
6028
|
-
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
6029
|
-
}
|
|
6030
|
-
function parseHex(hex) {
|
|
6031
|
-
let h = hex.trim().replace("#", "");
|
|
6032
|
-
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
6033
|
-
if (!/^[0-9a-fA-F]{6}$/.test(h)) return [0, 0, 0];
|
|
6034
|
-
return [
|
|
6035
|
-
parseInt(h.slice(0, 2), 16),
|
|
6036
|
-
parseInt(h.slice(2, 4), 16),
|
|
6037
|
-
parseInt(h.slice(4, 6), 16)
|
|
6038
|
-
];
|
|
6039
|
-
}
|
|
6040
|
-
const ALLOWED_RADIUS = [8, 16, 24];
|
|
6041
|
-
function resolveTheme(options = {}) {
|
|
6042
|
-
const mode = resolveMode(options.theme);
|
|
6043
|
-
const tokens = mode === "dark" ? { ...DARK_TOKENS } : { ...LIGHT_TOKENS };
|
|
6044
|
-
let radius = 16;
|
|
6045
|
-
if (options.radius !== void 0) {
|
|
6046
|
-
if (ALLOWED_RADIUS.includes(options.radius)) {
|
|
6047
|
-
radius = options.radius;
|
|
6048
|
-
} else {
|
|
6049
|
-
console.warn(
|
|
6050
|
-
`[NeoFaceID SDK] radius ${options.radius} inválido — permitidos: 8, 16, 24. Usando 16.`
|
|
6051
|
-
);
|
|
6052
|
-
}
|
|
6053
|
-
}
|
|
6054
|
-
let accent = tokens.action;
|
|
6055
|
-
let accentFellBack = false;
|
|
6056
|
-
if (options.accent) {
|
|
6057
|
-
const ratio = contrastRatio(options.accent, "#FFFFFF");
|
|
6058
|
-
if (ratio >= 4.5) {
|
|
6059
|
-
accent = options.accent;
|
|
6060
|
-
} else {
|
|
6061
|
-
accentFellBack = true;
|
|
6062
|
-
console.warn(
|
|
6063
|
-
`[NeoFaceID SDK] accent ${options.accent} reprova AA vs branco (${ratio.toFixed(2)}:1). Usando ${BLUE[700]}.`
|
|
6064
|
-
);
|
|
6065
|
-
accent = BLUE[700];
|
|
6066
|
-
}
|
|
6067
|
-
}
|
|
6068
|
-
return { mode, tokens: { ...tokens, action: accent }, radius, accent, accentFellBack };
|
|
6069
|
-
}
|
|
6070
|
-
function resolveMode(theme) {
|
|
6071
|
-
if (theme === "dark") return "dark";
|
|
6072
|
-
if (theme === "light") return "light";
|
|
6073
|
-
if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
|
|
6074
|
-
if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark";
|
|
6075
|
-
}
|
|
6076
|
-
return "light";
|
|
6077
|
-
}
|
|
6078
|
-
const CSS_VAR = {
|
|
6079
|
-
ground: "--nfid-ground",
|
|
6080
|
-
surface: "--nfid-surface",
|
|
6081
|
-
surfaceMuted: "--nfid-surface-muted",
|
|
6082
|
-
line: "--nfid-line",
|
|
6083
|
-
text: "--nfid-text",
|
|
6084
|
-
textMuted: "--nfid-text-muted",
|
|
6085
|
-
textSubtle: "--nfid-text-subtle",
|
|
6086
|
-
action: "--nfid-action",
|
|
6087
|
-
actionText: "--nfid-action-text",
|
|
6088
|
-
accent: "--nfid-accent",
|
|
6089
|
-
overlay: "--nfid-overlay",
|
|
6090
|
-
focusRing: "--nfid-focus-ring",
|
|
6091
|
-
radius: "--nfid-radius"
|
|
6147
|
+
}
|
|
6148
|
+
throw new NeoFaceError("Timed out waiting for identification", ErrorType.NETWORK_ERROR);
|
|
6092
6149
|
};
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
const
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6150
|
+
async function requestPasswordReset(email2, applicationToken) {
|
|
6151
|
+
const baseUrl = getBaseUrl();
|
|
6152
|
+
const response = await fetch(`${baseUrl}/api/v1/user/password/reset/request/`, {
|
|
6153
|
+
method: "POST",
|
|
6154
|
+
headers: {
|
|
6155
|
+
"Content-Type": "application/json",
|
|
6156
|
+
"X-App-Token": applicationToken
|
|
6157
|
+
},
|
|
6158
|
+
body: JSON.stringify({ email: email2 })
|
|
6159
|
+
});
|
|
6160
|
+
if (!response.ok) {
|
|
6161
|
+
const errorData = await response.json();
|
|
6162
|
+
throw new NeoFaceError(
|
|
6163
|
+
errorData.message || "Erro ao solicitar recuperação de senha",
|
|
6164
|
+
ErrorType.API_ERROR
|
|
6165
|
+
);
|
|
6102
6166
|
}
|
|
6103
|
-
|
|
6104
|
-
style.id = INJECTED_STYLE_ID;
|
|
6105
|
-
style.textContent = css;
|
|
6106
|
-
document.head.appendChild(style);
|
|
6107
|
-
return resolved;
|
|
6108
|
-
}
|
|
6109
|
-
function buildRootCss(theme) {
|
|
6110
|
-
const t = theme.tokens;
|
|
6111
|
-
return `.neofaceid-root {
|
|
6112
|
-
${CSS_VAR.ground}: ${t.ground};
|
|
6113
|
-
${CSS_VAR.surface}: ${t.surface};
|
|
6114
|
-
${CSS_VAR.surfaceMuted}: ${t.surfaceMuted};
|
|
6115
|
-
${CSS_VAR.line}: ${t.line};
|
|
6116
|
-
${CSS_VAR.text}: ${t.text};
|
|
6117
|
-
${CSS_VAR.textMuted}: ${t.textMuted};
|
|
6118
|
-
${CSS_VAR.textSubtle}: ${t.textSubtle};
|
|
6119
|
-
${CSS_VAR.action}: ${t.action};
|
|
6120
|
-
${CSS_VAR.actionText}: ${t.actionText};
|
|
6121
|
-
${CSS_VAR.accent}: ${t.accent};
|
|
6122
|
-
${CSS_VAR.overlay}: ${t.overlay};
|
|
6123
|
-
${CSS_VAR.focusRing}: ${t.focusRing};
|
|
6124
|
-
${CSS_VAR.radius}: ${theme.radius}px;
|
|
6125
|
-
color: var(${CSS_VAR.text});
|
|
6126
|
-
font-family: inherit;
|
|
6127
|
-
}
|
|
6128
|
-
.neofaceid-root :focus-visible {
|
|
6129
|
-
outline: 2px solid var(${CSS_VAR.focusRing});
|
|
6130
|
-
outline-offset: 2px;
|
|
6131
|
-
}`;
|
|
6167
|
+
return response.json();
|
|
6132
6168
|
}
|
|
6133
|
-
function
|
|
6134
|
-
|
|
6135
|
-
const
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6169
|
+
async function confirmPasswordReset(token, new_password) {
|
|
6170
|
+
const baseUrl = getBaseUrl();
|
|
6171
|
+
const response = await fetch(`${baseUrl}/api/v1/user/password/reset/confirm/`, {
|
|
6172
|
+
method: "POST",
|
|
6173
|
+
headers: {
|
|
6174
|
+
"Content-Type": "application/json"
|
|
6175
|
+
},
|
|
6176
|
+
body: JSON.stringify({ token, new_password })
|
|
6177
|
+
});
|
|
6178
|
+
if (!response.ok) {
|
|
6179
|
+
const errorData = await response.json();
|
|
6180
|
+
throw new NeoFaceError(
|
|
6181
|
+
errorData.error || errorData.message || "Erro ao redefinir senha",
|
|
6182
|
+
ErrorType.API_ERROR
|
|
6183
|
+
);
|
|
6139
6184
|
}
|
|
6140
|
-
|
|
6141
|
-
style.id = id;
|
|
6142
|
-
style.textContent = css;
|
|
6143
|
-
document.head.appendChild(style);
|
|
6185
|
+
return response.json();
|
|
6144
6186
|
}
|
|
6187
|
+
const api = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
6188
|
+
__proto__: null,
|
|
6189
|
+
checkUserExistence,
|
|
6190
|
+
completeOnboarding,
|
|
6191
|
+
completeOnboardingWithData,
|
|
6192
|
+
confirmPasswordReset,
|
|
6193
|
+
getOnboardingDetails,
|
|
6194
|
+
getTaskStatus,
|
|
6195
|
+
identifyPerson,
|
|
6196
|
+
identifyPersonAsync,
|
|
6197
|
+
loginWithBiometric,
|
|
6198
|
+
loginWithEmail,
|
|
6199
|
+
pollTaskStatus,
|
|
6200
|
+
recognize,
|
|
6201
|
+
recognizeBiometric,
|
|
6202
|
+
recognizeByPurpose,
|
|
6203
|
+
recordFaceVideo,
|
|
6204
|
+
registerApplication,
|
|
6205
|
+
registerBiometric,
|
|
6206
|
+
registerDocumentByImage,
|
|
6207
|
+
registerPersonWithBiometric,
|
|
6208
|
+
registerPersonWithoutFace,
|
|
6209
|
+
requestPasswordReset,
|
|
6210
|
+
simpleIdentification,
|
|
6211
|
+
startProofOfLife,
|
|
6212
|
+
validateOnboardingToken,
|
|
6213
|
+
validateToken,
|
|
6214
|
+
videoToBase64
|
|
6215
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
6145
6216
|
const modalReducer$1 = (state, action) => {
|
|
6146
6217
|
switch (action.type) {
|
|
6147
6218
|
case "PERMISSION_GRANTED":
|
|
@@ -8668,10 +8739,11 @@ class ConsentModal {
|
|
|
8668
8739
|
}
|
|
8669
8740
|
const DEFAULT_APP_NAME = "sua aplicação";
|
|
8670
8741
|
function requestConsent(info = {}) {
|
|
8671
|
-
const
|
|
8672
|
-
|
|
8742
|
+
const globalAppName = getAppName();
|
|
8743
|
+
const appName = info.appName ?? globalAppName ?? DEFAULT_APP_NAME;
|
|
8744
|
+
if (!info.appName && !globalAppName) {
|
|
8673
8745
|
console.warn(
|
|
8674
|
-
'[NeoFaceID SDK] requestConsent
|
|
8746
|
+
'[NeoFaceID SDK] requestConsent sem appName — usando fallback "sua aplicação". Passe via NeoFaceSDK.init({ appName }) ou opts do caller.'
|
|
8675
8747
|
);
|
|
8676
8748
|
}
|
|
8677
8749
|
const flow = info.flow ?? "verification";
|
|
@@ -8710,7 +8782,7 @@ class BiometricCaptureModal {
|
|
|
8710
8782
|
try {
|
|
8711
8783
|
await this.createModal();
|
|
8712
8784
|
await this.initializeCamera();
|
|
8713
|
-
this.
|
|
8785
|
+
this.enableCaptureButton();
|
|
8714
8786
|
} catch (error) {
|
|
8715
8787
|
this.options.onError(
|
|
8716
8788
|
new NeoFaceError(
|
|
@@ -8743,7 +8815,7 @@ class BiometricCaptureModal {
|
|
|
8743
8815
|
<div class="neofaceid-modal-content">
|
|
8744
8816
|
<div class="neofaceid-modal-header">
|
|
8745
8817
|
<h2>${title}</h2>
|
|
8746
|
-
<button class="neofaceid-close-btn" type="button">×</button>
|
|
8818
|
+
<button class="neofaceid-close-btn" type="button" aria-label="Fechar">×</button>
|
|
8747
8819
|
</div>
|
|
8748
8820
|
<div class="neofaceid-modal-body">
|
|
8749
8821
|
<p class="neofaceid-subtitle">${subtitle}</p>
|
|
@@ -8752,9 +8824,6 @@ class BiometricCaptureModal {
|
|
|
8752
8824
|
<canvas class="neofaceid-canvas" style="display: none;"></canvas>
|
|
8753
8825
|
<div class="neofaceid-overlay">
|
|
8754
8826
|
<div class="neofaceid-frame"></div>
|
|
8755
|
-
<div class="neofaceid-countdown">
|
|
8756
|
-
<span class="neofaceid-countdown-number">${this.options.countdown || 3}</span>
|
|
8757
|
-
</div>
|
|
8758
8827
|
</div>
|
|
8759
8828
|
</div>
|
|
8760
8829
|
<div class="neofaceid-status">
|
|
@@ -8765,6 +8834,9 @@ class BiometricCaptureModal {
|
|
|
8765
8834
|
<button class="neofaceid-cancel-btn" type="button">Cancelar</button>
|
|
8766
8835
|
<button class="neofaceid-capture-btn" type="button" disabled>Capturar</button>
|
|
8767
8836
|
</div>
|
|
8837
|
+
<div class="neofaceid-seal-row">
|
|
8838
|
+
<span class="neofaceid-seal">Protegido por NeoFaceID</span>
|
|
8839
|
+
</div>
|
|
8768
8840
|
</div>
|
|
8769
8841
|
</div>
|
|
8770
8842
|
`;
|
|
@@ -8801,42 +8873,24 @@ class BiometricCaptureModal {
|
|
|
8801
8873
|
}
|
|
8802
8874
|
}
|
|
8803
8875
|
/**
|
|
8804
|
-
*
|
|
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.
|
|
8805
8879
|
*/
|
|
8806
|
-
|
|
8880
|
+
enableCaptureButton() {
|
|
8807
8881
|
if (!this.modal) return;
|
|
8808
|
-
const countdownElement = this.modal.querySelector(".neofaceid-countdown-number");
|
|
8809
8882
|
const captureBtn = this.modal.querySelector(".neofaceid-capture-btn");
|
|
8810
8883
|
const statusText = this.modal.querySelector(".neofaceid-status-text");
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
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);
|
|
8814
8893
|
}
|
|
8815
|
-
this.countdownInterval = window.setInterval(() => {
|
|
8816
|
-
count--;
|
|
8817
|
-
if (countdownElement) {
|
|
8818
|
-
countdownElement.textContent = count.toString();
|
|
8819
|
-
}
|
|
8820
|
-
if (count <= 0) {
|
|
8821
|
-
if (this.countdownInterval) {
|
|
8822
|
-
clearInterval(this.countdownInterval);
|
|
8823
|
-
this.countdownInterval = null;
|
|
8824
|
-
}
|
|
8825
|
-
if (countdownElement) {
|
|
8826
|
-
countdownElement.style.display = "none";
|
|
8827
|
-
}
|
|
8828
|
-
if (captureBtn) {
|
|
8829
|
-
captureBtn.disabled = false;
|
|
8830
|
-
captureBtn.textContent = "Capturar Agora";
|
|
8831
|
-
}
|
|
8832
|
-
if (statusText) {
|
|
8833
|
-
statusText.textContent = "Pronto para capturar!";
|
|
8834
|
-
}
|
|
8835
|
-
if (this.options.mode === "auto") {
|
|
8836
|
-
setTimeout(() => this.captureImage(), 500);
|
|
8837
|
-
}
|
|
8838
|
-
}
|
|
8839
|
-
}, 1e3);
|
|
8840
8894
|
}
|
|
8841
8895
|
/**
|
|
8842
8896
|
* Captura a imagem da câmera
|
|
@@ -9018,18 +9072,22 @@ class BiometricCaptureModal {
|
|
|
9018
9072
|
.neofaceid-close-btn {
|
|
9019
9073
|
background: none;
|
|
9020
9074
|
border: none;
|
|
9021
|
-
font-size:
|
|
9075
|
+
font-size: 22px;
|
|
9022
9076
|
cursor: pointer;
|
|
9023
9077
|
color: #666;
|
|
9024
9078
|
padding: 0;
|
|
9025
|
-
width:
|
|
9026
|
-
height:
|
|
9079
|
+
min-width: 44px;
|
|
9080
|
+
min-height: 44px;
|
|
9027
9081
|
display: flex;
|
|
9028
9082
|
align-items: center;
|
|
9029
9083
|
justify-content: center;
|
|
9030
|
-
border-radius:
|
|
9084
|
+
border-radius: 22px;
|
|
9031
9085
|
transition: background-color 0.2s;
|
|
9032
9086
|
}
|
|
9087
|
+
.neofaceid-close-btn:focus-visible {
|
|
9088
|
+
outline: 2px solid var(--nfid-focus-ring);
|
|
9089
|
+
outline-offset: 2px;
|
|
9090
|
+
}
|
|
9033
9091
|
|
|
9034
9092
|
.neofaceid-close-btn:hover {
|
|
9035
9093
|
background-color: #f0f0f0;
|
|
@@ -9087,24 +9145,18 @@ class BiometricCaptureModal {
|
|
|
9087
9145
|
animation: pulse 2s infinite;
|
|
9088
9146
|
}
|
|
9089
9147
|
|
|
9090
|
-
.neofaceid-
|
|
9091
|
-
position: absolute;
|
|
9092
|
-
top: 20px;
|
|
9093
|
-
right: 20px;
|
|
9094
|
-
background: rgba(0, 0, 0, 0.7);
|
|
9095
|
-
color: white;
|
|
9096
|
-
padding: 10px;
|
|
9097
|
-
border-radius: 50%;
|
|
9098
|
-
width: 50px;
|
|
9099
|
-
height: 50px;
|
|
9148
|
+
.neofaceid-seal-row {
|
|
9100
9149
|
display: flex;
|
|
9101
|
-
align-items: center;
|
|
9102
9150
|
justify-content: center;
|
|
9151
|
+
padding: 12px 20px 16px;
|
|
9152
|
+
border-top: 1px solid var(--nfid-line, #E6ECF4);
|
|
9103
9153
|
}
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
font-
|
|
9107
|
-
|
|
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);
|
|
9108
9160
|
}
|
|
9109
9161
|
|
|
9110
9162
|
.neofaceid-status {
|
|
@@ -10808,7 +10860,7 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
10808
10860
|
initializeBiometricDetection,
|
|
10809
10861
|
isAdvancedDetectionAvailable
|
|
10810
10862
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
10811
|
-
const VERSION = "1.
|
|
10863
|
+
const VERSION = "1.31.0";
|
|
10812
10864
|
const RELEASE_DATE = "2026-09-02";
|
|
10813
10865
|
let cachedSession = null;
|
|
10814
10866
|
function getCachedCaptureSession() {
|
|
@@ -11122,6 +11174,9 @@ class OnboardingCaptureModal {
|
|
|
11122
11174
|
<button class="neofaceid-cancel-btn">Cancelar</button>
|
|
11123
11175
|
<button class="neofaceid-capture-btn" disabled>Capturar</button>
|
|
11124
11176
|
</div>
|
|
11177
|
+
<div class="neofaceid-seal-row">
|
|
11178
|
+
<span class="neofaceid-seal">Protegido por NeoFaceID</span>
|
|
11179
|
+
</div>
|
|
11125
11180
|
</div>
|
|
11126
11181
|
`;
|
|
11127
11182
|
injectThemeStyles();
|
|
@@ -11145,6 +11200,8 @@ class OnboardingCaptureModal {
|
|
|
11145
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; }
|
|
11146
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; }
|
|
11147
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); }
|
|
11148
11205
|
`
|
|
11149
11206
|
);
|
|
11150
11207
|
overlay.classList.add("neofaceid-root");
|
|
@@ -11765,6 +11822,552 @@ const authorizeOperation = async (applicationToken, cpf, options) => {
|
|
|
11765
11822
|
throw new NeoFaceError("Unknown error during authorization", ErrorType.UNKNOWN);
|
|
11766
11823
|
}
|
|
11767
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
|
+
}
|
|
11768
12371
|
const DOCUMENT_INFO = {
|
|
11769
12372
|
RG: {
|
|
11770
12373
|
name: "Documento de Identidade (RG / CIN / CPF)",
|
|
@@ -12923,6 +13526,7 @@ export {
|
|
|
12923
13526
|
NeoFaceID,
|
|
12924
13527
|
RELEASE_DATE,
|
|
12925
13528
|
VERSION,
|
|
13529
|
+
authorize,
|
|
12926
13530
|
authorizeOperation,
|
|
12927
13531
|
biometricLogin,
|
|
12928
13532
|
biometricLoginWithFallback,
|
|
@@ -12931,11 +13535,17 @@ export {
|
|
|
12931
13535
|
completeOnboardingWithData,
|
|
12932
13536
|
confirmPasswordReset,
|
|
12933
13537
|
detectBiometricType,
|
|
13538
|
+
getAccent,
|
|
13539
|
+
getAppName,
|
|
12934
13540
|
getApplicationToken,
|
|
12935
13541
|
getBaseUrl,
|
|
12936
13542
|
getCachedCaptureSession,
|
|
12937
13543
|
getConfig,
|
|
12938
13544
|
getEnvironment,
|
|
13545
|
+
getLocale,
|
|
13546
|
+
getRadius,
|
|
13547
|
+
getResolvedThemeMode,
|
|
13548
|
+
getTheme,
|
|
12939
13549
|
identifyPerson,
|
|
12940
13550
|
identifyPersonAsync,
|
|
12941
13551
|
init,
|