@cap.js/widget 0.1.57 → 0.1.58
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.
- package/cap.d.ts +1 -0
- package/cap.min.js +1 -1
- package/package.json +1 -1
- package/src/cap.js +227 -19
- package/src/worker.js +206 -2
package/cap.d.ts
CHANGED
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=(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,""")}"`:"";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(()=>{this.#d&&(this.#d.state="error",this.#d.notify())})}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{}if(!this.#d)return[];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&&this.#p&&(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;){if(!this.#d||!this.#p)return s;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}#P(){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}}#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=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.#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.#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.#P();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.#P();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)})();
|
|
1
|
+
(()=>{const e="0.0.8",t="vibrate"in navigator&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches;if("undefined"==typeof window)return;const i=["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"],s=(e,t,s)=>{const r=0===t?"9999px":"0",n=t===s-1?"9999px":"0";return`color:#1e1e2e;background:${(e=>{if("cap"===e)return"#89b4fa";let t=0;for(let i=0;i<e.length;i++)t=e.charCodeAt(i)+((t<<5)-t);return i[Math.abs(t)%i.length]})(e)};margin-left:${t?"-6px":0};padding:0 6px;border-radius:${r} ${n} ${n} ${r};font-weight:600`},r={};for(const e of["debug","info","warn","error"])r[e]=(t,...i)=>{if(window.CAP_SILENT||"debug"===e&&!window.CAP_DEBUG)return;const r=t.map(e=>`%c${e}`).join(" "),n=t.map((e,i)=>s(e,i,t.length));console["debug"===e?"log":e](r,...n,...i)};const n=e=>e?["cap",e]:["cap"],a=e=>`${Math.round(performance.now()-e)}ms`,o=(e,t)=>Object.assign(new Error(t),{code:e}),l=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t),c=(e,t)=>t?t.aborted?Promise.reject(o("aborted","aborted")):Promise.race([e,new Promise((e,i)=>t.addEventListener("abort",()=>i(o("aborted","aborted")),{once:!0}))]):e,h="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(","),d={"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 u(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 p=null;async function g(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 p||(p=new Promise((e,t)=>{const i=window.CAP_PAKO_URL||"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";r.debug(n("instr"),"DecompressionStream unavailable, loading pako from",i);const s=document.createElement("script");s.src=i;const a=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;a&&s.setAttribute("nonce",a),s.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("pako loaded but inflateRaw is missing"))},s.onerror=()=>{p=null,t(new Error(`failed to load pako fallback from ${i}`))},document.head.appendChild(s)})),(await p).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,vp:[window.innerWidth,window.innerHeight]}):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,""")}"`:"";s.srcdoc='<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><script'+l+">"+i+"\n<\/script></body></html>",document.body.appendChild(s)})}let m=null;const v=()=>{if(m)return m;const t=window.CAP_CUSTOM_WASM_URL||`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${e}/browser/cap_wasm_bg.wasm`,i=performance.now();return r.debug(n("wasm"),"fetching",t),m=fetch(t).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).then(e=>(r.debug(n("wasm"),`ready in ${a(i)}`),e)).catch(e=>{throw m=null,r.warn(n("wasm"),`load failed (${a(i)}):`,e.message||e),e}),m};let f=null;const b=()=>{if(f)return f;const t=window.CAP_CUSTOM_HASHWX_URL||`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${e}/browser/hashwx.wasm`,i=performance.now();return r.debug(n("wasm"),"fetching",t),f=fetch(t).then(e=>{if(!e.ok)throw new Error(`Failed to fetch hashwx wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).then(e=>(r.debug(n("wasm"),`hashwx ready in ${a(i)}`),e)).catch(e=>{throw f=null,r.warn(n("wasm"),`hashwx load failed (${a(i)}):`,e.message||e),e}),f};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&v().catch(()=>{});let w=null;function y(){return w||(w=URL.createObjectURL(new Blob(['(()=>{const e=(e,...t)=>{self.CAP_SILENT||console[e]("[cap worker]",...t)};let t=!1;const n="function"==typeof MessageChannel?new MessageChannel:null,s=()=>new Promise(e=>{if(!n)return setTimeout(e,0);n.port1.onmessage=()=>e(),n.port2.postMessage(0)}),r=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 w=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]&w)!==(f[a]&w)&&(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})}},o=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)})},a=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),l=(e,t)=>{const n=e.length,s=1+(n+8>>6),r=new Uint8Array(s<<6);r.set(e),r[n]=128;const o=8*n,l=new DataView(r.buffer);l.setUint32(r.length-4,o>>>0,!1),l.setUint32(r.length-8,Math.floor(o/4294967296),!1);let i=1779033703,c=3144134277,f=1013904242,w=2773480762,g=1359893119,d=2600822924,h=528734635,u=1541459225;const m=new Uint32Array(64);for(let e=0;e<s;e++){const t=e<<6;for(let e=0;e<16;e++)m[e]=l.getUint32(t+(e<<2),!1);for(let e=16;e<64;e++){const t=m[e-15],n=m[e-2],s=(t>>>7|t<<25)^(t>>>18|t<<14)^t>>>3,r=(n>>>17|n<<15)^(n>>>19|n<<13)^n>>>10;m[e]=m[e-16]+s+m[e-7]+r>>>0}let n=i,s=c,r=f,o=w,b=g,p=d,_=h,y=u;for(let e=0;e<64;e++){const t=y+((b>>>6|b<<26)^(b>>>11|b<<21)^(b>>>25|b<<7))+(b&p^~b&_)+a[e]+m[e]>>>0,l=n&s^n&r^s&r;y=_,_=p,p=b,b=o+t>>>0,o=r,r=s,s=n,n=t+(((n>>>2|n<<30)^(n>>>13|n<<19)^(n>>>22|n<<10))+l>>>0)>>>0}i=i+n>>>0,c=c+s>>>0,f=f+r>>>0,w=w+o>>>0,g=g+b>>>0,d=d+p>>>0,h=h+_>>>0,u=u+y>>>0}const b=new DataView(t.buffer,t.byteOffset,32);b.setUint32(0,i,!1),b.setUint32(4,c,!1),b.setUint32(8,f,!1),b.setUint32(12,w,!1),b.setUint32(16,g,!1),b.setUint32(20,d,!1),b.setUint32(24,h,!1),b.setUint32(28,u,!1)};let i=null;const c=async e=>{const{c:n,d:r,n:o,workerIndex:a,workerCount:c,hashwxModule:f}=e;if(!Number.isInteger(o)||o<1||!Number.isInteger(r)||r<1)throw new Error("malformed hashwx challenge payload");const w=o>>>0,g=((1n<<64n)-1n)/BigInt(r);t=!1;const{w:d,ctx:h,compiled:u,seedPtr:m,regPtr:b,memPtr:p}=(e=>{if(i)return i;const t=new WebAssembly.Instance(e,{}).exports;t._initialize&&t._initialize();let n=!0,s=t.hashwx_alloc(1);if(-1!==s&&0!==s||(n=!1,s=t.hashwx_alloc(0)),s<=0)throw new Error("hashwx_alloc failed");return i={w:t,ctx:s,compiled:n,seedPtr:t.hashwx_seed(s),regPtr:n?t.hashwx_registers(s):0,memPtr:n?t.hashwx_memory(s):0},i})(f),_=new Uint8Array(32);for(let e=0;e<32;e++)_[e]=parseInt(n.slice(2*e,2*e+2),16);const y=new Uint8Array(40);y.set(_,0);const x=new Uint8Array(32),M=performance.now();let U=0,A=M,I=M;try{for(let e=a;;e+=c){let n=e;for(let e=0;e<8;e++)y[32+e]=255&n,n=Math.floor(n/256);l(y,x),new Uint8Array(d.memory.buffer,m,32).set(x),d.hashwx_make(h,m);let r=null;if(u){const e=d.hashwx_module(h),t=d.hashwx_module_size(h),n=new Uint8Array(d.memory.buffer,e,t).slice();r=new WebAssembly.Instance(new WebAssembly.Module(n),{env:{memory:d.memory}}).exports.exec}const o=BigInt(e)*BigInt(w);for(let e=0;e<w;e++){const n=o+BigInt(e);let a;if(u?(d.hashwx_exec_begin(h,n),r(b,p),a=BigInt.asUintN(64,d.hashwx_exec_final(h))):a=BigInt.asUintN(64,d.hashwx_exec(h,n)),U++,a<=g)return void self.postMessage({found:!0,nonce:n.toString(),hashes:U,compiled:u,durationMs:(performance.now()-M).toFixed(2)});if(!(255&U)){const e=performance.now();if(e-A>=16&&(e-I>=150&&(I=e,self.postMessage({progress:U})),await s(),A=performance.now(),t))return self.postMessage({found:!1,error:"stopped"})}}}}catch(e){throw i=null,e}};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})=>{if("stop"!==e?.kind)return"rsw"===e?.kind?o(e):"hashwx"===e?.kind?self.postMessage({found:!1,error:"hashwx requires WebAssembly"}):r({salt:e.salt,target:e.target});t=!0});let f=null;self.onmessage=async({data:n})=>{if("stop"===n?.kind)return void(t=!0);if("rsw"===n?.kind)return o(n);if("hashwx"===n?.kind)try{return await c(n)}catch(t){return e("error","hashwx solver threw:",t.message||t),self.postMessage({found:!1,error:t.message||String(t)})}const{salt:s,target:a,wasmModule:l}=n;if(l instanceof WebAssembly.Module&&null===f){const t=(t=>{try{let e,n=0,s=null;const r=()=>(null!==s&&0!==s.byteLength||(s=new Uint8Array(e.memory.buffer)),s),o=new TextEncoder,a=(e,t,s)=>{if(void 0===s){const s=o.encode(e),a=t(s.length,1)>>>0;return r().subarray(a,a+s.length).set(s),n=s.length,a}let a=e.length,l=t(a,1)>>>0;const i=r();let c=0;for(;c<a;c++){const t=e.charCodeAt(c);if(t>127)break;i[l+c]=t}if(c!==a){0!==c&&(e=e.slice(c));const t=c+3*e.length;l=s(l,a,t,1)>>>0,a=t;const n=r().subarray(l+c,l+a),{written:i}=o.encodeInto(e,n);c+=i,l=s(l,a,c,1)>>>0}return n=c,l},l={wbg:{}};l.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 i=new WebAssembly.Instance(t,l);return e=i.exports,e.__wbindgen_start&&e.__wbindgen_start(),f=(t,s)=>{const r=a(t,e.__wbindgen_malloc,e.__wbindgen_realloc),o=n,l=a(s,e.__wbindgen_malloc,e.__wbindgen_realloc),i=n;return BigInt.asUintN(64,e.solve_pow(r,o,l,i))},!0}catch(t){return e("error","wasm init failed:",t.message||t),!1}})(l);if(!t)return e("warn","wasm init failed, falling back to JS solver"),r({salt:s,target:a})}if(null===f)return e("warn","no wasm module provided, falling back to JS solver"),r({salt:s,target:a});try{const e=performance.now(),t=f(s,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"})),w)}class k{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=y(),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++,r.warn(n("pool"),`worker died, replacing (attempt ${this._spawnFailures}/3)`),this._spawnFailures>3?(r.error(n("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})}}stopAll(){for(const e of this._workers)try{e.postMessage({kind:"stop"})}catch{}}terminate(){const e=this._workers;this._workers=[],this._idle=[],this._queue=[];for(const t of e)try{t.postMessage({kind:"stop"})}catch{}setTimeout(()=>{for(const t of e)try{t.terminate()}catch{}},250)}}class x 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;#m=null;#v=null;get#f(){return t&&!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)}}}#w(){this.#d=this.#b(),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)}#A(){this.#_()||r.info(n("challenges"),"solved invisible challenge")}#x(){"idle"===this.#d.state&&this.#_()&&(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 l(`${e}challenge`,{method:"POST",signal:this.#v?.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 i.challenges.some(e=>"hashwx"===e?.protocol)&&b().catch(()=>{}),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++,[u(`${r}${e}`,s.s),u(`${r}${e}d`,s.d)]))}this.#d.challenges=n,this.#d.state="solving",this.#d.solvePromise=this.#C(n).catch(()=>{this.#d&&(this.#d.state="error",this.#d.notify())})}catch{if(!this.#d)return;this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#C(e){y();let t=null;try{t=await v()}catch{}if(!this.#d)return[];this.#p||(this.#p=new k(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&&this.#p&&(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;){if(!this.#d||!this.#p)return s;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 o("missing_endpoint","speculative redeem: missing apiEndpoint");let s=null;if(t.instrumentation){if(s=await g(t.instrumentation),!this.#d)return;if(s?.__timeout||s?.__blocked)return this.#d.state="done",void this.#d.notify()}const r=await l(`${i}redeem`,{method:"POST",body:JSON.stringify({token:t.token,solutions:e,...s&&{instr:s}}),headers:{"Content-Type":"application/json"},signal:this.#v?.signal});let n;try{n=await r.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!this.#d)return;if(!n.success)throw new Error(n.error||"Speculative redeem failed");this.#d.token=n.token,this.#d.tokenExpires=new Date(n.expires).getTime(),this.#d.state="done",this.#d._invisibleElapsed=this.#d._t0?a(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"}#I(e){const t=this.querySelector(`input[name='${this.#T}']`);t&&(t.value=e)}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||this.#m?.[e]||t}#P(){r.debug(n("solve"),`served from speculative cache (saved ${this.#d._invisibleElapsed||"?"})`),this.dispatchEvent("progress",{progress:100}),this.#I(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.#f&&navigator.vibrate([10,50,20,30,40]),this.#A(),this.#w(),this.#l=!1,{success:!0,token:this.token}}#L(){this.#m=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=d[e]?e:d[e.split("-")[0]]?e.split("-")[0]:null;if(!t)return null;const i=d[t].split("/"),s={};return h.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(){y(),this.#v=new AbortController,this.#d||(this.#d=this.#b()),this.#p||(this.#p=new k(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.#L(),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}">`,r.debug(n(),`widget ready (workers=${this.#t}, haptics=${this.#f})`),this.#y(),this.#M(),this.addEventListener("invalid",this.#$)}#$=()=>{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.#U();const e=performance.now(),t=this.#v?.signal;r.debug(n("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,s,c=this.getAttribute("data-cap-api-endpoint");if(!c&&window?.CAP_CUSTOM_FETCH)c="/";else if(!c)throw o("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.#P();if("done"===this.#d.state)i=this.#d.results,s=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(()=>{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))s=this.#d.challengeResp,this.#d.challengeResp=null,i=await this.solveChallengesV2(s.challenges,t);else{if("done"!==this.#d.state)throw o("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.#P();i=this.#d.results,s=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const e=this.#d.challengeResp;if(2===e?.format&&Array.isArray(e.challenges))s=e,this.#d.challengeResp=null;else{const e=await l(`${c}challenge`,{method:"POST",signal:t});try{s=await e.json()}catch{throw o("challenge_parse_error","Failed to parse challenge response from server")}if(s.error)throw o("network_error",s.error)}if(2===s.format&&Array.isArray(s.challenges))i=await this.solveChallengesV2(s.challenges,t);else{const{challenge:e,token:r}=s;let n=e;if(!Array.isArray(n)){let t=0;n=Array.from({length:e.c},()=>(t++,[u(`${r}${t}`,e.s),u(`${r}${t}d`,e.d)]))}i=await this.solveChallenges(n,t)}}const h=s.instrumentation?g(s.instrumentation):Promise.resolve(null),d=await h;if(t?.aborted||!this.#d)return;if(d?.__timeout||d?.__blocked){l(`${c}redeem`,{method:"POST",body:JSON.stringify({token:s.token,solutions:i,...d.__blocked&&{instr_blocked:!0},...d.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"},signal:t}).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",a=d?.__blocked?`Instrumentation blocked (${d.blockReason||"automated_browser"})`:"Instrumentation timed out";this.removeEventListener("error",this.boundHandleError);const o=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,code:e,message:a}});return super.dispatchEvent(o),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",o),r.error(n("instr"),`[${e}] ${a}`),void(this.#l=!1)}const{token:p}=s,m=await l(`${c}redeem`,{method:"POST",body:JSON.stringify({token:p,solutions:i,...d&&{instr:d}}),headers:{"Content-Type":"application/json"},signal:t});let v;try{v=await m.json()}catch{throw o("redeem_failed","Failed to parse server response")}if(t?.aborted||!this.#d)return;if(this.dispatchEvent("progress",{progress:100}),!v.success)throw o("invalid_solution",v.error||"Invalid solution");this.#I(v.token),this.dispatchEvent("solve",{token:v.token}),this.token=v.token,this.#w(),this.#e&&clearTimeout(this.#e);const f=new Date(v.expires).getTime()-Date.now();return f>0&&f<864e5?this.#e=setTimeout(()=>this.reset(),f):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.#f&&navigator.vibrate([10,50,20,30,40]),r.debug(n("solve"),`verified in ${a(e)}`),this.#A(),{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 s=0;const a=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&&"hashwx"!==i.protocol&&"instrumentation"!==i.protocol)throw o("challenge_unsupported",`unsupported format-2 protocol '${i?.protocol}'`)}let l=!1,h=0;for(const t of e)if("sha256-pow"===t.protocol)l=!0;else if("hashwx"===t.protocol){h++;const{c:e,d:i,n:s}=t.payload??{};if("string"!=typeof e||!/^[0-9a-f]{64}$/i.test(e)||!Number.isInteger(i)||i<1||i>1e9||!Number.isInteger(s)||s<1||s>1048576)throw o("challenge_unsupported","malformed hashwx challenge payload")}const d=h>0,u="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;let p=null;if(u&&l)try{p=await v()}catch(e){r.warn(n("wasm"),"unavailable, falling back to JS solver:",e.message||e)}let m=null;if(d){if(!u)throw o("challenge_unsupported","hashwx requires WebAssembly");m=await b()}const f=Math.max(1,Math.min(this.#t,e.length)),w=new k(f);w.setWasm(p),w._ensureSize(f);const y=Math.max(1,this.#t),x=h>y,_=x?1:y;let A=d?new k(y):null;A&&A._ensureSize(y);const E=async e=>{let t;A.stopAll();const i=await Promise.race([Promise.allSettled(e).then(()=>!0),new Promise(e=>{t=setTimeout(()=>e(!1),1e3)})]);clearTimeout(t),i||(r.warn(n("solve"),"hashwx workers did not stop in time, replacing the pool"),A.terminate(),A=new k(y),A._ensureSize(y))},C=(e,t)=>{let i;return Promise.race([e,new Promise((e,s)=>{i=setTimeout(()=>s(new Error(`[cap] ${t} timed out after 60000ms`)),6e4)})]).finally(()=>clearTimeout(i))},S=new Array(e.length).fill(0),T=()=>{const e=S.reduce((e,t)=>e+t,0)+s,t=Math.min(99,Math.round(e/i*100));this.dispatchEvent("progress",{progress:t})},I=async(e,t)=>{const{c:i,d:l,n:c}=e.payload,h=Math.max(1,l),d=new Array(_).fill(0),u=[];try{for(let e=0;e<_;e++){const s=e,r=A.runMsg({kind:"hashwx",hashwxModule:m,c:i,d:l,n:c,workerIndex:s,workerCount:_},e=>{d[s]=e;let i=0;for(const e of d)i+=e;S[t]=Math.min(.99,i/h),T()});r.catch(()=>{}),u.push(r)}const e=await C((p=u,new Promise((e,t)=>{let i=p.length,s=null;for(const r of p)r.then(e,e=>{s||(s=e),i--,0===i&&t(s)})})).catch(e=>{throw o("solve_failed",e?.message||"every hashwx worker failed")}),`hashwx worker #${t}`);a[t]={nonce:e.nonce},r.debug(n("solve"),`hashwx #${t}: ${e.hashes} hashes in ${e.durationMs}ms`,`compiled=${e.compiled}`),S[t]=0,s++,T()}catch(e){throw await E(u),e}var p;return u},P=[];e.forEach((e,t)=>{"hashwx"===e.protocol&&P.push({ch:e,idx:t})});const L=P.length?x?Promise.all(P.map(e=>I(e.ch,e.idx))):(async()=>{for(let e=0;e<P.length;e++){const t=await I(P[e].ch,P[e].idx);e<P.length-1&&await E(t)}})():null;try{await c(Promise.all([L,...e.map((e,t)=>"sha256-pow"===e.protocol?C(w.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{a[t]={nonce:Number(e)},S[t]=0,s++,T()}):"rsw"===e.protocol?C(w.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{S[t]=e,T()}),`rsw worker #${t}`).then(e=>{a[t]={y:e.y},S[t]=0,s++,T()}):"hashwx"===e.protocol?null:g(e.payload.blob).then(e=>{a[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},S[t]=0,s++,T()}))]),t)}finally{w.terminate(),A&&A.terminate()}return a}async solveChallenges(e,t){const i=e.length;let s=0;let a=null;const o="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(o)try{a=await v()}catch(e){r.warn(n("wasm"),"unavailable, falling back to JS solver:",e.message||e)}if(!o&&(r.warn(n("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 l=new k(this.#t);l.setWasm(a),l._ensureSize(this.#t);const h=[];try{for(let r=0;r<e.length;r+=this.#t){const n=e.slice(r,Math.min(r+this.#t,e.length)),a=await c(Promise.all(n.map(([e,t])=>l.run(e,t).then(e=>{s++;const t=Math.min(99,Math.round((0+s)/i*100));return this.dispatchEvent("progress",{progress:t}),e}))),t);h.push(...a)}}finally{l.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.#U(),setTimeout(()=>this.#U(),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.#f&&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))}#H(){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}#U(){this.#n&&this.#s&&!this.#H()&&(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.#f&&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&&(r.warn(n(),"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error",t="unknown"){r.error(n("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.#u&&(clearTimeout(this.#u),this.#u=null),this.#d&&this.#w(),this.token=null,this.dispatchEvent("reset"),this.#I("")}get tokenValue(){return this.token}disconnectedCallback(){this.#v?.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 _{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=_,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&r.warn(n(),"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override"):customElements.define("cap-widget",x),"object"==typeof exports&&"undefined"!=typeof module?module.exports=_:"function"==typeof define&&define.amd&&define([],()=>_),"undefined"!=typeof exports&&(exports.default=_)})();
|
package/package.json
CHANGED
package/src/cap.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
(() => {
|
|
2
|
-
const WASM_VERSION = "0.0.
|
|
2
|
+
const WASM_VERSION = "0.0.8";
|
|
3
3
|
const _browserHasHaptics =
|
|
4
4
|
"vibrate" in navigator &&
|
|
5
5
|
!window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
@@ -209,7 +209,7 @@
|
|
|
209
209
|
blockReason: d.blockReason || "automated_browser",
|
|
210
210
|
});
|
|
211
211
|
} else if (d.result) {
|
|
212
|
-
resolve(d.result);
|
|
212
|
+
resolve({ ...d.result, vp: [window.innerWidth, window.innerHeight] });
|
|
213
213
|
} else {
|
|
214
214
|
resolve({ __timeout: true });
|
|
215
215
|
}
|
|
@@ -267,6 +267,52 @@
|
|
|
267
267
|
return wasmModulePromise;
|
|
268
268
|
};
|
|
269
269
|
|
|
270
|
+
const firstFulfilled = (tasks) =>
|
|
271
|
+
new Promise((resolve, reject) => {
|
|
272
|
+
let pending = tasks.length;
|
|
273
|
+
let firstError = null;
|
|
274
|
+
for (const task of tasks) {
|
|
275
|
+
task.then(resolve, (err) => {
|
|
276
|
+
if (!firstError) firstError = err;
|
|
277
|
+
pending--;
|
|
278
|
+
if (pending === 0) reject(firstError);
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const MAX_HASHWX_DIFFICULTY = 1_000_000_000;
|
|
284
|
+
const MAX_HASHWX_NONCES_PER_HASH = 1_048_576;
|
|
285
|
+
|
|
286
|
+
let hashwxModulePromise = null;
|
|
287
|
+
|
|
288
|
+
const getHashwxModule = () => {
|
|
289
|
+
if (hashwxModulePromise) return hashwxModulePromise;
|
|
290
|
+
|
|
291
|
+
const wasmUrl =
|
|
292
|
+
window.CAP_CUSTOM_HASHWX_URL ||
|
|
293
|
+
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/hashwx.wasm`;
|
|
294
|
+
|
|
295
|
+
const t0 = performance.now();
|
|
296
|
+
log.debug(T("wasm"), "fetching", wasmUrl);
|
|
297
|
+
hashwxModulePromise = fetch(wasmUrl)
|
|
298
|
+
.then((r) => {
|
|
299
|
+
if (!r.ok) throw new Error(`Failed to fetch hashwx wasm: ${r.status}`);
|
|
300
|
+
return r.arrayBuffer();
|
|
301
|
+
})
|
|
302
|
+
.then((buf) => WebAssembly.compile(buf))
|
|
303
|
+
.then((mod) => {
|
|
304
|
+
log.debug(T("wasm"), `hashwx ready in ${since(t0)}`);
|
|
305
|
+
return mod;
|
|
306
|
+
})
|
|
307
|
+
.catch((e) => {
|
|
308
|
+
hashwxModulePromise = null;
|
|
309
|
+
log.warn(T("wasm"), `hashwx load failed (${since(t0)}):`, e.message || e);
|
|
310
|
+
throw e;
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
return hashwxModulePromise;
|
|
314
|
+
};
|
|
315
|
+
|
|
270
316
|
if (
|
|
271
317
|
typeof WebAssembly === "object" &&
|
|
272
318
|
typeof WebAssembly.compile === "function"
|
|
@@ -292,6 +338,9 @@
|
|
|
292
338
|
return _sharedWorkerUrl;
|
|
293
339
|
}
|
|
294
340
|
|
|
341
|
+
const WORKER_STOP_GRACE_MS = 250;
|
|
342
|
+
const HASHWX_SETTLE_MS = 1000;
|
|
343
|
+
|
|
295
344
|
class WorkerPool {
|
|
296
345
|
constructor(size) {
|
|
297
346
|
this._size = size;
|
|
@@ -412,15 +461,31 @@
|
|
|
412
461
|
}
|
|
413
462
|
}
|
|
414
463
|
|
|
415
|
-
|
|
464
|
+
stopAll() {
|
|
416
465
|
for (const w of this._workers) {
|
|
417
466
|
try {
|
|
418
|
-
w.
|
|
467
|
+
w.postMessage({ kind: "stop" });
|
|
419
468
|
} catch {}
|
|
420
469
|
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
terminate() {
|
|
473
|
+
const workers = this._workers;
|
|
421
474
|
this._workers = [];
|
|
422
475
|
this._idle = [];
|
|
423
476
|
this._queue = [];
|
|
477
|
+
for (const w of workers) {
|
|
478
|
+
try {
|
|
479
|
+
w.postMessage({ kind: "stop" });
|
|
480
|
+
} catch {}
|
|
481
|
+
}
|
|
482
|
+
setTimeout(() => {
|
|
483
|
+
for (const w of workers) {
|
|
484
|
+
try {
|
|
485
|
+
w.terminate();
|
|
486
|
+
} catch {}
|
|
487
|
+
}
|
|
488
|
+
}, WORKER_STOP_GRACE_MS);
|
|
424
489
|
}
|
|
425
490
|
}
|
|
426
491
|
|
|
@@ -565,6 +630,9 @@
|
|
|
565
630
|
this.#speculative.challengeResp = resp;
|
|
566
631
|
|
|
567
632
|
if (resp.format === 2 && Array.isArray(resp.challenges)) {
|
|
633
|
+
if (resp.challenges.some((ch) => ch?.protocol === "hashwx")) {
|
|
634
|
+
getHashwxModule().catch(() => {});
|
|
635
|
+
}
|
|
568
636
|
this.#speculative.state = "idle";
|
|
569
637
|
this.#speculative.notify();
|
|
570
638
|
return;
|
|
@@ -1225,37 +1293,96 @@
|
|
|
1225
1293
|
!(
|
|
1226
1294
|
ch.protocol === "sha256-pow" ||
|
|
1227
1295
|
ch.protocol === "rsw" ||
|
|
1296
|
+
ch.protocol === "hashwx" ||
|
|
1228
1297
|
ch.protocol === "instrumentation"
|
|
1229
1298
|
)
|
|
1230
1299
|
) {
|
|
1231
|
-
// Unknown protocol = older widget on a newer server. Fall back to
|
|
1232
|
-
// erroring out -- the host can detect this and serve format-1.
|
|
1233
1300
|
throw _err("challenge_unsupported", `unsupported format-2 protocol '${ch?.protocol}'`);
|
|
1234
1301
|
}
|
|
1235
1302
|
}
|
|
1236
1303
|
|
|
1237
|
-
let
|
|
1304
|
+
let needsCapWasm = false;
|
|
1305
|
+
let hashwxCount = 0;
|
|
1306
|
+
for (const ch of challenges) {
|
|
1307
|
+
if (ch.protocol === "sha256-pow") needsCapWasm = true;
|
|
1308
|
+
else if (ch.protocol === "hashwx") {
|
|
1309
|
+
hashwxCount++;
|
|
1310
|
+
const { c, d, n } = ch.payload ?? {};
|
|
1311
|
+
if (
|
|
1312
|
+
typeof c !== "string" ||
|
|
1313
|
+
!/^[0-9a-f]{64}$/i.test(c) ||
|
|
1314
|
+
!Number.isInteger(d) ||
|
|
1315
|
+
d < 1 ||
|
|
1316
|
+
d > MAX_HASHWX_DIFFICULTY ||
|
|
1317
|
+
!Number.isInteger(n) ||
|
|
1318
|
+
n < 1 ||
|
|
1319
|
+
n > MAX_HASHWX_NONCES_PER_HASH
|
|
1320
|
+
) {
|
|
1321
|
+
throw _err("challenge_unsupported", "malformed hashwx challenge payload");
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
const needsHashwx = hashwxCount > 0;
|
|
1326
|
+
|
|
1238
1327
|
const wasmSupported =
|
|
1239
1328
|
typeof WebAssembly === "object" &&
|
|
1240
1329
|
typeof WebAssembly.instantiate === "function";
|
|
1241
|
-
|
|
1330
|
+
|
|
1331
|
+
let wasmModule = null;
|
|
1332
|
+
if (wasmSupported && needsCapWasm) {
|
|
1242
1333
|
try { wasmModule = await getWasmModule(); }
|
|
1243
1334
|
catch (e) { log.warn(T("wasm"), "unavailable, falling back to JS solver:", e.message || e); }
|
|
1244
1335
|
}
|
|
1245
1336
|
|
|
1337
|
+
let hashwxModule = null;
|
|
1338
|
+
if (needsHashwx) {
|
|
1339
|
+
if (!wasmSupported) {
|
|
1340
|
+
throw _err("challenge_unsupported", "hashwx requires WebAssembly");
|
|
1341
|
+
}
|
|
1342
|
+
hashwxModule = await getHashwxModule();
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1246
1345
|
const poolSize = Math.max(1, Math.min(this.#workersCount, challenges.length));
|
|
1247
1346
|
const pool = new WorkerPool(poolSize);
|
|
1248
1347
|
pool.setWasm(wasmModule);
|
|
1249
1348
|
pool._ensureSize(poolSize);
|
|
1250
1349
|
|
|
1350
|
+
const hashwxWorkers = Math.max(1, this.#workersCount);
|
|
1351
|
+
const hashwxQueued = hashwxCount > hashwxWorkers;
|
|
1352
|
+
const hashwxStripes = hashwxQueued ? 1 : hashwxWorkers;
|
|
1353
|
+
let hashwxPool = needsHashwx ? new WorkerPool(hashwxWorkers) : null;
|
|
1354
|
+
if (hashwxPool) hashwxPool._ensureSize(hashwxWorkers);
|
|
1355
|
+
|
|
1356
|
+
const reclaimStripes = async (stripes) => {
|
|
1357
|
+
hashwxPool.stopAll();
|
|
1358
|
+
let timer;
|
|
1359
|
+
const settled = await Promise.race([
|
|
1360
|
+
Promise.allSettled(stripes).then(() => true),
|
|
1361
|
+
new Promise((resolve) => {
|
|
1362
|
+
timer = setTimeout(() => resolve(false), HASHWX_SETTLE_MS);
|
|
1363
|
+
}),
|
|
1364
|
+
]);
|
|
1365
|
+
clearTimeout(timer);
|
|
1366
|
+
if (settled) return;
|
|
1367
|
+
log.warn(T("solve"), "hashwx workers did not stop in time, replacing the pool");
|
|
1368
|
+
hashwxPool.terminate();
|
|
1369
|
+
hashwxPool = new WorkerPool(hashwxWorkers);
|
|
1370
|
+
hashwxPool._ensureSize(hashwxWorkers);
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1251
1373
|
const TASK_TIMEOUT_MS = 60_000;
|
|
1252
|
-
const withTimeout = (promise, label) =>
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1374
|
+
const withTimeout = (promise, label) => {
|
|
1375
|
+
let timer;
|
|
1376
|
+
return Promise.race([
|
|
1377
|
+
promise,
|
|
1378
|
+
new Promise((_, rej) => {
|
|
1379
|
+
timer = setTimeout(
|
|
1380
|
+
() => rej(new Error(`[cap] ${label} timed out after ${TASK_TIMEOUT_MS}ms`)),
|
|
1381
|
+
TASK_TIMEOUT_MS,
|
|
1382
|
+
);
|
|
1383
|
+
}),
|
|
1384
|
+
]).finally(() => clearTimeout(timer));
|
|
1385
|
+
};
|
|
1259
1386
|
|
|
1260
1387
|
const inFlight = new Array(challenges.length).fill(0);
|
|
1261
1388
|
const emit = () => {
|
|
@@ -1264,9 +1391,82 @@
|
|
|
1264
1391
|
this.dispatchEvent("progress", { progress: visual });
|
|
1265
1392
|
};
|
|
1266
1393
|
|
|
1394
|
+
const solveHashwx = async (ch, idx) => {
|
|
1395
|
+
const { c, d, n } = ch.payload;
|
|
1396
|
+
const expected = Math.max(1, d);
|
|
1397
|
+
const striped = new Array(hashwxStripes).fill(0);
|
|
1398
|
+
const stripes = [];
|
|
1399
|
+
try {
|
|
1400
|
+
for (let s = 0; s < hashwxStripes; s++) {
|
|
1401
|
+
const stripe = s;
|
|
1402
|
+
const task = hashwxPool.runMsg(
|
|
1403
|
+
{
|
|
1404
|
+
kind: "hashwx",
|
|
1405
|
+
hashwxModule,
|
|
1406
|
+
c,
|
|
1407
|
+
d,
|
|
1408
|
+
n,
|
|
1409
|
+
workerIndex: stripe,
|
|
1410
|
+
workerCount: hashwxStripes,
|
|
1411
|
+
},
|
|
1412
|
+
(hashes) => {
|
|
1413
|
+
striped[stripe] = hashes;
|
|
1414
|
+
let sum = 0;
|
|
1415
|
+
for (const v of striped) sum += v;
|
|
1416
|
+
inFlight[idx] = Math.min(0.99, sum / expected);
|
|
1417
|
+
emit();
|
|
1418
|
+
},
|
|
1419
|
+
);
|
|
1420
|
+
task.catch(() => {});
|
|
1421
|
+
stripes.push(task);
|
|
1422
|
+
}
|
|
1423
|
+
const data = await withTimeout(
|
|
1424
|
+
firstFulfilled(stripes).catch((err) => {
|
|
1425
|
+
throw _err(
|
|
1426
|
+
"solve_failed",
|
|
1427
|
+
err?.message || "every hashwx worker failed",
|
|
1428
|
+
);
|
|
1429
|
+
}),
|
|
1430
|
+
`hashwx worker #${idx}`,
|
|
1431
|
+
);
|
|
1432
|
+
solutions[idx] = { nonce: data.nonce };
|
|
1433
|
+
log.debug(
|
|
1434
|
+
T("solve"),
|
|
1435
|
+
`hashwx #${idx}: ${data.hashes} hashes in ${data.durationMs}ms`,
|
|
1436
|
+
`compiled=${data.compiled}`,
|
|
1437
|
+
);
|
|
1438
|
+
inFlight[idx] = 0;
|
|
1439
|
+
completed++;
|
|
1440
|
+
emit();
|
|
1441
|
+
} catch (err) {
|
|
1442
|
+
await reclaimStripes(stripes);
|
|
1443
|
+
throw err;
|
|
1444
|
+
}
|
|
1445
|
+
return stripes;
|
|
1446
|
+
};
|
|
1447
|
+
|
|
1448
|
+
const hashwxJobs = [];
|
|
1449
|
+
challenges.forEach((ch, idx) => {
|
|
1450
|
+
if (ch.protocol === "hashwx") hashwxJobs.push({ ch, idx });
|
|
1451
|
+
});
|
|
1452
|
+
const hashwxSequence = hashwxJobs.length
|
|
1453
|
+
? hashwxQueued
|
|
1454
|
+
? Promise.all(hashwxJobs.map((job) => solveHashwx(job.ch, job.idx)))
|
|
1455
|
+
: (async () => {
|
|
1456
|
+
for (let i = 0; i < hashwxJobs.length; i++) {
|
|
1457
|
+
const stripes = await solveHashwx(
|
|
1458
|
+
hashwxJobs[i].ch,
|
|
1459
|
+
hashwxJobs[i].idx,
|
|
1460
|
+
);
|
|
1461
|
+
if (i < hashwxJobs.length - 1) await reclaimStripes(stripes);
|
|
1462
|
+
}
|
|
1463
|
+
})()
|
|
1464
|
+
: null;
|
|
1465
|
+
|
|
1267
1466
|
try {
|
|
1268
|
-
await raceAbort(Promise.all(
|
|
1269
|
-
|
|
1467
|
+
await raceAbort(Promise.all([
|
|
1468
|
+
hashwxSequence,
|
|
1469
|
+
...challenges.map((ch, idx) => {
|
|
1270
1470
|
if (ch.protocol === "sha256-pow") {
|
|
1271
1471
|
return withTimeout(
|
|
1272
1472
|
pool.run(ch.payload.salt, ch.payload.target),
|
|
@@ -1293,7 +1493,9 @@
|
|
|
1293
1493
|
emit();
|
|
1294
1494
|
});
|
|
1295
1495
|
}
|
|
1296
|
-
|
|
1496
|
+
|
|
1497
|
+
if (ch.protocol === "hashwx") return null;
|
|
1498
|
+
|
|
1297
1499
|
return runInstrumentationChallenge(ch.payload.blob).then((out) => {
|
|
1298
1500
|
if (out?.__timeout) solutions[idx] = { timeout: true };
|
|
1299
1501
|
else if (out?.__blocked) solutions[idx] = { blocked: true };
|
|
@@ -1303,9 +1505,10 @@
|
|
|
1303
1505
|
emit();
|
|
1304
1506
|
});
|
|
1305
1507
|
}),
|
|
1306
|
-
), signal);
|
|
1508
|
+
]), signal);
|
|
1307
1509
|
} finally {
|
|
1308
1510
|
pool.terminate();
|
|
1511
|
+
if (hashwxPool) hashwxPool.terminate();
|
|
1309
1512
|
}
|
|
1310
1513
|
|
|
1311
1514
|
return solutions;
|
|
@@ -1695,6 +1898,11 @@
|
|
|
1695
1898
|
clearTimeout(this.#resetTimer);
|
|
1696
1899
|
this.#resetTimer = null;
|
|
1697
1900
|
}
|
|
1901
|
+
if (this.#speculativeTimer) {
|
|
1902
|
+
clearTimeout(this.#speculativeTimer);
|
|
1903
|
+
this.#speculativeTimer = null;
|
|
1904
|
+
}
|
|
1905
|
+
if (this.#speculative) this.#resetSpeculativeState();
|
|
1698
1906
|
this.token = null;
|
|
1699
1907
|
this.dispatchEvent("reset");
|
|
1700
1908
|
this.#setToken("");
|
package/src/worker.js
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
if (!self.CAP_SILENT) console[method]("[cap worker]", ...args);
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
+
const HASHWX_CLOCK_EVERY = 256;
|
|
7
|
+
const HASHWX_YIELD_MS = 16;
|
|
8
|
+
const HASHWX_PROGRESS_MS = 150;
|
|
9
|
+
let stopRequested = false;
|
|
10
|
+
const yieldChannel = typeof MessageChannel === "function" ? new MessageChannel() : null;
|
|
11
|
+
const macrotask = () =>
|
|
12
|
+
new Promise((resolve) => {
|
|
13
|
+
if (!yieldChannel) return setTimeout(resolve, 0);
|
|
14
|
+
yieldChannel.port1.onmessage = () => resolve();
|
|
15
|
+
yieldChannel.port2.postMessage(0);
|
|
16
|
+
});
|
|
17
|
+
|
|
6
18
|
const solveFallback = async ({ salt, target }) => {
|
|
7
19
|
let nonce = 0;
|
|
8
20
|
const batchSize = 50000;
|
|
@@ -65,8 +77,8 @@
|
|
|
65
77
|
};
|
|
66
78
|
|
|
67
79
|
const solveRsw = (data) => {
|
|
68
|
-
const N = BigInt(
|
|
69
|
-
let y = BigInt(
|
|
80
|
+
const N = BigInt(`0x${data.N}`);
|
|
81
|
+
let y = BigInt(`0x${data.x}`);
|
|
70
82
|
const t = data.t | 0;
|
|
71
83
|
const chunk = Math.max(64, Math.floor(t / 50));
|
|
72
84
|
const t0 = performance.now();
|
|
@@ -82,11 +94,191 @@
|
|
|
82
94
|
});
|
|
83
95
|
};
|
|
84
96
|
|
|
97
|
+
const SHA_K = new Uint32Array([
|
|
98
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
99
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
100
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
101
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
102
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
103
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
104
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
105
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
const sha256Into = (bytes, out) => {
|
|
109
|
+
const len = bytes.length;
|
|
110
|
+
const blocks = ((len + 8) >> 6) + 1;
|
|
111
|
+
const padded = new Uint8Array(blocks << 6);
|
|
112
|
+
padded.set(bytes);
|
|
113
|
+
padded[len] = 0x80;
|
|
114
|
+
const bitLen = len * 8;
|
|
115
|
+
const dv = new DataView(padded.buffer);
|
|
116
|
+
dv.setUint32(padded.length - 4, bitLen >>> 0, false);
|
|
117
|
+
dv.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000), false);
|
|
118
|
+
|
|
119
|
+
let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;
|
|
120
|
+
let h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
|
|
121
|
+
const w = new Uint32Array(64);
|
|
122
|
+
|
|
123
|
+
for (let b = 0; b < blocks; b++) {
|
|
124
|
+
const off = b << 6;
|
|
125
|
+
for (let i = 0; i < 16; i++) w[i] = dv.getUint32(off + (i << 2), false);
|
|
126
|
+
for (let i = 16; i < 64; i++) {
|
|
127
|
+
const x = w[i - 15], y = w[i - 2];
|
|
128
|
+
const s0 = ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
|
|
129
|
+
const s1 = ((y >>> 17) | (y << 15)) ^ ((y >>> 19) | (y << 13)) ^ (y >>> 10);
|
|
130
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
131
|
+
}
|
|
132
|
+
let a = h0, bb = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
|
|
133
|
+
for (let i = 0; i < 64; i++) {
|
|
134
|
+
const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));
|
|
135
|
+
const ch = (e & f) ^ (~e & g);
|
|
136
|
+
const t1 = (h + S1 + ch + SHA_K[i] + w[i]) >>> 0;
|
|
137
|
+
const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));
|
|
138
|
+
const maj = (a & bb) ^ (a & c) ^ (bb & c);
|
|
139
|
+
const t2 = (S0 + maj) >>> 0;
|
|
140
|
+
h = g; g = f; f = e; e = (d + t1) >>> 0;
|
|
141
|
+
d = c; c = bb; bb = a; a = (t1 + t2) >>> 0;
|
|
142
|
+
}
|
|
143
|
+
h0 = (h0 + a) >>> 0; h1 = (h1 + bb) >>> 0; h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0;
|
|
144
|
+
h4 = (h4 + e) >>> 0; h5 = (h5 + f) >>> 0; h6 = (h6 + g) >>> 0; h7 = (h7 + h) >>> 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const odv = new DataView(out.buffer, out.byteOffset, 32);
|
|
148
|
+
odv.setUint32(0, h0, false); odv.setUint32(4, h1, false);
|
|
149
|
+
odv.setUint32(8, h2, false); odv.setUint32(12, h3, false);
|
|
150
|
+
odv.setUint32(16, h4, false); odv.setUint32(20, h5, false);
|
|
151
|
+
odv.setUint32(24, h6, false); odv.setUint32(28, h7, false);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
let hashwxRuntime = null;
|
|
155
|
+
|
|
156
|
+
const getHashwxRuntime = (hashwxModule) => {
|
|
157
|
+
if (hashwxRuntime) return hashwxRuntime;
|
|
158
|
+
|
|
159
|
+
const instance = new WebAssembly.Instance(hashwxModule, {});
|
|
160
|
+
const w = instance.exports;
|
|
161
|
+
if (w._initialize) w._initialize();
|
|
162
|
+
|
|
163
|
+
let compiled = true;
|
|
164
|
+
let ctx = w.hashwx_alloc(1);
|
|
165
|
+
if (ctx === -1 || ctx === 0) {
|
|
166
|
+
compiled = false;
|
|
167
|
+
ctx = w.hashwx_alloc(0);
|
|
168
|
+
}
|
|
169
|
+
if (ctx <= 0) throw new Error("hashwx_alloc failed");
|
|
170
|
+
|
|
171
|
+
hashwxRuntime = {
|
|
172
|
+
w,
|
|
173
|
+
ctx,
|
|
174
|
+
compiled,
|
|
175
|
+
seedPtr: w.hashwx_seed(ctx),
|
|
176
|
+
regPtr: compiled ? w.hashwx_registers(ctx) : 0,
|
|
177
|
+
memPtr: compiled ? w.hashwx_memory(ctx) : 0,
|
|
178
|
+
};
|
|
179
|
+
return hashwxRuntime;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const solveHashwx = async (data) => {
|
|
183
|
+
const { c, d, n, workerIndex, workerCount, hashwxModule } = data;
|
|
184
|
+
if (!Number.isInteger(n) || n < 1 || !Number.isInteger(d) || d < 1) {
|
|
185
|
+
throw new Error("malformed hashwx challenge payload");
|
|
186
|
+
}
|
|
187
|
+
const noncesPerHash = n >>> 0;
|
|
188
|
+
const target = ((1n << 64n) - 1n) / BigInt(d);
|
|
189
|
+
stopRequested = false;
|
|
190
|
+
|
|
191
|
+
const { w, ctx, compiled, seedPtr, regPtr, memPtr } =
|
|
192
|
+
getHashwxRuntime(hashwxModule);
|
|
193
|
+
|
|
194
|
+
const challenge = new Uint8Array(32);
|
|
195
|
+
for (let i = 0; i < 32; i++) challenge[i] = parseInt(c.slice(i * 2, i * 2 + 2), 16);
|
|
196
|
+
const seedInput = new Uint8Array(40);
|
|
197
|
+
seedInput.set(challenge, 0);
|
|
198
|
+
const seedOut = new Uint8Array(32);
|
|
199
|
+
|
|
200
|
+
const t0 = performance.now();
|
|
201
|
+
let hashes = 0;
|
|
202
|
+
let lastYield = t0;
|
|
203
|
+
let lastReport = t0;
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
for (let block = workerIndex; ; block += workerCount) {
|
|
207
|
+
let rest = block;
|
|
208
|
+
for (let i = 0; i < 8; i++) { seedInput[32 + i] = rest & 0xff; rest = Math.floor(rest / 256); }
|
|
209
|
+
sha256Into(seedInput, seedOut);
|
|
210
|
+
new Uint8Array(w.memory.buffer, seedPtr, 32).set(seedOut);
|
|
211
|
+
w.hashwx_make(ctx, seedPtr);
|
|
212
|
+
|
|
213
|
+
let side = null;
|
|
214
|
+
if (compiled) {
|
|
215
|
+
const codePtr = w.hashwx_module(ctx);
|
|
216
|
+
const codeSize = w.hashwx_module_size(ctx);
|
|
217
|
+
const bytes = new Uint8Array(w.memory.buffer, codePtr, codeSize).slice();
|
|
218
|
+
side = new WebAssembly.Instance(new WebAssembly.Module(bytes), {
|
|
219
|
+
env: { memory: w.memory },
|
|
220
|
+
}).exports.exec;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const base = BigInt(block) * BigInt(noncesPerHash);
|
|
224
|
+
for (let k = 0; k < noncesPerHash; k++) {
|
|
225
|
+
const nonce = base + BigInt(k);
|
|
226
|
+
let hash;
|
|
227
|
+
if (compiled) {
|
|
228
|
+
w.hashwx_exec_begin(ctx, nonce);
|
|
229
|
+
side(regPtr, memPtr);
|
|
230
|
+
hash = BigInt.asUintN(64, w.hashwx_exec_final(ctx));
|
|
231
|
+
} else {
|
|
232
|
+
hash = BigInt.asUintN(64, w.hashwx_exec(ctx, nonce));
|
|
233
|
+
}
|
|
234
|
+
hashes++;
|
|
235
|
+
if (hash <= target) {
|
|
236
|
+
self.postMessage({
|
|
237
|
+
found: true,
|
|
238
|
+
nonce: nonce.toString(),
|
|
239
|
+
hashes,
|
|
240
|
+
compiled,
|
|
241
|
+
durationMs: (performance.now() - t0).toFixed(2),
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if ((hashes & (HASHWX_CLOCK_EVERY - 1)) === 0) {
|
|
246
|
+
const now = performance.now();
|
|
247
|
+
if (now - lastYield >= HASHWX_YIELD_MS) {
|
|
248
|
+
if (now - lastReport >= HASHWX_PROGRESS_MS) {
|
|
249
|
+
lastReport = now;
|
|
250
|
+
self.postMessage({ progress: hashes });
|
|
251
|
+
}
|
|
252
|
+
await macrotask();
|
|
253
|
+
lastYield = performance.now();
|
|
254
|
+
if (stopRequested) {
|
|
255
|
+
return self.postMessage({ found: false, error: "stopped" });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
hashwxRuntime = null;
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
85
267
|
if (typeof WebAssembly !== "object" || typeof WebAssembly?.instantiate !== "function") {
|
|
86
268
|
wlog("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)");
|
|
87
269
|
|
|
88
270
|
self.onmessage = async ({ data }) => {
|
|
271
|
+
if (data?.kind === "stop") {
|
|
272
|
+
stopRequested = true;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
89
275
|
if (data?.kind === "rsw") return solveRsw(data);
|
|
276
|
+
if (data?.kind === "hashwx") {
|
|
277
|
+
return self.postMessage({
|
|
278
|
+
found: false,
|
|
279
|
+
error: "hashwx requires WebAssembly",
|
|
280
|
+
});
|
|
281
|
+
}
|
|
90
282
|
return solveFallback({ salt: data.salt, target: data.target });
|
|
91
283
|
};
|
|
92
284
|
|
|
@@ -179,7 +371,19 @@
|
|
|
179
371
|
};
|
|
180
372
|
|
|
181
373
|
self.onmessage = async ({ data }) => {
|
|
374
|
+
if (data?.kind === "stop") {
|
|
375
|
+
stopRequested = true;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
182
378
|
if (data?.kind === "rsw") return solveRsw(data);
|
|
379
|
+
if (data?.kind === "hashwx") {
|
|
380
|
+
try {
|
|
381
|
+
return await solveHashwx(data);
|
|
382
|
+
} catch (error) {
|
|
383
|
+
wlog("error", "hashwx solver threw:", error.message || error);
|
|
384
|
+
return self.postMessage({ found: false, error: error.message || String(error) });
|
|
385
|
+
}
|
|
386
|
+
}
|
|
183
387
|
const { salt, target, wasmModule } = data;
|
|
184
388
|
if (wasmModule instanceof WebAssembly.Module && solve_pow_function === null) {
|
|
185
389
|
const ok = initFromModule(wasmModule);
|