vesant-sdk 1.7.0-dev.059da4f → 1.7.0-dev.117915b
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/{client-ZNdnpWe7.d.mts → client-B0qhE2kr.d.mts} +1 -1
- package/dist/{client-DoMSYMMR.d.ts → client-DF7hlMEz.d.ts} +13 -0
- package/dist/{client-DMIRx7Tu.d.mts → client-DrjgZoH_.d.mts} +13 -0
- package/dist/{client-C3DCmGe9.d.ts → client-DtH2RLuy.d.ts} +1 -1
- package/dist/compliance/index.d.mts +2 -2
- package/dist/compliance/index.d.ts +2 -2
- package/dist/compliance/index.js +0 -3
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +0 -3
- package/dist/compliance/index.mjs.map +1 -1
- package/dist/geolocation/index.d.mts +2 -2
- package/dist/geolocation/index.d.ts +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -13
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +29 -0
- package/dist/kyc/index.d.ts +29 -0
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +4 -2
- package/dist/react.d.ts +4 -2
- package/dist/react.js +112 -73
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +112 -73
- package/dist/react.mjs.map +1 -1
- package/dist/tax/index.d.mts +1 -24
- package/dist/tax/index.d.ts +1 -24
- package/dist/tax/index.js +1 -10
- package/dist/tax/index.js.map +1 -1
- package/dist/tax/index.mjs +1 -10
- package/dist/tax/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -883,6 +883,87 @@ var Camera = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0i
|
|
|
883
883
|
var Done = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik04LjUgMTIuNUwxMC41IDE0LjVMMTUuNSA5LjUiIHN0cm9rZT0iIzFDMjc0QyIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPg0KPHBhdGggZD0iTTcgMy4zMzc4MkM4LjQ3MDg3IDIuNDg2OTcgMTAuMTc4NiAyIDEyIDJDMTcuNTIyOCAyIDIyIDYuNDc3MTUgMjIgMTJDMjIgMTcuNTIyOCAxNy41MjI4IDIyIDEyIDIyQzYuNDc3MTUgMjIgMiAxNy41MjI4IDIgMTJDMiAxMC4xNzg2IDIuNDg2OTcgOC40NzA4NyAzLjMzNzgyIDciIHN0cm9rZT0iIzFDMjc0QyIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPg0KPC9zdmc+";
|
|
884
884
|
var Close = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xNC41IDkuNTAwMDJMOS41IDE0LjVNOS40OTk5OCA5LjVMMTQuNSAxNC41IiBzdHJva2U9IiMxQzI3NEMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4NCjxwYXRoIGQ9Ik03IDMuMzM3ODJDOC40NzA4NyAyLjQ4Njk3IDEwLjE3ODYgMiAxMiAyQzE3LjUyMjggMiAyMiA2LjQ3NzE1IDIyIDEyQzIyIDE3LjUyMjggMTcuNTIyOCAyMiAxMiAyMkM2LjQ3NzE1IDIyIDIgMTcuNTIyOCAyIDEyQzIgMTAuMTc4NiAyLjQ4Njk3IDguNDcwODcgMy4zMzc4MiA3IiBzdHJva2U9IiMxQzI3NEMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4NCjwvc3ZnPg==";
|
|
885
885
|
|
|
886
|
+
// src/kyc/faceDetection.ts
|
|
887
|
+
var FACE_MESSAGES = {
|
|
888
|
+
idle: "Initializing camera...",
|
|
889
|
+
loading: "Loading face detection...",
|
|
890
|
+
scanning: "Position your face in the circle",
|
|
891
|
+
too_far: "Face too far. Please move closer to the camera",
|
|
892
|
+
too_close: "Too close. Please move back a little",
|
|
893
|
+
off_center: "Center your face in the circle",
|
|
894
|
+
ok: "Looking great! Tap the button to capture"
|
|
895
|
+
};
|
|
896
|
+
var FACE_COLORS = {
|
|
897
|
+
idle: "#9ca3af",
|
|
898
|
+
loading: "#3b82f6",
|
|
899
|
+
scanning: "#3b82f6",
|
|
900
|
+
too_far: "#ef4444",
|
|
901
|
+
too_close: "#f59e0b",
|
|
902
|
+
off_center: "#f59e0b",
|
|
903
|
+
ok: "#10b981"
|
|
904
|
+
};
|
|
905
|
+
var MEDIAPIPE_BASE = "https://cdn.jsdelivr.net/npm/@mediapipe/face_detection";
|
|
906
|
+
function mapDetectionsToFaceStatus(detections) {
|
|
907
|
+
if (detections.length === 0) return "scanning";
|
|
908
|
+
const bb = detections[0].boundingBox;
|
|
909
|
+
if (bb.width < 0.18) return "too_far";
|
|
910
|
+
if (bb.width > 0.72) return "too_close";
|
|
911
|
+
if (bb.xCenter < 0.28 || bb.xCenter > 0.72 || bb.yCenter < 0.28 || bb.yCenter > 0.72) {
|
|
912
|
+
return "off_center";
|
|
913
|
+
}
|
|
914
|
+
return "ok";
|
|
915
|
+
}
|
|
916
|
+
function isCaptureDisabled(ready, detectionActive, faceStatus) {
|
|
917
|
+
return !ready || detectionActive && faceStatus !== "ok";
|
|
918
|
+
}
|
|
919
|
+
function resolveMediaPipeBase(base) {
|
|
920
|
+
if (!base) return MEDIAPIPE_BASE;
|
|
921
|
+
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
922
|
+
}
|
|
923
|
+
var LIVENESS_SAMPLE_LIMIT = 20;
|
|
924
|
+
function buildLivenessArtifact(samples) {
|
|
925
|
+
if (samples.length === 0) return void 0;
|
|
926
|
+
return JSON.stringify({
|
|
927
|
+
version: 1,
|
|
928
|
+
source: "mediapipe-face-detection",
|
|
929
|
+
samples: samples.slice(-LIVENESS_SAMPLE_LIMIT)
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
var mediapipeLoaderPromises = /* @__PURE__ */ new Map();
|
|
933
|
+
function loadMediaPipeFaceDetection(assetBasePath) {
|
|
934
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
935
|
+
return Promise.reject(new Error("MediaPipe requires a browser environment"));
|
|
936
|
+
}
|
|
937
|
+
const w = window;
|
|
938
|
+
if (w.FaceDetection) {
|
|
939
|
+
return Promise.resolve(w.FaceDetection);
|
|
940
|
+
}
|
|
941
|
+
const src = `${resolveMediaPipeBase(assetBasePath)}/face_detection.js`;
|
|
942
|
+
const existing = mediapipeLoaderPromises.get(src);
|
|
943
|
+
if (existing) return existing;
|
|
944
|
+
const loader = new Promise((resolve, reject) => {
|
|
945
|
+
const script = document.createElement("script");
|
|
946
|
+
script.src = src;
|
|
947
|
+
script.async = true;
|
|
948
|
+
script.crossOrigin = "anonymous";
|
|
949
|
+
script.onload = () => {
|
|
950
|
+
if (w.FaceDetection) {
|
|
951
|
+
resolve(w.FaceDetection);
|
|
952
|
+
} else {
|
|
953
|
+
mediapipeLoaderPromises.delete(src);
|
|
954
|
+
reject(new Error("MediaPipe loaded but FaceDetection global is missing"));
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
script.onerror = () => {
|
|
958
|
+
mediapipeLoaderPromises.delete(src);
|
|
959
|
+
reject(new Error("Failed to load MediaPipe face_detection script"));
|
|
960
|
+
};
|
|
961
|
+
document.head.appendChild(script);
|
|
962
|
+
});
|
|
963
|
+
mediapipeLoaderPromises.set(src, loader);
|
|
964
|
+
return loader;
|
|
965
|
+
}
|
|
966
|
+
|
|
886
967
|
// src/kyc/FaceCaptureModal.tsx
|
|
887
968
|
var MOBILE_UA = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
888
969
|
var SESSION_EXPIRY_MS = 15 * 60 * 1e3;
|
|
@@ -916,7 +997,8 @@ function FaceCaptureModal({
|
|
|
916
997
|
onComplete,
|
|
917
998
|
onCancel,
|
|
918
999
|
defaultDevice,
|
|
919
|
-
renderQR
|
|
1000
|
+
renderQR,
|
|
1001
|
+
mediapipeAssetBasePath
|
|
920
1002
|
}) {
|
|
921
1003
|
const isMobile = typeof navigator !== "undefined" && MOBILE_UA.test(navigator.userAgent);
|
|
922
1004
|
const initialChoice = defaultDevice ?? (isMobile ? "this" : "ask");
|
|
@@ -933,6 +1015,7 @@ function FaceCaptureModal({
|
|
|
933
1015
|
const [captureMode, setCaptureMode] = useState("idle");
|
|
934
1016
|
const [capturedPreview, setCapturedPreview] = useState(null);
|
|
935
1017
|
const [capturedBase64, setCapturedBase64] = useState(null);
|
|
1018
|
+
const [capturedArtifact, setCapturedArtifact] = useState(null);
|
|
936
1019
|
const [livenessMessage, setLivenessMessage] = useState(LIVENESS_MESSAGES[0]);
|
|
937
1020
|
const qrPayload = session.link || `vesant://reuse-kyc?token=${encodeURIComponent(session.token)}`;
|
|
938
1021
|
const cancelledRef = useRef(false);
|
|
@@ -1030,7 +1113,10 @@ function FaceCaptureModal({
|
|
|
1030
1113
|
const data = await client.submitEventBasedFaceVerificationSession({
|
|
1031
1114
|
token: session.token,
|
|
1032
1115
|
reference: ref,
|
|
1033
|
-
proof
|
|
1116
|
+
proof,
|
|
1117
|
+
// undefined when detection wasn't running for this capture —
|
|
1118
|
+
// JSON.stringify drops it, so the field is absent on the wire.
|
|
1119
|
+
liveness_artifact: capturedArtifact ?? void 0
|
|
1034
1120
|
});
|
|
1035
1121
|
return { ok: true, data };
|
|
1036
1122
|
} catch (err2) {
|
|
@@ -1076,16 +1162,18 @@ function FaceCaptureModal({
|
|
|
1076
1162
|
submittingRef.current = false;
|
|
1077
1163
|
}
|
|
1078
1164
|
};
|
|
1079
|
-
const handleCameraCapture = (dataUrl) => {
|
|
1165
|
+
const handleCameraCapture = (dataUrl, livenessArtifact) => {
|
|
1080
1166
|
const raw = dataUrl.split(",")[1] ?? "";
|
|
1081
1167
|
setCapturedPreview(dataUrl);
|
|
1082
1168
|
setCapturedBase64(raw);
|
|
1169
|
+
setCapturedArtifact(livenessArtifact ?? null);
|
|
1083
1170
|
setCaptureMode("preview");
|
|
1084
1171
|
};
|
|
1085
1172
|
const handleCameraCancel = () => setCaptureMode("idle");
|
|
1086
1173
|
const handleRetake = () => {
|
|
1087
1174
|
setCapturedPreview(null);
|
|
1088
1175
|
setCapturedBase64(null);
|
|
1176
|
+
setCapturedArtifact(null);
|
|
1089
1177
|
setCaptureMode("live");
|
|
1090
1178
|
};
|
|
1091
1179
|
const handleConfirmSubmit = () => {
|
|
@@ -1157,7 +1245,8 @@ function FaceCaptureModal({
|
|
|
1157
1245
|
{
|
|
1158
1246
|
onCapture: handleCameraCapture,
|
|
1159
1247
|
onCancel: handleCameraCancel,
|
|
1160
|
-
message: livenessMessage
|
|
1248
|
+
message: livenessMessage,
|
|
1249
|
+
assetBasePath: mediapipeAssetBasePath
|
|
1161
1250
|
}
|
|
1162
1251
|
), /* @__PURE__ */ React.createElement("p", { style: attemptsTextStyle }, "Attempt ", attempts + 1, " of ", maxAttempts));
|
|
1163
1252
|
}
|
|
@@ -1388,59 +1477,10 @@ var attemptsTextStyle = {
|
|
|
1388
1477
|
};
|
|
1389
1478
|
var footerStyle = { padding: "12px 24px 16px", borderTop: "1px solid #f3f4f6" };
|
|
1390
1479
|
var footerTextStyle = { margin: 0, fontSize: 12, color: "#9ca3af", textAlign: "center" };
|
|
1391
|
-
|
|
1392
|
-
idle: "Initializing camera...",
|
|
1393
|
-
loading: "Loading face detection...",
|
|
1394
|
-
scanning: "Position your face in the circle",
|
|
1395
|
-
too_far: "Face too far. Please move closer to the camera",
|
|
1396
|
-
too_close: "Too close. Please move back a little",
|
|
1397
|
-
off_center: "Center your face in the circle",
|
|
1398
|
-
ok: "Looking great! Tap the button to capture"
|
|
1399
|
-
};
|
|
1400
|
-
var FACE_COLORS = {
|
|
1401
|
-
idle: "#9ca3af",
|
|
1402
|
-
loading: "#3b82f6",
|
|
1403
|
-
scanning: "#3b82f6",
|
|
1404
|
-
too_far: "#ef4444",
|
|
1405
|
-
too_close: "#f59e0b",
|
|
1406
|
-
off_center: "#f59e0b",
|
|
1407
|
-
ok: "#10b981"
|
|
1408
|
-
};
|
|
1409
|
-
var MEDIAPIPE_BASE = "https://cdn.jsdelivr.net/npm/@mediapipe/face_detection";
|
|
1410
|
-
var mediapipeLoaderPromise = null;
|
|
1411
|
-
function loadMediaPipeFaceDetection() {
|
|
1412
|
-
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1413
|
-
return Promise.reject(new Error("MediaPipe requires a browser environment"));
|
|
1414
|
-
}
|
|
1415
|
-
const w = window;
|
|
1416
|
-
if (w.FaceDetection) {
|
|
1417
|
-
return Promise.resolve(w.FaceDetection);
|
|
1418
|
-
}
|
|
1419
|
-
if (mediapipeLoaderPromise) return mediapipeLoaderPromise;
|
|
1420
|
-
mediapipeLoaderPromise = new Promise((resolve, reject) => {
|
|
1421
|
-
const script = document.createElement("script");
|
|
1422
|
-
script.src = `${MEDIAPIPE_BASE}/face_detection.js`;
|
|
1423
|
-
script.async = true;
|
|
1424
|
-
script.crossOrigin = "anonymous";
|
|
1425
|
-
script.onload = () => {
|
|
1426
|
-
if (w.FaceDetection) {
|
|
1427
|
-
resolve(w.FaceDetection);
|
|
1428
|
-
} else {
|
|
1429
|
-
mediapipeLoaderPromise = null;
|
|
1430
|
-
reject(new Error("MediaPipe loaded but FaceDetection global is missing"));
|
|
1431
|
-
}
|
|
1432
|
-
};
|
|
1433
|
-
script.onerror = () => {
|
|
1434
|
-
mediapipeLoaderPromise = null;
|
|
1435
|
-
reject(new Error("Failed to load MediaPipe face_detection script"));
|
|
1436
|
-
};
|
|
1437
|
-
document.head.appendChild(script);
|
|
1438
|
-
});
|
|
1439
|
-
return mediapipeLoaderPromise;
|
|
1440
|
-
}
|
|
1441
|
-
function LiveCamera({ onCapture, onCancel, message }) {
|
|
1480
|
+
function LiveCamera({ onCapture, onCancel, message, assetBasePath }) {
|
|
1442
1481
|
const videoRef = useRef(null);
|
|
1443
1482
|
const streamRef = useRef(null);
|
|
1483
|
+
const samplesRef = useRef([]);
|
|
1444
1484
|
const [ready, setReady] = useState(false);
|
|
1445
1485
|
const [error, setError] = useState(null);
|
|
1446
1486
|
const [faceStatus, setFaceStatus] = useState("idle");
|
|
@@ -1495,31 +1535,29 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1495
1535
|
let detector = null;
|
|
1496
1536
|
setFaceStatus("loading");
|
|
1497
1537
|
setFaceDetectionFailed(false);
|
|
1538
|
+
samplesRef.current = [];
|
|
1498
1539
|
(async () => {
|
|
1499
1540
|
try {
|
|
1500
|
-
const FaceDetection = await loadMediaPipeFaceDetection();
|
|
1541
|
+
const FaceDetection = await loadMediaPipeFaceDetection(assetBasePath);
|
|
1501
1542
|
if (cancelled) return;
|
|
1543
|
+
const assetBase = resolveMediaPipeBase(assetBasePath);
|
|
1502
1544
|
const d = new FaceDetection({
|
|
1503
|
-
locateFile: (f) => `${
|
|
1545
|
+
locateFile: (f) => `${assetBase}/${f}`
|
|
1504
1546
|
});
|
|
1505
1547
|
d.setOptions({ model: "short", minDetectionConfidence: 0.5 });
|
|
1506
1548
|
d.onResults((results) => {
|
|
1507
1549
|
if (cancelled) return;
|
|
1508
1550
|
const detections = results.detections ?? [];
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
next = "off_center";
|
|
1518
|
-
} else {
|
|
1519
|
-
next = "ok";
|
|
1520
|
-
}
|
|
1551
|
+
const status = mapDetectionsToFaceStatus(detections);
|
|
1552
|
+
samplesRef.current.push({
|
|
1553
|
+
t: Date.now(),
|
|
1554
|
+
status,
|
|
1555
|
+
...detections.length > 0 ? { boundingBox: detections[0].boundingBox } : {}
|
|
1556
|
+
});
|
|
1557
|
+
if (samplesRef.current.length > LIVENESS_SAMPLE_LIMIT) {
|
|
1558
|
+
samplesRef.current.shift();
|
|
1521
1559
|
}
|
|
1522
|
-
setFaceStatus(
|
|
1560
|
+
setFaceStatus(status);
|
|
1523
1561
|
});
|
|
1524
1562
|
await d.initialize();
|
|
1525
1563
|
if (cancelled) return;
|
|
@@ -1555,7 +1593,7 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1555
1593
|
} catch {
|
|
1556
1594
|
}
|
|
1557
1595
|
};
|
|
1558
|
-
}, [ready]);
|
|
1596
|
+
}, [ready, assetBasePath]);
|
|
1559
1597
|
const capture = () => {
|
|
1560
1598
|
const video = videoRef.current;
|
|
1561
1599
|
if (!video || !video.videoWidth) return;
|
|
@@ -1572,7 +1610,7 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1572
1610
|
ctx.drawImage(video, sx, sy, size, size, 0, 0, size, size);
|
|
1573
1611
|
streamRef.current?.getTracks().forEach((t) => t.stop());
|
|
1574
1612
|
streamRef.current = null;
|
|
1575
|
-
onCapture(canvas.toDataURL("image/jpeg", 0.9));
|
|
1613
|
+
onCapture(canvas.toDataURL("image/jpeg", 0.9), buildLivenessArtifact(samplesRef.current));
|
|
1576
1614
|
};
|
|
1577
1615
|
if (error) {
|
|
1578
1616
|
return /* @__PURE__ */ React.createElement("div", { style: { ...contentStyle, alignItems: "center", textAlign: "center", padding: 0 } }, /* @__PURE__ */ React.createElement("div", { style: errorCircleStyle }, "!"), /* @__PURE__ */ React.createElement("h3", { style: titleStyle }, "Camera unavailable"), /* @__PURE__ */ React.createElement("p", { style: alertTextStyle }, error), /* @__PURE__ */ React.createElement("div", { style: buttonsContainerStyle }, /* @__PURE__ */ React.createElement("button", { style: secondaryButtonStyle, onClick: onCancel }, "Back")));
|
|
@@ -1580,7 +1618,7 @@ function LiveCamera({ onCapture, onCancel, message }) {
|
|
|
1580
1618
|
const detectionActive = ready && !faceDetectionFailed;
|
|
1581
1619
|
const liveMessage = detectionActive ? FACE_MESSAGES[faceStatus] : message;
|
|
1582
1620
|
const liveFaceColor = detectionActive ? FACE_COLORS[faceStatus] : void 0;
|
|
1583
|
-
const captureDisabled =
|
|
1621
|
+
const captureDisabled = isCaptureDisabled(ready, detectionActive, faceStatus);
|
|
1584
1622
|
const ringPulse = detectionActive && (faceStatus === "too_far" || faceStatus === "too_close") ? "pulse 1.5s ease-in-out infinite" : void 0;
|
|
1585
1623
|
const dynamicCircleStyle = {
|
|
1586
1624
|
...faceCircleStyle,
|
|
@@ -2107,6 +2145,7 @@ function useEventBasedFaceVerificationSubmission(client) {
|
|
|
2107
2145
|
defaultDevice: opts.defaultDevice,
|
|
2108
2146
|
renderQR: opts.renderQR,
|
|
2109
2147
|
onCancel: opts.onCancel,
|
|
2148
|
+
mediapipeAssetBasePath: opts.mediapipeAssetBasePath,
|
|
2110
2149
|
onComplete: (result) => {
|
|
2111
2150
|
cleanup();
|
|
2112
2151
|
resolve(result);
|