vesant-sdk 1.7.1-dev.afc5a32 → 1.7.1-dev.c2ac5a5

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.
Files changed (42) hide show
  1. package/README.md +4 -0
  2. package/dist/{client-D23KhWeh.d.mts → client-5q4whhGu.d.mts} +1 -1
  3. package/dist/{client-fy3trF2K.d.ts → client-BaUekQT8.d.ts} +32 -10
  4. package/dist/{client-B3DCAHlg.d.ts → client-DUHC-68_.d.ts} +1 -1
  5. package/dist/{client-BwXMQA2a.d.mts → client-XDEhh9VN.d.mts} +32 -10
  6. package/dist/compliance/index.d.mts +2 -2
  7. package/dist/compliance/index.d.ts +2 -2
  8. package/dist/compliance/index.js +39 -1
  9. package/dist/compliance/index.js.map +1 -1
  10. package/dist/compliance/index.mjs +39 -1
  11. package/dist/compliance/index.mjs.map +1 -1
  12. package/dist/geolocation/index.d.mts +2 -2
  13. package/dist/geolocation/index.d.ts +2 -2
  14. package/dist/geolocation/index.js +39 -1
  15. package/dist/geolocation/index.js.map +1 -1
  16. package/dist/geolocation/index.mjs +39 -1
  17. package/dist/geolocation/index.mjs.map +1 -1
  18. package/dist/index.d.mts +3 -3
  19. package/dist/index.d.ts +3 -3
  20. package/dist/index.js +86 -23
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +86 -23
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/kyc/core.d.mts +1 -1
  25. package/dist/kyc/core.d.ts +1 -1
  26. package/dist/kyc/core.js +47 -22
  27. package/dist/kyc/core.js.map +1 -1
  28. package/dist/kyc/core.mjs +47 -22
  29. package/dist/kyc/core.mjs.map +1 -1
  30. package/dist/kyc/index.d.mts +178 -39
  31. package/dist/kyc/index.d.ts +178 -39
  32. package/dist/kyc/index.js +47 -22
  33. package/dist/kyc/index.js.map +1 -1
  34. package/dist/kyc/index.mjs +47 -22
  35. package/dist/kyc/index.mjs.map +1 -1
  36. package/dist/react.d.mts +126 -48
  37. package/dist/react.d.ts +126 -48
  38. package/dist/react.js +131 -20
  39. package/dist/react.js.map +1 -1
  40. package/dist/react.mjs +129 -21
  41. package/dist/react.mjs.map +1 -1
  42. package/package.json +1 -1
