astra-sdk-web 1.1.7 → 1.1.9

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.
@@ -14,6 +14,12 @@ var React__default = /*#__PURE__*/_interopDefault(React);
14
14
  // src/components/KycFlow.tsx
15
15
 
16
16
  // src/services/kycApiService.ts
17
+ var COMPLETED_STEPS = {
18
+ INITIATED: "initiated",
19
+ FACE: "face_scan",
20
+ DOCS: "document_upload",
21
+ COMPLETED: "completed"
22
+ };
17
23
  var KycApiService = class {
18
24
  config;
19
25
  constructor(config) {
@@ -436,7 +442,17 @@ function DocumentUploadModal({ onComplete }) {
436
442
  const checkSession = async () => {
437
443
  if (!apiService) return;
438
444
  try {
439
- await apiService.checkSessionActive();
445
+ const statusResponse = await apiService.getSessionStatus();
446
+ const { completed_steps, next_step, status } = statusResponse.data;
447
+ if (status !== "ACTIVE") {
448
+ throw new Error("Session expired or inactive");
449
+ }
450
+ if (completed_steps.includes(COMPLETED_STEPS.DOCS)) {
451
+ console.log("Document already uploaded");
452
+ }
453
+ if (next_step === COMPLETED_STEPS.FACE && !completed_steps.includes(COMPLETED_STEPS.FACE)) {
454
+ console.warn("Face scan not completed, but in document upload modal");
455
+ }
440
456
  setSessionError(null);
441
457
  } catch (error) {
442
458
  const message = error.message || "Session expired or inactive";
@@ -749,6 +765,8 @@ var FaceMeshService = class {
749
765
  }
750
766
  this.processLiveness(faceOnCanvas, w, h);
751
767
  } else {
768
+ this.livenessStateRef.current.currentYaw = null;
769
+ this.livenessStateRef.current.currentAbsYaw = null;
752
770
  const vid = this.videoRef.current;
753
771
  if (vid) {
754
772
  const vidW = Math.max(1, vid?.videoWidth || displayW);
@@ -792,6 +810,8 @@ var FaceMeshService = class {
792
810
  const midX = (leftEyeOuter.x + rightEyeOuter.x) / 2;
793
811
  const yaw = (nT.x - midX) / Math.max(1e-6, faceWidth);
794
812
  const absYaw = Math.abs(yaw);
813
+ this.livenessStateRef.current.currentYaw = yaw;
814
+ this.livenessStateRef.current.currentAbsYaw = absYaw;
795
815
  const xs = faceOnCanvas.map((p) => p.x), ys = faceOnCanvas.map((p) => p.y);
796
816
  const minX = Math.min(...xs) * w, maxX = Math.max(...xs) * w;
797
817
  const minY = Math.min(...ys) * h, maxY = Math.max(...ys) * h;
@@ -818,11 +838,13 @@ var FaceMeshService = class {
818
838
  } else if (absYaw < centerThreshold) {
819
839
  state.centerHold += 1;
820
840
  if (state.centerHold >= holdFramesCenter) {
821
- const newStage = "LEFT";
822
- state.stage = newStage;
823
- state.centerHold = 0;
824
- if (this.callbacks.onLivenessUpdate) {
825
- this.callbacks.onLivenessUpdate(newStage, "Turn your face LEFT");
841
+ if (!state.livenessCompleted) {
842
+ const newStage = "LEFT";
843
+ state.stage = newStage;
844
+ state.centerHold = 0;
845
+ if (this.callbacks.onLivenessUpdate) {
846
+ this.callbacks.onLivenessUpdate(newStage, "Turn your face LEFT");
847
+ }
826
848
  }
827
849
  }
828
850
  } else {
@@ -861,16 +883,12 @@ var FaceMeshService = class {
861
883
  state.rightHold += 1;
862
884
  if (state.rightHold >= holdFramesTurn) {
863
885
  state.rightHold = 0;
864
- if (!state.snapTriggered) {
865
- state.snapTriggered = true;
866
- const newStage = "DONE";
867
- state.stage = newStage;
868
- if (this.callbacks.onLivenessUpdate) {
869
- this.callbacks.onLivenessUpdate(newStage, "Capturing...");
870
- }
871
- if (this.callbacks.onCaptureTrigger) {
872
- this.callbacks.onCaptureTrigger();
873
- }
886
+ state.livenessCompleted = true;
887
+ const newStage = "DONE";
888
+ state.stage = newStage;
889
+ state.centerHold = 0;
890
+ if (this.callbacks.onLivenessUpdate) {
891
+ this.callbacks.onLivenessUpdate(newStage, "Great! Now look straight at the camera");
874
892
  }
875
893
  }
876
894
  } else {
@@ -879,6 +897,25 @@ var FaceMeshService = class {
879
897
  this.callbacks.onLivenessUpdate(state.stage, yaw < -0.08 ? "You're facing left. Turn RIGHT" : "Turn a bit more RIGHT");
880
898
  }
881
899
  }
900
+ } else if (state.stage === "DONE") {
901
+ const reducedThreshold = 0.08;
902
+ if (absYaw < reducedThreshold) {
903
+ state.centerHold += 1;
904
+ if (state.centerHold >= holdFramesCenter && !state.snapTriggered) {
905
+ state.snapTriggered = true;
906
+ if (this.callbacks.onLivenessUpdate) {
907
+ this.callbacks.onLivenessUpdate(state.stage, "Capturing...");
908
+ }
909
+ if (this.callbacks.onCaptureTrigger) {
910
+ this.callbacks.onCaptureTrigger();
911
+ }
912
+ }
913
+ } else {
914
+ state.centerHold = 0;
915
+ if (this.callbacks.onLivenessUpdate) {
916
+ this.callbacks.onLivenessUpdate(state.stage, "Please look straight at the camera");
917
+ }
918
+ }
882
919
  }
883
920
  }
884
921
  }
@@ -1014,7 +1051,10 @@ function useFaceScan(videoRef, canvasRef, callbacks) {
1014
1051
  snapTriggered: false,
1015
1052
  lastResultsAt: 0,
1016
1053
  stage: "CENTER",
1017
- livenessReady: false
1054
+ livenessReady: false,
1055
+ currentYaw: null,
1056
+ currentAbsYaw: null,
1057
+ livenessCompleted: false
1018
1058
  });
1019
1059
  React.useEffect(() => {
1020
1060
  livenessStateRef.current.centerHold = refs.centerHold.current;
@@ -1035,6 +1075,22 @@ function useFaceScan(videoRef, canvasRef, callbacks) {
1035
1075
  }, []);
1036
1076
  const handleFaceCapture = React.useCallback(async () => {
1037
1077
  if (!videoRef.current) return;
1078
+ const reducedThreshold = 0.08;
1079
+ const currentAbsYaw = livenessStateRef.current.currentAbsYaw;
1080
+ if (currentAbsYaw === null || currentAbsYaw === void 0) {
1081
+ setState((prev) => ({
1082
+ ...prev,
1083
+ livenessInstruction: "Please position your face in front of the camera"
1084
+ }));
1085
+ return;
1086
+ }
1087
+ if (currentAbsYaw >= reducedThreshold) {
1088
+ setState((prev) => ({
1089
+ ...prev,
1090
+ livenessInstruction: "Please look straight at the camera before capturing"
1091
+ }));
1092
+ return;
1093
+ }
1038
1094
  setState((prev) => ({ ...prev, loading: true }));
1039
1095
  try {
1040
1096
  const video = videoRef.current;
@@ -1257,7 +1313,7 @@ function FaceScanModal({ onComplete }) {
1257
1313
  const errorData = error?.errorData || {};
1258
1314
  if (errorMessage.includes("Face already registered") || errorMessage.includes("already registered") || errorData?.message?.includes("Face already registered") || error?.statusCode === 500 && errorMessage.includes("Face")) {
1259
1315
  setToast({
1260
- message: "Face has already been registered for this session. Proceeding to document upload.",
1316
+ message: "Face already registered",
1261
1317
  type: "warning"
1262
1318
  });
1263
1319
  return;
@@ -1275,7 +1331,21 @@ function FaceScanModal({ onComplete }) {
1275
1331
  const checkSession = async () => {
1276
1332
  if (!apiService) return;
1277
1333
  try {
1278
- await apiService.checkSessionActive();
1334
+ const statusResponse = await apiService.getSessionStatus();
1335
+ const { completed_steps, next_step, status } = statusResponse.data;
1336
+ if (status !== "ACTIVE") {
1337
+ throw new Error("Session expired or inactive");
1338
+ }
1339
+ if (completed_steps.includes(COMPLETED_STEPS.FACE)) {
1340
+ setState((prev) => ({ ...prev, showDocumentUpload: true }));
1341
+ return;
1342
+ }
1343
+ if (next_step !== COMPLETED_STEPS.FACE && next_step !== COMPLETED_STEPS.INITIATED) {
1344
+ if (next_step === COMPLETED_STEPS.DOCS) {
1345
+ setState((prev) => ({ ...prev, showDocumentUpload: true }));
1346
+ return;
1347
+ }
1348
+ }
1279
1349
  setSessionError(null);
1280
1350
  } catch (error) {
1281
1351
  const message = error.message || "Session expired or inactive";
@@ -1286,7 +1356,7 @@ function FaceScanModal({ onComplete }) {
1286
1356
  }
1287
1357
  };
1288
1358
  checkSession();
1289
- }, [apiService, navigate]);
1359
+ }, [apiService, navigate, setState]);
1290
1360
  React.useEffect(() => {
1291
1361
  setState((prev) => ({ ...prev, cameraReady }));
1292
1362
  }, [cameraReady, setState]);