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.
- package/dist/astra-sdk.cjs.js +90 -20
- package/dist/astra-sdk.cjs.js.map +1 -1
- package/dist/astra-sdk.css +16 -0
- package/dist/astra-sdk.css.map +1 -1
- package/dist/astra-sdk.d.cts +0 -4
- package/dist/astra-sdk.es.js +90 -20
- package/dist/astra-sdk.es.js.map +1 -1
- package/dist/components.cjs.js +90 -20
- package/dist/components.cjs.js.map +1 -1
- package/dist/components.css +16 -0
- package/dist/components.css.map +1 -1
- package/dist/components.es.js +90 -20
- package/dist/components.es.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/package.json +1 -1
- package/src/features/faceScan/hooks/useFaceScan.ts +24 -0
- package/src/pages/DocumentUploadModal.tsx +21 -1
- package/src/pages/FaceScanModal.tsx +26 -14
- package/src/services/faceMeshService.ts +47 -15
- package/src/services/kycApiService.ts +7 -0
package/dist/components.cjs.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
this.callbacks.onLivenessUpdate
|
|
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
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
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
|
|
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.
|
|
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]);
|