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/astra-sdk.cjs.js
CHANGED
|
@@ -219,6 +219,12 @@ function mergeConfig(userConfig) {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
// src/services/kycApiService.ts
|
|
222
|
+
var COMPLETED_STEPS = {
|
|
223
|
+
INITIATED: "initiated",
|
|
224
|
+
FACE: "face_scan",
|
|
225
|
+
DOCS: "document_upload",
|
|
226
|
+
COMPLETED: "completed"
|
|
227
|
+
};
|
|
222
228
|
var KycApiService = class {
|
|
223
229
|
config;
|
|
224
230
|
constructor(config) {
|
|
@@ -641,7 +647,17 @@ function DocumentUploadModal({ onComplete }) {
|
|
|
641
647
|
const checkSession = async () => {
|
|
642
648
|
if (!apiService) return;
|
|
643
649
|
try {
|
|
644
|
-
await apiService.
|
|
650
|
+
const statusResponse = await apiService.getSessionStatus();
|
|
651
|
+
const { completed_steps, next_step, status } = statusResponse.data;
|
|
652
|
+
if (status !== "ACTIVE") {
|
|
653
|
+
throw new Error("Session expired or inactive");
|
|
654
|
+
}
|
|
655
|
+
if (completed_steps.includes(COMPLETED_STEPS.DOCS)) {
|
|
656
|
+
console.log("Document already uploaded");
|
|
657
|
+
}
|
|
658
|
+
if (next_step === COMPLETED_STEPS.FACE && !completed_steps.includes(COMPLETED_STEPS.FACE)) {
|
|
659
|
+
console.warn("Face scan not completed, but in document upload modal");
|
|
660
|
+
}
|
|
645
661
|
setSessionError(null);
|
|
646
662
|
} catch (error) {
|
|
647
663
|
const message = error.message || "Session expired or inactive";
|
|
@@ -954,6 +970,8 @@ var FaceMeshService = class {
|
|
|
954
970
|
}
|
|
955
971
|
this.processLiveness(faceOnCanvas, w, h);
|
|
956
972
|
} else {
|
|
973
|
+
this.livenessStateRef.current.currentYaw = null;
|
|
974
|
+
this.livenessStateRef.current.currentAbsYaw = null;
|
|
957
975
|
const vid = this.videoRef.current;
|
|
958
976
|
if (vid) {
|
|
959
977
|
const vidW = Math.max(1, vid?.videoWidth || displayW);
|
|
@@ -997,6 +1015,8 @@ var FaceMeshService = class {
|
|
|
997
1015
|
const midX = (leftEyeOuter.x + rightEyeOuter.x) / 2;
|
|
998
1016
|
const yaw = (nT.x - midX) / Math.max(1e-6, faceWidth);
|
|
999
1017
|
const absYaw = Math.abs(yaw);
|
|
1018
|
+
this.livenessStateRef.current.currentYaw = yaw;
|
|
1019
|
+
this.livenessStateRef.current.currentAbsYaw = absYaw;
|
|
1000
1020
|
const xs = faceOnCanvas.map((p) => p.x), ys = faceOnCanvas.map((p) => p.y);
|
|
1001
1021
|
const minX = Math.min(...xs) * w, maxX = Math.max(...xs) * w;
|
|
1002
1022
|
const minY = Math.min(...ys) * h, maxY = Math.max(...ys) * h;
|
|
@@ -1023,11 +1043,13 @@ var FaceMeshService = class {
|
|
|
1023
1043
|
} else if (absYaw < centerThreshold) {
|
|
1024
1044
|
state.centerHold += 1;
|
|
1025
1045
|
if (state.centerHold >= holdFramesCenter) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
this.callbacks.onLivenessUpdate
|
|
1046
|
+
if (!state.livenessCompleted) {
|
|
1047
|
+
const newStage = "LEFT";
|
|
1048
|
+
state.stage = newStage;
|
|
1049
|
+
state.centerHold = 0;
|
|
1050
|
+
if (this.callbacks.onLivenessUpdate) {
|
|
1051
|
+
this.callbacks.onLivenessUpdate(newStage, "Turn your face LEFT");
|
|
1052
|
+
}
|
|
1031
1053
|
}
|
|
1032
1054
|
}
|
|
1033
1055
|
} else {
|
|
@@ -1066,16 +1088,12 @@ var FaceMeshService = class {
|
|
|
1066
1088
|
state.rightHold += 1;
|
|
1067
1089
|
if (state.rightHold >= holdFramesTurn) {
|
|
1068
1090
|
state.rightHold = 0;
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1076
|
-
if (this.callbacks.onCaptureTrigger) {
|
|
1077
|
-
this.callbacks.onCaptureTrigger();
|
|
1078
|
-
}
|
|
1091
|
+
state.livenessCompleted = true;
|
|
1092
|
+
const newStage = "DONE";
|
|
1093
|
+
state.stage = newStage;
|
|
1094
|
+
state.centerHold = 0;
|
|
1095
|
+
if (this.callbacks.onLivenessUpdate) {
|
|
1096
|
+
this.callbacks.onLivenessUpdate(newStage, "Great! Now look straight at the camera");
|
|
1079
1097
|
}
|
|
1080
1098
|
}
|
|
1081
1099
|
} else {
|
|
@@ -1084,6 +1102,25 @@ var FaceMeshService = class {
|
|
|
1084
1102
|
this.callbacks.onLivenessUpdate(state.stage, yaw < -0.08 ? "You're facing left. Turn RIGHT" : "Turn a bit more RIGHT");
|
|
1085
1103
|
}
|
|
1086
1104
|
}
|
|
1105
|
+
} else if (state.stage === "DONE") {
|
|
1106
|
+
const reducedThreshold = 0.08;
|
|
1107
|
+
if (absYaw < reducedThreshold) {
|
|
1108
|
+
state.centerHold += 1;
|
|
1109
|
+
if (state.centerHold >= holdFramesCenter && !state.snapTriggered) {
|
|
1110
|
+
state.snapTriggered = true;
|
|
1111
|
+
if (this.callbacks.onLivenessUpdate) {
|
|
1112
|
+
this.callbacks.onLivenessUpdate(state.stage, "Capturing...");
|
|
1113
|
+
}
|
|
1114
|
+
if (this.callbacks.onCaptureTrigger) {
|
|
1115
|
+
this.callbacks.onCaptureTrigger();
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
} else {
|
|
1119
|
+
state.centerHold = 0;
|
|
1120
|
+
if (this.callbacks.onLivenessUpdate) {
|
|
1121
|
+
this.callbacks.onLivenessUpdate(state.stage, "Please look straight at the camera");
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1087
1124
|
}
|
|
1088
1125
|
}
|
|
1089
1126
|
}
|
|
@@ -1219,7 +1256,10 @@ function useFaceScan(videoRef, canvasRef, callbacks) {
|
|
|
1219
1256
|
snapTriggered: false,
|
|
1220
1257
|
lastResultsAt: 0,
|
|
1221
1258
|
stage: "CENTER",
|
|
1222
|
-
livenessReady: false
|
|
1259
|
+
livenessReady: false,
|
|
1260
|
+
currentYaw: null,
|
|
1261
|
+
currentAbsYaw: null,
|
|
1262
|
+
livenessCompleted: false
|
|
1223
1263
|
});
|
|
1224
1264
|
React.useEffect(() => {
|
|
1225
1265
|
livenessStateRef.current.centerHold = refs.centerHold.current;
|
|
@@ -1240,6 +1280,22 @@ function useFaceScan(videoRef, canvasRef, callbacks) {
|
|
|
1240
1280
|
}, []);
|
|
1241
1281
|
const handleFaceCapture = React.useCallback(async () => {
|
|
1242
1282
|
if (!videoRef.current) return;
|
|
1283
|
+
const reducedThreshold = 0.08;
|
|
1284
|
+
const currentAbsYaw = livenessStateRef.current.currentAbsYaw;
|
|
1285
|
+
if (currentAbsYaw === null || currentAbsYaw === void 0) {
|
|
1286
|
+
setState((prev) => ({
|
|
1287
|
+
...prev,
|
|
1288
|
+
livenessInstruction: "Please position your face in front of the camera"
|
|
1289
|
+
}));
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (currentAbsYaw >= reducedThreshold) {
|
|
1293
|
+
setState((prev) => ({
|
|
1294
|
+
...prev,
|
|
1295
|
+
livenessInstruction: "Please look straight at the camera before capturing"
|
|
1296
|
+
}));
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1243
1299
|
setState((prev) => ({ ...prev, loading: true }));
|
|
1244
1300
|
try {
|
|
1245
1301
|
const video = videoRef.current;
|
|
@@ -1462,7 +1518,7 @@ function FaceScanModal({ onComplete }) {
|
|
|
1462
1518
|
const errorData = error?.errorData || {};
|
|
1463
1519
|
if (errorMessage.includes("Face already registered") || errorMessage.includes("already registered") || errorData?.message?.includes("Face already registered") || error?.statusCode === 500 && errorMessage.includes("Face")) {
|
|
1464
1520
|
setToast({
|
|
1465
|
-
message: "Face
|
|
1521
|
+
message: "Face already registered",
|
|
1466
1522
|
type: "warning"
|
|
1467
1523
|
});
|
|
1468
1524
|
return;
|
|
@@ -1480,7 +1536,21 @@ function FaceScanModal({ onComplete }) {
|
|
|
1480
1536
|
const checkSession = async () => {
|
|
1481
1537
|
if (!apiService) return;
|
|
1482
1538
|
try {
|
|
1483
|
-
await apiService.
|
|
1539
|
+
const statusResponse = await apiService.getSessionStatus();
|
|
1540
|
+
const { completed_steps, next_step, status } = statusResponse.data;
|
|
1541
|
+
if (status !== "ACTIVE") {
|
|
1542
|
+
throw new Error("Session expired or inactive");
|
|
1543
|
+
}
|
|
1544
|
+
if (completed_steps.includes(COMPLETED_STEPS.FACE)) {
|
|
1545
|
+
setState((prev) => ({ ...prev, showDocumentUpload: true }));
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
if (next_step !== COMPLETED_STEPS.FACE && next_step !== COMPLETED_STEPS.INITIATED) {
|
|
1549
|
+
if (next_step === COMPLETED_STEPS.DOCS) {
|
|
1550
|
+
setState((prev) => ({ ...prev, showDocumentUpload: true }));
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1484
1554
|
setSessionError(null);
|
|
1485
1555
|
} catch (error) {
|
|
1486
1556
|
const message = error.message || "Session expired or inactive";
|
|
@@ -1491,7 +1561,7 @@ function FaceScanModal({ onComplete }) {
|
|
|
1491
1561
|
}
|
|
1492
1562
|
};
|
|
1493
1563
|
checkSession();
|
|
1494
|
-
}, [apiService, navigate]);
|
|
1564
|
+
}, [apiService, navigate, setState]);
|
|
1495
1565
|
React.useEffect(() => {
|
|
1496
1566
|
setState((prev) => ({ ...prev, cameraReady }));
|
|
1497
1567
|
}, [cameraReady, setState]);
|