UNPKG

@seontechnologies/seon-id-verification

Version:

An advanced SDK featuring web components for natural person identification through document scanning, facial recognition, hand gesture, and face turning detection, designed for secure and efficient user verification.

734 lines (733 loc) 27.4 kB
var De = (t) => { throw TypeError(t); }; var le = (t, e, s) => e.has(t) || De("Cannot " + s); var r = (t, e, s) => (le(t, e, "read from private field"), s ? s.call(t) : e.get(t)), _ = (t, e, s) => e.has(t) ? De("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, s), v = (t, e, s, n) => (le(t, e, "write to private field"), n ? n.call(t, s) : e.set(t, s), s), x = (t, e, s) => (le(t, e, "access private method"), s); import { f as Be, p as Ie, r as V, s as fe, g as ce, n as pe, h as me, k as Me, m as Xe, o as Ye, q as Ge, u as Fe, v as ze, w as Ke, x as Je, y as Ze, z as et, t as Qe, A as tt, C as st, j as P, D as rt, a as Ce, l as j } from "./index-oGnhSncZ.mjs"; import { C as nt, a as it } from "./CameraCard-DCtEAYmX.mjs"; import { s as Te, X as ot, E as at, I as ct, U as lt, S as ut, L as ht, a as Le } from "./UploadLivenessVideo-ia7J-Ak0.mjs"; import * as q from "react"; import { useRef as U, useState as Y, useEffect as Z, useCallback as B, useMemo as dt } from "react"; import { S as ft } from "./SelectInput-D_egVIuA.mjs"; var T, u, oe, D, G, ee, N, H, ae, te, se, K, J, W, re, m, ie, ye, ge, ve, be, we, xe, Re, je, $e, pt = ($e = class extends Be { constructor(e, s) { super(); _(this, m); _(this, T); _(this, u); _(this, oe); _(this, D); _(this, G); _(this, ee); _(this, N); _(this, H); _(this, ae); _(this, te); // This property keeps track of the last query with defined data. // It will be used to pass the previous data and query to the placeholder function between renders. _(this, se); _(this, K); _(this, J); _(this, W); _(this, re, /* @__PURE__ */ new Set()); this.options = s, v(this, T, e), v(this, H, null), v(this, N, Ie()), this.options.experimental_prefetchInRender || r(this, N).reject( new Error("experimental_prefetchInRender feature flag is not enabled") ), this.bindMethods(), this.setOptions(s); } bindMethods() { this.refetch = this.refetch.bind(this); } onSubscribe() { this.listeners.size === 1 && (r(this, u).addObserver(this), Pe(r(this, u), this.options) ? x(this, m, ie).call(this) : this.updateResult(), x(this, m, be).call(this)); } onUnsubscribe() { this.hasListeners() || this.destroy(); } shouldFetchOnReconnect() { return Oe( r(this, u), this.options, this.options.refetchOnReconnect ); } shouldFetchOnWindowFocus() { return Oe( r(this, u), this.options, this.options.refetchOnWindowFocus ); } destroy() { this.listeners = /* @__PURE__ */ new Set(), x(this, m, we).call(this), x(this, m, xe).call(this), r(this, u).removeObserver(this); } setOptions(e) { const s = this.options, n = r(this, u); if (this.options = r(this, T).defaultQueryOptions(e), this.options.enabled !== void 0 && typeof this.options.enabled != "boolean" && typeof this.options.enabled != "function" && typeof V(this.options.enabled, r(this, u)) != "boolean") throw new Error( "Expected enabled to be a boolean or a callback that returns a boolean" ); x(this, m, Re).call(this), r(this, u).setOptions(this.options), s._defaulted && !fe(this.options, s) && r(this, T).getQueryCache().notify({ type: "observerOptionsUpdated", query: r(this, u), observer: this }); const o = this.hasListeners(); o && Ue( r(this, u), n, this.options, s ) && x(this, m, ie).call(this), this.updateResult(), o && (r(this, u) !== n || V(this.options.enabled, r(this, u)) !== V(s.enabled, r(this, u)) || ce(this.options.staleTime, r(this, u)) !== ce(s.staleTime, r(this, u))) && x(this, m, ye).call(this); const i = x(this, m, ge).call(this); o && (r(this, u) !== n || V(this.options.enabled, r(this, u)) !== V(s.enabled, r(this, u)) || i !== r(this, W)) && x(this, m, ve).call(this, i); } getOptimisticResult(e) { const s = r(this, T).getQueryCache().build(r(this, T), e), n = this.createResult(s, e); return yt(this, n) && (v(this, D, n), v(this, ee, this.options), v(this, G, r(this, u).state)), n; } getCurrentResult() { return r(this, D); } trackResult(e, s) { return new Proxy(e, { get: (n, o) => (this.trackProp(o), s == null || s(o), Reflect.get(n, o)) }); } trackProp(e) { r(this, re).add(e); } getCurrentQuery() { return r(this, u); } refetch({ ...e } = {}) { return this.fetch({ ...e }); } fetchOptimistic(e) { const s = r(this, T).defaultQueryOptions(e), n = r(this, T).getQueryCache().build(r(this, T), s); return n.fetch().then(() => this.createResult(n, s)); } fetch(e) { return x(this, m, ie).call(this, { ...e, cancelRefetch: e.cancelRefetch ?? !0 }).then(() => (this.updateResult(), r(this, D))); } createResult(e, s) { var ne; const n = r(this, u), o = this.options, i = r(this, D), a = r(this, G), p = r(this, ee), h = e !== n ? e.state : r(this, oe), { state: b } = e; let c = { ...b }, S = !1, d; if (s._optimisticResults) { const O = this.hasListeners(), A = !O && Pe(e, s), z = O && Ue(e, n, s, o); (A || z) && (c = { ...c, ...Ge(b.data, e.options) }), s._optimisticResults === "isRestoring" && (c.fetchStatus = "idle"); } let { error: C, errorUpdatedAt: w, status: f } = c; d = c.data; let I = !1; if (s.placeholderData !== void 0 && d === void 0 && f === "pending") { let O; i != null && i.isPlaceholderData && s.placeholderData === (p == null ? void 0 : p.placeholderData) ? (O = i.data, I = !0) : O = typeof s.placeholderData == "function" ? s.placeholderData( (ne = r(this, se)) == null ? void 0 : ne.state.data, r(this, se) ) : s.placeholderData, O !== void 0 && (f = "success", d = Fe( i == null ? void 0 : i.data, O, s ), S = !0); } if (s.select && d !== void 0 && !I) if (i && d === (a == null ? void 0 : a.data) && s.select === r(this, ae)) d = r(this, te); else try { v(this, ae, s.select), d = s.select(d), d = Fe(i == null ? void 0 : i.data, d, s), v(this, te, d), v(this, H, null); } catch (O) { v(this, H, O); } r(this, H) && (C = r(this, H), d = r(this, te), w = Date.now(), f = "error"); const y = c.fetchStatus === "fetching", M = f === "pending", k = f === "error", g = M && y, F = d !== void 0, L = { status: f, fetchStatus: c.fetchStatus, isPending: M, isSuccess: f === "success", isError: k, isInitialLoading: g, isLoading: g, data: d, dataUpdatedAt: c.dataUpdatedAt, error: C, errorUpdatedAt: w, failureCount: c.fetchFailureCount, failureReason: c.fetchFailureReason, errorUpdateCount: c.errorUpdateCount, isFetched: c.dataUpdateCount > 0 || c.errorUpdateCount > 0, isFetchedAfterMount: c.dataUpdateCount > h.dataUpdateCount || c.errorUpdateCount > h.errorUpdateCount, isFetching: y, isRefetching: y && !M, isLoadingError: k && !F, isPaused: c.fetchStatus === "paused", isPlaceholderData: S, isRefetchError: k && F, isStale: Ee(e, s), refetch: this.refetch, promise: r(this, N) }; if (this.options.experimental_prefetchInRender) { const O = (X) => { L.status === "error" ? X.reject(L.error) : L.data !== void 0 && X.resolve(L.data); }, A = () => { const X = v(this, N, L.promise = Ie()); O(X); }, z = r(this, N); switch (z.status) { case "pending": e.queryHash === n.queryHash && O(z); break; case "fulfilled": (L.status === "error" || L.data !== z.value) && A(); break; case "rejected": (L.status !== "error" || L.error !== z.reason) && A(); break; } } return L; } updateResult() { const e = r(this, D), s = this.createResult(r(this, u), this.options); if (v(this, G, r(this, u).state), v(this, ee, this.options), r(this, G).data !== void 0 && v(this, se, r(this, u)), fe(s, e)) return; v(this, D, s); const n = () => { if (!e) return !0; const { notifyOnChangeProps: o } = this.options, i = typeof o == "function" ? o() : o; if (i === "all" || !i && !r(this, re).size) return !0; const a = new Set( i ?? r(this, re) ); return this.options.throwOnError && a.add("error"), Object.keys(r(this, D)).some((p) => { const l = p; return r(this, D)[l] !== e[l] && a.has(l); }); }; x(this, m, je).call(this, { listeners: n() }); } onQueryUpdate() { this.updateResult(), this.hasListeners() && x(this, m, be).call(this); } }, T = new WeakMap(), u = new WeakMap(), oe = new WeakMap(), D = new WeakMap(), G = new WeakMap(), ee = new WeakMap(), N = new WeakMap(), H = new WeakMap(), ae = new WeakMap(), te = new WeakMap(), se = new WeakMap(), K = new WeakMap(), J = new WeakMap(), W = new WeakMap(), re = new WeakMap(), m = new WeakSet(), ie = function(e) { x(this, m, Re).call(this); let s = r(this, u).fetch( this.options, e ); return e != null && e.throwOnError || (s = s.catch(pe)), s; }, ye = function() { x(this, m, we).call(this); const e = ce( this.options.staleTime, r(this, u) ); if (me || r(this, D).isStale || !Me(e)) return; const n = Xe(r(this, D).dataUpdatedAt, e) + 1; v(this, K, setTimeout(() => { r(this, D).isStale || this.updateResult(); }, n)); }, ge = function() { return (typeof this.options.refetchInterval == "function" ? this.options.refetchInterval(r(this, u)) : this.options.refetchInterval) ?? !1; }, ve = function(e) { x(this, m, xe).call(this), v(this, W, e), !(me || V(this.options.enabled, r(this, u)) === !1 || !Me(r(this, W)) || r(this, W) === 0) && v(this, J, setInterval(() => { (this.options.refetchIntervalInBackground || Ye.isFocused()) && x(this, m, ie).call(this); }, r(this, W))); }, be = function() { x(this, m, ye).call(this), x(this, m, ve).call(this, x(this, m, ge).call(this)); }, we = function() { r(this, K) && (clearTimeout(r(this, K)), v(this, K, void 0)); }, xe = function() { r(this, J) && (clearInterval(r(this, J)), v(this, J, void 0)); }, Re = function() { const e = r(this, T).getQueryCache().build(r(this, T), this.options); if (e === r(this, u)) return; const s = r(this, u); v(this, u, e), v(this, oe, e.state), this.hasListeners() && (s == null || s.removeObserver(this), e.addObserver(this)); }, je = function(e) { ze.batch(() => { e.listeners && this.listeners.forEach((s) => { s(r(this, D)); }), r(this, T).getQueryCache().notify({ query: r(this, u), type: "observerResultsUpdated" }); }); }, $e); function mt(t, e) { return V(e.enabled, t) !== !1 && t.state.data === void 0 && !(t.state.status === "error" && e.retryOnMount === !1); } function Pe(t, e) { return mt(t, e) || t.state.data !== void 0 && Oe(t, e, e.refetchOnMount); } function Oe(t, e, s) { if (V(e.enabled, t) !== !1) { const n = typeof s == "function" ? s(t) : s; return n === "always" || n !== !1 && Ee(t, e); } return !1; } function Ue(t, e, s, n) { return (t !== e || V(n.enabled, t) === !1) && (!s.suspense || t.state.status !== "error") && Ee(t, s); } function Ee(t, e) { return V(e.enabled, t) !== !1 && t.isStaleByTime(ce(e.staleTime, t)); } function yt(t, e) { return !fe(t.getCurrentResult(), e); } var qe = q.createContext(!1), gt = () => q.useContext(qe); qe.Provider; function vt() { let t = !1; return { clearReset: () => { t = !1; }, reset: () => { t = !0; }, isReset: () => t }; } var bt = q.createContext(vt()), wt = () => q.useContext(bt), xt = (t, e) => { (t.suspense || t.throwOnError || t.experimental_prefetchInRender) && (e.isReset() || (t.retryOnMount = !1)); }, Rt = (t) => { q.useEffect(() => { t.clearReset(); }, [t]); }, Ot = ({ result: t, errorResetBoundary: e, throwOnError: s, query: n, suspense: o }) => t.isError && !e.isReset() && !t.isFetching && n && (o && t.data === void 0 || Ke(s, [t.error, n])), Ct = (t) => { const e = t.staleTime; t.suspense && (t.staleTime = typeof e == "function" ? (...s) => Math.max(e(...s), 1e3) : Math.max(e ?? 1e3, 1e3), typeof t.gcTime == "number" && (t.gcTime = Math.max(t.gcTime, 1e3))); }, Et = (t, e) => t.isLoading && t.isFetching && !e, _t = (t, e) => (t == null ? void 0 : t.suspense) && e.isPending, Ae = (t, e, s) => e.fetchOptimistic(t).catch(() => { s.clearReset(); }); function St(t, e, s) { var c, S, d, C, w; if (process.env.NODE_ENV !== "production" && (typeof t != "object" || Array.isArray(t))) throw new Error( 'Bad argument type. Starting with v5, only the "Object" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object' ); const n = Je(), o = gt(), i = wt(), a = n.defaultQueryOptions(t); (S = (c = n.getDefaultOptions().queries) == null ? void 0 : c._experimental_beforeQuery) == null || S.call( c, a ), process.env.NODE_ENV !== "production" && (a.queryFn || console.error( `[${a.queryHash}]: No queryFn was passed as an option, and no default queryFn was found. The queryFn parameter is only optional when using a default queryFn. More info here: https://tanstack.com/query/latest/docs/framework/react/guides/default-query-function` )), a._optimisticResults = o ? "isRestoring" : "optimistic", Ct(a), xt(a, i), Rt(i); const p = !n.getQueryCache().get(a.queryHash), [l] = q.useState( () => new e( n, a ) ), h = l.getOptimisticResult(a), b = !o && t.subscribed !== !1; if (q.useSyncExternalStore( q.useCallback( (f) => { const I = b ? l.subscribe(ze.batchCalls(f)) : pe; return l.updateResult(), I; }, [l, b] ), () => l.getCurrentResult(), () => l.getCurrentResult() ), q.useEffect(() => { l.setOptions(a); }, [a, l]), _t(a, h)) throw Ae(a, l, i); if (Ot({ result: h, errorResetBoundary: i, throwOnError: a.throwOnError, query: n.getQueryCache().get(a.queryHash), suspense: a.suspense })) throw h.error; if ((C = (d = n.getDefaultOptions().queries) == null ? void 0 : d._experimental_afterQuery) == null || C.call( d, a, h ), a.experimental_prefetchInRender && !me && Et(h, o)) { const f = p ? ( // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted Ae(a, l, i) ) : ( // subscribe to the "cache promise" so that we can finalize the currentThenable once data comes in (w = n.getQueryCache().get(a.queryHash)) == null ? void 0 : w.promise ); f == null || f.catch(pe).finally(() => { l.updateResult(); }); } return a.notifyOnChangeProps ? h : l.trackResult(h); } function kt(t, e) { return St(t, pt); } const Dt = async () => (await rt()).map((s) => ({ value: s.deviceId, text: s.label })), It = ({ onDataLoaded: t }) => { const e = U(null), [s, n] = Y(null), [o, i] = Y(null), { data: a, error: p } = kt({ queryKey: ["cameraList"], initialData: [], queryFn: Dt }), l = U(!1); Z(() => { if (s) return () => { s.getTracks().forEach((c) => { c.stop(); }), Ze(); }; }, [s]), Z(() => { }, [p]); const h = B(async (c) => { if (!et()) { Qe({ ERROR: "Camera access denied" }); return; } l.current = !0; const S = { video: { deviceId: { exact: c || (await tt()).deviceId } } }; navigator.mediaDevices.getUserMedia(S).then(async (d) => { if (!o) return; const C = await st(d); n(C.stream), o.srcObject = C.stream; }).catch((d) => { console.error(d); }); }, [o]); Z(() => { if (!o) { l.current = !1; return; } l.current || h(); const c = () => { t == null || t(); }; return o.addEventListener("loadeddata", c), () => { o.removeEventListener("loadeddata", c); }; }, [h, t, o]); const b = P.jsxs(P.Fragment, { children: [a.length <= 1 ? null : P.jsx("div", { className: "tw-absolute tw-z-[9999] tw-top-[-36px] hover:tw-top-1 tw-opacity-100 hover:tw-opacity-75 tw-transition-all tw-duration-300", children: P.jsx(ft, { idPrefix: "liveness-camera", onChange: (c) => { o && h(c.value); }, options: a, placeholder: a[0], chevronPosition: "bottom" }) }), P.jsx("video", { id: "liveness-webcam", ref: i, className: "tw-bg-black tw-object-cover tw-object-center tw-max-w-none tw-w-full tw-h-full sm:tw-h-auto", autoPlay: !0, playsInline: !0 }), !1] }); return { videoMarkupRef: e, videoComponent: b, videoStream: s, videoElement: o }; }, Mt = [ "video/mp4", "video/webm", "video/webm;codecs=vp8", "video/webm;codecs=daala", "video/webm;codecs=h264" ], Ve = Mt.find((t) => MediaRecorder.isTypeSupported(t)) || "video/webm", Ft = ({ stream: t, onRecordingFinished: e }) => { const s = U(null), n = U([]), o = U(!1); Z(() => { if (!t) return; const p = (b) => { b.data.size > 0 && n.current.push(b.data); }, l = async () => { const b = new Blob(n.current, { type: Ve }); n.current = [], o.current && e(b); }, h = new MediaRecorder(t, { mimeType: Ve }); return h.addEventListener("dataavailable", p), h.addEventListener("stop", l), s.current = h, () => { h.removeEventListener("dataavailable", p), h.removeEventListener("stop", l), h.stop(); }; }, [t, e]); const i = B(() => !s.current || s.current.state === "recording" ? !1 : (o.current = !1, n.current = [], s.current.start(), !0), []), a = B((p) => !s.current || s.current.state === "inactive" ? !1 : (o.current = p, s.current.stop(), !0), []); return { startRecording: i, stopRecording: a }; }, Tt = (t) => { const e = Math.sqrt(t.x ** 2 + t.y ** 2); if (e === 0) throw new Error("Direction vector cannot be zero"); return { x: t.x / e, y: t.y / e }; }, Lt = (t, e) => ({ x: e.x - t.x, y: e.y - t.y }), Pt = (t, e) => { const s = { x: e.x - t.x, y: e.y - t.y }; return { x: -s.y, y: s.x }; }, Ut = (t, e, s) => { const n = s.x, o = s.y; return (n * (t.x - e.x) + o * (t.y - e.y)) / Math.sqrt(n * n + o * o); }, ue = (t, e) => Math.sqrt(Math.pow(t.x - e.x, 2) + Math.pow(t.y - e.y, 2)), he = (t, e) => { const s = { x: e.x - t.x, y: e.y - t.y }; return Math.atan2(s.y, s.x) * 180 / Math.PI; }, At = (t, e, s) => { const n = Tt(e), o = { x: s.x - t.x, y: s.y - t.y }, i = o.x * n.x + o.y * n.y; return { x: t.x + n.x * i, y: t.y + n.y * i }; }, Vt = ({ boundingBox: t, videoHeight: e, videoWidth: s }) => { const n = t.width / s, o = t.height / e, i = Math.max(n, o), a = t.originX / s, p = t.originY / e, l = 1 - (a + n), h = 1 - (p + o), { faceTopEdgeMin: b, faceRightEdgeMin: c, faceBottomEdgeMin: S, faceLeftEdgeMin: d, minFaceArea: C } = Ce.config.livenessCheckSettings.thresholdConfiguration || {}, w = { top: b ?? 0.3, right: c ?? 0.2, bottom: S ?? 0.1, left: d ?? 0.2, size: C ?? 0.4 }, f = p > w.top, I = a > w.right, y = h > w.bottom, M = l > w.left, k = i > w.size; return { top: p, bottom: h, right: a, left: l, width: n, height: o, size: i, topOk: f, rightOk: I, bottomOk: y, leftOk: M, sizeOk: k, overallOk: f && I && y && M && k }; }, $t = ({ keypoints: t }) => { const [e, s, n, o, i, a] = t, p = Lt(i, a), l = At(i, p, n), h = ue(i, a), b = ue(i, l), c = b ? (b / h - 0.5) * 2 * 45 : 0, { rollAbsMaxDeg: S, pitchMin: d, pitchMax: C, yawAbsMaxDeg: w } = Ce.config.livenessCheckSettings.thresholdConfiguration || {}, f = { roll: S ?? 10, pitchMin: d ?? -0.12, pitchMax: C ?? 0.45, yaw: w ?? 15 }, I = !!b && Math.abs(c) < f.yaw, y = ue(i, a), M = Pt(i, a), k = Ut(n, i, M), g = y ? k / y : 0, F = y > 0 && g > f.pitchMin && g < f.pitchMax, $ = he(e, s), L = he(n, o) - 90, ne = he(i, a), O = ($ + L + ne) / 3, A = Math.abs(O) < f.roll; return { eyeLeft: e, eyeRight: s, nose: n, mouth: o, earLeft: i, earRight: a, yawReference: l, yaw: c, yawOk: I, pitch: g, pitchOk: F, roll: O, rollOk: A, overallOk: I && F && A }; }, zt = 10, de = at.mediaPipe.CFaceDetectionConfig, Qt = ({ setDetectionInfo: t, videoMarkupRef: e, videoElement: s }) => { const n = U(null), o = U(0), i = U(null), a = U(null), p = U(null), [l, h] = Y(!1), [b, c] = Y(!1), [S, d] = Y(null), [C, w] = Y(!1), f = B(async () => { var O, A; if (a.current && cancelAnimationFrame(a.current), p.current && clearTimeout(p.current), !(s != null && s.srcObject) || !i.current || !(i.current instanceof Te)) { p.current = setTimeout(() => f(), 1e3); return; } const y = performance.now(), M = i.current.detectForVideo(s, y).detections; let k = !1, g = "", F = "position_face"; if (M.length === 1) { const z = M[0], { keypoints: X, boundingBox: _e } = z; if (_e) { const E = s.videoWidth, Q = s.videoHeight, R = Vt({ boundingBox: _e, videoWidth: E, videoHeight: Q }); g += `Position: ${R.overallOk ? "" : "!!!"} `, g += ` top: ${(R.top * 100).toFixed(2)}% ${R.topOk ? "" : "!!!"} `, g += ` bottom: ${(R.bottom * 100).toFixed(2)}% ${R.bottomOk ? "" : "!!!"} `, g += ` right: ${(R.right * 100).toFixed(2)}% ${R.rightOk ? "" : "!!!"} `, g += ` left: ${(R.left * 100).toFixed(2)}% ${R.leftOk ? "" : "!!!"} `, g += ` size: ${(R.size * 100).toFixed(2)}% ${R.sizeOk ? "" : "!!!"} `, (A = (O = e.current) == null ? void 0 : O.querySelector("#face")) == null || A.setAttribute("style", `top: ${R.top * 100}%; right: ${R.right * 100}%; width: ${R.width * 100}%; height: ${R.height * 100}%;`), R.overallOk || (F = R.sizeOk ? "center_face" : "move_closer", k = !0); } else g += `No bounding box detected `; if (X.length === 6) { const E = $t({ keypoints: X }), Q = (R, { x: Ne, y: He }, We = "red") => { var Se, ke; (ke = (Se = e.current) == null ? void 0 : Se.querySelector(R)) == null || ke.setAttribute("style", `top: ${He * 100}%; right: ${Ne * 100}%; background: ${We};`); }; Q("#left_eye", E.eyeLeft), Q("#right_eye", E.eyeRight), Q("#nose", E.nose), Q("#mouth", E.mouth), Q("#left_ear", E.earLeft), Q("#right_ear", E.earRight), Q("#yaw_reference", E.yawReference, "green"), g += ` Rotation: ${E.overallOk ? "" : "!!!"} `, g += ` yaw: ${E.yaw.toFixed(2)}° ${E.yawOk ? "" : "!!!"} `, g += ` pitch: ${(E.pitch * 100).toFixed(2)}% ${E.pitchOk ? "" : "!!!"} `, g += ` roll: ${E.roll.toFixed(2)}° ${E.rollOk ? "" : "!!!"} `, E.overallOk || (F = "straighten_face", k = !0); } else g += `No keypoints detected `; } else g = M.length ? "Multiple faces detected" : "No face detected", k = !0; t(g), d(k ? F : "hold"), k ? (h(!1), o.current = 0, n.current = null) : (o.current = o.current + 1, o.current === zt && (h(!0), n.current = y)); const $ = Ce.config.promptLength; if ((n.current ? y - n.current : 0) > $ * 1e3) { a.current && cancelAnimationFrame(a.current), c(!0); return; } a.current = window.requestAnimationFrame(() => f()); }, [s, t, e]); return Z(() => (ot.forVisionTasks(de.forVisionTasks).then((y) => Te.createFromOptions(y, { baseOptions: { modelAssetPath: de.modelAssetPath, delegate: "GPU" }, minDetectionConfidence: de.minDetectionConfidence, runningMode: "VIDEO" })).then((y) => { i.current = y, w(!0); }), () => { var y; (y = i.current) == null || y.close(), i.current = null; }), []), { startDetector: B(() => { f(); }, [f]), isFaceDetected: l, isCompleted: b, instruction: S, initialized: C }; }, jt = ({ onSucess: t, onFail: e }) => { const [s, n] = Y(!1), o = B(async (i, a = []) => { n(!0); try { if (!i) throw new Error("Video blob is null"); if (!((i == null ? void 0 : i.size) || 0)) throw new Error("Video blob size is 0"); const l = await new ct(a).getUploadUrl(); if (!(l != null && l.ok)) throw new Error("Error getting video upload url"); if ((await new lt({ url: l.videoUploadUrl, video: i, mimeType: i.type }).startUploadLivenessVideo()).ok === !1) throw new Error("Error uploading video"); t(); } catch (p) { e(p); } finally { n(!1); } }, [t, e]); return { isUploading: s, uploadVideo: o }; }, qt = (t) => { Qe({ title: j.error_liveness_upload_title, description: j.error_liveness_upload_description, btnText: j.restart_button, ERROR: t }); }, Gt = ({ onNext: t, onBack: e }) => { const s = U(null), n = U(null), o = B(($) => { n.current && (n.current.innerText = $); }, []), i = B(() => { var $; o("Camera loaded"), ($ = s.current) == null || $.call(s); }, [o]), { isUploading: a, uploadVideo: p } = jt({ onFail: qt, onSucess: t }), { videoComponent: l, videoStream: h, videoElement: b, videoMarkupRef: c } = It({ onDataLoaded: i }), { startRecording: S, stopRecording: d } = Ft({ onRecordingFinished: p, stream: h }), { startDetector: C, isCompleted: w, isFaceDetected: f, instruction: I, initialized: y } = Qt({ videoMarkupRef: c, setDetectionInfo: o, videoElement: b }), M = dt(() => { switch (I) { case "center_face": return { text: j.liveness_check_action_center_face }; case "move_closer": return { text: j.liveness_check_action_move_closer }; case "straighten_face": return { text: j.liveness_check_action_straighten_face }; case "hold": return { text: j.liveness_check_action_hold }; } return { icon: P.jsx(ut, { width: 48, hanging: 48 }), text: j.liveness_check_action_position_face }; }, [I]); Z(() => (s.current = C, () => { s.current = null; }), [C]), Z(() => { w ? d(!0) : f ? S() : d(!1); }, [f, w, S, d]); const F = [ { animateTo: { startAnimationTo: f, strokeDasharray: "0", strokeWidth: "4" }, outline: "idle", dimension: "face-only" }, { outline: "countdown", dimension: "face-only", startAnimation: f } ][f || w ? 1 : 0]; return P.jsxs(P.Fragment, { children: [P.jsx(nt, { className: `tw-w-full tw-h-full sm:tw-h-auto ${a && "tw-opacity-0"}`, children: P.jsxs(it, { idPrefix: "selfie-liveness-camera", onBack: e, title: j.liveness_check_selfie_flow_title, instructions: M, children: [P.jsxs(ht, { dimension: F.dimension, outline: F.outline, startAnimation: F.startAnimation, animateTo: F.animateTo, isSuccessful: w, children: [l, !y && P.jsx(Le, { isUploading: !0 })] }), !1] }) }), P.jsx(Le, { isUploading: a })] }); }; export { Gt as default };