@neofaceid/web-sdk 1.33.0 → 1.34.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 +9 -1
- package/dist/neoface-id-sdk.es.js +239 -30
- package/dist/neoface-id-sdk.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -91,6 +91,14 @@ export declare interface AuthorizeOptions {
|
|
|
91
91
|
onSuccess?: (result: LivenessChallengeResult) => void;
|
|
92
92
|
onError?: (error: NeoFaceError) => void;
|
|
93
93
|
onCancel?: () => void;
|
|
94
|
+
/**
|
|
95
|
+
* NEO-420 · US14.9 — "screen flash" assistivo: quando o frame está muito
|
|
96
|
+
* escuro, inverte o fundo para branco alto brilho para usar a tela como
|
|
97
|
+
* fonte de luz. Só ajuda quando faz diferença: se não subir o brilho,
|
|
98
|
+
* reverte. Nunca usado como sinal de liveness (essa decisão é do servidor).
|
|
99
|
+
* Default: `true`.
|
|
100
|
+
*/
|
|
101
|
+
autoLighting?: boolean;
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
export declare class BiometricCaptureModal {
|
|
@@ -1626,7 +1634,7 @@ export declare const validateToken: (applicationToken: string) => Promise<boolea
|
|
|
1626
1634
|
* MINOR: Incrementado quando adicionamos funcionalidades mantendo compatibilidade
|
|
1627
1635
|
* PATCH: Incrementado quando corrigimos bugs mantendo compatibilidade
|
|
1628
1636
|
*/
|
|
1629
|
-
export declare const VERSION = "1.
|
|
1637
|
+
export declare const VERSION = "1.34.0";
|
|
1630
1638
|
|
|
1631
1639
|
/**
|
|
1632
1640
|
* Executa `fn(sessionId)`. Se o servidor devolver 410 (sessão consumida/expirada),
|
|
@@ -10866,7 +10866,7 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
10866
10866
|
initializeBiometricDetection,
|
|
10867
10867
|
isAdvancedDetectionAvailable
|
|
10868
10868
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
10869
|
-
const VERSION = "1.
|
|
10869
|
+
const VERSION = "1.34.0";
|
|
10870
10870
|
const RELEASE_DATE = "2026-09-02";
|
|
10871
10871
|
let cachedSession = null;
|
|
10872
10872
|
function getCachedCaptureSession() {
|
|
@@ -12459,6 +12459,201 @@ function AuthorizePermissionDenied({
|
|
|
12459
12459
|
] })
|
|
12460
12460
|
] });
|
|
12461
12461
|
}
|
|
12462
|
+
function measureFrameBrightness(video, options = {}) {
|
|
12463
|
+
if (!video || video.videoWidth === 0 || video.videoHeight === 0) return 0;
|
|
12464
|
+
const sample = options.sample ?? 64;
|
|
12465
|
+
const vw = video.videoWidth;
|
|
12466
|
+
const vh = video.videoHeight;
|
|
12467
|
+
const roi = options.roi ?? centerRoi(vw, vh, 0.4);
|
|
12468
|
+
const canvas = options.scratch ?? document.createElement("canvas");
|
|
12469
|
+
canvas.width = sample;
|
|
12470
|
+
canvas.height = sample;
|
|
12471
|
+
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
12472
|
+
if (!ctx) return 0;
|
|
12473
|
+
try {
|
|
12474
|
+
ctx.drawImage(
|
|
12475
|
+
video,
|
|
12476
|
+
roi.x,
|
|
12477
|
+
roi.y,
|
|
12478
|
+
roi.width,
|
|
12479
|
+
roi.height,
|
|
12480
|
+
0,
|
|
12481
|
+
0,
|
|
12482
|
+
sample,
|
|
12483
|
+
sample
|
|
12484
|
+
);
|
|
12485
|
+
const data = ctx.getImageData(0, 0, sample, sample).data;
|
|
12486
|
+
return computeLumaMean(data);
|
|
12487
|
+
} catch {
|
|
12488
|
+
return 0;
|
|
12489
|
+
}
|
|
12490
|
+
}
|
|
12491
|
+
function centerRoi(vw, vh, fraction) {
|
|
12492
|
+
const w = Math.round(vw * fraction);
|
|
12493
|
+
const h = Math.round(vh * fraction);
|
|
12494
|
+
return {
|
|
12495
|
+
x: Math.round((vw - w) / 2),
|
|
12496
|
+
y: Math.round((vh - h) / 2),
|
|
12497
|
+
width: w,
|
|
12498
|
+
height: h
|
|
12499
|
+
};
|
|
12500
|
+
}
|
|
12501
|
+
function computeLumaMean(rgba) {
|
|
12502
|
+
const len = rgba.length;
|
|
12503
|
+
if (len === 0) return 0;
|
|
12504
|
+
let sum = 0;
|
|
12505
|
+
let n = 0;
|
|
12506
|
+
for (let i = 0; i < len; i += 4) {
|
|
12507
|
+
const r = rgba[i];
|
|
12508
|
+
const g = rgba[i + 1];
|
|
12509
|
+
const b = rgba[i + 2];
|
|
12510
|
+
sum += 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
12511
|
+
n += 1;
|
|
12512
|
+
}
|
|
12513
|
+
if (n === 0) return 0;
|
|
12514
|
+
return sum / (n * 255);
|
|
12515
|
+
}
|
|
12516
|
+
const DARK_THRESHOLD = 0.235;
|
|
12517
|
+
const IMPROVEMENT_TARGET = 0.12;
|
|
12518
|
+
const SAMPLE_INTERVAL_MS = 600;
|
|
12519
|
+
const EVALUATION_DELAY_MS = 600;
|
|
12520
|
+
const MIN_TOGGLE_MS = 3e3;
|
|
12521
|
+
function useScreenFlash(videoRef, options = {}) {
|
|
12522
|
+
const enabled = options.enabled ?? true;
|
|
12523
|
+
const darkThreshold = options.darkThreshold ?? DARK_THRESHOLD;
|
|
12524
|
+
const improvementTarget = options.improvementTarget ?? IMPROVEMENT_TARGET;
|
|
12525
|
+
const sampleIntervalMs = options.sampleIntervalMs ?? SAMPLE_INTERVAL_MS;
|
|
12526
|
+
const minToggleMs = options.minToggleMs ?? MIN_TOGGLE_MS;
|
|
12527
|
+
const [flashOn, setFlashOn] = useState(false);
|
|
12528
|
+
const [lastBrightness, setLastBrightness] = useState(0);
|
|
12529
|
+
const darkStreakRef = useRef(0);
|
|
12530
|
+
const lastToggleAtRef = useRef(0);
|
|
12531
|
+
const preFlashBrightnessRef = useRef(null);
|
|
12532
|
+
const flashOnRef = useRef(false);
|
|
12533
|
+
const scratchRef = useRef(null);
|
|
12534
|
+
useEffect(() => {
|
|
12535
|
+
flashOnRef.current = flashOn;
|
|
12536
|
+
}, [flashOn]);
|
|
12537
|
+
useEffect(() => {
|
|
12538
|
+
if (!enabled) {
|
|
12539
|
+
setFlashOn(false);
|
|
12540
|
+
return () => {
|
|
12541
|
+
};
|
|
12542
|
+
}
|
|
12543
|
+
if (typeof document !== "undefined" && !scratchRef.current) {
|
|
12544
|
+
scratchRef.current = document.createElement("canvas");
|
|
12545
|
+
}
|
|
12546
|
+
let timer = null;
|
|
12547
|
+
let evalTimer = null;
|
|
12548
|
+
let disposed = false;
|
|
12549
|
+
const tick = () => {
|
|
12550
|
+
if (disposed) return;
|
|
12551
|
+
const b = measureFrameBrightness(videoRef.current, {
|
|
12552
|
+
scratch: scratchRef.current ?? void 0
|
|
12553
|
+
});
|
|
12554
|
+
setLastBrightness(b);
|
|
12555
|
+
const now = Date.now();
|
|
12556
|
+
if (!flashOnRef.current) {
|
|
12557
|
+
if (b > 0 && b < darkThreshold) {
|
|
12558
|
+
darkStreakRef.current += 1;
|
|
12559
|
+
} else {
|
|
12560
|
+
darkStreakRef.current = 0;
|
|
12561
|
+
}
|
|
12562
|
+
if (darkStreakRef.current >= 2 && now - lastToggleAtRef.current >= minToggleMs) {
|
|
12563
|
+
preFlashBrightnessRef.current = b;
|
|
12564
|
+
lastToggleAtRef.current = now;
|
|
12565
|
+
flashOnRef.current = true;
|
|
12566
|
+
setFlashOn(true);
|
|
12567
|
+
darkStreakRef.current = 0;
|
|
12568
|
+
evalTimer = setTimeout(() => {
|
|
12569
|
+
if (disposed) return;
|
|
12570
|
+
const after = measureFrameBrightness(videoRef.current, {
|
|
12571
|
+
scratch: scratchRef.current ?? void 0
|
|
12572
|
+
});
|
|
12573
|
+
const gained = after - (preFlashBrightnessRef.current ?? 0);
|
|
12574
|
+
if (gained < improvementTarget) {
|
|
12575
|
+
lastToggleAtRef.current = Date.now();
|
|
12576
|
+
flashOnRef.current = false;
|
|
12577
|
+
setFlashOn(false);
|
|
12578
|
+
}
|
|
12579
|
+
preFlashBrightnessRef.current = null;
|
|
12580
|
+
}, EVALUATION_DELAY_MS);
|
|
12581
|
+
}
|
|
12582
|
+
}
|
|
12583
|
+
};
|
|
12584
|
+
timer = setInterval(tick, sampleIntervalMs);
|
|
12585
|
+
tick();
|
|
12586
|
+
return () => {
|
|
12587
|
+
disposed = true;
|
|
12588
|
+
if (timer) clearInterval(timer);
|
|
12589
|
+
if (evalTimer) clearTimeout(evalTimer);
|
|
12590
|
+
};
|
|
12591
|
+
}, [enabled, darkThreshold, improvementTarget, sampleIntervalMs, minToggleMs, videoRef]);
|
|
12592
|
+
return { flashOn, lastBrightness };
|
|
12593
|
+
}
|
|
12594
|
+
function ScreenFlashOverlay({
|
|
12595
|
+
active,
|
|
12596
|
+
zIndex = 10001,
|
|
12597
|
+
onDismiss
|
|
12598
|
+
}) {
|
|
12599
|
+
if (!active) return null;
|
|
12600
|
+
const overlayStyle = {
|
|
12601
|
+
position: "fixed",
|
|
12602
|
+
inset: 0,
|
|
12603
|
+
background: "#FFFFFF",
|
|
12604
|
+
zIndex,
|
|
12605
|
+
pointerEvents: "none",
|
|
12606
|
+
animation: "nfid-flash-in 200ms ease-out"
|
|
12607
|
+
};
|
|
12608
|
+
const hintStyle = {
|
|
12609
|
+
position: "fixed",
|
|
12610
|
+
top: 12,
|
|
12611
|
+
left: "50%",
|
|
12612
|
+
transform: "translateX(-50%)",
|
|
12613
|
+
zIndex: zIndex + 1,
|
|
12614
|
+
background: "rgba(10,19,32,.72)",
|
|
12615
|
+
color: "#FFFFFF",
|
|
12616
|
+
fontSize: 12,
|
|
12617
|
+
fontWeight: 600,
|
|
12618
|
+
letterSpacing: 0.2,
|
|
12619
|
+
padding: "6px 12px",
|
|
12620
|
+
borderRadius: 999,
|
|
12621
|
+
pointerEvents: onDismiss ? "auto" : "none",
|
|
12622
|
+
display: "flex",
|
|
12623
|
+
alignItems: "center",
|
|
12624
|
+
gap: 8
|
|
12625
|
+
};
|
|
12626
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12627
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
12628
|
+
@keyframes nfid-flash-in { from { opacity: 0 } to { opacity: 1 } }
|
|
12629
|
+
@media (prefers-reduced-motion: reduce) {
|
|
12630
|
+
.nfid-screen-flash { animation: none !important; }
|
|
12631
|
+
}
|
|
12632
|
+
` }),
|
|
12633
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-screen-flash", style: overlayStyle, "aria-hidden": "true" }),
|
|
12634
|
+
/* @__PURE__ */ jsxs("div", { className: "nfid-screen-flash-hint", style: hintStyle, role: "status", children: [
|
|
12635
|
+
"Aumentando a luz da tela",
|
|
12636
|
+
onDismiss && /* @__PURE__ */ jsx(
|
|
12637
|
+
"button",
|
|
12638
|
+
{
|
|
12639
|
+
type: "button",
|
|
12640
|
+
onClick: onDismiss,
|
|
12641
|
+
"aria-label": "Desligar iluminação assistiva",
|
|
12642
|
+
style: {
|
|
12643
|
+
background: "transparent",
|
|
12644
|
+
border: "none",
|
|
12645
|
+
color: "#FFFFFF",
|
|
12646
|
+
cursor: "pointer",
|
|
12647
|
+
fontSize: 14,
|
|
12648
|
+
lineHeight: 1,
|
|
12649
|
+
padding: "0 4px"
|
|
12650
|
+
},
|
|
12651
|
+
children: "×"
|
|
12652
|
+
}
|
|
12653
|
+
)
|
|
12654
|
+
] })
|
|
12655
|
+
] });
|
|
12656
|
+
}
|
|
12462
12657
|
const STYLE_ID = "neofaceid-authorize-styles";
|
|
12463
12658
|
const GESTURE_TO_GLYPH = {
|
|
12464
12659
|
center: "center",
|
|
@@ -12502,6 +12697,7 @@ function AuthorizeModalComponent({
|
|
|
12502
12697
|
onSuccess,
|
|
12503
12698
|
onError,
|
|
12504
12699
|
onCancel,
|
|
12700
|
+
autoLighting = true,
|
|
12505
12701
|
onClose
|
|
12506
12702
|
}) {
|
|
12507
12703
|
const videoRef = useRef(null);
|
|
@@ -12513,6 +12709,10 @@ function AuthorizeModalComponent({
|
|
|
12513
12709
|
const [failureAt, setFailureAt] = useState(void 0);
|
|
12514
12710
|
const [runCounter, setRunCounter] = useState(0);
|
|
12515
12711
|
const cancelRef = useRef(false);
|
|
12712
|
+
const [flashDismissed, setFlashDismissed] = useState(false);
|
|
12713
|
+
const { flashOn } = useScreenFlash(videoRef, {
|
|
12714
|
+
enabled: autoLighting && !flashDismissed && phase === "challenging"
|
|
12715
|
+
});
|
|
12516
12716
|
const locale = getLocale();
|
|
12517
12717
|
const headerAppName = appName ?? getAppName() ?? "sua aplicação";
|
|
12518
12718
|
const headerAmount = typeof amount === "number" && Number.isFinite(amount) ? formatCurrency(amount, locale) : null;
|
|
@@ -12664,42 +12864,51 @@ function AuthorizeModalComponent({
|
|
|
12664
12864
|
}
|
|
12665
12865
|
) });
|
|
12666
12866
|
}
|
|
12667
|
-
return /* @__PURE__ */
|
|
12867
|
+
return /* @__PURE__ */ jsxs(Sheet, { open: true, onDismiss: void 0, dismissOnOverlay: false, ariaLabel: "Autorização por biometria", children: [
|
|
12668
12868
|
/* @__PURE__ */ jsx(
|
|
12669
|
-
|
|
12869
|
+
ScreenFlashOverlay,
|
|
12670
12870
|
{
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
onClick: handleClose,
|
|
12674
|
-
"aria-label": "Cancelar autorização",
|
|
12675
|
-
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" }) })
|
|
12871
|
+
active: flashOn,
|
|
12872
|
+
onDismiss: () => setFlashDismissed(true)
|
|
12676
12873
|
}
|
|
12677
12874
|
),
|
|
12678
|
-
/* @__PURE__ */ jsxs("div", {
|
|
12679
|
-
/* @__PURE__ */ jsx("span", { className: "nfid-authorize-appname", children: headerAppName }),
|
|
12680
|
-
headerAmount && /* @__PURE__ */ jsxs("span", { className: "nfid-authorize-amount", children: [
|
|
12681
|
-
"Autorizando ",
|
|
12682
|
-
headerAmount
|
|
12683
|
-
] }),
|
|
12684
|
-
/* @__PURE__ */ jsx("span", { className: "nfid-authorize-brand", children: "NeoFaceID" })
|
|
12685
|
-
] }),
|
|
12686
|
-
/* @__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 }) }) }),
|
|
12687
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 12, marginTop: 16 }, children: [
|
|
12688
|
-
/* @__PURE__ */ jsx(ChallengeGlyph, { gesture: gestureKey, size: 40 }),
|
|
12875
|
+
/* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
12689
12876
|
/* @__PURE__ */ jsx(
|
|
12690
|
-
"
|
|
12877
|
+
"button",
|
|
12691
12878
|
{
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12695
|
-
|
|
12879
|
+
type: "button",
|
|
12880
|
+
className: "nfid-authorize-close",
|
|
12881
|
+
onClick: handleClose,
|
|
12882
|
+
"aria-label": "Cancelar autorização",
|
|
12883
|
+
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" }) })
|
|
12696
12884
|
}
|
|
12697
|
-
)
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12885
|
+
),
|
|
12886
|
+
/* @__PURE__ */ jsxs("div", { className: "nfid-authorize-header", children: [
|
|
12887
|
+
/* @__PURE__ */ jsx("span", { className: "nfid-authorize-appname", children: headerAppName }),
|
|
12888
|
+
headerAmount && /* @__PURE__ */ jsxs("span", { className: "nfid-authorize-amount", children: [
|
|
12889
|
+
"Autorizando ",
|
|
12890
|
+
headerAmount
|
|
12891
|
+
] }),
|
|
12892
|
+
/* @__PURE__ */ jsx("span", { className: "nfid-authorize-brand", children: "NeoFaceID" })
|
|
12893
|
+
] }),
|
|
12894
|
+
/* @__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 }) }) }),
|
|
12895
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 12, marginTop: 16 }, children: [
|
|
12896
|
+
/* @__PURE__ */ jsx(ChallengeGlyph, { gesture: gestureKey, size: 40 }),
|
|
12897
|
+
/* @__PURE__ */ jsx(
|
|
12898
|
+
"p",
|
|
12899
|
+
{
|
|
12900
|
+
className: "nfid-authorize-instruction",
|
|
12901
|
+
"aria-live": "assertive",
|
|
12902
|
+
style: { margin: 0 },
|
|
12903
|
+
children: instruction
|
|
12904
|
+
}
|
|
12905
|
+
)
|
|
12906
|
+
] }),
|
|
12907
|
+
phase === "preparing" && /* @__PURE__ */ jsx("p", { className: "nfid-authorize-support", children: "Ligando sua câmera…" }),
|
|
12908
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-authorize-actions", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleClose, children: "Não consigo fazer esse movimento" }) }),
|
|
12909
|
+
/* @__PURE__ */ jsx("div", { className: "nfid-authorize-footer", children: /* @__PURE__ */ jsx("span", { className: "nfid-authorize-seal", children: "Protegido por NeoFaceID" }) })
|
|
12910
|
+
] })
|
|
12911
|
+
] });
|
|
12703
12912
|
}
|
|
12704
12913
|
async function progressiveHold(setter) {
|
|
12705
12914
|
const total = 1500;
|