@hcaptcha/loader
Version:
This is a JavaScript library to easily configure the loading of the hCaptcha JS client SDK with built-in error handling.
5 lines (4 loc) • 11.8 kB
JavaScript
var g=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var $=(t,e,r)=>e in t?g(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r;var X=(t,e)=>{for(var r in e)g(t,r,{get:e[r],enumerable:!0})},Y=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of H(e))!W.call(t,o)&&o!==r&&g(t,o,{get:()=>e[o],enumerable:!(n=q(e,o))||n.enumerable});return t};var G=t=>Y(g({},"__esModule",{value:!0}),t);var A=(t,e,r)=>($(t,typeof e!="symbol"?e+"":e,r),r);var xe={};X(xe,{hCaptchaLoader:()=>B});module.exports=G(xe);var N="hCaptcha-script",h="hCaptchaOnLoad",R="script-error";var d="@hCaptcha/loader";function C(t){return Object.entries(t).filter(([,e])=>e||e===!1).map(([e,r])=>`${encodeURIComponent(e)}=${encodeURIComponent(String(r))}`).join("&")}function x(t){let e=t&&t.ownerDocument||document,r=e.defaultView||e.parentWindow||window;return{document:e,window:r}}function b(t){return t||document.head}function I(t){t.setTag("source",d),t.setTag("url",document.URL),t.setContext("os",{UA:navigator.userAgent}),t.setContext("browser",{...K()}),t.setContext("device",{...V(),screen_width_pixels:screen.width,screen_height_pixels:screen.height,language:navigator.language,orientation:screen.orientation?.type||"Unknown",processor_count:navigator.hardwareConcurrency,platform:navigator.platform})}function K(){let t=navigator.userAgent,e,r;return t.indexOf("Firefox")!==-1?(e="Firefox",r=t.match(/Firefox\/([\d.]+)/)?.[1]):t.indexOf("Edg")!==-1?(e="Microsoft Edge",r=t.match(/Edg\/([\d.]+)/)?.[1]):t.indexOf("Chrome")!==-1&&t.indexOf("Safari")!==-1?(e="Chrome",r=t.match(/Chrome\/([\d.]+)/)?.[1]):t.indexOf("Safari")!==-1&&t.indexOf("Chrome")===-1?(e="Safari",r=t.match(/Version\/([\d.]+)/)?.[1]):t.indexOf("Opera")!==-1||t.indexOf("OPR")!==-1?(e="Opera",r=t.match(/(Opera|OPR)\/([\d.]+)/)?.[2]):t.indexOf("MSIE")!==-1||t.indexOf("Trident")!==-1?(e="Internet Explorer",r=t.match(/(MSIE |rv:)([\d.]+)/)?.[2]):(e="Unknown",r="Unknown"),{name:e,version:r}}function T(t){return new Promise(e=>setTimeout(e,t))}function V(){let t=navigator.userAgent,e;t.indexOf("Win")!==-1?e="Windows":t.indexOf("Mac")!==-1?e="Mac":t.indexOf("Linux")!==-1?e="Linux":t.indexOf("Android")!==-1?e="Android":t.indexOf("like Mac")!==-1||t.indexOf("iPhone")!==-1||t.indexOf("iPad")!==-1?e="iOS":e="Unknown";let r;return/Mobile|iPhone|iPod|Android/i.test(t)?r="Mobile":/Tablet|iPad/i.test(t)?r="Tablet":r="Desktop",{model:e,family:e,device:r}}var z=class P{_parent;breadcrumbs=[];context={};extra={};tags={};request;user;constructor(e){this._parent=e}get parent(){return this._parent}child(){return new P(this)}setRequest(e){return this.request=e,this}removeRequest(){return this.request=void 0,this}addBreadcrumb(e){return typeof e.timestamp>"u"&&(e.timestamp=new Date().toISOString()),this.breadcrumbs.push(e),this}setExtra(e,r){return this.extra[e]=r,this}removeExtra(e){return delete this.extra[e],this}setContext(e,r){return typeof r.type>"u"&&(r.type=e),this.context[e]=r,this}removeContext(e){return delete this.context[e],this}setTags(e){return this.tags={...this.tags,...e},this}setTag(e,r){return this.tags[e]=r,this}removeTag(e){return delete this.tags[e],this}setUser(e){return this.user=e,this}removeUser(){return this.user=void 0,this}toBody(){let e=[],r=this;for(;r;)e.push(r),r=r.parent;return e.reverse().reduce((n,o)=>(n.breadcrumbs=[...n.breadcrumbs??[],...o.breadcrumbs],n.extra={...n.extra,...o.extra},n.contexts={...n.contexts,...o.context},n.tags={...n.tags,...o.tags},o.user&&(n.user=o.user),o.request&&(n.request=o.request),n),{breadcrumbs:[],extra:{},contexts:{},tags:{},request:void 0,user:void 0})}clear(){this.breadcrumbs=[],this.context={},this.tags={},this.user=void 0}},J=/^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,Q=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpack|resource|moz-extension).*?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js))(?::(\d+))?(?::(\d+))?\s*$/i,Z=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,ee=/^(?:(\w+):)\/\/(?:(\w+)(?::(\w+))?@)([\w.-]+)(?::(\d+))?\/(.+)/,y="?",_="An unknown error occurred",te="0.0.4";function re(t){for(let e=0;e<t.length;e++)t[e]=Math.floor(Math.random()*256);return t}function a(t){return(t+256).toString(16).substring(1)}function ne(){let t=re(new Array(16));return t[6]=t[6]&15|64,t[8]=t[8]&63|128,a(t[0])+a(t[1])+a(t[2])+a(t[3])+"-"+a(t[4])+a(t[5])+"-"+a(t[6])+a(t[7])+"-"+a(t[8])+a(t[9])+"-"+a(t[10])+a(t[11])+a(t[12])+a(t[13])+a(t[14])+a(t[15])}var se=[[J,"chrome"],[Z,"winjs"],[Q,"gecko"]];function oe(t){if(!t.stack)return null;let e=[],r=t.stack.split?.(`
`)??[];for(let n=0;n<r.length;++n){let o=null,s=null,i=null;for(let[u,f]of se)if(s=u.exec(r[n]),s){i=f;break}if(!(!s||!i)){if(i==="chrome")o={filename:s[2]?.startsWith("address at ")?s[2].substring(11):s[2],function:s[1]||y,lineno:s[3]?+s[3]:null,colno:s[4]?+s[4]:null};else if(i==="winjs")o={filename:s[2],function:s[1]||y,lineno:+s[3],colno:s[4]?+s[4]:null};else if(i==="gecko")n===0&&!s[5]&&t.columnNumber!==void 0&&e.length>0&&(e[0].column=t.columnNumber+1),o={filename:s[3],function:s[1]||y,lineno:s[4]?+s[4]:null,colno:s[5]?+s[5]:null};else continue;!o.function&&o.lineno&&(o.function=y),e.push(o)}}return e.length?e.reverse():null}function ie(t){let e=oe(t);return{type:t.name,value:t.message,stacktrace:{frames:e??[]}}}function ae(t){let e=ee.exec(t),r=e?e.slice(1):[];if(r.length!==6)throw new Error("Invalid DSN");let n=r[5].split("/"),o=n.slice(0,-1).join("/");return r[0]+"://"+r[3]+(r[4]?":"+r[4]:"")+(o?"/"+o:"")+"/api/"+n.pop()+"/envelope/?sentry_version=7&sentry_key="+r[1]+(r[2]?"&sentry_secret="+r[2]:"")}function ce(t,e,r){let n={event_id:ne().replaceAll("-",""),platform:"javascript",sdk:{name:"@hcaptcha/sentry",version:te},environment:e,release:r,timestamp:Date.now()/1e3,...t.scope.toBody()};if(t.type==="exception"){n.message=t.error?.message??"Unknown error",n.fingerprint=[n.message];let o=[],s=t.error;for(let i=0;i<5&&s&&(o.push(ie(s)),!(!s.cause||!(s.cause instanceof Error)));i++)s=s.cause;n.exception={values:o.reverse()}}return t.type==="message"&&(n.message=t.message,n.level=t.level),n}function ue(t){if(t instanceof Error)return t;if(typeof t=="string")return new Error(t);if(typeof t=="object"&&t!==null&&!Array.isArray(t)){let{message:r,...n}=t,o=new Error(typeof r=="string"?r:_);return Object.assign(o,n)}let e=new Error(_);return Object.assign(e,{cause:t})}async function le(t,e,r){try{if(typeof fetch<"u"&&typeof AbortSignal<"u"){let n;if(r){let i=new AbortController;n=i.signal,setTimeout(()=>i.abort(),r)}let o=await fetch(t,{...e,signal:n}),s=await o.text();return{status:o.status,body:s}}return await new Promise((n,o)=>{let s=new XMLHttpRequest;if(s.open(e?.method??"GET",t),s.onload=()=>n({status:s.status,body:s.responseText}),s.onerror=()=>o(new Error("XHR Network Error")),e?.headers)for(let[i,u]of Object.entries(e.headers))s.setRequestHeader(i,u);if(r){let i=setTimeout(()=>{s.abort(),o(new Error("Request timed out"))},r);s.onloadend=()=>{clearTimeout(i)}}s.send(e?.body?.toString())})}catch(n){return{status:0,body:n?.toString?.()??"Unknown error"}}}var c,v=(c=class{apiURL;dsn;environment;release;sampleRate;debug;_scope;shouldBuffer=!1;bufferlimit=20;buffer=[];constructor(e){this.environment=e.environment,this.release=e.release,this.sampleRate=e.sampleRate??1,this.debug=e.debug??!1,this._scope=e.scope??new z,this.apiURL=ae(e.dsn),this.dsn=e.dsn,this.shouldBuffer=e.buffer??!1,this.bufferlimit=e.bufferLimit??20}static init(e){c._instance||(c._instance=new c(e))}static get instance(){if(!c._instance)throw new Error("Sentry has not been initialized");return c._instance}log(...e){this.debug&&console.log(...e)}get scope(){return this._scope}static get scope(){return c.instance.scope}withScope(e){let r=this._scope.child();e(r)}static withScope(e){c.instance.withScope(e)}captureException(e,r){this.captureEvent({type:"exception",level:"error",error:ue(e),scope:r??this._scope})}static captureException(e,r){c.instance.captureException(e,r)}captureMessage(e,r="info",n){this.captureEvent({type:"message",level:r,message:e,scope:n??this._scope})}static captureMessage(e,r="info",n){c.instance.captureMessage(e,r,n)}captureEvent(e){if(Math.random()>=this.sampleRate){this.log("Dropped event due to sample rate");return}if(this.shouldBuffer){if(this.buffer.length>=this.bufferlimit)return;this.buffer.push(e)}else this.sendEvent(e)}async sendEvent(e,r=5e3){try{this.log("Sending sentry event",e);let n=ce(e,this.environment,this.release),o={event_id:n.event_id,dsn:this.dsn},s={type:"event"},i=JSON.stringify(o)+`
`+JSON.stringify(s)+`
`+JSON.stringify(n),u=await le(this.apiURL,{method:"POST",headers:{"Content-Type":"application/x-sentry-envelope"},body:i},r);this.log("Sentry response",u.status),u.status!==200&&(console.log(u.body),console.error("Failed to send event to Sentry",u))}catch(n){console.error("Failed to send event",n)}}async flush(e=5e3){try{this.log("Flushing sentry events",this.buffer.length);let r=this.buffer.splice(0,this.buffer.length).map(n=>this.sendEvent(n,e));await Promise.all(r),this.log("Flushed all events")}catch(r){console.error("Failed to flush events",r)}}static flush(e=5e3){return c.instance.flush(e)}static reset(){c._instance=void 0}},A(c,"_instance"),c);var de="https://d233059272824702afc8c43834c4912d@sentry.hcaptcha.com/6",pe="2.3.0",fe="production";function M(t=!0){if(!t)return D();v.init({dsn:de,release:pe,environment:fe});let e=v.scope;return I(e),D(e)}function D(t=null){return{addBreadcrumb:e=>{t&&t.addBreadcrumb(e)},captureRequest:e=>{t&&t.setRequest(e)},captureException:e=>{t&&v.captureException(e,t)}}}function L({scriptLocation:t,query:e,loadAsync:r=!0,crossOrigin:n="anonymous",apihost:o="https://js.hcaptcha.com",cleanup:s=!1,secureApi:i=!1,scriptSource:u=""}={},f){let p=b(t),w=x(p);return new Promise((F,O)=>{let l=w.document.createElement("script");l.id=N,u?l.src=`${u}?onload=${h}`:i?l.src=`${o}/1/secure-api.js?onload=${h}`:l.src=`${o}/1/api.js?onload=${h}`,l.crossOrigin=n,l.async=r;let S=(m,j)=>{try{!i&&s&&p.removeChild(l),j(m)}catch(k){O(k)}};l.onload=m=>S(m,F),l.onerror=m=>{f&&f(l.src),S(m,O)},l.src+=e!==""?`&${e}`:"",p.appendChild(l)})}var E=[];function ge(t={cleanup:!1},e){try{e.addBreadcrumb({category:d,message:"hCaptcha loader params",data:t});let r=b(t.scriptLocation),n=x(r),o=E.find(({scope:i})=>i===n.window);if(o)return e.addBreadcrumb({category:d,message:"hCaptcha already loaded"}),o.promise;let s=new Promise(async(i,u)=>{try{n.window[h]=()=>{e.addBreadcrumb({category:d,message:"hCaptcha script called onload function"}),i(n.window.hcaptcha)};let f=C({custom:t.custom,render:t.render,sentry:t.sentry,assethost:t.assethost,imghost:t.imghost,reportapi:t.reportapi,endpoint:t.endpoint,host:t.host,recaptchacompat:t.recaptchacompat,hl:t.hl,uj:t.uj});await L({query:f,...t},p=>{e.captureRequest({url:p,method:"GET"})}),e.addBreadcrumb({category:d,message:"hCaptcha loaded",data:o})}catch{e.addBreadcrumb({category:d,message:"hCaptcha failed to load"});let p=E.findIndex(w=>w.scope===n.window);p!==-1&&E.splice(p,1),u(new Error(R))}});return E.push({promise:s,scope:n.window}),s}catch(r){return e.captureException(r),Promise.reject(new Error(R))}}async function U(t,e,r=0){let n=t.maxRetries??2,o=t.retryDelay??1e3,s=r<n?"Retry loading hCaptcha Api":"Exceeded maximum retries";try{return await ge(t,e)}catch(i){return e.addBreadcrumb({category:d,message:s}),r>=n?(e.captureException(i),Promise.reject(i)):(e.addBreadcrumb({category:d,message:`Waiting ${o}ms before retry attempt ${r+1}`}),await T(o),r+=1,U(t,e,r))}}async function B(t={}){let e=M(t.sentry);return await U(t,e)}