@cap.js/widget 0.1.56 → 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 +237 -21
- 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{if(!this.#d)return;this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#A(e){m();let t=null;try{t=await v()}catch{}this.#p||(this.#p=new f(1),this.#p._spawn()),this.#p.setWasm(t);const i=e.length,s=new Array(i);let r=1,n=!1;this.#d.promoteFn=e=>{n||(n=!0,r=e,this.#p._size=e,this.#p._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let a=0;for(;a<i;){const t=r,o=[],l=[];for(let s=0;s<t&&a<i;s++)l.push(a),o.push(e[a]),a++;this.#p._ensureSize(Math.max(r,t));const c=await Promise.all(o.map(e=>this.#p.run(e[0],e[1]).then(e=>(this.#d&&this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!n&&a<i&&await new Promise(e=>setTimeout(e,120))}return this.#d?(this.#d.results=s,this.#d.state="redeeming",this.#S(s),s):s}async#S(e){try{if(!this.#d)return;const t=this.#d.challengeResp,i=t._apiEndpoint;if(!i)throw a("missing_endpoint","speculative redeem: missing apiEndpoint");let s=null;if(t.instrumentation){if(s=await p(t.instrumentation),!this.#d)return;if(s?.__timeout||s?.__blocked)return this.#d.state="done",void this.#d.notify()}const r=await o(`${i}redeem`,{method:"POST",body:JSON.stringify({token:t.token,solutions:e,...s&&{instr:s}}),headers:{"Content-Type":"application/json"},signal:this.#b?.signal});let l;try{l=await r.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!this.#d)return;if(!l.success)throw new Error(l.error||"Speculative redeem failed");this.#d.token=l.token,this.#d.tokenExpires=new Date(l.expires).getTime(),this.#d.state="done",this.#d._invisibleElapsed=this.#d._t0?n(this.#d._t0):"?",this.#d.notify()}catch{if(!this.#d)return;this.#d.state="done",this.#d.notify()}}get#T(){return this.getAttribute("data-cap-hidden-field-name")||"cap-token"}#L(e){const t=this.querySelector(`input[name='${this.#T}']`);t&&(t.value=e)}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||this.#v?.[e]||t}#I(){s.debug(r("solve"),`served from speculative cache (saved ${this.#d._invisibleElapsed||"?"})`),this.dispatchEvent("progress",{progress:100}),this.#L(this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const e=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),e),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),this.#E(),this.#w(),this.#l=!1,{success:!0,token:this.token}}#P(){this.#v=function(e){const t=e?[e]:navigator.languages||[navigator.language||""];for(let e of t){if(!e)continue;if(e=e.toLowerCase(),"en"===e||e.startsWith("en-"))return null;const t=h[e]?e:h[e.split("-")[0]]?e.split("-")[0]:null;if(!t)return null;const i=h[t].split("/"),s={};return c.forEach((e,t)=>{s[e]=i[t]}),s}return null}(window.CAP_LANG||this.getAttribute("data-cap-lang"))}static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","data-cap-worker-count","data-cap-i18n-initial-state","required"]}constructor(){super(),this.#c&&this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this);try{this.#h=this.attachInternals()}catch{}}#M(){this.#h?.setValidity&&(this.hasAttribute("required")&&!this.token?this.#h.setValidity({valueMissing:!0},this.getI18nText("required-label","Please verify you're human"),this.#s||this):this.#h.setValidity({}))}initialize(){m(),this.#b=new AbortController,this.#d||(this.#d=this.#f()),this.#p||(this.#p=new f(1),this.#p._spawn())}attributeChangedCallback(e,t,i){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),i){const i=t=>{const i=this.getAttribute(e);"function"==typeof window[i]&&window[i].call(this,t)};this.#c.set(e,i),this.addEventListener(t,i)}}"data-cap-worker-count"===e&&this.setWorkersCount(parseInt(i,10)),"data-cap-i18n-initial-state"===e&&this.#s&&this.#s?.querySelector(".label.active")&&this.animateLabel(this.getI18nText("initial-state","Verify you're human")),"required"===e&&this.#M()}async connectedCallback(){this.#o=this,this.shadowRoot?this.#i=this.shadowRoot:this.#i=this.attachShadow({mode:"open"}),this.#s||(this.#s=document.createElement("div")),this.#P(),this.createUI(),this.addEventListeners(),this.initialize(),this.#r.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count"),t=e?parseInt(e,10):null;this.setWorkersCount(t||navigator.hardwareConcurrency||8),this.#o.innerHTML=`<input type="hidden" name="${this.#T}">`,s.debug(r(),`widget ready (workers=${this.#t}, haptics=${this.#m})`),this.#y(),this.#M(),this.addEventListener("invalid",this.#H)}#H=()=>{if(this.#s){try{this.scrollIntoView({behavior:"smooth",block:"center"})}catch{this.scrollIntoView()}this.#s.classList.remove("invalid"),this.#s.offsetWidth,this.#s.classList.add("invalid"),setTimeout(()=>this.#s?.classList.remove("invalid"),1500)}};async solve(){if(this.#l)return;this.#$();const e=performance.now(),t=this.#b?.signal;s.debug(r("solve"),"starting");try{this.#l=!0,this.updateUI("verifying",this.getI18nText("verifying-label","Verifying..."),!0),this.#r.setAttribute("aria-label",this.getI18nText("verifying-aria-label","Verifying you're a human, please wait")),this.dispatchEvent("progress",{progress:0});try{let i,l,c=this.getAttribute("data-cap-api-endpoint");if(!c&&window?.CAP_CUSTOM_FETCH)c="/";else if(!c)throw a("missing_endpoint","Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(c.endsWith("/")||(c+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#I();if("done"===this.#d.state)i=this.#d.results,l=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100});else if("solving"===this.#d.state||"redeeming"===this.#d.state||"fetching"===this.#d.state||"waiting"===this.#d.state){"waiting"===this.#d.state&&(this.#u&&(clearTimeout(this.#u),this.#u=null),this.#d.state="waiting",this.#C()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const e=setInterval(()=>{if(t?.aborted||!this.#d)return void clearInterval(e);const i=this.#d.state;if("done"===i||"error"===i)return void clearInterval(e);const s=this.#d.challenges?this.#d.challenges.length:1,r=this.#d.completedCount,n="redeeming"===i?99:"fetching"===i||"waiting"===i?0:Math.min(98,Math.round(r/s*100));this.dispatchEvent("progress",{progress:n})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(e),t?.aborted||!this.#d)return;if("idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))l=this.#d.challengeResp,this.#d.challengeResp=null,i=await this.solveChallengesV2(l.challenges,t);else{if("done"!==this.#d.state)throw a("solve_failed","Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#I();i=this.#d.results,l=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const e=this.#d.challengeResp;if(2===e?.format&&Array.isArray(e.challenges))l=e,this.#d.challengeResp=null;else{const e=await o(`${c}challenge`,{method:"POST",signal:t});try{l=await e.json()}catch{throw a("challenge_parse_error","Failed to parse challenge response from server")}if(l.error)throw a("network_error",l.error)}if(2===l.format&&Array.isArray(l.challenges))i=await this.solveChallengesV2(l.challenges,t);else{const{challenge:e,token:s}=l;let r=e;if(!Array.isArray(r)){let t=0;r=Array.from({length:e.c},()=>(t++,[d(`${s}${t}`,e.s),d(`${s}${t}d`,e.d)]))}i=await this.solveChallenges(r,t)}}const h=l.instrumentation?p(l.instrumentation):Promise.resolve(null),u=await h;if(t?.aborted||!this.#d)return;if(u?.__timeout||u?.__blocked){o(`${c}redeem`,{method:"POST",body:JSON.stringify({token:l.token,solutions:i,...u.__blocked&&{instr_blocked:!0},...u.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"},signal:t}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),u?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again"));const e=u?.__blocked?"instr_blocked":"instr_timeout",n=u?.__blocked?`Instrumentation blocked (${u.blockReason||"automated_browser"})`:"Instrumentation timed out";this.removeEventListener("error",this.boundHandleError);const a=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,code:e,message:n}});return super.dispatchEvent(a),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",a),s.error(r("instr"),`[${e}] ${n}`),void(this.#l=!1)}const{token:g}=l,v=await o(`${c}redeem`,{method:"POST",body:JSON.stringify({token:g,solutions:i,...u&&{instr:u}}),headers:{"Content-Type":"application/json"},signal:t});let b;try{b=await v.json()}catch{throw a("redeem_failed","Failed to parse server response")}if(t?.aborted||!this.#d)return;if(this.dispatchEvent("progress",{progress:100}),!b.success)throw a("invalid_solution",b.error||"Invalid solution");this.#L(b.token),this.dispatchEvent("solve",{token:b.token}),this.token=b.token,this.#w(),this.#e&&clearTimeout(this.#e);const m=new Date(b.expires).getTime()-Date.now();return m>0&&m<864e5?this.#e=setTimeout(()=>this.reset(),m):this.error("Invalid expiration time","invalid_expires"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),s.debug(r("solve"),`verified in ${n(e)}`),this.#E(),{success:!0,token:this.token}}catch(e){if(t?.aborted||!this.#d)return;throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message,e.code||"solve_failed"),e}}finally{this.#l=!1}}async solveChallengesV2(e,t){const i=e.length;let n=0;const o=new Array(e.length);for(let t=0;t<e.length;t++){const i=e[t];if(!i||"object"!=typeof i||"sha256-pow"!==i.protocol&&"rsw"!==i.protocol&&"instrumentation"!==i.protocol)throw a("challenge_unsupported",`unsupported format-2 protocol '${i?.protocol}'`)}let c=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{c=await v()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}const h=Math.max(1,Math.min(this.#t,e.length)),d=new f(h);d.setWasm(c),d._ensureSize(h);const u=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),g=new Array(e.length).fill(0),b=()=>{const e=g.reduce((e,t)=>e+t,0)+n,t=Math.min(99,Math.round(e/i*100));this.dispatchEvent("progress",{progress:t})};try{await l(Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?u(d.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{o[t]={nonce:Number(e)},g[t]=0,n++,b()}):"rsw"===e.protocol?u(d.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{g[t]=e,b()}),`rsw worker #${t}`).then(e=>{o[t]={y:e.y},g[t]=0,n++,b()}):p(e.payload.blob).then(e=>{o[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},g[t]=0,n++,b()}))),t)}finally{d.terminate()}return o}async solveChallenges(e,t){const i=e.length;let n=0;let a=null;const o="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(o)try{a=await v()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}if(!o&&(s.warn(r("wasm"),"WebAssembly disabled in this browser, solver will be ~10x slower"),!this.#i.querySelector(".warning"))){const e=document.createElement("div");e.className="warning",e.style.cssText="width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;",e.innerText=this.getI18nText("wasm-disabled","Enable WASM for significantly faster solving"),this.#i.insertBefore(e,this.#i.firstChild),setTimeout(()=>{e.style.marginBottom="calc(-1 * var(--cap-border-radius, 14px))",e.style.opacity=1},10)}const c=new f(this.#t);c.setWasm(a),c._ensureSize(this.#t);const h=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),a=await l(Promise.all(r.map(([e,t])=>c.run(e,t).then(e=>{n++;const t=Math.min(99,Math.round((0+n)/i*100));return this.dispatchEvent("progress",{progress:t}),e}))),t);h.push(...a)}}finally{c.terminate()}return h}setWorkersCount(e){const t=parseInt(e,10),i=Math.min(navigator.hardwareConcurrency||8,16);this.#t=!Number.isNaN(t)&&t>0&&t<=i?t:navigator.hardwareConcurrency||8}createUI(){this.#s.classList.add("captcha"),this.#s.setAttribute("role","group"),this.#s.setAttribute("aria-label",this.getI18nText("group-aria-label","Cap verification")),this.#r=document.createElement("div"),this.#r.className="captcha-trigger",this.#r.setAttribute("part","trigger"),this.#r.setAttribute("role","button"),this.#r.setAttribute("tabindex","0"),this.#r.setAttribute("aria-label",this.getI18nText("verify-aria-label","Click to verify you're a human")),this.#r.setAttribute("aria-live","polite"),this.#r.setAttribute("disabled","true"),this.#r.innerHTML=`<div class="checkbox" part="checkbox" aria-hidden="true"><svg class="progress-ring" viewBox="0 0 32 32" aria-hidden="true"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText("initial-state","Verify you're human")}</span></p>`,this.#s.appendChild(this.#r),this.#a=document.createElement("a"),this.#a.className="cap-troubleshoot-link",this.#a.setAttribute("part","troubleshoot"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("rel","noopener"),this.#a.hidden=!0,this.#s.appendChild(this.#a),this.#n=document.createElement("a"),this.#n.className="credits",this.#n.setAttribute("aria-label","Secured by Cap"),this.#n.setAttribute("href","https://trycap.dev"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#n.textContent="Cap",this.#s.appendChild(this.#n),this.#i.innerHTML=`<style${window.CAP_CSS_NONCE?` nonce=${window.CAP_CSS_NONCE}`:""}>:host{display:inline-block}@media (prefers-reduced-motion:reduce){.captcha,.captcha *{transition:none!important;animation:none!important}.label{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.label:not(.active),.label.exit{display:none!important}}.captcha,.captcha *{box-sizing:border-box}.captcha{width:var(--cap-widget-width,260px);height:var(--cap-widget-height,58px);background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);-webkit-user-select:none;user-select:none;cursor:pointer;-webkit-tap-highlight-color:#fff0;color:var(--cap-color,#212121);font-family:var(--cap-font,system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif);transition:filter .2s,transform .2s,height .2s;display:inline-block;position:relative;overflow:hidden}.captcha.has-troubleshoot{height:calc(var(--cap-widget-height,58px) + 26px)}.captcha.has-troubleshoot .captcha-trigger{inset-block-end:26px}.captcha:not([data-state]):active{transform:scale(.97)}.captcha:hover{filter:brightness(98%)}.captcha-trigger{padding:var(--cap-widget-padding,14px);align-items:center;gap:var(--cap-gap,15px);border-radius:inherit;transition:inset .2s;display:flex;position:absolute;inset:0}.captcha-trigger:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:-3px}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px);flex-shrink:0;transition:opacity .2s}.captcha p{-webkit-user-select:none;user-select:none;margin:0;font-size:15px;font-weight:500}.label-wrapper{flex:1;align-items:center;min-width:0;height:2em;display:flex;position:relative;overflow:hidden}.label-wrapper:before,.label-wrapper:after{content:"";pointer-events:none;z-index:1;width:100%;height:.6em;position:absolute;inset-inline-start:0}.label-wrapper:before{background:linear-gradient(to bottom, var(--cap-background,#fdfdfd), transparent);top:0}.label-wrapper:after{background:linear-gradient(to top, var(--cap-background,#fdfdfd), transparent);bottom:0}.label{white-space:nowrap;opacity:0;filter:blur(2px);transition:transform .5s cubic-bezier(.25,1,.5,1),opacity .5s,filter .5s;position:absolute;transform:translateY(100%)}.label.active{opacity:1;filter:none;transform:translateY(0)}.label.exit{opacity:0;filter:blur(2px);transform:translateY(-100%)}.checkbox .progress-ring{width:100%;height:100%;display:none;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96px;transition:stroke-dashoffset .3s}.captcha[data-state=verifying] .checkbox{background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;display:flex;transform:scale(1.1)}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{background-image:var(--cap-checkmark,url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E));background-size:cover;border:1px solid #0000}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E"));background-size:cover;border:1px solid #0000}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha.invalid{border-color:var(--cap-invalid-border-color,#f55b50);box-shadow:0 0 0 3px var(--cap-invalid-ring-color,#f55b5033);animation:.5s cubic-bezier(.36,.07,.19,.97) cap-shake}@keyframes cap-shake{10%,90%{transform:translate(-1px)}20%,80%{transform:translate(2px)}30%,50%,70%{transform:translate(-4px)}40%,60%{transform:translate(4px)}}@media (prefers-reduced-motion:reduce){.captcha.invalid{animation:none!important}}.captcha-trigger[disabled]{cursor:not-allowed}.captcha[data-state=verifying] .captcha-trigger{cursor:progress}.captcha[data-state=done] .captcha-trigger{cursor:default}.credits{color:var(--cap-color,#212121);text-underline-offset:.18em;z-index:2;border-radius:4px;justify-content:flex-end;align-items:center;min-width:24px;min-height:24px;padding:4px 6px;text-decoration:underline;text-decoration-thickness:.08em;position:absolute;inset-block-end:4px;inset-inline-end:4px;opacity:.8!important;font-size:12px!important;display:inline-flex!important}.captcha .credits{visibility:visible!important;pointer-events:all!important;display:inline-flex!important}.credits:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px;opacity:1!important}.cap-troubleshoot-link{min-width:24px;min-height:24px;color:var(--cap-troubleshoot-color,#0050a0);text-underline-offset:.15em;cursor:pointer;z-index:2;border-radius:4px;align-items:center;padding:4px 6px;font-size:13px;font-weight:500;text-decoration:underline;text-decoration-thickness:.08em;display:inline-flex;position:absolute;inset-block-end:4px;inset-inline-start:14px}.cap-troubleshoot-link[hidden]{display:none}.cap-troubleshoot-link:hover{opacity:.85}.cap-troubleshoot-link:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px}@media (forced-colors:active){.captcha,.checkbox{border-color:canvastext}:is(.captcha-trigger:focus-visible,.credits:focus-visible,.cap-troubleshoot-link:focus-visible){outline-color:highlight}.progress-ring-bg{stroke:graytext}.progress-ring-circle{stroke:canvastext}.captcha.invalid{box-shadow:none;border-color:mark}.credits{opacity:1!important}}</style>`,this.#i.appendChild(this.#s),this.#$(),setTimeout(()=>this.#$(),100)}addEventListeners(){this.#r&&(this.#n.addEventListener("click",e=>{e.preventDefault(),window.open(`https://trycap.dev/?${new URLSearchParams({utm_source:"cap_widget",utm_medium:"referral",utm_campaign:"widget",utm_content:window.CAP_DISABLE_WIDGET_REF?"":location.hostname,ref:window.CAP_DISABLE_WIDGET_REF?"":location.href||"",sub:window.CAP_DISABLE_WIDGET_REF?"":document.referrer||""}).toString()}`,"_blank")}),this.#r.addEventListener("click",()=>{this.#r.hasAttribute("disabled")||this.solve()}),this.#r.addEventListener("mousedown",()=>{!this.#r.hasAttribute("disabled")&&this.#m&&navigator.vibrate(5)}),this.#r.addEventListener("keydown",e=>{e.target===this.#r&&("Enter"!==e.key&&" "!==e.key||this.#r.hasAttribute("disabled")||(e.preventDefault(),e.stopPropagation(),this.solve()))}),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset))}#N(){if(!this.#o)return!1;const e=this.#o.getBoundingClientRect();if(0===e.width&&0===e.height)return!0;const t=window.getComputedStyle(this.#o);return"none"===t.display||"hidden"===t.visibility}#$(){this.#n&&this.#s&&!this.#N()&&(this.#n.isConnected&&this.#n.parentNode===this.#s||this.#s.appendChild(this.#n),this.#n.textContent&&this.#n.textContent.trim()||(this.#n.textContent="Cap"),"https://trycap.dev"!==this.#n.getAttribute("href")&&this.#n.setAttribute("href","https://trycap.dev"),this.#n.style.cssText=["display: inline-flex !important","visibility: visible !important","opacity: 0.8 !important","pointer-events: all !important","font-size: 12px !important","transform: none !important","clip-path: none !important","filter: none !important","position: absolute !important"].join("; "))}animateLabel(e){if(!this.#r)return;const t=this.#r.querySelector(".label-wrapper");if(!t)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){const i=t.querySelector(".label.active");if(i)i.textContent=e;else{const i=document.createElement("span");i.className="label active",i.textContent=e,t.appendChild(i)}return}const i=t.querySelector(".label.active"),s=document.createElement("span");s.className="label",s.textContent=e,t.appendChild(s),s.offsetWidth,s.classList.add("active"),i&&(i.classList.remove("active"),i.classList.add("exit"),i.addEventListener("transitionend",()=>i.remove(),{once:!0}))}updateUI(e,t,i=!1){this.#s&&this.#r&&(this.#s.setAttribute("data-state",e),this.#s.classList.remove("has-troubleshoot"),this.animateLabel(t),this.#a&&(this.#a.hidden=!0),i?this.#r.setAttribute("disabled","true"):this.#r.removeAttribute("disabled"))}updateUIBlocked(e,t=!1){if(this.#s&&this.#r&&(this.#s.setAttribute("data-state","error"),this.#r.removeAttribute("disabled"),this.animateLabel(e),this.#a))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#a.setAttribute("href",e),this.#a.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#a.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#a.hidden=!0,this.#s.classList.remove("has-troubleshoot")}handleProgress(e){if(!this.#r)return;const t=this.#r.querySelector(".progress-ring-circle");if(t){const i=2*Math.PI*14,s=i-e.detail.progress/100*i;t.style.strokeDashoffset=s}const i=this.#r.querySelector(".label-wrapper");if(i){const e=i.querySelector(".label.active");e&&(e.textContent=`${this.getI18nText("verifying-label","Verifying...")}`)}this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done",this.getI18nText("solved-label","You're a human"),!0),this.executeAttributeCode("onsolve",e),this.#h?.setValidity?.({}),this.#s?.classList.remove("invalid")}handleError(e){this.updateUI("error",this.getI18nText("error-label","Error. Try again.")),this.executeAttributeCode("onerror",e),this.#m&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#M()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(s.warn(r(),"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error",t="unknown"){s.error(r("solve"),`[${t}] ${e}`),this.dispatchEvent("error",{isCap:!0,code:t,message:e})}dispatchEvent(e,t={}){const i=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(i)}reset(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.token=null,this.dispatchEvent("reset"),this.#L("")}get tokenValue(){return this.token}disconnectedCallback(){this.#b?.abort(),this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#k(),this.#u&&(clearTimeout(this.#u),this.#u=null),this.#p&&(this.#p.terminate(),this.#p=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class y{constructor(e={},t){const i=t||document.createElement("cap-widget");if(Object.entries(e).forEach(([e,t])=>{i.setAttribute(e,t)}),!e.apiEndpoint&&!window?.CAP_CUSTOM_FETCH)throw i.remove(),new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");e.apiEndpoint&&i.setAttribute("data-cap-api-endpoint",e.apiEndpoint),t||i.hasAttribute("data-cap-disable-haptics")||i.setAttribute("data-cap-disable-haptics",""),this.widget=i,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>i.token,configurable:!0,enumerable:!0}),t||(i.style.display="none",document.documentElement.appendChild(i))}}window.Cap=y,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&s.warn(r(),"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override"):customElements.define("cap-widget",w),"object"==typeof exports&&"undefined"!=typeof module?module.exports=y:"function"==typeof define&&define.amd&&define([],()=>y),"undefined"!=typeof exports&&(exports.default=y)})();
|
|
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;
|
|
@@ -585,7 +653,13 @@
|
|
|
585
653
|
this.#speculative.challenges = challenges;
|
|
586
654
|
this.#speculative.state = "solving";
|
|
587
655
|
|
|
588
|
-
this.#speculative.solvePromise = this.#speculativeSolveAll(
|
|
656
|
+
this.#speculative.solvePromise = this.#speculativeSolveAll(
|
|
657
|
+
challenges,
|
|
658
|
+
).catch(() => {
|
|
659
|
+
if (!this.#speculative) return;
|
|
660
|
+
this.#speculative.state = "error";
|
|
661
|
+
this.#speculative.notify();
|
|
662
|
+
});
|
|
589
663
|
} catch {
|
|
590
664
|
if (!this.#speculative) return;
|
|
591
665
|
this.#speculative.state = "error";
|
|
@@ -601,6 +675,7 @@
|
|
|
601
675
|
wasmModule = await getWasmModule();
|
|
602
676
|
} catch {}
|
|
603
677
|
|
|
678
|
+
if (!this.#speculative) return [];
|
|
604
679
|
if (!this.#speculativePool) {
|
|
605
680
|
this.#speculativePool = new WorkerPool(1);
|
|
606
681
|
this.#speculativePool._spawn();
|
|
@@ -614,7 +689,7 @@
|
|
|
614
689
|
let promoted = false;
|
|
615
690
|
|
|
616
691
|
this.#speculative.promoteFn = (fullCount) => {
|
|
617
|
-
if (promoted) return;
|
|
692
|
+
if (promoted || !this.#speculativePool) return;
|
|
618
693
|
promoted = true;
|
|
619
694
|
concurrency = fullCount;
|
|
620
695
|
this.#speculativePool._size = fullCount;
|
|
@@ -629,6 +704,7 @@
|
|
|
629
704
|
let nextIndex = 0;
|
|
630
705
|
|
|
631
706
|
while (nextIndex < total) {
|
|
707
|
+
if (!this.#speculative || !this.#speculativePool) return results;
|
|
632
708
|
const batchSize = concurrency;
|
|
633
709
|
const batch = [];
|
|
634
710
|
const batchIndices = [];
|
|
@@ -1217,37 +1293,96 @@
|
|
|
1217
1293
|
!(
|
|
1218
1294
|
ch.protocol === "sha256-pow" ||
|
|
1219
1295
|
ch.protocol === "rsw" ||
|
|
1296
|
+
ch.protocol === "hashwx" ||
|
|
1220
1297
|
ch.protocol === "instrumentation"
|
|
1221
1298
|
)
|
|
1222
1299
|
) {
|
|
1223
|
-
// Unknown protocol = older widget on a newer server. Fall back to
|
|
1224
|
-
// erroring out -- the host can detect this and serve format-1.
|
|
1225
1300
|
throw _err("challenge_unsupported", `unsupported format-2 protocol '${ch?.protocol}'`);
|
|
1226
1301
|
}
|
|
1227
1302
|
}
|
|
1228
1303
|
|
|
1229
|
-
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
|
+
|
|
1230
1327
|
const wasmSupported =
|
|
1231
1328
|
typeof WebAssembly === "object" &&
|
|
1232
1329
|
typeof WebAssembly.instantiate === "function";
|
|
1233
|
-
|
|
1330
|
+
|
|
1331
|
+
let wasmModule = null;
|
|
1332
|
+
if (wasmSupported && needsCapWasm) {
|
|
1234
1333
|
try { wasmModule = await getWasmModule(); }
|
|
1235
1334
|
catch (e) { log.warn(T("wasm"), "unavailable, falling back to JS solver:", e.message || e); }
|
|
1236
1335
|
}
|
|
1237
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
|
+
|
|
1238
1345
|
const poolSize = Math.max(1, Math.min(this.#workersCount, challenges.length));
|
|
1239
1346
|
const pool = new WorkerPool(poolSize);
|
|
1240
1347
|
pool.setWasm(wasmModule);
|
|
1241
1348
|
pool._ensureSize(poolSize);
|
|
1242
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
|
+
|
|
1243
1373
|
const TASK_TIMEOUT_MS = 60_000;
|
|
1244
|
-
const withTimeout = (promise, label) =>
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
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
|
+
};
|
|
1251
1386
|
|
|
1252
1387
|
const inFlight = new Array(challenges.length).fill(0);
|
|
1253
1388
|
const emit = () => {
|
|
@@ -1256,9 +1391,82 @@
|
|
|
1256
1391
|
this.dispatchEvent("progress", { progress: visual });
|
|
1257
1392
|
};
|
|
1258
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
|
+
|
|
1259
1466
|
try {
|
|
1260
|
-
await raceAbort(Promise.all(
|
|
1261
|
-
|
|
1467
|
+
await raceAbort(Promise.all([
|
|
1468
|
+
hashwxSequence,
|
|
1469
|
+
...challenges.map((ch, idx) => {
|
|
1262
1470
|
if (ch.protocol === "sha256-pow") {
|
|
1263
1471
|
return withTimeout(
|
|
1264
1472
|
pool.run(ch.payload.salt, ch.payload.target),
|
|
@@ -1285,7 +1493,9 @@
|
|
|
1285
1493
|
emit();
|
|
1286
1494
|
});
|
|
1287
1495
|
}
|
|
1288
|
-
|
|
1496
|
+
|
|
1497
|
+
if (ch.protocol === "hashwx") return null;
|
|
1498
|
+
|
|
1289
1499
|
return runInstrumentationChallenge(ch.payload.blob).then((out) => {
|
|
1290
1500
|
if (out?.__timeout) solutions[idx] = { timeout: true };
|
|
1291
1501
|
else if (out?.__blocked) solutions[idx] = { blocked: true };
|
|
@@ -1295,9 +1505,10 @@
|
|
|
1295
1505
|
emit();
|
|
1296
1506
|
});
|
|
1297
1507
|
}),
|
|
1298
|
-
), signal);
|
|
1508
|
+
]), signal);
|
|
1299
1509
|
} finally {
|
|
1300
1510
|
pool.terminate();
|
|
1511
|
+
if (hashwxPool) hashwxPool.terminate();
|
|
1301
1512
|
}
|
|
1302
1513
|
|
|
1303
1514
|
return solutions;
|
|
@@ -1687,6 +1898,11 @@
|
|
|
1687
1898
|
clearTimeout(this.#resetTimer);
|
|
1688
1899
|
this.#resetTimer = null;
|
|
1689
1900
|
}
|
|
1901
|
+
if (this.#speculativeTimer) {
|
|
1902
|
+
clearTimeout(this.#speculativeTimer);
|
|
1903
|
+
this.#speculativeTimer = null;
|
|
1904
|
+
}
|
|
1905
|
+
if (this.#speculative) this.#resetSpeculativeState();
|
|
1690
1906
|
this.token = null;
|
|
1691
1907
|
this.dispatchEvent("reset");
|
|
1692
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);
|