vesant-sdk 1.7.0-dev.e0ee6d5 → 1.7.0-next.a744d2e
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/react.d.mts +2 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +242 -22
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +242 -22
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.d.mts
CHANGED
|
@@ -529,10 +529,12 @@ declare function useReuseKYCSubmission(client: KycClient): {
|
|
|
529
529
|
verifyFace: (session: CreateReuseKycSessionResponse, opts?: {
|
|
530
530
|
defaultDevice?: "ask" | "this" | "mobile";
|
|
531
531
|
renderQR?: (payload: string) => React.ReactNode;
|
|
532
|
+
onCancel?: () => void;
|
|
532
533
|
}) => Promise<ReuseKycCallback | null>;
|
|
533
534
|
runFlow: (request: CreateReuseKycSessionRequest, opts?: {
|
|
534
535
|
defaultDevice?: "ask" | "this" | "mobile";
|
|
535
536
|
renderQR?: (payload: string) => React.ReactNode;
|
|
537
|
+
onCancel?: () => void;
|
|
536
538
|
}) => Promise<{
|
|
537
539
|
kind: "not_required";
|
|
538
540
|
session: CreateReuseKycSessionResponse;
|
package/dist/react.d.ts
CHANGED
|
@@ -529,10 +529,12 @@ declare function useReuseKYCSubmission(client: KycClient): {
|
|
|
529
529
|
verifyFace: (session: CreateReuseKycSessionResponse, opts?: {
|
|
530
530
|
defaultDevice?: "ask" | "this" | "mobile";
|
|
531
531
|
renderQR?: (payload: string) => React.ReactNode;
|
|
532
|
+
onCancel?: () => void;
|
|
532
533
|
}) => Promise<ReuseKycCallback | null>;
|
|
533
534
|
runFlow: (request: CreateReuseKycSessionRequest, opts?: {
|
|
534
535
|
defaultDevice?: "ask" | "this" | "mobile";
|
|
535
536
|
renderQR?: (payload: string) => React.ReactNode;
|
|
537
|
+
onCancel?: () => void;
|
|
536
538
|
}) => Promise<{
|
|
537
539
|
kind: "not_required";
|
|
538
540
|
session: CreateReuseKycSessionResponse;
|
package/dist/react.js
CHANGED
|
@@ -888,7 +888,6 @@ 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
|
-
var Upload = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xNyAxN0gxNy4wMU0xNS42IDE0SDE4QzE4LjkzMTkgMTQgMTkuMzk3OCAxNCAxOS43NjU0IDE0LjE1MjJDMjAuMjU1NCAxNC4zNTUyIDIwLjY0NDggMTQuNzQ0NiAyMC44NDc4IDE1LjIzNDZDMjEgMTUuNjAyMiAyMSAxNi4wNjgxIDIxIDE3QzIxIDE3LjkzMTkgMjEgMTguMzk3OCAyMC44NDc4IDE4Ljc2NTRDMjAuNjQ0OCAxOS4yNTU0IDIwLjI1NTQgMTkuNjQ0OCAxOS43NjU0IDE5Ljg0NzhDMTkuMzk3OCAyMCAxOC45MzE5IDIwIDE4IDIwSDZDNS4wNjgxMiAyMCA0LjYwMjE4IDIwIDQuMjM0NjMgMTkuODQ3OEMzLjc0NDU4IDE5LjY0NDggMy4zNTUyMyAxOS4yNTU0IDMuMTUyMjQgMTguNzY1NEMzIDE4LjM5NzggMyAxNy45MzE5IDMgMTdDMyAxNi4wNjgxIDMgMTUuNjAyMiAzLjE1MjI0IDE1LjIzNDZDMy4zNTUyMyAxNC43NDQ2IDMuNzQ0NTggMTQuMzU1MiA0LjIzNDYzIDE0LjE1MjJDNC42MDIxOCAxNCA1LjA2ODEyIDE0IDYgMTRIOC40TTEyIDE1VjRNMTIgNEwxNSA3TTEyIDRMOSA3IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+DQo8L3N2Zz4=";
|
|
892
891
|
|
|
893
892
|
// src/kyc/FaceCaptureModal.tsx
|
|
894
893
|
var MOBILE_UA = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
@@ -905,9 +904,9 @@ function headerSubtitle(stageKind) {
|
|
|
905
904
|
case "accepted":
|
|
906
905
|
return "All set";
|
|
907
906
|
case "declined":
|
|
908
|
-
return "Verification
|
|
907
|
+
return "Verification Declined";
|
|
909
908
|
case "max_attempts":
|
|
910
|
-
return "We couldn't verify
|
|
909
|
+
return "We couldn't verify your identity";
|
|
911
910
|
default:
|
|
912
911
|
return "Please capture a clear photo of your face";
|
|
913
912
|
}
|
|
@@ -920,16 +919,18 @@ function FaceCaptureModal({
|
|
|
920
919
|
client,
|
|
921
920
|
session,
|
|
922
921
|
onComplete,
|
|
922
|
+
onCancel,
|
|
923
923
|
defaultDevice,
|
|
924
924
|
renderQR
|
|
925
925
|
}) {
|
|
926
926
|
const isMobile = typeof navigator !== "undefined" && MOBILE_UA.test(navigator.userAgent);
|
|
927
|
+
const initialChoice = defaultDevice ?? (isMobile ? "this" : "ask");
|
|
927
928
|
const initialStage = (() => {
|
|
928
|
-
|
|
929
|
-
if (
|
|
930
|
-
if (choice === "mobile") return { kind: "qr", mobileConnected: false };
|
|
929
|
+
if (initialChoice === "this") return { kind: "capture" };
|
|
930
|
+
if (initialChoice === "mobile") return { kind: "qr", mobileConnected: false };
|
|
931
931
|
return { kind: "choose" };
|
|
932
932
|
})();
|
|
933
|
+
const hasMethodChoice = initialChoice === "ask";
|
|
933
934
|
const [stage, setStage] = React.useState(initialStage);
|
|
934
935
|
const [attempts, setAttempts] = React.useState(session.attempts);
|
|
935
936
|
const maxAttempts = session.max_attempts || 1;
|
|
@@ -1110,6 +1111,9 @@ function FaceCaptureModal({
|
|
|
1110
1111
|
}, [captureMode]);
|
|
1111
1112
|
const close = (result) => {
|
|
1112
1113
|
cancelledRef.current = true;
|
|
1114
|
+
if (result === null && onCancel) {
|
|
1115
|
+
onCancel();
|
|
1116
|
+
}
|
|
1113
1117
|
onComplete(result);
|
|
1114
1118
|
};
|
|
1115
1119
|
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 +1122,7 @@ function FaceCaptureModal({
|
|
|
1118
1122
|
style: primaryButtonStyle,
|
|
1119
1123
|
onClick: () => setStage({ kind: "capture" })
|
|
1120
1124
|
},
|
|
1121
|
-
/* @__PURE__ */ React__default.default.createElement("img", { src:
|
|
1125
|
+
/* @__PURE__ */ React__default.default.createElement("img", { src: Camera, alt: "", width: 20, height: 20 }),
|
|
1122
1126
|
/* @__PURE__ */ React__default.default.createElement("span", null, "Continue on this device")
|
|
1123
1127
|
), /* @__PURE__ */ React__default.default.createElement(
|
|
1124
1128
|
"button",
|
|
@@ -1135,6 +1139,13 @@ function FaceCaptureModal({
|
|
|
1135
1139
|
onClick: () => setStage({ kind: "capture" })
|
|
1136
1140
|
},
|
|
1137
1141
|
"Use this device instead"
|
|
1142
|
+
), hasMethodChoice && /* @__PURE__ */ React__default.default.createElement(
|
|
1143
|
+
"button",
|
|
1144
|
+
{
|
|
1145
|
+
style: secondaryButtonStyle,
|
|
1146
|
+
onClick: () => setStage({ kind: "choose" })
|
|
1147
|
+
},
|
|
1148
|
+
"Change verification method"
|
|
1138
1149
|
), /* @__PURE__ */ React__default.default.createElement("button", { style: cancelButtonStyle, onClick: () => close(null) }, "Cancel")));
|
|
1139
1150
|
const renderCapture = (declinedReason) => {
|
|
1140
1151
|
if (captureMode === "live") {
|
|
@@ -1150,13 +1161,23 @@ function FaceCaptureModal({
|
|
|
1150
1161
|
if (captureMode === "preview" && capturedPreview) {
|
|
1151
1162
|
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
1163
|
}
|
|
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 again" : "Open Camera")),
|
|
1164
|
+
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(
|
|
1165
|
+
"button",
|
|
1166
|
+
{
|
|
1167
|
+
style: secondaryButtonStyle,
|
|
1168
|
+
onClick: () => setStage({ kind: "choose" })
|
|
1169
|
+
},
|
|
1170
|
+
"Change verification method"
|
|
1171
|
+
), /* @__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
1172
|
};
|
|
1155
1173
|
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
1174
|
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) =>
|
|
1175
|
+
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));
|
|
1176
|
+
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."), /* @__PURE__ */ React__default.default.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React__default.default.createElement("button", { style: primaryButtonStyle, onClick: () => close(result) }, "Close")));
|
|
1177
|
+
const renderError = (message) => {
|
|
1178
|
+
const sessionExpired = /session\s+expired/i.test(message);
|
|
1179
|
+
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")));
|
|
1180
|
+
};
|
|
1160
1181
|
const body = (() => {
|
|
1161
1182
|
switch (stage.kind) {
|
|
1162
1183
|
case "choose":
|
|
@@ -1364,11 +1385,63 @@ var attemptsTextStyle = {
|
|
|
1364
1385
|
};
|
|
1365
1386
|
var footerStyle = { padding: "12px 24px 16px", borderTop: "1px solid #f3f4f6" };
|
|
1366
1387
|
var footerTextStyle = { margin: 0, fontSize: 12, color: "#9ca3af", textAlign: "center" };
|
|
1388
|
+
var FACE_MESSAGES = {
|
|
1389
|
+
idle: "Initializing camera...",
|
|
1390
|
+
loading: "Loading face detection...",
|
|
1391
|
+
scanning: "Position your face in the circle",
|
|
1392
|
+
too_far: "Face too far. Please move closer to the camera",
|
|
1393
|
+
too_close: "Too close. Please move back a little",
|
|
1394
|
+
off_center: "Center your face in the circle",
|
|
1395
|
+
ok: "Looking great! Tap the button to capture"
|
|
1396
|
+
};
|
|
1397
|
+
var FACE_COLORS = {
|
|
1398
|
+
idle: "#9ca3af",
|
|
1399
|
+
loading: "#3b82f6",
|
|
1400
|
+
scanning: "#3b82f6",
|
|
1401
|
+
too_far: "#ef4444",
|
|
1402
|
+
too_close: "#f59e0b",
|
|
1403
|
+
off_center: "#f59e0b",
|
|
1404
|
+
ok: "#10b981"
|
|
1405
|
+
};
|
|
1406
|
+
var MEDIAPIPE_BASE = "https://cdn.jsdelivr.net/npm/@mediapipe/face_detection";
|
|
1407
|
+
var mediapipeLoaderPromise = null;
|
|
1408
|
+
function loadMediaPipeFaceDetection() {
|
|
1409
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1410
|
+
return Promise.reject(new Error("MediaPipe requires a browser environment"));
|
|
1411
|
+
}
|
|
1412
|
+
const w = window;
|
|
1413
|
+
if (w.FaceDetection) {
|
|
1414
|
+
return Promise.resolve(w.FaceDetection);
|
|
1415
|
+
}
|
|
1416
|
+
if (mediapipeLoaderPromise) return mediapipeLoaderPromise;
|
|
1417
|
+
mediapipeLoaderPromise = new Promise((resolve, reject) => {
|
|
1418
|
+
const script = document.createElement("script");
|
|
1419
|
+
script.src = `${MEDIAPIPE_BASE}/face_detection.js`;
|
|
1420
|
+
script.async = true;
|
|
1421
|
+
script.crossOrigin = "anonymous";
|
|
1422
|
+
script.onload = () => {
|
|
1423
|
+
if (w.FaceDetection) {
|
|
1424
|
+
resolve(w.FaceDetection);
|
|
1425
|
+
} else {
|
|
1426
|
+
mediapipeLoaderPromise = null;
|
|
1427
|
+
reject(new Error("MediaPipe loaded but FaceDetection global is missing"));
|
|
1428
|
+
}
|
|
1429
|
+
};
|
|
1430
|
+
script.onerror = () => {
|
|
1431
|
+
mediapipeLoaderPromise = null;
|
|
1432
|
+
reject(new Error("Failed to load MediaPipe face_detection script"));
|
|
1433
|
+
};
|
|
1434
|
+
document.head.appendChild(script);
|
|
1435
|
+
});
|
|
1436
|
+
return mediapipeLoaderPromise;
|
|
1437
|
+
}
|
|
1367
1438
|
function LiveCamera({ onCapture, onCancel, message }) {
|
|
1368
1439
|
const videoRef = React.useRef(null);
|
|
1369
1440
|
const streamRef = React.useRef(null);
|
|
1370
1441
|
const [ready, setReady] = React.useState(false);
|
|
1371
1442
|
const [error, setError] = React.useState(null);
|
|
1443
|
+
const [faceStatus, setFaceStatus] = React.useState("idle");
|
|
1444
|
+
const [faceDetectionFailed, setFaceDetectionFailed] = React.useState(false);
|
|
1372
1445
|
React.useEffect(() => {
|
|
1373
1446
|
let cancelled = false;
|
|
1374
1447
|
async function init() {
|
|
@@ -1409,6 +1482,77 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1409
1482
|
streamRef.current = null;
|
|
1410
1483
|
};
|
|
1411
1484
|
}, []);
|
|
1485
|
+
React.useEffect(() => {
|
|
1486
|
+
if (!ready) {
|
|
1487
|
+
setFaceStatus("idle");
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
let cancelled = false;
|
|
1491
|
+
let rafId = null;
|
|
1492
|
+
let detector = null;
|
|
1493
|
+
setFaceStatus("loading");
|
|
1494
|
+
setFaceDetectionFailed(false);
|
|
1495
|
+
(async () => {
|
|
1496
|
+
try {
|
|
1497
|
+
const FaceDetection = await loadMediaPipeFaceDetection();
|
|
1498
|
+
if (cancelled) return;
|
|
1499
|
+
const d = new FaceDetection({
|
|
1500
|
+
locateFile: (f) => `${MEDIAPIPE_BASE}/${f}`
|
|
1501
|
+
});
|
|
1502
|
+
d.setOptions({ model: "short", minDetectionConfidence: 0.5 });
|
|
1503
|
+
d.onResults((results) => {
|
|
1504
|
+
if (cancelled) return;
|
|
1505
|
+
const detections = results.detections ?? [];
|
|
1506
|
+
let next;
|
|
1507
|
+
if (detections.length === 0) {
|
|
1508
|
+
next = "scanning";
|
|
1509
|
+
} else {
|
|
1510
|
+
const bb = detections[0].boundingBox;
|
|
1511
|
+
if (bb.width < 0.18) next = "too_far";
|
|
1512
|
+
else if (bb.width > 0.72) next = "too_close";
|
|
1513
|
+
else if (bb.xCenter < 0.28 || bb.xCenter > 0.72 || bb.yCenter < 0.28 || bb.yCenter > 0.72) {
|
|
1514
|
+
next = "off_center";
|
|
1515
|
+
} else {
|
|
1516
|
+
next = "ok";
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
setFaceStatus(next);
|
|
1520
|
+
});
|
|
1521
|
+
await d.initialize();
|
|
1522
|
+
if (cancelled) return;
|
|
1523
|
+
detector = d;
|
|
1524
|
+
setFaceStatus("scanning");
|
|
1525
|
+
const tick = async () => {
|
|
1526
|
+
if (cancelled) return;
|
|
1527
|
+
const v = videoRef.current;
|
|
1528
|
+
if (v?.readyState === 4 && detector) {
|
|
1529
|
+
try {
|
|
1530
|
+
await detector.send({ image: v });
|
|
1531
|
+
} catch {
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
if (!cancelled) {
|
|
1535
|
+
rafId = requestAnimationFrame(tick);
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
tick();
|
|
1539
|
+
} catch (err) {
|
|
1540
|
+
console.error("Face detection failed to initialize:", err);
|
|
1541
|
+
if (!cancelled) {
|
|
1542
|
+
setFaceDetectionFailed(true);
|
|
1543
|
+
setFaceStatus("scanning");
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
})();
|
|
1547
|
+
return () => {
|
|
1548
|
+
cancelled = true;
|
|
1549
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
1550
|
+
try {
|
|
1551
|
+
detector?.close?.();
|
|
1552
|
+
} catch {
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
}, [ready]);
|
|
1412
1556
|
const capture = () => {
|
|
1413
1557
|
const video = videoRef.current;
|
|
1414
1558
|
if (!video || !video.videoWidth) return;
|
|
@@ -1430,7 +1574,17 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1430
1574
|
if (error) {
|
|
1431
1575
|
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
1576
|
}
|
|
1433
|
-
|
|
1577
|
+
const detectionActive = ready && !faceDetectionFailed;
|
|
1578
|
+
const liveMessage = detectionActive ? FACE_MESSAGES[faceStatus] : message;
|
|
1579
|
+
const liveFaceColor = detectionActive ? FACE_COLORS[faceStatus] : void 0;
|
|
1580
|
+
const captureDisabled = !ready || detectionActive && faceStatus !== "ok";
|
|
1581
|
+
const ringPulse = detectionActive && (faceStatus === "too_far" || faceStatus === "too_close") ? "pulse 1.5s ease-in-out infinite" : void 0;
|
|
1582
|
+
const dynamicCircleStyle = {
|
|
1583
|
+
...faceCircleStyle,
|
|
1584
|
+
...liveFaceColor ? { borderColor: liveFaceColor } : null,
|
|
1585
|
+
...ringPulse ? { animation: ringPulse } : null
|
|
1586
|
+
};
|
|
1587
|
+
return /* @__PURE__ */ React__default.default.createElement("div", { style: videoFrameStyle }, /* @__PURE__ */ React__default.default.createElement(
|
|
1434
1588
|
"video",
|
|
1435
1589
|
{
|
|
1436
1590
|
ref: videoRef,
|
|
@@ -1439,24 +1593,87 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1439
1593
|
autoPlay: true,
|
|
1440
1594
|
style: videoStyle
|
|
1441
1595
|
}
|
|
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:
|
|
1596
|
+
), /* @__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(
|
|
1443
1597
|
"button",
|
|
1444
1598
|
{
|
|
1445
|
-
|
|
1599
|
+
type: "button",
|
|
1600
|
+
onClick: onCancel,
|
|
1601
|
+
"aria-label": "Close camera",
|
|
1602
|
+
style: overlayCloseButtonStyle
|
|
1603
|
+
},
|
|
1604
|
+
/* @__PURE__ */ React__default.default.createElement("img", { src: Close, alt: "", width: 16, height: 16 })
|
|
1605
|
+
), !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(
|
|
1606
|
+
"button",
|
|
1607
|
+
{
|
|
1608
|
+
type: "button",
|
|
1446
1609
|
onClick: capture,
|
|
1447
|
-
disabled:
|
|
1610
|
+
disabled: captureDisabled,
|
|
1611
|
+
"aria-label": "Capture",
|
|
1612
|
+
style: captureDisabled ? { ...shutterButtonStyle, opacity: 0.5, cursor: "not-allowed" } : shutterButtonStyle
|
|
1448
1613
|
},
|
|
1449
|
-
/* @__PURE__ */ React__default.default.createElement("
|
|
1450
|
-
|
|
1451
|
-
), /* @__PURE__ */ React__default.default.createElement("button", { style: secondaryButtonStyle, onClick: onCancel }, "Cancel")));
|
|
1614
|
+
/* @__PURE__ */ React__default.default.createElement("span", { style: shutterInnerStyle })
|
|
1615
|
+
)));
|
|
1452
1616
|
}
|
|
1453
1617
|
var videoFrameStyle = {
|
|
1454
1618
|
position: "relative",
|
|
1455
1619
|
width: "100%",
|
|
1456
|
-
aspectRatio: "
|
|
1457
|
-
borderRadius:
|
|
1620
|
+
aspectRatio: "3 / 4",
|
|
1621
|
+
borderRadius: 24,
|
|
1458
1622
|
overflow: "hidden",
|
|
1459
|
-
background: "#
|
|
1623
|
+
background: "#000000",
|
|
1624
|
+
border: "4px solid rgba(255, 255, 255, 0.08)",
|
|
1625
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)"
|
|
1626
|
+
};
|
|
1627
|
+
var overlayCloseButtonStyle = {
|
|
1628
|
+
position: "absolute",
|
|
1629
|
+
top: 12,
|
|
1630
|
+
right: 12,
|
|
1631
|
+
width: 32,
|
|
1632
|
+
height: 32,
|
|
1633
|
+
display: "inline-flex",
|
|
1634
|
+
alignItems: "center",
|
|
1635
|
+
justifyContent: "center",
|
|
1636
|
+
padding: 0,
|
|
1637
|
+
border: "none",
|
|
1638
|
+
borderRadius: "50%",
|
|
1639
|
+
background: "rgba(0, 0, 0, 0.4)",
|
|
1640
|
+
backdropFilter: "blur(6px)",
|
|
1641
|
+
color: "#ffffff",
|
|
1642
|
+
cursor: "pointer",
|
|
1643
|
+
zIndex: 10
|
|
1644
|
+
};
|
|
1645
|
+
var bottomGradientStyle = {
|
|
1646
|
+
position: "absolute",
|
|
1647
|
+
bottom: 0,
|
|
1648
|
+
left: 0,
|
|
1649
|
+
right: 0,
|
|
1650
|
+
padding: "16px",
|
|
1651
|
+
background: "linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%)",
|
|
1652
|
+
display: "flex",
|
|
1653
|
+
alignItems: "center",
|
|
1654
|
+
justifyContent: "center",
|
|
1655
|
+
zIndex: 10
|
|
1656
|
+
};
|
|
1657
|
+
var shutterButtonStyle = {
|
|
1658
|
+
width: 64,
|
|
1659
|
+
height: 64,
|
|
1660
|
+
borderRadius: "50%",
|
|
1661
|
+
background: "rgba(255, 255, 255, 0.15)",
|
|
1662
|
+
backdropFilter: "blur(6px)",
|
|
1663
|
+
border: "2px solid rgba(255, 255, 255, 0.7)",
|
|
1664
|
+
display: "inline-flex",
|
|
1665
|
+
alignItems: "center",
|
|
1666
|
+
justifyContent: "center",
|
|
1667
|
+
cursor: "pointer",
|
|
1668
|
+
padding: 0,
|
|
1669
|
+
transition: "transform 120ms ease-out, background 120ms"
|
|
1670
|
+
};
|
|
1671
|
+
var shutterInnerStyle = {
|
|
1672
|
+
display: "block",
|
|
1673
|
+
width: 44,
|
|
1674
|
+
height: 44,
|
|
1675
|
+
borderRadius: "50%",
|
|
1676
|
+
background: "rgba(255, 255, 255, 0.85)"
|
|
1460
1677
|
};
|
|
1461
1678
|
var videoStyle = {
|
|
1462
1679
|
width: "100%",
|
|
@@ -1500,7 +1717,9 @@ var videoLoadingStyle = {
|
|
|
1500
1717
|
justifyContent: "center",
|
|
1501
1718
|
color: "#e5e7eb",
|
|
1502
1719
|
fontSize: 14,
|
|
1503
|
-
fontWeight: 500
|
|
1720
|
+
fontWeight: 500,
|
|
1721
|
+
background: "rgba(0, 0, 0, 0.4)",
|
|
1722
|
+
zIndex: 5
|
|
1504
1723
|
};
|
|
1505
1724
|
var liveMessagePillContainerStyle = {
|
|
1506
1725
|
position: "absolute",
|
|
@@ -1884,6 +2103,7 @@ function useReuseKYCSubmission(client$1) {
|
|
|
1884
2103
|
session,
|
|
1885
2104
|
defaultDevice: opts.defaultDevice,
|
|
1886
2105
|
renderQR: opts.renderQR,
|
|
2106
|
+
onCancel: opts.onCancel,
|
|
1887
2107
|
onComplete: (result) => {
|
|
1888
2108
|
cleanup();
|
|
1889
2109
|
resolve(result);
|