cap-widget 0.1.52 → 0.1.55
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 +20 -0
- package/cap.min.js +1 -1
- package/package.json +1 -1
- package/src/cap.css +1 -1
- package/src/cap.js +199 -101
- package/src/i18n/translations.js +87 -0
- package/src/worker.js +10 -8
package/cap.d.ts
CHANGED
|
@@ -2,9 +2,12 @@ declare global {
|
|
|
2
2
|
interface Window {
|
|
3
3
|
CAP_CUSTOM_FETCH?: typeof fetch;
|
|
4
4
|
CAP_CUSTOM_WASM_URL?: string;
|
|
5
|
+
CAP_PAKO_URL?: string;
|
|
5
6
|
CAP_CSS_NONCE?: string;
|
|
6
7
|
CAP_SCRIPT_NONCE?: string;
|
|
7
8
|
CAP_DONT_SKIP_REDEFINE?: boolean;
|
|
9
|
+
CAP_DEBUG?: boolean;
|
|
10
|
+
CAP_SILENT?: boolean;
|
|
8
11
|
Cap: typeof Cap;
|
|
9
12
|
}
|
|
10
13
|
}
|
|
@@ -17,8 +20,24 @@ interface CapSolveEventDetail {
|
|
|
17
20
|
token: string;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
type CapErrorCode =
|
|
24
|
+
| "missing_endpoint"
|
|
25
|
+
| "network_error"
|
|
26
|
+
| "challenge_parse_error"
|
|
27
|
+
| "challenge_unsupported"
|
|
28
|
+
| "solve_failed"
|
|
29
|
+
| "instr_timeout"
|
|
30
|
+
| "instr_blocked"
|
|
31
|
+
| "redeem_failed"
|
|
32
|
+
| "invalid_solution"
|
|
33
|
+
| "invalid_expires"
|
|
34
|
+
| "wasm_load_failed"
|
|
35
|
+
| "worker_spawn_failed"
|
|
36
|
+
| "unknown";
|
|
37
|
+
|
|
20
38
|
interface CapErrorEventDetail {
|
|
21
39
|
isCap: boolean;
|
|
40
|
+
code: CapErrorCode;
|
|
22
41
|
message: string;
|
|
23
42
|
}
|
|
24
43
|
|
|
@@ -116,6 +135,7 @@ export {
|
|
|
116
135
|
type CapProgressEvent,
|
|
117
136
|
type CapSolveEvent,
|
|
118
137
|
type CapErrorEvent,
|
|
138
|
+
type CapErrorCode,
|
|
119
139
|
type CapResetEvent,
|
|
120
140
|
type SolveResult,
|
|
121
141
|
};
|
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=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t);function i(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 s=null;async function r(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 a=0;for(const e of r)a+=e.length;const n=new Uint8Array(a);let o=0;for(const e of r)n.set(e,o),o+=e.length;return n}catch{}return s||(s=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=document.createElement("script");r.src=i;const a=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;a&&r.setAttribute("nonce",a),r.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("[cap] pako loaded but inflateRaw is missing"))},r.onerror=()=>{s=null,t(new Error(`[cap] failed to load pako fallback from ${i}`))},document.head.appendChild(r)})),(await s).inflateRaw(e)}(t));return new Promise(e=>{var t=setTimeout(()=>{a(),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 a(){r||(r=!0,clearTimeout(t),window.removeEventListener("message",n),s.parentNode&&s.parentNode.removeChild(s))}function n(t){if(s.contentWindow&&t.source===s.contentWindow){var i=t.data;i&&"object"==typeof i&&("cap:instr"===i.type?(a(),i.blocked?e({__blocked:!0,blockReason:i.blockReason||"automated_browser"}):i.result?e(i.result):e({__timeout:!0})):"cap:error"===i.type&&(a(),e({__timeout:!0})))}}window.addEventListener("message",n);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 a=null;const n=()=>{if(a)return a;const e=window.CAP_CUSTOM_WASM_URL||"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.7/browser/cap_wasm_bg.wasm";return a=fetch(e).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).catch(e=>{throw a=null,e}),a};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&n().catch(()=>{});let o=null;function l(){return o||(o=URL.createObjectURL(new Blob(['(()=>{const e=async({salt:e,target:t})=>{let n=0;const o=new TextEncoder,r=4*t.length,s=Math.floor(r/8),a=r%8,l=t.length%2==0?t:`${t}0`,i=l.length/2,c=new Uint8Array(i);for(let e=0;e<i;e++)c[e]=parseInt(l.substring(2*e,2*e+2),16);const f=a>0?255<<8-a&255:0;for(;;)try{for(let t=0;t<5e4;t++){const t=e+n,r=o.encode(t),l=await crypto.subtle.digest("SHA-256",r),i=new Uint8Array(l);let g=!0;for(let e=0;e<s;e++)if(i[e]!==c[e]){g=!1;break}if(g&&a>0&&(i[s]&f)!==(c[s]&f)&&(g=!1),g)return void self.postMessage({nonce:n,found:!0});n++}}catch(e){return console.error("[cap worker]",e),void self.postMessage({found:!1,error:e.message})}},t=e=>{const t=BigInt("0x"+e.N);let n=BigInt("0x"+e.x);const o=0|e.t,r=Math.max(64,Math.floor(o/50)),s=performance.now();for(let e=0;e<o;e+=r){const s=Math.min(o,e+r);for(let o=e;o<s;o++)n=n*n%t;s<o&&self.postMessage({progress:s/o})}self.postMessage({found:!0,y:n.toString(16),durationMs:(performance.now()-s).toFixed(2)})};if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return console.warn("[cap worker] wasm not supported, falling back to alternative solver. this will be significantly slower."),void(self.onmessage=async({data:n})=>"rsw"===n?.kind?t(n):e({salt:n.salt,target:n.target}));let n=null;self.onmessage=async({data:o})=>{if("rsw"===o?.kind)return t(o);const{salt:r,target:s,wasmModule:a}=o;if(a instanceof WebAssembly.Module&&null===n){const t=(e=>{try{let t,o=0,r=null;const s=()=>(null!==r&&0!==r.byteLength||(r=new Uint8Array(t.memory.buffer)),r),a=new TextEncoder,l=(e,t,n)=>{if(void 0===n){const n=a.encode(e),r=t(n.length,1)>>>0;return s().subarray(r,r+n.length).set(n),o=n.length,r}let r=e.length,l=t(r,1)>>>0;const i=s();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=n(l,r,t,1)>>>0,r=t;const o=s().subarray(l+c,l+r),{written:i}=a.encodeInto(e,o);c+=i,l=n(l,r,c,1)>>>0}return o=c,l},i={wbg:{}};i.wbg.__wbindgen_init_externref_table=()=>{const e=t.__wbindgen_export_0,n=e.grow(4);e.set(0,void 0),e.set(n+0,void 0),e.set(n+1,null),e.set(n+2,!0),e.set(n+3,!1)};const c=new WebAssembly.Instance(e,i);return t=c.exports,t.__wbindgen_start&&t.__wbindgen_start(),n=(e,n)=>{const r=l(e,t.__wbindgen_malloc,t.__wbindgen_realloc),s=o,a=l(n,t.__wbindgen_malloc,t.__wbindgen_realloc),i=o;return BigInt.asUintN(64,t.solve_pow(r,s,a,i))},!0}catch(e){return console.error("[cap worker] failed to init wasm from module:",e),!1}})(a);if(!t)return console.warn("[cap worker] wasm init failed, falling back to JS solver."),e({salt:r,target:s})}if(null===n)return console.warn("[cap worker] no wasm module provided, falling back to JS solver."),e({salt:r,target:s});try{const e=performance.now(),t=n(r,s),o=performance.now();self.postMessage({nonce:Number(t),found:!0,durationMs:(o-e).toFixed(2)})}catch(e){console.error("[cap worker]",e),self.postMessage({found:!1,error:e.message||String(e)})}},self.onerror=e=>{self.postMessage({found:!1,error:e})}})();'],{type:"application/javascript"})),o)}class c{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=l(),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++,this._spawnFailures>3?(console.error("[cap] worker spawn failed repeatedly, not retrying"),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 a=!1;const n=({data:l})=>{if(!a)if(!l||"number"!=typeof l.progress||l.found)a=!0,e.removeEventListener("message",n),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(a)return;a=!0,e.removeEventListener("message",n),e.removeEventListener("error",o);const i=this._replaceWorker(e);s(t),i&&this._dispatch()};e.addEventListener("message",n),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 h extends HTMLElement{static formAssociated=!0;#e=null;#t=navigator.hardwareConcurrency||8;token=null;#i;#s;#r;#a;#n;#o;#l=!1;#c;#h;#d=null;#p=null;#u=null;#g=null;get#v(){return e&&!window.CAP_DISABLE_HAPTICS&&!this.hasAttribute("data-cap-disable-haptics")}#m(){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)}}}#b(){this.#d=this.#m(),this.#f()}#w(){this.#g&&(window.removeEventListener("mousemove",this.#g),window.removeEventListener("touchstart",this.#g),window.removeEventListener("keydown",this.#g),this.#g=null)}#f(){this.#w();const e=()=>{this.#w(),this.#y()};this.#g=e,window.addEventListener("mousemove",e,{passive:!0}),window.addEventListener("touchstart",e,{passive:!0}),window.addEventListener("keydown",e,{passive:!0})}#k(){return"function"==typeof this.checkVisibility?this.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0}):!!(this.offsetParent||this.getClientRects().length>0)}#y(){"idle"===this.#d.state&&this.#k()&&(this.#d.state="waiting",this.#p=setTimeout(()=>{this.#x()},2500))}async#x(){if("waiting"!==this.#d.state)return;this.#d.state="fetching";let e=this.getAttribute("data-cap-api-endpoint");if(!e&&window?.CAP_CUSTOM_FETCH&&(e="/"),e){e.endsWith("/")||(e+="/");try{const s=await t(`${e}challenge`,{method:"POST"});let r;try{r=await s.json()}catch{throw new Error("Failed to parse speculative challenge response")}if(r.error)throw new Error(r.error);if(r._apiEndpoint=e,this.#d.challengeResp=r,2===r.format&&Array.isArray(r.challenges))return this.#d.state="idle",void this.#d.notify();const{challenge:a,token:n}=r;let o=a;if(!Array.isArray(o)){let e=0;o=Array.from({length:a.c},()=>(e++,[i(`${n}${e}`,a.s),i(`${n}${e}d`,a.d)]))}this.#d.challenges=o,this.#d.state="solving",this.#d.solvePromise=this.#_(o)}catch(e){console.warn("[cap] speculative challenge fetch failed:",e),this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#_(e){l();let t=null;try{t=await n()}catch{}this.#u||(this.#u=new c(1),this.#u._spawn()),this.#u.setWasm(t);const i=e.length,s=new Array(i);let r=1,a=!1;this.#d.promoteFn=e=>{a||(a=!0,r=e,this.#u._size=e,this.#u._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let o=0;for(;o<i;){const t=r,n=[],l=[];for(let s=0;s<t&&o<i;s++)l.push(o),n.push(e[o]),o++;this.#u._ensureSize(Math.max(r,t));const c=await Promise.all(n.map(e=>this.#u.run(e[0],e[1]).then(e=>(this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!a&&o<i&&await new Promise(e=>setTimeout(e,120))}return this.#d.results=s,this.#d.state="redeeming",this.#E(s),s}async#E(e){try{const i=this.#d.challengeResp,s=i._apiEndpoint;if(!s)throw new Error("[cap] speculative redeem: missing apiEndpoint");let a=null;if(i.instrumentation&&(a=await r(i.instrumentation),a?.__timeout||a?.__blocked))return this.#d.state="done",void this.#d.notify();const n=await t(`${s}redeem`,{method:"POST",body:JSON.stringify({token:i.token,solutions:e,...a&&{instr:a}}),headers:{"Content-Type":"application/json"}});let o;try{o=await n.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!o.success)throw new Error(o.error||"Speculative redeem failed");this.#d.token=o.token,this.#d.tokenExpires=new Date(o.expires).getTime(),this.#d.state="done",this.#d.notify()}catch(e){console.warn("[cap] speculative redeem failed (will redo on click):",e),this.#d.state="done",this.#d.notify()}}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||t}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{}}#A(){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(){l(),this.#d||(this.#d=this.#m()),this.#u||(this.#u=new c(1),this.#u._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.#A()}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.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);const i=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.#o.innerHTML=`<input type="hidden" name="${i}">`,this.#f(),this.#A(),this.addEventListener("invalid",this.#C)}#C=()=>{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)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 e,s,a=this.getAttribute("data-cap-api-endpoint");if(!a&&window?.CAP_CUSTOM_FETCH)a="/";else if(!a)throw new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(a.endsWith("/")||(a+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires){this.dispatchEvent("progress",{progress:100});const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).value=this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const t=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),t),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#v&&navigator.vibrate([10,50,20,30,40]),this.#b(),this.#l=!1,{success:!0,token:this.token}}if("done"===this.#d.state)e=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.#p&&(clearTimeout(this.#p),this.#p=null),this.#d.state="waiting",this.#x()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const t=setInterval(()=>{const e=this.#d.state;if("done"===e||"error"===e)return void clearInterval(t);const i=this.#d.challenges?this.#d.challenges.length:1,s=this.#d.completedCount,r="redeeming"===e?99:"fetching"===e||"waiting"===e?0:Math.min(98,Math.round(s/i*100));this.dispatchEvent("progress",{progress:r})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(t),"idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))s=this.#d.challengeResp,this.#d.challengeResp=null,e=await this.solveChallengesV2(s.challenges);else{if("done"!==this.#d.state)throw new Error("Speculative solve failed – please try again");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires){this.dispatchEvent("progress",{progress:100});const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).value=this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const t=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),t),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#v&&navigator.vibrate([10,50,20,30,40]),this.#b(),this.#l=!1,{success:!0,token:this.token}}e=this.#d.results,s=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const r=this.#d.challengeResp;if(2===r?.format&&Array.isArray(r.challenges))s=r,this.#d.challengeResp=null;else{const e=await t(`${a}challenge`,{method:"POST"});try{s=await e.json()}catch{throw new Error("Failed to parse challenge response from server")}if(s.error)throw new Error(s.error)}if(2===s.format&&Array.isArray(s.challenges))e=await this.solveChallengesV2(s.challenges);else{const{challenge:t,token:r}=s;let a=t;if(!Array.isArray(a)){let e=0;a=Array.from({length:t.c},()=>(e++,[i(`${r}${e}`,t.s),i(`${r}${e}d`,t.d)]))}e=await this.solveChallenges(a)}}const n=s.instrumentation?r(s.instrumentation):Promise.resolve(null),o=await n;if(o?.__timeout||o?.__blocked){t(`${a}redeem`,{method:"POST",body:JSON.stringify({token:s.token,solutions:e,...o.__blocked&&{instr_blocked:!0},...o.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"}}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),o?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.removeEventListener("error",this.boundHandleError);const i=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,message:"Instrumentation failed"}});return super.dispatchEvent(i),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",i),console.error("[cap]","Instrumentation failed"),void(this.#l=!1)}const{token:l}=s,c=await t(`${a}redeem`,{method:"POST",body:JSON.stringify({token:l,solutions:e,...o&&{instr:o}}),headers:{"Content-Type":"application/json"}});let h;try{h=await c.json()}catch{throw new Error("Failed to parse server response")}if(this.dispatchEvent("progress",{progress:100}),!h.success)throw new Error(h.error||"Invalid solution");const d=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${d}']`)&&(this.querySelector(`input[name='${d}']`).value=h.token),this.dispatchEvent("solve",{token:h.token}),this.token=h.token,this.#b(),this.#e&&clearTimeout(this.#e);const p=new Date(h.expires).getTime()-Date.now();return p>0&&p<864e5?this.#e=setTimeout(()=>this.reset(),p):this.error("Invalid expiration time"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#v&&navigator.vibrate([10,50,20,30,40]),{success:!0,token:this.token}}catch(e){throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message),e}}finally{this.#l=!1}}async solveChallengesV2(e){const t=e.length;let i=0;const s=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 new Error(`[cap] unsupported format-2 protocol '${i?.protocol}'`)}let a=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{a=await n()}catch(e){console.warn("[cap] wasm unavailable, falling back to JS solver:",e)}const o=Math.max(1,Math.min(this.#t,e.length)),l=new c(o);l.setWasm(a),l._ensureSize(o);const h=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),d=new Array(e.length).fill(0),p=()=>{const e=d.reduce((e,t)=>e+t,0)+i,s=Math.min(99,Math.round(e/t*100));this.dispatchEvent("progress",{progress:s})};try{await Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?h(l.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{s[t]={nonce:Number(e)},d[t]=0,i++,p()}):"rsw"===e.protocol?h(l.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{d[t]=e,p()}),`rsw worker #${t}`).then(e=>{s[t]={y:e.y},d[t]=0,i++,p()}):r(e.payload.blob).then(e=>{s[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},d[t]=0,i++,p()})))}finally{l.terminate()}return s}async solveChallenges(e){const t=e.length;let i=0;let s=null;const r="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(r)try{s=await n()}catch(e){console.warn("[cap] wasm unavailable, falling back to JS solver:",e)}if(!r&&!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 a=new c(this.#t);a.setWasm(s),a._ensureSize(this.#t);const o=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),n=await Promise.all(r.map(([e,s])=>a.run(e,s).then(e=>{i++;const s=Math.min(99,Math.round((0+i)/t*100));return this.dispatchEvent("progress",{progress:s}),e})));o.push(...n)}}finally{a.terminate()}return o}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.#n=document.createElement("a"),this.#n.className="cap-troubleshoot-link",this.#n.setAttribute("part","troubleshoot"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("rel","noopener"),this.#n.hidden=!0,this.#s.appendChild(this.#n),this.#a=document.createElement("a"),this.#a.className="credits",this.#a.setAttribute("part","attribution"),this.#a.setAttribute("aria-label","Secured by Cap"),this.#a.setAttribute("href","https://trycap.dev"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#a.textContent="Cap",this.#s.appendChild(this.#a),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[part=attribution]{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)}addEventListeners(){this.#r&&(this.#a.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.#v&&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))}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.#n&&(this.#n.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.#n))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#n.setAttribute("href",e),this.#n.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#n.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#n.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.#v&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#A()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(console.error("[cap] using `onxxx='…'` is strongly discouraged and will be deprecated soon. please use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error"){console.error("[cap]",e),this.dispatchEvent("error",{isCap:!0,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");const e=this.getAttribute("data-cap-hidden-field-name")||"cap-token";this.querySelector(`input[name='${e}']`)&&(this.querySelector(`input[name='${e}']`).value="")}get tokenValue(){return this.token}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#w(),this.#p&&(clearTimeout(this.#p),this.#p=null),this.#u&&(this.#u.terminate(),this.#u=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class d{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=d,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&console.warn("[cap] the cap-widget element has already been defined, skipping re-defining it.\nto prevent this, set window.CAP_DONT_SKIP_REDEFINE to true"):customElements.define("cap-widget",h),"object"==typeof exports&&"undefined"!=typeof module?module.exports=d:"function"==typeof define&&define.amd&&define([],()=>d),"undefined"!=typeof exports&&(exports.default=d)})();
|
|
1
|
+
(()=>{const e="vibrate"in navigator&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches;if("undefined"==typeof window)return;const t=["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"],i=(e,i,s)=>{const r=0===i?"9999px":"0",n=i===s-1?"9999px":"0";return`color:#1e1e2e;background:${(e=>{if("cap"===e)return"#89b4fa";let i=0;for(let t=0;t<e.length;t++)i=e.charCodeAt(t)+((i<<5)-i);return t[Math.abs(i)%t.length]})(e)};margin-left:${i?"-6px":0};padding:0 6px;border-radius:${r} ${n} ${n} ${r};font-weight:600`},s={};for(const e of["debug","info","warn","error"])s[e]=(t,...s)=>{if(window.CAP_SILENT||"debug"===e&&!window.CAP_DEBUG)return;const r=t.map(e=>`%c${e}`).join(" "),n=t.map((e,s)=>i(e,s,t.length));console["debug"===e?"log":e](r,...n,...s)};const r=e=>e?["cap",e]:["cap"],n=e=>`${Math.round(performance.now()-e)}ms`,a=(e,t)=>Object.assign(new Error(t),{code:e}),o=(e,t={})=>window?.CAP_CUSTOM_FETCH?window.CAP_CUSTOM_FETCH(e,t):fetch(e,t),l="initial-state,verifying-label,solved-label,error-label,required-label,troubleshooting-label,group-aria-label,verify-aria-label,verifying-aria-label,verified-aria-label,error-aria-label".split(","),c={"zh-cn":"确认你是真人/正在验证.../你是真人/出错了。请重试。/请确认你是真人/故障排除/Cap 验证/点击以确认你是真人/正在验证你是真人,请稍候/我们已确认你是真人,你可以继续了/发生错误,请重试",es:"Verifica que eres humano/Verificando.../Eres humano/Error. Inténtalo de nuevo./Verifica que eres humano/Solucionar problemas/Verificación de Cap/Haz clic para verificar que eres humano/Verificando que eres humano, espera/Hemos verificado que eres humano, ya puedes continuar/Se produjo un error, inténtalo de nuevo",hi:"पुष्टि करें कि आप मानव हैं/सत्यापित हो रहा है.../आप मानव हैं/त्रुटि। पुनः प्रयास करें।/कृपया पुष्टि करें कि आप मानव हैं/समस्या निवारण/Cap सत्यापन/पुष्टि करने के लिए क्लिक करें कि आप मानव हैं/सत्यापित किया जा रहा है कि आप मानव हैं, प्रतीक्षा करें/हमने पुष्टि कर दी है कि आप मानव हैं, अब आप जारी रख सकते हैं/एक त्रुटि हुई, पुनः प्रयास करें",ar:"تحقق من أنك إنسان/جارٍ التحقق.../أنت إنسان/خطأ. حاول مرة أخرى./يرجى التحقق من أنك إنسان/استكشاف الأخطاء وإصلاحها/تحقق Cap/انقر للتحقق من أنك إنسان/جارٍ التحقق من أنك إنسان، يرجى الانتظار/لقد تحققنا من أنك إنسان، يمكنك المتابعة الآن/حدث خطأ، يرجى المحاولة مرة أخرى",pt:"Sou humano/Verificando.../Você é humano/Erro. Tente novamente./Verifique que você é humano/Solução de problemas/Verificação Cap/Clique para verificar que você é humano/Verificando que você é humano, aguarde/Verificamos que você é humano, você pode continuar/Ocorreu um erro, tente novamente",ru:"Я человек/Проверка.../Вы человек/Ошибка. Повторите./Подтвердите, что вы человек/Устранение неполадок/Проверка Cap/Нажмите, чтобы подтвердить, что вы человек/Проверяем, что вы человек, подождите/Мы подтвердили, что вы человек, можете продолжить/Произошла ошибка, повторите попытку",ja:"私は人間です/確認中.../あなたは人間です/エラー。再試行を。/あなたが人間であることを確認してください/トラブルシューティング/Cap 認証/クリックして人間であることを確認/あなたが人間であることを確認しています。お待ちください/あなたが人間であることを確認しました。続行できます/エラーが発生しました。もう一度お試しください",de:"Ich bin ein Mensch/Wird überprüft.../Sie sind ein Mensch/Fehler. Erneut versuchen./Bitte bestätigen Sie, dass Sie ein Mensch sind/Fehlerbehebung/Cap-Verifizierung/Klicken, um zu bestätigen, dass Sie ein Mensch sind/Überprüfung, ob Sie ein Mensch sind, bitte warten/Wir haben bestätigt, dass Sie ein Mensch sind, Sie können fortfahren/Ein Fehler ist aufgetreten, bitte erneut versuchen",fr:"Je suis humain/Vérification.../Vous êtes humain/Erreur. Réessayez./Veuillez vérifier que vous êtes humain/Dépannage/Vérification Cap/Cliquez pour vérifier que vous êtes humain/Vérification que vous êtes humain, veuillez patienter/Nous avons vérifié que vous êtes humain, vous pouvez continuer/Une erreur s'est produite, veuillez réessayer"};function h(e,t){let i=function(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return t>>>0}(e),s="";function r(){return i^=i<<13,i^=i>>>17,i^=i<<5,i>>>0}for(;s.length<t;){s+=r().toString(16).padStart(8,"0")}return s.substring(0,t)}let d=null;async function u(e){const t=(e=>{const t=atob(e),i=new Uint8Array(t.length);for(let e=0;e<t.length;e++)i[e]=t.charCodeAt(e);return i})(e),i=(new TextDecoder).decode(await async function(e){if("undefined"!=typeof DecompressionStream)try{const t=new DecompressionStream("deflate-raw"),i=t.writable.getWriter(),s=t.readable.getReader();i.write(e).then(()=>i.close()).catch(()=>{});const r=[];for(;;){const{done:e,value:t}=await s.read();if(e)break;r.push(t)}let n=0;for(const e of r)n+=e.length;const a=new Uint8Array(n);let o=0;for(const e of r)a.set(e,o),o+=e.length;return a}catch{}return d||(d=new Promise((e,t)=>{const i=window.CAP_PAKO_URL||"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";s.debug(r("instr"),"DecompressionStream unavailable, loading pako from",i);const n=document.createElement("script");n.src=i;const a=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE;a&&n.setAttribute("nonce",a),n.onload=()=>{window.pako?.inflateRaw?e(window.pako):t(new Error("pako loaded but inflateRaw is missing"))},n.onerror=()=>{d=null,t(new Error(`failed to load pako fallback from ${i}`))},document.head.appendChild(n)})),(await d).inflateRaw(e)}(t));return new Promise(e=>{var t=setTimeout(()=>{n(),e({__timeout:!0})},2e4),s=document.createElement("iframe");s.setAttribute("sandbox","allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.cssText="position:absolute;width:1px;height:1px;top:-9999px;left:-9999px;border:none;opacity:0;pointer-events:none;";var r=!1;function n(){r||(r=!0,clearTimeout(t),window.removeEventListener("message",a),s.parentNode&&s.parentNode.removeChild(s))}function a(t){if(s.contentWindow&&t.source===s.contentWindow){var i=t.data;i&&"object"==typeof i&&("cap:instr"===i.type?(n(),i.blocked?e({__blocked:!0,blockReason:i.blockReason||"automated_browser"}):i.result?e(i.result):e({__timeout:!0})):"cap:error"===i.type&&(n(),e({__timeout:!0})))}}window.addEventListener("message",a);const o=window.CAP_SCRIPT_NONCE||window.CAP_CSS_NONCE,l=o?` nonce="${String(o).replace(/"/g,""")}"`:"";s.srcdoc='<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><script'+l+">"+i+"\n<\/script></body></html>",document.body.appendChild(s)})}let p=null;const g=()=>{if(p)return p;const e=window.CAP_CUSTOM_WASM_URL||"https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.7/browser/cap_wasm_bg.wasm",t=performance.now();return s.debug(r("wasm"),"fetching",e),p=fetch(e).then(e=>{if(!e.ok)throw new Error(`Failed to fetch wasm: ${e.status}`);return e.arrayBuffer()}).then(e=>WebAssembly.compile(e)).then(e=>(s.debug(r("wasm"),`ready in ${n(t)}`),e)).catch(e=>{throw p=null,s.warn(r("wasm"),`load failed (${n(t)}):`,e.message||e),e}),p};"object"==typeof WebAssembly&&"function"==typeof WebAssembly.compile&&g().catch(()=>{});let v=null;function m(){return v||(v=URL.createObjectURL(new Blob(['(()=>{const e=(e,...t)=>{self.CAP_SILENT||console[e]("[cap worker]",...t)},t=async({salt:t,target:n})=>{let s=0;const r=new TextEncoder,o=4*n.length,a=Math.floor(o/8),l=o%8,i=n.length%2==0?n:`${n}0`,c=i.length/2,f=new Uint8Array(c);for(let e=0;e<c;e++)f[e]=parseInt(i.substring(2*e,2*e+2),16);const g=l>0?255<<8-l&255:0;for(;;)try{for(let e=0;e<5e4;e++){const e=t+s,n=r.encode(e),o=await crypto.subtle.digest("SHA-256",n),i=new Uint8Array(o);let c=!0;for(let e=0;e<a;e++)if(i[e]!==f[e]){c=!1;break}if(c&&l>0&&(i[a]&g)!==(f[a]&g)&&(c=!1),c)return void self.postMessage({nonce:s,found:!0});s++}}catch(t){return e("error","fallback solver crashed:",t.message||t),void self.postMessage({found:!1,error:t.message})}},n=e=>{const t=BigInt("0x"+e.N);let n=BigInt("0x"+e.x);const s=0|e.t,r=Math.max(64,Math.floor(s/50)),o=performance.now();for(let e=0;e<s;e+=r){const o=Math.min(s,e+r);for(let s=e;s<o;s++)n=n*n%t;o<s&&self.postMessage({progress:o/s})}self.postMessage({found:!0,y:n.toString(16),durationMs:(performance.now()-o).toFixed(2)})};if("object"!=typeof WebAssembly||"function"!=typeof WebAssembly?.instantiate)return e("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)"),void(self.onmessage=async({data:e})=>"rsw"===e?.kind?n(e):t({salt:e.salt,target:e.target}));let s=null;self.onmessage=async({data:r})=>{if("rsw"===r?.kind)return n(r);const{salt:o,target:a,wasmModule:l}=r;if(l instanceof WebAssembly.Module&&null===s){const n=(t=>{try{let e,n=0,r=null;const o=()=>(null!==r&&0!==r.byteLength||(r=new Uint8Array(e.memory.buffer)),r),a=new TextEncoder,l=(e,t,s)=>{if(void 0===s){const s=a.encode(e),r=t(s.length,1)>>>0;return o().subarray(r,r+s.length).set(s),n=s.length,r}let r=e.length,l=t(r,1)>>>0;const i=o();let c=0;for(;c<r;c++){const t=e.charCodeAt(c);if(t>127)break;i[l+c]=t}if(c!==r){0!==c&&(e=e.slice(c));const t=c+3*e.length;l=s(l,r,t,1)>>>0,r=t;const n=o().subarray(l+c,l+r),{written:i}=a.encodeInto(e,n);c+=i,l=s(l,r,c,1)>>>0}return n=c,l},i={wbg:{}};i.wbg.__wbindgen_init_externref_table=()=>{const t=e.__wbindgen_export_0,n=t.grow(4);t.set(0,void 0),t.set(n+0,void 0),t.set(n+1,null),t.set(n+2,!0),t.set(n+3,!1)};const c=new WebAssembly.Instance(t,i);return e=c.exports,e.__wbindgen_start&&e.__wbindgen_start(),s=(t,s)=>{const r=l(t,e.__wbindgen_malloc,e.__wbindgen_realloc),o=n,a=l(s,e.__wbindgen_malloc,e.__wbindgen_realloc),i=n;return BigInt.asUintN(64,e.solve_pow(r,o,a,i))},!0}catch(t){return e("error","wasm init failed:",t.message||t),!1}})(l);if(!n)return e("warn","wasm init failed, falling back to JS solver"),t({salt:o,target:a})}if(null===s)return e("warn","no wasm module provided, falling back to JS solver"),t({salt:o,target:a});try{const e=performance.now(),t=s(o,a),n=performance.now();self.postMessage({nonce:Number(t),found:!0,durationMs:(n-e).toFixed(2)})}catch(t){e("error","solve_pow threw:",t.message||t),self.postMessage({found:!1,error:t.message||String(t)})}},self.onerror=e=>{self.postMessage({found:!1,error:e})}})();'],{type:"application/javascript"})),v)}class b{constructor(e){this._size=e,this._workers=[],this._idle=[],this._queue=[],this._wasmModule=null,this._spawnFailures=0}setWasm(e){this._wasmModule=e}_spawn(){const e=m(),t=new Worker(e);return t._busy=!1,this._workers.push(t),this._idle.push(t),t}_replaceWorker(e){const t=this._workers.indexOf(e);-1!==t&&this._workers.splice(t,1);const i=this._idle.indexOf(e);-1!==i&&this._idle.splice(i,1);try{e.terminate()}catch{}return this._spawnFailures++,s.warn(r("pool"),`worker died, replacing (attempt ${this._spawnFailures}/3)`),this._spawnFailures>3?(s.error(r("pool"),"worker spawn failed repeatedly, giving up"),null):this._spawn()}_ensureSize(e){for(;this._workers.length<e;)this._spawn()}run(e,t){return new Promise((i,s)=>{this._queue.push({salt:e,target:t,resolve:i,reject:s}),this._dispatch()})}runMsg(e,t){return new Promise((i,s)=>{this._queue.push({msg:e,onProgress:t,resolve:i,reject:s}),this._dispatch()})}_dispatch(){for(;this._idle.length>0&&this._queue.length>0;){const e=this._idle.shift(),t=this._queue.shift(),{resolve:i,reject:s}=t,r=void 0!==t.msg;let n=!1;const a=({data:l})=>{if(!n)if(!l||"number"!=typeof l.progress||l.found)n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o),this._spawnFailures=0,this._idle.push(e),l.found?i(r?l:l.nonce):s(new Error(l.error||"worker failed")),this._dispatch();else if(t.onProgress)try{t.onProgress(l.progress)}catch{}},o=t=>{if(n)return;n=!0,e.removeEventListener("message",a),e.removeEventListener("error",o);const i=this._replaceWorker(e);s(t),i&&this._dispatch()};e.addEventListener("message",a),e.addEventListener("error",o),r?e.postMessage(t.msg):this._wasmModule?e.postMessage({salt:t.salt,target:t.target,wasmModule:this._wasmModule},[]):e.postMessage({salt:t.salt,target:t.target})}}terminate(){for(const e of this._workers)try{e.terminate()}catch{}this._workers=[],this._idle=[],this._queue=[]}}class f extends HTMLElement{static formAssociated=!0;#e=null;#t=navigator.hardwareConcurrency||8;token=null;#i;#s;#r;#n;#a;#o;#l=!1;#c;#h;#d=null;#u=null;#p=null;#g=null;#v=null;get#m(){return e&&!window.CAP_DISABLE_HAPTICS&&!this.hasAttribute("data-cap-disable-haptics")}#b(){return{state:"idle",challengeResp:null,challenges:null,results:[],completedCount:0,solvePromise:null,promoteFn:null,_listeners:[],pendingPromotion:null,token:null,tokenExpires:null,notify(){for(const e of this._listeners)e();this._listeners=[]},onSettled(e){"done"===this.state||"error"===this.state?e():this._listeners.push(e)}}}#f(){this.#d=this.#b(),this.#w()}#y(){this.#g&&(window.removeEventListener("mousemove",this.#g),window.removeEventListener("touchstart",this.#g),window.removeEventListener("keydown",this.#g),this.#g=null)}#w(){this.#y();const e=()=>{this.#y(),this.#k()};this.#g=e,window.addEventListener("mousemove",e,{passive:!0}),window.addEventListener("touchstart",e,{passive:!0}),window.addEventListener("keydown",e,{passive:!0})}#x(){return"function"==typeof this.checkVisibility?this.checkVisibility({checkOpacity:!0,checkVisibilityCSS:!0}):!!(this.offsetParent||this.getClientRects().length>0)}#_(){this.#x()||s.info(r("challenges"),"solved invisible challenge")}#k(){"idle"===this.#d.state&&this.#x()&&(this.#d.state="waiting",this.#u=setTimeout(()=>{this.#E()},2500))}async#E(){if("waiting"!==this.#d.state)return;this.#d.state="fetching",this.#d._t0=performance.now();let e=this.getAttribute("data-cap-api-endpoint");if(!e&&window?.CAP_CUSTOM_FETCH&&(e="/"),e){e.endsWith("/")||(e+="/");try{const t=await o(`${e}challenge`,{method:"POST"});let i;try{i=await t.json()}catch{throw new Error("Failed to parse speculative challenge response")}if(i.error)throw new Error(i.error);if(i._apiEndpoint=e,this.#d.challengeResp=i,2===i.format&&Array.isArray(i.challenges))return this.#d.state="idle",void this.#d.notify();const{challenge:s,token:r}=i;let n=s;if(!Array.isArray(n)){let e=0;n=Array.from({length:s.c},()=>(e++,[h(`${r}${e}`,s.s),h(`${r}${e}d`,s.d)]))}this.#d.challenges=n,this.#d.state="solving",this.#d.solvePromise=this.#C(n)}catch{this.#d.state="error",this.#d.notify()}}else this.#d.state="idle"}async#C(e){m();let t=null;try{t=await g()}catch{}this.#p||(this.#p=new b(1),this.#p._spawn()),this.#p.setWasm(t);const i=e.length,s=new Array(i);let r=1,n=!1;this.#d.promoteFn=e=>{n||(n=!0,r=e,this.#p._size=e,this.#p._ensureSize(e))},null!==this.#d.pendingPromotion&&(this.#d.promoteFn(this.#d.pendingPromotion),this.#d.pendingPromotion=null);let a=0;for(;a<i;){const t=r,o=[],l=[];for(let s=0;s<t&&a<i;s++)l.push(a),o.push(e[a]),a++;this.#p._ensureSize(Math.max(r,t));const c=await Promise.all(o.map(e=>this.#p.run(e[0],e[1]).then(e=>(this.#d.completedCount++,e))));for(let e=0;e<l.length;e++)s[l[e]]=c[e];!n&&a<i&&await new Promise(e=>setTimeout(e,120))}return this.#d.results=s,this.#d.state="redeeming",this.#A(s),s}async#A(e){try{const t=this.#d.challengeResp,i=t._apiEndpoint;if(!i)throw a("missing_endpoint","speculative redeem: missing apiEndpoint");let s=null;if(t.instrumentation&&(s=await u(t.instrumentation),s?.__timeout||s?.__blocked))return this.#d.state="done",void this.#d.notify();const r=await o(`${i}redeem`,{method:"POST",body:JSON.stringify({token:t.token,solutions:e,...s&&{instr:s}}),headers:{"Content-Type":"application/json"}});let l;try{l=await r.json()}catch{throw new Error("Failed to parse speculative redeem response")}if(!l.success)throw new Error(l.error||"Speculative redeem failed");this.#d.token=l.token,this.#d.tokenExpires=new Date(l.expires).getTime(),this.#d.state="done",this.#d._invisibleElapsed=this.#d._t0?n(this.#d._t0):"?",this.#d.notify()}catch{this.#d.state="done",this.#d.notify()}}get#S(){return this.getAttribute("data-cap-hidden-field-name")||"cap-token"}#T(e){const t=this.querySelector(`input[name='${this.#S}']`);t&&(t.value=e)}getI18nText(e,t){return this.getAttribute(`data-cap-i18n-${e}`)||this.#v?.[e]||t}#L(){s.debug(r("solve"),`served from speculative cache (saved ${this.#d._invisibleElapsed||"?"})`),this.dispatchEvent("progress",{progress:100}),this.#T(this.#d.token),this.dispatchEvent("solve",{token:this.#d.token}),this.token=this.#d.token;const e=this.#d.tokenExpires-Date.now();return this.#e&&clearTimeout(this.#e),this.#e=setTimeout(()=>this.reset(),e),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),this.#_(),this.#f(),this.#l=!1,{success:!0,token:this.token}}#I(){this.#v=function(e){const t=e?[e]:navigator.languages||[navigator.language||""];for(let e of t){if(!e)continue;if(e=e.toLowerCase(),"en"===e||e.startsWith("en-"))return null;const t=c[e]?e:c[e.split("-")[0]]?e.split("-")[0]:null;if(!t)return null;const i=c[t].split("/"),s={};return l.forEach((e,t)=>{s[e]=i[t]}),s}return null}(window.CAP_LANG||this.getAttribute("data-cap-lang"))}static get observedAttributes(){return["onsolve","onprogress","onreset","onerror","data-cap-worker-count","data-cap-i18n-initial-state","required"]}constructor(){super(),this.#c&&this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c=new Map,this.boundHandleProgress=this.handleProgress.bind(this),this.boundHandleSolve=this.handleSolve.bind(this),this.boundHandleError=this.handleError.bind(this),this.boundHandleReset=this.handleReset.bind(this);try{this.#h=this.attachInternals()}catch{}}#P(){this.#h?.setValidity&&(this.hasAttribute("required")&&!this.token?this.#h.setValidity({valueMissing:!0},this.getI18nText("required-label","Please verify you're human"),this.#s||this):this.#h.setValidity({}))}initialize(){m(),this.#d||(this.#d=this.#b()),this.#p||(this.#p=new b(1),this.#p._spawn())}attributeChangedCallback(e,t,i){if(e.startsWith("on")){const t=e.slice(2),s=this.#c.get(e);if(s&&this.removeEventListener(t,s),i){const i=t=>{const i=this.getAttribute(e);"function"==typeof window[i]&&window[i].call(this,t)};this.#c.set(e,i),this.addEventListener(t,i)}}"data-cap-worker-count"===e&&this.setWorkersCount(parseInt(i,10)),"data-cap-i18n-initial-state"===e&&this.#s&&this.#s?.querySelector(".label.active")&&this.animateLabel(this.getI18nText("initial-state","Verify you're human")),"required"===e&&this.#P()}async connectedCallback(){this.#o=this,this.shadowRoot?this.#i=this.shadowRoot:this.#i=this.attachShadow({mode:"open"}),this.#s||(this.#s=document.createElement("div")),this.#I(),this.createUI(),this.addEventListeners(),this.initialize(),this.#r.removeAttribute("disabled");const e=this.getAttribute("data-cap-worker-count"),t=e?parseInt(e,10):null;this.setWorkersCount(t||navigator.hardwareConcurrency||8),this.#o.innerHTML=`<input type="hidden" name="${this.#S}">`,s.debug(r(),`widget ready (workers=${this.#t}, haptics=${this.#m})`),this.#w(),this.#P(),this.addEventListener("invalid",this.#M)}#M=()=>{if(this.#s){try{this.scrollIntoView({behavior:"smooth",block:"center"})}catch{this.scrollIntoView()}this.#s.classList.remove("invalid"),this.#s.offsetWidth,this.#s.classList.add("invalid"),setTimeout(()=>this.#s?.classList.remove("invalid"),1500)}};async solve(){if(this.#l)return;this.#H();const e=performance.now();s.debug(r("solve"),"starting");try{this.#l=!0,this.updateUI("verifying",this.getI18nText("verifying-label","Verifying..."),!0),this.#r.setAttribute("aria-label",this.getI18nText("verifying-aria-label","Verifying you're a human, please wait")),this.dispatchEvent("progress",{progress:0});try{let t,i,l=this.getAttribute("data-cap-api-endpoint");if(!l&&window?.CAP_CUSTOM_FETCH)l="/";else if(!l)throw a("missing_endpoint","Missing API endpoint. Either custom fetch or an API endpoint must be provided.");if(l.endsWith("/")||(l+="/"),"done"===this.#d.state&&this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#L();if("done"===this.#d.state)t=this.#d.results,i=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100});else if("solving"===this.#d.state||"redeeming"===this.#d.state||"fetching"===this.#d.state||"waiting"===this.#d.state){"waiting"===this.#d.state&&(this.#u&&(clearTimeout(this.#u),this.#u=null),this.#d.state="waiting",this.#E()),this.#d.pendingPromotion=this.#t,this.#d.promoteFn&&this.#d.promoteFn(this.#t);const e=setInterval(()=>{const t=this.#d.state;if("done"===t||"error"===t)return void clearInterval(e);const i=this.#d.challenges?this.#d.challenges.length:1,s=this.#d.completedCount,r="redeeming"===t?99:"fetching"===t||"waiting"===t?0:Math.min(98,Math.round(s/i*100));this.dispatchEvent("progress",{progress:r})},150);if(await new Promise(e=>this.#d.onSettled(e)),clearInterval(e),"idle"===this.#d.state&&2===this.#d.challengeResp?.format&&Array.isArray(this.#d.challengeResp.challenges))i=this.#d.challengeResp,this.#d.challengeResp=null,t=await this.solveChallengesV2(i.challenges);else{if("done"!==this.#d.state)throw a("solve_failed","Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");if(this.#d.token&&this.#d.tokenExpires&&Date.now()<this.#d.tokenExpires)return this.#L();t=this.#d.results,i=this.#d.challengeResp,this.dispatchEvent("progress",{progress:100})}}else{const e=this.#d.challengeResp;if(2===e?.format&&Array.isArray(e.challenges))i=e,this.#d.challengeResp=null;else{const e=await o(`${l}challenge`,{method:"POST"});try{i=await e.json()}catch{throw a("challenge_parse_error","Failed to parse challenge response from server")}if(i.error)throw a("network_error",i.error)}if(2===i.format&&Array.isArray(i.challenges))t=await this.solveChallengesV2(i.challenges);else{const{challenge:e,token:s}=i;let r=e;if(!Array.isArray(r)){let t=0;r=Array.from({length:e.c},()=>(t++,[h(`${s}${t}`,e.s),h(`${s}${t}d`,e.d)]))}t=await this.solveChallenges(r)}}const c=i.instrumentation?u(i.instrumentation):Promise.resolve(null),d=await c;if(d?.__timeout||d?.__blocked){o(`${l}redeem`,{method:"POST",body:JSON.stringify({token:i.token,solutions:t,...d.__blocked&&{instr_blocked:!0},...d.__timeout&&{instr_timeout:!0}}),headers:{"Content-Type":"application/json"}}).catch(()=>{}),this.updateUIBlocked(this.getI18nText("error-label","Error"),d?.__blocked),this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again"));const e=d?.__blocked?"instr_blocked":"instr_timeout",n=d?.__blocked?`Instrumentation blocked (${d.blockReason||"automated_browser"})`:"Instrumentation timed out";this.removeEventListener("error",this.boundHandleError);const a=new CustomEvent("error",{bubbles:!0,composed:!0,detail:{isCap:!0,code:e,message:n}});return super.dispatchEvent(a),this.addEventListener("error",this.boundHandleError),this.executeAttributeCode("onerror",a),s.error(r("instr"),`[${e}] ${n}`),void(this.#l=!1)}const{token:p}=i,g=await o(`${l}redeem`,{method:"POST",body:JSON.stringify({token:p,solutions:t,...d&&{instr:d}}),headers:{"Content-Type":"application/json"}});let v;try{v=await g.json()}catch{throw a("redeem_failed","Failed to parse server response")}if(this.dispatchEvent("progress",{progress:100}),!v.success)throw a("invalid_solution",v.error||"Invalid solution");this.#T(v.token),this.dispatchEvent("solve",{token:v.token}),this.token=v.token,this.#f(),this.#e&&clearTimeout(this.#e);const m=new Date(v.expires).getTime()-Date.now();return m>0&&m<864e5?this.#e=setTimeout(()=>this.reset(),m):this.error("Invalid expiration time","invalid_expires"),this.#r.setAttribute("aria-label",this.getI18nText("verified-aria-label","We have verified you're a human, you may now continue")),this.#m&&navigator.vibrate([10,50,20,30,40]),s.debug(r("solve"),`verified in ${n(e)}`),this.#_(),{success:!0,token:this.token}}catch(e){throw this.#r.setAttribute("aria-label",this.getI18nText("error-aria-label","An error occurred, please try again")),this.error(e.message,e.code||"solve_failed"),e}}finally{this.#l=!1}}async solveChallengesV2(e){const t=e.length;let i=0;const n=new Array(e.length);for(let t=0;t<e.length;t++){const i=e[t];if(!i||"object"!=typeof i||"sha256-pow"!==i.protocol&&"rsw"!==i.protocol&&"instrumentation"!==i.protocol)throw a("challenge_unsupported",`unsupported format-2 protocol '${i?.protocol}'`)}let o=null;if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate)try{o=await g()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}const l=Math.max(1,Math.min(this.#t,e.length)),c=new b(l);c.setWasm(o),c._ensureSize(l);const h=(e,t)=>Promise.race([e,new Promise((e,i)=>setTimeout(()=>i(new Error(`[cap] ${t} timed out after 60000ms`)),6e4))]),d=new Array(e.length).fill(0),p=()=>{const e=d.reduce((e,t)=>e+t,0)+i,s=Math.min(99,Math.round(e/t*100));this.dispatchEvent("progress",{progress:s})};try{await Promise.all(e.map((e,t)=>"sha256-pow"===e.protocol?h(c.run(e.payload.salt,e.payload.target),`sha256-pow worker #${t}`).then(e=>{n[t]={nonce:Number(e)},d[t]=0,i++,p()}):"rsw"===e.protocol?h(c.runMsg({kind:"rsw",N:e.payload.N,x:e.payload.x,t:0|e.payload.t},e=>{d[t]=e,p()}),`rsw worker #${t}`).then(e=>{n[t]={y:e.y},d[t]=0,i++,p()}):u(e.payload.blob).then(e=>{n[t]=e?.__timeout?{timeout:!0}:e?.__blocked?{blocked:!0}:{instr:e},d[t]=0,i++,p()})))}finally{c.terminate()}return n}async solveChallenges(e){const t=e.length;let i=0;let n=null;const a="object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate;if(a)try{n=await g()}catch(e){s.warn(r("wasm"),"unavailable, falling back to JS solver:",e.message||e)}if(!a&&(s.warn(r("wasm"),"WebAssembly disabled in this browser, solver will be ~10x slower"),!this.#i.querySelector(".warning"))){const e=document.createElement("div");e.className="warning",e.style.cssText="width:var(--cap-widget-width,230px);background:rgb(237,56,46);color:white;padding:4px 6px;padding-bottom:calc(var(--cap-border-radius,14px) + 5px);font-size:10px;box-sizing:border-box;font-family:system-ui;border-top-left-radius:8px;border-top-right-radius:8px;text-align:center;user-select:none;margin-bottom:-35.5px;opacity:0;transition:margin-bottom .3s,opacity .3s;",e.innerText=this.getI18nText("wasm-disabled","Enable WASM for significantly faster solving"),this.#i.insertBefore(e,this.#i.firstChild),setTimeout(()=>{e.style.marginBottom="calc(-1 * var(--cap-border-radius, 14px))",e.style.opacity=1},10)}const o=new b(this.#t);o.setWasm(n),o._ensureSize(this.#t);const l=[];try{for(let s=0;s<e.length;s+=this.#t){const r=e.slice(s,Math.min(s+this.#t,e.length)),n=await Promise.all(r.map(([e,s])=>o.run(e,s).then(e=>{i++;const s=Math.min(99,Math.round((0+i)/t*100));return this.dispatchEvent("progress",{progress:s}),e})));l.push(...n)}}finally{o.terminate()}return l}setWorkersCount(e){const t=parseInt(e,10),i=Math.min(navigator.hardwareConcurrency||8,16);this.#t=!Number.isNaN(t)&&t>0&&t<=i?t:navigator.hardwareConcurrency||8}createUI(){this.#s.classList.add("captcha"),this.#s.setAttribute("role","group"),this.#s.setAttribute("aria-label",this.getI18nText("group-aria-label","Cap verification")),this.#r=document.createElement("div"),this.#r.className="captcha-trigger",this.#r.setAttribute("part","trigger"),this.#r.setAttribute("role","button"),this.#r.setAttribute("tabindex","0"),this.#r.setAttribute("aria-label",this.getI18nText("verify-aria-label","Click to verify you're a human")),this.#r.setAttribute("aria-live","polite"),this.#r.setAttribute("disabled","true"),this.#r.innerHTML=`<div class="checkbox" part="checkbox" aria-hidden="true"><svg class="progress-ring" viewBox="0 0 32 32" aria-hidden="true"><circle class="progress-ring-bg" cx="16" cy="16" r="14"></circle><circle class="progress-ring-circle" cx="16" cy="16" r="14"></circle></svg></div><p part="label" class="label-wrapper"><span class="label active">${this.getI18nText("initial-state","Verify you're human")}</span></p>`,this.#s.appendChild(this.#r),this.#a=document.createElement("a"),this.#a.className="cap-troubleshoot-link",this.#a.setAttribute("part","troubleshoot"),this.#a.setAttribute("target","_blank"),this.#a.setAttribute("rel","noopener"),this.#a.hidden=!0,this.#s.appendChild(this.#a),this.#n=document.createElement("a"),this.#n.className="credits",this.#n.setAttribute("aria-label","Secured by Cap"),this.#n.setAttribute("href","https://trycap.dev"),this.#n.setAttribute("target","_blank"),this.#n.setAttribute("title","Secured by Cap: The self-hosted CAPTCHA for the modern web."),this.#n.textContent="Cap",this.#s.appendChild(this.#n),this.#i.innerHTML=`<style${window.CAP_CSS_NONCE?` nonce=${window.CAP_CSS_NONCE}`:""}>:host{display:inline-block}@media (prefers-reduced-motion:reduce){.captcha,.captcha *{transition:none!important;animation:none!important}.label{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.label:not(.active),.label.exit{display:none!important}}.captcha,.captcha *{box-sizing:border-box}.captcha{width:var(--cap-widget-width,260px);height:var(--cap-widget-height,58px);background-color:var(--cap-background,#fdfdfd);border:1px solid var(--cap-border-color,#dddddd8f);border-radius:var(--cap-border-radius,14px);-webkit-user-select:none;user-select:none;cursor:pointer;-webkit-tap-highlight-color:#fff0;color:var(--cap-color,#212121);font-family:var(--cap-font,system, -apple-system, "BlinkMacSystemFont", ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", "Ubuntu", "arial", sans-serif);transition:filter .2s,transform .2s,height .2s;display:inline-block;position:relative;overflow:hidden}.captcha.has-troubleshoot{height:calc(var(--cap-widget-height,58px) + 26px)}.captcha.has-troubleshoot .captcha-trigger{inset-block-end:26px}.captcha:not([data-state]):active{transform:scale(.97)}.captcha:hover{filter:brightness(98%)}.captcha-trigger{padding:var(--cap-widget-padding,14px);align-items:center;gap:var(--cap-gap,15px);border-radius:inherit;transition:inset .2s;display:flex;position:absolute;inset:0}.captcha-trigger:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:-3px}.checkbox{width:var(--cap-checkbox-size,25px);height:var(--cap-checkbox-size,25px);border:var(--cap-checkbox-border,1px solid #aaaaaad1);border-radius:var(--cap-checkbox-border-radius,6px);background-color:var(--cap-checkbox-background,#fafafa91);margin-top:var(--cap-checkbox-margin,2px);margin-bottom:var(--cap-checkbox-margin,2px);flex-shrink:0;transition:opacity .2s}.captcha p{-webkit-user-select:none;user-select:none;margin:0;font-size:15px;font-weight:500}.label-wrapper{flex:1;align-items:center;min-width:0;height:2em;display:flex;position:relative;overflow:hidden}.label-wrapper:before,.label-wrapper:after{content:"";pointer-events:none;z-index:1;width:100%;height:.6em;position:absolute;inset-inline-start:0}.label-wrapper:before{background:linear-gradient(to bottom, var(--cap-background,#fdfdfd), transparent);top:0}.label-wrapper:after{background:linear-gradient(to top, var(--cap-background,#fdfdfd), transparent);bottom:0}.label{white-space:nowrap;opacity:0;filter:blur(2px);transition:transform .5s cubic-bezier(.25,1,.5,1),opacity .5s,filter .5s;position:absolute;transform:translateY(100%)}.label.active{opacity:1;filter:none;transform:translateY(0)}.label.exit{opacity:0;filter:blur(2px);transform:translateY(-100%)}.checkbox .progress-ring{width:100%;height:100%;display:none;transform:rotate(-90deg)}.checkbox .progress-ring-bg{fill:none;stroke:var(--cap-spinner-background-color,#eee);stroke-width:var(--cap-spinner-thickness,3)}.checkbox .progress-ring-circle{fill:none;stroke:var(--cap-spinner-color,#000);stroke-width:var(--cap-spinner-thickness,3);stroke-linecap:round;stroke-dasharray:87.96;stroke-dashoffset:87.96px;transition:stroke-dashoffset .3s}.captcha[data-state=verifying] .checkbox{background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;display:flex;transform:scale(1.1)}.captcha[data-state=verifying] .checkbox .progress-ring{display:block}.captcha[data-state=done] .checkbox{background-image:var(--cap-checkmark,url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E));background-size:cover;border:1px solid #0000}.captcha[data-state=done] .checkbox .progress-ring{display:none}.captcha[data-state=error] .checkbox{background-image:var(--cap-error-cross,url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C%2Fsvg%3E"));background-size:cover;border:1px solid #0000}.captcha[data-state=error] .checkbox .progress-ring{display:none}.captcha.invalid{border-color:var(--cap-invalid-border-color,#f55b50);box-shadow:0 0 0 3px var(--cap-invalid-ring-color,#f55b5033);animation:.5s cubic-bezier(.36,.07,.19,.97) cap-shake}@keyframes cap-shake{10%,90%{transform:translate(-1px)}20%,80%{transform:translate(2px)}30%,50%,70%{transform:translate(-4px)}40%,60%{transform:translate(4px)}}@media (prefers-reduced-motion:reduce){.captcha.invalid{animation:none!important}}.captcha-trigger[disabled]{cursor:not-allowed}.captcha[data-state=verifying] .captcha-trigger{cursor:progress}.captcha[data-state=done] .captcha-trigger{cursor:default}.credits{color:var(--cap-color,#212121);text-underline-offset:.18em;z-index:2;border-radius:4px;justify-content:flex-end;align-items:center;min-width:24px;min-height:24px;padding:4px 6px;text-decoration:underline;text-decoration-thickness:.08em;position:absolute;inset-block-end:4px;inset-inline-end:4px;opacity:.8!important;font-size:12px!important;display:inline-flex!important}.captcha .credits{visibility:visible!important;pointer-events:all!important;display:inline-flex!important}.credits:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px;opacity:1!important}.cap-troubleshoot-link{min-width:24px;min-height:24px;color:var(--cap-troubleshoot-color,#0050a0);text-underline-offset:.15em;cursor:pointer;z-index:2;border-radius:4px;align-items:center;padding:4px 6px;font-size:13px;font-weight:500;text-decoration:underline;text-decoration-thickness:.08em;display:inline-flex;position:absolute;inset-block-end:4px;inset-inline-start:14px}.cap-troubleshoot-link[hidden]{display:none}.cap-troubleshoot-link:hover{opacity:.85}.cap-troubleshoot-link:focus-visible{outline:2px solid var(--cap-focus-ring,#06c);outline-offset:2px}@media (forced-colors:active){.captcha,.checkbox{border-color:canvastext}:is(.captcha-trigger:focus-visible,.credits:focus-visible,.cap-troubleshoot-link:focus-visible){outline-color:highlight}.progress-ring-bg{stroke:graytext}.progress-ring-circle{stroke:canvastext}.captcha.invalid{box-shadow:none;border-color:mark}.credits{opacity:1!important}}</style>`,this.#i.appendChild(this.#s),this.#H(),setTimeout(()=>this.#H(),100)}addEventListeners(){this.#r&&(this.#n.addEventListener("click",e=>{e.preventDefault(),window.open(`https://trycap.dev/?${new URLSearchParams({utm_source:"cap_widget",utm_medium:"referral",utm_campaign:"widget",utm_content:window.CAP_DISABLE_WIDGET_REF?"":location.hostname,ref:window.CAP_DISABLE_WIDGET_REF?"":location.href||"",sub:window.CAP_DISABLE_WIDGET_REF?"":document.referrer||""}).toString()}`,"_blank")}),this.#r.addEventListener("click",()=>{this.#r.hasAttribute("disabled")||this.solve()}),this.#r.addEventListener("mousedown",()=>{!this.#r.hasAttribute("disabled")&&this.#m&&navigator.vibrate(5)}),this.#r.addEventListener("keydown",e=>{e.target===this.#r&&("Enter"!==e.key&&" "!==e.key||this.#r.hasAttribute("disabled")||(e.preventDefault(),e.stopPropagation(),this.solve()))}),this.addEventListener("progress",this.boundHandleProgress),this.addEventListener("solve",this.boundHandleSolve),this.addEventListener("error",this.boundHandleError),this.addEventListener("reset",this.boundHandleReset))}#$(){if(!this.#o)return!1;const e=this.#o.getBoundingClientRect();if(0===e.width&&0===e.height)return!0;const t=window.getComputedStyle(this.#o);return"none"===t.display||"hidden"===t.visibility}#H(){this.#n&&this.#s&&!this.#$()&&(this.#n.isConnected&&this.#n.parentNode===this.#s||this.#s.appendChild(this.#n),this.#n.textContent&&this.#n.textContent.trim()||(this.#n.textContent="Cap"),"https://trycap.dev"!==this.#n.getAttribute("href")&&this.#n.setAttribute("href","https://trycap.dev"),this.#n.style.cssText=["display: inline-flex !important","visibility: visible !important","opacity: 0.8 !important","pointer-events: all !important","font-size: 12px !important","transform: none !important","clip-path: none !important","filter: none !important","position: absolute !important"].join("; "))}animateLabel(e){if(!this.#r)return;const t=this.#r.querySelector(".label-wrapper");if(!t)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches){const i=t.querySelector(".label.active");if(i)i.textContent=e;else{const i=document.createElement("span");i.className="label active",i.textContent=e,t.appendChild(i)}return}const i=t.querySelector(".label.active"),s=document.createElement("span");s.className="label",s.textContent=e,t.appendChild(s),s.offsetWidth,s.classList.add("active"),i&&(i.classList.remove("active"),i.classList.add("exit"),i.addEventListener("transitionend",()=>i.remove(),{once:!0}))}updateUI(e,t,i=!1){this.#s&&this.#r&&(this.#s.setAttribute("data-state",e),this.#s.classList.remove("has-troubleshoot"),this.animateLabel(t),this.#a&&(this.#a.hidden=!0),i?this.#r.setAttribute("disabled","true"):this.#r.removeAttribute("disabled"))}updateUIBlocked(e,t=!1){if(this.#s&&this.#r&&(this.#s.setAttribute("data-state","error"),this.#r.removeAttribute("disabled"),this.animateLabel(e),this.#a))if(t){const e=this.getAttribute("data-cap-troubleshooting-url")||"https://trycap.dev/guide/troubleshooting/instrumentation.html";this.#a.setAttribute("href",e),this.#a.textContent=this.getI18nText("troubleshooting-label","Troubleshoot"),this.#a.hidden=!1,this.#s.classList.add("has-troubleshoot")}else this.#a.hidden=!0,this.#s.classList.remove("has-troubleshoot")}handleProgress(e){if(!this.#r)return;const t=this.#r.querySelector(".progress-ring-circle");if(t){const i=2*Math.PI*14,s=i-e.detail.progress/100*i;t.style.strokeDashoffset=s}const i=this.#r.querySelector(".label-wrapper");if(i){const e=i.querySelector(".label.active");e&&(e.textContent=`${this.getI18nText("verifying-label","Verifying...")}`)}this.executeAttributeCode("onprogress",e)}handleSolve(e){this.updateUI("done",this.getI18nText("solved-label","You're a human"),!0),this.executeAttributeCode("onsolve",e),this.#h?.setValidity?.({}),this.#s?.classList.remove("invalid")}handleError(e){this.updateUI("error",this.getI18nText("error-label","Error. Try again.")),this.executeAttributeCode("onerror",e),this.#m&&navigator.vibrate([10,40,10])}handleReset(e){this.updateUI("",this.getI18nText("initial-state","I'm a human")),this.executeAttributeCode("onreset",e),this.#P()}executeAttributeCode(e,t){const i=this.getAttribute(e);i&&(s.warn(r(),"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead."),new Function("event",i).call(this,t))}error(e="Unknown error",t="unknown"){s.error(r("solve"),`[${t}] ${e}`),this.dispatchEvent("error",{isCap:!0,code:t,message:e})}dispatchEvent(e,t={}){const i=new CustomEvent(e,{bubbles:!0,composed:!0,detail:t});super.dispatchEvent(i)}reset(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.token=null,this.dispatchEvent("reset"),this.#T("")}get tokenValue(){return this.token}disconnectedCallback(){this.removeEventListener("progress",this.boundHandleProgress),this.removeEventListener("solve",this.boundHandleSolve),this.removeEventListener("error",this.boundHandleError),this.removeEventListener("reset",this.boundHandleReset),this.#c.forEach((e,t)=>{this.removeEventListener(t.slice(2),e)}),this.#c.clear(),this.#i&&(this.#i.innerHTML=""),this.reset(),this.cleanup()}cleanup(){this.#e&&(clearTimeout(this.#e),this.#e=null),this.#y(),this.#u&&(clearTimeout(this.#u),this.#u=null),this.#p&&(this.#p.terminate(),this.#p=null),this.#d&&(this.#d.state="error",this.#d.notify(),this.#d=null)}}class w{constructor(e={},t){const i=t||document.createElement("cap-widget");if(Object.entries(e).forEach(([e,t])=>{i.setAttribute(e,t)}),!e.apiEndpoint&&!window?.CAP_CUSTOM_FETCH)throw i.remove(),new Error("Missing API endpoint. Either custom fetch or an API endpoint must be provided.");e.apiEndpoint&&i.setAttribute("data-cap-api-endpoint",e.apiEndpoint),t||i.hasAttribute("data-cap-disable-haptics")||i.setAttribute("data-cap-disable-haptics",""),this.widget=i,this.solve=this.widget.solve.bind(this.widget),this.reset=this.widget.reset.bind(this.widget),this.addEventListener=this.widget.addEventListener.bind(this.widget),Object.defineProperty(this,"token",{get:()=>i.token,configurable:!0,enumerable:!0}),t||(i.style.display="none",document.documentElement.appendChild(i))}}window.Cap=w,customElements.get("cap-widget")||window?.CAP_DONT_SKIP_REDEFINE?customElements.get("cap-widget")&&s.warn(r(),"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override"):customElements.define("cap-widget",f),"object"==typeof exports&&"undefined"!=typeof module?module.exports=w:"function"==typeof define&&define.amd&&define([],()=>w),"undefined"!=typeof exports&&(exports.default=w)})();
|
package/package.json
CHANGED
package/src/cap.css
CHANGED
package/src/cap.js
CHANGED
|
@@ -8,6 +8,31 @@
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
const _ctp = ["#f5c2e7","#cba6f7","#f38ba8","#fab387","#f9e2af","#a6e3a1","#94e2d5","#89dceb","#b4befe"];
|
|
12
|
+
const _bg = (s) => {
|
|
13
|
+
if (s === "cap") return "#89b4fa";
|
|
14
|
+
let h = 0;
|
|
15
|
+
for (let i = 0; i < s.length; i++) h = s.charCodeAt(i) + ((h << 5) - h);
|
|
16
|
+
return _ctp[Math.abs(h) % _ctp.length];
|
|
17
|
+
};
|
|
18
|
+
const _style = (t, i, n) => {
|
|
19
|
+
const l = i === 0 ? "9999px" : "0";
|
|
20
|
+
const r = i === n - 1 ? "9999px" : "0";
|
|
21
|
+
return `color:#1e1e2e;background:${_bg(t)};margin-left:${i ? "-6px" : 0};padding:0 6px;border-radius:${l} ${r} ${r} ${l};font-weight:600`;
|
|
22
|
+
};
|
|
23
|
+
const log = {};
|
|
24
|
+
for (const lvl of ["debug", "info", "warn", "error"]) {
|
|
25
|
+
log[lvl] = (tags, ...args) => {
|
|
26
|
+
if (window.CAP_SILENT || (lvl === "debug" && !window.CAP_DEBUG)) return;
|
|
27
|
+
const fmt = tags.map((t) => `%c${t}`).join(" ");
|
|
28
|
+
const styles = tags.map((t, i) => _style(t, i, tags.length));
|
|
29
|
+
console[lvl === "debug" ? "log" : lvl](fmt, ...styles, ...args);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const T = (sub) => (sub ? ["cap", sub] : ["cap"]);
|
|
33
|
+
const since = (t) => `${Math.round(performance.now() - t)}ms`;
|
|
34
|
+
const _err = (code, message) => Object.assign(new Error(message), { code });
|
|
35
|
+
|
|
11
36
|
const capFetch = (u, conf = {}) => {
|
|
12
37
|
if (window?.CAP_CUSTOM_FETCH) {
|
|
13
38
|
return window.CAP_CUSTOM_FETCH(u, conf);
|
|
@@ -16,6 +41,33 @@
|
|
|
16
41
|
return fetch(u, conf);
|
|
17
42
|
};
|
|
18
43
|
|
|
44
|
+
const I18N_KEYS = "%%i18nKeys%%".split(",");
|
|
45
|
+
const I18N_ROWS = %%i18nData%%;
|
|
46
|
+
|
|
47
|
+
function _resolveI18nMap(forced) {
|
|
48
|
+
const prefs = forced
|
|
49
|
+
? [forced]
|
|
50
|
+
: navigator.languages || [navigator.language || ""];
|
|
51
|
+
for (let pref of prefs) {
|
|
52
|
+
if (!pref) continue;
|
|
53
|
+
pref = pref.toLowerCase();
|
|
54
|
+
if (pref === "en" || pref.startsWith("en-")) return null;
|
|
55
|
+
const code = I18N_ROWS[pref]
|
|
56
|
+
? pref
|
|
57
|
+
: I18N_ROWS[pref.split("-")[0]]
|
|
58
|
+
? pref.split("-")[0]
|
|
59
|
+
: null;
|
|
60
|
+
if (!code) return null;
|
|
61
|
+
const parts = I18N_ROWS[code].split("/");
|
|
62
|
+
const map = {};
|
|
63
|
+
I18N_KEYS.forEach((k, i) => {
|
|
64
|
+
map[k] = parts[i];
|
|
65
|
+
});
|
|
66
|
+
return map;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
19
71
|
function prng(seed, length) {
|
|
20
72
|
function fnv1a(str) {
|
|
21
73
|
let hash = 2166136261;
|
|
@@ -78,17 +130,18 @@
|
|
|
78
130
|
const url =
|
|
79
131
|
window.CAP_PAKO_URL ||
|
|
80
132
|
"https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako_inflate.min.js";
|
|
133
|
+
log.debug(T("instr"), "DecompressionStream unavailable, loading pako from", url);
|
|
81
134
|
const script = document.createElement("script");
|
|
82
135
|
script.src = url;
|
|
83
136
|
const pakoNonce = window.CAP_SCRIPT_NONCE || window.CAP_CSS_NONCE;
|
|
84
137
|
if (pakoNonce) script.setAttribute("nonce", pakoNonce);
|
|
85
138
|
script.onload = () => {
|
|
86
139
|
if (window.pako?.inflateRaw) resolve(window.pako);
|
|
87
|
-
else reject(new Error("
|
|
140
|
+
else reject(new Error("pako loaded but inflateRaw is missing"));
|
|
88
141
|
};
|
|
89
142
|
script.onerror = () => {
|
|
90
143
|
_pakoPromise = null;
|
|
91
|
-
reject(new Error(`
|
|
144
|
+
reject(new Error(`failed to load pako fallback from ${url}`));
|
|
92
145
|
};
|
|
93
146
|
document.head.appendChild(script);
|
|
94
147
|
});
|
|
@@ -178,14 +231,21 @@
|
|
|
178
231
|
window.CAP_CUSTOM_WASM_URL ||
|
|
179
232
|
`https://cdn.jsdelivr.net/npm/@cap.js/wasm@${WASM_VERSION}/browser/cap_wasm_bg.wasm`;
|
|
180
233
|
|
|
234
|
+
const t0 = performance.now();
|
|
235
|
+
log.debug(T("wasm"), "fetching", wasmUrl);
|
|
181
236
|
wasmModulePromise = fetch(wasmUrl)
|
|
182
237
|
.then((r) => {
|
|
183
238
|
if (!r.ok) throw new Error(`Failed to fetch wasm: ${r.status}`);
|
|
184
239
|
return r.arrayBuffer();
|
|
185
240
|
})
|
|
186
241
|
.then((buf) => WebAssembly.compile(buf))
|
|
242
|
+
.then((mod) => {
|
|
243
|
+
log.debug(T("wasm"), `ready in ${since(t0)}`);
|
|
244
|
+
return mod;
|
|
245
|
+
})
|
|
187
246
|
.catch((e) => {
|
|
188
247
|
wasmModulePromise = null;
|
|
248
|
+
log.warn(T("wasm"), `load failed (${since(t0)}):`, e.message || e);
|
|
189
249
|
throw e;
|
|
190
250
|
});
|
|
191
251
|
|
|
@@ -251,8 +311,9 @@
|
|
|
251
311
|
} catch {}
|
|
252
312
|
|
|
253
313
|
this._spawnFailures++;
|
|
314
|
+
log.warn(T("pool"), `worker died, replacing (attempt ${this._spawnFailures}/3)`);
|
|
254
315
|
if (this._spawnFailures > 3) {
|
|
255
|
-
|
|
316
|
+
log.error(T("pool"), "worker spawn failed repeatedly, giving up");
|
|
256
317
|
return null;
|
|
257
318
|
}
|
|
258
319
|
|
|
@@ -367,6 +428,7 @@
|
|
|
367
428
|
#speculativeTimer = null;
|
|
368
429
|
#speculativePool = null;
|
|
369
430
|
#interactionHandler = null;
|
|
431
|
+
#i18n = null;
|
|
370
432
|
|
|
371
433
|
get #hasHaptics() {
|
|
372
434
|
return (
|
|
@@ -438,10 +500,13 @@
|
|
|
438
500
|
checkVisibilityCSS: true,
|
|
439
501
|
});
|
|
440
502
|
}
|
|
441
|
-
// Fallback: offsetParent is null for display:none; also check the style directly
|
|
442
503
|
return !!(this.offsetParent || this.getClientRects().length > 0);
|
|
443
504
|
}
|
|
444
505
|
|
|
506
|
+
#logInvisible() {
|
|
507
|
+
if (!this.#isVisible()) log.info(T("challenges"), "solved invisible challenge");
|
|
508
|
+
}
|
|
509
|
+
|
|
445
510
|
#onFirstInteraction() {
|
|
446
511
|
if (this.#speculative.state !== "idle") return;
|
|
447
512
|
if (!this.#isVisible()) return;
|
|
@@ -454,6 +519,7 @@
|
|
|
454
519
|
async #beginSpeculativeSolve() {
|
|
455
520
|
if (this.#speculative.state !== "waiting") return;
|
|
456
521
|
this.#speculative.state = "fetching";
|
|
522
|
+
this.#speculative._t0 = performance.now();
|
|
457
523
|
|
|
458
524
|
let apiEndpoint = this.getAttribute("data-cap-api-endpoint");
|
|
459
525
|
if (!apiEndpoint && window?.CAP_CUSTOM_FETCH) {
|
|
@@ -502,8 +568,7 @@
|
|
|
502
568
|
this.#speculative.state = "solving";
|
|
503
569
|
|
|
504
570
|
this.#speculative.solvePromise = this.#speculativeSolveAll(challenges);
|
|
505
|
-
} catch
|
|
506
|
-
console.warn("[cap] speculative challenge fetch failed:", e);
|
|
571
|
+
} catch {
|
|
507
572
|
this.#speculative.state = "error";
|
|
508
573
|
this.#speculative.notify();
|
|
509
574
|
}
|
|
@@ -590,7 +655,7 @@
|
|
|
590
655
|
const challengeResp = this.#speculative.challengeResp;
|
|
591
656
|
const apiEndpoint = challengeResp._apiEndpoint;
|
|
592
657
|
if (!apiEndpoint)
|
|
593
|
-
throw
|
|
658
|
+
throw _err("missing_endpoint", "speculative redeem: missing apiEndpoint");
|
|
594
659
|
|
|
595
660
|
let instrOut = null;
|
|
596
661
|
if (challengeResp.instrumentation) {
|
|
@@ -627,19 +692,63 @@
|
|
|
627
692
|
this.#speculative.token = resp.token;
|
|
628
693
|
this.#speculative.tokenExpires = new Date(resp.expires).getTime();
|
|
629
694
|
this.#speculative.state = "done";
|
|
695
|
+
this.#speculative._invisibleElapsed = this.#speculative._t0 ? since(this.#speculative._t0) : "?";
|
|
630
696
|
this.#speculative.notify();
|
|
631
|
-
} catch
|
|
632
|
-
console.warn(
|
|
633
|
-
"[cap] speculative redeem failed (will redo on click):",
|
|
634
|
-
e,
|
|
635
|
-
);
|
|
697
|
+
} catch {
|
|
636
698
|
this.#speculative.state = "done";
|
|
637
699
|
this.#speculative.notify();
|
|
638
700
|
}
|
|
639
701
|
}
|
|
640
702
|
|
|
703
|
+
get #fieldName() {
|
|
704
|
+
return this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
#setToken(value) {
|
|
708
|
+
const input = this.querySelector(`input[name='${this.#fieldName}']`);
|
|
709
|
+
if (input) input.value = value;
|
|
710
|
+
}
|
|
711
|
+
|
|
641
712
|
getI18nText(key, defaultValue) {
|
|
642
|
-
return
|
|
713
|
+
return (
|
|
714
|
+
this.getAttribute(`data-cap-i18n-${key}`) ||
|
|
715
|
+
this.#i18n?.[key] ||
|
|
716
|
+
defaultValue
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
#commitSpeculativeToken() {
|
|
721
|
+
log.debug(T("solve"), `served from speculative cache (saved ${this.#speculative._invisibleElapsed || "?"})`);
|
|
722
|
+
this.dispatchEvent("progress", { progress: 100 });
|
|
723
|
+
|
|
724
|
+
this.#setToken(this.#speculative.token);
|
|
725
|
+
|
|
726
|
+
this.dispatchEvent("solve", { token: this.#speculative.token });
|
|
727
|
+
this.token = this.#speculative.token;
|
|
728
|
+
|
|
729
|
+
const expiresIn = this.#speculative.tokenExpires - Date.now();
|
|
730
|
+
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
731
|
+
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
732
|
+
|
|
733
|
+
this.#trigger.setAttribute(
|
|
734
|
+
"aria-label",
|
|
735
|
+
this.getI18nText(
|
|
736
|
+
"verified-aria-label",
|
|
737
|
+
"We have verified you're a human, you may now continue",
|
|
738
|
+
),
|
|
739
|
+
);
|
|
740
|
+
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
741
|
+
|
|
742
|
+
this.#logInvisible();
|
|
743
|
+
this.#resetSpeculativeState();
|
|
744
|
+
this.#solving = false;
|
|
745
|
+
return { success: true, token: this.token };
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
#resolveI18n() {
|
|
749
|
+
this.#i18n = _resolveI18nMap(
|
|
750
|
+
window.CAP_LANG || this.getAttribute("data-cap-lang"),
|
|
751
|
+
);
|
|
643
752
|
}
|
|
644
753
|
|
|
645
754
|
static get observedAttributes() {
|
|
@@ -746,6 +855,7 @@
|
|
|
746
855
|
}
|
|
747
856
|
|
|
748
857
|
if (!this.#div) this.#div = document.createElement("div");
|
|
858
|
+
this.#resolveI18n();
|
|
749
859
|
this.createUI();
|
|
750
860
|
this.addEventListeners();
|
|
751
861
|
this.initialize();
|
|
@@ -754,10 +864,9 @@
|
|
|
754
864
|
const workers = this.getAttribute("data-cap-worker-count");
|
|
755
865
|
const parsedWorkers = workers ? parseInt(workers, 10) : null;
|
|
756
866
|
this.setWorkersCount(parsedWorkers || navigator.hardwareConcurrency || 8);
|
|
757
|
-
|
|
758
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
759
|
-
this.#host.innerHTML = `<input type="hidden" name="${fieldName}">`;
|
|
867
|
+
this.#host.innerHTML = `<input type="hidden" name="${this.#fieldName}">`;
|
|
760
868
|
|
|
869
|
+
log.debug(T(), `widget ready (workers=${this.#workersCount}, haptics=${this.#hasHaptics})`);
|
|
761
870
|
this.#attachInteractionListeners();
|
|
762
871
|
this.#updateValidity();
|
|
763
872
|
|
|
@@ -782,6 +891,10 @@
|
|
|
782
891
|
return;
|
|
783
892
|
}
|
|
784
893
|
|
|
894
|
+
this.#enforceCredits();
|
|
895
|
+
const _solveT0 = performance.now();
|
|
896
|
+
log.debug(T("solve"), "starting");
|
|
897
|
+
|
|
785
898
|
try {
|
|
786
899
|
this.#solving = true;
|
|
787
900
|
this.updateUI(
|
|
@@ -803,7 +916,8 @@
|
|
|
803
916
|
if (!apiEndpoint && window?.CAP_CUSTOM_FETCH) {
|
|
804
917
|
apiEndpoint = "/";
|
|
805
918
|
} else if (!apiEndpoint) {
|
|
806
|
-
throw
|
|
919
|
+
throw _err(
|
|
920
|
+
"missing_endpoint",
|
|
807
921
|
"Missing API endpoint. Either custom fetch or an API endpoint must be provided.",
|
|
808
922
|
);
|
|
809
923
|
}
|
|
@@ -818,33 +932,7 @@
|
|
|
818
932
|
this.#speculative.tokenExpires &&
|
|
819
933
|
Date.now() < this.#speculative.tokenExpires
|
|
820
934
|
) {
|
|
821
|
-
this
|
|
822
|
-
|
|
823
|
-
const fieldName =
|
|
824
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
825
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
826
|
-
this.querySelector(`input[name='${fieldName}']`).value =
|
|
827
|
-
this.#speculative.token;
|
|
828
|
-
}
|
|
829
|
-
this.dispatchEvent("solve", { token: this.#speculative.token });
|
|
830
|
-
this.token = this.#speculative.token;
|
|
831
|
-
|
|
832
|
-
const expiresIn = this.#speculative.tokenExpires - Date.now();
|
|
833
|
-
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
834
|
-
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
835
|
-
|
|
836
|
-
this.#trigger.setAttribute(
|
|
837
|
-
"aria-label",
|
|
838
|
-
this.getI18nText(
|
|
839
|
-
"verified-aria-label",
|
|
840
|
-
"We have verified you're a human, you may now continue",
|
|
841
|
-
),
|
|
842
|
-
);
|
|
843
|
-
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
844
|
-
|
|
845
|
-
this.#resetSpeculativeState();
|
|
846
|
-
this.#solving = false;
|
|
847
|
-
return { success: true, token: this.token };
|
|
935
|
+
return this.#commitSpeculativeToken();
|
|
848
936
|
}
|
|
849
937
|
|
|
850
938
|
if (this.#speculative.state === "done") {
|
|
@@ -905,7 +993,7 @@
|
|
|
905
993
|
solutions = await this.solveChallengesV2(challengeResp.challenges);
|
|
906
994
|
} else {
|
|
907
995
|
if (this.#speculative.state !== "done") {
|
|
908
|
-
throw
|
|
996
|
+
throw _err("solve_failed", "Unable to solve challenge, self-hosted instance likely down. This is not an issue with Cap.");
|
|
909
997
|
}
|
|
910
998
|
|
|
911
999
|
if (
|
|
@@ -913,33 +1001,7 @@
|
|
|
913
1001
|
this.#speculative.tokenExpires &&
|
|
914
1002
|
Date.now() < this.#speculative.tokenExpires
|
|
915
1003
|
) {
|
|
916
|
-
this
|
|
917
|
-
|
|
918
|
-
const fieldName =
|
|
919
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
920
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
921
|
-
this.querySelector(`input[name='${fieldName}']`).value =
|
|
922
|
-
this.#speculative.token;
|
|
923
|
-
}
|
|
924
|
-
this.dispatchEvent("solve", { token: this.#speculative.token });
|
|
925
|
-
this.token = this.#speculative.token;
|
|
926
|
-
|
|
927
|
-
const expiresIn = this.#speculative.tokenExpires - Date.now();
|
|
928
|
-
if (this.#resetTimer) clearTimeout(this.#resetTimer);
|
|
929
|
-
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
930
|
-
|
|
931
|
-
this.#trigger.setAttribute(
|
|
932
|
-
"aria-label",
|
|
933
|
-
this.getI18nText(
|
|
934
|
-
"verified-aria-label",
|
|
935
|
-
"We have verified you're a human, you may now continue",
|
|
936
|
-
),
|
|
937
|
-
);
|
|
938
|
-
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
939
|
-
|
|
940
|
-
this.#resetSpeculativeState();
|
|
941
|
-
this.#solving = false;
|
|
942
|
-
return { success: true, token: this.token };
|
|
1004
|
+
return this.#commitSpeculativeToken();
|
|
943
1005
|
}
|
|
944
1006
|
|
|
945
1007
|
solutions = this.#speculative.results;
|
|
@@ -958,9 +1020,9 @@
|
|
|
958
1020
|
try {
|
|
959
1021
|
challengeResp = await challengeRaw.json();
|
|
960
1022
|
} catch {
|
|
961
|
-
throw
|
|
1023
|
+
throw _err("challenge_parse_error", "Failed to parse challenge response from server");
|
|
962
1024
|
}
|
|
963
|
-
if (challengeResp.error) throw
|
|
1025
|
+
if (challengeResp.error) throw _err("network_error", challengeResp.error);
|
|
964
1026
|
}
|
|
965
1027
|
|
|
966
1028
|
if (
|
|
@@ -1014,16 +1076,20 @@
|
|
|
1014
1076
|
"An error occurred, please try again",
|
|
1015
1077
|
),
|
|
1016
1078
|
);
|
|
1079
|
+
const instrCode = instrOut?.__blocked ? "instr_blocked" : "instr_timeout";
|
|
1080
|
+
const instrMsg = instrOut?.__blocked
|
|
1081
|
+
? `Instrumentation blocked (${instrOut.blockReason || "automated_browser"})`
|
|
1082
|
+
: "Instrumentation timed out";
|
|
1017
1083
|
this.removeEventListener("error", this.boundHandleError);
|
|
1018
1084
|
const errEvent = new CustomEvent("error", {
|
|
1019
1085
|
bubbles: true,
|
|
1020
1086
|
composed: true,
|
|
1021
|
-
detail: { isCap: true, message:
|
|
1087
|
+
detail: { isCap: true, code: instrCode, message: instrMsg },
|
|
1022
1088
|
});
|
|
1023
1089
|
super.dispatchEvent(errEvent);
|
|
1024
1090
|
this.addEventListener("error", this.boundHandleError);
|
|
1025
1091
|
this.executeAttributeCode("onerror", errEvent);
|
|
1026
|
-
|
|
1092
|
+
log.error(T("instr"), `[${instrCode}] ${instrMsg}`);
|
|
1027
1093
|
this.#solving = false;
|
|
1028
1094
|
return;
|
|
1029
1095
|
}
|
|
@@ -1044,17 +1110,13 @@
|
|
|
1044
1110
|
try {
|
|
1045
1111
|
resp = await redeemResponse.json();
|
|
1046
1112
|
} catch {
|
|
1047
|
-
throw
|
|
1113
|
+
throw _err("redeem_failed", "Failed to parse server response");
|
|
1048
1114
|
}
|
|
1049
1115
|
|
|
1050
1116
|
this.dispatchEvent("progress", { progress: 100 });
|
|
1051
|
-
if (!resp.success) throw
|
|
1117
|
+
if (!resp.success) throw _err("invalid_solution", resp.error || "Invalid solution");
|
|
1052
1118
|
|
|
1053
|
-
|
|
1054
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
1055
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
1056
|
-
this.querySelector(`input[name='${fieldName}']`).value = resp.token;
|
|
1057
|
-
}
|
|
1119
|
+
this.#setToken(resp.token);
|
|
1058
1120
|
|
|
1059
1121
|
this.dispatchEvent("solve", { token: resp.token });
|
|
1060
1122
|
this.token = resp.token;
|
|
@@ -1066,7 +1128,7 @@
|
|
|
1066
1128
|
if (expiresIn > 0 && expiresIn < 24 * 60 * 60 * 1000) {
|
|
1067
1129
|
this.#resetTimer = setTimeout(() => this.reset(), expiresIn);
|
|
1068
1130
|
} else {
|
|
1069
|
-
this.error("Invalid expiration time");
|
|
1131
|
+
this.error("Invalid expiration time", "invalid_expires");
|
|
1070
1132
|
}
|
|
1071
1133
|
|
|
1072
1134
|
this.#trigger.setAttribute(
|
|
@@ -1078,6 +1140,8 @@
|
|
|
1078
1140
|
);
|
|
1079
1141
|
if (this.#hasHaptics) navigator.vibrate([10, 50, 20, 30, 40]);
|
|
1080
1142
|
|
|
1143
|
+
log.debug(T("solve"), `verified in ${since(_solveT0)}`);
|
|
1144
|
+
this.#logInvisible();
|
|
1081
1145
|
return { success: true, token: this.token };
|
|
1082
1146
|
} catch (err) {
|
|
1083
1147
|
this.#trigger.setAttribute(
|
|
@@ -1087,7 +1151,7 @@
|
|
|
1087
1151
|
"An error occurred, please try again",
|
|
1088
1152
|
),
|
|
1089
1153
|
);
|
|
1090
|
-
this.error(err.message);
|
|
1154
|
+
this.error(err.message, err.code || "solve_failed");
|
|
1091
1155
|
throw err;
|
|
1092
1156
|
}
|
|
1093
1157
|
} finally {
|
|
@@ -1113,7 +1177,7 @@
|
|
|
1113
1177
|
) {
|
|
1114
1178
|
// Unknown protocol = older widget on a newer server. Fall back to
|
|
1115
1179
|
// erroring out -- the host can detect this and serve format-1.
|
|
1116
|
-
throw
|
|
1180
|
+
throw _err("challenge_unsupported", `unsupported format-2 protocol '${ch?.protocol}'`);
|
|
1117
1181
|
}
|
|
1118
1182
|
}
|
|
1119
1183
|
|
|
@@ -1123,7 +1187,7 @@
|
|
|
1123
1187
|
typeof WebAssembly.instantiate === "function";
|
|
1124
1188
|
if (wasmSupported) {
|
|
1125
1189
|
try { wasmModule = await getWasmModule(); }
|
|
1126
|
-
catch (e) {
|
|
1190
|
+
catch (e) { log.warn(T("wasm"), "unavailable, falling back to JS solver:", e.message || e); }
|
|
1127
1191
|
}
|
|
1128
1192
|
|
|
1129
1193
|
const poolSize = Math.max(1, Math.min(this.#workersCount, challenges.length));
|
|
@@ -1209,11 +1273,12 @@
|
|
|
1209
1273
|
try {
|
|
1210
1274
|
wasmModule = await getWasmModule();
|
|
1211
1275
|
} catch (e) {
|
|
1212
|
-
|
|
1276
|
+
log.warn(T("wasm"), "unavailable, falling back to JS solver:", e.message || e);
|
|
1213
1277
|
}
|
|
1214
1278
|
}
|
|
1215
1279
|
|
|
1216
1280
|
if (!wasmSupported) {
|
|
1281
|
+
log.warn(T("wasm"), "WebAssembly disabled in this browser, solver will be ~10x slower");
|
|
1217
1282
|
if (!this.#shadow.querySelector(".warning")) {
|
|
1218
1283
|
const warningEl = document.createElement("div");
|
|
1219
1284
|
warningEl.className = "warning";
|
|
@@ -1309,7 +1374,6 @@
|
|
|
1309
1374
|
|
|
1310
1375
|
this.#credits = document.createElement("a");
|
|
1311
1376
|
this.#credits.className = "credits";
|
|
1312
|
-
this.#credits.setAttribute("part", "attribution");
|
|
1313
1377
|
this.#credits.setAttribute("aria-label", "Secured by Cap");
|
|
1314
1378
|
this.#credits.setAttribute("href", "https://trycap.dev");
|
|
1315
1379
|
this.#credits.setAttribute("target", "_blank");
|
|
@@ -1323,6 +1387,9 @@
|
|
|
1323
1387
|
this.#shadow.innerHTML = `<style${window.CAP_CSS_NONCE ? ` nonce=${window.CAP_CSS_NONCE}` : ""}>%%capCSS%%</style>`;
|
|
1324
1388
|
|
|
1325
1389
|
this.#shadow.appendChild(this.#div);
|
|
1390
|
+
|
|
1391
|
+
this.#enforceCredits();
|
|
1392
|
+
setTimeout(() => this.#enforceCredits(), 100);
|
|
1326
1393
|
}
|
|
1327
1394
|
|
|
1328
1395
|
addEventListeners() {
|
|
@@ -1376,6 +1443,39 @@
|
|
|
1376
1443
|
this.addEventListener("reset", this.boundHandleReset);
|
|
1377
1444
|
}
|
|
1378
1445
|
|
|
1446
|
+
#hostIsHidden() {
|
|
1447
|
+
if (!this.#host) return false;
|
|
1448
|
+
const rect = this.#host.getBoundingClientRect();
|
|
1449
|
+
if (rect.width === 0 && rect.height === 0) return true;
|
|
1450
|
+
const cs = window.getComputedStyle(this.#host);
|
|
1451
|
+
if (cs.display === "none" || cs.visibility === "hidden") return true;
|
|
1452
|
+
return false;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
#enforceCredits() {
|
|
1456
|
+
if (!this.#credits || !this.#div || this.#hostIsHidden()) return;
|
|
1457
|
+
if (!this.#credits.isConnected || this.#credits.parentNode !== this.#div) {
|
|
1458
|
+
this.#div.appendChild(this.#credits);
|
|
1459
|
+
}
|
|
1460
|
+
if (!this.#credits.textContent || !this.#credits.textContent.trim()) {
|
|
1461
|
+
this.#credits.textContent = "Cap";
|
|
1462
|
+
}
|
|
1463
|
+
if (this.#credits.getAttribute("href") !== "https://trycap.dev") {
|
|
1464
|
+
this.#credits.setAttribute("href", "https://trycap.dev");
|
|
1465
|
+
}
|
|
1466
|
+
this.#credits.style.cssText = [
|
|
1467
|
+
"display: inline-flex !important",
|
|
1468
|
+
"visibility: visible !important",
|
|
1469
|
+
"opacity: 0.8 !important",
|
|
1470
|
+
"pointer-events: all !important",
|
|
1471
|
+
"font-size: 12px !important",
|
|
1472
|
+
"transform: none !important",
|
|
1473
|
+
"clip-path: none !important",
|
|
1474
|
+
"filter: none !important",
|
|
1475
|
+
"position: absolute !important",
|
|
1476
|
+
].join("; ");
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1379
1479
|
animateLabel(text) {
|
|
1380
1480
|
if (!this.#trigger) return;
|
|
1381
1481
|
const wrapper = this.#trigger.querySelector(".label-wrapper");
|
|
@@ -1515,16 +1615,17 @@
|
|
|
1515
1615
|
return;
|
|
1516
1616
|
}
|
|
1517
1617
|
|
|
1518
|
-
|
|
1519
|
-
|
|
1618
|
+
log.warn(
|
|
1619
|
+
T(),
|
|
1620
|
+
"inline `onxxx='…'` handlers are deprecated. use `addEventListener` callbacks instead.",
|
|
1520
1621
|
);
|
|
1521
1622
|
|
|
1522
1623
|
new Function("event", code).call(this, event);
|
|
1523
1624
|
}
|
|
1524
1625
|
|
|
1525
|
-
error(message = "Unknown error") {
|
|
1526
|
-
|
|
1527
|
-
this.dispatchEvent("error", { isCap: true, message });
|
|
1626
|
+
error(message = "Unknown error", code = "unknown") {
|
|
1627
|
+
log.error(T("solve"), `[${code}] ${message}`);
|
|
1628
|
+
this.dispatchEvent("error", { isCap: true, code, message });
|
|
1528
1629
|
}
|
|
1529
1630
|
|
|
1530
1631
|
dispatchEvent(eventName, detail = {}) {
|
|
@@ -1543,11 +1644,7 @@
|
|
|
1543
1644
|
}
|
|
1544
1645
|
this.token = null;
|
|
1545
1646
|
this.dispatchEvent("reset");
|
|
1546
|
-
|
|
1547
|
-
this.getAttribute("data-cap-hidden-field-name") || "cap-token";
|
|
1548
|
-
if (this.querySelector(`input[name='${fieldName}']`)) {
|
|
1549
|
-
this.querySelector(`input[name='${fieldName}']`).value = "";
|
|
1550
|
-
}
|
|
1647
|
+
this.#setToken("");
|
|
1551
1648
|
}
|
|
1552
1649
|
|
|
1553
1650
|
get tokenValue() {
|
|
@@ -1642,8 +1739,9 @@
|
|
|
1642
1739
|
if (!customElements.get("cap-widget") && !window?.CAP_DONT_SKIP_REDEFINE) {
|
|
1643
1740
|
customElements.define("cap-widget", CapWidget);
|
|
1644
1741
|
} else if (customElements.get("cap-widget")) {
|
|
1645
|
-
|
|
1646
|
-
|
|
1742
|
+
log.warn(
|
|
1743
|
+
T(),
|
|
1744
|
+
"cap-widget custom element already defined, skipping re-define. set window.CAP_DONT_SKIP_REDEFINE = true to override",
|
|
1647
1745
|
);
|
|
1648
1746
|
}
|
|
1649
1747
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const shipped = [
|
|
2
|
+
"zh-cn", "es", "hi", "ar", "pt", "ru", "ja", "de", "fr",
|
|
3
|
+
];
|
|
4
|
+
|
|
5
|
+
export const shippedKeys = [
|
|
6
|
+
"initial-state", "verifying-label", "solved-label", "error-label",
|
|
7
|
+
"required-label", "troubleshooting-label", "group-aria-label",
|
|
8
|
+
"verify-aria-label", "verifying-aria-label", "verified-aria-label",
|
|
9
|
+
"error-aria-label",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const keys = [
|
|
13
|
+
"initial-state", // Verify you're human
|
|
14
|
+
"verifying-label", // Verifying...
|
|
15
|
+
"solved-label", // You're a human
|
|
16
|
+
"error-label", // Error. Try again.
|
|
17
|
+
"required-label", // Please verify you're human
|
|
18
|
+
"troubleshooting-label", // Troubleshoot
|
|
19
|
+
"group-aria-label", // Cap verification
|
|
20
|
+
"verify-aria-label", // Click to verify you're a human
|
|
21
|
+
"verifying-aria-label", // Verifying you're a human, please wait
|
|
22
|
+
"verified-aria-label", // We have verified you're a human, you may now continue
|
|
23
|
+
"error-aria-label", // An error occurred, please try again
|
|
24
|
+
"wasm-disabled", // Enable WASM for significantly faster solving
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export const translations = {
|
|
28
|
+
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","Activa WASM para una resolución mucho más rápida"],
|
|
29
|
+
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","Ative o WASM para resolver muito mais rápido"],
|
|
30
|
+
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","Activez WASM pour une résolution bien plus rapide"],
|
|
31
|
+
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","Aktivieren Sie WASM für deutlich schnelleres Lösen"],
|
|
32
|
+
it: ["Verifica di essere umano","Verifica in corso...","Sei umano","Errore. Riprova.","Verifica di essere umano","Risoluzione dei problemi","Verifica Cap","Clicca per verificare di essere umano","Verifica che sei umano, attendi","Abbiamo verificato che sei umano, puoi continuare","Si è verificato un errore, riprova","Abilita WASM per una risoluzione molto più veloce"],
|
|
33
|
+
nl: ["Ik ben een mens","Verifiëren...","Je bent een mens","Fout. Probeer opnieuw.","Verifieer dat je een mens bent","Problemen oplossen","Cap-verificatie","Klik om te verifiëren dat je een mens bent","Verifiëren dat je een mens bent, even geduld","We hebben geverifieerd dat je een mens bent, je kunt doorgaan","Er is een fout opgetreden, probeer opnieuw","Schakel WASM in voor veel sneller oplossen"],
|
|
34
|
+
sv: ["Jag är människa","Verifierar...","Du är människa","Fel. Försök igen.","Verifiera att du är människa","Felsökning","Cap-verifiering","Klicka för att verifiera att du är människa","Verifierar att du är människa, vänta","Vi har verifierat att du är människa, du kan fortsätta","Ett fel uppstod, försök igen","Aktivera WASM för betydligt snabbare lösning"],
|
|
35
|
+
da: ["Jeg er et menneske","Bekræfter...","Du er et menneske","Fejl. Prøv igen.","Bekræft, at du er et menneske","Fejlfinding","Cap-bekræftelse","Klik for at bekræfte, at du er et menneske","Bekræfter, at du er et menneske, vent","Vi har bekræftet, at du er et menneske, du kan fortsætte","Der opstod en fejl, prøv igen","Aktivér WASM for betydeligt hurtigere løsning"],
|
|
36
|
+
nb: ["Jeg er et menneske","Bekrefter...","Du er et menneske","Feil. Prøv igjen.","Bekreft at du er et menneske","Feilsøking","Cap-bekreftelse","Klikk for å bekrefte at du er et menneske","Bekrefter at du er et menneske, vent","Vi har bekreftet at du er et menneske, du kan fortsette","Det oppstod en feil, prøv igjen","Aktiver WASM for betydelig raskere løsning"],
|
|
37
|
+
fi: ["Vahvista, että olet ihminen","Vahvistetaan...","Olet ihminen","Virhe. Yritä uudelleen.","Vahvista, että olet ihminen","Vianmääritys","Cap-vahvistus","Napsauta vahvistaaksesi, että olet ihminen","Vahvistetaan, että olet ihminen, odota","Olemme vahvistaneet, että olet ihminen, voit jatkaa","Tapahtui virhe, yritä uudelleen","Ota WASM käyttöön huomattavasti nopeampaa ratkaisua varten"],
|
|
38
|
+
pl: ["Jestem człowiekiem","Weryfikacja...","Jesteś człowiekiem","Błąd. Spróbuj ponownie.","Potwierdź, że jesteś człowiekiem","Rozwiązywanie problemów","Weryfikacja Cap","Kliknij, aby potwierdzić, że jesteś człowiekiem","Weryfikacja, że jesteś człowiekiem, czekaj","Potwierdziliśmy, że jesteś człowiekiem, możesz kontynuować","Wystąpił błąd, spróbuj ponownie","Włącz WASM, aby rozwiązywać znacznie szybciej"],
|
|
39
|
+
cs: ["Ověřte, že jste člověk","Ověřování...","Jste člověk","Chyba. Zkuste to znovu.","Ověřte, že jste člověk","Řešení potíží","Ověření Cap","Kliknutím ověřte, že jste člověk","Ověřujeme, že jste člověk, čekejte","Ověřili jsme, že jste člověk, můžete pokračovat","Došlo k chybě, zkuste to znovu","Povolte WASM pro výrazně rychlejší řešení"],
|
|
40
|
+
sk: ["Overte, že ste človek","Overovanie...","Ste človek","Chyba. Skúste znova.","Overte, že ste človek","Riešenie problémov","Overenie Cap","Kliknutím overte, že ste človek","Overujeme, že ste človek, čakajte","Overili sme, že ste človek, môžete pokračovať","Vyskytla sa chyba, skúste znova","Povoľte WASM pre výrazne rýchlejšie riešenie"],
|
|
41
|
+
ru: ["Я человек","Проверка...","Вы человек","Ошибка. Повторите.","Подтвердите, что вы человек","Устранение неполадок","Проверка Cap","Нажмите, чтобы подтвердить, что вы человек","Проверяем, что вы человек, подождите","Мы подтвердили, что вы человек, можете продолжить","Произошла ошибка, повторите попытку","Включите WASM для значительно более быстрого решения"],
|
|
42
|
+
uk: ["Я людина","Перевірка...","Ви людина","Помилка. Спробуйте.","Підтвердьте, що ви людина","Усунення несправностей","Перевірка Cap","Натисніть, щоб підтвердити, що ви людина","Перевіряємо, що ви людина, зачекайте","Ми підтвердили, що ви людина, можете продовжити","Сталася помилка, спробуйте ще раз","Увімкніть WASM для значно швидшого розв’язання"],
|
|
43
|
+
ca: ["Verifica que ets humà","Verificant...","Ets humà","Error. Torna-ho a provar.","Verifica que ets humà","Resolució de problemes","Verificació de Cap","Fes clic per verificar que ets humà","Verificant que ets humà, espera","Hem verificat que ets humà, ja pots continuar","S'ha produït un error, torna-ho a provar","Activa WASM per resoldre molt més ràpid"],
|
|
44
|
+
gl: ["Verifica que es humano","Verificando...","Es humano","Erro. Téntao de novo.","Verifica que es humano","Resolución de problemas","Verificación de Cap","Fai clic para verificar que es humano","Verificando que es humano, agarda","Verificamos que es humano, xa podes continuar","Produciuse un erro, téntao de novo","Activa WASM para resolver moito máis rápido"],
|
|
45
|
+
af: ["Bevestig dat jy 'n mens is","Verifieer tans...","Jy is 'n mens","Fout. Probeer weer.","Bevestig asseblief dat jy 'n mens is","Probleemoplossing","Cap-verifikasie","Klik om te bevestig dat jy 'n mens is","Bevestig tans dat jy 'n mens is, wag asseblief","Ons het bevestig dat jy 'n mens is, jy kan voortgaan","'n Fout het voorgekom, probeer weer","Aktiveer WASM vir aansienlik vinniger oplossing"],
|
|
46
|
+
id: ["Verifikasi Anda manusia","Memverifikasi...","Anda manusia","Kesalahan. Coba lagi.","Harap verifikasi Anda manusia","Pemecahan masalah","Verifikasi Cap","Klik untuk memverifikasi Anda manusia","Memverifikasi Anda manusia, harap tunggu","Kami telah memverifikasi Anda manusia, Anda dapat melanjutkan","Terjadi kesalahan, coba lagi","Aktifkan WASM untuk penyelesaian yang jauh lebih cepat"],
|
|
47
|
+
ms: ["Sahkan anda manusia","Mengesahkan...","Anda manusia","Ralat. Cuba lagi.","Sila sahkan anda manusia","Penyelesaian masalah","Pengesahan Cap","Klik untuk mengesahkan anda manusia","Mengesahkan anda manusia, sila tunggu","Kami telah mengesahkan anda manusia, anda boleh teruskan","Ralat berlaku, sila cuba lagi","Dayakan WASM untuk penyelesaian yang jauh lebih pantas"],
|
|
48
|
+
ro: ["Verificați că sunteți om","Se verifică...","Sunteți om","Eroare. Încercați din nou.","Verificați că sunteți om","Depanare","Verificare Cap","Faceți clic pentru a verifica că sunteți om","Verificăm că sunteți om, așteptați","Am verificat că sunteți om, puteți continua","A apărut o eroare, încercați din nou","Activați WASM pentru o rezolvare mult mai rapidă"],
|
|
49
|
+
hu: ["Igazolja, hogy ember","Ellenőrzés...","Ön ember","Hiba. Próbálja újra.","Igazolja, hogy ember","Hibaelhárítás","Cap-ellenőrzés","Kattintson az emberi voltának igazolásához","Ellenőrizzük, hogy ember-e, kérjük várjon","Igazoltuk, hogy ember, folytathatja","Hiba történt, próbálja újra","Engedélyezze a WASM-ot a sokkal gyorsabb megoldásért"],
|
|
50
|
+
el: ["Είμαι άνθρωπος","Επαλήθευση...","Είστε άνθρωπος","Σφάλμα. Δοκιμάστε ξανά.","Επιβεβαιώστε ότι είστε άνθρωπος","Αντιμετώπιση προβλημάτων","Επαλήθευση Cap","Κάντε κλικ για να επιβεβαιώσετε ότι είστε άνθρωπος","Επαληθεύουμε ότι είστε άνθρωπος, περιμένετε","Επιβεβαιώσαμε ότι είστε άνθρωπος, μπορείτε να συνεχίσετε","Παρουσιάστηκε σφάλμα, δοκιμάστε ξανά","Ενεργοποιήστε το WASM για πολύ ταχύτερη επίλυση"],
|
|
51
|
+
bg: ["Потвърдете, че сте човек","Проверка...","Вие сте човек","Грешка. Опитайте пак.","Потвърдете, че сте човек","Отстраняване на неизправности","Проверка Cap","Щракнете, за да потвърдите, че сте човек","Проверяваме, че сте човек, изчакайте","Потвърдихме, че сте човек, можете да продължите","Възникна грешка, опитайте отново","Активирайте WASM за значително по-бързо решаване"],
|
|
52
|
+
sr: ["Потврдите да сте човек","Провера...","Ви сте човек","Грешка. Покушајте опет.","Потврдите да сте човек","Решавање проблема","Cap провера","Кликните да потврдите да сте човек","Проверавамо да сте човек, сачекајте","Потврдили смо да сте човек, можете наставити","Дошло је до грешке, покушајте поново","Омогућите WASM за знатно брже решавање"],
|
|
53
|
+
hr: ["Potvrdite da ste čovjek","Provjera...","Vi ste čovjek","Greška. Pokušajte opet.","Potvrdite da ste čovjek","Rješavanje problema","Cap provjera","Kliknite da potvrdite da ste čovjek","Provjeravamo da ste čovjek, pričekajte","Potvrdili smo da ste čovjek, možete nastaviti","Došlo je do pogreške, pokušajte ponovno","Omogućite WASM za znatno brže rješavanje"],
|
|
54
|
+
sl: ["Potrdite, da ste človek","Preverjanje...","Ste človek","Napaka. Poskusite znova.","Potrdite, da ste človek","Odpravljanje težav","Preverjanje Cap","Kliknite za potrditev, da ste človek","Preverjamo, da ste človek, počakajte","Potrdili smo, da ste človek, lahko nadaljujete","Prišlo je do napake, poskusite znova","Omogočite WASM za bistveno hitrejše reševanje"],
|
|
55
|
+
et: ["Kinnitage, et olete inimene","Kontrollimine...","Olete inimene","Viga. Proovige uuesti.","Kinnitage, et olete inimene","Tõrkeotsing","Cap kontroll","Klõpsake, et kinnitada, et olete inimene","Kontrollime, et olete inimene, oodake","Kinnitasime, et olete inimene, võite jätkata","Ilmnes viga, proovige uuesti","Lubage WASM oluliselt kiiremaks lahendamiseks"],
|
|
56
|
+
lv: ["Esmu cilvēks","Pārbauda...","Jūs esat cilvēks","Kļūda. Mēģiniet vēlreiz.","Apstipriniet, ka esat cilvēks","Problēmu novēršana","Cap pārbaude","Noklikšķiniet, lai apstiprinātu, ka esat cilvēks","Pārbaudām, ka esat cilvēks, uzgaidiet","Mēs apstiprinājām, ka esat cilvēks, varat turpināt","Radās kļūda, mēģiniet vēlreiz","Iespējojiet WASM ievērojami ātrākai risināšanai"],
|
|
57
|
+
lt: ["Esu žmogus","Tikrinama...","Jūs esate žmogus","Klaida. Bandykite vėl.","Patvirtinkite, kad esate žmogus","Trikčių šalinimas","Cap patvirtinimas","Spustelėkite, kad patvirtintumėte, jog esate žmogus","Tikriname, ar esate žmogus, palaukite","Patvirtinome, kad esate žmogus, galite tęsti","Įvyko klaida, bandykite dar kartą","Įjunkite WASM, kad išspręstumėte daug greičiau"],
|
|
58
|
+
tr: ["Ben insanım","Doğrulanıyor...","İnsansınız","Hata. Tekrar deneyin.","Lütfen insan olduğunuzu doğrulayın","Sorun giderme","Cap doğrulaması","İnsan olduğunuzu doğrulamak için tıklayın","İnsan olduğunuz doğrulanıyor, lütfen bekleyin","İnsan olduğunuzu doğruladık, devam edebilirsiniz","Bir hata oluştu, tekrar deneyin","Çok daha hızlı çözüm için WASM'ı etkinleştirin"],
|
|
59
|
+
vi: ["Xác minh bạn là con người","Đang xác minh...","Bạn là con người","Lỗi. Thử lại.","Vui lòng xác minh bạn là con người","Khắc phục sự cố","Xác minh Cap","Nhấp để xác minh bạn là con người","Đang xác minh bạn là con người, vui lòng đợi","Chúng tôi đã xác minh bạn là con người, bạn có thể tiếp tục","Đã xảy ra lỗi, vui lòng thử lại","Bật WASM để giải nhanh hơn đáng kể"],
|
|
60
|
+
tl: ["Patunayan na ikaw ay tao","Bineberipika...","Ikaw ay tao","Error. Subukan ulit.","Pakipatunayan na ikaw ay tao","Pag-troubleshoot","Pagpapatunay ng Cap","I-click para patunayan na ikaw ay tao","Pinapatunayan na ikaw ay tao, maghintay","Napatunayan namin na ikaw ay tao, maaari nang magpatuloy","May naganap na error, subukan ulit","I-enable ang WASM para sa mas mabilis na paglutas"],
|
|
61
|
+
ar: ["تحقق من أنك إنسان","جارٍ التحقق...","أنت إنسان","خطأ. حاول مرة أخرى.","يرجى التحقق من أنك إنسان","استكشاف الأخطاء وإصلاحها","تحقق Cap","انقر للتحقق من أنك إنسان","جارٍ التحقق من أنك إنسان، يرجى الانتظار","لقد تحققنا من أنك إنسان، يمكنك المتابعة الآن","حدث خطأ، يرجى المحاولة مرة أخرى","فعّل WASM لحل أسرع بكثير"],
|
|
62
|
+
he: ["אמת שאתה אנושי","מאמת...","אתה אנושי","שגיאה. נסה שוב.","נא לאמת שאתה אנושי","פתרון בעיות","אימות Cap","לחץ כדי לאמת שאתה אנושי","מאמת שאתה אנושי, אנא המתן","אימתנו שאתה אנושי, אפשר להמשיך","אירעה שגיאה, נסה שוב","הפעל את WASM לפתרון מהיר בהרבה"],
|
|
63
|
+
fa: ["تأیید کنید که انسان هستید","در حال تأیید...","شما انسان هستید","خطا. دوباره تلاش کنید.","لطفاً تأیید کنید که انسان هستید","عیبیابی","تأیید Cap","برای تأیید اینکه انسان هستید کلیک کنید","در حال تأیید اینکه انسان هستید، لطفاً صبر کنید","تأیید کردیم که انسان هستید، میتوانید ادامه دهید","خطایی رخ داد، دوباره تلاش کنید","برای حل بسیار سریعتر، WASM را فعال کنید"],
|
|
64
|
+
"zh-cn": ["确认你是真人","正在验证...","你是真人","出错了。请重试。","请确认你是真人","故障排除","Cap 验证","点击以确认你是真人","正在验证你是真人,请稍候","我们已确认你是真人,你可以继续了","发生错误,请重试","启用 WASM 可大幅加快求解速度"],
|
|
65
|
+
"zh-tw": ["確認你是真人","正在驗證...","你是真人","發生錯誤。請重試。","請確認你是真人","疑難排解","Cap 驗證","點擊以確認你是真人","正在驗證你是真人,請稍候","我們已確認你是真人,你可以繼續了","發生錯誤,請重試","啟用 WASM 可大幅加快解算速度"],
|
|
66
|
+
ja: ["私は人間です","確認中...","あなたは人間です","エラー。再試行を。","あなたが人間であることを確認してください","トラブルシューティング","Cap 認証","クリックして人間であることを確認","あなたが人間であることを確認しています。お待ちください","あなたが人間であることを確認しました。続行できます","エラーが発生しました。もう一度お試しください","WASM を有効にすると大幅に高速化されます"],
|
|
67
|
+
ko: ["사람인지 확인하세요","확인 중...","당신은 사람입니다","오류. 다시 시도하세요.","사람인지 확인해 주세요","문제 해결","Cap 인증","클릭하여 사람인지 확인하세요","사람인지 확인 중입니다. 잠시 기다려 주세요","사람임을 확인했습니다. 계속할 수 있습니다","오류가 발생했습니다. 다시 시도하세요","훨씬 빠른 처리를 위해 WASM을 활성화하세요"],
|
|
68
|
+
az: ["Mən insanam","Yoxlanılır...","Siz insansınız","Xəta. Yenidən cəhd edin.","İnsan olduğunuzu təsdiqləyin","Problemlərin həlli","Cap yoxlaması","İnsan olduğunuzu təsdiqləmək üçün klikləyin","İnsan olduğunuz yoxlanılır, gözləyin","İnsan olduğunuzu təsdiqlədik, davam edə bilərsiniz","Xəta baş verdi, yenidən cəhd edin","Daha sürətli həll üçün WASM-ı aktivləşdirin"],
|
|
69
|
+
kk: ["Адам екеніңізді растаңыз","Тексерілуде...","Сіз адамсыз","Қате. Қайталап көріңіз.","Адам екеніңізді растаңыз","Ақаулықтарды жою","Cap растауы","Адам екеніңізді растау үшін басыңыз","Адам екеніңізді тексерудеміз, күтіңіз","Адам екеніңізді растадық, жалғастыра аласыз","Қате орын алды, қайталап көріңіз","Әлдеқайда жылдам шешу үшін WASM қосыңыз"],
|
|
70
|
+
ka: ["მე ადამიანი ვარ","მოწმდება...","თქვენ ადამიანი ხართ","შეცდომა. სცადეთ.","დაადასტურეთ, რომ ადამიანი ხართ","პრობლემის გადაჭრა","Cap-ის დადასტურება","დააწკაპუნეთ, რომ დაადასტუროთ, რომ ადამიანი ხართ","ვამოწმებთ, რომ ადამიანი ხართ, დაელოდეთ","დავადასტურეთ, რომ ადამიანი ხართ, შეგიძლიათ გააგრძელოთ","მოხდა შეცდომა, სცადეთ ხელახლა","ჩართეთ WASM მნიშვნელოვნად სწრაფი ამოხსნისთვის"],
|
|
71
|
+
hy: ["Հաստատեք, որ մարդ եք","Ստուգվում է...","Դուք մարդ եք","Սխալ. Կրկին փորձեք։","Հաստատեք, որ մարդ եք","Անսարքությունների վերացում","Cap ստուգում","Սեղմեք՝ հաստատելու, որ մարդ եք","Ստուգում ենք, որ մարդ եք, սպասեք","Մենք հաստատեցինք, որ մարդ եք, կարող եք շարունակել","Սխալ տեղի ունեցավ, կրկին փորձեք","Միացրեք WASM-ը զգալիորեն ավելի արագ լուծման համար"],
|
|
72
|
+
ur: ["تصدیق کریں کہ آپ انسان ہیں","تصدیق ہو رہی ہے...","آپ انسان ہیں","خرابی۔ دوبارہ کوشش کریں۔","براہ کرم تصدیق کریں کہ آپ انسان ہیں","مسئلہ حل کریں","Cap تصدیق","تصدیق کے لیے کلک کریں کہ آپ انسان ہیں","تصدیق ہو رہی ہے کہ آپ انسان ہیں، انتظار کریں","ہم نے تصدیق کر لی کہ آپ انسان ہیں، اب آپ جاری رکھ سکتے ہیں","ایک خرابی پیش آئی، دوبارہ کوشش کریں","نمایاں طور پر تیز حل کے لیے WASM فعال کریں"],
|
|
73
|
+
hi: ["पुष्टि करें कि आप मानव हैं","सत्यापित हो रहा है...","आप मानव हैं","त्रुटि। पुनः प्रयास करें।","कृपया पुष्टि करें कि आप मानव हैं","समस्या निवारण","Cap सत्यापन","पुष्टि करने के लिए क्लिक करें कि आप मानव हैं","सत्यापित किया जा रहा है कि आप मानव हैं, प्रतीक्षा करें","हमने पुष्टि कर दी है कि आप मानव हैं, अब आप जारी रख सकते हैं","एक त्रुटि हुई, पुनः प्रयास करें","काफी तेज़ समाधान के लिए WASM सक्षम करें"],
|
|
74
|
+
bn: ["আপনি মানুষ তা যাচাই করুন","যাচাই করা হচ্ছে...","আপনি মানুষ","ত্রুটি। আবার চেষ্টা করুন।","অনুগ্রহ করে যাচাই করুন যে আপনি মানুষ","সমস্যা সমাধান","Cap যাচাই","আপনি মানুষ তা যাচাই করতে ক্লিক করুন","আপনি মানুষ তা যাচাই করা হচ্ছে, অপেক্ষা করুন","আমরা যাচাই করেছি যে আপনি মানুষ, এখন চালিয়ে যেতে পারেন","একটি ত্রুটি ঘটেছে, আবার চেষ্টা করুন","অনেক দ্রুত সমাধানের জন্য WASM সক্ষম করুন"],
|
|
75
|
+
ta: ["நான் மனிதர்","சரிபார்க்கிறது...","நீங்கள் மனிதர்","பிழை. மீண்டும் முயலவும்.","நீங்கள் மனிதர் என்பதை உறுதிப்படுத்தவும்","சிக்கல் தீர்வு","Cap சரிபார்ப்பு","நீங்கள் மனிதர் என உறுதிப்படுத்த கிளிக் செய்யவும்","நீங்கள் மனிதர் என சரிபார்க்கிறது, காத்திருக்கவும்","நீங்கள் மனிதர் என உறுதிப்படுத்தினோம், தொடரலாம்","பிழை ஏற்பட்டது, மீண்டும் முயற்சிக்கவும்","மிக வேகமான தீர்வுக்கு WASM ஐ இயக்கவும்"],
|
|
76
|
+
te: ["నేను మనిషిని","ధృవీకరిస్తోంది...","మీరు మనిషి","లోపం. మళ్లీ ప్రయత్నించండి.","దయచేసి మీరు మనిషి అని ధృవీకరించండి","సమస్య పరిష్కారం","Cap ధృవీకరణ","మీరు మనిషి అని ధృవీకరించడానికి క్లిక్ చేయండి","మీరు మనిషి అని ధృవీకరిస్తోంది, వేచి ఉండండి","మీరు మనిషి అని మేము ధృవీకరించాము, ఇప్పుడు కొనసాగవచ్చు","లోపం సంభవించింది, మళ్లీ ప్రయత్నించండి","చాలా వేగవంతమైన పరిష్కారం కోసం WASM ప్రారంభించండి"],
|
|
77
|
+
mr: ["मी मानव आहे","पडताळणी होत आहे...","तुम्ही मानव आहात","त्रुटी. पुन्हा प्रयत्न करा.","कृपया तुम्ही मानव आहात याची पुष्टी करा","समस्यानिवारण","Cap पडताळणी","तुम्ही मानव आहात याची पुष्टी करण्यासाठी क्लिक करा","तुम्ही मानव आहात याची पडताळणी होत आहे, प्रतीक्षा करा","आम्ही पुष्टी केली की तुम्ही मानव आहात, आता पुढे जाऊ शकता","त्रुटी आली, पुन्हा प्रयत्न करा","खूप जलद सोडवण्यासाठी WASM सक्षम करा"],
|
|
78
|
+
gu: ["તમે માનવ છો તેની ખાતરી કરો","ચકાસણી થઈ રહી છે...","તમે માનવ છો","ભૂલ. ફરી પ્રયાસ કરો.","કૃપા કરીને ખાતરી કરો કે તમે માનવ છો","સમસ્યાનિવારણ","Cap ચકાસણી","તમે માનવ છો તેની ખાતરી કરવા ક્લિક કરો","તમે માનવ છો તેની ચકાસણી થઈ રહી છે, રાહ જુઓ","અમે ખાતરી કરી કે તમે માનવ છો, હવે ચાલુ રાખી શકો છો","ભૂલ આવી, ફરી પ્રયાસ કરો","ઘણા ઝડપી ઉકેલ માટે WASM સક્ષમ કરો"],
|
|
79
|
+
kn: ["ನಾನು ಮನುಷ್ಯ","ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ...","ನೀವು ಮನುಷ್ಯ","ದೋಷ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.","ದಯವಿಟ್ಟು ನೀವು ಮನುಷ್ಯ ಎಂದು ದೃಢೀಕರಿಸಿ","ಸಮಸ್ಯೆ ಪರಿಹಾರ","Cap ಪರಿಶೀಲನೆ","ನೀವು ಮನುಷ್ಯ ಎಂದು ದೃಢೀಕರಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ","ನೀವು ಮನುಷ್ಯ ಎಂದು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ, ನಿರೀಕ್ಷಿಸಿ","ನೀವು ಮನುಷ್ಯ ಎಂದು ದೃಢೀಕರಿಸಿದ್ದೇವೆ, ಮುಂದುವರಿಯಬಹುದು","ದೋಷ ಸಂಭವಿಸಿದೆ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ","ಬಹಳ ವೇಗದ ಪರಿಹಾರಕ್ಕಾಗಿ WASM ಸಕ್ರಿಯಗೊಳಿಸಿ"],
|
|
80
|
+
ml: ["ഞാൻ മനുഷ്യനാണ്","പരിശോധിക്കുന്നു...","നിങ്ങൾ മനുഷ്യനാണ്","പിശക്. വീണ്ടും ശ്രമിക്കുക.","ദയവായി നിങ്ങൾ മനുഷ്യനാണെന്ന് സ്ഥിരീകരിക്കുക","പ്രശ്നപരിഹാരം","Cap പരിശോധന","നിങ്ങൾ മനുഷ്യനാണെന്ന് സ്ഥിരീകരിക്കാൻ ക്ലിക്ക് ചെയ്യുക","നിങ്ങൾ മനുഷ്യനാണെന്ന് പരിശോധിക്കുന്നു, കാത്തിരിക്കുക","നിങ്ങൾ മനുഷ്യനാണെന്ന് ഞങ്ങൾ സ്ഥിരീകരിച്ചു, തുടരാം","ഒരു പിശക് സംഭവിച്ചു, വീണ്ടും ശ്രമിക്കുക","വളരെ വേഗത്തിലുള്ള പരിഹാരത്തിന് WASM പ്രവർത്തനക്ഷമമാക്കുക"],
|
|
81
|
+
pa: ["ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਪੁਸ਼ਟੀ ਹੋ ਰਹੀ ਹੈ...","ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਗਲਤੀ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।","ਕਿਰਪਾ ਕਰਕੇ ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਸਮੱਸਿਆ ਹੱਲ","Cap ਪੁਸ਼ਟੀ","ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ","ਪੁਸ਼ਟੀ ਹੋ ਰਹੀ ਹੈ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ, ਉਡੀਕ ਕਰੋ","ਅਸੀਂ ਪੁਸ਼ਟੀ ਕਰ ਲਈ ਹੈ ਕਿ ਤੁਸੀਂ ਮਨੁੱਖ ਹੋ, ਹੁਣ ਜਾਰੀ ਰੱਖ ਸਕਦੇ ਹੋ","ਇੱਕ ਗਲਤੀ ਆਈ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ","ਬਹੁਤ ਤੇਜ਼ ਹੱਲ ਲਈ WASM ਚਾਲੂ ਕਰੋ"],
|
|
82
|
+
th: ["ยืนยันว่าคุณเป็นมนุษย์","กำลังยืนยัน...","คุณเป็นมนุษย์","ข้อผิดพลาด ลองอีกครั้ง","โปรดยืนยันว่าคุณเป็นมนุษย์","การแก้ไขปัญหา","การยืนยัน Cap","คลิกเพื่อยืนยันว่าคุณเป็นมนุษย์","กำลังยืนยันว่าคุณเป็นมนุษย์ โปรดรอ","เรายืนยันแล้วว่าคุณเป็นมนุษย์ คุณดำเนินการต่อได้","เกิดข้อผิดพลาด โปรดลองอีกครั้ง","เปิดใช้งาน WASM เพื่อการแก้ปัญหาที่เร็วขึ้นมาก"],
|
|
83
|
+
sw: ["Mimi ni binadamu","Inathibitisha...","Wewe ni binadamu","Hitilafu. Jaribu tena.","Tafadhali thibitisha kuwa wewe ni binadamu","Utatuzi wa matatizo","Uthibitisho wa Cap","Bofya ili kuthibitisha kuwa wewe ni binadamu","Inathibitisha kuwa wewe ni binadamu, tafadhali subiri","Tumethibitisha kuwa wewe ni binadamu, unaweza kuendelea","Hitilafu imetokea, tafadhali jaribu tena","Washa WASM kwa utatuzi wa haraka zaidi"],
|
|
84
|
+
am: ["ሰው መሆንዎን ያረጋግጡ","በማረጋገጥ ላይ...","እርስዎ ሰው ነዎት","ስህተት። እንደገና ይሞክሩ።","እባክዎ ሰው መሆንዎን ያረጋግጡ","ችግር መፍታት","የCap ማረጋገጫ","ሰው መሆንዎን ለማረጋገጥ ጠቅ ያድርጉ","ሰው መሆንዎን በማረጋገጥ ላይ፣ እባክዎ ይጠብቁ","ሰው መሆንዎን አረጋግጠናል፣ መቀጠል ይችላሉ","ስህተት ተከስቷል፣ እባክዎ እንደገና ይሞክሩ","በጣም ፈጣን መፍትሄ ለማግኘት WASM ን ያንቁ"],
|
|
85
|
+
my: ["ကျွန်ုပ် လူသားဖြစ်သည်","အတည်ပြုနေသည်...","သင်သည် လူသားဖြစ်သည်","အမှား။ ထပ်ကြိုးစားပါ။","သင်သည် လူသားဖြစ်ကြောင်း အတည်ပြုပါ","ပြဿနာဖြေရှင်းခြင်း","Cap အတည်ပြုခြင်း","သင်သည် လူသားဖြစ်ကြောင်း အတည်ပြုရန် နှိပ်ပါ","သင်သည် လူသားဖြစ်ကြောင်း အတည်ပြုနေသည်၊ စောင့်ပါ","သင်သည် လူသားဖြစ်ကြောင်း ကျွန်ုပ်တို့ အတည်ပြုပြီးပါပြီ၊ ဆက်လက်လုပ်ဆောင်နိုင်ပါသည်","အမှားဖြစ်ပွားခဲ့သည်၊ ထပ်ကြိုးစားပါ","များစွာပိုမြန်သော ဖြေရှင်းမှုအတွက် WASM ကိုဖွင့်ပါ"],
|
|
86
|
+
km: ["បញ្ជាក់ថាអ្នកជាមនុស្ស","កំពុងផ្ទៀងផ្ទាត់...","អ្នកជាមនុស្ស","កំហុស។ សាកល្បងម្តងទៀត។","សូមបញ្ជាក់ថាអ្នកជាមនុស្ស","ការដោះស្រាយបញ្ហា","ការផ្ទៀងផ្ទាត់ Cap","ចុចដើម្បីបញ្ជាក់ថាអ្នកជាមនុស្ស","កំពុងផ្ទៀងផ្ទាត់ថាអ្នកជាមនុស្ស សូមរង់ចាំ","យើងបានផ្ទៀងផ្ទាត់ថាអ្នកជាមនុស្ស អ្នកអាចបន្តបាន","មានកំហុសកើតឡើង សូមសាកល្បងម្តងទៀត","បើក WASM សម្រាប់ការដោះស្រាយលឿនជាងមុនច្រើន"],
|
|
87
|
+
};
|
package/src/worker.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
(() => {
|
|
2
|
+
const wlog = (method, ...args) => {
|
|
3
|
+
if (!self.CAP_SILENT) console[method]("[cap worker]", ...args);
|
|
4
|
+
};
|
|
5
|
+
|
|
2
6
|
const solveFallback = async ({ salt, target }) => {
|
|
3
7
|
let nonce = 0;
|
|
4
8
|
const batchSize = 50000;
|
|
@@ -50,7 +54,7 @@
|
|
|
50
54
|
nonce++;
|
|
51
55
|
}
|
|
52
56
|
} catch (error) {
|
|
53
|
-
|
|
57
|
+
wlog("error","fallback solver crashed:", error.message || error);
|
|
54
58
|
self.postMessage({
|
|
55
59
|
found: false,
|
|
56
60
|
error: error.message,
|
|
@@ -79,9 +83,7 @@
|
|
|
79
83
|
};
|
|
80
84
|
|
|
81
85
|
if (typeof WebAssembly !== "object" || typeof WebAssembly?.instantiate !== "function") {
|
|
82
|
-
|
|
83
|
-
"[cap worker] wasm not supported, falling back to alternative solver. this will be significantly slower.",
|
|
84
|
-
);
|
|
86
|
+
wlog("warn","WebAssembly unavailable, using JS fallback solver (significantly slower)");
|
|
85
87
|
|
|
86
88
|
self.onmessage = async ({ data }) => {
|
|
87
89
|
if (data?.kind === "rsw") return solveRsw(data);
|
|
@@ -171,7 +173,7 @@
|
|
|
171
173
|
|
|
172
174
|
return true;
|
|
173
175
|
} catch (e) {
|
|
174
|
-
|
|
176
|
+
wlog("error","wasm init failed:", e.message || e);
|
|
175
177
|
return false;
|
|
176
178
|
}
|
|
177
179
|
};
|
|
@@ -182,13 +184,13 @@
|
|
|
182
184
|
if (wasmModule instanceof WebAssembly.Module && solve_pow_function === null) {
|
|
183
185
|
const ok = initFromModule(wasmModule);
|
|
184
186
|
if (!ok) {
|
|
185
|
-
|
|
187
|
+
wlog("warn","wasm init failed, falling back to JS solver");
|
|
186
188
|
return solveFallback({ salt, target });
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
|
|
190
192
|
if (solve_pow_function === null) {
|
|
191
|
-
|
|
193
|
+
wlog("warn","no wasm module provided, falling back to JS solver");
|
|
192
194
|
return solveFallback({ salt, target });
|
|
193
195
|
}
|
|
194
196
|
|
|
@@ -203,7 +205,7 @@
|
|
|
203
205
|
durationMs: (endTime - startTime).toFixed(2),
|
|
204
206
|
});
|
|
205
207
|
} catch (error) {
|
|
206
|
-
|
|
208
|
+
wlog("error","solve_pow threw:", error.message || error);
|
|
207
209
|
|
|
208
210
|
self.postMessage({
|
|
209
211
|
found: false,
|