package/dist/react.mjs CHANGED
@@ -423,14 +423,11 @@ function useCipherText(client) {
423
423
  const [configLoading, setConfigLoading] = useState(!!client);
424
424
  const [configError, setConfigError] = useState(null);
425
425
  const configRef = useRef(void 0);
426
- const configPromiseRef = useRef(null);
427
426
  useEffect(() => {
428
427
  if (!client) return;
429
428
  let cancelled = false;
430
429
  setConfigLoading(true);
431
- const promise = client.getGPSConfig();
432
- configPromiseRef.current = promise;
433
- promise.then((cfg) => {
430
+ client.getGPSConfig().then((cfg) => {
434
431
  if (!cancelled) {
435
432
  configRef.current = cfg;
436
433
  setConfigLoading(false);
@@ -445,13 +442,21 @@ function useCipherText(client) {
445
442
  cancelled = true;
446
443
  };
447
444
  }, [client]);
445
+ const refreshConfig = useCallback(async () => {
446
+ if (!client) return;
447
+ try {
448
+ configRef.current = await client.refreshGPSConfig();
449
+ setConfigError(null);
450
+ } catch (error) {
451
+ setConfigError(error instanceof Error ? error : new Error("Failed to refresh GPS config"));
452
+ }
453
+ }, [client]);
448
454
  const generate = useCallback(
449
455
  async (options) => {
450
456
  try {
451
- if (configPromiseRef.current) {
457
+ if (client) {
452
458
  try {
453
- const cfg = await configPromiseRef.current;
454
- configRef.current = cfg;
459
+ configRef.current = await client.getGPSConfig();
455
460
  } catch {
456
461
  }
457
462
  }
@@ -461,9 +466,9 @@ function useCipherText(client) {
461
466
  return null;
462
467
  }
463
468
  },
464
- []
469
+ [client]
465
470
  );
466
- return { generate, configLoading, configError };
471
+ return { generate, refreshConfig, configLoading, configError };
467
472
  }
468
473
  function useLocationRequests(client, options = {}) {
469
474
  const [requests, setRequests] = useState([]);
@@ -1003,6 +1008,46 @@ function loadMediaPipeFaceDetection(assetBasePath) {
1003
1008
 
1004
1009
  // src/kyc/hostedJourney.ts
1005
1010
  var REUSE_KYC_SESSION_EXPIRY_MS = 10 * 60 * 1e3;
1011
+ var JOURNEY_FRAME_HEIGHT = "clamp(500px, 64vh, 680px)";
1012
+ var JOURNEY_CONFIRM_TIMEOUT_MS = 45e3;
1013
+ function journeyOutcomeFromMessage(data) {
1014
+ const status = data?.verification_status;
1015
+ if (typeof status !== "string") return null;
1016
+ switch (status) {
1017
+ case "verification.accepted":
1018
+ return "accepted";
1019
+ case "verification.declined":
1020
+ return "declined";
1021
+ case "verification.cancelled":
1022
+ case "request.timeout":
1023
+ case "request.invalid":
1024
+ case "request.unauthorized":
1025
+ case "request.deleted":
1026
+ return "cancelled";
1027
+ default:
1028
+ return null;
1029
+ }
1030
+ }
1031
+ function journeyPollIntervalMs(confirming) {
1032
+ return confirming ? 1e3 : 2500;
1033
+ }
1034
+ function pendingJourneyResult(reference) {
1035
+ return {
1036
+ event: "reuse_kyc",
1037
+ reference,
1038
+ resource_id: "",
1039
+ status: "pending",
1040
+ data: {
1041
+ retries_remaining: 0,
1042
+ retry_limit_exceeded: false,
1043
+ trigger_alert: false,
1044
+ enforce_logout: false,
1045
+ freeze_account: false,
1046
+ block: false,
1047
+ freeze_duration_minutes: 0
1048
+ }
1049
+ };
1050
+ }
1006
1051
  function tryStartOperation(guard) {
1007
1052
  if (guard.current) return false;
1008
1053
  guard.current = true;
@@ -1014,12 +1059,22 @@ function releaseOperation(guard) {
1014
1059
  function retryTarget(hasHostedJourney) {
1015
1060
  return hasHostedJourney ? "journey" : "capture";
1016
1061
  }
1062
+ var CAPTURE_MODAL_MAX_WIDTH = 448;
1017
1063
  function modalMaxWidth(hasHostedJourney) {
1018
- return hasHostedJourney ? 680 : 448;
1064
+ return hasHostedJourney ? CAPTURE_MODAL_MAX_WIDTH : CAPTURE_MODAL_MAX_WIDTH;
1065
+ }
1066
+ var JOURNEY_CONTENT_PADDING = 12;
1067
+ function resultForModalClose(stageKind, result, unconfirmed) {
1068
+ const terminal = stageKind === "accepted" || stageKind === "declined" || stageKind === "max_attempts";
1069
+ if (terminal && result !== void 0) return result;
1070
+ const awaitingConfirmation = stageKind === "confirming" || stageKind === "unconfirmed";
1071
+ if (awaitingConfirmation && unconfirmed !== void 0) return unconfirmed;
1072
+ return null;
1019
1073
  }
1020
1074
 
1021
1075
  // src/kyc/FaceCaptureModal.tsx
1022
1076
  var MOBILE_UA = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
1077
+ var ACCEPTED_AUTO_CLOSE_MS = 1200;
1023
1078
  var LIVENESS_MESSAGES = [
1024
1079
  "Position your face inside the oval",
1025
1080
  "Make sure your face is well lit",
@@ -1032,6 +1087,10 @@ function headerSubtitle(stageKind) {
1032
1087
  return "Use your phone to continue";
1033
1088
  case "journey":
1034
1089
  return "Follow the steps to verify your identity";
1090
+ case "confirming":
1091
+ return "Confirming your result";
1092
+ case "unconfirmed":
1093
+ return "Still confirming";
1035
1094
  case "accepted":
1036
1095
  return "All set";
1037
1096
  case "declined":
@@ -1131,8 +1190,10 @@ function FaceCaptureModal({
1131
1190
  stopped = true;
1132
1191
  };
1133
1192
  }, [stage.kind, stage.kind === "qr" ? stage.mobileConnected : false]);
1193
+ const journeyUrl = stage.kind === "journey" || stage.kind === "confirming" ? stage.url : "";
1134
1194
  useEffect(() => {
1135
- if (stage.kind !== "journey" || !stage.url) return;
1195
+ if (stage.kind !== "journey" && stage.kind !== "confirming" || !journeyUrl) return;
1196
+ const intervalMs = journeyPollIntervalMs(stage.kind === "confirming");
1136
1197
  let stopped = false;
1137
1198
  const checkOnce = async () => {
1138
1199
  try {
@@ -1149,27 +1210,43 @@ function FaceCaptureModal({
1149
1210
  if (stopped || cancelledRef.current) return;
1150
1211
  await checkOnce();
1151
1212
  if (!stopped && !cancelledRef.current) {
1152
- setTimeout(tick, 2500);
1213
+ setTimeout(tick, intervalMs);
1153
1214
  }
1154
1215
  };
1155
1216
  void tick();
1156
1217
  let frameOrigin = "";
1157
1218
  try {
1158
- frameOrigin = new URL(stage.url).origin;
1219
+ frameOrigin = new URL(journeyUrl).origin;
1159
1220
  } catch {
1160
1221
  frameOrigin = "";
1161
1222
  }
1162
1223
  const onMessage = (e) => {
1163
1224
  if (!frameOrigin || e.origin !== frameOrigin) return;
1164
- const status = e.data?.verification_status;
1165
- if (status) void checkOnce();
1225
+ const outcome = journeyOutcomeFromMessage(e.data);
1226
+ if (!outcome) return;
1227
+ void checkOnce();
1228
+ setStage((prev) => {
1229
+ if (prev.kind !== "journey") return prev;
1230
+ if (outcome === "cancelled") {
1231
+ return { kind: "error", message: "The verification was closed before it finished. Please try again." };
1232
+ }
1233
+ return { kind: "confirming", outcome, url: prev.url };
1234
+ });
1166
1235
  };
1167
1236
  window.addEventListener("message", onMessage);
1168
1237
  return () => {
1169
1238
  stopped = true;
1170
1239
  window.removeEventListener("message", onMessage);
1171
1240
  };
1172
- }, [stage.kind, stage.kind === "journey" ? stage.url : ""]);
1241
+ }, [stage.kind, journeyUrl]);
1242
+ useEffect(() => {
1243
+ if (stage.kind !== "confirming") return;
1244
+ const outcome = stage.outcome;
1245
+ const timer = setTimeout(() => {
1246
+ setStage((prev) => prev.kind === "confirming" ? { kind: "unconfirmed", outcome } : prev);
1247
+ }, JOURNEY_CONFIRM_TIMEOUT_MS);
1248
+ return () => clearTimeout(timer);
1249
+ }, [stage.kind, stage.kind === "confirming" ? stage.outcome : ""]);
1173
1250
  const handleJourneyRetry = async () => {
1174
1251
  if (!tryStartOperation(journeyRetryingRef)) return;
1175
1252
  setStage({ kind: "journey", url: "" });
@@ -1316,12 +1393,23 @@ function FaceCaptureModal({
1316
1393
  }, 3e3);
1317
1394
  return () => clearInterval(interval);
1318
1395
  }, [captureMode]);
1319
- const close = (result) => {
1396
+ const close = useCallback((result) => {
1320
1397
  cancelledRef.current = true;
1321
1398
  if (result === null && onCancel) {
1322
1399
  onCancel();
1323
1400
  }
1324
1401
  onComplete(result);
1402
+ }, [onCancel, onComplete]);
1403
+ useEffect(() => {
1404
+ if (stage.kind !== "accepted") return;
1405
+ const result = stage.result;
1406
+ const timer = setTimeout(() => close(result), ACCEPTED_AUTO_CLOSE_MS);
1407
+ return () => clearTimeout(timer);
1408
+ }, [close, stage]);
1409
+ const handleHeaderClose = () => {
1410
+ const result = "result" in stage ? stage.result : void 0;
1411
+ const unconfirmed = stage.kind === "confirming" || stage.kind === "unconfirmed" ? pendingJourneyResult(session.reference) : void 0;
1412
+ close(resultForModalClose(stage.kind, result, unconfirmed));
1325
1413
  };
1326
1414
  const renderChoose = () => /* @__PURE__ */ React.createElement("div", { style: contentStyle }, /* @__PURE__ */ React.createElement("div", { style: visualGuideContainerStyle }, /* @__PURE__ */ React.createElement("div", { style: visualGuideStyle }, /* @__PURE__ */ React.createElement("div", { style: circleStyle }, /* @__PURE__ */ React.createElement("img", { src: Camera, alt: "", width: 48, height: 48 })))), /* @__PURE__ */ React.createElement("p", { style: subtitleStyle }, "How would you like to verify?"), /* @__PURE__ */ React.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React.createElement(
1327
1415
  "button",
@@ -1393,7 +1481,16 @@ function FaceCaptureModal({
1393
1481
  "Try Again"
1394
1482
  ), /* @__PURE__ */ React.createElement("button", { style: cancelButtonStyle, onClick: () => close(null) }, sessionExpired ? "Close" : "Cancel")));
1395
1483
  };
1396
- const renderJourney = (url) => /* @__PURE__ */ React.createElement("div", { style: contentStyle }, url ? /* @__PURE__ */ React.createElement(
1484
+ const renderConfirming = () => /* @__PURE__ */ React.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React.createElement("div", { style: { ...spinnerStyle, margin: "24px auto", width: 32, height: 32 } }), /* @__PURE__ */ React.createElement("h3", { style: titleStyle }, "Confirming your result\u2026"), /* @__PURE__ */ React.createElement("p", { style: { ...attemptsTextStyle, marginTop: 8 } }, "This usually takes a few seconds."));
1485
+ const renderUnconfirmed = (outcome) => /* @__PURE__ */ React.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center" } }, /* @__PURE__ */ React.createElement("div", { style: errorCircleStyle }, "!"), /* @__PURE__ */ React.createElement("h3", { style: titleStyle }, "Still confirming"), /* @__PURE__ */ React.createElement("p", { style: alertTextStyle }, outcome === "accepted" ? "Your verification was submitted, but we haven't received the final result yet. You can close this window and we'll keep checking in the background." : "Your last attempt wasn't accepted, but we haven't received the details yet. You can try again or close this window."), /* @__PURE__ */ React.createElement("div", { style: buttonsContainerStyle }, outcome === "declined" && /* @__PURE__ */ React.createElement("button", { style: primaryButtonStyle, onClick: () => void handleJourneyRetry() }, "Try Again"), /* @__PURE__ */ React.createElement(
1486
+ "button",
1487
+ {
1488
+ style: outcome === "accepted" ? primaryButtonStyle : cancelButtonStyle,
1489
+ onClick: () => close(pendingJourneyResult(session.reference))
1490
+ },
1491
+ "Close"
1492
+ )));
1493
+ const renderJourney = (url) => /* @__PURE__ */ React.createElement("div", { style: { ...contentStyle, padding: JOURNEY_CONTENT_PADDING } }, url ? /* @__PURE__ */ React.createElement(
1397
1494
  "iframe",
1398
1495
  {
1399
1496
  src: url,
@@ -1412,6 +1509,10 @@ function FaceCaptureModal({
1412
1509
  return renderCapture(stage.declinedReason);
1413
1510
  case "journey":
1414
1511
  return renderJourney(stage.url);
1512
+ case "confirming":
1513
+ return renderConfirming();
1514
+ case "unconfirmed":
1515
+ return renderUnconfirmed(stage.outcome);
1415
1516
  case "submitting":
1416
1517
  return renderSubmitting();
1417
1518
  case "accepted":
@@ -1427,7 +1528,7 @@ function FaceCaptureModal({
1427
1528
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("style", null, keyframes), /* @__PURE__ */ React.createElement("div", { style: overlayStyle }, /* @__PURE__ */ React.createElement("div", { style: { ...modalStyle, maxWidth: modalMaxWidth(journeyMode) } }, /* @__PURE__ */ React.createElement("div", { style: headerStyle }, /* @__PURE__ */ React.createElement(
1428
1529
  "button",
1429
1530
  {
1430
- onClick: () => close(null),
1531
+ onClick: handleHeaderClose,
1431
1532
  style: closeButtonStyle,
1432
1533
  "aria-label": "Close"
1433
1534
  },
@@ -1486,7 +1587,7 @@ var contentStyle = {
1486
1587
  };
1487
1588
  var journeyFrameStyle = {
1488
1589
  width: "100%",
1489
- height: "min(520px, 60vh)",
1590
+ height: JOURNEY_FRAME_HEIGHT,
1490
1591
  border: 0,
1491
1592
  borderRadius: 12,
1492
1593
  background: "#f9fafb"
@@ -2273,6 +2374,13 @@ function getRiskColor(risk) {
2273
2374
  };
2274
2375
  return colorMap[risk] || "#6b7280";
2275
2376
  }
2377
+ function isMobileDevice(userAgent) {
2378
+ const ua = userAgent ?? (typeof navigator === "undefined" ? "" : navigator.userAgent);
2379
+ return /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
2380
+ }
2381
+ function buildEventBasedFaceVerificationQrPayload(token) {
2382
+ return `vesant://reuse-kyc?token=${encodeURIComponent(token)}`;
2383
+ }
2276
2384
  function useEventBasedFaceVerificationSubmission(client) {
2277
2385
  const startSession = useCallback(
2278
2386
  (request) => client.createEventBasedFaceVerificationSession(request),
@@ -2320,6 +2428,6 @@ function useEventBasedFaceVerificationSubmission(client) {
2320
2428
  return { startSession, verifyFace, runFlow };
2321
2429
  }
2322
2430
 
2323
- export { createDeviceFingerprint, fileToBase64, formatKycStatus, getBrowserInfo, getRiskColor, getStatusColor, isValidFileSize, isValidFileType, useCipherText, useCustomerProfile, useEventBasedFaceVerificationSubmission, useGeolocation, useKycAlerts, useKycOverview, useKycPreferences, useKycRequests, useKycSubmission, useLocationCapture, useLocationRequests, useLoginVerification, useRegistration, useTransactionVerification };
2431
+ export { FaceCaptureModal_default as FaceCaptureModal, buildEventBasedFaceVerificationQrPayload, createDeviceFingerprint, fileToBase64, formatKycStatus, getBrowserInfo, getRiskColor, getStatusColor, isMobileDevice, isValidFileSize, isValidFileType, useCipherText, useCustomerProfile, useEventBasedFaceVerificationSubmission, useGeolocation, useKycAlerts, useKycOverview, useKycPreferences, useKycRequests, useKycSubmission, useLocationCapture, useLocationRequests, useLoginVerification, useRegistration, useTransactionVerification };
2324
2432
  //# sourceMappingURL=react.mjs.map
2325
2433
  //# sourceMappingURL=react.mjs.map