vec-idp-web-sdk
Version:
VECU Identity Verification Web SDK - A secure, easy-to-integrate identity verification solution
3 lines (2 loc) • 13.4 kB
JavaScript
import{EventEmitter as e,Logger as t,VecuError as s,TimeoutError as i,ProviderError as o}from"../index.esm.js";class r{constructor(){this._isLoaded=!1,this.sdkInstance=null,this.activeUI=null,this.eventEmitter=new e,this.logger=new t("info",!0)}get isLoaded(){return this._isLoaded}mapEvent(e){if(!e||"object"!=typeof e)return null;const t=e;return{type:String(t.type||"unknown"),data:t.data||t,timestamp:new Date}}destroy(){this.activeUI&&(this.activeUI.destroy(),this.activeUI=null),this.sdkInstance&&(this.cleanupSDK(),this.sdkInstance=null),this.eventEmitter&&this.eventEmitter.removeAllListeners(),this._isLoaded=!1,this.logger.info(`${this.name} provider destroyed`)}async loadScript(e,t){return new Promise((i,o)=>{if(t&&window[t])return this.logger.info(`${this.name} SDK already loaded`),void i();const r=document.createElement("script");r.src=e,r.async=!0,r.crossOrigin="anonymous",r.onload=()=>{this.logger.info(`${this.name} SDK loaded successfully`),i()},r.onerror=t=>{this.logger.error(`Failed to load ${this.name} SDK`,t),o(new s("PROVIDER_SDK_LOAD_FAILED",`Failed to load ${this.name} SDK from ${e}`))},document.head.appendChild(r)})}createUIContainer(e,t){const s=document.createElement("div");return s.className=`vecu-idv-${this.name}-container vecu-idv-${t}`,s.setAttribute("data-provider",this.name),s.style.cssText=`\n position: ${"modal"===t?"fixed":"relative"};\n width: 100%;\n height: 100%;\n ${"modal"===t?"top: 0; left: 0; z-index: 9999;":""}\n `,e.appendChild(s),s}removeUIContainer(e){e&&e.parentNode&&e.parentNode.removeChild(e)}emitProviderEvent(e,t){const s={type:e,data:t,timestamp:new Date};this.eventEmitter.emit(e,s),this.eventEmitter.emit("provider:event",s)}handleProviderError(e,t){const i=e instanceof s?e:new s("PROVIDER_ERROR",`${this.name} provider error in ${t}: ${e instanceof Error?e.message:String(e)}`,this.name);throw this.logger.error(`${this.name} provider error`,i),this.emitProviderEvent("provider:error",{code:i.code,message:i.message,provider:this.name,context:t}),i}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}validateInitOptions(e){if(!e.sessionId)throw new s("INVALID_OPTIONS","Session ID is required");if(!e.token)throw new s("INVALID_OPTIONS","Token is required");if(!(e.container&&e.container instanceof HTMLElement))throw new s("INVALID_OPTIONS","Valid HTML container element is required");if(!["modal","embedded"].includes(e.mode))throw new s("INVALID_OPTIONS",'Mode must be either "modal" or "embedded"')}}const n={socure:{scriptUrl:"https://websdk.socure.com/bundle.js",supportedFeatures:["document_verification","liveness_check","face_match","address_verification","database_check","qr_code_handoff"]}},a="ready",c="start",d="complete",u="error",l="close",m="document:front:capture",h="document:back:capture",p="document:processing",v="liveness:start",D="liveness:processing",f="liveness:complete";function S(e,t){return new Promise((s,i)=>{const o=function(e,t){const s=document.createElement(e);return t&&Object.entries(t).forEach(([e,t])=>{"className"===e?s.className=t:"style"===e?s.setAttribute("style",t):e.startsWith("data-")?s.setAttribute(e,t):s[e]=t}),s}("script",{src:e,async:"true",...t});o.onload=()=>s(),o.onerror=()=>i(new Error(`Failed to load script: ${e}`)),document.head.appendChild(o)})}class g{constructor(){this.loadPromise=null,this.sdkInstance=null,this.isDestroyed=!1}static getInstance(){return g.instance||(g.instance=new g),g.instance}async load(){if((this.isDestroyed||!this.sdkInstance&&window.SocureDocVSDK)&&(this.isDestroyed=!1,this.sdkInstance=null,this.loadPromise=null,delete window.SocureDocVSDK),this.sdkInstance)return this.sdkInstance;if(this.loadPromise)return this.loadPromise;this.loadPromise=this.loadSDK();try{return this.sdkInstance=await this.loadPromise,this.sdkInstance}catch(e){throw this.loadPromise=null,e}}async loadSDK(){const e=n.socure,t="SocureDocVSDK";if(window[t])return window[t];const s=3e4,o=new Promise((e,t)=>{setTimeout(()=>{t(new i("Socure SDK load timeout after 30000ms",s))},s)}),r=S(this.isDestroyed?`${e.scriptUrl}?t=${Date.now()}`:e.scriptUrl,{"data-provider":"socure",crossorigin:"anonymous"}).then(()=>new Promise((e,s)=>{setTimeout(()=>{const i=window[t];i?e(i):s(new Error(`Socure DocV SDK not found at window.${t}`))},100)}));return Promise.race([r,o])}isLoaded(){return null!==this.sdkInstance}getSDK(){return this.sdkInstance}destroy(){this.isDestroyed=!0,window.SocureDocVSDK&&delete window.SocureDocVSDK;document.querySelectorAll('script[src*="websdk.socure.com"]').forEach(e=>{e.remove()}),this.sdkInstance=null,this.loadPromise=null,g.instance=null}}g.instance=null;class w{static mapEvent(e){if(!e||"object"!=typeof e)return null;const t=e.type;return{type:this.eventMap[t]||t,data:this.mapEventData(t,e.data),timestamp:new Date(e.timestamp||Date.now())}}static mapEventData(e,t){switch(e){case"complete":return this.mapCompleteData(t);case"error":return this.mapErrorData(t);case"document_front_capture":case"document_back_capture":return this.mapDocumentCaptureData(t);case"liveness_complete":return this.mapLivenessData(t);case"qr_code_displayed":return this.mapQRCodeData(t);default:return t}}static mapCompleteData(e){return e?{sessionId:e.referenceId,status:"completed",documentData:e.documentData?{type:e.documentData.type,number:e.documentData.documentNumber,issuingCountry:e.documentData.issuingCountry,expirationDate:e.documentData.expirationDate,firstName:e.documentData.firstName,lastName:e.documentData.lastName,dateOfBirth:e.documentData.dateOfBirth,address:e.documentData.address}:void 0,livenessData:e.livenessData?{passed:e.livenessData.passed,score:e.livenessData.score,confidence:e.livenessData.confidence}:void 0,fraudSignals:e.fraud?{overallRisk:this.mapRiskLevel(e.fraud.score),signals:e.fraud.signals.map(e=>({type:e.name,risk:e.risk,description:e.description}))}:void 0}:{}}static mapErrorData(e){return e?{code:e.code||"SOCURE_ERROR",message:e.message||"Socure verification error",details:e.details,provider:"socure"}:{code:"UNKNOWN_ERROR",message:"Unknown error occurred"}}static mapDocumentCaptureData(e){return{side:e?.side||"unknown",quality:e?.quality||"unknown",timestamp:(new Date).toISOString()}}static mapLivenessData(e){return{passed:e?.passed||!1,score:e?.score||0,confidence:e?.confidence||"low",timestamp:(new Date).toISOString()}}static mapQRCodeData(e){return{qrCodeUrl:e?.url,sessionUrl:e?.sessionUrl,expiresAt:e?.expiresAt}}static mapRiskLevel(e){return e<30?"low":e<70?"medium":"high"}static mapWebhookData(e){if(!e)return null;const t=e.documentVerification?.decision||e.selfieVerification?.decision||"review";return{sessionId:e.referenceId,provider:"socure",status:"complete"===e.status?"completed":"failed",decision:this.mapDecision(t),documentData:e.documentVerification?{type:e.documentVerification.documentType,...e.documentVerification.documentFields}:void 0,livenessData:e.selfieVerification?{passed:"accept"===e.selfieVerification.decision,score:e.selfieVerification.livenessScore,confidence:this.mapConfidence(e.selfieVerification.livenessScore)}:void 0,fraudSignals:e.fraud?{overallRisk:this.mapRiskLevel(e.fraud.score),signals:e.fraud.signals.map(e=>({type:e,risk:"medium",description:e}))}:void 0,completedAt:new Date(e.updatedAt)}}static mapDecision(e){switch(e){case"accept":return"approved";case"reject":return"declined";default:return"review"}}static mapConfidence(e){return e>=80?"high":e>=50?"medium":"low"}}w.eventMap={init:a,ready:a,start:c,document_front_capture:m,document_back_capture:h,document_processing:p,liveness_start:v,liveness_processing:D,liveness_complete:f,complete:d,error:u,close:l,qr_code_displayed:"qr_code:displayed",mobile_handoff:"mobile:handoff"};class I extends r{constructor(){super(),this.name="socure",this.version="1.0.0",this.supportedFeatures=[...n.socure.supportedFeatures],this.socureDocVSDK=null,this.activeSession=null,this.sdkLoader=g.getInstance()}async loadSDK(){try{this.logger.info("Loading Socure DocV SDK..."),this.sdkLoader||(this.sdkLoader=g.getInstance()),this.socureDocVSDK=await this.sdkLoader.load(),this._isLoaded=!0,this.logger.info("Socure DocV SDK loaded successfully"),this.emitProviderEvent("provider:loaded",{provider:this.name})}catch(e){this._isLoaded=!1,this.handleProviderError(e,"loadSDK")}}async initializeVerification(e){try{if(this.validateInitOptions(e),window.SocureDocVSDK||document.querySelector('iframe[src*="socure"]')){if(this.logger.info("Detected existing Socure state, cleaning up before initialization..."),e.container instanceof HTMLElement)for(;e.container.firstChild;)e.container.removeChild(e.container.firstChild);document.querySelectorAll('iframe[src*="socure"], iframe[id*="socure"]').forEach(e=>{e.remove()});["SocureDocVSDK","Socure","socure","SOCURE"].forEach(e=>{window[e]&&delete window[e]}),document.querySelectorAll('script[src*="websdk.socure.com"]').forEach(e=>{e.remove()}),this._isLoaded=!1,this.socureDocVSDK=null,this.sdkLoader&&(this.sdkLoader.destroy(),this.sdkLoader=g.getInstance()),await new Promise(e=>setTimeout(e,300)),await this.loadSDK()}if(!this.socureDocVSDK)throw new o(this.name,"Socure DocV SDK not loaded");this.logger.info("Initializing Socure verification",{sessionId:e.sessionId,hasSDK:!!this.socureDocVSDK,sdkType:typeof this.socureDocVSDK,methods:this.socureDocVSDK?Object.keys(this.socureDocVSDK):[]});const t=e.config?.publicKey||e.config?.sdkKey;if(!t)throw new o(this.name,"Socure SDK key is required in provider config");const s=e.token;if(!s)throw new o(this.name,"docvTransactionToken is required");const i=this.createUIContainer(e.container,e.mode),r={onProgress:t=>{this.logger.info("Socure progress event",t),this.handleProgressEvent(t,e.sessionId)},onSuccess:t=>{if(this.logger.info("Socure verification completed",t),"status"in t&&"DOCUMENTS_UPLOADED"===t.status)this.emitProviderEvent("verification:completed",{sessionId:e.sessionId,result:{status:"completed",docvTransactionToken:t.docvTransactionToken,deviceSessionToken:t.deviceSessionToken,customerUserId:t.customerUserId}});else{const s=w.mapEvent({type:"complete",data:t,timestamp:Date.now()});s&&this.emitProviderEvent(s.type,s.data),this.emitProviderEvent("verification:completed",{sessionId:e.sessionId,result:t})}},onError:t=>{if(this.logger.error("Socure verification error",t),!("status"in t)||"CONSENT_DECLINED"!==t.status&&"DOCUMENTS_UPLOAD_FAILED"!==t.status){const s=w.mapEvent({type:"error",data:t,timestamp:Date.now()});s&&this.emitProviderEvent(s.type,s.data),"code"in t&&"USER_CANCELLED"===t.code&&this.emitProviderEvent("ui:closed",{sessionId:e.sessionId})}else{const s="CONSENT_DECLINED"===t.status?"USER_CANCELLED":"UPLOAD_FAILED";this.emitProviderEvent("verification:failed",{sessionId:e.sessionId,error:{code:s,message:t.status.replace(/_/g," ").toLowerCase(),docvTransactionToken:t.docvTransactionToken}}),"CONSENT_DECLINED"===t.status&&this.emitProviderEvent("ui:closed",{sessionId:e.sessionId})}},qrCodeNeeded:e.config?.qrCode||!1},n=`socure-container-${Date.now()}`;i.id=n;const a=`#${n}`;let c;try{c=this.socureDocVSDK.launch(t,s,a,r)}catch(e){throw e}this.activeSession=c&&"object"==typeof c?c:{id:e.sessionId,status:"active",destroy:()=>{this.logger.info("Destroying Socure session")}},setTimeout(()=>{document.querySelector(a)},500);const d={container:i,sessionId:e.sessionId,provider:this.name,destroy:()=>{this.destroySession(),this.removeUIContainer(i)}};return this.activeUI=d,this.emitProviderEvent("ui:created",{sessionId:e.sessionId}),setTimeout(()=>{this.emitProviderEvent("ui:ready",{sessionId:e.sessionId})},100),d}catch(e){this.handleProviderError(e,"initializeVerification")}}processWebhookData(e){try{const t=w.mapWebhookData(e);return{status:t.status,decision:t.decision,data:{documentData:t.documentData,livenessData:t.livenessData,fraudSignals:t.fraudSignals},metadata:{provider:this.name,processedAt:(new Date).toISOString()}}}catch(e){throw this.logger.error("Failed to process webhook data",e),new o(this.name,"Failed to process webhook data")}}mapEvent(e){return w.mapEvent(e)}cleanupSDK(){this.destroySession();document.querySelectorAll('iframe[src*="socure"], iframe[id*="socure"]').forEach(e=>{this.logger.info("Removing Socure iframe from DOM"),e.remove()});["SocureDocVSDK","Socure","socure","SOCURE"].forEach(e=>{window[e]&&(this.logger.info(`Clearing global ${e}`),delete window[e])});document.querySelectorAll('[id*="socure-container"], .socure-sdk-container').forEach(e=>{this.logger.info("Removing Socure container from DOM"),e.remove()}),this.sdkLoader.destroy(),this.socureDocVSDK=null}handleProgressEvent(e,t){if(e.status){const s={WAITING_FOR_USER_TO_REDIRECT:"qr_code_displayed",WAITING_FOR_UPLOAD:"verification:started"}[e.status]||"verification:progress";this.emitProviderEvent(s,{sessionId:t,status:e.status,docvTransactionToken:e.docvTransactionToken,customerUserId:e.customerUserId,mobileNumber:e.mobileNumber}),this.emitProviderEvent("verification:progress",{sessionId:t,step:e.status,percentage:"WAITING_FOR_USER_TO_REDIRECT"===e.status?10:30,message:e.status.replace(/_/g," ").toLowerCase()})}else this.logger.warn("Received unexpected progress event structure from Socure",e)}destroySession(){if(this.activeSession){try{this.activeSession.destroy()}catch(e){this.logger.error("Error destroying Socure session",e)}this.activeSession=null}}}export{I as SocureProvider};
//# sourceMappingURL=SocureProvider-D9O2DIbN.esm.js.map