cap-widget 0.1.55 → 0.1.56

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.
Files changed (3) hide show
  1. package/cap.min.js +1 -1
  2. package/package.json +1 -1
  3. package/src/cap.js +56 -10
package/cap.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{const e="vibrate"in navigator&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches;if("undefined"==typeof window)return;const t=["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"],i=(e,i,s)=>{const r=0===i?"9999px":"0",n=i===s-1?"9999px":"0";return`color:#1e1e2e;background:${(e=>{if("cap"===e)return"#89b4fa";let i=0;for(let t=0;t<e.length;t++)i=e.charCodeAt(t)+((i<<5)-i);return t[Math.abs(i)%t.length]})(e)};margin-left:${i?"-6px":0};padding:0 6px;border-radius:${r} ${n} ${n} ${r};font-weight:600`},s={};for(const e of["debug","info","warn","error"])s[e]=(t,...s)=>{if(window.CAP_SILENT||"debug"===e&&!window.CAP_DEBUG)return;const r=t.map(e=>`%c${e}`).join(" "),n=t.map((e,s)=>i(e,s,t.length));console["debug"===e?"log":e](r,...n,...s)};const r=e=>e?["cap",e]:["cap"],n=e=>`${Math.round(performance.now()-e)}ms`,a=(e,t)=>Object.assign(new Error(t),{code:e}),o=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t),l="initial-state,verifying-label,solved-label,error-label,required-label,troubleshooting-label,group-aria-label,verify-aria-label,verifying-aria-label,verified-aria-label,error-aria-label".split(","),c={"zh-cn":"确认你是真人/正在验证.../你是真人/出错了。请重试。/请确认你是真人/故障排除/Cap 验证/点击以确认你是真人/正在验证你是真人,请稍候/我们已确认你是真人,你可以继续了/发生错误,请重试",es:"Verifica que eres humano/Verificando.../Eres humano/Error. Inténtalo de nuevo./Verifica que eres humano/Solucionar problemas/Verificación de Cap/Haz clic para verificar que eres humano/Verificando que eres humano, espera/Hemos verificado que eres humano, ya puedes continuar/Se produjo un error, inténtalo de nuevo",hi:"पुष्टि करें कि आप मानव हैं/सत्यापित हो रहा है.../आप मानव हैं/त्रुटि। पुनः प्रयास करें।/कृपया पुष्टि करें कि आप मानव हैं/समस्या निवारण/Cap सत्यापन/पुष्टि करने के लिए क्लिक करें कि आप मानव हैं/सत्यापित किया जा रहा है कि आप मानव हैं, प्रतीक्षा करें/हमने पुष्टि कर दी है कि आप मानव हैं, अब आप जारी रख सकते हैं/एक त्रुटि हुई, पुनः प्रयास करें",ar:"تحقق من أنك إنسان/جارٍ التحقق.../أنت إنسان/خطأ. حاول مرة أخرى./يرجى التحقق من أنك إنسان/استكشاف الأخطاء وإصلاحها/تحقق Cap/انقر للتحقق من أنك إنسان/جارٍ التحقق من أنك إنسان، يرجى الانتظار/لقد تحققنا من أنك إنسان، يمكنك المتابعة الآن/حدث خطأ، يرجى المحاولة مرة أخرى",pt:"Sou humano/Verificando.../Você é humano/Erro. Tente novamente./Verifique que você é humano/Solução de problemas/Verificação Cap/Clique para verificar que você é humano/Verificando que você é humano, aguarde/Verificamos que você é humano, você pode continuar/Ocorreu um erro, tente novamente",ru:"Я человек/Проверка.../Вы человек/Ошибка. Повторите./Подтвердите, что вы человек/Устранение неполадок/Проверка Cap/Нажмите, чтобы подтвердить, что вы человек/Проверяем, что вы человек, подождите/Мы подтвердили, что вы человек, можете продолжить/Произошла ошибка, повторите попытку",ja:"私は人間です/確認中.../あなたは人間です/エラー。再試行を。/あなたが人間であることを確認してください/トラブルシューティング/Cap 認証/クリックして人間であることを確認/あなたが人間であることを確認しています。お待ちください/あなたが人間であることを確認しました。続行できます/エラーが発生しました。もう一度お試しください",de:"Ich bin ein Mensch/Wird überprüft.../Sie sind ein Mensch/Fehler. Erneut versuchen./Bitte bestätigen Sie, dass Sie ein Mensch sind/Fehlerbehebung/Cap-Verifizierung/Klicken, um zu bestätigen, dass Sie ein Mensch sind/Überprüfung, ob Sie ein Mensch sind, bitte warten/Wir haben bestätigt, dass Sie ein Mensch sind, Sie können fortfahren/Ein Fehler ist aufgetreten, bitte erneut versuchen",fr:"Je suis humain/Vérification.../Vous êtes humain/Erreur. Réessayez./Veuillez vérifier que vous êtes humain/Dépannage/Vérification Cap/Cliquez pour vérifier que vous êtes humain/Vérification que vous êtes humain, veuillez patienter/Nous avons vérifié que vous êtes humain, vous pouvez continuer/Une erreur s'est produite, veuillez réessayer"};function h(e,t){let i=function(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return t>>>0}(e),s="";function r(){return i^=i<<13,i^=i>>>17,i^=i<<5,i>>>0}for(;s.length<t;){s+=r().toString(16).padStart(8,"0")}return s.substring(0,t)}let d=null;async function u(e){const t=(e=>{const t=atob(e),i=new Uint8Array(t.length);for(let e=0;e<t.length;e++)i[e]=t.charCodeAt(e);return i})(e),i=(new TextDecoder).decode(await async function(e){if("undefined"!=typeof DecompressionStream)try{const t=new DecompressionStream("deflate-raw"),i=t.writable.getWriter(),s=t.readable.getReader();i.write(e).then(()=>i.close()).catch(()=>{});const r=[];for(;;){const{done:e,value:t}=await s.read();if(e)break;r.push(t)}let n=0;for(const e of r)n+=e.length;const a=new Uint8Array(n);let o=0;for(const e of r)a.set(e,o),o+=e.length;return a}catch{}return d||(d=new Promise((e,t)=>{const i=window.CAP_PAKO_URL||"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";s.debug(r("instr"),"DecompressionStream unavailable, loading pako from",i);const n=document.createElement("script");n.src=i;const a=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;a&&n.setAttribute("nonce",a),n.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("pako loaded but inflateRaw is missing"))},n.onerror=()=>{d=null,t(new Error(`failed to load pako fallback from ${i}`))},document.head.appendChild(n)})),(await d).inflateRaw(e)}(t));return new Promise(e=>{var t=setTimeout(()=>{n(),e({__timeout:!0})},2e4),s=document.createElement("iframe");s.setAttribute("sandbox","allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.cssText="position:absolute;width:1px;height:1px;top:-9999px;left:-9999px;border:none;opacity:0;pointer-events:none;";var r=!1;function n(){r||(r=!0,clearTimeout(t),window.removeEventListener("message",a),s.parentNode&&s.parentNode.removeChild(s))}function a(t){if(s.contentWindow&&t.source===s.contentWindow){var i=t.data;i&&"object"==typeof i&&("cap:instr"===i.type?(n(),i.blocked?e({__blocked:!0,blockReason:i.blockReason||"automated_browser"}):i.result?e(i.result):e({__timeout:!0})):"cap:error"===i.type&&(n(),e({__timeout:!0})))}}window.addEventListener("message",a);const o=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE,l=o?` nonce="${String(o).replace(/"/g,"&quot;")}"`:"";s.srcdoc='<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><script'+l+">"+i+"\n<\/script></body></html>",document.body.appendChild(s)})}let p=null;const g=()=>{if(p)return p;const e=window.CAP_CUSTOM_WASM_URL||"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.7/browser/cap_wasm_bg.wasm",t=performance.now();return s.debug(r("wasm"),"fetching",e),p=fetch(e).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).then(e=>(s.debug(r("wasm"),`ready in ${n(t)}`),e)).catch(e=>{throw p=null,s.warn(r("wasm"),`load failed (${n(t)}):`,e.message||e),e}),p};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&g().catch(()=>{});let v=null;function m(){return v||(v=URL.createObjectURL(new Blob(['(()=>{const e=(e,...t)=>{self.CAP_SILENT||console[e]("[cap worker]",...t)},t=async({salt:t,target:n})=>{let s=0;const r=new TextEncoder,o=4*n.length,a=Math.floor(o/8),l=o%8,i=n.length%2==0?n:`${n}0`,c=i.length/2,f=new Uint8Array(c);for(let e=0;e<c;e++)f[e]=parseInt(i.substring(2*e,2*e+2),16);const g=l>0?255<<8-l&255:0;for(;;)try{for(let e=0;e<5e4;e++){const e=t+s,n=r.encode(e),o=await crypto.subtle.digest("SHA-256",n),i=new Uint8Array(o);let c=!0;for(let e=0;e<a;e++)if(i[e]!==f[e]){c=!1;break}if(c&&l>0&&(i[a]&g)!==(f[a]&g)&&(c=!1),c)return void self.postMessage({nonce:s,found:!0});s++}}catch(t){return e("error","fallback solver crashed:",t.message||t),void self.postMessage({found:!1,error:t.message})}},n=e=>{const t=BigInt("0x"+e.N);let n=BigInt("0x"+e.x);const s=0|e.t,r=Math.max(64,Math.floor(s/50)),o=performance.now();for(let e=0;e<s;e+=r){const o=Math.min(s,e+r);for(let s=e;s<o;s++)n=n*n%t;o<s&&self.postMessage({progress:o/s})}self.postMessage({found:!0,y:n.toString(16),durationMs:(performance.now()-o).toFixed(2)})};if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return e("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)"),void(self.onmessage=async({data:e})=>"rsw"===e?.kind?n(e):t({salt:e.salt,target:e.target}));let s=null;self.onmessage=async({data:r})=>{if("rsw"===r?.kind)return n(r);const{salt:o,target:a,wasmModule:l}=r;if(l instanceof WebAssembly.Module&&null===s){const n=(t=>{try{let e,n=0,r=null;const o=()=>(null!==r&&0!==r.byteLength||(r=new Uint8Array(e.memory.buffer)),r),a=new TextEncoder,l=(e,t,s)=>{if(void 0===s){const s=a.encode(e),r=t(s.length,1)>>>0;return o().subarray(r,r+s.length).set(s),n=s.length,r}let r=e.length,l=t(r,1)>>>0;const i=o();let c=0;for(;c<r;c++){const t=e.charCodeAt(c);if(t>127)break;i[l+c]=t}if(c!==r){0!==c&&(e=e.slice(c));const t=c+3*e.length;l=s(l,r,t,1)>>>0,r=t;const n=o().subarray(l+c,l+r),{written:i}=a.encodeInto(e,n);c+=i,l=s(l,r,c,1)>>>0}return n=c,l},i={wbg:{}};i.wbg.__wbindgen_init_externref_table=()=>{const t=e.__wbindgen_export_0,n=t.grow(4);t.set(0,void 0),t.set(n+0,void 0),t.set(n+1,null),t.set(n+2,!0),t.set(n+3,!1)};const c=new WebAssembly.Instance(t,i);return e=c.exports,e.__wbindgen_start&&e.__wbindgen_start(),s=(t,s)=>{const r=l(t,e.__wbindgen_malloc,e.__wbindgen_realloc),o=n,a=l(s,e.__wbindgen_malloc,e.__wbindgen_realloc),i=n;return BigInt.asUintN(64,e.solve_pow(r,o,a,i))},!0}catch(t){return e("error","wasm init failed:",t.message||t),!1}})(l);if(!n)return e("warn","wasm init failed, falling back to JS solver"),t({salt:o,target:a})}if(null===s)return e("warn","no wasm module provided, falling back to JS solver"),t({salt:o,target:a});try{const e=performance.now(),t=s(o,a),n=performance.now();self.postMessage({nonce:Number(t),found:!0,durationMs:(n-e).toFixed(2)})}catch(t){e("error","solve_pow threw:",t.message||t),self.postMessage({found:!1,error:t.message||String(t)})}},self.onerror=e=>{self.postMessage({found:!1,error:e})}})();'],{type:"application/javascript"})),v)}class b{constructor(e){this._size=e,this._workers=[],this._idle=[],this._queue=[],this._wasmModule=null,this._spawnFailures=0}setWasm(e){this._wasmModule=e}_spawn(){const e=m(),t=new Worker(e);return t._busy=!1,this._workers.push(t),this._idle.push(t),t}_replaceWorker(e){const t=this._workers.indexOf(e);-1!==t&&this._workers.splice(t,1);const i=this._idle.indexOf(e);-1!==i&&this._idle.splice(i,1);try{e.terminate()}catch{}return this._spawnFailures++,s.warn(r("pool"),`worker died, replacing (attempt ${this._spawnFailures}/3)`),this._spawnFailures>3?(s.error(r("pool"),"worker spawn failed repeatedly, giving up"),null):this._spawn()}_ensureSize(e){for(;this._workers.length<e;)this._spawn()}run(e,t){return new Promise((i,s)=>{this._queue.push({salt:e,target:t,resolve:i,reject:s}),this._dispatch()})}runMsg(e,t){return new Promise((i,s)=>{this._queue.push({msg:e,onProgress:t,resolve:i,reject:s}),this._dispatch()})}_dispatch(){for(;this._idle.length>0&&this._queue.length>0;){const e=this._idle.shift(),t=this._queue.shift(),{resolve:i,reject:s}=t,r=void 0!==t.msg;let n=!1;const a=({data:l})=>{if(!n)if(!l||"number"!=typeof l.progress||l.found)n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o),this._spawnFailures=0,this._idle.push(e),l.found?i(r?l:l.nonce):s(new Error(l.error||"worker failed")),this._dispatch();else if(t.onProgress)try{t.onProgress(l.progress)}catch{}},o=t=>{if(n)return;n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o);const i=this._replaceWorker(e);s(t),i&&this._dispatch()};e.addEventListener("message",a),e.addEventListener("error",o),r?e.postMessage(t.msg):this._wasmModule?e.postMessage({salt:t.salt,target:t.target,wasmModule:this._wasmModule},[]):e.postMessage({salt:t.salt,target:t.target})}}terminate(){for(const e of this._workers)try{e.terminate()}catch{}this._workers=[],this._idle=[],this._queue=[]}}class f extends HTMLElement{static formAssociated=!0;#e=null;#t=navigator.hardwareConcurrency||8;token=null;#i;#s;#r;#n;#a;#o;#l=!1;#c;#h;#d=null;#u=null;#p=null;#g=null;#v=null;get#m(){return e&&!window.CAP_DISABLE_HAPTICS&&!this.hasAttribute("data-cap-disable-haptics")}#b(){return{state:"idle",challengeResp:null,challenges:null,results:[],completedCount:0,solvePromise:null,promoteFn:null,_listeners:[],pendingPromotion:null,token:null,tokenExpires:null,notify(){for(const e of this._listeners)e();this._listeners=[]},onSettled(e){"done"===this.state||"error"===this.state?e():this._listeners.push(e)}}}#f(){this.#d=this.#b(),this.#w()}#y(){this.#g&&(window.removeEventListener("mousemove",this.#g),window.removeEventListener("touchstart",this.#g),window.removeEventListener("keydown",this.#g),this.#g=null)}#w(){this.#y();const e=()=>{this.#y(),this.#k()};this.#g=e,window.addEventListener("mousemove",e,{passive:!0}),window.addEventListener("touchstart",e,{passive:!0}),window.addEventListener("keydown",e,{passive:!0})}#x(){return"function"==typeof this.checkVisibility?this.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0}):!!(this.offsetParent||this.getClientRects().length>0)}#_(){this.#x()||s.info(r("challenges"),"solved invisible challenge")}#k(){"idle"===this.#d.state&&this.#x()&&(this.#d.state="waiting",this.#u=setTimeout(()=>{this.#E()},2500))}async#E(){if("waiting"!==this.#d.state)return;this.#d.state="fetching",this.#d._t0=performance.now();let e=this.getAttribute("data-cap-api-endpoint");if(!e&&window?.CAP_CUSTOM_FETCH&&(e="/"),e){e.endsWith("/")||(e+="/");try{const t=await o(`${e}challenge`,{method:"POST"});let i;try{i=await t.json()}catch{throw new Error("Failed to parse speculative challenge response")}if(i.error)throw new Error(i.error);if(i._apiEndpoint=e,this.#d.challengeResp=i,2===i.format&&Array.isArray(i.challenges))return this.#d.state="idle",void this.#d.notify();const{challenge:s,token:r}=i;let n=s;if(!Array.isArray(n)){let e=0;n=Array.from({length:s.c},()=>(e++,[h(`${r}${e}`,s.s),h(`${r}${e}d`,s.d)]))}this.#d.challenges=n,this.#d.state="solving",this.#d.solvePromise=this.#C(n)}catch{this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#C(e){m();let t=null;try{t=await g()}catch{}this.#p||(this.#p=new b(1),this.#p._spawn()),this.#p.setWasm(t);const i=e.length,s=new Array(i);let r=1,n=!1;this.#d.promoteFn=e=>{n||(n=!0,r=e,this.#p._size=e,this.#p._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let a=0;for(;a<i;){const t=r,o=[],l=[];for(let s=0;s<t&&a<i;s++)l.push(a),o.push(e[a]),a++;this.#p._ensureSize(Math.max(r,t));const c=await Promise.all(o.map(e=>this.#p.run(e[0],e[1]).then(e=>(this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!n&&a<i&&await new Promise(e=>setTimeout(e,120))}return this.#d.results=s,this.#d.state="redeeming",this.#A(s),s}async#A(e){try{const t=this.#d.challengeResp,i=t._apiEndpoint;if(!i)throw a("missing_endpoint","speculative redeem: missing apiEndpoint");let s=null;if(t.instrumentation&&(s=await u(t.instrumentation),s?.__timeout||s?.__blocked))return this.#d.state="done",void this.#d.notify();const r=await o(`${i}redeem`,{method:"POST",body:JSON.stringify({token:t.token,solutions:e,...s&&{instr:s}}),headers:{"Content-Type":"application/json"}});let l;try{l=await r.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!l.success)throw new Error(l.error||"Speculative redeem failed");this.#d.token=l.token,this.#d.tokenExpires=new Date(l.expires).getTime(),this.#d.state="done",this.#d._invisibleElapsed=this.#d._t0?n(this.#d._t0):"?",this.#d.notify()}catch{this.#d.state="done",this.#d.notify()}}get#S(){return this.getAttribute("data-cap-hidden-field-name")||"cap-token"}#T(e){const t=this.querySelector(`input[name='${this.#S}']`);t&&(t.value=e)}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||this.#v?.[e]||t}#L(){s.debug(r("solve"),`served from speculative cache (saved ${this.#d._invisibleElapsed||"?"})`),this.dispatchEvent("progress",{progress:100}),this.#T(this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const e=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),e),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),this.#_(),this.#f(),this.#l=!1,{success:!0,token:this.token}}#I(){this.#v=function(e){const t=e?[e]:navigator.languages||[navigator.language||""];for(let e of t){if(!e)continue;if(e=e.toLowerCase(),"en"===e||e.startsWith("en-"))return null;const t=c[e]?e:c[e.split("-")[0]]?e.split("-")[0]:null;if(!t)return null;const i=c[t].split("/"),s={};return l.forEach((e,t)=>{s[e]=i[t]}),s}return null}(window.CAP_LANG||this.getAttribute("data-cap-lang"))}static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","data-cap-worker-count","data-cap-i18n-initial-state","required"]}constructor(){super(),this.#c&&this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this);try{this.#h=this.attachInternals()}catch{}}#P(){this.#h?.setValidity&&(this.hasAttribute("required")&&!this.token?this.#h.setValidity({valueMissing:!0},this.getI18nText("required-label","Please verify you're human"),this.#s||this):this.#h.setValidity({}))}initialize(){m(),this.#d||(this.#d=this.#b()),this.#p||(this.#p=new b(1),this.#p._spawn())}attributeChangedCallback(e,t,i){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),i){const i=t=>{const i=this.getAttribute(e);"function"==typeof window[i]&&window[i].call(this,t)};this.#c.set(e,i),this.addEventListener(t,i)}}"data-cap-worker-count"===e&&this.setWorkersCount(parseInt(i,10)),"data-cap-i18n-initial-state"===e&&this.#s&&this.#s?.querySelector(".label.active")&&this.animateLabel(this.getI18nText("initial-state","Verify you're human")),"required"===e&&this.#P()}async connectedCallback(){this.#o=this,this.shadowRoot?this.#i=this.shadowRoot:this.#i=this.attachShadow({mode:"open"}),this.#s||(this.#s=document.createElement("div")),this.#I(),this.createUI(),this.addEventListeners(),this.initialize(),this.#r.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count"),t=e?parseInt(e,10):null;this.setWorkersCount(t||navigator.hardwareConcurrency||8),this.#o.innerHTML=`<input type="hidden" name="${this.#S}">`,s.debug(r(),`widget ready (workers=${this.#t}, haptics=${this.#m})`),this.#w(),this.#P(),this.addEventListener("invalid",this.#M)}#M=()=>{if(this.#s){try{this.scrollIntoView({behavior:"smooth",block:"center"})}catch{this.scrollIntoView()}this.#s.classList.remove("invalid"),this.#s.offsetWidth,this.#s.classList.add("invalid"),setTimeout(()=>this.#s?.classList.remove("invalid"),1500)}};async solve(){if(this.#l)return;this.#H();const e=performance.now();s.debug(r("solve"),"starting");try{this.#l=!0,this.updateUI("verifying",this.getI18nText("verifying-label","Verifying..."),!0),this.#r.setAttribute("aria-label",this.getI18nText("verifying-aria-label","Verifying you're a human, please wait")),this.dispatchEvent("progress",{progress:0});try{let t,i,l=this.getAttribute("data-cap-api-endpoint");if(!l&&window?.CAP_CUSTOM_FETCH)l="/";else if(!l)throw a("missing_endpoint","Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(l.endsWith("/")||(l+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#L();if("done"===this.#d.state)t=this.#d.results,i=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100});else if("solving"===this.#d.state||"redeeming"===this.#d.state||"fetching"===this.#d.state||"waiting"===this.#d.state){"waiting"===this.#d.state&&(this.#u&&(clearTimeout(this.#u),this.#u=null),this.#d.state="waiting",this.#E()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const e=setInterval(()=>{const t=this.#d.state;if("done"===t||"error"===t)return void clearInterval(e);const i=this.#d.challenges?this.#d.challenges.length:1,s=this.#d.completedCount,r="redeeming"===t?99:"fetching"===t||"waiting"===t?0:Math.min(98,Math.round(s/i*100));this.dispatchEvent("progress",{progress:r})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(e),"idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))i=this.#d.challengeResp,this.#d.challengeResp=null,t=await this.solveChallengesV2(i.challenges);else{if("done"!==this.#d.state)throw a("solve_failed","Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#L();t=this.#d.results,i=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const e=this.#d.challengeResp;if(2===e?.format&&Array.isArray(e.challenges))i=e,this.#d.challengeResp=null;else{const e=await o(`${l}challenge`,{method:"POST"});try{i=await e.json()}catch{throw a("challenge_parse_error","Failed to parse challenge response from server")}if(i.error)throw a("network_error",i.error)}if(2===i.format&&Array.isArray(i.challenges))t=await this.solveChallengesV2(i.challenges);else{const{challenge:e,token:s}=i;let r=e;if(!Array.isArray(r)){let t=0;r=Array.from({length:e.c},()=>(t++,[h(`${s}${t}`,e.s),h(`${s}${t}d`,e.d)]))}t=await this.solveChallenges(r)}}const c=i.instrumentation?u(i.instrumentation):Promise.resolve(null),d=await c;if(d?.__timeout||d?.__blocked){o(`${l}redeem`,{method:"POST",body:JSON.stringify({token:i.token,solutions:t,...d.__blocked&&{instr_blocked:!0},...d.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"}}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),d?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again"));const e=d?.__blocked?"instr_blocked":"instr_timeout",n=d?.__blocked?`Instrumentation blocked (${d.blockReason||"automated_browser"})`:"Instrumentation timed out";this.removeEventListener("error",this.boundHandleError);const a=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,code:e,message:n}});return super.dispatchEvent(a),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",a),s.error(r("instr"),`[${e}] ${n}`),void(this.#l=!1)}const{token:p}=i,g=await o(`${l}redeem`,{method:"POST",body:JSON.stringify({token:p,solutions:t,...d&&{instr:d}}),headers:{"Content-Type":"application/json"}});let v;try{v=await g.json()}catch{throw a("redeem_failed","Failed to parse server response")}if(this.dispatchEvent("progress",{progress:100}),!v.success)throw a("invalid_solution",v.error||"Invalid solution");this.#T(v.token),this.dispatchEvent("solve",{token:v.token}),this.token=v.token,this.#f(),this.#e&&clearTimeout(this.#e);const m=new Date(v.expires).getTime()-Date.now();return m>0&&m<864e5?this.#e=setTimeout(()=>this.reset(),m):this.error("Invalid expiration time","invalid_expires"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),s.debug(r("solve"),`verified in ${n(e)}`),this.#_(),{success:!0,token:this.token}}catch(e){throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message,e.code||"solve_failed"),e}}finally{this.#l=!1}}async solveChallengesV2(e){const t=e.length;let i=0;const n=new Array(e.length);for(let t=0;t<e.length;t++){const i=e[t];if(!i||"object"!=typeof i||"sha256-pow"!==i.protocol&&"rsw"!==i.protocol&&"instrumentation"!==i.protocol)throw a("challenge_unsupported",`unsupported format-2 protocol '${i?.protocol}'`)}let o=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{o=await g()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}const l=Math.max(1,Math.min(this.#t,e.length)),c=new b(l);c.setWasm(o),c._ensureSize(l);const h=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),d=new Array(e.length).fill(0),p=()=>{const e=d.reduce((e,t)=>e+t,0)+i,s=Math.min(99,Math.round(e/t*100));this.dispatchEvent("progress",{progress:s})};try{await Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?h(c.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{n[t]={nonce:Number(e)},d[t]=0,i++,p()}):"rsw"===e.protocol?h(c.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{d[t]=e,p()}),`rsw worker #${t}`).then(e=>{n[t]={y:e.y},d[t]=0,i++,p()}):u(e.payload.blob).then(e=>{n[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},d[t]=0,i++,p()})))}finally{c.terminate()}return n}async solveChallenges(e){const t=e.length;let i=0;let n=null;const a="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(a)try{n=await g()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}if(!a&&(s.warn(r("wasm"),"WebAssembly disabled in this browser, solver will be ~10x slower"),!this.#i.querySelector(".warning"))){const e=document.createElement("div");e.className="warning",e.style.cssText="width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;",e.innerText=this.getI18nText("wasm-disabled","Enable WASM for significantly faster solving"),this.#i.insertBefore(e,this.#i.firstChild),setTimeout(()=>{e.style.marginBottom="calc(-1 * var(--cap-border-radius, 14px))",e.style.opacity=1},10)}const o=new b(this.#t);o.setWasm(n),o._ensureSize(this.#t);const l=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),n=await Promise.all(r.map(([e,s])=>o.run(e,s).then(e=>{i++;const s=Math.min(99,Math.round((0+i)/t*100));return this.dispatchEvent("progress",{progress:s}),e})));l.push(...n)}}finally{o.terminate()}return l}setWorkersCount(e){const t=parseInt(e,10),i=Math.min(navigator.hardwareConcurrency||8,16);this.#t=!Number.isNaN(t)&&t>0&&t<=i?t:navigator.hardwareConcurrency||8}createUI(){this.#s.classList.add("captcha"),this.#s.setAttribute("role","group"),this.#s.setAttribute("aria-label",this.getI18nText("group-aria-label","Cap verification")),this.#r=document.createElement("div"),this.#r.className="captcha-trigger",this.#r.setAttribute("part","trigger"),this.#r.setAttribute("role","button"),this.#r.setAttribute("tabindex","0"),this.#r.setAttribute("aria-label",this.getI18nText("verify-aria-label","Click to verify you're a human")),this.#r.setAttribute("aria-live","polite"),this.#r.setAttribute("disabled","true"),this.#r.innerHTML=`<div class="checkbox" part="checkbox" aria-hidden="true"><svg class="progress-ring" viewBox="0 0 32 32" aria-hidden="true"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText("initial-state","Verify you're human")}</span></p>`,this.#s.appendChild(this.#r),this.#a=document.createElement("a"),this.#a.className="cap-troubleshoot-link",this.#a.setAttribute("part","troubleshoot"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("rel","noopener"),this.#a.hidden=!0,this.#s.appendChild(this.#a),this.#n=document.createElement("a"),this.#n.className="credits",this.#n.setAttribute("aria-label","Secured by Cap"),this.#n.setAttribute("href","https://trycap.dev"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#n.textContent="Cap",this.#s.appendChild(this.#n),this.#i.innerHTML=`<style${window.CAP_CSS_NONCE?` nonce=${window.CAP_CSS_NONCE}`:""}>:host{display:inline-block}@media (prefers-reduced-motion:reduce){.captcha,.captcha *{transition:none!important;animation:none!important}.label{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.label:not(.active),.label.exit{display:none!important}}.captcha,.captcha *{box-sizing:border-box}.captcha{width:var(--cap-widget-width,260px);height:var(--cap-widget-height,58px);background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);-webkit-user-select:none;user-select:none;cursor:pointer;-webkit-tap-highlight-color:#fff0;color:var(--cap-color,#212121);font-family:var(--cap-font,system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif);transition:filter .2s,transform .2s,height .2s;display:inline-block;position:relative;overflow:hidden}.captcha.has-troubleshoot{height:calc(var(--cap-widget-height,58px) + 26px)}.captcha.has-troubleshoot .captcha-trigger{inset-block-end:26px}.captcha:not([data-state]):active{transform:scale(.97)}.captcha:hover{filter:brightness(98%)}.captcha-trigger{padding:var(--cap-widget-padding,14px);align-items:center;gap:var(--cap-gap,15px);border-radius:inherit;transition:inset .2s;display:flex;position:absolute;inset:0}.captcha-trigger:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:-3px}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px);flex-shrink:0;transition:opacity .2s}.captcha p{-webkit-user-select:none;user-select:none;margin:0;font-size:15px;font-weight:500}.label-wrapper{flex:1;align-items:center;min-width:0;height:2em;display:flex;position:relative;overflow:hidden}.label-wrapper:before,.label-wrapper:after{content:"";pointer-events:none;z-index:1;width:100%;height:.6em;position:absolute;inset-inline-start:0}.label-wrapper:before{background:linear-gradient(to bottom, var(--cap-background,#fdfdfd), transparent);top:0}.label-wrapper:after{background:linear-gradient(to top, var(--cap-background,#fdfdfd), transparent);bottom:0}.label{white-space:nowrap;opacity:0;filter:blur(2px);transition:transform .5s cubic-bezier(.25,1,.5,1),opacity .5s,filter .5s;position:absolute;transform:translateY(100%)}.label.active{opacity:1;filter:none;transform:translateY(0)}.label.exit{opacity:0;filter:blur(2px);transform:translateY(-100%)}.checkbox .progress-ring{width:100%;height:100%;display:none;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96px;transition:stroke-dashoffset .3s}.captcha[data-state=verifying] .checkbox{background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;display:flex;transform:scale(1.1)}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{background-image:var(--cap-checkmark,url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E));background-size:cover;border:1px solid #0000}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E"));background-size:cover;border:1px solid #0000}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha.invalid{border-color:var(--cap-invalid-border-color,#f55b50);box-shadow:0 0 0 3px var(--cap-invalid-ring-color,#f55b5033);animation:.5s cubic-bezier(.36,.07,.19,.97) cap-shake}@keyframes cap-shake{10%,90%{transform:translate(-1px)}20%,80%{transform:translate(2px)}30%,50%,70%{transform:translate(-4px)}40%,60%{transform:translate(4px)}}@media (prefers-reduced-motion:reduce){.captcha.invalid{animation:none!important}}.captcha-trigger[disabled]{cursor:not-allowed}.captcha[data-state=verifying] .captcha-trigger{cursor:progress}.captcha[data-state=done] .captcha-trigger{cursor:default}.credits{color:var(--cap-color,#212121);text-underline-offset:.18em;z-index:2;border-radius:4px;justify-content:flex-end;align-items:center;min-width:24px;min-height:24px;padding:4px 6px;text-decoration:underline;text-decoration-thickness:.08em;position:absolute;inset-block-end:4px;inset-inline-end:4px;opacity:.8!important;font-size:12px!important;display:inline-flex!important}.captcha .credits{visibility:visible!important;pointer-events:all!important;display:inline-flex!important}.credits:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px;opacity:1!important}.cap-troubleshoot-link{min-width:24px;min-height:24px;color:var(--cap-troubleshoot-color,#0050a0);text-underline-offset:.15em;cursor:pointer;z-index:2;border-radius:4px;align-items:center;padding:4px 6px;font-size:13px;font-weight:500;text-decoration:underline;text-decoration-thickness:.08em;display:inline-flex;position:absolute;inset-block-end:4px;inset-inline-start:14px}.cap-troubleshoot-link[hidden]{display:none}.cap-troubleshoot-link:hover{opacity:.85}.cap-troubleshoot-link:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px}@media (forced-colors:active){.captcha,.checkbox{border-color:canvastext}:is(.captcha-trigger:focus-visible,.credits:focus-visible,.cap-troubleshoot-link:focus-visible){outline-color:highlight}.progress-ring-bg{stroke:graytext}.progress-ring-circle{stroke:canvastext}.captcha.invalid{box-shadow:none;border-color:mark}.credits{opacity:1!important}}</style>`,this.#i.appendChild(this.#s),this.#H(),setTimeout(()=>this.#H(),100)}addEventListeners(){this.#r&&(this.#n.addEventListener("click",e=>{e.preventDefault(),window.open(`https://trycap.dev/?${new URLSearchParams({utm_source:"cap_widget",utm_medium:"referral",utm_campaign:"widget",utm_content:window.CAP_DISABLE_WIDGET_REF?"":location.hostname,ref:window.CAP_DISABLE_WIDGET_REF?"":location.href||"",sub:window.CAP_DISABLE_WIDGET_REF?"":document.referrer||""}).toString()}`,"_blank")}),this.#r.addEventListener("click",()=>{this.#r.hasAttribute("disabled")||this.solve()}),this.#r.addEventListener("mousedown",()=>{!this.#r.hasAttribute("disabled")&&this.#m&&navigator.vibrate(5)}),this.#r.addEventListener("keydown",e=>{e.target===this.#r&&("Enter"!==e.key&&" "!==e.key||this.#r.hasAttribute("disabled")||(e.preventDefault(),e.stopPropagation(),this.solve()))}),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset))}#$(){if(!this.#o)return!1;const e=this.#o.getBoundingClientRect();if(0===e.width&&0===e.height)return!0;const t=window.getComputedStyle(this.#o);return"none"===t.display||"hidden"===t.visibility}#H(){this.#n&&this.#s&&!this.#$()&&(this.#n.isConnected&&this.#n.parentNode===this.#s||this.#s.appendChild(this.#n),this.#n.textContent&&this.#n.textContent.trim()||(this.#n.textContent="Cap"),"https://trycap.dev"!==this.#n.getAttribute("href")&&this.#n.setAttribute("href","https://trycap.dev"),this.#n.style.cssText=["display: inline-flex !important","visibility: visible !important","opacity: 0.8 !important","pointer-events: all !important","font-size: 12px !important","transform: none !important","clip-path: none !important","filter: none !important","position: absolute !important"].join("; "))}animateLabel(e){if(!this.#r)return;const t=this.#r.querySelector(".label-wrapper");if(!t)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){const i=t.querySelector(".label.active");if(i)i.textContent=e;else{const i=document.createElement("span");i.className="label active",i.textContent=e,t.appendChild(i)}return}const i=t.querySelector(".label.active"),s=document.createElement("span");s.className="label",s.textContent=e,t.appendChild(s),s.offsetWidth,s.classList.add("active"),i&&(i.classList.remove("active"),i.classList.add("exit"),i.addEventListener("transitionend",()=>i.remove(),{once:!0}))}updateUI(e,t,i=!1){this.#s&&this.#r&&(this.#s.setAttribute("data-state",e),this.#s.classList.remove("has-troubleshoot"),this.animateLabel(t),this.#a&&(this.#a.hidden=!0),i?this.#r.setAttribute("disabled","true"):this.#r.removeAttribute("disabled"))}updateUIBlocked(e,t=!1){if(this.#s&&this.#r&&(this.#s.setAttribute("data-state","error"),this.#r.removeAttribute("disabled"),this.animateLabel(e),this.#a))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#a.setAttribute("href",e),this.#a.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#a.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#a.hidden=!0,this.#s.classList.remove("has-troubleshoot")}handleProgress(e){if(!this.#r)return;const t=this.#r.querySelector(".progress-ring-circle");if(t){const i=2*Math.PI*14,s=i-e.detail.progress/100*i;t.style.strokeDashoffset=s}const i=this.#r.querySelector(".label-wrapper");if(i){const e=i.querySelector(".label.active");e&&(e.textContent=`${this.getI18nText("verifying-label","Verifying...")}`)}this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done",this.getI18nText("solved-label","You're a human"),!0),this.executeAttributeCode("onsolve",e),this.#h?.setValidity?.({}),this.#s?.classList.remove("invalid")}handleError(e){this.updateUI("error",this.getI18nText("error-label","Error. Try again.")),this.executeAttributeCode("onerror",e),this.#m&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#P()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(s.warn(r(),"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error",t="unknown"){s.error(r("solve"),`[${t}] ${e}`),this.dispatchEvent("error",{isCap:!0,code:t,message:e})}dispatchEvent(e,t={}){const i=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(i)}reset(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.token=null,this.dispatchEvent("reset"),this.#T("")}get tokenValue(){return this.token}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#y(),this.#u&&(clearTimeout(this.#u),this.#u=null),this.#p&&(this.#p.terminate(),this.#p=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class w{constructor(e={},t){const i=t||document.createElement("cap-widget");if(Object.entries(e).forEach(([e,t])=>{i.setAttribute(e,t)}),!e.apiEndpoint&&!window?.CAP_CUSTOM_FETCH)throw i.remove(),new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");e.apiEndpoint&&i.setAttribute("data-cap-api-endpoint",e.apiEndpoint),t||i.hasAttribute("data-cap-disable-haptics")||i.setAttribute("data-cap-disable-haptics",""),this.widget=i,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>i.token,configurable:!0,enumerable:!0}),t||(i.style.display="none",document.documentElement.appendChild(i))}}window.Cap=w,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&s.warn(r(),"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override"):customElements.define("cap-widget",f),"object"==typeof exports&&"undefined"!=typeof module?module.exports=w:"function"==typeof define&&define.amd&&define([],()=>w),"undefined"!=typeof exports&&(exports.default=w)})();
1
+ (()=>{const e="vibrate"in navigator&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches;if("undefined"==typeof window)return;const t=["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"],i=(e,i,s)=>{const r=0===i?"9999px":"0",n=i===s-1?"9999px":"0";return`color:#1e1e2e;background:${(e=>{if("cap"===e)return"#89b4fa";let i=0;for(let t=0;t<e.length;t++)i=e.charCodeAt(t)+((i<<5)-i);return t[Math.abs(i)%t.length]})(e)};margin-left:${i?"-6px":0};padding:0 6px;border-radius:${r} ${n} ${n} ${r};font-weight:600`},s={};for(const e of["debug","info","warn","error"])s[e]=(t,...s)=>{if(window.CAP_SILENT||"debug"===e&&!window.CAP_DEBUG)return;const r=t.map(e=>`%c${e}`).join(" "),n=t.map((e,s)=>i(e,s,t.length));console["debug"===e?"log":e](r,...n,...s)};const r=e=>e?["cap",e]:["cap"],n=e=>`${Math.round(performance.now()-e)}ms`,a=(e,t)=>Object.assign(new Error(t),{code:e}),o=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t),l=(e,t)=>t?t.aborted?Promise.reject(a("aborted","aborted")):Promise.race([e,new Promise((e,i)=>t.addEventListener("abort",()=>i(a("aborted","aborted")),{once:!0}))]):e,c="initial-state,verifying-label,solved-label,error-label,required-label,troubleshooting-label,group-aria-label,verify-aria-label,verifying-aria-label,verified-aria-label,error-aria-label".split(","),h={"zh-cn":"确认你是真人/正在验证.../你是真人/出错了。请重试。/请确认你是真人/故障排除/Cap 验证/点击以确认你是真人/正在验证你是真人,请稍候/我们已确认你是真人,你可以继续了/发生错误,请重试",es:"Verifica que eres humano/Verificando.../Eres humano/Error. Inténtalo de nuevo./Verifica que eres humano/Solucionar problemas/Verificación de Cap/Haz clic para verificar que eres humano/Verificando que eres humano, espera/Hemos verificado que eres humano, ya puedes continuar/Se produjo un error, inténtalo de nuevo",hi:"पुष्टि करें कि आप मानव हैं/सत्यापित हो रहा है.../आप मानव हैं/त्रुटि। पुनः प्रयास करें।/कृपया पुष्टि करें कि आप मानव हैं/समस्या निवारण/Cap सत्यापन/पुष्टि करने के लिए क्लिक करें कि आप मानव हैं/सत्यापित किया जा रहा है कि आप मानव हैं, प्रतीक्षा करें/हमने पुष्टि कर दी है कि आप मानव हैं, अब आप जारी रख सकते हैं/एक त्रुटि हुई, पुनः प्रयास करें",ar:"تحقق من أنك إنسان/جارٍ التحقق.../أنت إنسان/خطأ. حاول مرة أخرى./يرجى التحقق من أنك إنسان/استكشاف الأخطاء وإصلاحها/تحقق Cap/انقر للتحقق من أنك إنسان/جارٍ التحقق من أنك إنسان، يرجى الانتظار/لقد تحققنا من أنك إنسان، يمكنك المتابعة الآن/حدث خطأ، يرجى المحاولة مرة أخرى",pt:"Sou humano/Verificando.../Você é humano/Erro. Tente novamente./Verifique que você é humano/Solução de problemas/Verificação Cap/Clique para verificar que você é humano/Verificando que você é humano, aguarde/Verificamos que você é humano, você pode continuar/Ocorreu um erro, tente novamente",ru:"Я человек/Проверка.../Вы человек/Ошибка. Повторите./Подтвердите, что вы человек/Устранение неполадок/Проверка Cap/Нажмите, чтобы подтвердить, что вы человек/Проверяем, что вы человек, подождите/Мы подтвердили, что вы человек, можете продолжить/Произошла ошибка, повторите попытку",ja:"私は人間です/確認中.../あなたは人間です/エラー。再試行を。/あなたが人間であることを確認してください/トラブルシューティング/Cap 認証/クリックして人間であることを確認/あなたが人間であることを確認しています。お待ちください/あなたが人間であることを確認しました。続行できます/エラーが発生しました。もう一度お試しください",de:"Ich bin ein Mensch/Wird überprüft.../Sie sind ein Mensch/Fehler. Erneut versuchen./Bitte bestätigen Sie, dass Sie ein Mensch sind/Fehlerbehebung/Cap-Verifizierung/Klicken, um zu bestätigen, dass Sie ein Mensch sind/Überprüfung, ob Sie ein Mensch sind, bitte warten/Wir haben bestätigt, dass Sie ein Mensch sind, Sie können fortfahren/Ein Fehler ist aufgetreten, bitte erneut versuchen",fr:"Je suis humain/Vérification.../Vous êtes humain/Erreur. Réessayez./Veuillez vérifier que vous êtes humain/Dépannage/Vérification Cap/Cliquez pour vérifier que vous êtes humain/Vérification que vous êtes humain, veuillez patienter/Nous avons vérifié que vous êtes humain, vous pouvez continuer/Une erreur s'est produite, veuillez réessayer"};function d(e,t){let i=function(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return t>>>0}(e),s="";function r(){return i^=i<<13,i^=i>>>17,i^=i<<5,i>>>0}for(;s.length<t;){s+=r().toString(16).padStart(8,"0")}return s.substring(0,t)}let u=null;async function p(e){const t=(e=>{const t=atob(e),i=new Uint8Array(t.length);for(let e=0;e<t.length;e++)i[e]=t.charCodeAt(e);return i})(e),i=(new TextDecoder).decode(await async function(e){if("undefined"!=typeof DecompressionStream)try{const t=new DecompressionStream("deflate-raw"),i=t.writable.getWriter(),s=t.readable.getReader();i.write(e).then(()=>i.close()).catch(()=>{});const r=[];for(;;){const{done:e,value:t}=await s.read();if(e)break;r.push(t)}let n=0;for(const e of r)n+=e.length;const a=new Uint8Array(n);let o=0;for(const e of r)a.set(e,o),o+=e.length;return a}catch{}return u||(u=new Promise((e,t)=>{const i=window.CAP_PAKO_URL||"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";s.debug(r("instr"),"DecompressionStream unavailable, loading pako from",i);const n=document.createElement("script");n.src=i;const a=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;a&&n.setAttribute("nonce",a),n.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("pako loaded but inflateRaw is missing"))},n.onerror=()=>{u=null,t(new Error(`failed to load pako fallback from ${i}`))},document.head.appendChild(n)})),(await u).inflateRaw(e)}(t));return new Promise(e=>{var t=setTimeout(()=>{n(),e({__timeout:!0})},2e4),s=document.createElement("iframe");s.setAttribute("sandbox","allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.cssText="position:absolute;width:1px;height:1px;top:-9999px;left:-9999px;border:none;opacity:0;pointer-events:none;";var r=!1;function n(){r||(r=!0,clearTimeout(t),window.removeEventListener("message",a),s.parentNode&&s.parentNode.removeChild(s))}function a(t){if(s.contentWindow&&t.source===s.contentWindow){var i=t.data;i&&"object"==typeof i&&("cap:instr"===i.type?(n(),i.blocked?e({__blocked:!0,blockReason:i.blockReason||"automated_browser"}):i.result?e(i.result):e({__timeout:!0})):"cap:error"===i.type&&(n(),e({__timeout:!0})))}}window.addEventListener("message",a);const o=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE,l=o?` nonce="${String(o).replace(/"/g,"&quot;")}"`:"";s.srcdoc='<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><script'+l+">"+i+"\n<\/script></body></html>",document.body.appendChild(s)})}let g=null;const v=()=>{if(g)return g;const e=window.CAP_CUSTOM_WASM_URL||"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.7/browser/cap_wasm_bg.wasm",t=performance.now();return s.debug(r("wasm"),"fetching",e),g=fetch(e).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).then(e=>(s.debug(r("wasm"),`ready in ${n(t)}`),e)).catch(e=>{throw g=null,s.warn(r("wasm"),`load failed (${n(t)}):`,e.message||e),e}),g};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&v().catch(()=>{});let b=null;function m(){return b||(b=URL.createObjectURL(new Blob(['(()=>{const e=(e,...t)=>{self.CAP_SILENT||console[e]("[cap worker]",...t)},t=async({salt:t,target:n})=>{let s=0;const r=new TextEncoder,o=4*n.length,a=Math.floor(o/8),l=o%8,i=n.length%2==0?n:`${n}0`,c=i.length/2,f=new Uint8Array(c);for(let e=0;e<c;e++)f[e]=parseInt(i.substring(2*e,2*e+2),16);const g=l>0?255<<8-l&255:0;for(;;)try{for(let e=0;e<5e4;e++){const e=t+s,n=r.encode(e),o=await crypto.subtle.digest("SHA-256",n),i=new Uint8Array(o);let c=!0;for(let e=0;e<a;e++)if(i[e]!==f[e]){c=!1;break}if(c&&l>0&&(i[a]&g)!==(f[a]&g)&&(c=!1),c)return void self.postMessage({nonce:s,found:!0});s++}}catch(t){return e("error","fallback solver crashed:",t.message||t),void self.postMessage({found:!1,error:t.message})}},n=e=>{const t=BigInt("0x"+e.N);let n=BigInt("0x"+e.x);const s=0|e.t,r=Math.max(64,Math.floor(s/50)),o=performance.now();for(let e=0;e<s;e+=r){const o=Math.min(s,e+r);for(let s=e;s<o;s++)n=n*n%t;o<s&&self.postMessage({progress:o/s})}self.postMessage({found:!0,y:n.toString(16),durationMs:(performance.now()-o).toFixed(2)})};if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return e("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)"),void(self.onmessage=async({data:e})=>"rsw"===e?.kind?n(e):t({salt:e.salt,target:e.target}));let s=null;self.onmessage=async({data:r})=>{if("rsw"===r?.kind)return n(r);const{salt:o,target:a,wasmModule:l}=r;if(l instanceof WebAssembly.Module&&null===s){const n=(t=>{try{let e,n=0,r=null;const o=()=>(null!==r&&0!==r.byteLength||(r=new Uint8Array(e.memory.buffer)),r),a=new TextEncoder,l=(e,t,s)=>{if(void 0===s){const s=a.encode(e),r=t(s.length,1)>>>0;return o().subarray(r,r+s.length).set(s),n=s.length,r}let r=e.length,l=t(r,1)>>>0;const i=o();let c=0;for(;c<r;c++){const t=e.charCodeAt(c);if(t>127)break;i[l+c]=t}if(c!==r){0!==c&&(e=e.slice(c));const t=c+3*e.length;l=s(l,r,t,1)>>>0,r=t;const n=o().subarray(l+c,l+r),{written:i}=a.encodeInto(e,n);c+=i,l=s(l,r,c,1)>>>0}return n=c,l},i={wbg:{}};i.wbg.__wbindgen_init_externref_table=()=>{const t=e.__wbindgen_export_0,n=t.grow(4);t.set(0,void 0),t.set(n+0,void 0),t.set(n+1,null),t.set(n+2,!0),t.set(n+3,!1)};const c=new WebAssembly.Instance(t,i);return e=c.exports,e.__wbindgen_start&&e.__wbindgen_start(),s=(t,s)=>{const r=l(t,e.__wbindgen_malloc,e.__wbindgen_realloc),o=n,a=l(s,e.__wbindgen_malloc,e.__wbindgen_realloc),i=n;return BigInt.asUintN(64,e.solve_pow(r,o,a,i))},!0}catch(t){return e("error","wasm init failed:",t.message||t),!1}})(l);if(!n)return e("warn","wasm init failed, falling back to JS solver"),t({salt:o,target:a})}if(null===s)return e("warn","no wasm module provided, falling back to JS solver"),t({salt:o,target:a});try{const e=performance.now(),t=s(o,a),n=performance.now();self.postMessage({nonce:Number(t),found:!0,durationMs:(n-e).toFixed(2)})}catch(t){e("error","solve_pow threw:",t.message||t),self.postMessage({found:!1,error:t.message||String(t)})}},self.onerror=e=>{self.postMessage({found:!1,error:e})}})();'],{type:"application/javascript"})),b)}class f{constructor(e){this._size=e,this._workers=[],this._idle=[],this._queue=[],this._wasmModule=null,this._spawnFailures=0}setWasm(e){this._wasmModule=e}_spawn(){const e=m(),t=new Worker(e);return t._busy=!1,this._workers.push(t),this._idle.push(t),t}_replaceWorker(e){const t=this._workers.indexOf(e);-1!==t&&this._workers.splice(t,1);const i=this._idle.indexOf(e);-1!==i&&this._idle.splice(i,1);try{e.terminate()}catch{}return this._spawnFailures++,s.warn(r("pool"),`worker died, replacing (attempt ${this._spawnFailures}/3)`),this._spawnFailures>3?(s.error(r("pool"),"worker spawn failed repeatedly, giving up"),null):this._spawn()}_ensureSize(e){for(;this._workers.length<e;)this._spawn()}run(e,t){return new Promise((i,s)=>{this._queue.push({salt:e,target:t,resolve:i,reject:s}),this._dispatch()})}runMsg(e,t){return new Promise((i,s)=>{this._queue.push({msg:e,onProgress:t,resolve:i,reject:s}),this._dispatch()})}_dispatch(){for(;this._idle.length>0&&this._queue.length>0;){const e=this._idle.shift(),t=this._queue.shift(),{resolve:i,reject:s}=t,r=void 0!==t.msg;let n=!1;const a=({data:l})=>{if(!n)if(!l||"number"!=typeof l.progress||l.found)n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o),this._spawnFailures=0,this._idle.push(e),l.found?i(r?l:l.nonce):s(new Error(l.error||"worker failed")),this._dispatch();else if(t.onProgress)try{t.onProgress(l.progress)}catch{}},o=t=>{if(n)return;n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o);const i=this._replaceWorker(e);s(t),i&&this._dispatch()};e.addEventListener("message",a),e.addEventListener("error",o),r?e.postMessage(t.msg):this._wasmModule?e.postMessage({salt:t.salt,target:t.target,wasmModule:this._wasmModule},[]):e.postMessage({salt:t.salt,target:t.target})}}terminate(){for(const e of this._workers)try{e.terminate()}catch{}this._workers=[],this._idle=[],this._queue=[]}}class w extends HTMLElement{static formAssociated=!0;#e=null;#t=navigator.hardwareConcurrency||8;token=null;#i;#s;#r;#n;#a;#o;#l=!1;#c;#h;#d=null;#u=null;#p=null;#g=null;#v=null;#b=null;get#m(){return e&&!window.CAP_DISABLE_HAPTICS&&!this.hasAttribute("data-cap-disable-haptics")}#f(){return{state:"idle",challengeResp:null,challenges:null,results:[],completedCount:0,solvePromise:null,promoteFn:null,_listeners:[],pendingPromotion:null,token:null,tokenExpires:null,notify(){for(const e of this._listeners)e();this._listeners=[]},onSettled(e){"done"===this.state||"error"===this.state?e():this._listeners.push(e)}}}#w(){this.#d=this.#f(),this.#y()}#k(){this.#g&&(window.removeEventListener("mousemove",this.#g),window.removeEventListener("touchstart",this.#g),window.removeEventListener("keydown",this.#g),this.#g=null)}#y(){this.#k();const e=()=>{this.#k(),this.#x()};this.#g=e,window.addEventListener("mousemove",e,{passive:!0}),window.addEventListener("touchstart",e,{passive:!0}),window.addEventListener("keydown",e,{passive:!0})}#_(){return"function"==typeof this.checkVisibility?this.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0}):!!(this.offsetParent||this.getClientRects().length>0)}#E(){this.#_()||s.info(r("challenges"),"solved invisible challenge")}#x(){"idle"===this.#d.state&&this.#_()&&(this.#d.state="waiting",this.#u=setTimeout(()=>{this.#C()},2500))}async#C(){if("waiting"!==this.#d.state)return;this.#d.state="fetching",this.#d._t0=performance.now();let e=this.getAttribute("data-cap-api-endpoint");if(!e&&window?.CAP_CUSTOM_FETCH&&(e="/"),e){e.endsWith("/")||(e+="/");try{const t=await o(`${e}challenge`,{method:"POST",signal:this.#b?.signal});let i;try{i=await t.json()}catch{throw new Error("Failed to parse speculative challenge response")}if(i.error)throw new Error(i.error);if(!this.#d)return;if(i._apiEndpoint=e,this.#d.challengeResp=i,2===i.format&&Array.isArray(i.challenges))return this.#d.state="idle",void this.#d.notify();const{challenge:s,token:r}=i;let n=s;if(!Array.isArray(n)){let e=0;n=Array.from({length:s.c},()=>(e++,[d(`${r}${e}`,s.s),d(`${r}${e}d`,s.d)]))}this.#d.challenges=n,this.#d.state="solving",this.#d.solvePromise=this.#A(n)}catch{if(!this.#d)return;this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#A(e){m();let t=null;try{t=await v()}catch{}this.#p||(this.#p=new f(1),this.#p._spawn()),this.#p.setWasm(t);const i=e.length,s=new Array(i);let r=1,n=!1;this.#d.promoteFn=e=>{n||(n=!0,r=e,this.#p._size=e,this.#p._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let a=0;for(;a<i;){const t=r,o=[],l=[];for(let s=0;s<t&&a<i;s++)l.push(a),o.push(e[a]),a++;this.#p._ensureSize(Math.max(r,t));const c=await Promise.all(o.map(e=>this.#p.run(e[0],e[1]).then(e=>(this.#d&&this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!n&&a<i&&await new Promise(e=>setTimeout(e,120))}return this.#d?(this.#d.results=s,this.#d.state="redeeming",this.#S(s),s):s}async#S(e){try{if(!this.#d)return;const t=this.#d.challengeResp,i=t._apiEndpoint;if(!i)throw a("missing_endpoint","speculative redeem: missing apiEndpoint");let s=null;if(t.instrumentation){if(s=await p(t.instrumentation),!this.#d)return;if(s?.__timeout||s?.__blocked)return this.#d.state="done",void this.#d.notify()}const r=await o(`${i}redeem`,{method:"POST",body:JSON.stringify({token:t.token,solutions:e,...s&&{instr:s}}),headers:{"Content-Type":"application/json"},signal:this.#b?.signal});let l;try{l=await r.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!this.#d)return;if(!l.success)throw new Error(l.error||"Speculative redeem failed");this.#d.token=l.token,this.#d.tokenExpires=new Date(l.expires).getTime(),this.#d.state="done",this.#d._invisibleElapsed=this.#d._t0?n(this.#d._t0):"?",this.#d.notify()}catch{if(!this.#d)return;this.#d.state="done",this.#d.notify()}}get#T(){return this.getAttribute("data-cap-hidden-field-name")||"cap-token"}#L(e){const t=this.querySelector(`input[name='${this.#T}']`);t&&(t.value=e)}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||this.#v?.[e]||t}#I(){s.debug(r("solve"),`served from speculative cache (saved ${this.#d._invisibleElapsed||"?"})`),this.dispatchEvent("progress",{progress:100}),this.#L(this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const e=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),e),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),this.#E(),this.#w(),this.#l=!1,{success:!0,token:this.token}}#P(){this.#v=function(e){const t=e?[e]:navigator.languages||[navigator.language||""];for(let e of t){if(!e)continue;if(e=e.toLowerCase(),"en"===e||e.startsWith("en-"))return null;const t=h[e]?e:h[e.split("-")[0]]?e.split("-")[0]:null;if(!t)return null;const i=h[t].split("/"),s={};return c.forEach((e,t)=>{s[e]=i[t]}),s}return null}(window.CAP_LANG||this.getAttribute("data-cap-lang"))}static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","data-cap-worker-count","data-cap-i18n-initial-state","required"]}constructor(){super(),this.#c&&this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this);try{this.#h=this.attachInternals()}catch{}}#M(){this.#h?.setValidity&&(this.hasAttribute("required")&&!this.token?this.#h.setValidity({valueMissing:!0},this.getI18nText("required-label","Please verify you're human"),this.#s||this):this.#h.setValidity({}))}initialize(){m(),this.#b=new AbortController,this.#d||(this.#d=this.#f()),this.#p||(this.#p=new f(1),this.#p._spawn())}attributeChangedCallback(e,t,i){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),i){const i=t=>{const i=this.getAttribute(e);"function"==typeof window[i]&&window[i].call(this,t)};this.#c.set(e,i),this.addEventListener(t,i)}}"data-cap-worker-count"===e&&this.setWorkersCount(parseInt(i,10)),"data-cap-i18n-initial-state"===e&&this.#s&&this.#s?.querySelector(".label.active")&&this.animateLabel(this.getI18nText("initial-state","Verify you're human")),"required"===e&&this.#M()}async connectedCallback(){this.#o=this,this.shadowRoot?this.#i=this.shadowRoot:this.#i=this.attachShadow({mode:"open"}),this.#s||(this.#s=document.createElement("div")),this.#P(),this.createUI(),this.addEventListeners(),this.initialize(),this.#r.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count"),t=e?parseInt(e,10):null;this.setWorkersCount(t||navigator.hardwareConcurrency||8),this.#o.innerHTML=`<input type="hidden" name="${this.#T}">`,s.debug(r(),`widget ready (workers=${this.#t}, haptics=${this.#m})`),this.#y(),this.#M(),this.addEventListener("invalid",this.#H)}#H=()=>{if(this.#s){try{this.scrollIntoView({behavior:"smooth",block:"center"})}catch{this.scrollIntoView()}this.#s.classList.remove("invalid"),this.#s.offsetWidth,this.#s.classList.add("invalid"),setTimeout(()=>this.#s?.classList.remove("invalid"),1500)}};async solve(){if(this.#l)return;this.#$();const e=performance.now(),t=this.#b?.signal;s.debug(r("solve"),"starting");try{this.#l=!0,this.updateUI("verifying",this.getI18nText("verifying-label","Verifying..."),!0),this.#r.setAttribute("aria-label",this.getI18nText("verifying-aria-label","Verifying you're a human, please wait")),this.dispatchEvent("progress",{progress:0});try{let i,l,c=this.getAttribute("data-cap-api-endpoint");if(!c&&window?.CAP_CUSTOM_FETCH)c="/";else if(!c)throw a("missing_endpoint","Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(c.endsWith("/")||(c+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#I();if("done"===this.#d.state)i=this.#d.results,l=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100});else if("solving"===this.#d.state||"redeeming"===this.#d.state||"fetching"===this.#d.state||"waiting"===this.#d.state){"waiting"===this.#d.state&&(this.#u&&(clearTimeout(this.#u),this.#u=null),this.#d.state="waiting",this.#C()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const e=setInterval(()=>{if(t?.aborted||!this.#d)return void clearInterval(e);const i=this.#d.state;if("done"===i||"error"===i)return void clearInterval(e);const s=this.#d.challenges?this.#d.challenges.length:1,r=this.#d.completedCount,n="redeeming"===i?99:"fetching"===i||"waiting"===i?0:Math.min(98,Math.round(r/s*100));this.dispatchEvent("progress",{progress:n})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(e),t?.aborted||!this.#d)return;if("idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))l=this.#d.challengeResp,this.#d.challengeResp=null,i=await this.solveChallengesV2(l.challenges,t);else{if("done"!==this.#d.state)throw a("solve_failed","Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#I();i=this.#d.results,l=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const e=this.#d.challengeResp;if(2===e?.format&&Array.isArray(e.challenges))l=e,this.#d.challengeResp=null;else{const e=await o(`${c}challenge`,{method:"POST",signal:t});try{l=await e.json()}catch{throw a("challenge_parse_error","Failed to parse challenge response from server")}if(l.error)throw a("network_error",l.error)}if(2===l.format&&Array.isArray(l.challenges))i=await this.solveChallengesV2(l.challenges,t);else{const{challenge:e,token:s}=l;let r=e;if(!Array.isArray(r)){let t=0;r=Array.from({length:e.c},()=>(t++,[d(`${s}${t}`,e.s),d(`${s}${t}d`,e.d)]))}i=await this.solveChallenges(r,t)}}const h=l.instrumentation?p(l.instrumentation):Promise.resolve(null),u=await h;if(t?.aborted||!this.#d)return;if(u?.__timeout||u?.__blocked){o(`${c}redeem`,{method:"POST",body:JSON.stringify({token:l.token,solutions:i,...u.__blocked&&{instr_blocked:!0},...u.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"},signal:t}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),u?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again"));const e=u?.__blocked?"instr_blocked":"instr_timeout",n=u?.__blocked?`Instrumentation blocked (${u.blockReason||"automated_browser"})`:"Instrumentation timed out";this.removeEventListener("error",this.boundHandleError);const a=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,code:e,message:n}});return super.dispatchEvent(a),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",a),s.error(r("instr"),`[${e}] ${n}`),void(this.#l=!1)}const{token:g}=l,v=await o(`${c}redeem`,{method:"POST",body:JSON.stringify({token:g,solutions:i,...u&&{instr:u}}),headers:{"Content-Type":"application/json"},signal:t});let b;try{b=await v.json()}catch{throw a("redeem_failed","Failed to parse server response")}if(t?.aborted||!this.#d)return;if(this.dispatchEvent("progress",{progress:100}),!b.success)throw a("invalid_solution",b.error||"Invalid solution");this.#L(b.token),this.dispatchEvent("solve",{token:b.token}),this.token=b.token,this.#w(),this.#e&&clearTimeout(this.#e);const m=new Date(b.expires).getTime()-Date.now();return m>0&&m<864e5?this.#e=setTimeout(()=>this.reset(),m):this.error("Invalid expiration time","invalid_expires"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),s.debug(r("solve"),`verified in ${n(e)}`),this.#E(),{success:!0,token:this.token}}catch(e){if(t?.aborted||!this.#d)return;throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message,e.code||"solve_failed"),e}}finally{this.#l=!1}}async solveChallengesV2(e,t){const i=e.length;let n=0;const o=new Array(e.length);for(let t=0;t<e.length;t++){const i=e[t];if(!i||"object"!=typeof i||"sha256-pow"!==i.protocol&&"rsw"!==i.protocol&&"instrumentation"!==i.protocol)throw a("challenge_unsupported",`unsupported format-2 protocol '${i?.protocol}'`)}let c=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{c=await v()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}const h=Math.max(1,Math.min(this.#t,e.length)),d=new f(h);d.setWasm(c),d._ensureSize(h);const u=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),g=new Array(e.length).fill(0),b=()=>{const e=g.reduce((e,t)=>e+t,0)+n,t=Math.min(99,Math.round(e/i*100));this.dispatchEvent("progress",{progress:t})};try{await l(Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?u(d.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{o[t]={nonce:Number(e)},g[t]=0,n++,b()}):"rsw"===e.protocol?u(d.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{g[t]=e,b()}),`rsw worker #${t}`).then(e=>{o[t]={y:e.y},g[t]=0,n++,b()}):p(e.payload.blob).then(e=>{o[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},g[t]=0,n++,b()}))),t)}finally{d.terminate()}return o}async solveChallenges(e,t){const i=e.length;let n=0;let a=null;const o="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(o)try{a=await v()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}if(!o&&(s.warn(r("wasm"),"WebAssembly disabled in this browser, solver will be ~10x slower"),!this.#i.querySelector(".warning"))){const e=document.createElement("div");e.className="warning",e.style.cssText="width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;",e.innerText=this.getI18nText("wasm-disabled","Enable WASM for significantly faster solving"),this.#i.insertBefore(e,this.#i.firstChild),setTimeout(()=>{e.style.marginBottom="calc(-1 * var(--cap-border-radius, 14px))",e.style.opacity=1},10)}const c=new f(this.#t);c.setWasm(a),c._ensureSize(this.#t);const h=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),a=await l(Promise.all(r.map(([e,t])=>c.run(e,t).then(e=>{n++;const t=Math.min(99,Math.round((0+n)/i*100));return this.dispatchEvent("progress",{progress:t}),e}))),t);h.push(...a)}}finally{c.terminate()}return h}setWorkersCount(e){const t=parseInt(e,10),i=Math.min(navigator.hardwareConcurrency||8,16);this.#t=!Number.isNaN(t)&&t>0&&t<=i?t:navigator.hardwareConcurrency||8}createUI(){this.#s.classList.add("captcha"),this.#s.setAttribute("role","group"),this.#s.setAttribute("aria-label",this.getI18nText("group-aria-label","Cap verification")),this.#r=document.createElement("div"),this.#r.className="captcha-trigger",this.#r.setAttribute("part","trigger"),this.#r.setAttribute("role","button"),this.#r.setAttribute("tabindex","0"),this.#r.setAttribute("aria-label",this.getI18nText("verify-aria-label","Click to verify you're a human")),this.#r.setAttribute("aria-live","polite"),this.#r.setAttribute("disabled","true"),this.#r.innerHTML=`<div class="checkbox" part="checkbox" aria-hidden="true"><svg class="progress-ring" viewBox="0 0 32 32" aria-hidden="true"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText("initial-state","Verify you're human")}</span></p>`,this.#s.appendChild(this.#r),this.#a=document.createElement("a"),this.#a.className="cap-troubleshoot-link",this.#a.setAttribute("part","troubleshoot"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("rel","noopener"),this.#a.hidden=!0,this.#s.appendChild(this.#a),this.#n=document.createElement("a"),this.#n.className="credits",this.#n.setAttribute("aria-label","Secured by Cap"),this.#n.setAttribute("href","https://trycap.dev"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#n.textContent="Cap",this.#s.appendChild(this.#n),this.#i.innerHTML=`<style${window.CAP_CSS_NONCE?` nonce=${window.CAP_CSS_NONCE}`:""}>:host{display:inline-block}@media (prefers-reduced-motion:reduce){.captcha,.captcha *{transition:none!important;animation:none!important}.label{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.label:not(.active),.label.exit{display:none!important}}.captcha,.captcha *{box-sizing:border-box}.captcha{width:var(--cap-widget-width,260px);height:var(--cap-widget-height,58px);background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);-webkit-user-select:none;user-select:none;cursor:pointer;-webkit-tap-highlight-color:#fff0;color:var(--cap-color,#212121);font-family:var(--cap-font,system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif);transition:filter .2s,transform .2s,height .2s;display:inline-block;position:relative;overflow:hidden}.captcha.has-troubleshoot{height:calc(var(--cap-widget-height,58px) + 26px)}.captcha.has-troubleshoot .captcha-trigger{inset-block-end:26px}.captcha:not([data-state]):active{transform:scale(.97)}.captcha:hover{filter:brightness(98%)}.captcha-trigger{padding:var(--cap-widget-padding,14px);align-items:center;gap:var(--cap-gap,15px);border-radius:inherit;transition:inset .2s;display:flex;position:absolute;inset:0}.captcha-trigger:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:-3px}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px);flex-shrink:0;transition:opacity .2s}.captcha p{-webkit-user-select:none;user-select:none;margin:0;font-size:15px;font-weight:500}.label-wrapper{flex:1;align-items:center;min-width:0;height:2em;display:flex;position:relative;overflow:hidden}.label-wrapper:before,.label-wrapper:after{content:"";pointer-events:none;z-index:1;width:100%;height:.6em;position:absolute;inset-inline-start:0}.label-wrapper:before{background:linear-gradient(to bottom, var(--cap-background,#fdfdfd), transparent);top:0}.label-wrapper:after{background:linear-gradient(to top, var(--cap-background,#fdfdfd), transparent);bottom:0}.label{white-space:nowrap;opacity:0;filter:blur(2px);transition:transform .5s cubic-bezier(.25,1,.5,1),opacity .5s,filter .5s;position:absolute;transform:translateY(100%)}.label.active{opacity:1;filter:none;transform:translateY(0)}.label.exit{opacity:0;filter:blur(2px);transform:translateY(-100%)}.checkbox .progress-ring{width:100%;height:100%;display:none;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96px;transition:stroke-dashoffset .3s}.captcha[data-state=verifying] .checkbox{background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;display:flex;transform:scale(1.1)}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{background-image:var(--cap-checkmark,url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E));background-size:cover;border:1px solid #0000}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E"));background-size:cover;border:1px solid #0000}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha.invalid{border-color:var(--cap-invalid-border-color,#f55b50);box-shadow:0 0 0 3px var(--cap-invalid-ring-color,#f55b5033);animation:.5s cubic-bezier(.36,.07,.19,.97) cap-shake}@keyframes cap-shake{10%,90%{transform:translate(-1px)}20%,80%{transform:translate(2px)}30%,50%,70%{transform:translate(-4px)}40%,60%{transform:translate(4px)}}@media (prefers-reduced-motion:reduce){.captcha.invalid{animation:none!important}}.captcha-trigger[disabled]{cursor:not-allowed}.captcha[data-state=verifying] .captcha-trigger{cursor:progress}.captcha[data-state=done] .captcha-trigger{cursor:default}.credits{color:var(--cap-color,#212121);text-underline-offset:.18em;z-index:2;border-radius:4px;justify-content:flex-end;align-items:center;min-width:24px;min-height:24px;padding:4px 6px;text-decoration:underline;text-decoration-thickness:.08em;position:absolute;inset-block-end:4px;inset-inline-end:4px;opacity:.8!important;font-size:12px!important;display:inline-flex!important}.captcha .credits{visibility:visible!important;pointer-events:all!important;display:inline-flex!important}.credits:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px;opacity:1!important}.cap-troubleshoot-link{min-width:24px;min-height:24px;color:var(--cap-troubleshoot-color,#0050a0);text-underline-offset:.15em;cursor:pointer;z-index:2;border-radius:4px;align-items:center;padding:4px 6px;font-size:13px;font-weight:500;text-decoration:underline;text-decoration-thickness:.08em;display:inline-flex;position:absolute;inset-block-end:4px;inset-inline-start:14px}.cap-troubleshoot-link[hidden]{display:none}.cap-troubleshoot-link:hover{opacity:.85}.cap-troubleshoot-link:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px}@media (forced-colors:active){.captcha,.checkbox{border-color:canvastext}:is(.captcha-trigger:focus-visible,.credits:focus-visible,.cap-troubleshoot-link:focus-visible){outline-color:highlight}.progress-ring-bg{stroke:graytext}.progress-ring-circle{stroke:canvastext}.captcha.invalid{box-shadow:none;border-color:mark}.credits{opacity:1!important}}</style>`,this.#i.appendChild(this.#s),this.#$(),setTimeout(()=>this.#$(),100)}addEventListeners(){this.#r&&(this.#n.addEventListener("click",e=>{e.preventDefault(),window.open(`https://trycap.dev/?${new URLSearchParams({utm_source:"cap_widget",utm_medium:"referral",utm_campaign:"widget",utm_content:window.CAP_DISABLE_WIDGET_REF?"":location.hostname,ref:window.CAP_DISABLE_WIDGET_REF?"":location.href||"",sub:window.CAP_DISABLE_WIDGET_REF?"":document.referrer||""}).toString()}`,"_blank")}),this.#r.addEventListener("click",()=>{this.#r.hasAttribute("disabled")||this.solve()}),this.#r.addEventListener("mousedown",()=>{!this.#r.hasAttribute("disabled")&&this.#m&&navigator.vibrate(5)}),this.#r.addEventListener("keydown",e=>{e.target===this.#r&&("Enter"!==e.key&&" "!==e.key||this.#r.hasAttribute("disabled")||(e.preventDefault(),e.stopPropagation(),this.solve()))}),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset))}#N(){if(!this.#o)return!1;const e=this.#o.getBoundingClientRect();if(0===e.width&&0===e.height)return!0;const t=window.getComputedStyle(this.#o);return"none"===t.display||"hidden"===t.visibility}#$(){this.#n&&this.#s&&!this.#N()&&(this.#n.isConnected&&this.#n.parentNode===this.#s||this.#s.appendChild(this.#n),this.#n.textContent&&this.#n.textContent.trim()||(this.#n.textContent="Cap"),"https://trycap.dev"!==this.#n.getAttribute("href")&&this.#n.setAttribute("href","https://trycap.dev"),this.#n.style.cssText=["display: inline-flex !important","visibility: visible !important","opacity: 0.8 !important","pointer-events: all !important","font-size: 12px !important","transform: none !important","clip-path: none !important","filter: none !important","position: absolute !important"].join("; "))}animateLabel(e){if(!this.#r)return;const t=this.#r.querySelector(".label-wrapper");if(!t)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){const i=t.querySelector(".label.active");if(i)i.textContent=e;else{const i=document.createElement("span");i.className="label active",i.textContent=e,t.appendChild(i)}return}const i=t.querySelector(".label.active"),s=document.createElement("span");s.className="label",s.textContent=e,t.appendChild(s),s.offsetWidth,s.classList.add("active"),i&&(i.classList.remove("active"),i.classList.add("exit"),i.addEventListener("transitionend",()=>i.remove(),{once:!0}))}updateUI(e,t,i=!1){this.#s&&this.#r&&(this.#s.setAttribute("data-state",e),this.#s.classList.remove("has-troubleshoot"),this.animateLabel(t),this.#a&&(this.#a.hidden=!0),i?this.#r.setAttribute("disabled","true"):this.#r.removeAttribute("disabled"))}updateUIBlocked(e,t=!1){if(this.#s&&this.#r&&(this.#s.setAttribute("data-state","error"),this.#r.removeAttribute("disabled"),this.animateLabel(e),this.#a))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#a.setAttribute("href",e),this.#a.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#a.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#a.hidden=!0,this.#s.classList.remove("has-troubleshoot")}handleProgress(e){if(!this.#r)return;const t=this.#r.querySelector(".progress-ring-circle");if(t){const i=2*Math.PI*14,s=i-e.detail.progress/100*i;t.style.strokeDashoffset=s}const i=this.#r.querySelector(".label-wrapper");if(i){const e=i.querySelector(".label.active");e&&(e.textContent=`${this.getI18nText("verifying-label","Verifying...")}`)}this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done",this.getI18nText("solved-label","You're a human"),!0),this.executeAttributeCode("onsolve",e),this.#h?.setValidity?.({}),this.#s?.classList.remove("invalid")}handleError(e){this.updateUI("error",this.getI18nText("error-label","Error. Try again.")),this.executeAttributeCode("onerror",e),this.#m&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#M()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(s.warn(r(),"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error",t="unknown"){s.error(r("solve"),`[${t}] ${e}`),this.dispatchEvent("error",{isCap:!0,code:t,message:e})}dispatchEvent(e,t={}){const i=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(i)}reset(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.token=null,this.dispatchEvent("reset"),this.#L("")}get tokenValue(){return this.token}disconnectedCallback(){this.#b?.abort(),this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#k(),this.#u&&(clearTimeout(this.#u),this.#u=null),this.#p&&(this.#p.terminate(),this.#p=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class y{constructor(e={},t){const i=t||document.createElement("cap-widget");if(Object.entries(e).forEach(([e,t])=>{i.setAttribute(e,t)}),!e.apiEndpoint&&!window?.CAP_CUSTOM_FETCH)throw i.remove(),new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");e.apiEndpoint&&i.setAttribute("data-cap-api-endpoint",e.apiEndpoint),t||i.hasAttribute("data-cap-disable-haptics")||i.setAttribute("data-cap-disable-haptics",""),this.widget=i,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>i.token,configurable:!0,enumerable:!0}),t||(i.style.display="none",document.documentElement.appendChild(i))}}window.Cap=y,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&s.warn(r(),"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override"):customElements.define("cap-widget",w),"object"==typeof exports&&"undefined"!=typeof module?module.exports=y:"function"==typeof define&&define.amd&&define([],()=>y),"undefined"!=typeof exports&&(exports.default=y)})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cap-widget",
3
- "version": "0.1.55",
3
+ "version": "0.1.56",
4
4
  "description": "The self-hosted CAPTCHA for the modern web.",
5
5
  "keywords": [
6
6
  "algorithm",
package/src/cap.js CHANGED
@@ -41,6 +41,21 @@
41
41
  return fetch(u, conf);
42
42
  };
43
43
 
44
+ const raceAbort = (promise, signal) => {
45
+ if (!signal) return promise;
46
+ if (signal.aborted) return Promise.reject(_err("aborted", "aborted"));
47
+ return Promise.race([
48
+ promise,
49
+ new Promise((_, reject) =>
50
+ signal.addEventListener(
51
+ "abort",
52
+ () => reject(_err("aborted", "aborted")),
53
+ { once: true },
54
+ ),
55
+ ),
56
+ ]);
57
+ };
58
+
44
59
  const I18N_KEYS = "%%i18nKeys%%".split(",");
45
60
  const I18N_ROWS = %%i18nData%%;
46
61
 
@@ -429,6 +444,7 @@
429
444
  #speculativePool = null;
430
445
  #interactionHandler = null;
431
446
  #i18n = null;
447
+ #abort = null;
432
448
 
433
449
  get #hasHaptics() {
434
450
  return (
@@ -534,6 +550,7 @@
534
550
  try {
535
551
  const raw = await capFetch(`${apiEndpoint}challenge`, {
536
552
  method: "POST",
553
+ signal: this.#abort?.signal,
537
554
  });
538
555
  let resp;
539
556
  try {
@@ -542,6 +559,7 @@
542
559
  throw new Error("Failed to parse speculative challenge response");
543
560
  }
544
561
  if (resp.error) throw new Error(resp.error);
562
+ if (!this.#speculative) return;
545
563
 
546
564
  resp._apiEndpoint = apiEndpoint;
547
565
  this.#speculative.challengeResp = resp;
@@ -569,6 +587,7 @@
569
587
 
570
588
  this.#speculative.solvePromise = this.#speculativeSolveAll(challenges);
571
589
  } catch {
590
+ if (!this.#speculative) return;
572
591
  this.#speculative.state = "error";
573
592
  this.#speculative.notify();
574
593
  }
@@ -627,7 +646,7 @@
627
646
  this.#speculativePool
628
647
  .run(challenge[0], challenge[1])
629
648
  .then((nonce) => {
630
- this.#speculative.completedCount++;
649
+ if (this.#speculative) this.#speculative.completedCount++;
631
650
  return nonce;
632
651
  }),
633
652
  ),
@@ -644,6 +663,7 @@
644
663
  }
645
664
  }
646
665
 
666
+ if (!this.#speculative) return results;
647
667
  this.#speculative.results = results;
648
668
  this.#speculative.state = "redeeming";
649
669
  this.#speculativeRedeem(results);
@@ -652,6 +672,7 @@
652
672
 
653
673
  async #speculativeRedeem(solutions) {
654
674
  try {
675
+ if (!this.#speculative) return;
655
676
  const challengeResp = this.#speculative.challengeResp;
656
677
  const apiEndpoint = challengeResp._apiEndpoint;
657
678
  if (!apiEndpoint)
@@ -662,6 +683,7 @@
662
683
  instrOut = await runInstrumentationChallenge(
663
684
  challengeResp.instrumentation,
664
685
  );
686
+ if (!this.#speculative) return;
665
687
  if (instrOut?.__timeout || instrOut?.__blocked) {
666
688
  this.#speculative.state = "done";
667
689
  this.#speculative.notify();
@@ -677,6 +699,7 @@
677
699
  ...(instrOut && { instr: instrOut }),
678
700
  }),
679
701
  headers: { "Content-Type": "application/json" },
702
+ signal: this.#abort?.signal,
680
703
  });
681
704
 
682
705
  let resp;
@@ -686,6 +709,7 @@
686
709
  throw new Error("Failed to parse speculative redeem response");
687
710
  }
688
711
 
712
+ if (!this.#speculative) return;
689
713
  if (!resp.success)
690
714
  throw new Error(resp.error || "Speculative redeem failed");
691
715
 
@@ -695,6 +719,7 @@
695
719
  this.#speculative._invisibleElapsed = this.#speculative._t0 ? since(this.#speculative._t0) : "?";
696
720
  this.#speculative.notify();
697
721
  } catch {
722
+ if (!this.#speculative) return;
698
723
  this.#speculative.state = "done";
699
724
  this.#speculative.notify();
700
725
  }
@@ -797,6 +822,7 @@
797
822
 
798
823
  initialize() {
799
824
  _getSharedWorkerUrl();
825
+ this.#abort = new AbortController();
800
826
  if (!this.#speculative) {
801
827
  this.#speculative = this.#makeSpeculativeState();
802
828
  }
@@ -893,6 +919,7 @@
893
919
 
894
920
  this.#enforceCredits();
895
921
  const _solveT0 = performance.now();
922
+ const signal = this.#abort?.signal;
896
923
  log.debug(T("solve"), "starting");
897
924
 
898
925
  try {
@@ -960,6 +987,10 @@
960
987
  }
961
988
 
962
989
  const progressInterval = setInterval(() => {
990
+ if (signal?.aborted || !this.#speculative) {
991
+ clearInterval(progressInterval);
992
+ return;
993
+ }
963
994
  const st = this.#speculative.state;
964
995
  if (st === "done" || st === "error") {
965
996
  clearInterval(progressInterval);
@@ -982,6 +1013,7 @@
982
1013
  this.#speculative.onSettled(resolve),
983
1014
  );
984
1015
  clearInterval(progressInterval);
1016
+ if (signal?.aborted || !this.#speculative) return;
985
1017
 
986
1018
  if (
987
1019
  this.#speculative.state === "idle" &&
@@ -990,7 +1022,10 @@
990
1022
  ) {
991
1023
  challengeResp = this.#speculative.challengeResp;
992
1024
  this.#speculative.challengeResp = null;
993
- solutions = await this.solveChallengesV2(challengeResp.challenges);
1025
+ solutions = await this.solveChallengesV2(
1026
+ challengeResp.challenges,
1027
+ signal,
1028
+ );
994
1029
  } else {
995
1030
  if (this.#speculative.state !== "done") {
996
1031
  throw _err("solve_failed", "Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");
@@ -1016,6 +1051,7 @@
1016
1051
  } else {
1017
1052
  const challengeRaw = await capFetch(`${apiEndpoint}challenge`, {
1018
1053
  method: "POST",
1054
+ signal,
1019
1055
  });
1020
1056
  try {
1021
1057
  challengeResp = await challengeRaw.json();
@@ -1029,7 +1065,10 @@
1029
1065
  challengeResp.format === 2 &&
1030
1066
  Array.isArray(challengeResp.challenges)
1031
1067
  ) {
1032
- solutions = await this.solveChallengesV2(challengeResp.challenges);
1068
+ solutions = await this.solveChallengesV2(
1069
+ challengeResp.challenges,
1070
+ signal,
1071
+ );
1033
1072
  } else {
1034
1073
  const { challenge, token } = challengeResp;
1035
1074
  let challenges = challenge;
@@ -1043,7 +1082,7 @@
1043
1082
  ];
1044
1083
  });
1045
1084
  }
1046
- solutions = await this.solveChallenges(challenges);
1085
+ solutions = await this.solveChallenges(challenges, signal);
1047
1086
  }
1048
1087
  }
1049
1088
 
@@ -1052,6 +1091,7 @@
1052
1091
  : Promise.resolve(null);
1053
1092
 
1054
1093
  const instrOut = await instrPromise;
1094
+ if (signal?.aborted || !this.#speculative) return;
1055
1095
 
1056
1096
  if (instrOut?.__timeout || instrOut?.__blocked) {
1057
1097
  capFetch(`${apiEndpoint}redeem`, {
@@ -1063,6 +1103,7 @@
1063
1103
  ...(instrOut.__timeout && { instr_timeout: true }),
1064
1104
  }),
1065
1105
  headers: { "Content-Type": "application/json" },
1106
+ signal,
1066
1107
  }).catch(() => {});
1067
1108
 
1068
1109
  this.updateUIBlocked(
@@ -1104,6 +1145,7 @@
1104
1145
  ...(instrOut && { instr: instrOut }),
1105
1146
  }),
1106
1147
  headers: { "Content-Type": "application/json" },
1148
+ signal,
1107
1149
  });
1108
1150
 
1109
1151
  let resp;
@@ -1113,6 +1155,8 @@
1113
1155
  throw _err("redeem_failed", "Failed to parse server response");
1114
1156
  }
1115
1157
 
1158
+ if (signal?.aborted || !this.#speculative) return;
1159
+
1116
1160
  this.dispatchEvent("progress", { progress: 100 });
1117
1161
  if (!resp.success) throw _err("invalid_solution", resp.error || "Invalid solution");
1118
1162
 
@@ -1144,6 +1188,7 @@
1144
1188
  this.#logInvisible();
1145
1189
  return { success: true, token: this.token };
1146
1190
  } catch (err) {
1191
+ if (signal?.aborted || !this.#speculative) return;
1147
1192
  this.#trigger.setAttribute(
1148
1193
  "aria-label",
1149
1194
  this.getI18nText(
@@ -1159,7 +1204,7 @@
1159
1204
  }
1160
1205
  }
1161
1206
 
1162
- async solveChallengesV2(challenges) {
1207
+ async solveChallengesV2(challenges, signal) {
1163
1208
  const total = challenges.length;
1164
1209
  let completed = 0;
1165
1210
 
@@ -1212,7 +1257,7 @@
1212
1257
  };
1213
1258
 
1214
1259
  try {
1215
- await Promise.all(
1260
+ await raceAbort(Promise.all(
1216
1261
  challenges.map((ch, idx) => {
1217
1262
  if (ch.protocol === "sha256-pow") {
1218
1263
  return withTimeout(
@@ -1250,7 +1295,7 @@
1250
1295
  emit();
1251
1296
  });
1252
1297
  }),
1253
- );
1298
+ ), signal);
1254
1299
  } finally {
1255
1300
  pool.terminate();
1256
1301
  }
@@ -1258,7 +1303,7 @@
1258
1303
  return solutions;
1259
1304
  }
1260
1305
 
1261
- async solveChallenges(challenges) {
1306
+ async solveChallenges(challenges, signal) {
1262
1307
  const total = challenges.length;
1263
1308
  let completed = 0;
1264
1309
 
@@ -1306,7 +1351,7 @@
1306
1351
  i,
1307
1352
  Math.min(i + this.#workersCount, challenges.length),
1308
1353
  );
1309
- const chunkResults = await Promise.all(
1354
+ const chunkResults = await raceAbort(Promise.all(
1310
1355
  chunk.map(([salt, target]) =>
1311
1356
  pool.run(salt, target).then((nonce) => {
1312
1357
  completed++;
@@ -1318,7 +1363,7 @@
1318
1363
  return nonce;
1319
1364
  }),
1320
1365
  ),
1321
- );
1366
+ ), signal);
1322
1367
  results.push(...chunkResults);
1323
1368
  }
1324
1369
  } finally {
@@ -1652,6 +1697,7 @@
1652
1697
  }
1653
1698
 
1654
1699
  disconnectedCallback() {
1700
+ this.#abort?.abort();
1655
1701
  this.removeEventListener("progress", this.boundHandleProgress);
1656
1702
  this.removeEventListener("solve", this.boundHandleSolve);
1657
1703
  this.removeEventListener("error", this.boundHandleError);