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.

613 lines (612 loc) 25.7 kB
var ce = Object.defineProperty; var le = (s, o, t) => o in s ? ce(s, o, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[o] = t; var I = (s, o, t) => le(s, typeof o != "symbol" ? o + "" : o, t); import { j as i, l as e, b as $, a as w, t as a, d as E, i as P, c as M, e as X, L as ee, S as ae } from "./index-oGnhSncZ.mjs"; import { useRef as q, useState as T, useCallback as z, useEffect as F, createElement as de } from "react"; import { createCaptureUi as ue } from "@microblink/capture"; import { C as te, a as oe } from "./CameraCard-DCtEAYmX.mjs"; import { R as re } from "./RetryLimitHandler-Bj2Rrg3E.mjs"; import { C as pe } from "./CardContentWrapper-CkWrRMQr.mjs"; import { T as Y } from "./TextWIcon-wzcHnhrW.mjs"; const me = { scan_the_front_side: "Scan the front side of the document", flip_document: "Flip the document", scan_the_back_side: "Scan the back side of the document", scanning_wrong_side: "Scanning wrong side", move_closer: "Move closer", move_farther: "Move farther", camera_angle_too_steep: "Keep document parallel to phone", document_too_close_to_edge: "Move farther", rotate_phone_animation: "Rotate card or turn phone to landscape", rotate_phone: "Rotate phone or card", lightning_too_bright: "Move to spot with less lighting", lightning_too_dark: "Move to brighter spot", blur_detected: "Keep document and phone still", glare_detected: "Tilt or move document to remove reflection", occluded: "Keep the document fully visible", // Tutorial need_help_tooltip: "Need help?", onboarding_field_visible_title: "Keep all the details visible", onboarding_field_visible_details: "Make sure you keep the document well lit. All document fields should be visible on the camera screen.", tutorial_fields_visible_title: "Keep all the fields visible", tutorial_fields_visible_start: "Start scanning", tutorial_fields_visible_details: "Make sure you aren’t covering parts of the document with a finger, including the bottom lines. Also, watch out for hologram reflections that go over the document fields.", tutorial_harsh_light_title: "Watch out for harsh light", tutorial_harsh_light_details: "Avoid direct harsh light because it reflects from the document and can make parts of the document unreadable. If you can’t read data on the document, it won’t be visible to the camera either.", tutorial_keep_still_title: "Keep still while scanning", tutorial_keep_still_details: "Try to keep the phone and document still while scanning. Moving either can blur the image and make data on the document unreadable.", // Camera camera_unavailable: "Camera Unavailable", camera_permission_error: "App doesn't have permission to use the camera, please change privacy settings", settings: "Settings", camera_media_capture_error: "Unable to capture media", camera_unable_to_resume_session: "Unable to resume", camera_query_in_progress: "", // Shared done: "Done", cancel: "Cancel", back: "Back", next: "Next", ok: "OK", dismiss: "Dismiss" }, ne = () => i.jsx("div", { className: "tw-absolute tw-h-full tw-w-full", children: i.jsx("div", { className: "mb-style-scope mb-1lz2sq8 mb-video-screen", children: i.jsx("div", { className: "mb-79tnxm", children: i.jsxs("div", { children: [i.jsx("div", { className: "mb-1kst2vr", children: i.jsx("div", { className: "mb-qaqzbh", children: i.jsx("div", { className: "mb-1v17koz", style: { opacity: "1", background: "rgba(102, 102, 102, .5)" }, children: i.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 100 100", className: "mb-1omzjeg", children: [i.jsx("path", { fill: "#fff", fillRule: "evenodd", d: "M50 7.692C26.634 7.692 7.692 26.634 7.692 50S26.634 92.308 50 92.308 92.308 73.366 92.308 50 73.366 7.692 50 7.692ZM0 50C0 22.386 22.386 0 50 0s50 22.386 50 50-22.386 50-50 50S0 77.614 0 50Z", clipRule: "evenodd", opacity: ".75" }), i.jsx("circle", { cx: "50", cy: "50", r: "4", fill: "#fff" })] }) }) }) }), i.jsx("div", { className: "mb-dcm5x3", children: i.jsx("div", { className: "mb-j1awg8", style: { opacity: "1", transform: "translateY(0px)" }, children: i.jsx("div", { children: e.document_capture_front_side }) }) })] }) }) }) }); class ie { constructor(o) { I(this, "reqBody"); I(this, "responseData", null); this.reqBody = o; } async postDocuments() { const o = await $({ endpoint: "/sessions/flow/init-document-photo-upload-v1", method: "POST", body: this.reqBody }); return this.responseData = o, this.responseData; } async getResponseData() { return this.responseData; } } class K { constructor({ url: o, image: t }) { I(this, "UploadDocumentToBucketResponseData", {}); I(this, "url"); I(this, "image"); I(this, "filename"); this.url = o, this.image = t, this.filename = `${(/* @__PURE__ */ new Date()).getTime() + Math.floor(Math.random() + 1e5)}`; } async startUploadDocumentToBucket() { const o = await this.imageDataToBlob(this.image), t = await $({ endpoint: this.url, method: "PUT", body: o, headers: { "Content-Type": "image/png", "Content-Disposition": `attachment; filename=${this.filename}.png` }, excludeJWT: !0, isFullUrl: !0, binaryBody: !0 }); return this.UploadDocumentToBucketResponseData = t, this.UploadDocumentToBucketResponseData; } async getUploadDocumentToBucketResponse() { return this.UploadDocumentToBucketResponseData; } async imageDataToBlob(o) { const t = document.createElement("canvas"); t.id = "imageDataToBlob"; const p = t.getContext("2d"); return t.width = o.width, t.height = o.height, p == null || p.putImageData(o, 0, 0), new Promise((g) => { t.toBlob((_) => { const v = document.getElementById("imageDataToBlob"); v && v.remove(), g(_); }, "image/png"); }); } } class se { constructor() { I(this, "documentProcessingResultResponseData", {}); } async getDocumentProcessing() { const o = await $({ endpoint: "/sessions/flow/document-processing-result-v1" }); return this.documentProcessingResultResponseData = o, this.documentProcessingResultResponseData; } async getDocumentProcessingResult() { return this.documentProcessingResultResponseData; } } const f = new re("error_code_5", "document capture"), _e = ({ onNext: s, onScannerClosed: o, data: t, onBack: p, hardRefresh: g }) => { var N; const _ = q(null), [v, R] = T(), b = q(), d = q(!1), [V, j] = T(!1), O = w.config, [W, B] = T(!1), r = z(() => { var n; R(void 0), B(!1), (n = b.current) == null || n.dismount(), o(), g(); }, [g, o]), x = z(async () => { var y, D, S; if (((y = w.config.idVerificationSettings) == null ? void 0 : y.responseMethod) === "ASYNC") { s(); return; } B(!0); const c = ((D = w.config.idVerificationSettings) == null ? void 0 : D.resultPollingCount) || 5, m = (((S = w.config.idVerificationSettings) == null ? void 0 : S.resultPollingInterval) || 2) * 1e3, u = new se(); for (let C = 0; C < c; C++) { try { await u.getDocumentProcessing(); const l = await u.getDocumentProcessingResult(); if (l != null && l.errorCode) { a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: l, btnAction() { f.handleRetry(() => p()); } }); return; } if (E("Document processing result", l), (l == null ? void 0 : l.documentProcessingResult) === "SUCCESS") { s(); return; } else if ((l == null ? void 0 : l.documentProcessingResult) === "INVALID_ID_TYPE") { E("Invalid ID type"), a({ logo: "document-not-supported", title: e.error_document_type_title, description: e.error_document_type_description, btnText: e.restart_button, btnAction() { f.handleRetry(() => p()); } }); return; } else if ((l == null ? void 0 : l.documentProcessingResult) === "INVALID_ID_COUNTRY") { E("Invalid ID country"), a({ logo: "country-not-supported", title: e.error_invalid_country_title, description: e.error_invalid_country_description, btnText: e.restart_button, btnAction() { f.handleRetry(() => p()); } }); return; } else if ((l == null ? void 0 : l.documentProcessingResult) === "UNKNOWN_ERROR") { E("Unknown error"), a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, btnAction() { f.handleRetry(() => p()); } }); return; } } catch { a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, btnAction() { f.handleRetry(() => p()); } }); } await new Promise((l) => setTimeout(l, m)); } a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, btnAction() { f.handleRetry(() => r()); } }); }, [p, s, r]), k = z(async (n) => { let c = 0; n != null && n.firstCapture && (n != null && n.secondCapture) ? c = 2 : (n != null && n.firstCapture || n != null && n.secondCapture) && (c = 1); const m = new ie({ numberOfImages: c, selectedIdCardType: t != null && t.country && (t != null && t.idType) ? { country: t.country.value, idType: t.idType.value } : void 0 }); m.postDocuments().then(() => { m.getResponseData().then((u) => { var l, L, Z, G, J, Q; if (!u) return; if (!u.ok) { a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: u }); return; } const y = ((l = n.firstCapture) == null ? void 0 : l.side) === "back" ? (L = n.secondCapture) == null ? void 0 : L.imageResult : (Z = n.firstCapture) == null ? void 0 : Z.imageResult, D = new K({ url: u.frontSideUploadUrl, image: y }); D.startUploadDocumentToBucket().then(() => { D.getUploadDocumentToBucketResponse().then((h) => { h.ok ? c === 1 && x() : a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: h, btnAction() { f.handleRetry(() => r()); } }); }).catch((h) => { a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: h }); }); }).catch((h) => { a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: h, btnAction() { f.handleRetry(() => r()); } }); }); const S = ((G = n.firstCapture) == null ? void 0 : G.side) === "back" ? (J = n.firstCapture) == null ? void 0 : J.imageResult : (Q = n.secondCapture) == null ? void 0 : Q.imageResult, C = new K({ url: u.backSideUploadUrl, image: S }); c > 1 && C.startUploadDocumentToBucket().then(() => (C.getUploadDocumentToBucketResponse().then((h) => { if (!h.ok) { a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: h, btnAction() { f.handleRetry(() => r()); } }); return; } }).catch((h) => { a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: h }); }), u.ok)).then((h) => { h && x(); }); }).catch((u) => { a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: u, btnAction() { f.handleRetry(() => r()); } }); }); }).catch((u) => { a({ logo: "general-error", title: e.error_liveness_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: u, btnAction() { f.handleRetry(() => r()); } }); }); }, [t, r, x]), A = z(async () => { var n, c; _.current && (b.current = await ue({ sdkSettings: { callbacks: { onCaptureResult: (m) => { R(m), k(m); }, onFrameAnalysis: () => { j(!0); } }, licenseKey: O.microblinkLicenseKey, resourceUrl: "https://idv-static.seon.io/sdk-assets", analyzerSettings: { captureSingleSide: ((n = t == null ? void 0 : t.idType) == null ? void 0 : n.value) === "PASSPORT" || !1, minimumDocumentDpi: 230, blurPolicy: w.config.blurCheckEnabled ? "relaxed" : "disabled", captureStrategy: "default" } }, uiSettings: { target: _.current, destroyInstanceOnDismount: !0, localization: me, showTutorial: !1, showErrorDialog: !1 } }).catch((m) => { a({ ERROR: m, btnAction() { r(), M("error", "error_code_4"); }, hideBtn: P() }); }), (c = b.current) == null || c.captureSdk.subscribe((m, u) => { var y, D, S, C, l, L; m.errorState !== u.errorState && ((y = u.errorState) != null && y.message.toLowerCase().includes("No capable devices") || (D = m.errorState) != null && D.message.toLowerCase().includes("No capable devices") ? (X("Camera error", m.errorState, u.errorState), a({ logo: "camera-access", title: e.error_device_support_title, description: e.error_device_support_description, btnText: e.error_device_support_button, btnAction() { r(), M("error", "error_code_1"); }, hideBtn: P() })) : (S = u.errorState) != null && S.message.toLowerCase().includes("camera") || (C = m.errorState) != null && C.message.toLowerCase().includes("camera") || (l = m.errorState) != null && l.message.toLowerCase().includes("video") || (L = u.errorState) != null && L.message.toLowerCase().includes("video") ? (X("Camera error", m.errorState, u.errorState), a({ logo: "camera-access", title: e.error_no_camera_access_title, description: e.error_no_camera_access_description, btnText: e.error_no_camera_access_button, btnAction() { r(); } })) : a({ btnAction() { r(), M("error", "error_code_4"); }, hideBtn: P() })); })); }, [ (N = t == null ? void 0 : t.idType) == null ? void 0 : N.value, k, r, O.microblinkLicenseKey ]); return F(() => { d.current || A().then(() => { d.current = !0; }).catch((n) => { a({ btnAction() { this.ERROR = n, r(), M("error", "error_code_4"); }, hideBtn: P() }); }); }, [A, r]), F(() => () => { var n, c; try { (n = b.current) == null || n.captureSdk.destroy(), (c = b.current) == null || c.dismount(), b.current = void 0; } catch { } }, []), i.jsxs(i.Fragment, { children: [W ? i.jsx(ee, {}) : i.jsx(te, { className: "tw-w-full", children: i.jsx(oe, { idPrefix: "blink-id-camera", onBack: V ? o : () => { }, title: e.document_capture_flow_title, children: i.jsx("div", { className: "blink-id-container tw-min-h-[300px] tw-h-full tw-bg-web-secondary tw-text-center tw-relative", ref: _, children: i.jsx(ne, {}) }) }) }), null] }); }, ge = ({ onBack: s, onNext: o }) => i.jsx(ae, { stepOf: "document-capture", className: "tw-w-full", children: i.jsx(pe, { idPrefix: "document-capture", description: e.tutorial_screen_description, backButtonText: e.back_to_previous_step_button, nextButtonText: e.tutorial_screen_scan_button, onBack: s, onNext: o, title: e.tutorial_screen_title, className: "tw-gap-12", children: i.jsxs("div", { className: "tw-flex tw-flex-col tw-gap-3", children: [i.jsx(Y, { text: e.tutorial_screen_list_1 }), i.jsx(Y, { text: e.tutorial_screen_list_2 }), i.jsx(Y, { text: e.tutorial_screen_list_3 })] }) }) }), U = new re("error_code_5", "document capture"), H = "https://idv-static.seon.io/sdk-assets/blink-id", he = async ({ onNext: s, onBack: o, resetDocumentScreen: t }) => { var v, R; const p = ((v = w.config.idVerificationSettings) == null ? void 0 : v.resultPollingCount) || 5, g = (((R = w.config.idVerificationSettings) == null ? void 0 : R.resultPollingInterval) || 2) * 1e3, _ = new se(); for (let b = 0; b < p; b++) { try { const d = await _.getDocumentProcessing(); if (d != null && d.errorCode) throw new Error("Error while polling"); if (E("Document processing result", d), (d == null ? void 0 : d.documentProcessingResult) === "SUCCESS") { s(); return; } else if ((d == null ? void 0 : d.documentProcessingResult) === "INVALID_ID_TYPE") { E("Invalid ID type"), a({ logo: "document-not-supported", title: e.error_document_type_title, description: e.error_document_type_description, btnText: e.restart_button, btnAction() { U.handleRetry(() => o()); } }); return; } else if ((d == null ? void 0 : d.documentProcessingResult) === "INVALID_ID_COUNTRY") { E("Invalid ID country"), a({ logo: "country-not-supported", title: e.error_invalid_country_title, description: e.error_invalid_country_description, btnText: e.restart_button, btnAction() { U.handleRetry(() => o()); } }); return; } else if ((d == null ? void 0 : d.documentProcessingResult) === "UNKNOWN_ERROR") throw E("Unknown error"), new Error("Unknown error"); } catch { a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, btnAction() { U.handleRetry(() => o()); } }); } await new Promise((d) => setTimeout(d, g)); } a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, btnAction() { U.handleRetry(() => t()); } }); }, be = async ({ frontSide: s, backSide: o, country: t, idType: p }) => { if (!s && o && (s = o, o = void 0), !s) throw new Error("No front side image provided"); const _ = await new ie({ numberOfImages: o ? 2 : 1, selectedIdCardType: t && p ? { country: t.value, idType: p.value } : void 0 }).postDocuments(); if (!(_ != null && _.ok)) throw new Error("Could not initialize document photo upload"); if (!(await new K({ url: _.frontSideUploadUrl, image: s }).startUploadDocumentToBucket()).ok) throw new Error("Could not upload front side document"); if (o && !(await new K({ url: _.backSideUploadUrl, image: o }).startUploadDocumentToBucket()).ok) throw new Error("Could not upload back side document"); }, fe = ({ onNext: s, onScannerClosed: o, data: t, onBack: p, hardRefresh: g }) => { const [_, v] = T(null), [R, b] = T(!1), [d, V] = T(!1), [j, O] = T(""), [W, B] = T(!1); return F(() => { const r = document.createElement("script"); r.src = `${H}/js/blinkid-in-browser/blinkid-in-browser.esm.js`, r.type = "module", r.async = !0; const x = `${H}/resources/BlinkIDWasmSDK.worker.min.js`; return console.log("fetch", x), fetch(x).then((k) => k.blob()).then((k) => O(URL.createObjectURL(k))).catch(console.error), r.onload = () => { console.log("Script loaded successfully!"), b(!0); }, r.onerror = () => { console.error("Failed to load the script."); }, document.body.appendChild(r), () => { document.body.removeChild(r); }; }, []), F(() => { if (!R || !j) return; console.log(_); const r = _; if (!r) { console.log("BlinkID container not found"); return; } r.licenseKey = w.config.microblinkLicenseKey, r.engineLocation = `${H}/resources/`, r.workerLocation = j, r.recognizers = ["BlinkIdMultiSideRecognizer"], r.allowHelloMessage = !1, r.allowHelpScreensFab = !1, r.allowHelpScreensOnboarding = !1, r.enableDrag = !1, r.scanFromImage = !1, r.recognizerOptions = { BlinkIdMultiSideRecognizer: { returnEncodedFaceImage: !0, returnEncodedFullDocumentImage: !0, returnEncodedSignatureImage: !0, returnFaceImage: !0, returnFullDocumentImage: !0, returnSignatureImage: !0, saveCameraFrames: !0 } }; const x = (n) => { const c = n.detail; console.log("Could not load UI component"), console.dir(c), a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: c, btnAction() { U.handleRetry(() => { o(), g(); }); } }); }, k = (n) => { const c = n.detail; console.log("Could not scan a document"), console.log(c), a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: c, btnAction() { U.handleRetry(() => { o(), g(); }); } }); }, A = (n) => { const c = n.detail; if (c != null && c.recognizer) { const m = c == null ? void 0 : c.recognizer; B(!0), be({ frontSide: m.frontCameraFrame.frame, backSide: m.backCameraFrame.frame, country: t == null ? void 0 : t.country, idType: t == null ? void 0 : t.idType }).then(() => { var y; if (((y = w.config.idVerificationSettings) == null ? void 0 : y.responseMethod) === "ASYNC") s(); else return he({ onNext: s, onBack: p, resetDocumentScreen: () => { p(), g(); } }); }).catch((u) => { console.error("Error while posting documents", u), a({ logo: "general-error", title: e.error_document_upload_title, description: e.error_document_upload_description, btnText: e.restart_button, ERROR: u, btnAction() { U.handleRetry(() => { o(), g(); }); } }); }).finally(() => { B(!1); }); } else console.log("No recognizer found in scan results"); }, N = () => { r.startCameraScan(), console.log("BlinkID is ready"), V(!0); }; return r.addEventListener("fatalError", x), r.addEventListener("scanError", k), r.addEventListener("scanSuccess", A), r.addEventListener("ready", N), console.log("BlinkID is starting"), () => { r.removeEventListener("fatalError", x), r.removeEventListener("scanError", k), r.removeEventListener("scanSuccess", A), r.removeEventListener("ready", N); }; }, [_, R, j, t == null ? void 0 : t.country, t == null ? void 0 : t.idType, g, p, s, o]), i.jsx(i.Fragment, { children: W ? i.jsx(ee, {}) : i.jsx(te, { className: "tw-w-full", children: i.jsxs(oe, { idPrefix: "blink-id-camera", onBack: o, title: e.document_capture_flow_title, className: d ? "blinkid-ready" : "", children: [de("blinkid-in-browser", { className: "blink-id-container tw-min-h-[300px] tw-h-full tw-bg-web-secondary tw-text-center tw-relative", ref: v }), i.jsx("div", { className: "blink-id-placeholder blink-id-container tw-min-h-[300px] tw-h-full tw-bg-web-secondary tw-text-center tw-relative", children: i.jsx(ne, {}) })] }) }) }); }, Ce = (s) => { const [o, t] = T(!1), p = w.config.documentCaptureSdk === "blinkID"; return o ? p ? i.jsx(fe, { ...s, onScannerClosed: () => t(!1) }) : i.jsx(_e, { ...s, onScannerClosed: () => t(!1) }) : i.jsx(ge, { onBack: s.onBack, onNext: () => t(!0) }); }; export { Ce as default };