vesant-sdk 1.7.0-dev.e0ee6d5 → 1.7.0-dev.e1da577
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/{client-ZNdnpWe7.d.mts → client-B0qhE2kr.d.mts} +1 -1
- package/dist/{client-DoMSYMMR.d.ts → client-DF7hlMEz.d.ts} +13 -0
- package/dist/{client-DMIRx7Tu.d.mts → client-DrjgZoH_.d.mts} +13 -0
- package/dist/{client-C3DCmGe9.d.ts → client-DtH2RLuy.d.ts} +1 -1
- package/dist/compliance/index.d.mts +2 -2
- package/dist/compliance/index.d.ts +2 -2
- package/dist/compliance/index.js +0 -3
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +0 -3
- package/dist/compliance/index.mjs.map +1 -1
- package/dist/geolocation/index.d.mts +2 -2
- package/dist/geolocation/index.d.ts +2 -2
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +40 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +40 -22
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +1 -1
- package/dist/kyc/core.d.ts +1 -1
- package/dist/kyc/core.js +36 -18
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +36 -18
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +161 -58
- package/dist/kyc/index.d.ts +161 -58
- package/dist/kyc/index.js +36 -18
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +36 -18
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +18 -14
- package/dist/react.d.ts +18 -14
- package/dist/react.js +303 -35
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +303 -35
- package/dist/react.mjs.map +1 -1
- package/dist/tax/index.d.mts +18 -1
- package/dist/tax/index.d.ts +18 -1
- package/dist/tax/index.js +4 -1
- package/dist/tax/index.js.map +1 -1
- package/dist/tax/index.mjs +4 -1
- package/dist/tax/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -888,10 +888,91 @@ function useCustomerProfile(client, customerId, options = {}) {
|
|
|
888
888
|
var Camera = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjAvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvMjAwMS9SRUMtU1ZHLTIwMDEwOTA0L0RURC9zdmcxMC5kdGQiPg0KPCEtLSBVcGxvYWRlZCB0bzogU1ZHIFJlcG8sIHd3dy5zdmdyZXBvLmNvbSwgR2VuZXJhdG9yOiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4NCjxzdmcgdmVyc2lvbj0iMS4wIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgDQoJIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDY0IDY0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2NCA2NCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBmaWxsPSIjMjMxRjIwIiBkPSJNNjAsMTBINDkuNjU2bC02LjgyOC02LjgyOEM0Mi4wNzgsMi40MjIsNDEuMDYyLDIsNDAsMkgyNGMtMS4wNjIsMC0yLjA3OCwwLjQyMi0yLjgyOCwxLjE3MkwxNC4zNDQsMTBINA0KCQljLTIuMjExLDAtNCwxLjc4OS00LDR2NDRjMCwyLjIxMSwxLjc4OSw0LDQsNGg1NmMyLjIxMSwwLDQtMS43ODksNC00VjE0QzY0LDExLjc4OSw2Mi4yMTEsMTAsNjAsMTB6IE0zMiw1MA0KCQljLTguODM2LDAtMTYtNy4xNjQtMTYtMTZzNy4xNjQtMTYsMTYtMTZzMTYsNy4xNjQsMTYsMTZTNDAuODM2LDUwLDMyLDUweiIvPg0KCTxjaXJjbGUgZmlsbD0iIzIzMUYyMCIgY3g9IjMyIiBjeT0iMzQiIHI9IjgiLz4NCjwvZz4NCjwvc3ZnPg==";
|
|
889
889
|
var Done = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik04LjUgMTIuNUwxMC41IDE0LjVMMTUuNSA5LjUiIHN0cm9rZT0iIzFDMjc0QyIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPg0KPHBhdGggZD0iTTcgMy4zMzc4MkM4LjQ3MDg3IDIuNDg2OTcgMTAuMTc4NiAyIDEyIDJDMTcuNTIyOCAyIDIyIDYuNDc3MTUgMjIgMTJDMjIgMTcuNTIyOCAxNy41MjI4IDIyIDEyIDIyQzYuNDc3MTUgMjIgMiAxNy41MjI4IDIgMTJDMiAxMC4xNzg2IDIuNDg2OTcgOC40NzA4NyAzLjMzNzgyIDciIHN0cm9rZT0iIzFDMjc0QyIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPg0KPC9zdmc+";
|
|
890
890
|
var Close = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xNC41IDkuNTAwMDJMOS41IDE0LjVNOS40OTk5OCA5LjVMMTQuNSAxNC41IiBzdHJva2U9IiMxQzI3NEMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4NCjxwYXRoIGQ9Ik03IDMuMzM3ODJDOC40NzA4NyAyLjQ4Njk3IDEwLjE3ODYgMiAxMiAyQzE3LjUyMjggMiAyMiA2LjQ3NzE1IDIyIDEyQzIyIDE3LjUyMjggMTcuNTIyOCAyMiAxMiAyMkM2LjQ3NzE1IDIyIDIgMTcuNTIyOCAyIDEyQzIgMTAuMTc4NiAyLjQ4Njk3IDguNDcwODcgMy4zMzc4MiA3IiBzdHJva2U9IiMxQzI3NEMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4NCjwvc3ZnPg==";
|
|
891
|
-
|
|
891
|
+
|
|
892
|
+
// src/kyc/faceDetection.ts
|
|
893
|
+
var FACE_MESSAGES = {
|
|
894
|
+
idle: "Initializing camera...",
|
|
895
|
+
loading: "Loading face detection...",
|
|
896
|
+
scanning: "Position your face in the circle",
|
|
897
|
+
too_far: "Face too far. Please move closer to the camera",
|
|
898
|
+
too_close: "Too close. Please move back a little",
|
|
899
|
+
off_center: "Center your face in the circle",
|
|
900
|
+
ok: "Looking great! Tap the button to capture"
|
|
901
|
+
};
|
|
902
|
+
var FACE_COLORS = {
|
|
903
|
+
idle: "#9ca3af",
|
|
904
|
+
loading: "#3b82f6",
|
|
905
|
+
scanning: "#3b82f6",
|
|
906
|
+
too_far: "#ef4444",
|
|
907
|
+
too_close: "#f59e0b",
|
|
908
|
+
off_center: "#f59e0b",
|
|
909
|
+
ok: "#10b981"
|
|
910
|
+
};
|
|
911
|
+
var MEDIAPIPE_BASE = "https://cdn.jsdelivr.net/npm/@mediapipe/face_detection";
|
|
912
|
+
function mapDetectionsToFaceStatus(detections) {
|
|
913
|
+
if (detections.length === 0) return "scanning";
|
|
914
|
+
const bb = detections[0].boundingBox;
|
|
915
|
+
if (bb.width < 0.18) return "too_far";
|
|
916
|
+
if (bb.width > 0.72) return "too_close";
|
|
917
|
+
if (bb.xCenter < 0.28 || bb.xCenter > 0.72 || bb.yCenter < 0.28 || bb.yCenter > 0.72) {
|
|
918
|
+
return "off_center";
|
|
919
|
+
}
|
|
920
|
+
return "ok";
|
|
921
|
+
}
|
|
922
|
+
function isCaptureDisabled(ready, detectionActive, faceStatus) {
|
|
923
|
+
return !ready || detectionActive && faceStatus !== "ok";
|
|
924
|
+
}
|
|
925
|
+
function resolveMediaPipeBase(base) {
|
|
926
|
+
if (!base) return MEDIAPIPE_BASE;
|
|
927
|
+
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
928
|
+
}
|
|
929
|
+
var LIVENESS_SAMPLE_LIMIT = 20;
|
|
930
|
+
function buildLivenessArtifact(samples) {
|
|
931
|
+
if (samples.length === 0) return void 0;
|
|
932
|
+
return JSON.stringify({
|
|
933
|
+
version: 1,
|
|
934
|
+
source: "mediapipe-face-detection",
|
|
935
|
+
samples: samples.slice(-LIVENESS_SAMPLE_LIMIT)
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
var mediapipeLoaderPromises = /* @__PURE__ */ new Map();
|
|
939
|
+
function loadMediaPipeFaceDetection(assetBasePath) {
|
|
940
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
941
|
+
return Promise.reject(new Error("MediaPipe requires a browser environment"));
|
|
942
|
+
}
|
|
943
|
+
const w = window;
|
|
944
|
+
if (w.FaceDetection) {
|
|
945
|
+
return Promise.resolve(w.FaceDetection);
|
|
946
|
+
}
|
|
947
|
+
const src = `${resolveMediaPipeBase(assetBasePath)}/face_detection.js`;
|
|
948
|
+
const existing = mediapipeLoaderPromises.get(src);
|
|
949
|
+
if (existing) return existing;
|
|
950
|
+
const loader = new Promise((resolve, reject) => {
|
|
951
|
+
const script = document.createElement("script");
|
|
952
|
+
script.src = src;
|
|
953
|
+
script.async = true;
|
|
954
|
+
script.crossOrigin = "anonymous";
|
|
955
|
+
script.onload = () => {
|
|
956
|
+
if (w.FaceDetection) {
|
|
957
|
+
resolve(w.FaceDetection);
|
|
958
|
+
} else {
|
|
959
|
+
mediapipeLoaderPromises.delete(src);
|
|
960
|
+
reject(new Error("MediaPipe loaded but FaceDetection global is missing"));
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
script.onerror = () => {
|
|
964
|
+
mediapipeLoaderPromises.delete(src);
|
|
965
|
+
reject(new Error("Failed to load MediaPipe face_detection script"));
|
|
966
|
+
};
|
|
967
|
+
document.head.appendChild(script);
|
|
968
|
+
});
|
|
969
|
+
mediapipeLoaderPromises.set(src, loader);
|
|
970
|
+
return loader;
|
|
971
|
+
}
|
|
892
972
|
|
|
893
973
|
// src/kyc/FaceCaptureModal.tsx
|
|
894
974
|
var MOBILE_UA = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
975
|
+
var SESSION_EXPIRY_MS = 15 * 60 * 1e3;
|
|
895
976
|
var LIVENESS_MESSAGES = [
|
|
896
977
|
"Position your face inside the circle",
|
|
897
978
|
"Make sure your face is well lit",
|
|
@@ -905,9 +986,9 @@ function headerSubtitle(stageKind) {
|
|
|
905
986
|
case "accepted":
|
|
906
987
|
return "All set";
|
|
907
988
|
case "declined":
|
|
908
|
-
return "Verification
|
|
989
|
+
return "Verification Declined";
|
|
909
990
|
case "max_attempts":
|
|
910
|
-
return "We couldn't verify
|
|
991
|
+
return "We couldn't verify your identity";
|
|
911
992
|
default:
|
|
912
993
|
return "Please capture a clear photo of your face";
|
|
913
994
|
}
|
|
@@ -920,16 +1001,19 @@ function FaceCaptureModal({
|
|
|
920
1001
|
client,
|
|
921
1002
|
session,
|
|
922
1003
|
onComplete,
|
|
1004
|
+
onCancel,
|
|
923
1005
|
defaultDevice,
|
|
924
|
-
renderQR
|
|
1006
|
+
renderQR,
|
|
1007
|
+
mediapipeAssetBasePath
|
|
925
1008
|
}) {
|
|
926
1009
|
const isMobile = typeof navigator !== "undefined" && MOBILE_UA.test(navigator.userAgent);
|
|
1010
|
+
const initialChoice = defaultDevice ?? (isMobile ? "this" : "ask");
|
|
927
1011
|
const initialStage = (() => {
|
|
928
|
-
|
|
929
|
-
if (
|
|
930
|
-
if (choice === "mobile") return { kind: "qr", mobileConnected: false };
|
|
1012
|
+
if (initialChoice === "this") return { kind: "capture" };
|
|
1013
|
+
if (initialChoice === "mobile") return { kind: "qr", mobileConnected: false };
|
|
931
1014
|
return { kind: "choose" };
|
|
932
1015
|
})();
|
|
1016
|
+
const hasMethodChoice = initialChoice === "ask";
|
|
933
1017
|
const [stage, setStage] = React.useState(initialStage);
|
|
934
1018
|
const [attempts, setAttempts] = React.useState(session.attempts);
|
|
935
1019
|
const maxAttempts = session.max_attempts || 1;
|
|
@@ -937,21 +1021,30 @@ function FaceCaptureModal({
|
|
|
937
1021
|
const [captureMode, setCaptureMode] = React.useState("idle");
|
|
938
1022
|
const [capturedPreview, setCapturedPreview] = React.useState(null);
|
|
939
1023
|
const [capturedBase64, setCapturedBase64] = React.useState(null);
|
|
1024
|
+
const [capturedArtifact, setCapturedArtifact] = React.useState(null);
|
|
940
1025
|
const [livenessMessage, setLivenessMessage] = React.useState(LIVENESS_MESSAGES[0]);
|
|
941
1026
|
const qrPayload = session.link || `vesant://reuse-kyc?token=${encodeURIComponent(session.token)}`;
|
|
942
1027
|
const cancelledRef = React.useRef(false);
|
|
943
1028
|
const submittingRef = React.useRef(false);
|
|
1029
|
+
React.useEffect(() => {
|
|
1030
|
+
const timer = setTimeout(() => {
|
|
1031
|
+
setStage(
|
|
1032
|
+
(prev) => prev.kind === "choose" || prev.kind === "qr" || prev.kind === "capture" ? { kind: "error", message: "Session expired" } : prev
|
|
1033
|
+
);
|
|
1034
|
+
}, SESSION_EXPIRY_MS);
|
|
1035
|
+
return () => clearTimeout(timer);
|
|
1036
|
+
}, [session.token]);
|
|
944
1037
|
React.useEffect(() => {
|
|
945
1038
|
if (stage.kind !== "qr") return;
|
|
946
1039
|
let stopped = false;
|
|
947
1040
|
const intervalMs = 2e3;
|
|
948
|
-
const deadline = Date.now() +
|
|
1041
|
+
const deadline = Date.now() + SESSION_EXPIRY_MS;
|
|
949
1042
|
let mobileSeen = stage.mobileConnected;
|
|
950
1043
|
const tick = async () => {
|
|
951
1044
|
if (stopped || cancelledRef.current) return;
|
|
952
1045
|
try {
|
|
953
1046
|
if (mobileSeen) {
|
|
954
|
-
const result = await client.
|
|
1047
|
+
const result = await client.getEventBasedFaceVerificationSessionStatus(session.token);
|
|
955
1048
|
if (result.status === "accepted") {
|
|
956
1049
|
setStage({ kind: "accepted", result });
|
|
957
1050
|
stopped = true;
|
|
@@ -1023,10 +1116,13 @@ function FaceCaptureModal({
|
|
|
1023
1116
|
try {
|
|
1024
1117
|
const postPromise = (async () => {
|
|
1025
1118
|
try {
|
|
1026
|
-
const data = await client.
|
|
1119
|
+
const data = await client.submitEventBasedFaceVerificationSession({
|
|
1027
1120
|
token: session.token,
|
|
1028
1121
|
reference: ref,
|
|
1029
|
-
proof
|
|
1122
|
+
proof,
|
|
1123
|
+
// undefined when detection wasn't running for this capture —
|
|
1124
|
+
// JSON.stringify drops it, so the field is absent on the wire.
|
|
1125
|
+
liveness_artifact: capturedArtifact ?? void 0
|
|
1030
1126
|
});
|
|
1031
1127
|
return { ok: true, data };
|
|
1032
1128
|
} catch (err2) {
|
|
@@ -1039,7 +1135,7 @@ function FaceCaptureModal({
|
|
|
1039
1135
|
while (Date.now() < deadline) {
|
|
1040
1136
|
if (settled || cancelledRef.current) return null;
|
|
1041
1137
|
try {
|
|
1042
|
-
const r = await client.
|
|
1138
|
+
const r = await client.getEventBasedFaceVerificationSessionStatus(session.token);
|
|
1043
1139
|
if (isFreshPollResult(r)) return r;
|
|
1044
1140
|
} catch {
|
|
1045
1141
|
}
|
|
@@ -1072,16 +1168,18 @@ function FaceCaptureModal({
|
|
|
1072
1168
|
submittingRef.current = false;
|
|
1073
1169
|
}
|
|
1074
1170
|
};
|
|
1075
|
-
const handleCameraCapture = (dataUrl) => {
|
|
1171
|
+
const handleCameraCapture = (dataUrl, livenessArtifact) => {
|
|
1076
1172
|
const raw = dataUrl.split(",")[1] ?? "";
|
|
1077
1173
|
setCapturedPreview(dataUrl);
|
|
1078
1174
|
setCapturedBase64(raw);
|
|
1175
|
+
setCapturedArtifact(livenessArtifact ?? null);
|
|
1079
1176
|
setCaptureMode("preview");
|
|
1080
1177
|
};
|
|
1081
1178
|
const handleCameraCancel = () => setCaptureMode("idle");
|
|
1082
1179
|
const handleRetake = () => {
|
|
1083
1180
|
setCapturedPreview(null);
|
|
1084
1181
|
setCapturedBase64(null);
|
|
1182
|
+
setCapturedArtifact(null);
|
|
1085
1183
|
setCaptureMode("live");
|
|
1086
1184
|
};
|
|
1087
1185
|
const handleConfirmSubmit = () => {
|
|
@@ -1110,6 +1208,9 @@ function FaceCaptureModal({
|
|
|
1110
1208
|
}, [captureMode]);
|
|
1111
1209
|
const close = (result) => {
|
|
1112
1210
|
cancelledRef.current = true;
|
|
1211
|
+
if (result === null && onCancel) {
|
|
1212
|
+
onCancel();
|
|
1213
|
+
}
|
|
1113
1214
|
onComplete(result);
|
|
1114
1215
|
};
|
|
1115
1216
|
const renderChoose = () => /* @__PURE__ */ React__default.default.createElement("div", { style: contentStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: visualGuideContainerStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: visualGuideStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: circleStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 48, height: 48 })))), /* @__PURE__ */ React__default.default.createElement("p", { style: subtitleStyle }, "How would you like to verify?"), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement(
|
|
@@ -1118,7 +1219,7 @@ function FaceCaptureModal({
|
|
|
1118
1219
|
style: primaryButtonStyle,
|
|
1119
1220
|
onClick: () => setStage({ kind: "capture" })
|
|
1120
1221
|
},
|
|
1121
|
-
/* @__PURE__ */ React__default.default.createElement("img", { src:
|
|
1222
|
+
/* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 20, height: 20 }),
|
|
1122
1223
|
/* @__PURE__ */ React__default.default.createElement("span", null, "Continue on this device")
|
|
1123
1224
|
), /* @__PURE__ */ React__default.default.createElement(
|
|
1124
1225
|
"button",
|
|
@@ -1135,6 +1236,13 @@ function FaceCaptureModal({
|
|
|
1135
1236
|
onClick: () => setStage({ kind: "capture" })
|
|
1136
1237
|
},
|
|
1137
1238
|
"Use this device instead"
|
|
1239
|
+
), hasMethodChoice && /* @__PURE__ */ React__default.default.createElement(
|
|
1240
|
+
"button",
|
|
1241
|
+
{
|
|
1242
|
+
style: secondaryButtonStyle,
|
|
1243
|
+
onClick: () => setStage({ kind: "choose" })
|
|
1244
|
+
},
|
|
1245
|
+
"Change verification method"
|
|
1138
1246
|
), /* @__PURE__ */ React__default.default.createElement("button", { style: cancelButtonStyle, onClick: () => close(null) }, "Cancel")));
|
|
1139
1247
|
const renderCapture = (declinedReason) => {
|
|
1140
1248
|
if (captureMode === "live") {
|
|
@@ -1143,20 +1251,31 @@ function FaceCaptureModal({
|
|
|
1143
1251
|
{
|
|
1144
1252
|
onCapture: handleCameraCapture,
|
|
1145
1253
|
onCancel: handleCameraCancel,
|
|
1146
|
-
message: livenessMessage
|
|
1254
|
+
message: livenessMessage,
|
|
1255
|
+
assetBasePath: mediapipeAssetBasePath
|
|
1147
1256
|
}
|
|
1148
1257
|
), /* @__PURE__ */ React__default.default.createElement("p", { style: attemptsTextStyle }, "Attempt ", attempts + 1, " of ", maxAttempts));
|
|
1149
1258
|
}
|
|
1150
1259
|
if (captureMode === "preview" && capturedPreview) {
|
|
1151
1260
|
return /* @__PURE__ */ React__default.default.createElement("div", { style: contentStyle }, declinedReason && /* @__PURE__ */ React__default.default.createElement("div", { style: alertBoxStyle }, /* @__PURE__ */ React__default.default.createElement("strong", null, "Verification declined."), /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, declinedReason)), /* @__PURE__ */ React__default.default.createElement("p", { style: subtitleStyle }, "Looks good? Submit this selfie or retake it."), /* @__PURE__ */ React__default.default.createElement("div", { style: previewBoxStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: capturedPreview, alt: "Captured selfie preview", style: previewImgStyle })), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: handleConfirmSubmit }, /* @__PURE__ */ React__default.default.createElement("img", { src: Done, alt: "", width: 20, height: 20 }), /* @__PURE__ */ React__default.default.createElement("span", null, "Submit")), /* @__PURE__ */ React__default.default.createElement("button", { style: secondaryButtonStyle, onClick: handleRetake }, "Retake"), /* @__PURE__ */ React__default.default.createElement("button", { style: cancelButtonStyle, onClick: () => close(null) }, "Cancel")), /* @__PURE__ */ React__default.default.createElement("p", { style: attemptsTextStyle }, "Attempt ", attempts + 1, " of ", maxAttempts));
|
|
1152
1261
|
}
|
|
1153
|
-
return /* @__PURE__ */ React__default.default.createElement("div", { style: contentStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: visualGuideContainerStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: visualGuideStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: circleStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 48, height: 48 })), /* @__PURE__ */ React__default.default.createElement("div", { style: badgeStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: Done, alt: "", width: 16, height: 16 })))), declinedReason && /* @__PURE__ */ React__default.default.createElement("div", { style: alertBoxStyle }, /* @__PURE__ */ React__default.default.createElement("strong", null, "Verification declined."), /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, declinedReason)), /* @__PURE__ */ React__default.default.createElement("div", { style: instructionsBoxStyle }, /* @__PURE__ */ React__default.default.createElement("h3", { style: instructionsTitleStyle }, "Tips for best results:"), /* @__PURE__ */ React__default.default.createElement("ul", { style: instructionsListStyle }, /* @__PURE__ */ React__default.default.createElement("li", { style: instructionItemStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: bulletStyle }, "\u2022"), /* @__PURE__ */ React__default.default.createElement("span", null, "Ensure good lighting on your face")), /* @__PURE__ */ React__default.default.createElement("li", { style: instructionItemStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: bulletStyle }, "\u2022"), /* @__PURE__ */ React__default.default.createElement("span", null, "Remove glasses or accessories if possible")), /* @__PURE__ */ React__default.default.createElement("li", { style: instructionItemStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: bulletStyle }, "\u2022"), /* @__PURE__ */ React__default.default.createElement("span", null, "Look directly at the camera")))), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: handleOpenCamera }, /* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 20, height: 20 }), /* @__PURE__ */ React__default.default.createElement("span", null, declinedReason ? "Try
|
|
1262
|
+
return /* @__PURE__ */ React__default.default.createElement("div", { style: contentStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: visualGuideContainerStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: visualGuideStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: circleStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 48, height: 48 })), /* @__PURE__ */ React__default.default.createElement("div", { style: badgeStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: Done, alt: "", width: 16, height: 16 })))), declinedReason && /* @__PURE__ */ React__default.default.createElement("div", { style: alertBoxStyle }, /* @__PURE__ */ React__default.default.createElement("strong", null, "Verification declined."), /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, declinedReason)), /* @__PURE__ */ React__default.default.createElement("div", { style: instructionsBoxStyle }, /* @__PURE__ */ React__default.default.createElement("h3", { style: instructionsTitleStyle }, "Tips for best results:"), /* @__PURE__ */ React__default.default.createElement("ul", { style: instructionsListStyle }, /* @__PURE__ */ React__default.default.createElement("li", { style: instructionItemStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: bulletStyle }, "\u2022"), /* @__PURE__ */ React__default.default.createElement("span", null, "Ensure good lighting on your face")), /* @__PURE__ */ React__default.default.createElement("li", { style: instructionItemStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: bulletStyle }, "\u2022"), /* @__PURE__ */ React__default.default.createElement("span", null, "Remove glasses or accessories if possible")), /* @__PURE__ */ React__default.default.createElement("li", { style: instructionItemStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: bulletStyle }, "\u2022"), /* @__PURE__ */ React__default.default.createElement("span", null, "Look directly at the camera")))), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: handleOpenCamera }, /* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 20, height: 20 }), /* @__PURE__ */ React__default.default.createElement("span", null, declinedReason ? "Try Again" : "Open Camera")), hasMethodChoice && /* @__PURE__ */ React__default.default.createElement(
|
|
1263
|
+
"button",
|
|
1264
|
+
{
|
|
1265
|
+
style: secondaryButtonStyle,
|
|
1266
|
+
onClick: () => setStage({ kind: "choose" })
|
|
1267
|
+
},
|
|
1268
|
+
"Change verification method"
|
|
1269
|
+
), /* @__PURE__ */ React__default.default.createElement("button", { style: cancelButtonStyle, onClick: () => close(null) }, "Cancel")), /* @__PURE__ */ React__default.default.createElement("p", { style: attemptsTextStyle }, "Attempt ", attempts + 1, " of ", maxAttempts));
|
|
1154
1270
|
};
|
|
1155
1271
|
const renderSubmitting = () => /* @__PURE__ */ React__default.default.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React__default.default.createElement("div", { style: { ...spinnerStyle, margin: "24px auto", width: 32, height: 32 } }), /* @__PURE__ */ React__default.default.createElement("p", { style: subtitleStyle }, "Verifying your photo\u2026"), /* @__PURE__ */ React__default.default.createElement("p", { style: { ...attemptsTextStyle, marginTop: 8 } }, "This usually takes a few seconds."));
|
|
1156
1272
|
const renderAccepted = (result) => /* @__PURE__ */ React__default.default.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React__default.default.createElement("div", { style: successCircleStyle }, /* @__PURE__ */ React__default.default.createElement("img", { src: Done, alt: "", width: 48, height: 48 })), /* @__PURE__ */ React__default.default.createElement("h3", { style: titleStyle }, "Verified"), /* @__PURE__ */ React__default.default.createElement("p", { style: subtitleStyle }, "Your identity has been confirmed. You can continue."), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: () => close(result) }, "Continue")));
|
|
1157
|
-
const renderDeclined = (result) => /* @__PURE__ */ React__default.default.createElement("div", { style: contentStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: alertBoxStyle }, /* @__PURE__ */ React__default.default.createElement("
|
|
1158
|
-
const renderMaxAttempts = (result) => /* @__PURE__ */ React__default.default.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React__default.default.createElement("div", { style: errorCircleStyle }, "!"), /* @__PURE__ */ React__default.default.createElement("h3", { style: titleStyle }, "Maximum
|
|
1159
|
-
const renderError = (message) =>
|
|
1273
|
+
const renderDeclined = (result) => /* @__PURE__ */ React__default.default.createElement("div", { style: contentStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: alertBoxStyle }, /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, result.declined_reason ?? "We couldn't match your selfie. Please take a new one.")), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: handleRetakeAfterDecline }, /* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 20, height: 20 }), /* @__PURE__ */ React__default.default.createElement("span", null, "Retake")), /* @__PURE__ */ React__default.default.createElement("button", { style: cancelButtonStyle, onClick: () => close(result) }, "Cancel")), /* @__PURE__ */ React__default.default.createElement("p", { style: attemptsTextStyle }, "Attempt ", Math.min(attempts + 1, maxAttempts), " of ", maxAttempts));
|
|
1274
|
+
const renderMaxAttempts = (result) => /* @__PURE__ */ React__default.default.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React__default.default.createElement("div", { style: errorCircleStyle }, "!"), /* @__PURE__ */ React__default.default.createElement("h3", { style: titleStyle }, "Maximum Attempts Reached"), /* @__PURE__ */ React__default.default.createElement("p", { style: subtitleStyle }, result.declined_reason ?? "We couldn't verify your identity after several attempts."), result.data?.freeze_account && /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, "For your security, your account has been temporarily restricted", result.data.freeze_duration_minutes ? ` for ${result.data.freeze_duration_minutes} minutes` : "", ". Please contact support if you need immediate help."), result.data?.enforce_logout && /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, "You will be signed out of your session."), result.data?.block && /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, "This action has been blocked for security reasons."), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: () => close(result) }, "Close")));
|
|
1275
|
+
const renderError = (message) => {
|
|
1276
|
+
const sessionExpired = /session\s+expired/i.test(message);
|
|
1277
|
+
return /* @__PURE__ */ React__default.default.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React__default.default.createElement("div", { style: errorCircleStyle }, "!"), /* @__PURE__ */ React__default.default.createElement("h3", { style: titleStyle }, sessionExpired ? "Session expired" : "Something Went Wrong"), /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, sessionExpired ? "Your verification session is no longer valid. Please start a new verification from the beginning." : message), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, !sessionExpired && /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: () => setStage({ kind: "capture" }) }, "Try Again"), /* @__PURE__ */ React__default.default.createElement("button", { style: cancelButtonStyle, onClick: () => close(null) }, sessionExpired ? "Close" : "Cancel")));
|
|
1278
|
+
};
|
|
1160
1279
|
const body = (() => {
|
|
1161
1280
|
switch (stage.kind) {
|
|
1162
1281
|
case "choose":
|
|
@@ -1364,11 +1483,14 @@ var attemptsTextStyle = {
|
|
|
1364
1483
|
};
|
|
1365
1484
|
var footerStyle = { padding: "12px 24px 16px", borderTop: "1px solid #f3f4f6" };
|
|
1366
1485
|
var footerTextStyle = { margin: 0, fontSize: 12, color: "#9ca3af", textAlign: "center" };
|
|
1367
|
-
function LiveCamera({ onCapture, onCancel, message }) {
|
|
1486
|
+
function LiveCamera({ onCapture, onCancel, message, assetBasePath }) {
|
|
1368
1487
|
const videoRef = React.useRef(null);
|
|
1369
1488
|
const streamRef = React.useRef(null);
|
|
1489
|
+
const samplesRef = React.useRef([]);
|
|
1370
1490
|
const [ready, setReady] = React.useState(false);
|
|
1371
1491
|
const [error, setError] = React.useState(null);
|
|
1492
|
+
const [faceStatus, setFaceStatus] = React.useState("idle");
|
|
1493
|
+
const [faceDetectionFailed, setFaceDetectionFailed] = React.useState(false);
|
|
1372
1494
|
React.useEffect(() => {
|
|
1373
1495
|
let cancelled = false;
|
|
1374
1496
|
async function init() {
|
|
@@ -1409,6 +1531,75 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1409
1531
|
streamRef.current = null;
|
|
1410
1532
|
};
|
|
1411
1533
|
}, []);
|
|
1534
|
+
React.useEffect(() => {
|
|
1535
|
+
if (!ready) {
|
|
1536
|
+
setFaceStatus("idle");
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
let cancelled = false;
|
|
1540
|
+
let rafId = null;
|
|
1541
|
+
let detector = null;
|
|
1542
|
+
setFaceStatus("loading");
|
|
1543
|
+
setFaceDetectionFailed(false);
|
|
1544
|
+
samplesRef.current = [];
|
|
1545
|
+
(async () => {
|
|
1546
|
+
try {
|
|
1547
|
+
const FaceDetection = await loadMediaPipeFaceDetection(assetBasePath);
|
|
1548
|
+
if (cancelled) return;
|
|
1549
|
+
const assetBase = resolveMediaPipeBase(assetBasePath);
|
|
1550
|
+
const d = new FaceDetection({
|
|
1551
|
+
locateFile: (f) => `${assetBase}/${f}`
|
|
1552
|
+
});
|
|
1553
|
+
d.setOptions({ model: "short", minDetectionConfidence: 0.5 });
|
|
1554
|
+
d.onResults((results) => {
|
|
1555
|
+
if (cancelled) return;
|
|
1556
|
+
const detections = results.detections ?? [];
|
|
1557
|
+
const status = mapDetectionsToFaceStatus(detections);
|
|
1558
|
+
samplesRef.current.push({
|
|
1559
|
+
t: Date.now(),
|
|
1560
|
+
status,
|
|
1561
|
+
...detections.length > 0 ? { boundingBox: detections[0].boundingBox } : {}
|
|
1562
|
+
});
|
|
1563
|
+
if (samplesRef.current.length > LIVENESS_SAMPLE_LIMIT) {
|
|
1564
|
+
samplesRef.current.shift();
|
|
1565
|
+
}
|
|
1566
|
+
setFaceStatus(status);
|
|
1567
|
+
});
|
|
1568
|
+
await d.initialize();
|
|
1569
|
+
if (cancelled) return;
|
|
1570
|
+
detector = d;
|
|
1571
|
+
setFaceStatus("scanning");
|
|
1572
|
+
const tick = async () => {
|
|
1573
|
+
if (cancelled) return;
|
|
1574
|
+
const v = videoRef.current;
|
|
1575
|
+
if (v?.readyState === 4 && detector) {
|
|
1576
|
+
try {
|
|
1577
|
+
await detector.send({ image: v });
|
|
1578
|
+
} catch {
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
if (!cancelled) {
|
|
1582
|
+
rafId = requestAnimationFrame(tick);
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
tick();
|
|
1586
|
+
} catch (err) {
|
|
1587
|
+
console.error("Face detection failed to initialize:", err);
|
|
1588
|
+
if (!cancelled) {
|
|
1589
|
+
setFaceDetectionFailed(true);
|
|
1590
|
+
setFaceStatus("scanning");
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
})();
|
|
1594
|
+
return () => {
|
|
1595
|
+
cancelled = true;
|
|
1596
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
1597
|
+
try {
|
|
1598
|
+
detector?.close?.();
|
|
1599
|
+
} catch {
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
}, [ready, assetBasePath]);
|
|
1412
1603
|
const capture = () => {
|
|
1413
1604
|
const video = videoRef.current;
|
|
1414
1605
|
if (!video || !video.videoWidth) return;
|
|
@@ -1425,12 +1616,22 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1425
1616
|
ctx.drawImage(video, sx, sy, size, size, 0, 0, size, size);
|
|
1426
1617
|
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
1427
1618
|
streamRef.current = null;
|
|
1428
|
-
onCapture(canvas.toDataURL("image/jpeg", 0.9));
|
|
1619
|
+
onCapture(canvas.toDataURL("image/jpeg", 0.9), buildLivenessArtifact(samplesRef.current));
|
|
1429
1620
|
};
|
|
1430
1621
|
if (error) {
|
|
1431
1622
|
return /* @__PURE__ */ React__default.default.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center", padding: 0 } }, /* @__PURE__ */ React__default.default.createElement("div", { style: errorCircleStyle }, "!"), /* @__PURE__ */ React__default.default.createElement("h3", { style: titleStyle }, "Camera unavailable"), /* @__PURE__ */ React__default.default.createElement("p", { style: alertTextStyle }, error), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: secondaryButtonStyle, onClick: onCancel }, "Back")));
|
|
1432
1623
|
}
|
|
1433
|
-
|
|
1624
|
+
const detectionActive = ready && !faceDetectionFailed;
|
|
1625
|
+
const liveMessage = detectionActive ? FACE_MESSAGES[faceStatus] : message;
|
|
1626
|
+
const liveFaceColor = detectionActive ? FACE_COLORS[faceStatus] : void 0;
|
|
1627
|
+
const captureDisabled = isCaptureDisabled(ready, detectionActive, faceStatus);
|
|
1628
|
+
const ringPulse = detectionActive && (faceStatus === "too_far" || faceStatus === "too_close") ? "pulse 1.5s ease-in-out infinite" : void 0;
|
|
1629
|
+
const dynamicCircleStyle = {
|
|
1630
|
+
...faceCircleStyle,
|
|
1631
|
+
...liveFaceColor ? { borderColor: liveFaceColor } : null,
|
|
1632
|
+
...ringPulse ? { animation: ringPulse } : null
|
|
1633
|
+
};
|
|
1634
|
+
return /* @__PURE__ */ React__default.default.createElement("div", { style: videoFrameStyle }, /* @__PURE__ */ React__default.default.createElement(
|
|
1434
1635
|
"video",
|
|
1435
1636
|
{
|
|
1436
1637
|
ref: videoRef,
|
|
@@ -1439,24 +1640,87 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1439
1640
|
autoPlay: true,
|
|
1440
1641
|
style: videoStyle
|
|
1441
1642
|
}
|
|
1442
|
-
), /* @__PURE__ */ React__default.default.createElement("div", { style: faceOverlayContainerStyle, "aria-hidden": "true" }, /* @__PURE__ */ React__default.default.createElement("div", { style: faceRingWrapStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: faceDashedRingStyle }), /* @__PURE__ */ React__default.default.createElement("div", { style:
|
|
1643
|
+
), /* @__PURE__ */ React__default.default.createElement("div", { style: faceOverlayContainerStyle, "aria-hidden": "true" }, /* @__PURE__ */ React__default.default.createElement("div", { style: faceRingWrapStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: faceDashedRingStyle }), /* @__PURE__ */ React__default.default.createElement("div", { style: dynamicCircleStyle }))), liveMessage && /* @__PURE__ */ React__default.default.createElement("div", { style: liveMessagePillContainerStyle }, /* @__PURE__ */ React__default.default.createElement("div", { style: liveMessagePillStyle }, /* @__PURE__ */ React__default.default.createElement("span", { style: liveMessagePillTextStyle }, liveMessage))), /* @__PURE__ */ React__default.default.createElement(
|
|
1644
|
+
"button",
|
|
1645
|
+
{
|
|
1646
|
+
type: "button",
|
|
1647
|
+
onClick: onCancel,
|
|
1648
|
+
"aria-label": "Close camera",
|
|
1649
|
+
style: overlayCloseButtonStyle
|
|
1650
|
+
},
|
|
1651
|
+
/* @__PURE__ */ React__default.default.createElement("img", { src: Close, alt: "", width: 16, height: 16 })
|
|
1652
|
+
), !ready && /* @__PURE__ */ React__default.default.createElement("div", { style: videoLoadingStyle }, "Starting camera\u2026"), /* @__PURE__ */ React__default.default.createElement("div", { style: bottomGradientStyle }, /* @__PURE__ */ React__default.default.createElement(
|
|
1443
1653
|
"button",
|
|
1444
1654
|
{
|
|
1445
|
-
|
|
1655
|
+
type: "button",
|
|
1446
1656
|
onClick: capture,
|
|
1447
|
-
disabled:
|
|
1657
|
+
disabled: captureDisabled,
|
|
1658
|
+
"aria-label": "Capture",
|
|
1659
|
+
style: captureDisabled ? { ...shutterButtonStyle, opacity: 0.5, cursor: "not-allowed" } : shutterButtonStyle
|
|
1448
1660
|
},
|
|
1449
|
-
/* @__PURE__ */ React__default.default.createElement("
|
|
1450
|
-
|
|
1451
|
-
), /* @__PURE__ */ React__default.default.createElement("button", { style: secondaryButtonStyle, onClick: onCancel }, "Cancel")));
|
|
1661
|
+
/* @__PURE__ */ React__default.default.createElement("span", { style: shutterInnerStyle })
|
|
1662
|
+
)));
|
|
1452
1663
|
}
|
|
1453
1664
|
var videoFrameStyle = {
|
|
1454
1665
|
position: "relative",
|
|
1455
1666
|
width: "100%",
|
|
1456
|
-
aspectRatio: "
|
|
1457
|
-
borderRadius:
|
|
1667
|
+
aspectRatio: "3 / 4",
|
|
1668
|
+
borderRadius: 24,
|
|
1458
1669
|
overflow: "hidden",
|
|
1459
|
-
background: "#
|
|
1670
|
+
background: "#000000",
|
|
1671
|
+
border: "4px solid rgba(255, 255, 255, 0.08)",
|
|
1672
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)"
|
|
1673
|
+
};
|
|
1674
|
+
var overlayCloseButtonStyle = {
|
|
1675
|
+
position: "absolute",
|
|
1676
|
+
top: 12,
|
|
1677
|
+
right: 12,
|
|
1678
|
+
width: 32,
|
|
1679
|
+
height: 32,
|
|
1680
|
+
display: "inline-flex",
|
|
1681
|
+
alignItems: "center",
|
|
1682
|
+
justifyContent: "center",
|
|
1683
|
+
padding: 0,
|
|
1684
|
+
border: "none",
|
|
1685
|
+
borderRadius: "50%",
|
|
1686
|
+
background: "rgba(0, 0, 0, 0.4)",
|
|
1687
|
+
backdropFilter: "blur(6px)",
|
|
1688
|
+
color: "#ffffff",
|
|
1689
|
+
cursor: "pointer",
|
|
1690
|
+
zIndex: 10
|
|
1691
|
+
};
|
|
1692
|
+
var bottomGradientStyle = {
|
|
1693
|
+
position: "absolute",
|
|
1694
|
+
bottom: 0,
|
|
1695
|
+
left: 0,
|
|
1696
|
+
right: 0,
|
|
1697
|
+
padding: "16px",
|
|
1698
|
+
background: "linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%)",
|
|
1699
|
+
display: "flex",
|
|
1700
|
+
alignItems: "center",
|
|
1701
|
+
justifyContent: "center",
|
|
1702
|
+
zIndex: 10
|
|
1703
|
+
};
|
|
1704
|
+
var shutterButtonStyle = {
|
|
1705
|
+
width: 64,
|
|
1706
|
+
height: 64,
|
|
1707
|
+
borderRadius: "50%",
|
|
1708
|
+
background: "rgba(255, 255, 255, 0.15)",
|
|
1709
|
+
backdropFilter: "blur(6px)",
|
|
1710
|
+
border: "2px solid rgba(255, 255, 255, 0.7)",
|
|
1711
|
+
display: "inline-flex",
|
|
1712
|
+
alignItems: "center",
|
|
1713
|
+
justifyContent: "center",
|
|
1714
|
+
cursor: "pointer",
|
|
1715
|
+
padding: 0,
|
|
1716
|
+
transition: "transform 120ms ease-out, background 120ms"
|
|
1717
|
+
};
|
|
1718
|
+
var shutterInnerStyle = {
|
|
1719
|
+
display: "block",
|
|
1720
|
+
width: 44,
|
|
1721
|
+
height: 44,
|
|
1722
|
+
borderRadius: "50%",
|
|
1723
|
+
background: "rgba(255, 255, 255, 0.85)"
|
|
1460
1724
|
};
|
|
1461
1725
|
var videoStyle = {
|
|
1462
1726
|
width: "100%",
|
|
@@ -1500,7 +1764,9 @@ var videoLoadingStyle = {
|
|
|
1500
1764
|
justifyContent: "center",
|
|
1501
1765
|
color: "#e5e7eb",
|
|
1502
1766
|
fontSize: 14,
|
|
1503
|
-
fontWeight: 500
|
|
1767
|
+
fontWeight: 500,
|
|
1768
|
+
background: "rgba(0, 0, 0, 0.4)",
|
|
1769
|
+
zIndex: 5
|
|
1504
1770
|
};
|
|
1505
1771
|
var liveMessagePillContainerStyle = {
|
|
1506
1772
|
position: "absolute",
|
|
@@ -1865,9 +2131,9 @@ function getRiskColor(risk) {
|
|
|
1865
2131
|
};
|
|
1866
2132
|
return colorMap[risk] || "#6b7280";
|
|
1867
2133
|
}
|
|
1868
|
-
function
|
|
2134
|
+
function useEventBasedFaceVerificationSubmission(client$1) {
|
|
1869
2135
|
const startSession = React.useCallback(
|
|
1870
|
-
(request) => client$1.
|
|
2136
|
+
(request) => client$1.createEventBasedFaceVerificationSession(request),
|
|
1871
2137
|
[client$1]
|
|
1872
2138
|
);
|
|
1873
2139
|
const verifyFace = React.useCallback(
|
|
@@ -1884,6 +2150,8 @@ function useReuseKYCSubmission(client$1) {
|
|
|
1884
2150
|
session,
|
|
1885
2151
|
defaultDevice: opts.defaultDevice,
|
|
1886
2152
|
renderQR: opts.renderQR,
|
|
2153
|
+
onCancel: opts.onCancel,
|
|
2154
|
+
mediapipeAssetBasePath: opts.mediapipeAssetBasePath,
|
|
1887
2155
|
onComplete: (result) => {
|
|
1888
2156
|
cleanup();
|
|
1889
2157
|
resolve(result);
|
|
@@ -1920,6 +2188,7 @@ exports.isValidFileSize = isValidFileSize;
|
|
|
1920
2188
|
exports.isValidFileType = isValidFileType;
|
|
1921
2189
|
exports.useCipherText = useCipherText;
|
|
1922
2190
|
exports.useCustomerProfile = useCustomerProfile;
|
|
2191
|
+
exports.useEventBasedFaceVerificationSubmission = useEventBasedFaceVerificationSubmission;
|
|
1923
2192
|
exports.useGeolocation = useGeolocation;
|
|
1924
2193
|
exports.useKycAlerts = useKycAlerts;
|
|
1925
2194
|
exports.useKycOverview = useKycOverview;
|
|
@@ -1930,7 +2199,6 @@ exports.useLocationCapture = useLocationCapture;
|
|
|
1930
2199
|
exports.useLocationRequests = useLocationRequests;
|
|
1931
2200
|
exports.useLoginVerification = useLoginVerification;
|
|
1932
2201
|
exports.useRegistration = useRegistration;
|
|
1933
|
-
exports.useReuseKYCSubmission = useReuseKYCSubmission;
|
|
1934
2202
|
exports.useTransactionVerification = useTransactionVerification;
|
|
1935
2203
|
//# sourceMappingURL=react.js.map
|
|
1936
2204
|
//# sourceMappingURL=react.js.map
|